From 080f69b873807ffdb5a3d4ce5e47f2b3fd4dcc11 Mon Sep 17 00:00:00 2001
From: RedMonster-HUN <54554640+RedMonster-HUN@users.noreply.github.com>
Date: Mon, 18 Sep 2023 14:12:25 +0200
Subject: [PATCH 001/107] Update translation_hu.xml (#2773)
Translation corrected up to line 437
---
translations/translation_hu.xml | 134 ++++++++++++++++----------------
1 file changed, 67 insertions(+), 67 deletions(-)
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index 9564c521c..b21bfd0a1 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -18,27 +18,27 @@
-
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
-
+
+
@@ -58,49 +58,49 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
@@ -110,9 +110,9 @@
-
-
-
+
+
+
@@ -141,8 +141,8 @@
-
-
+
+
@@ -157,12 +157,12 @@
-
-
+
+
-
-
+
+
@@ -175,8 +175,8 @@
-
-
+
+
@@ -188,8 +188,8 @@
-
-
+
+
@@ -202,8 +202,8 @@
-
-
+
+
@@ -299,12 +299,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
@@ -365,7 +365,7 @@ Az útvonal automatikusan mentésre kerül a szerkesztő bezárásakor és felü
-
+
@@ -412,13 +412,13 @@ Az útvonal automatikusan mentésre kerül a szerkesztő bezárásakor és felü
-
+
-
-
-
+
+
+
@@ -426,15 +426,15 @@ Az útvonal automatikusan mentésre kerül a szerkesztő bezárásakor és felü
-
+
-
-
+
+
From 514d8aecd5b3860e9b0a1e56ea791dbfd597229f Mon Sep 17 00:00:00 2001
From: SniperKittenCZ <61847408+SniperKittenCZ@users.noreply.github.com>
Date: Mon, 18 Sep 2023 14:36:00 +0200
Subject: [PATCH 002/107] Update translation_cz.xml
---
translations/translation_cz.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml
index 7ee9aa392..865c96a0c 100644
--- a/translations/translation_cz.xml
+++ b/translations/translation_cz.xml
@@ -321,7 +321,7 @@
-
+
From d9c9ac3e7bceec76a2b2f3d1e85d7e9bc6b8a490 Mon Sep 17 00:00:00 2001
From: Peter Vaiko
Date: Tue, 19 Sep 2023 13:54:14 -0400
Subject: [PATCH 003/107] fix: pathfinder reverse turn
Always extend the path before changing from
reverse to forward to allow the vehicle to
align better with the forward leg.
#2777
---
scripts/ai/turns/AITurn.lua | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/ai/turns/AITurn.lua b/scripts/ai/turns/AITurn.lua
index 2118efaee..012c5b62b 100644
--- a/scripts/ai/turns/AITurn.lua
+++ b/scripts/ai/turns/AITurn.lua
@@ -730,8 +730,8 @@ function CourseTurn:onPathfindingDone(path)
self.turnCourse:setUseTightTurnOffsetForLastWaypoints(15)
local endingTurnLength = self.turnContext:appendEndingTurnCourse(self.turnCourse, nil, true)
local x = AIUtil.getDirectionNodeToReverserNodeOffset(self.vehicle)
- self:debug('Extending course at direction switch for reversing: %.1f m', -x )
- self.turnCourse:adjustForReversing(math.max(0, -x))
+ self:debug('Extending course at direction switch for reversing to %.1f m (or at least 1m)', -x )
+ self.turnCourse:adjustForReversing(math.max(1, -x))
TurnManeuver.setLowerImplements(self.turnCourse, endingTurnLength, true)
else
self:debug('No path found in %d ms, falling back to normal turn course generator', g_currentMission.time - (self.pathfindingStartedAt or 0))
From 9b3bae4149c2b415c5423ab6bee9d418fab88119 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 5 Jul 2023 21:03:18 +0200
Subject: [PATCH 004/107] WIP
---
Courseplay.lua | 3 +-
config/MasterTranslations.xml | 14 +-
config/jobParameters/JobParameterSetup.xml | 2 +
.../SiloLoaderJobParameterSetup.xml | 16 +-
modDesc.xml | 29 +
scripts/Course.lua | 1 +
scripts/CpSettingsUtil.lua | 4 +-
.../ai/AIDriveStrategyShovelSiloLoader.lua | 506 ++++++++++++++++++
scripts/ai/ImplementUtil.lua | 63 ++-
scripts/ai/controllers/ShovelController.lua | 60 ++-
scripts/ai/jobs/CpAIJob.lua | 2 +-
scripts/ai/jobs/CpAIJobSiloLoader.lua | 44 +-
scripts/ai/jobs/CpJobParameters.lua | 45 +-
.../parameters/CpAIParameterPositionAngle.lua | 3 +-
scripts/gui/CpAIFrameExtended.lua | 52 +-
scripts/gui/CpGamePadHudScreen.lua | 4 +-
scripts/gui/hud/CpBaseHud.lua | 7 +-
scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua | 8 +-
scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua | 8 +
scripts/pathfinder/PathfinderUtil.lua | 33 +-
scripts/silo/BunkerSiloWrapper.lua | 40 +-
scripts/specializations/CpAIBaleFinder.lua | 4 +-
.../specializations/CpAIBunkerSiloWorker.lua | 11 +-
.../specializations/CpAICombineUnloader.lua | 4 +-
scripts/specializations/CpAIFieldWorker.lua | 4 +-
.../specializations/CpAISiloLoaderWorker.lua | 33 +-
scripts/specializations/CpAIWorker.lua | 2 +-
scripts/specializations/CpGamePadHud.lua | 3 +-
scripts/specializations/CpShovelPositions.lua | 422 +++++++++++++++
scripts/trigger/TriggerManager.lua | 44 ++
scripts/trigger/TriggerWrapper.lua | 20 +
31 files changed, 1448 insertions(+), 43 deletions(-)
create mode 100644 scripts/ai/AIDriveStrategyShovelSiloLoader.lua
create mode 100644 scripts/specializations/CpShovelPositions.lua
create mode 100644 scripts/trigger/TriggerManager.lua
create mode 100644 scripts/trigger/TriggerWrapper.lua
diff --git a/Courseplay.lua b/Courseplay.lua
index 737948e89..f4ff27aea 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -339,11 +339,12 @@ function Courseplay.register(typeManager)
CpAIFieldWorker.register(typeManager, typeName, typeEntry.specializations)
CpAIBaleFinder.register(typeManager, typeName, typeEntry.specializations)
CpAICombineUnloader.register(typeManager, typeName, typeEntry.specializations)
- CpAIBunkerSiloWorker.register(typeManager, typeName, typeEntry.specializations)
CpAISiloLoaderWorker.register(typeManager, typeName, typeEntry.specializations)
+ CpAIBunkerSiloWorker.register(typeManager, typeName, typeEntry.specializations)
CpGamePadHud.register(typeManager, typeName,typeEntry.specializations)
CpHud.register(typeManager, typeName, typeEntry.specializations)
CpInfoTexts.register(typeManager, typeName, typeEntry.specializations)
+ CpShovelPositions.register(typeManager, typeName, typeEntry.specializations)
end
end
TypeManager.finalizeTypes = Utils.prependedFunction(TypeManager.finalizeTypes, Courseplay.register)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index 919c581e4..ed8a652c8 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -79,6 +79,10 @@
+
+
+
+
@@ -300,7 +304,15 @@
-
+
+
+
+
+
+
+
+
+
diff --git a/config/jobParameters/JobParameterSetup.xml b/config/jobParameters/JobParameterSetup.xml
index fa003f020..4d7c917dc 100644
--- a/config/jobParameters/JobParameterSetup.xml
+++ b/config/jobParameters/JobParameterSetup.xml
@@ -19,12 +19,14 @@
2
3
4
+ 5
nearest
first
last
bunkerSilo
+ siloLoader
diff --git a/config/jobParameters/SiloLoaderJobParameterSetup.xml b/config/jobParameters/SiloLoaderJobParameterSetup.xml
index 6ec615b9c..68040f16b 100644
--- a/config/jobParameters/SiloLoaderJobParameterSetup.xml
+++ b/config/jobParameters/SiloLoaderJobParameterSetup.xml
@@ -10,6 +10,20 @@
-
+
+
+
+
+
+ 1
+ 2
+
+
+ trailer
+ unloadTrigger
+
+
+
+
diff --git a/modDesc.xml b/modDesc.xml
index 6d7920e3a..b57225da1 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -251,6 +251,8 @@ Changelog 7.1.0.0:
+
+
@@ -318,6 +320,32 @@ Changelog 7.1.0.0:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -405,6 +433,7 @@ Changelog 7.1.0.0:
+
diff --git a/scripts/Course.lua b/scripts/Course.lua
index 5b6e579b7..58c09b489 100644
--- a/scripts/Course.lua
+++ b/scripts/Course.lua
@@ -910,6 +910,7 @@ function Course:appendWaypoints(waypoints)
end
--- Append another course to the course
+---@param other Course
function Course:append(other)
self:appendWaypoints(other.waypoints)
end
diff --git a/scripts/CpSettingsUtil.lua b/scripts/CpSettingsUtil.lua
index 24d9639bc..945cf28e9 100644
--- a/scripts/CpSettingsUtil.lua
+++ b/scripts/CpSettingsUtil.lua
@@ -70,7 +70,7 @@ function CpSettingsUtil.init()
schema:register(XMLValueType.STRING, "Settings#autoUpdateGui", "Gui gets updated automatically")
local key = "Settings.SettingSubTitle(?)"
- schema:register(XMLValueType.STRING, key .."#title", "Setting sub title", nil, true)
+ schema:register(XMLValueType.STRING, key .."#title", "Setting sub title", nil)
schema:register(XMLValueType.BOOL, key .."#prefix", "Setting sub title is a prefix", true)
schema:register(XMLValueType.STRING, key.."#isDisabled", "Callback function, if the settings is disabled.") -- optional
@@ -157,7 +157,7 @@ function CpSettingsUtil.loadSettingsFromSetup(class, filePath)
class.pageTitle = setupKey .. "title"
end
xmlFile:iterate("Settings.SettingSubTitle", function (i, masterKey)
- local subTitle = xmlFile:getValue(masterKey.."#title")
+ local subTitle = xmlFile:getValue(masterKey.."#title", "...")
--- This flag can by used to simplify the translation text.
local pre = xmlFile:getValue(masterKey.."#prefix", true)
if pre then
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
new file mode 100644
index 000000000..11f8019a2
--- /dev/null
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -0,0 +1,506 @@
+--[[
+This file is part of Courseplay (https://github.com/Courseplay/courseplay)
+Copyright (C) 2022
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+]]
+
+---@class AIDriveStrategyShovelSiloLoader : AIDriveStrategyCourse
+---@field shovelController ShovelController
+AIDriveStrategyShovelSiloLoader = {}
+local AIDriveStrategyShovelSiloLoader_mt = Class(AIDriveStrategyShovelSiloLoader, AIDriveStrategyCourse)
+
+----------------------------------------------------------------
+--- State properties
+----------------------------------------------------------------
+--[[
+ shovelPosition : number (1-4)
+ shovelMovingSpeed : number|nil speed while the shovel/ front loader is moving
+]]
+
+
+----------------------------------------------------------------
+--- States
+----------------------------------------------------------------
+
+AIDriveStrategyShovelSiloLoader.myStates = {
+ DRIVING_ALIGNMENT_COURSE = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+ DRIVING_INTO_SILO = {shovelPosition = ShovelController.POSITIONS.LOADING, shovelMovingSpeed = 0},
+ DRIVING_OUT_OF_SILO = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+ WAITING_FOR_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+ DRIVING_TO_UNLOAD_POSITION = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+ DRIVING_TO_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+ DRIVING_TO_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
+ UNLOADING = {shovelPosition = ShovelController.POSITIONS.UNLOADING, shovelMovingSpeed = 0},
+}
+
+AIDriveStrategyShovelSiloLoader.safeSpaceToTrailer = 5
+AIDriveStrategyShovelSiloLoader.maxValidTrailerDistance = 30
+
+function AIDriveStrategyShovelSiloLoader.new(customMt)
+ if customMt == nil then
+ customMt = AIDriveStrategyShovelSiloLoader_mt
+ end
+ local self = AIDriveStrategyCourse.new(customMt)
+ AIDriveStrategyCourse.initStates(self, AIDriveStrategyShovelSiloLoader.myStates)
+ self.state = self.states.INITIAL
+ return self
+end
+
+function AIDriveStrategyShovelSiloLoader:delete()
+ AIDriveStrategyShovelSiloLoader:superClass().delete(self)
+ if self.siloController then
+ self.siloController:delete()
+ self.siloController = nil
+ end
+ CpUtil.destroyNode(self.heapNode)
+ CpUtil.destroyNode(self.unloadNode)
+ CpUtil.destroyNode(self.unloadPositionNode)
+end
+
+function AIDriveStrategyShovelSiloLoader:getGeneratedCourse(jobParameters)
+ return nil
+end
+
+function AIDriveStrategyShovelSiloLoader:setSiloAndHeap(bunkerSilo, heapSilo)
+ self.bunkerSilo = bunkerSilo
+ self.heapSilo = heapSilo
+end
+
+function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
+
+ -- to always have a valid course (for the traffic conflict detector mainly)
+ self.course = Course.createStraightForwardCourse(self.vehicle, 25)
+ self:startCourse(self.course, 1)
+
+ self.jobParameters = jobParameters
+ local position = jobParameters.unloadPosition
+ self.unloadPositionNode = CpUtil.createNode("unloadPositionNode", position.x, position.z, position.angle )
+
+ if self.bunkerSilo ~= nil then
+ self:debug("Bunker silo was found.")
+ self.silo = self.bunkerSilo
+ else
+ self:debug("Heap was found.")
+ self.silo = self.heapSilo
+ end
+
+ self.siloController = CpBunkerSiloLoaderController(self.silo, self.vehicle, self)
+end
+
+-----------------------------------------------------------------------------------------------------------------------
+--- Implement handling
+-----------------------------------------------------------------------------------------------------------------------
+function AIDriveStrategyShovelSiloLoader:initializeImplementControllers(vehicle)
+ self:addImplementController(vehicle, MotorController, Motorized, {}, nil)
+ self:addImplementController(vehicle, WearableController, Wearable, {}, nil)
+
+ self.shovelImplement, self.shovelController = self:addImplementController(vehicle, ShovelController, Shovel, {}, nil)
+
+end
+
+--- Fuel save only allowed when no trailer is there to unload into.
+function AIDriveStrategyShovelSiloLoader:isFuelSaveAllowed()
+ return self.state == self.states.WAITING_FOR_TRAILER
+end
+
+-----------------------------------------------------------------------------------------------------------------------
+--- Static parameters (won't change while driving)
+-----------------------------------------------------------------------------------------------------------------------
+function AIDriveStrategyShovelSiloLoader:setAllStaticParameters()
+ self.reverser = AIReverseDriver(self.vehicle, self.ppc)
+ self.proximityController = ProximityController(self.vehicle, self:getWorkWidth())
+ self.proximityController:registerIgnoreObjectCallback(self, self.ignoreProximityObject)
+ self:setFrontAndBackMarkers()
+
+ self.siloEndProximitySensor = SingleForwardLookingProximitySensorPack(self.vehicle, self.shovelController:getShovelNode(), 5, 1)
+
+ self.heapNode = CpUtil.createNode("heapNode", 0, 0, 0, nil)
+ self.unloadNode = CpUtil.createNode("unloadNode", 0, 0, 0, nil)
+end
+
+-----------------------------------------------------------------------------------------------------------------------
+--- Event listeners
+-----------------------------------------------------------------------------------------------------------------------
+function AIDriveStrategyShovelSiloLoader:onWaypointPassed(ix, course)
+ if course:isLastWaypointIx(ix) then
+ if self.state == self.states.DRIVING_ALIGNMENT_COURSE then
+ local course = self:getRememberedCourseAndIx()
+ self:startCourse(course, 1)
+ self.state = self.states.DRIVING_INTO_SILO
+ elseif self.state == self.states.DRIVING_INTO_SILO then
+ self:startDrivingOutOfSilo()
+ elseif self.state == self.states.DRIVING_OUT_OF_SILO then
+ self:startPathfindingToUnloadPosition()
+ elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
+ self.state = self.states.WAITING_FOR_TRAILER
+ elseif self.state == self.states.DRIVING_TO_TRAILER then
+ local course = Course.createFromNodeToNode(self.vehicle, self.vehicle:getAIDirectionNode(), self.unloadNode,
+ 0, 0, 0, 3, false)
+ self:startCourse(course, 1)
+
+ self.state = self.states.DRIVING_TO_UNLOAD
+ elseif self.state == self.states.DRIVING_TO_UNLOAD then
+ self.state = self.states.UNLOADING
+
+ --self.vehicle:stopCurrentAIJob(AIMessageSuccessFinishedJob.new())
+ end
+ end
+end
+
+--- this the part doing the actual work on the field after/before all
+--- implements are started/lowered etc.
+function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
+ self:updateLowFrequencyImplementControllers()
+
+ local moveForwards = not self.ppc:isReversing()
+ local gx, gz
+
+ ----------------------------------------------------------------
+ if not moveForwards then
+ local maxSpeed
+ gx, gz, maxSpeed = self:getReverseDriveData()
+ self:setMaxSpeed(maxSpeed)
+ else
+ gx, _, gz = self.ppc:getGoalPointPosition()
+ end
+ if self.state == self.states.INITIAL then
+ if self.silo:getTotalFillLevel() <=0 then
+ self:debug("Stopping the driver, as the silo is empty.")
+ self.vehicle:stopCurrentAIJob(AIMessageSuccessFinishedJob.new())
+ return
+ end
+ if self.shovelController:isFull() then
+ self:startPathfindingToUnloadPosition()
+ else
+ self:startDrivingToSilo()
+ end
+ self:setMaxSpeed(0)
+ elseif self.state == self.states.DRIVING_ALIGNMENT_COURSE then
+ self:setMaxSpeed(self.settings.fieldSpeed:getValue())
+ elseif self.state == self.states.WAITING_FOR_PATHFINDER then
+ self:setMaxSpeed(0)
+ elseif self.state == self.states.DRIVING_INTO_SILO then
+ self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
+
+ local _, _, closestObject = self.siloEndProximitySensor:getClosestObjectDistanceAndRootVehicle()
+ local isEndReached, maxSpeed = self.siloController:isEndReached(self.shovelController:getShovelNode(), 0)
+ if self.silo:isTheSameSilo(closestObject) or isEndReached then
+ self:debug("End wall detected or bunker silo end is reached.")
+ self:startDrivingOutOfSilo()
+ end
+ if self.shovelController:isFull() then
+ self:debug("Shovel is full, starting to drive out of the silo.")
+ self:startDrivingOutOfSilo()
+ end
+ elseif self.state == self.states.DRIVING_OUT_OF_SILO then
+ self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
+ elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
+ self:setMaxSpeed(self.settings.fieldSpeed:getValue())
+ elseif self.state == self.states.WAITING_FOR_TRAILER then
+ self:setMaxSpeed(0)
+ self:searchForTrailerToUnloadInto()
+ elseif self.state == self.states.DRIVING_TO_TRAILER then
+ self:setMaxSpeed(self.settings.fieldSpeed:getValue())
+ elseif self.state == self.states.DRIVING_TO_UNLOAD then
+ self:setMaxSpeed(self.settings.reverseSpeed:getValue())
+ if self.shovelController:isShovelOverTrailer(self.targetTrailer.trailer) then
+ self.state = self.states.UNLOADING
+ end
+ elseif self.state == self.states.UNLOADING then
+ self:setMaxSpeed(0)
+ if self:hasFinishedUnloading() then
+ self:startDrivingToSilo()
+ end
+ end
+ if self.state.properties.shovelPosition then
+ if not self.frozen and self.shovelController:moveShovelToPosition(self.state.properties.shovelPosition) then
+ if self.state.properties.shovelMovingSpeed ~= nil then
+ self:setMaxSpeed(self.state.properties.shovelMovingSpeed)
+ end
+ end
+ end
+
+ self:limitSpeed()
+ return gx, gz, moveForwards, self.maxSpeed, 100
+end
+
+function AIDriveStrategyShovelSiloLoader:update(dt)
+ AIDriveStrategyCourse.update(self)
+ self:updateImplementControllers(dt)
+ if CpDebug:isChannelActive(CpDebug.DBG_SILO, self.vehicle) then
+ if self.course:isTemporary() then
+ self.course:draw()
+ elseif self.ppc:getCourse():isTemporary() then
+ self.ppc:getCourse():draw()
+ end
+ if self.silo then
+ self.silo:drawDebug()
+ end
+ if self.heapSilo then
+ CpUtil.drawDebugNode(self.heapNode, false, 3)
+ end
+ if self.targetTrailer then
+ CpUtil.drawDebugNode(self.unloadNode, false, 3)
+ CpUtil.drawDebugNode(self.targetTrailer.exactFillRootNode, false, 3, "ExactFillRootNode")
+ end
+ CpUtil.drawDebugNode(self.unloadPositionNode, false, 3)
+ end
+end
+
+--- Ignores the bunker silo for the proximity sensors.
+function AIDriveStrategyShovelSiloLoader:ignoreProximityObject(object, vehicle)
+ if self.silo:isTheSameSilo(object) then
+ return true
+ end
+ --- This ignores the terrain.
+ if object == nil then
+ return true
+ end
+end
+
+function AIDriveStrategyShovelSiloLoader:getProximitySensorWidth()
+ -- a bit less as size.width always has plenty of buffer
+ return self.vehicle.size.width - 0.5
+end
+
+----------------------------------------------------------------
+--- Pathfinding
+----------------------------------------------------------------
+
+--- Find an alignment path to the heap course.
+---@param course table heap course
+function AIDriveStrategyShovelSiloLoader:startPathfindingToStart(course)
+ if not self.pathfinder or not self.pathfinder:isActive() then
+ self.state = self.states.WAITING_FOR_PATHFINDER
+ self:rememberCourse(course, 1)
+
+ self.pathfindingStartedAt = g_currentMission.time
+ local done, path
+ local fm = self:getFrontAndBackMarkers()
+ self.pathfinder, done, path = PathfinderUtil.startPathfindingFromVehicleToWaypoint(
+ self.vehicle, course, 1, 0, -(fm + 4),
+ true, nil)
+ if done then
+ return self:onPathfindingDoneToStart(path)
+ else
+ self:setPathfindingDoneCallback(self, self.onPathfindingDoneToStart)
+ end
+ else
+ self:debug('Pathfinder already active')
+ end
+ return true
+end
+
+function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToStart(path)
+ if path and #path > 2 then
+ self:debug("Found alignment path to the course for the heap.")
+ local alignmentCourse = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
+ self:startCourse(alignmentCourse, 1)
+ self.state = self.states.DRIVING_ALIGNMENT_COURSE
+ else
+ local course = self:getRememberedCourseAndIx()
+ self:debug("No alignment path found!")
+ self:startCourse(course, 1)
+ self.state = self.states.DRIVING_INTO_SILO
+ end
+end
+
+
+function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
+ self:debugSparse("Searching for an trailer nearby.")
+ local function getClosestTrailerAndDistance()
+ local closestDistance = math.huge
+ local closestTrailer = nil
+ for i, vehicle in pairs(g_currentMission.vehicles) do
+ if SpecializationUtil.hasSpecialization(Trailer, vehicle.specializations) and AIUtil.isStopped(vehicle.rootVehicle) then
+ local dist = calcDistanceFrom(vehicle.rootNode, self.unloadPositionNode)
+ if dist < closestDistance then
+ closestDistance = dist
+ closestTrailer = vehicle
+ end
+ end
+ end
+ return closestTrailer, closestDistance
+ end
+ local trailer, dist = getClosestTrailerAndDistance()
+ if not trailer then
+ return
+ end
+ if dist > 20 then
+ return
+ end
+ self:debug("Found a trailer %s within distance %.2f", CpUtil.getName(trailer), dist)
+ local canLoad, fillUnitIndex, fillType, exactFillRootNode =
+ ImplementUtil.getCanLoadTo(trailer, self.shovelImplement)
+ if canLoad and exactFillRootNode ~= nil then
+ self.targetTrailer = {
+ fillUnitIndex = fillUnitIndex,
+ fillType = fillType,
+ exactFillRootNode = exactFillRootNode,
+ trailer = trailer
+ }
+ -- self:debug("Found valid trailer %s attached to %s with a distance of %.2fm to the silo front center for fill type %s in fill unit %d.",
+ -- CpUtil.getName(vehicle), CpUtil.getName(vehicle.rootVehicle),
+ -- self.maxValidTrailerDistance, g_fillTypeManager:getFillTypeTitleByIndex(fillType), fillUnitIndex)
+ self:startPathfindingToTrailer(trailer, exactFillRootNode)
+ end
+end
+
+function AIDriveStrategyShovelSiloLoader:startPathfindingToUnloadPosition()
+ if not self.pathfinder or not self.pathfinder:isActive() then
+ self.state = self.states.WAITING_FOR_PATHFINDER
+
+
+ local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
+ self.pathfindingStartedAt = g_currentMission.time
+ local done, path, goalNodeInvalid
+ self.pathfinder, done, path, goalNodeInvalid = PathfinderUtil.startPathfindingFromVehicleToNode(
+ self.vehicle, self.unloadPositionNode,
+ 0, -2*spaceToTrailer, true,
+ nil, {}, nil,
+ 0, nil, true
+ )
+ if done then
+ return self:onPathfindingDoneToUnloadPosition(path, goalNodeInvalid)
+ else
+ self:setPathfindingDoneCallback(self, self.onPathfindingDoneToUnloadPosition)
+ end
+ else
+ self:debug('Pathfinder already active')
+ end
+ return true
+end
+
+function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path, goalNodeInvalid)
+ if path and #path > 2 then
+ self:debug("Found path to unloading station.")
+ local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
+ self:startCourse(course, 1)
+ self.state = self.states.DRIVING_TO_UNLOAD_POSITION
+ else
+ self:debug("Failed to drive close to unload position.")
+ self.state = self.states.WAITING_FOR_TRAILER
+ end
+end
+
+--- Find an alignment path to the heap course.
+function AIDriveStrategyShovelSiloLoader:startPathfindingToTrailer(trailer, exactFillRootNode)
+ if not self.pathfinder or not self.pathfinder:isActive() then
+ self.state = self.states.WAITING_FOR_PATHFINDER
+ local dx, _, _ = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
+
+ local loadingLeftSide = dx > 0
+
+ local x, y, z = localToLocal(exactFillRootNode, trailer.rootNode, 0, 0, 0)
+
+ local gx, gy, gz = localToWorld(trailer.rootNode, x, y, z)
+ local dirX, dirZ = localDirectionToWorld(trailer.rootNode, loadingLeftSide and 1 or -1, 0, 0)
+ local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
+ setTranslation(self.unloadNode, gx, gy, gz)
+ setRotation(self.unloadNode, 0, yRot, 0)
+
+ local spaceToTrailer = math.max(self.turningRadius, self.safeSpaceToTrailer)
+
+ self.pathfindingStartedAt = g_currentMission.time
+ local done, path, goalNodeInvalid
+ self.pathfinder, done, path, goalNodeInvalid = PathfinderUtil.startPathfindingFromVehicleToNode(
+ self.vehicle, self.unloadNode,
+ 0, -spaceToTrailer, true,
+ nil, {}, nil,
+ 0, nil, true
+ )
+ if done then
+ return self:onPathfindingDoneToTrailer(path, goalNodeInvalid)
+ else
+ self:setPathfindingDoneCallback(self, self.onPathfindingDoneToTrailer)
+ end
+ else
+ self:debug('Pathfinder already active')
+ end
+ return true
+end
+
+function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToTrailer(path, goalNodeInvalid)
+ if path and #path > 2 then
+ self:debug("Found alignment path to trailer.")
+ local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
+ self:startCourse(course, 1)
+ self.state = self.states.DRIVING_TO_TRAILER
+ else
+ self:debug("Failed to find valid path to trailer!")
+ self.state = self.sates.WAITING_FOR_TRAILER
+ end
+end
+
+----------------------------------------------------------------
+--- Silo work
+----------------------------------------------------------------
+
+function AIDriveStrategyShovelSiloLoader:startDrivingToSilo()
+ local startPos, endPos = self.siloController:getTarget(self:getWorkWidth())
+ local x, z = unpack(startPos)
+ local dx, dz = unpack(endPos)
+
+ local siloCourse = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
+ 0, 0, 3, 3, false)
+
+
+ local distance = siloCourse:getDistanceBetweenVehicleAndWaypoint(self.vehicle, 1)
+
+ if distance > 2 * self.turningRadius then
+ self:debug("Start driving to silo with pathfinder.")
+ self:startPathfindingToStart(siloCourse)
+ else
+ self:debug("Start driving into the silo.")
+ self:startCourse(siloCourse, 1)
+ self.state = self.states.DRIVING_INTO_SILO
+ end
+end
+
+function AIDriveStrategyShovelSiloLoader:startDrivingOutOfSilo()
+ local startPos, endPos = self.siloController:getLastTarget()
+ local x, z = unpack(endPos)
+ local dx, dz = unpack(startPos)
+
+ local reverseCourse = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
+ 0, 0, 6, 3, true)
+ local ix = reverseCourse:getNextRevWaypointIxFromVehiclePosition(1, self.vehicle:getAIDirectionNode(), 10)
+ if ix == 1 then
+ ix = reverseCourse:getNumberOfWaypoints()
+ end
+ self:startCourse(reverseCourse, ix)
+ self.state = self.states.DRIVING_OUT_OF_SILO
+end
+
+function AIDriveStrategyShovelSiloLoader:getWorkWidth()
+ return self.settings.bunkerSiloWorkWidth:getValue()
+end
+
+----------------------------------------------------------------
+--- Unloading
+----------------------------------------------------------------
+function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
+ if self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
+ self:debug("Trailer is full, abort unloading into trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
+ return true
+ end
+ if self.shovelController:isEmpty() then
+ self:debug("Finished unloading, as the shovel is empty.")
+ return true
+ end
+
+ return false
+end
+
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index 8536cd752..c7cf60699 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -407,6 +407,9 @@ function ImplementUtil.getLevelerNode(object)
return object.spec_leveler and object.spec_leveler.nodes and object.spec_leveler.nodes[1] and object.spec_leveler.nodes[1]
end
+--- Visually displays the bale collector offset
+---@param vehicle table
+---@param offset number
function ImplementUtil.showBaleCollectorOffset(vehicle, offset)
local implement = AIUtil.getImplementWithSpecialization(vehicle, BaleLoader)
if not implement then
@@ -417,4 +420,62 @@ function ImplementUtil.showBaleCollectorOffset(vehicle, offset)
local dx, dy, dz = localToWorld(vehicle:getAIDirectionNode(), -offset, 3, 2)
DebugUtil.drawDebugLine(x, y, z, dx, dy, dz, 1, 0, 0)
end
-end
\ No newline at end of file
+end
+
+--- Checks if loading from an implement to another is possible.
+---@param loadTargetImplement table
+---@param implementToLoadFrom table
+---@param dischargeNode table|nil optional otherwise the current selected node is used.
+---@param suppressLog boolean|nil
+---@return boolean is loading possible?
+---@return number|nil target implement fill unit ix to load into.
+---@return number|nil fill type to load
+---@return number|nil target exact fill root node
+function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, dischargeNode, suppressLog)
+
+ local function debug(str, ...)
+ if not suppressLog then
+ CpUtil.debugVehicle(CpDebug.DBG_SILO, implementToLoadFrom.rootVehicle,
+ str, ...)
+ end
+ end
+
+ if dischargeNode == nil then
+ dischargeNode = implementToLoadFrom:getCurrentDischargeNode()
+ end
+ if dischargeNode == nil then
+ debug("No valid discharge node found!")
+ return false, nil, nil, nil
+ end
+
+ local fillType = implementToLoadFrom:getDischargeFillType(dischargeNode)
+
+ if fillType == nil or fillType == FillType.UNKNOWN then
+ debug("No valid fill type to load!")
+ return false, nil, nil, nil
+ end
+
+ local validTarget, targetFillUnitIndex, exactFillRootNode
+ for fillUnitIndex, fillUnit in pairs(loadTargetImplement:getFillUnits()) do
+ if loadTargetImplement:getFillUnitSupportsFillType(fillUnitIndex, fillType) then
+ if loadTargetImplement:getFillUnitAllowsFillType(fillUnitIndex, fillType) then
+ if loadTargetImplement.getFillUnitFreeCapacity == nil or loadTargetImplement:getFillUnitFreeCapacity(fillUnitIndex, fillType, implementToLoadFrom:getActiveFarm()) > 0 then
+ if loadTargetImplement.getIsFillAllowedFromFarm == nil or loadTargetImplement:getIsFillAllowedFromFarm(implementToLoadFrom:getActiveFarm()) then
+ validTarget, targetFillUnitIndex, exactFillRootNode = true, fillUnitIndex, loadTargetImplement:getFillUnitExactFillRootNode(fillUnitIndex)
+ else
+ debug("Fill unit(%d) filling to target farm %s from %s not allowed!", fillUnitIndex, loadTargetImplement:getOwnerFarmId(), implementToLoadFrom:getActiveFarm())
+ end
+ else
+ debug("Fill unit(%d) is full with fill type %s!", fillUnitIndex, g_fillTypeManager:getFillTypeTitleByIndex(fillType))
+ end
+ else
+ debug("Fill unit(%d) doesn't allow fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeTitleByIndex(fillType))
+ end
+ else
+ debug("Fill unit(%d) doesn't support fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeTitleByIndex(fillType))
+ end
+ end
+
+ return validTarget, targetFillUnitIndex, fillType, exactFillRootNode
+end
+
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 7a840dd6e..adc7efd12 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -1,6 +1,14 @@
---@class ShovelController : ImplementController
ShovelController = CpObject(ImplementController)
+ShovelController.POSITIONS = {
+ DEACTIVATED = 0,
+ LOADING = 1,
+ TRANSPORT = 2,
+ PRE_UNLOADING = 3,
+ UNLOADING = 4,
+}
+
function ShovelController:init(vehicle, implement)
ImplementController.init(self, vehicle, implement)
self.shovelSpec = self.implement.spec_shovel
@@ -16,11 +24,11 @@ function ShovelController:getShovelNode()
end
function ShovelController:isFull()
- return self:getFillLevelPercentage() >= 0.98
+ return self:getFillLevelPercentage() >= 99
end
function ShovelController:isEmpty()
- return self:getFillLevelPercentage() <= 0.01
+ return self:getFillLevelPercentage() <= 1
end
function ShovelController:getFillLevelPercentage()
@@ -40,6 +48,48 @@ function ShovelController:getShovelFillType()
return self.shovelSpec.loadingFillType
end
-function ShovelController:isReadyToLoad()
- return self:getShovelFillType() == FillType.UNKNOWN and self:getFillLevelPercentage() < 0.5
-end
\ No newline at end of file
+function ShovelController:getDischargeFillType()
+ return self.implement:getDischargeFillType(self:getDischargeNode())
+end
+
+function ShovelController:getDischargeNode()
+ return self.implement:getCurrentDischargeNode()
+end
+
+--- Is the shovel node over the trailer?
+---@param trailer table
+---@param margin number|nil
+---@return boolean
+function ShovelController:isShovelOverTrailer(trailer, margin)
+ local node = self:getShovelNode()
+ local x, y, z = localToLocal(trailer.rootNode, node, 0, 0, 0)
+ margin = margin or 0
+ return z < margin
+end
+
+function ShovelController:moveShovelToLoadingPosition()
+ return self:moveShovelToPosition(self.POSITIONS.LOADING)
+end
+
+function ShovelController:moveShovelToTransportPosition()
+ return self:moveShovelToPosition(self.POSITIONS.TRANSPORT)
+end
+
+function ShovelController:moveShovelToPreUnloadPosition()
+ return self:moveShovelToPosition(self.POSITIONS.PRE_UNLOADING)
+end
+
+function ShovelController:moveShovelToUnloadPosition()
+ return self:moveShovelToPosition(self.POSITIONS.UNLOADING)
+end
+
+function ShovelController:onFinished()
+ self.implement:cpResetShovelState()
+end
+
+---@param pos number shovel position 1-4
+---@return boolean reached?
+function ShovelController:moveShovelToPosition(pos)
+ self.implement:cpSetShovelState(pos)
+ return self.implement:areCpShovelPositionsDirty()
+end
diff --git a/scripts/ai/jobs/CpAIJob.lua b/scripts/ai/jobs/CpAIJob.lua
index 9d36dfb35..4212b4ace 100644
--- a/scripts/ai/jobs/CpAIJob.lua
+++ b/scripts/ai/jobs/CpAIJob.lua
@@ -364,8 +364,8 @@ function CpAIJob.registerJob(AIJobTypeManager)
AIJobTypeManager:registerJobType(CpAIJobBaleFinder.name, CpAIJobBaleFinder.jobName, CpAIJobBaleFinder)
AIJobTypeManager:registerJobType(CpAIJobFieldWork.name, CpAIJobFieldWork.jobName, CpAIJobFieldWork)
AIJobTypeManager:registerJobType(CpAIJobCombineUnloader.name, CpAIJobCombineUnloader.jobName, CpAIJobCombineUnloader)
- AIJobTypeManager:registerJobType(CpAIJobBunkerSilo.name, CpAIJobBunkerSilo.jobName, CpAIJobBunkerSilo)
AIJobTypeManager:registerJobType(CpAIJobSiloLoader.name, CpAIJobSiloLoader.jobName, CpAIJobSiloLoader)
+ AIJobTypeManager:registerJobType(CpAIJobBunkerSilo.name, CpAIJobBunkerSilo.jobName, CpAIJobBunkerSilo)
end
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 60499cae4..d3640814c 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -36,6 +36,7 @@ function CpAIJobSiloLoader:setupJobParameters()
CpAIJobSiloLoader:superClass().setupJobParameters(self)
self:setupCpJobParameters(CpSiloLoaderJobParameters(self))
self.cpJobParameters.loadPosition:setSnappingAngle(math.pi/8) -- AI menu snapping angle of 22.5 degree.
+ self.cpJobParameters.unloadPosition:setSnappingAngle(math.pi/8) -- AI menu snapping angle of 22.5 degree.
end
function CpAIJobSiloLoader:getIsAvailableForVehicle(vehicle)
@@ -68,6 +69,14 @@ function CpAIJobSiloLoader:applyCurrentState(vehicle, mission, farmId, isDirectS
self.cpJobParameters.loadPosition:setPosition(x, z)
self.cpJobParameters.loadPosition:setAngle(angle)
end
+
+ local x, z = self.cpJobParameters.unloadPosition:getPosition()
+
+ -- no unload position use the vehicle's current position
+ if x == nil or z == nil then
+ x, _, z = getWorldTranslation(vehicle.rootNode)
+ self.cpJobParameters.unloadPosition:setPosition(x, z)
+ end
end
@@ -121,6 +130,14 @@ function CpAIJobSiloLoader:validate(farmId)
return false, g_i18n:getText("CP_error_no_heap_found")
end
+ if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
+ --- Validate the trigger setup
+ local found, unloadStation = self:getUnloadTriggerAt(self.cpJobParameters.unloadPosition)
+
+ return false, g_i18n:getText("CP_error_no_unload_trigger_found")
+ end
+
+
return isValid, errorMessage
end
@@ -147,7 +164,32 @@ function CpAIJobSiloLoader:getBunkerSiloOrHeap(loadPosition, node)
return found, nil, heapSilo
end
+--- Gets the unload trigger at the unload position.
+---@param unloadPosition CpAIParameterPositionAngle
+---@return boolean
+---@return table|nil
+function CpAIJobSiloLoader:getUnloadTriggerAt(unloadPosition)
+ local x, z = unloadPosition:getPosition()
+ local angle = unloadPosition:getAngle()
+ if x == nil or angle == nil then
+ return false
+ end
+ return false
+end
+
function CpAIJobSiloLoader:drawSilos(map)
self.heapPlot:draw(map)
g_bunkerSiloManager:drawSilos(map, self.bunkerSilo)
-end
\ No newline at end of file
+end
+
+
+--- Gets the giants unload station.
+function CpAIJobSiloLoader:getUnloadingStations()
+ local unloadingStations = {}
+ for _, unloadingStation in pairs(g_currentMission.storageSystem:getUnloadingStations()) do
+ if g_currentMission.accessHandler:canPlayerAccess(unloadingStation) and unloadingStation:isa(UnloadingStation) then
+ table.insert(unloadingStations, unloadingStation)
+ end
+ end
+ return unloadingStations
+end
diff --git a/scripts/ai/jobs/CpJobParameters.lua b/scripts/ai/jobs/CpJobParameters.lua
index 58e4bf271..9fec909c1 100644
--- a/scripts/ai/jobs/CpJobParameters.lua
+++ b/scripts/ai/jobs/CpJobParameters.lua
@@ -127,6 +127,16 @@ function CpJobParameters:isBunkerSiloHudModeDisabled()
return self:isAIMenuJob()
end
+function CpJobParameters:isSiloLoadingHudModeDisabled()
+ local vehicle = self.job:getVehicle()
+ if vehicle then
+ if not vehicle:getCanStartCpSiloLoaderWorker() then
+ return true
+ end
+ end
+ return self:isAIMenuJob()
+end
+
--- Callback raised by a setting and executed as an vehicle event.
---@param callbackStr string event to be raised
---@param setting AIParameterSettingList setting that raised the callback.
@@ -137,7 +147,6 @@ function CpJobParameters:raiseCallback(callbackStr, setting, ...)
end
end
-
function CpJobParameters:__tostring()
return tostring(self.settings)
end
@@ -311,6 +320,9 @@ end
--- AI parameters for the bunker silo job.
---@class CpSiloLoaderJobParameters : CpJobParameters
+---@field unloadAt AIParameterSettingList
+---@field UNLOAD_TRAILER number
+---@field UNLOAD_TRIGGER number
CpSiloLoaderJobParameters = CpObject(CpJobParameters)
function CpSiloLoaderJobParameters:init(job)
@@ -326,3 +338,34 @@ end
function CpSiloLoaderJobParameters.getSettings(vehicle)
return vehicle.spec_cpAISiloLoaderWorker.cpJob:getCpJobParameters()
end
+
+function CpSiloLoaderJobParameters:isShovelSiloLoadDisabled()
+ local vehicle = self.job:getVehicle()
+ if vehicle then
+ return AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt)
+ end
+ return false
+end
+
+function CpSiloLoaderJobParameters:isUnloadPositionDisabled()
+ return self:isShovelSiloLoadDisabled() or self.unloadAt == CpSiloLoaderJobParameters.UNLOAD_TRAILER
+end
+
+function CpSiloLoaderJobParameters:isUnloadStationDisabled()
+ return true
+end
+
+function CpSiloLoaderJobParameters:generateUnloadingStations(setting, oldIx)
+ local unloadingStationIds = {}
+ local texts = {}
+ table.insert(unloadingStationIds, -1)
+ table.insert(texts, "---")
+ if self.job then
+ for i, unloadingStation in ipairs(self.job:getUnloadingStations()) do
+ local id = NetworkUtil.getObjectId(unloadingStation)
+ table.insert(unloadingStationIds, id)
+ table.insert(texts, unloadingStation:getName() or "")
+ end
+ end
+ return unloadingStationIds, texts, oldIx
+end
\ No newline at end of file
diff --git a/scripts/ai/parameters/CpAIParameterPositionAngle.lua b/scripts/ai/parameters/CpAIParameterPositionAngle.lua
index 46ccc8b02..dbdac4b0a 100644
--- a/scripts/ai/parameters/CpAIParameterPositionAngle.lua
+++ b/scripts/ai/parameters/CpAIParameterPositionAngle.lua
@@ -121,7 +121,8 @@ CpAIParameterPositionAngle = CpObject(CpAIParameterPosition)
CpAIParameterPositionAngle.POSITION_TYPES = {
DRIVE_TO = 0, --- with angle
FIELD_OR_SILO = 1, --- without angle
- UNLOAD = 2 --- with angle
+ UNLOAD = 2, --- with angle
+ LOAD = 3 --- with angle
}
---@param data table
---@param vehicle table
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index 99f2d296d..b7d393fec 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -122,6 +122,8 @@ function CpInGameMenuAIFrameExtended:onAIFrameLoadMapFinished()
self.unloadAiTargetMapHotspot = AITargetHotspot.new()
+ self.loadAiTargetMapHotspot = AITargetHotspot.new()
+
self.ingameMap.onClickHotspotCallback = Utils.appendedFunction(self.ingameMap.onClickHotspotCallback,
CpInGameMenuAIFrameExtended.onClickHotspot)
@@ -321,6 +323,7 @@ end
function CpInGameMenuAIFrameExtended:setMapSelectionItem(hotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.aiTargetMapHotspot)
if hotspot ~= nil then
local vehicle = InGameMenuMapUtil.getHotspotVehicle(hotspot)
@@ -353,6 +356,10 @@ function CpInGameMenuAIFrameExtended:setMapSelectionItem(hotspot)
if param:applyToMapHotspot(self.aiUnloadingMarkerHotspot) then
g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
end
+ elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
+ if param:applyToMapHotspot(self.loadAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.loadAiTargetMapHotspot)
+ end
end
end
end
@@ -401,6 +408,7 @@ function CpInGameMenuAIFrameExtended:onAIFrameClose()
self.lastHotspot = self.currentHotspot
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
CpInGameMenuAIFrameExtended.unbindCourseGeneratorSettings(self)
g_currentMission.inGameMenu:updatePages()
end
@@ -473,9 +481,36 @@ function CpInGameMenuAIFrameExtended:delete()
self.unloadAiTargetMapHotspot = nil
end
+ if self.loadAiTargetMapHotspot ~= nil then
+ self.loadAiTargetMapHotspot:delete()
+
+ self.loadAiTargetMapHotspot = nil
+ end
end
InGameMenuAIFrame.delete = Utils.appendedFunction(InGameMenuAIFrame.delete,CpInGameMenuAIFrameExtended.delete)
+
+function CpInGameMenuAIFrameExtended:onClickPositionParameter(superFunc, element, ...)
+ local parameter = element.aiParameter
+ if parameter:getCanBeChanged() then
+ --- Checks if the position setting is not disabled
+ superFunc(self, element, ...)
+ end
+end
+InGameMenuAIFrame.onClickPositionParameter = Utils.overwrittenFunction(
+ InGameMenuAIFrame.onClickPositionParameter, CpInGameMenuAIFrameExtended.onClickPositionParameter)
+
+function CpInGameMenuAIFrameExtended:onClickPositionRotationParameter(superFunc, element, ...)
+ local parameter = element.aiParameter
+ if parameter:getCanBeChanged() then
+ --- Checks if the position setting is not disabled
+ superFunc(self, element, ...)
+ end
+end
+InGameMenuAIFrame.onClickPositionRotationParameter = Utils.overwrittenFunction(
+ InGameMenuAIFrame.onClickPositionRotationParameter, CpInGameMenuAIFrameExtended.onClickPositionRotationParameter)
+
+
--- Ugly hack to swap the main AI hotspot with the field position hotspot,
--- as only the main hotspot can be moved by the player.
function CpInGameMenuAIFrameExtended:startPickingPosition(superFunc, parameter, callback, ...)
@@ -492,6 +527,11 @@ function CpInGameMenuAIFrameExtended:startPickingPosition(superFunc, parameter,
self.aiTargetMapHotspot = self.unloadAiTargetMapHotspot
self.unloadAiTargetMapHotspot = mapHotspot
self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD
+ elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
+ local mapHotspot = self.aiTargetMapHotspot
+ self.aiTargetMapHotspot = self.loadAiTargetMapHotspot
+ self.loadAiTargetMapHotspot = mapHotspot
+ self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.LOAD
end
end
callback = Utils.appendedFunction(callback,function (finished, x, z)
@@ -500,8 +540,11 @@ function CpInGameMenuAIFrameExtended:startPickingPosition(superFunc, parameter,
superFunc(self, parameter, callback, ...)
end
-InGameMenuAIFrame.startPickPosition = Utils.overwrittenFunction(InGameMenuAIFrame.startPickPosition,CpInGameMenuAIFrameExtended.startPickingPosition)
-InGameMenuAIFrame.startPickPositionAndRotation = Utils.overwrittenFunction(InGameMenuAIFrame.startPickPositionAndRotation,CpInGameMenuAIFrameExtended.startPickingPosition)
+InGameMenuAIFrame.startPickPosition = Utils.overwrittenFunction(InGameMenuAIFrame.startPickPosition,
+ CpInGameMenuAIFrameExtended.startPickingPosition)
+
+InGameMenuAIFrame.startPickPositionAndRotation = Utils.overwrittenFunction(InGameMenuAIFrame.startPickPositionAndRotation,
+ CpInGameMenuAIFrameExtended.startPickingPosition)
function CpInGameMenuAIFrameExtended:resetHotspots()
if self.currentPickingMapHotspotType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
@@ -528,6 +571,7 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
g_currentMission:removeMapHotspot(self.aiUnloadingMarkerHotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
local parameterType = parameter:getType()
@@ -550,6 +594,10 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
if parameter:applyToMapHotspot(self.unloadAiTargetMapHotspot) then
g_currentMission:addMapHotspot(self.unloadAiTargetMapHotspot)
end
+ elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
+ if parameter:applyToMapHotspot(self.loadAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.loadAiTargetMapHotspot)
+ end
end
elseif parameterType == AIParameterType.POSITION or parameterType == AIParameterType.POSITION_ANGLE then
element:setText(parameter:getString())
diff --git a/scripts/gui/CpGamePadHudScreen.lua b/scripts/gui/CpGamePadHudScreen.lua
index 276724dfe..f5950b3e9 100644
--- a/scripts/gui/CpGamePadHudScreen.lua
+++ b/scripts/gui/CpGamePadHudScreen.lua
@@ -260,7 +260,9 @@ end
function CpGamePadHudSiloLoaderScreen:update(dt, ...)
CpGamePadHudSiloLoaderScreen:superClass().update(self, dt, ...)
-
+ if not self.vehicle:getCanStartCpSiloLoaderWorker() or self.vehicle:getCpStartingPointSetting():getValue() ~= CpJobParameters.START_AT_SILO_LOADING then
+ self.vehicle:reopenCpGamePadHud()
+ end
end
function CpGamePadHudSiloLoaderScreen:drawWorkWidth()
diff --git a/scripts/gui/hud/CpBaseHud.lua b/scripts/gui/hud/CpBaseHud.lua
index 9e3df27a4..e4383ef88 100644
--- a/scripts/gui/hud/CpBaseHud.lua
+++ b/scripts/gui/hud/CpBaseHud.lua
@@ -425,9 +425,12 @@ function CpBaseHud:getActiveHudPage(vehicle)
elseif vehicle:getCanStartCpBaleFinder() and not vehicle:hasCpCourse() then
return self.baleFinderLayout
elseif vehicle:getCanStartCpBunkerSiloWorker() and vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
- or AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler) then
+ or (AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
+ and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)) then
return self.bunkerSiloWorkerLayout
- elseif vehicle:getCanStartCpSiloLoaderWorker() then
+ elseif vehicle:getCanStartCpSiloLoaderWorker() and
+ (AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) or
+ vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING) then
return self.siloLoaderWorkerLayout
else
return self.fieldworkLayout
diff --git a/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua b/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua
index b61ee59c4..dc5489420 100644
--- a/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua
+++ b/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua
@@ -101,5 +101,11 @@ function CpBunkerSiloWorkerHudPageElement:updateContent(vehicle, status)
end
function CpBunkerSiloWorkerHudPageElement:isStartingPointBtnDisabled(vehicle)
- return AIUtil.hasAIImplementWithSpecialization(vehicle, Leveler)
+ return AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
+ and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)
+
end
+
+function CpBunkerSiloWorkerHudPageElement:getStartingPointBtnText(vehicle)
+ return vehicle:getCpStartingPointSetting():getString()
+end
\ No newline at end of file
diff --git a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
index d6af9cdbd..e8e7aaec6 100644
--- a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
+++ b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
@@ -145,4 +145,12 @@ function CpSiloLoaderWorkerHudPageElement:arePositionEqual(parameters, otherPara
return false
end
return true
+end
+
+function CpSiloLoaderWorkerHudPageElement:isStartingPointBtnDisabled(vehicle)
+ return AIUtil.hasAIImplementWithSpecialization(vehicle, ConveyorBelt)
+end
+
+function CpSiloLoaderWorkerHudPageElement:getStartingPointBtnText(vehicle)
+ return vehicle:getCpStartingPointSetting():getString()
end
\ No newline at end of file
diff --git a/scripts/pathfinder/PathfinderUtil.lua b/scripts/pathfinder/PathfinderUtil.lua
index 29a5c062d..4565bfa01 100644
--- a/scripts/pathfinder/PathfinderUtil.lua
+++ b/scripts/pathfinder/PathfinderUtil.lua
@@ -663,8 +663,21 @@ function PathfinderUtil.initializeTrailerHeading(start, vehicleData)
end
end
----@param start State3D
+---@param vehicle table
---@param goal State3D
+---@param allowReverse boolean
+---@param fieldNum number|nil
+---@param vehiclesToIgnore table|nil
+---@param objectsToIgnore table|nil
+---@param maxFruitPercent number|nil
+---@param offFieldPenalty number|nil
+---@param areaToAvoid PathfinderUtil.Area|nil
+---@param mustBeAccurate boolean|nil
+---@param areaToIgnoreFruit PathfinderUtil.Area|nil
+---@return PathfinderInterface pathfinder
+---@return boolean done finished pathfinding?
+---@return table|nil path that was found?
+---@return boolean|nil goalNodeInvalid
function PathfinderUtil.startPathfindingFromVehicleToGoal(vehicle, goal,
allowReverse, fieldNum,
vehiclesToIgnore, objectsToIgnore,
@@ -789,6 +802,10 @@ end
--- in front of the vehicle when it stops working on that row before the turn starts. Negative values mean the
--- vehicle is towing the implements and is past the end of the row when the implement reaches the end of the row.
---@param turnOnField boolean is turn on field allowed?
+---@return PathfinderInterface pathfinder
+---@return boolean done finished pathfinding?
+---@return table|nil path that was found?
+---@return boolean|nil goalNodeInvalid
function PathfinderUtil.findPathForTurn(vehicle, startOffset, goalReferenceNode, goalOffset, turnRadius, allowReverse,
courseWithHeadland, workingWidth, backMarkerDistance, turnOnField)
local x, z, yRot = PathfinderUtil.getNodePositionAndDirection(vehicle:getAIDirectionNode(), 0, startOffset or 0)
@@ -839,6 +856,8 @@ end
---@param zOffset number offset in meters relative to the goal node (forward positive, backward negative)
--- Together with the goalReferenceNode defines the goal
---@param turnRadius number vehicle turning radius
+---@return table|nil path
+---@return number length
function PathfinderUtil.findAnalyticPath(solver, vehicleDirectionNode, startOffset, goalReferenceNode,
xOffset, zOffset, turnRadius)
local x, z, yRot = PathfinderUtil.getNodePositionAndDirection(vehicleDirectionNode, 0, startOffset or 0)
@@ -902,6 +921,10 @@ end
---@param offFieldPenalty number penalty to apply to nodes off the field
---@param areaToAvoid PathfinderUtil.NodeArea nodes in this area will be penalized so the path will most likely avoid it
---@param areaToIgnoreFruit PathfinderUtil.Area area to ignore fruit
+---@return PathfinderInterface pathfinder
+---@return boolean done finished pathfinding?
+---@return table|nil path that was found?
+---@return boolean|nil goalNodeInvalid
function PathfinderUtil.startPathfindingFromVehicleToWaypoint(vehicle, course, goalWaypointIx,
xOffset, zOffset, allowReverse,
fieldNum, vehiclesToIgnore, maxFruitPercent,
@@ -927,6 +950,10 @@ end
---@param offFieldPenalty number|nil penalty to apply to nodes off the field
---@param areaToAvoid PathfinderUtil.NodeArea|nil nodes in this area will be penalized so the path will most likely avoid it
---@param mustBeAccurate boolean|nil must be accurately find the goal position/angle (optional)
+---@return PathfinderInterface pathfinder
+---@return boolean done finished pathfinding?
+---@return table|nil path that was found?
+---@return boolean|nil goalNodeInvalid
function PathfinderUtil.startPathfindingFromVehicleToNode(vehicle, goalNode,
xOffset, zOffset, allowReverse,
fieldNum, vehiclesToIgnore, maxFruitPercent,
@@ -948,6 +975,10 @@ end
---@param fieldNum number if other than 0 or nil the pathfinding is restricted to the given field and its vicinity
---@param vehiclesToIgnore table[] list of vehicles to ignore for the collision detection (optional)
---@param maxFruitPercent number maximum percentage of fruit present before a node is marked as invalid (optional)
+---@return PathfinderInterface pathfinder
+---@return boolean done finished pathfinding?
+---@return table|nil path that was found?
+---@return boolean|nil goalNodeInvalid
function PathfinderUtil.startAStarPathfindingFromVehicleToNode(vehicle, goalNode,
xOffset, zOffset,
fieldNum, vehiclesToIgnore, maxFruitPercent)
diff --git a/scripts/silo/BunkerSiloWrapper.lua b/scripts/silo/BunkerSiloWrapper.lua
index 6c6062985..7ef3fc4f0 100644
--- a/scripts/silo/BunkerSiloWrapper.lua
+++ b/scripts/silo/BunkerSiloWrapper.lua
@@ -65,68 +65,98 @@ function CpSilo:init(sx, sz, wx, wz, hx, hz)
end
+---@return number sx
+---@return number sz
function CpSilo:getStartPosition()
return self.sx, self.sz
end
+---@return number wx
+---@return number wz
function CpSilo:getWidthPosition()
return self.wx, self.wz
end
+---@return number hx
+---@return number hz
function CpSilo:getHeightPosition()
return self.hx, self.hz
end
+---@return number width
function CpSilo:getWidth()
return self.width
end
+---@return number length
function CpSilo:getLength()
return self.length
end
+---@return number dirX
+---@return number dirZ
function CpSilo:getLengthDirection()
return self.dirXLength, self.dirZLength
end
+---@return number dirX
+---@return number dirZ
function CpSilo:getWidthDirection()
return self.dirXWidth, self.dirZWidth
end
+---@return number cx
+---@return number cz
function CpSilo:getCenter()
local cx, cz = self:getFrontCenter()
return cx + self.dirXLength * self.length/2, cz + self.dirZLength * self.length/2
end
+---@return number fcx
+---@return number fcz
function CpSilo:getFrontCenter()
local width = self:getWidth()
return self.sx + self.dirXWidth * width/2, self.sz + self.dirZWidth * width/2
end
+---@return number bcx
+---@return number bcz
function CpSilo:getBackCenter()
local length = self:getLength()
local fcx, fcz = self:getFrontCenter()
return fcx + self.dirXLength * length/2, fcz + self.dirZLength * length/2
end
---- Is the point directly in the silo area.
+--- Is the point directly in the silo area?
+---@param x number
+---@param z number
+---@return boolean
function CpSilo:isPointInSilo(x, z)
return self:isPointInArea(x, z, self.area)
end
+---@param node number
+---@return boolean
function CpSilo:isNodeInSilo(node)
local x, _, z = getWorldTranslation(node)
return self:isPointInArea(x, z, self.area)
end
+---@param vehicle table
+---@return boolean
function CpSilo:isVehicleInSilo(vehicle)
return self:isNodeInSilo(vehicle.rootNode)
end
+---@param x number
+---@param z number
+---@param area table
+---@return boolean
function CpSilo:isPointInArea(x, z, area)
return CpMathUtil.isPointInPolygon(area, x, z)
end
+---@return table area
function CpSilo:getArea()
return self.area
end
@@ -388,6 +418,14 @@ function CpBunkerSilo:getNode()
return self.silo.interactionTriggerNode
end
+function CpBunkerSilo:getFillType()
+ return self.silo.outputFillType
+end
+
+function CpBunkerSilo:getTotalFillLevel()
+ return self.silo.fillLevel
+end
+
function CpBunkerSilo:delete()
for _, controller in pairs(self.controllers) do
controller:setBunkerSiloInvalid()
diff --git a/scripts/specializations/CpAIBaleFinder.lua b/scripts/specializations/CpAIBaleFinder.lua
index 535e1197e..d0ba354c3 100644
--- a/scripts/specializations/CpAIBaleFinder.lua
+++ b/scripts/specializations/CpAIBaleFinder.lua
@@ -135,9 +135,9 @@ function CpAIBaleFinder:getCanStartCp(superFunc)
end
--- Only use the bale finder, if the cp field work job is not possible.
-function CpAIBaleFinder:getCpStartableJob(superFunc)
+function CpAIBaleFinder:getCpStartableJob(superFunc, ...)
local spec = self.spec_cpAIBaleFinder
- return superFunc(self) or self:getCanStartCpBaleFinder() and spec.cpJob
+ return superFunc(self, ...) or self:getCanStartCpBaleFinder() and spec.cpJob
end
function CpAIBaleFinder:getCpStartText(superFunc)
diff --git a/scripts/specializations/CpAIBunkerSiloWorker.lua b/scripts/specializations/CpAIBunkerSiloWorker.lua
index 6b73042db..2a6828256 100644
--- a/scripts/specializations/CpAIBunkerSiloWorker.lua
+++ b/scripts/specializations/CpAIBunkerSiloWorker.lua
@@ -98,8 +98,11 @@ function CpAIBunkerSiloWorker:getCanStartCpBunkerSiloWorker()
return not self:getCanStartCpFieldWork()
and not self:getCanStartCpBaleFinder()
and not self:getCanStartCpCombineUnloader()
- and not self:getCanStartCpSiloLoaderWorker()
- and (not self:hasCpCourse() or AIUtil.hasChildVehicleWithSpecialization(self, Leveler, nil))
+
+ and (not self:hasCpCourse() or
+ AIUtil.hasChildVehicleWithSpecialization(self, Leveler))
+ and not (AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
+ and AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt))
end
function CpAIBunkerSiloWorker:getCanStartCp(superFunc)
@@ -109,10 +112,10 @@ end
function CpAIBunkerSiloWorker:getCpStartableJob(superFunc, isStartedByHud)
local spec = self.spec_cpAIBunkerSiloWorker
local job = self:getCanStartCpBunkerSiloWorker() and spec.cpJob
- if isStartedByHud and not AIUtil.hasChildVehicleWithSpecialization(self, Leveler) then
+ if isStartedByHud then
job = self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO and job
end
- return superFunc(self) or job
+ return superFunc(self, isStartedByHud) or job
end
function CpAIBunkerSiloWorker:getCpStartText(superFunc)
diff --git a/scripts/specializations/CpAICombineUnloader.lua b/scripts/specializations/CpAICombineUnloader.lua
index ced1a7148..1a1d20bfe 100644
--- a/scripts/specializations/CpAICombineUnloader.lua
+++ b/scripts/specializations/CpAICombineUnloader.lua
@@ -215,9 +215,9 @@ function CpAICombineUnloader:getCanStartCp(superFunc)
return superFunc(self) or self:getCanStartCpCombineUnloader() and not self:getIsCpCourseRecorderActive()
end
-function CpAICombineUnloader:getCpStartableJob(superFunc)
+function CpAICombineUnloader:getCpStartableJob(superFunc, ...)
local spec = self.spec_cpAICombineUnloader
- return superFunc(self) or self:getCanStartCpCombineUnloader() and spec.cpJob
+ return superFunc(self, ...) or self:getCanStartCpCombineUnloader() and spec.cpJob
end
function CpAICombineUnloader:getCpStartText(superFunc)
diff --git a/scripts/specializations/CpAIFieldWorker.lua b/scripts/specializations/CpAIFieldWorker.lua
index 4fd0569f7..c16ef3294 100644
--- a/scripts/specializations/CpAIFieldWorker.lua
+++ b/scripts/specializations/CpAIFieldWorker.lua
@@ -299,9 +299,9 @@ function CpAIFieldWorker:getCanStartCp(superFunc)
end
--- Gets the field work job for the hud or start action event.
-function CpAIFieldWorker:getCpStartableJob(superFunc)
+function CpAIFieldWorker:getCpStartableJob(superFunc, ...)
local spec = self.spec_cpAIFieldWorker
- return self:getCanStartCpFieldWork() and self:hasCpCourse() and spec.cpJob or superFunc(self)
+ return self:getCanStartCpFieldWork() and self:hasCpCourse() and spec.cpJob or superFunc(self, ...)
end
function CpAIFieldWorker:getCpStartText(superFunc)
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index 972bf1174..0b8771950 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -1,6 +1,8 @@
local modName = CpAISiloLoaderWorker and CpAISiloLoaderWorker.MOD_NAME -- for reload
+--- Specialization for the silo loader job
+--- Used for shovel loader and big silo loader, like the Ropa NarwaRo.
---@class CpAISiloLoaderWorker
CpAISiloLoaderWorker = {}
@@ -92,11 +94,12 @@ function CpAISiloLoaderWorker:onUpdate(dt)
local spec = self.spec_cpAISiloLoaderWorker
end
---- Is the bunker silo allowed?
function CpAISiloLoaderWorker:getCanStartCpSiloLoaderWorker()
- return not self:getCanStartCpFieldWork() and not self:getCanStartCpBaleFinder() and not self:hasCpCourse()
- and not self:getCanStartCpCombineUnloader() and AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
- and AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt)
+ return not self:getCanStartCpFieldWork()
+ and not self:getCanStartCpBaleFinder()
+ and (not self:hasCpCourse() or AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt))
+ and not self:getCanStartCpCombineUnloader()
+ and AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
end
function CpAISiloLoaderWorker:getCanStartCp(superFunc)
@@ -105,7 +108,16 @@ end
function CpAISiloLoaderWorker:getCpStartableJob(superFunc, isStartedByHud)
local spec = self.spec_cpAISiloLoaderWorker
- return superFunc(self) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
+ if AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt) then
+ return superFunc(self, isStartedByHud) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
+ elseif isStartedByHud then
+ if self:getCanStartCpSiloLoaderWorker()
+ and self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING then
+ return superFunc(self, isStartedByHud) or spec.cpJob
+ end
+
+ end
+ return superFunc(self, isStartedByHud)
end
function CpAISiloLoaderWorker:getCpStartText(superFunc)
@@ -168,11 +180,16 @@ end
function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap)
if self.isServer then
- local strategy = AIDriveStrategySiloLoader.new()
- -- this also starts the strategy
+ local strategy
+ if AIUtil.hasAIImplementWithSpecialization(self, ConveyorBelt) then
+ CpUtil.debugVehicle(CpDebug.DBG_SILO, self, "Starting a silo loader strategy.")
+ strategy = AIDriveStrategySiloLoader.new()
+ else
+ CpUtil.debugVehicle(CpDebug.DBG_SILO, self, "Starting a shovel silo loader strategy.")
+ strategy = AIDriveStrategyShovelSiloLoader.new()
+ end
strategy:setSiloAndHeap(bunkerSilo, heap)
strategy:setAIVehicle(self, jobParameters)
- CpUtil.debugVehicle(CpDebug.DBG_SILO, self, "Starting silo worker job.")
self:startCpWithStrategy(strategy)
end
end
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 2034afe03..a600e569d 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -265,7 +265,7 @@ function CpAIWorker:changeCourseVisibility()
end
function CpAIWorker:startStopCpActionEvent()
- self:cpStartStopDriver()
+ self:cpStartStopDriver(true)
end
--- Directly starts a cp job or stops a currently active job.
diff --git a/scripts/specializations/CpGamePadHud.lua b/scripts/specializations/CpGamePadHud.lua
index 1afa7e2ec..9837bdb2e 100644
--- a/scripts/specializations/CpGamePadHud.lua
+++ b/scripts/specializations/CpGamePadHud.lua
@@ -197,7 +197,8 @@ function CpGamePadHud:actionEventOpenCloseDisplay()
elseif self:getCanStartCpBunkerSiloWorker() and self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
or AIUtil.hasChildVehicleWithSpecialization(self, Leveler) then
page = CpGamePadHud.BUNKER_SILO_PAGE
- elseif self:getCanStartCpSiloLoaderWorker() then
+ elseif self:getCanStartCpSiloLoaderWorker() and ( AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt)
+ or self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING) then
page = CpGamePadHud.SILO_LOADER_PAGE
else
page = CpGamePadHud.FIELDWORK_PAGE
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
new file mode 100644
index 000000000..2873e8eac
--- /dev/null
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -0,0 +1,422 @@
+--[[
+ This specialization is used to control the shovel position into 4 stages:
+ - Loading position 0.2m above the ground.
+ - Transport position
+ - Pre unloading position
+ - Unloading position
+
+ TODO:
+ - Fine tuning
+ - Testing from different front loaders ...
+ - Add Telescopic handlers support.
+]]--
+
+---@class CpShovelPositions
+CpShovelPositions = {
+ DEACTIVATED = 0,
+ LOADING = 1,
+ TRANSPORT = 2,
+ PRE_UNLOAD = 3,
+ UNLOADING = 4,
+ NUM_STATES = 4,
+ LOADING_POSITION = {
+ ARM_LIMITS = {
+ 0,
+ 0.1
+ },
+ SHOVEL_LIMITS = {
+ 88,
+ 92
+ },
+ },
+ TRANSPORT_POSITION = {
+ ARM_LIMITS = {
+ 0.1,
+ 0.20
+ },
+ SHOVEL_LIMITS = {
+ 53,
+ 57
+ },
+ },
+ PRE_UNLOAD_POSITION = {
+ ARM_LIMITS = {
+ 3,
+ 4
+ },
+ SHOVEL_LIMITS = {
+ 43,
+ 47
+ },
+ },
+ UNLOADING_POSITION = {
+ ARM_LIMITS = {
+ 4,
+ 5
+ },
+ },
+ DEBUG = false
+}
+CpShovelPositions.MOD_NAME = g_currentModName
+CpShovelPositions.NAME = ".cpShovelPositions"
+CpShovelPositions.SPEC_NAME = CpShovelPositions.MOD_NAME .. CpShovelPositions.NAME
+CpShovelPositions.KEY = "." .. CpShovelPositions.SPEC_NAME
+
+function CpShovelPositions.initSpecialization()
+ local schema = Vehicle.xmlSchemaSavegame
+ if CpShovelPositions.DEBUG then
+ g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelState', 'cpSetShovelState', 'consoleCommandSetShovelState', CpShovelPositions)
+ end
+end
+
+function CpShovelPositions.prerequisitesPresent(specializations)
+ return SpecializationUtil.hasSpecialization(Shovel, specializations) and not
+ SpecializationUtil.hasSpecialization(Trailer, specializations) and not
+ SpecializationUtil.hasSpecialization(ConveyorBelt, specializations)
+end
+
+function CpShovelPositions.register(typeManager, typeName, specializations)
+ if CpShovelPositions.prerequisitesPresent(specializations) then
+ typeManager:addSpecialization(typeName, CpShovelPositions.SPEC_NAME)
+ end
+end
+
+function CpShovelPositions.registerEventListeners(vehicleType)
+ SpecializationUtil.registerEventListener(vehicleType, "onLoad", CpShovelPositions)
+ SpecializationUtil.registerEventListener(vehicleType, "onDraw", CpShovelPositions)
+ SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", CpShovelPositions)
+ SpecializationUtil.registerEventListener(vehicleType, "onPostAttach", CpShovelPositions)
+end
+
+function CpShovelPositions.registerFunctions(vehicleType)
+ SpecializationUtil.registerFunction(vehicleType, "cpSetShovelState", CpShovelPositions.cpSetShovelState)
+ SpecializationUtil.registerFunction(vehicleType, "cpResetShovelState", CpShovelPositions.cpResetShovelState)
+ SpecializationUtil.registerFunction(vehicleType, "cpSetupShovelPositions", CpShovelPositions.cpSetupShovelPositions)
+ SpecializationUtil.registerFunction(vehicleType, "areCpShovelPositionsDirty", CpShovelPositions.areCpShovelPositionsDirty)
+ SpecializationUtil.registerFunction(vehicleType, "getCpShovelUnloadingPositionHeight", CpShovelPositions.getCpShovelUnloadingPositionHeight)
+end
+
+
+function CpShovelPositions:onLoad(savegame)
+ --- Register the spec: spec_ShovelPositions
+ self.spec_cpShovelPositions = self["spec_" .. CpShovelPositions.SPEC_NAME]
+ local spec = self.spec_cpShovelPositions
+ --- Current shovel state.
+ spec.state = CpShovelPositions.DEACTIVATED
+ spec.isDirty = false
+end
+
+function CpShovelPositions:onPostAttach()
+ if self.spec_cpShovelPositions then
+ CpShovelPositions.cpSetupShovelPositions(self)
+ end
+end
+
+function CpShovelPositions:onDraw()
+ if CpShovelPositions.DEBUG and self:getRootVehicle() then
+ local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ if shovelNode then
+ DebugUtil.drawDebugNode(shovelNode, "shovelNode")
+ end
+ end
+end
+
+function CpShovelPositions:consoleCommandSetShovelState(state)
+ local vehicle = g_currentMission.controlledVehicle
+ if not vehicle then
+ CpUtil.info("Not entered a valid vehicle!")
+ end
+ state = tonumber(state)
+ if state == nil or state < 0 or state > CpShovelPositions.NUM_STATES then
+ CpUtil.infoVehicle(vehicle, "No valid state(0 - %d) was given!", CpShovelPositions.NUM_STATES)
+ return
+ end
+ if not vehicle:getIsAIActive() then
+ local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(vehicle, Shovel)
+ if found then
+ shovels[1]:cpSetShovelState(state)
+ else
+ CpUtil.infoVehicle(vehicle, "No valid vehicle/implement with a shovel was found!")
+ end
+ else
+ CpUtil.infoVehicle(vehicle, "Error, AI is active!")
+ end
+end
+
+--- Changes the current shovel state position.
+function CpShovelPositions:cpSetShovelState(state)
+ local spec = self.spec_cpShovelPositions
+ if spec.state ~= state then
+ spec.state = state
+ if state == CpShovelPositions.DEACTIVATED then
+ ImplementUtil.stopMovingTool(spec.armVehicle, spec.armTool)
+ ImplementUtil.stopMovingTool(spec.shovelVehicle, spec.shovelTool)
+ end
+ end
+end
+
+--- Deactivates the shovel position control.
+function CpShovelPositions:cpResetShovelState()
+ CpShovelPositions.debug(self, "Reset shovelPositionState.")
+ local spec = self.spec_cpShovelPositions
+ spec.state = CpShovelPositions.DEACTIVATED
+ ImplementUtil.stopMovingTool(spec.armVehicle, spec.armTool)
+ ImplementUtil.stopMovingTool(spec.shovelVehicle, spec.shovelTool)
+end
+
+function CpShovelPositions:areCpShovelPositionsDirty()
+ local spec = self.spec_cpShovelPositions
+ return spec.isDirty
+end
+
+--- Sets the relevant moving tools.
+function CpShovelPositions:cpSetupShovelPositions()
+ local spec = self.spec_cpShovelPositions
+ spec.shovelToolIx = nil
+ spec.armToolIx = nil
+ spec.shovelTool = nil
+ spec.armTool = nil
+ local rootVehicle = self:getRootVehicle()
+ local childVehicles = rootVehicle:getChildVehicles()
+ for _, vehicle in ipairs(childVehicles) do
+ if vehicle.spec_cylindered then
+ for i, tool in pairs(vehicle.spec_cylindered.movingTools) do
+ if tool.controlGroupIndex ~= nil then
+ if tool.axis == "AXIS_FRONTLOADER_ARM" then
+ spec.armToolIx = i
+ spec.armTool = tool
+ spec.armVehicle = vehicle
+ spec.armProjectionNode = CpUtil.createNode("CpShovelArmProjectionNode",
+ 0, 0, 0, getParent(tool.node))
+ elseif tool.axis == "AXIS_FRONTLOADER_TOOL" then
+ spec.shovelToolIx = i
+ spec.shovelTool = tool
+ spec.shovelVehicle = vehicle
+ spec.shovelProjectionNode = CpUtil.createNode("CpShovelProjectionNode",
+ 0, 0, 0, getParent(tool.node))
+ end
+ end
+ end
+ end
+ end
+end
+
+function CpShovelPositions:onUpdateTick(dt)
+ local spec = self.spec_cpShovelPositions
+ if spec.shovelToolIx == nil or spec.armToolIx == nil then
+ return
+ end
+ if spec.state == CpShovelPositions.LOADING then
+ CpShovelPositions.updateLoadingPosition(self, dt)
+ elseif spec.state == CpShovelPositions.TRANSPORT then
+ CpShovelPositions.updateTransportPosition(self, dt)
+ elseif spec.state == CpShovelPositions.PRE_UNLOAD then
+ CpShovelPositions.updatePreUnloadPosition(self, dt)
+ elseif spec.state == CpShovelPositions.UNLOADING then
+ CpShovelPositions.updateUnloadingPosition(self, dt)
+ end
+end
+
+--- Changes the shovel angle dependent on the selected position.
+function CpShovelPositions.setShovelPosition(dt, spec, shovel, shovelNode, angle, limits)
+ local min, max = unpack(limits)
+ local targetAngle = math.rad(min) + math.rad(max - min)/2
+ if math.deg(angle) < max and math.deg(angle) > min then
+ ImplementUtil.stopMovingTool(spec.shovelVehicle, spec.shovelTool)
+ return false
+ end
+
+
+ local curRot = {}
+ curRot[1], curRot[2], curRot[3] = getRotation(spec.shovelTool.node)
+ local oldRot = curRot[spec.shovelTool.rotationAxis]
+ local radius = calcDistanceFrom(shovelNode, spec.shovelTool.node)
+ local x, y, z = getTranslation(spec.shovelTool.node)
+
+ setTranslation(spec.shovelProjectionNode, x, y, z)
+
+ setRotation(spec.shovelProjectionNode, targetAngle - math.pi/2, 0, 0)
+
+ local sx, sy, sz = getWorldTranslation(shovelNode)
+ local tx, _, tz = getWorldTranslation(spec.shovelTool.node)
+ local px, py, pz = localToWorld(spec.shovelProjectionNode, 0, 0, radius)
+
+ if CpShovelPositions.DEBUG then
+ DebugUtil.drawDebugCircleAtNode(spec.shovelTool.node, radius, 30, nil, true)
+
+ DebugUtil.drawDebugLine(px, py, pz, sx, sy, sz)
+ DebugUtil.drawDebugLine(px, py, pz, tx, py, tz)
+ end
+
+ local yRot = math.atan2(MathUtil.vector3Length(px - sx, py - sy, pz - sz),
+ MathUtil.vector3Length(px - tx, py - py, pz - tz))
+
+ local dyRot = 0
+ if angle > targetAngle then
+ dyRot = -yRot
+ else
+ dyRot = yRot
+ end
+
+ CpShovelPositions.debug(shovel,
+ "Shovel position(%d) angle: %.2f, targetAngle: %.2f, yRot: %.2f, oldRot: %.2f",
+ spec.state, math.deg(angle), math.deg(targetAngle), math.deg(dyRot), math.deg(oldRot))
+
+ return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle, spec.shovelTool, dt,
+ MathUtil.clamp(oldRot + dyRot , spec.shovelTool.rotMin, spec.shovelTool.rotMax))
+end
+
+--- Changes the front loader angle dependent on the selected position, relative to a target height.
+function CpShovelPositions.setArmPosition(dt, spec, shovel, shovelNode, limits)
+ --- Interval in which the shovel height should be in.
+ local min, max = unpack(limits)
+ local targetHeight = min + (max - min)/2
+
+ local attacherJointNode = shovel.spec_attachable.attacherJoint.node
+ local _, shovelY, shovelR = localToLocal(attacherJointNode, shovelNode, 0, 0, 0)
+
+ local x, y, z = getWorldTranslation(attacherJointNode)
+ local dy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z)
+
+ local targetAttacherHeight = dy + shovelY + targetHeight
+ local diff = targetAttacherHeight - y
+
+ CpShovelPositions.debug(shovel, "shovel => y: %.2f, z: %.2f, targetAttacherHeight: %.2f", shovelY, shovelR, targetAttacherHeight)
+
+ if math.abs(diff) < (max - min)/2 then
+ ImplementUtil.stopMovingTool(spec.armVehicle, spec.armTool)
+ return false
+ end
+
+ local curRot = {}
+ curRot[1], curRot[2], curRot[3] = getRotation(spec.armTool.node)
+ local oldRot = curRot[spec.armTool.rotationAxis]
+
+
+ setWorldTranslation(spec.armProjectionNode, x, targetAttacherHeight, z)
+
+
+ local _, ay, _ = localToLocal(spec.armTool.node, spec.armVehicle.rootNode, 0, 0, 0)
+
+ local nodeDiff = MathUtil.clamp( targetHeight - ay , -shovelR, shovelR) + ay
+
+ local ax, _, az = getWorldTranslation(spec.armTool.node)
+ local sx, sy, sz = getWorldTranslation(spec.shovelTool.node)
+
+ if CpShovelPositions.DEBUG then
+ DebugUtil.drawDebugCircleAtNode(spec.armTool.node, shovelR, 30, nil, true)
+
+ DebugUtil.drawDebugNode(spec.armProjectionNode, "Projection node", false, 0)
+
+ DebugUtil.drawDebugLine(x, targetAttacherHeight, z, sx, sy, sz)
+ DebugUtil.drawDebugLine(x, targetAttacherHeight, z, ax, targetAttacherHeight, az) -- y
+ end
+ local yRot = math.atan2(MathUtil.vector3Length(x - sx, targetAttacherHeight - sy, z - sz),
+ MathUtil.vector3Length(x - ax, 0, z - az))
+
+ if diff < 0 then
+ yRot = yRot
+ else
+ yRot = -yRot
+ end
+
+ CpShovelPositions.debug(shovel,
+ "Arm position(%d) height diff: %.2f, targetHeight: %.2f, old angle: %.2f, yRot: %.2f",
+ spec.state, diff, targetHeight, math.deg(oldRot), math.deg(yRot))
+
+ return ImplementUtil.moveMovingToolToRotation(spec.armVehicle, spec.armTool, dt,
+ MathUtil.clamp(oldRot + yRot , spec.armTool.rotMin, spec.armTool.rotMax))
+end
+
+function CpShovelPositions:updateLoadingPosition(dt)
+ local spec = self.spec_cpShovelPositions
+ local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local isDirty
+ if angle then
+ isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS)
+ isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
+ end
+ spec.isDirty = isDirty
+end
+
+function CpShovelPositions:updateTransportPosition(dt)
+ local spec = self.spec_cpShovelPositions
+ local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local isDirty
+ if angle then
+ isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS)
+ isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
+ end
+ spec.isDirty = isDirty
+end
+
+function CpShovelPositions:updatePreUnloadPosition(dt)
+ local spec = self.spec_cpShovelPositions
+ local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local isDirty
+ if angle then
+ isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS)
+ isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, self:getCpShovelUnloadingPositionHeight())
+ end
+ spec.isDirty = isDirty
+end
+
+function CpShovelPositions:updateUnloadingPosition(dt)
+ local spec = self.spec_cpShovelPositions
+ local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local isDirty
+ if angle and maxAngle then
+ isDirty = CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, self:getCpShovelUnloadingPositionHeight())
+ isDirty = isDirty or CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, {math.deg(maxAngle), math.deg(maxAngle) + 2})
+ end
+ spec.isDirty = isDirty
+end
+
+function CpShovelPositions:getCpShovelUnloadingPositionHeight()
+ return CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS
+end
+
+--- Gets all relevant shovel data.
+function CpShovelPositions:getShovelData()
+ local shovelSpec = self.spec_shovel
+ if shovelSpec == nil then
+ CpShovelPositions.debug(self, "Shovel spec not found!")
+ return
+ end
+ local info = shovelSpec.shovelDischargeInfo
+ if info == nil or info.node == nil then
+ CpShovelPositions.debugt(self, "Info or node not found!")
+ return
+ end
+ if info.maxSpeedAngle == nil or info.minSpeedAngle == nil then
+ CpShovelPositions.debug(self, "maxSpeedAngle or minSpeedAngle not found!")
+ return
+ end
+
+ if shovelSpec.shovelNodes == nil then
+ CpShovelPositions.debug(self, "Shovel nodes not found!")
+ return
+ end
+
+ if shovelSpec.shovelNodes[1] == nil then
+ CpShovelPositions.debug(self, "Shovel nodes index 0 not found!")
+ return
+ end
+
+ if shovelSpec.shovelNodes[1].node == nil then
+ CpShovelPositions.debug(self, "Shovel node not found!")
+ return
+ end
+ local _, dy, _ = localDirectionToWorld(info.node, 0, 0, 1)
+ local angle = math.acos(dy)
+ local factor = math.max(0, math.min(1, (angle - info.minSpeedAngle) / (info.maxSpeedAngle - info.minSpeedAngle)))
+ return angle, shovelSpec.shovelNodes[1].node, info.maxSpeedAngle, info.minSpeedAngle, factor
+end
+
+
+
+function CpShovelPositions.debug(implement, ...)
+ if CpShovelPositions.DEBUG then
+ CpUtil.infoImplement(implement, ...)
+ end
+end
\ No newline at end of file
diff --git a/scripts/trigger/TriggerManager.lua b/scripts/trigger/TriggerManager.lua
new file mode 100644
index 000000000..0fc40dd6f
--- /dev/null
+++ b/scripts/trigger/TriggerManager.lua
@@ -0,0 +1,44 @@
+--- Links all the needed trigger, except bunker silos to trigger wrappers.
+TriggerManager = CpObject()
+
+function TriggerManager:init()
+ self.unloadSilos = {}
+end
+
+function TriggerManager:addUnloadingSilo(silo)
+ if silo.exactFillRootNode ~= nil then
+ self.unloadSilos[silo.exactFillRootNode] = CpTrigger(silo, silo.exactFillRootNode)
+ end
+end
+
+function TriggerManager:removeUnloadingSilo(silo)
+ if silo.exactFillRootNode ~= nil then
+ if self.unloadSilos[silo.exactFillRootNode] then
+ self.unloadSilos[silo.exactFillRootNode]:delete()
+ self.unloadSilos[silo.exactFillRootNode] = nil
+ end
+ end
+end
+
+function TriggerManager:getUnloadTriggerForNode(node)
+ return self.unloadSilos[node]
+end
+
+
+g_triggerManager = TriggerManager()
+
+local function addUnloadingSilo(silo, superFunc, ...)
+ local ret = superFunc(silo, ...)
+ g_triggerManager:addUnloadingSilo(silo)
+ return ret
+end
+
+UnloadTrigger.load = Utils.overwrittenFunction(UnloadTrigger.load, addUnloadingSilo)
+
+
+local function removeUnloadingSilo(silo, ...)
+ g_triggerManager:removeUnloadingSilo(silo)
+end
+
+UnloadTrigger.delete = Utils.prependedFunction(UnloadTrigger.delete, removeUnloadingSilo)
+
diff --git a/scripts/trigger/TriggerWrapper.lua b/scripts/trigger/TriggerWrapper.lua
new file mode 100644
index 000000000..6729789f1
--- /dev/null
+++ b/scripts/trigger/TriggerWrapper.lua
@@ -0,0 +1,20 @@
+
+---@class CpTrigger
+CpTrigger = CpObject()
+
+function CpTrigger:init(trigger, node)
+ self.trigger = trigger
+ self.node = node
+end
+
+function CpTrigger:delete()
+
+end
+
+function CpTrigger:getNode()
+ return self.node
+end
+
+function CpTrigger:getTrigger()
+ return self.trigger
+end
\ No newline at end of file
From b102c581c9c9be5a0e08043ef7c1dd5af9266b61 Mon Sep 17 00:00:00 2001
From: schwiti6190
Date: Wed, 5 Jul 2023 19:03:42 +0000
Subject: [PATCH 005/107] Updated translations
---
translations/translation_br.xml | 3 +++
translations/translation_cs.xml | 3 +++
translations/translation_ct.xml | 3 +++
translations/translation_cz.xml | 3 +++
translations/translation_da.xml | 3 +++
translations/translation_de.xml | 3 +++
translations/translation_ea.xml | 3 +++
translations/translation_en.xml | 3 +++
translations/translation_es.xml | 3 +++
translations/translation_fc.xml | 3 +++
translations/translation_fi.xml | 3 +++
translations/translation_fr.xml | 3 +++
translations/translation_hu.xml | 3 +++
translations/translation_it.xml | 3 +++
translations/translation_jp.xml | 3 +++
translations/translation_kr.xml | 3 +++
translations/translation_nl.xml | 3 +++
translations/translation_no.xml | 3 +++
translations/translation_pl.xml | 3 +++
translations/translation_pt.xml | 3 +++
translations/translation_ro.xml | 3 +++
translations/translation_ru.xml | 3 +++
translations/translation_sv.xml | 3 +++
translations/translation_tr.xml | 3 +++
24 files changed, 72 insertions(+)
diff --git a/translations/translation_br.xml b/translations/translation_br.xml
index 5ddb82098..ad251013c 100644
--- a/translations/translation_br.xml
+++ b/translations/translation_br.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_cs.xml b/translations/translation_cs.xml
index 35d8fd82a..046448b0f 100644
--- a/translations/translation_cs.xml
+++ b/translations/translation_cs.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_ct.xml b/translations/translation_ct.xml
index de972a2f7..5f3785b2b 100644
--- a/translations/translation_ct.xml
+++ b/translations/translation_ct.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml
index 865c96a0c..2a0b74f6b 100644
--- a/translations/translation_cz.xml
+++ b/translations/translation_cz.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_da.xml b/translations/translation_da.xml
index 78d396796..3f42cd746 100644
--- a/translations/translation_da.xml
+++ b/translations/translation_da.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 920aaac57..63a4045ac 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_ea.xml b/translations/translation_ea.xml
index 28bdebd77..b96cffca8 100644
--- a/translations/translation_ea.xml
+++ b/translations/translation_ea.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 056b09749..ca149cc2d 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_es.xml b/translations/translation_es.xml
index e8639b195..106e4f123 100644
--- a/translations/translation_es.xml
+++ b/translations/translation_es.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_fc.xml b/translations/translation_fc.xml
index f5dfdcdfd..c6c370537 100644
--- a/translations/translation_fc.xml
+++ b/translations/translation_fc.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_fi.xml b/translations/translation_fi.xml
index 18a5c3445..6f9113620 100644
--- a/translations/translation_fi.xml
+++ b/translations/translation_fi.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_fr.xml b/translations/translation_fr.xml
index cad16a88e..7fe3d9197 100644
--- a/translations/translation_fr.xml
+++ b/translations/translation_fr.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index b21bfd0a1..603d2bdfd 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_it.xml b/translations/translation_it.xml
index 6db335ca6..306b20e9c 100644
--- a/translations/translation_it.xml
+++ b/translations/translation_it.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_jp.xml b/translations/translation_jp.xml
index cb2541d09..ab3407769 100644
--- a/translations/translation_jp.xml
+++ b/translations/translation_jp.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_kr.xml b/translations/translation_kr.xml
index 45800dfbb..ca2647db7 100644
--- a/translations/translation_kr.xml
+++ b/translations/translation_kr.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_nl.xml b/translations/translation_nl.xml
index 62b0470bb..9dad80708 100644
--- a/translations/translation_nl.xml
+++ b/translations/translation_nl.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_no.xml b/translations/translation_no.xml
index 07bb8d178..911f3562a 100644
--- a/translations/translation_no.xml
+++ b/translations/translation_no.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_pl.xml b/translations/translation_pl.xml
index 4fb5e7f30..e1e2f7f30 100644
--- a/translations/translation_pl.xml
+++ b/translations/translation_pl.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_pt.xml b/translations/translation_pt.xml
index 765e19c9e..9c9ef92aa 100644
--- a/translations/translation_pt.xml
+++ b/translations/translation_pt.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_ro.xml b/translations/translation_ro.xml
index 976b29198..ae794202e 100644
--- a/translations/translation_ro.xml
+++ b/translations/translation_ro.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_ru.xml b/translations/translation_ru.xml
index b2c114421..141be2eb0 100644
--- a/translations/translation_ru.xml
+++ b/translations/translation_ru.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_sv.xml b/translations/translation_sv.xml
index 63bbb2930..38a3614af 100644
--- a/translations/translation_sv.xml
+++ b/translations/translation_sv.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
diff --git a/translations/translation_tr.xml b/translations/translation_tr.xml
index 12c65739d..d504d7ed4 100644
--- a/translations/translation_tr.xml
+++ b/translations/translation_tr.xml
@@ -25,6 +25,7 @@
+
@@ -93,6 +94,8 @@
+
+
From cdd4dd1dd809c371e00e6ff24d55e01965fbb1d7 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 5 Jul 2023 21:21:48 +0200
Subject: [PATCH 006/107] Translation fix and adjustment
---
config/MasterTranslations.xml | 4 +
.../ai/AIDriveStrategyShovelSiloLoader.lua | 76 +++----------------
scripts/ai/controllers/ShovelController.lua | 6 +-
3 files changed, 19 insertions(+), 67 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index ed8a652c8..518eaa41e 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -305,6 +305,10 @@
+
+
+
+
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 11f8019a2..7fb7cdf8c 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -40,7 +40,6 @@ AIDriveStrategyShovelSiloLoader.myStates = {
DRIVING_OUT_OF_SILO = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
WAITING_FOR_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
DRIVING_TO_UNLOAD_POSITION = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
- DRIVING_TO_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
DRIVING_TO_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
UNLOADING = {shovelPosition = ShovelController.POSITIONS.UNLOADING, shovelMovingSpeed = 0},
}
@@ -145,12 +144,6 @@ function AIDriveStrategyShovelSiloLoader:onWaypointPassed(ix, course)
self:startPathfindingToUnloadPosition()
elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
self.state = self.states.WAITING_FOR_TRAILER
- elseif self.state == self.states.DRIVING_TO_TRAILER then
- local course = Course.createFromNodeToNode(self.vehicle, self.vehicle:getAIDirectionNode(), self.unloadNode,
- 0, 0, 0, 3, false)
- self:startCourse(course, 1)
-
- self.state = self.states.DRIVING_TO_UNLOAD
elseif self.state == self.states.DRIVING_TO_UNLOAD then
self.state = self.states.UNLOADING
@@ -211,12 +204,13 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
elseif self.state == self.states.WAITING_FOR_TRAILER then
self:setMaxSpeed(0)
self:searchForTrailerToUnloadInto()
- elseif self.state == self.states.DRIVING_TO_TRAILER then
- self:setMaxSpeed(self.settings.fieldSpeed:getValue())
elseif self.state == self.states.DRIVING_TO_UNLOAD then
self:setMaxSpeed(self.settings.reverseSpeed:getValue())
- if self.shovelController:isShovelOverTrailer(self.targetTrailer.trailer) then
- self.state = self.states.UNLOADING
+ if self.targetTrailer then
+ if self.shovelController:isShovelOverTrailer(self.targetTrailer.exactFillRootNode) then
+ self.state = self.states.UNLOADING
+ self:setMaxSpeed(0)
+ end
end
elseif self.state == self.states.UNLOADING then
self:setMaxSpeed(0)
@@ -351,10 +345,13 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
exactFillRootNode = exactFillRootNode,
trailer = trailer
}
- -- self:debug("Found valid trailer %s attached to %s with a distance of %.2fm to the silo front center for fill type %s in fill unit %d.",
- -- CpUtil.getName(vehicle), CpUtil.getName(vehicle.rootVehicle),
- -- self.maxValidTrailerDistance, g_fillTypeManager:getFillTypeTitleByIndex(fillType), fillUnitIndex)
- self:startPathfindingToTrailer(trailer, exactFillRootNode)
+ local dx, _, dz = getWorldTranslation(exactFillRootNode)
+ local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
+ local course = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
+ 0, -3, 0, 3, false)
+ local firstWpIx = course:getNearestWaypoints(self.vehicle:getAIDirectionNode())
+ self:startCourse(course, firstWpIx)
+ self.state = self.states.DRIVING_TO_UNLOAD
end
end
@@ -395,55 +392,6 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path,
end
end
---- Find an alignment path to the heap course.
-function AIDriveStrategyShovelSiloLoader:startPathfindingToTrailer(trailer, exactFillRootNode)
- if not self.pathfinder or not self.pathfinder:isActive() then
- self.state = self.states.WAITING_FOR_PATHFINDER
- local dx, _, _ = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
-
- local loadingLeftSide = dx > 0
-
- local x, y, z = localToLocal(exactFillRootNode, trailer.rootNode, 0, 0, 0)
-
- local gx, gy, gz = localToWorld(trailer.rootNode, x, y, z)
- local dirX, dirZ = localDirectionToWorld(trailer.rootNode, loadingLeftSide and 1 or -1, 0, 0)
- local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
- setTranslation(self.unloadNode, gx, gy, gz)
- setRotation(self.unloadNode, 0, yRot, 0)
-
- local spaceToTrailer = math.max(self.turningRadius, self.safeSpaceToTrailer)
-
- self.pathfindingStartedAt = g_currentMission.time
- local done, path, goalNodeInvalid
- self.pathfinder, done, path, goalNodeInvalid = PathfinderUtil.startPathfindingFromVehicleToNode(
- self.vehicle, self.unloadNode,
- 0, -spaceToTrailer, true,
- nil, {}, nil,
- 0, nil, true
- )
- if done then
- return self:onPathfindingDoneToTrailer(path, goalNodeInvalid)
- else
- self:setPathfindingDoneCallback(self, self.onPathfindingDoneToTrailer)
- end
- else
- self:debug('Pathfinder already active')
- end
- return true
-end
-
-function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToTrailer(path, goalNodeInvalid)
- if path and #path > 2 then
- self:debug("Found alignment path to trailer.")
- local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
- self:startCourse(course, 1)
- self.state = self.states.DRIVING_TO_TRAILER
- else
- self:debug("Failed to find valid path to trailer!")
- self.state = self.sates.WAITING_FOR_TRAILER
- end
-end
-
----------------------------------------------------------------
--- Silo work
----------------------------------------------------------------
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index adc7efd12..08774f4ae 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -57,12 +57,12 @@ function ShovelController:getDischargeNode()
end
--- Is the shovel node over the trailer?
----@param trailer table
+---@param refNode number
---@param margin number|nil
---@return boolean
-function ShovelController:isShovelOverTrailer(trailer, margin)
+function ShovelController:isShovelOverTrailer(refNode, margin)
local node = self:getShovelNode()
- local x, y, z = localToLocal(trailer.rootNode, node, 0, 0, 0)
+ local x, y, z = localToLocal(refNode, node, 0, 0, 0)
margin = margin or 0
return z < margin
end
From 5da1079554038ca25323c95e76a1c3e1fac6c684 Mon Sep 17 00:00:00 2001
From: schwiti6190
Date: Wed, 5 Jul 2023 19:22:09 +0000
Subject: [PATCH 007/107] Updated translations
---
translations/translation_br.xml | 1 +
translations/translation_cs.xml | 1 +
translations/translation_ct.xml | 1 +
translations/translation_cz.xml | 1 +
translations/translation_da.xml | 1 +
translations/translation_de.xml | 1 +
translations/translation_ea.xml | 1 +
translations/translation_en.xml | 1 +
translations/translation_es.xml | 1 +
translations/translation_fc.xml | 1 +
translations/translation_fi.xml | 1 +
translations/translation_fr.xml | 1 +
translations/translation_hu.xml | 1 +
translations/translation_it.xml | 1 +
translations/translation_jp.xml | 1 +
translations/translation_kr.xml | 1 +
translations/translation_nl.xml | 1 +
translations/translation_no.xml | 1 +
translations/translation_pl.xml | 1 +
translations/translation_pt.xml | 1 +
translations/translation_ro.xml | 1 +
translations/translation_ru.xml | 1 +
translations/translation_sv.xml | 1 +
translations/translation_tr.xml | 1 +
24 files changed, 24 insertions(+)
diff --git a/translations/translation_br.xml b/translations/translation_br.xml
index ad251013c..b4e68c90f 100644
--- a/translations/translation_br.xml
+++ b/translations/translation_br.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_cs.xml b/translations/translation_cs.xml
index 046448b0f..37d34c151 100644
--- a/translations/translation_cs.xml
+++ b/translations/translation_cs.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_ct.xml b/translations/translation_ct.xml
index 5f3785b2b..29f9b8820 100644
--- a/translations/translation_ct.xml
+++ b/translations/translation_ct.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml
index 2a0b74f6b..e5bfe8b43 100644
--- a/translations/translation_cz.xml
+++ b/translations/translation_cz.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_da.xml b/translations/translation_da.xml
index 3f42cd746..71b70cb3e 100644
--- a/translations/translation_da.xml
+++ b/translations/translation_da.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 63a4045ac..6893d93a0 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_ea.xml b/translations/translation_ea.xml
index b96cffca8..487297825 100644
--- a/translations/translation_ea.xml
+++ b/translations/translation_ea.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index ca149cc2d..454e60989 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_es.xml b/translations/translation_es.xml
index 106e4f123..d9278b066 100644
--- a/translations/translation_es.xml
+++ b/translations/translation_es.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_fc.xml b/translations/translation_fc.xml
index c6c370537..1e82fa96b 100644
--- a/translations/translation_fc.xml
+++ b/translations/translation_fc.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_fi.xml b/translations/translation_fi.xml
index 6f9113620..15f07d006 100644
--- a/translations/translation_fi.xml
+++ b/translations/translation_fi.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_fr.xml b/translations/translation_fr.xml
index 7fe3d9197..b7aca1aa1 100644
--- a/translations/translation_fr.xml
+++ b/translations/translation_fr.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index 603d2bdfd..7e9e1e8a0 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_it.xml b/translations/translation_it.xml
index 306b20e9c..bb65ac788 100644
--- a/translations/translation_it.xml
+++ b/translations/translation_it.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_jp.xml b/translations/translation_jp.xml
index ab3407769..32edfee7c 100644
--- a/translations/translation_jp.xml
+++ b/translations/translation_jp.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_kr.xml b/translations/translation_kr.xml
index ca2647db7..75bb4f709 100644
--- a/translations/translation_kr.xml
+++ b/translations/translation_kr.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_nl.xml b/translations/translation_nl.xml
index 9dad80708..89bb6efb2 100644
--- a/translations/translation_nl.xml
+++ b/translations/translation_nl.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_no.xml b/translations/translation_no.xml
index 911f3562a..4491229ea 100644
--- a/translations/translation_no.xml
+++ b/translations/translation_no.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_pl.xml b/translations/translation_pl.xml
index e1e2f7f30..fdf218218 100644
--- a/translations/translation_pl.xml
+++ b/translations/translation_pl.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_pt.xml b/translations/translation_pt.xml
index 9c9ef92aa..44394a95f 100644
--- a/translations/translation_pt.xml
+++ b/translations/translation_pt.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_ro.xml b/translations/translation_ro.xml
index ae794202e..0cbfb5ef2 100644
--- a/translations/translation_ro.xml
+++ b/translations/translation_ro.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_ru.xml b/translations/translation_ru.xml
index 141be2eb0..6b842b5d0 100644
--- a/translations/translation_ru.xml
+++ b/translations/translation_ru.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_sv.xml b/translations/translation_sv.xml
index 38a3614af..4f125e18a 100644
--- a/translations/translation_sv.xml
+++ b/translations/translation_sv.xml
@@ -94,6 +94,7 @@
+
diff --git a/translations/translation_tr.xml b/translations/translation_tr.xml
index d504d7ed4..c2b85d87c 100644
--- a/translations/translation_tr.xml
+++ b/translations/translation_tr.xml
@@ -94,6 +94,7 @@
+
From d9b98c96f02fa754c99042d1953c7fba69cbb1be Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 7 Jul 2023 15:42:56 +0200
Subject: [PATCH 008/107] WIP
---
Courseplay.lua | 2 +
.../CombineUnloaderJobParameterSetup.xml | 2 +-
modDesc.xml | 1 +
.../ai/AIDriveStrategyShovelSiloLoader.lua | 22 +++-
scripts/ai/controllers/ShovelController.lua | 5 +-
scripts/ai/jobs/CpAIJobSiloLoader.lua | 35 +++--
scripts/ai/jobs/CpJobParameters.lua | 7 +-
.../CpAIParameterUnloadingStation.lua | 2 +-
scripts/gui/CoursePlot.lua | 53 ++------
scripts/gui/CpAIFrameExtended.lua | 83 +++++++-----
scripts/gui/CpGuiUtil.lua | 67 ++++++++++
scripts/gui/FieldPlot.lua | 2 +-
scripts/gui/UnloadingTriggerPlot.lua | 49 +++++++
scripts/silo/BunkerSiloVehicleController.lua | 22 +++-
scripts/silo/BunkerSiloWrapper.lua | 8 --
scripts/trigger/TriggerManager.lua | 124 +++++++++++++++++-
scripts/trigger/TriggerWrapper.lua | 6 +
17 files changed, 371 insertions(+), 119 deletions(-)
create mode 100644 scripts/gui/UnloadingTriggerPlot.lua
diff --git a/Courseplay.lua b/Courseplay.lua
index f4ff27aea..ff40bf12d 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -194,12 +194,14 @@ FSCareerMissionInfo.saveToXMLFile = Utils.prependedFunction(FSCareerMissionInfo.
function Courseplay:update(dt)
g_devHelper:update()
g_bunkerSiloManager:update(dt)
+ g_triggerManager:update(dt)
end
function Courseplay:draw()
if not g_gui:getIsGuiVisible() then
g_vineScanner:draw()
g_bunkerSiloManager:draw()
+ g_triggerManager:draw()
end
g_devHelper:draw()
CpDebug:draw()
diff --git a/config/jobParameters/CombineUnloaderJobParameterSetup.xml b/config/jobParameters/CombineUnloaderJobParameterSetup.xml
index 21cd74d8e..92b203fe4 100644
--- a/config/jobParameters/CombineUnloaderJobParameterSetup.xml
+++ b/config/jobParameters/CombineUnloaderJobParameterSetup.xml
@@ -27,7 +27,7 @@
-
+
diff --git a/modDesc.xml b/modDesc.xml
index b57225da1..b0d9fc3e8 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -381,6 +381,7 @@ Changelog 7.1.0.0:
+
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 7fb7cdf8c..bb5b13975 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -42,6 +42,7 @@ AIDriveStrategyShovelSiloLoader.myStates = {
DRIVING_TO_UNLOAD_POSITION = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
DRIVING_TO_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
UNLOADING = {shovelPosition = ShovelController.POSITIONS.UNLOADING, shovelMovingSpeed = 0},
+ REVERSING_AWAY_FROM_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
}
AIDriveStrategyShovelSiloLoader.safeSpaceToTrailer = 5
@@ -104,7 +105,7 @@ end
function AIDriveStrategyShovelSiloLoader:initializeImplementControllers(vehicle)
self:addImplementController(vehicle, MotorController, Motorized, {}, nil)
self:addImplementController(vehicle, WearableController, Wearable, {}, nil)
-
+ ---@type table, ShovelController
self.shovelImplement, self.shovelController = self:addImplementController(vehicle, ShovelController, Shovel, {}, nil)
end
@@ -146,7 +147,12 @@ function AIDriveStrategyShovelSiloLoader:onWaypointPassed(ix, course)
self.state = self.states.WAITING_FOR_TRAILER
elseif self.state == self.states.DRIVING_TO_UNLOAD then
self.state = self.states.UNLOADING
-
+ elseif self.state == self.states.REVERSING_AWAY_FROM_UNLOAD then
+ if self.shovelController:isEmpty() then
+ self:startDrivingToSilo()
+ else
+ self.state = self.states.WAITING_FOR_TRAILER
+ end
--self.vehicle:stopCurrentAIJob(AIMessageSuccessFinishedJob.new())
end
end
@@ -215,8 +221,10 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
elseif self.state == self.states.UNLOADING then
self:setMaxSpeed(0)
if self:hasFinishedUnloading() then
- self:startDrivingToSilo()
+ self:startReversingAwayFromUnloading()
end
+ elseif self.state == self.states.REVERSING_AWAY_FROM_UNLOAD then
+ self:setMaxSpeed(self.settings.fieldSpeed:getValue())
end
if self.state.properties.shovelPosition then
if not self.frozen and self.shovelController:moveShovelToPosition(self.state.properties.shovelPosition) then
@@ -440,7 +448,7 @@ end
--- Unloading
----------------------------------------------------------------
function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
- if self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
+ if self.targetTrailer and self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
self:debug("Trailer is full, abort unloading into trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
return true
end
@@ -452,3 +460,9 @@ function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
return false
end
+function AIDriveStrategyShovelSiloLoader:startReversingAwayFromUnloading()
+ local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
+ local course = Course.createStraightReverseCourse(self.vehicle, 2*spaceToTrailer, 0 )
+ self:startCourse(course, 1)
+ self.state = self.states.REVERSING_AWAY_FROM_UNLOAD
+end
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 08774f4ae..f4e193e03 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -62,9 +62,10 @@ end
---@return boolean
function ShovelController:isShovelOverTrailer(refNode, margin)
local node = self:getShovelNode()
- local x, y, z = localToLocal(refNode, node, 0, 0, 0)
+ local _, _, distShovelToRoot = localToLocal(node, self.implement.rootVehicle:getAIDirectionNode(), 0, 0, 0)
+ local _, _, distTrailerToRoot = localToLocal(refNode, self.implement.rootVehicle:getAIDirectionNode(), 0, 0, 0)
margin = margin or 0
- return z < margin
+ return ( distTrailerToRoot - distShovelToRoot ) < margin
end
function ShovelController:moveShovelToLoadingPosition()
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index d3640814c..bffb77301 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -47,8 +47,8 @@ function CpAIJobSiloLoader:getCanStartJob()
return self.hasValidPosition
end
----@param vehicle Vehicle
----@param mission Mission
+---@param vehicle table
+---@param mission table
---@param farmId number
---@param isDirectStart boolean disables the drive to by giants
---@param isStartPositionInvalid boolean resets the drive to target position by giants and the field position to the vehicle position.
@@ -104,7 +104,10 @@ function CpAIJobSiloLoader:validate(farmId)
self.heapPlot:setVisible(false)
self.heap = nil
self.bunkerSilo = nil
+ self.unloadStation = nil
+ self.unloadTrigger = nil
self.hasValidPosition = false
+ self:getCpJobParameters().unloadStation:setValue(-1)
local isValid, errorMessage = CpAIJob.validate(self, farmId)
if not isValid then
return isValid, errorMessage
@@ -132,12 +135,23 @@ function CpAIJobSiloLoader:validate(farmId)
if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
--- Validate the trigger setup
- local found, unloadStation = self:getUnloadTriggerAt(self.cpJobParameters.unloadPosition)
-
- return false, g_i18n:getText("CP_error_no_unload_trigger_found")
+ local found, unloadTrigger, unloadStation = self:getUnloadTriggerAt(self.cpJobParameters.unloadPosition)
+ if found then
+ self.unloadStation = unloadStation
+ self.unloadTrigger = unloadTrigger
+ if unloadStation == nil then
+ return false, g_i18n:getText("CP_error_no_unload_trigger_found")
+ end
+ local id = NetworkUtil.getObjectId(unloadStation)
+ if id ~= nil then
+ self:getCpJobParameters().unloadStation:setValue(id)
+ self:getCpJobParameters().unloadStation:validateUnloadingStation()
+ end
+ else
+ return false, g_i18n:getText("CP_error_no_unload_trigger_found")
+ end
end
-
return isValid, errorMessage
end
@@ -170,16 +184,19 @@ end
---@return table|nil
function CpAIJobSiloLoader:getUnloadTriggerAt(unloadPosition)
local x, z = unloadPosition:getPosition()
- local angle = unloadPosition:getAngle()
- if x == nil or angle == nil then
+ local dirX, dirZ = unloadPosition:getDirection()
+ if x == nil or dirX == nil then
return false
end
- return false
+ return g_triggerManager:getDischargeableUnloadTriggerAt( x, z, dirX, dirZ, 5, 5)
end
function CpAIJobSiloLoader:drawSilos(map)
self.heapPlot:draw(map)
g_bunkerSiloManager:drawSilos(map, self.bunkerSilo)
+ if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
+ g_triggerManager:drawDischargeableTriggers(map, self.unloadTrigger)
+ end
end
diff --git a/scripts/ai/jobs/CpJobParameters.lua b/scripts/ai/jobs/CpJobParameters.lua
index 9fec909c1..5aff5addb 100644
--- a/scripts/ai/jobs/CpJobParameters.lua
+++ b/scripts/ai/jobs/CpJobParameters.lua
@@ -214,8 +214,8 @@ function CpCombineUnloaderJobParameters:isFieldUnloadDisabled()
return self.useGiantsUnload:getValue()
end
-function CpCombineUnloaderJobParameters:isUnloadStationSelectorDisabled()
- return self:isGiantsUnloadDisabled() or not self.useGiantsUnload:getValue()
+function CpCombineUnloaderJobParameters:isUnloadStationSelectorVisible()
+ return not self:isGiantsUnloadDisabled() and self.useGiantsUnload:getValue()
end
function CpCombineUnloaderJobParameters:isFieldUnloadPositionSelectorDisabled()
@@ -227,7 +227,6 @@ function CpCombineUnloaderJobParameters:isFieldUnloadTipSideDisabled()
return self:isFieldUnloadDisabled() or self:hasPipe() or not self.useFieldUnload:getValue()
end
-
function CpCombineUnloaderJobParameters:hasPipe()
local vehicle = self.job:getVehicle()
if vehicle then
@@ -348,7 +347,7 @@ function CpSiloLoaderJobParameters:isShovelSiloLoadDisabled()
end
function CpSiloLoaderJobParameters:isUnloadPositionDisabled()
- return self:isShovelSiloLoadDisabled() or self.unloadAt == CpSiloLoaderJobParameters.UNLOAD_TRAILER
+ return false --self:isShovelSiloLoadDisabled() or self.unloadAt == CpSiloLoaderJobParameters.UNLOAD_TRAILER
end
function CpSiloLoaderJobParameters:isUnloadStationDisabled()
diff --git a/scripts/ai/parameters/CpAIParameterUnloadingStation.lua b/scripts/ai/parameters/CpAIParameterUnloadingStation.lua
index 1afe6ecd4..22c39d61c 100644
--- a/scripts/ai/parameters/CpAIParameterUnloadingStation.lua
+++ b/scripts/ai/parameters/CpAIParameterUnloadingStation.lua
@@ -41,7 +41,7 @@ end
--- Applies the current position to the map hotspot.
function CpAIParameterUnloadingStation:applyToMapHotspot(mapHotspot)
- if not self:getCanBeChanged() then
+ if not self:getIsVisible() then
return false
end
local unloadingStation = self:getUnloadingStation()
diff --git a/scripts/gui/CoursePlot.lua b/scripts/gui/CoursePlot.lua
index 8b9edded8..aa60429ba 100644
--- a/scripts/gui/CoursePlot.lua
+++ b/scripts/gui/CoursePlot.lua
@@ -79,44 +79,11 @@ function CoursePlot:setStopPosition( x, z )
self.stopPosition.x, self.stopPosition.z = x, z
end
-function CoursePlot:worldToScreen(map, worldX, worldZ, isHudMap)
- local objectX = (worldX + map.worldCenterOffsetX) / map.worldSizeX * 0.5 + 0.25
- local objectZ = (worldZ + map.worldCenterOffsetZ) / map.worldSizeZ * 0.5 + 0.25
- local x, y, _, _ = map.fullScreenLayout:getMapObjectPosition(objectX, objectZ, 0, 0, 0, true)
- local rot = 0
- local visible = true
- if isHudMap then
- --- The plot is displayed in the hud.
- objectX = (worldX + map.worldCenterOffsetX) / map.worldSizeX * map.mapExtensionScaleFactor + map.mapExtensionOffsetX
- objectZ = (worldZ + map.worldCenterOffsetZ) / map.worldSizeZ * map.mapExtensionScaleFactor + map.mapExtensionOffsetZ
-
- x, y, rot, visible = map.layout:getMapObjectPosition(objectX, objectZ, 0, 0, 0, false)
- if map.state == IngameMap.STATE_MINIMAP_ROUND and map.layout.rotateWithMap then
- x, y, rot, visible = self:getMapObjectPositionCircleLayoutFix(map.layout, objectX, objectZ, 0, 0, 0, false)
- end
- end
- return x, y, rot, visible
-end
-
---- Giants was not so kind, as to allow getting the positions even, if the object is outside the map range ...
---- This is a custom version for: IngameMapLayoutCircle:getMapObjectPosition(...)
-function CoursePlot:getMapObjectPositionCircleLayoutFix(layout, objectU, objectV, width, height, rot, persistent)
- local mapWidth, mapHeight = layout:getMapSize()
- local mapX, mapY = layout:getMapPosition()
- local objectX = objectU * mapWidth + mapX
- local objectY = (1 - objectV) * mapHeight + mapY
- objectX, objectY, rot = layout:rotateWithMap(objectX, objectY, rot, persistent)
- objectX = objectX - width * 0.5
- objectY = objectY - height * 0.5
-
- return objectX, objectY, rot, true
-end
-
-function CoursePlot:screenToWorld( x, y )
- local worldX = ((x - self.x) / self.scaleX) - self.worldOffsetX
- local worldZ = ((y - self.y - self.height) / -self.scaleZ) - self.worldOffsetZ
- return worldX, worldZ
-end
+-- function CoursePlot:screenToWorld( x, y )
+-- local worldX = ((x - self.x) / self.scaleX) - self.worldOffsetX
+-- local worldZ = ((y - self.y - self.height) / -self.scaleZ) - self.worldOffsetZ
+-- return worldX, worldZ
+-- end
-- Draw the waypoints in the screen area defined in new(), the bottom left corner
-- is at worldX/worldZ coordinates, the size shown is worldWidth wide (and high)
@@ -129,14 +96,14 @@ function CoursePlot:drawPoints(map, points, isHudMap)
if points and #points > 1 then
-- I know this is in helpers.lua already but that code has too many dependencies
-- on global variables and vehicle.cp.
- local wp, np, startX, startY, endX, endY, dx, dz, dx2D, dy2D, width, rotation, r, g, b, sv, ev
+ local wp, np, startX, startY, endX, endY, dx, dz, dx2D, dy2D, width, rotation, r, g, b, sv, ev, _
-- render a line between subsequent waypoints
for i = 1, #points - 1 do
wp = points[ i ]
np = points[ i + 1 ]
- startX, startY, _, sv = self:worldToScreen(map, wp.x, wp.z, isHudMap)
- endX, endY, _, ev = self:worldToScreen(map, np.x, np.z, isHudMap)
+ startX, startY, _, sv = CpGuiUtil.worldToScreen(map, wp.x, wp.z, isHudMap)
+ endX, endY, _, ev = CpGuiUtil.worldToScreen(map, np.x, np.z, isHudMap)
-- render only if it is on the plot area
if startX and startY and endX and endY then
@@ -176,7 +143,7 @@ function CoursePlot:draw(map, isHudMap)
-- render a sign marking the end of the course
if self.stopPosition.x and self.stopPosition.z then
- local x, y, rotation = self:worldToScreen( map,self.stopPosition.x, self.stopPosition.z, isHudMap)
+ local x, y, rotation = CpGuiUtil.worldToScreen( map,self.stopPosition.x, self.stopPosition.z, isHudMap)
if x and y then
setOverlayColor( self.stopSignOverlayId, 1, 1, 1, 1 )
renderOverlay( self.stopSignOverlayId,
@@ -188,7 +155,7 @@ function CoursePlot:draw(map, isHudMap)
-- render a sign marking the current position used as a starting location for the course
if self.startPosition.x and self.startPosition.z then
- local x, y, rotation = self:worldToScreen(map, self.startPosition.x, self.startPosition.z, isHudMap)
+ local x, y, rotation = CpGuiUtil.worldToScreen(map, self.startPosition.x, self.startPosition.z, isHudMap)
if x and y then
setOverlayColor( self.startSignOverlayId, 1, 1, 1, 0.8 )
renderOverlay( self.startSignOverlayId,
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index b7d393fec..3ce7d0915 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -346,6 +346,10 @@ function CpInGameMenuAIFrameExtended:setMapSelectionItem(hotspot)
if param:applyToMapHotspot(self.fieldSiloAiTargetMapHotspot) then
g_currentMission:addMapHotspot(self.fieldSiloAiTargetMapHotspot)
end
+ elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
+ if param:applyToMapHotspot(self.loadAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.loadAiTargetMapHotspot)
+ end
elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD then
if param:applyToMapHotspot(self.unloadAiTargetMapHotspot) then
g_currentMission:addMapHotspot(self.unloadAiTargetMapHotspot)
@@ -356,10 +360,6 @@ function CpInGameMenuAIFrameExtended:setMapSelectionItem(hotspot)
if param:applyToMapHotspot(self.aiUnloadingMarkerHotspot) then
g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
end
- elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
- if param:applyToMapHotspot(self.loadAiTargetMapHotspot) then
- g_currentMission:addMapHotspot(self.loadAiTargetMapHotspot)
- end
end
end
end
@@ -613,57 +613,68 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
self.aiTargetMapHotspot:setWorldRotation(angle)
end
- else
- element:updateTitle()
+ end
+ end
+end
+InGameMenuAIFrame.updateParameterValueTexts = Utils.overwrittenFunction(InGameMenuAIFrame.updateParameterValueTexts,
+ CpInGameMenuAIFrameExtended.updateParameterValueTexts)
- if parameterType == AIParameterType.UNLOADING_STATION then
- if parameter.applyToMapHotspot then
- if parameter:applyToMapHotspot(self.aiUnloadingMarkerHotspot) then
- g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
- end
- else
- local unloadingStation = parameter:getUnloadingStation()
+function CpInGameMenuAIFrameExtended:updateWarnings()
+ for _, element in ipairs(self.currentJobElements) do
+ local parameter = element.aiParameter
+ local parameterType = parameter:getType()
+ if parameterType == AIParameterType.TEXT then
+ local title = element:getDescendantByName("title")
- if unloadingStation ~= nil then
- local placeable = unloadingStation.owningPlaceable
+ title:setText(parameter:getString())
+ elseif parameterType == AIParameterType.UNLOADING_STATION then
+ element:updateTitle()
+ if parameter.applyToMapHotspot then
+ if parameter:applyToMapHotspot(self.aiUnloadingMarkerHotspot) then
+ g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
+ end
+ else
+ local unloadingStation = parameter:getUnloadingStation()
- if placeable ~= nil and placeable.getHotspot ~= nil then
- local hotspot = placeable:getHotspot(1)
+ if unloadingStation ~= nil then
+ local placeable = unloadingStation.owningPlaceable
- if hotspot ~= nil then
- local x, z = hotspot:getWorldPosition()
+ if placeable ~= nil and placeable.getHotspot ~= nil then
+ local hotspot = placeable:getHotspot(1)
- self.aiUnloadingMarkerHotspot:setWorldPosition(x, z)
- g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
- end
+ if hotspot ~= nil then
+ local x, z = hotspot:getWorldPosition()
+ self.aiUnloadingMarkerHotspot:setWorldPosition(x, z)
+ g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
end
end
end
- elseif parameterType == AIParameterType.LOADING_STATION then
- local loadingStation = parameter:getLoadingStation()
+ end
+ elseif parameterType == AIParameterType.UNLOADING_STATION then
+ element:updateTitle()
+ local loadingStation = parameter:getLoadingStation()
- if loadingStation ~= nil and parameter:getCanBeChanged() then
- local placeable = loadingStation.owningPlaceable
+ if loadingStation ~= nil and parameter:getCanBeChanged() then
+ local placeable = loadingStation.owningPlaceable
- if placeable ~= nil and placeable.getHotspot ~= nil then
- local hotspot = placeable:getHotspot(1)
+ if placeable ~= nil and placeable.getHotspot ~= nil then
+ local hotspot = placeable:getHotspot(1)
- if hotspot ~= nil then
- local x, z = hotspot:getWorldPosition()
+ if hotspot ~= nil then
+ local x, z = hotspot:getWorldPosition()
- self.aiLoadingMarkerHotspot:setWorldPosition(x, z)
- g_currentMission:addMapHotspot(self.aiLoadingMarkerHotspot)
- end
+ self.aiLoadingMarkerHotspot:setWorldPosition(x, z)
+ g_currentMission:addMapHotspot(self.aiLoadingMarkerHotspot)
end
end
end
end
-
element:setDisabled(not parameter:getCanBeChanged())
end
end
-InGameMenuAIFrame.updateParameterValueTexts = Utils.overwrittenFunction(InGameMenuAIFrame.updateParameterValueTexts,
- CpInGameMenuAIFrameExtended.updateParameterValueTexts)
+
+InGameMenuAIFrame.updateWarnings = Utils.appendedFunction(InGameMenuAIFrame.updateWarnings,
+ CpInGameMenuAIFrameExtended.updateWarnings)
--- Enables clickable field hotspots.
function CpInGameMenuAIFrameExtended:onClickHotspot(element,hotspot)
diff --git a/scripts/gui/CpGuiUtil.lua b/scripts/gui/CpGuiUtil.lua
index 4a3fd484b..7922faf61 100644
--- a/scripts/gui/CpGuiUtil.lua
+++ b/scripts/gui/CpGuiUtil.lua
@@ -169,6 +169,15 @@ function CpGuiUtil.getGenericSubTitleElementFromLayout(rootElement)
return CpGuiUtil.getFirstElementWithProfileName(rootElement, "settingsMenuSubtitle")
end
+--- Gets the rgb color in 0-1 from 0-255.
+---@param r number
+---@param g number
+---@param b number
+---@param alpha number|nil
+---@return number
+---@return number
+---@return number
+---@return number
function CpGuiUtil.getNormalizedRgb(r, g, b, alpha)
return r / 255, g / 255, b / 255, alpha
end
@@ -205,6 +214,64 @@ function CpGuiUtil.setTarget(element, target)
element.targetName = target.name
end
+------------------------------------------------
+--- Plots
+------------------------------------------------
+
+--- Translates the world coordinates to screen coordinates.
+---@param map table
+---@param worldX number
+---@param worldZ number
+---@param isHudMap boolean|nil If the hud minimap is used.
+---@return number
+---@return number
+---@return number
+---@return boolean
+function CpGuiUtil.worldToScreen(map, worldX, worldZ, isHudMap)
+ local objectX = (worldX + map.worldCenterOffsetX) / map.worldSizeX * 0.5 + 0.25
+ local objectZ = (worldZ + map.worldCenterOffsetZ) / map.worldSizeZ * 0.5 + 0.25
+ local x, y, _, _ = map.fullScreenLayout:getMapObjectPosition(objectX, objectZ, 0, 0, 0, true)
+ local rot = 0
+ local visible = true
+ if isHudMap then
+ --- The plot is displayed in the hud.
+ objectX = (worldX + map.worldCenterOffsetX) / map.worldSizeX * map.mapExtensionScaleFactor + map.mapExtensionOffsetX
+ objectZ = (worldZ + map.worldCenterOffsetZ) / map.worldSizeZ * map.mapExtensionScaleFactor + map.mapExtensionOffsetZ
+
+ x, y, rot, visible = map.layout:getMapObjectPosition(objectX, objectZ, 0, 0, 0, false)
+ if map.state == IngameMap.STATE_MINIMAP_ROUND and map.layout.rotateWithMap then
+ x, y, rot, visible = CpGuiUtil.getMapObjectPositionCircleLayoutFix(map.layout, objectX, objectZ, 0, 0, 0, false)
+ end
+ end
+ return x, y, rot, visible
+end
+
+--- Giants was not so kind, as to allow getting the positions even, if the object is outside the map range ...
+--- This is a custom version for: IngameMapLayoutCircle:getMapObjectPosition(...)
+---@param layout table
+---@param objectU number
+---@param objectV number
+---@param width number
+---@param height number
+---@param rot number
+---@param persistent boolean
+---@return number
+---@return number
+---@return number
+---@return boolean
+function CpGuiUtil.getMapObjectPositionCircleLayoutFix(layout, objectU, objectV, width, height, rot, persistent)
+ local mapWidth, mapHeight = layout:getMapSize()
+ local mapX, mapY = layout:getMapPosition()
+ local objectX = objectU * mapWidth + mapX
+ local objectY = (1 - objectV) * mapHeight + mapY
+ objectX, objectY, rot = layout:rotateWithMap(objectX, objectY, rot, persistent)
+ objectX = objectX - width * 0.5
+ objectY = objectY - height * 0.5
+
+ return objectX, objectY, rot, true
+end
+
+
------------------------------------------------
--- Hud
------------------------------------------------
diff --git a/scripts/gui/FieldPlot.lua b/scripts/gui/FieldPlot.lua
index fa8f3a415..ed7f3694e 100644
--- a/scripts/gui/FieldPlot.lua
+++ b/scripts/gui/FieldPlot.lua
@@ -48,7 +48,7 @@ function FieldPlot:draw(map)
local lastWp = self.waypoints and #self.waypoints>0 and self.waypoints[#self.waypoints]
if self.drawLastWp and lastWp then
- local x, y = self:worldToScreen(map, lastWp.x, lastWp.z )
+ local x, y = CpGuiUtil.worldToScreen(map, lastWp.x, lastWp.z )
local signSizeMeters = 1.5* self.lineThickness
local zoom = map.fullScreenLayout:getIconZoom()
local width, height = signSizeMeters * map.uiScale * zoom, signSizeMeters * map.uiScale * zoom * g_screenAspectRatio
diff --git a/scripts/gui/UnloadingTriggerPlot.lua b/scripts/gui/UnloadingTriggerPlot.lua
new file mode 100644
index 000000000..b8f84607a
--- /dev/null
+++ b/scripts/gui/UnloadingTriggerPlot.lua
@@ -0,0 +1,49 @@
+--- Draws the bunker silo dimensions on the in game map.
+---@class UnloadingTriggerPlot
+UnloadingTriggerPlot = CpObject()
+
+function UnloadingTriggerPlot:init(node)
+ self.courseOverlayId = createImageOverlay('dataS/scripts/shared/graph_pixel.dds')
+ self.isVisible = false
+ -- the normal FS22 blue
+ self.color = {CpGuiUtil.getNormalizedRgb(42, 193, 237)}
+ -- a lighter shade of the same color
+ self.lightColor = {CpGuiUtil.getNormalizedRgb(45, 207, 255)}
+ -- a darker shade of the same color
+ self.darkColor = {CpGuiUtil.getNormalizedRgb(19, 87, 107)}
+ self.lineThickness = 2 / g_screenHeight -- 2 pixels
+ self.isHighlighted = false
+ local _
+ self.x, _, self.z = getWorldTranslation(node)
+end
+
+function UnloadingTriggerPlot:draw(map)
+ local r, g, b = unpack(self.color)
+ setOverlayColor( self.courseOverlayId, r, g, b, 0.8 )
+ local x, y = CpGuiUtil.worldToScreen(map, self.x, self.z, false)
+
+ local s1x, s1y = CpGuiUtil.worldToScreen(map, self.x - 5, self.z - 5, false)
+ local e1x, e1y = CpGuiUtil.worldToScreen(map, self.x + 5, self.z + 5, false)
+ local s2x, s2y = CpGuiUtil.worldToScreen(map, self.x + 5, self.z - 5, false)
+ local e2x, e2y = CpGuiUtil.worldToScreen(map, self.x - 5, self.z + 5, false)
+
+ --- Create a coss through the node position
+ local mapRotation = map.layout:getMapRotation()
+ local dx2D = e1x - s1x
+ local dy2D = ( e1y - s1y ) / g_screenAspectRatio
+ local width = MathUtil.vector2Length(dx2D, dy2D)
+ local rotation = MathUtil.getYRotationFromDirection(10, 10) - math.pi * 0.5 + mapRotation
+ setOverlayRotation( self.courseOverlayId, rotation, 0, 0 )
+ renderOverlay( self.courseOverlayId, s1x, s1y, width, self.lineThickness )
+
+ dx2D = e2x - s2x
+ dy2D = ( e2y - s2y ) / g_screenAspectRatio
+ width = MathUtil.vector2Length(dx2D, dy2D)
+ rotation = MathUtil.getYRotationFromDirection(-10, 10) - math.pi * 0.5 + mapRotation
+ setOverlayRotation( self.courseOverlayId, rotation, 0, 0 )
+ renderOverlay( self.courseOverlayId, s2x, s2y, width, self.lineThickness )
+end
+
+function UnloadingTriggerPlot:setHighlighted(highlighted)
+ self.isHighlighted = highlighted
+end
\ No newline at end of file
diff --git a/scripts/silo/BunkerSiloVehicleController.lua b/scripts/silo/BunkerSiloVehicleController.lua
index caf5ac979..f7fa57df0 100644
--- a/scripts/silo/BunkerSiloVehicleController.lua
+++ b/scripts/silo/BunkerSiloVehicleController.lua
@@ -29,8 +29,6 @@ function CpBunkerSiloVehicleController:init(silo, vehicle, driveStrategy, direct
^
|
]]
-
-
if dsz > dhz then
self:debug("Silo needs to be inverted.")
self.isInverted = true
@@ -44,8 +42,6 @@ function CpBunkerSiloVehicleController:init(silo, vehicle, driveStrategy, direct
| v |
wx sx
]]
-
-
self.isInverted = true
elseif dsz < 0 and dhz > 0 then
self:debug("Start distance: dsz: %.2f, dhz: %.2f", dsz, dhz)
@@ -317,6 +313,24 @@ CpBunkerSiloLoaderController = CpObject(CpBunkerSiloVehicleController)
function CpBunkerSiloLoaderController:init(silo, vehicle, driveStrategy)
CpBunkerSiloVehicleController.init(self, silo, vehicle,
driveStrategy, vehicle:getAIDirectionNode())
+
+
+ local sx, sz = self.silo:getStartPosition()
+ local hx, hz = self.silo:getHeightPosition()
+ local dx, _, dz = getWorldTranslation(vehicle:getAIDirectionNode())
+ self.isInverted = false
+
+ if MathUtil.vector2Length(sx-dx, sz-dz) < MathUtil.vector2Length(hx-dx, hz-dz) then
+ if self.silo.siloMode == self.silo.SIDE_MODES.ONE_SIDED_INVERTED then
+ self.isInverted = true
+ end
+ else
+ self.isInverted = true
+ if self.silo.siloMode == self.silo.SIDE_MODES.ONE_SIDED then
+ self.isInverted = false
+ end
+ end
+
end
--- Gets the next line with the most fill level.
diff --git a/scripts/silo/BunkerSiloWrapper.lua b/scripts/silo/BunkerSiloWrapper.lua
index 7ef3fc4f0..5eeb15573 100644
--- a/scripts/silo/BunkerSiloWrapper.lua
+++ b/scripts/silo/BunkerSiloWrapper.lua
@@ -704,11 +704,3 @@ function CpBunkerSilo:getDebugData()
end
return data
end
-
-function CpBunkerSilo:getFillType()
- return self.silo.outputFillType
-end
-
-function CpBunkerSilo:getTotalFillLevel()
- return self.silo.fillLevel
-end
\ No newline at end of file
diff --git a/scripts/trigger/TriggerManager.lua b/scripts/trigger/TriggerManager.lua
index 0fc40dd6f..401fdfa08 100644
--- a/scripts/trigger/TriggerManager.lua
+++ b/scripts/trigger/TriggerManager.lua
@@ -1,29 +1,141 @@
--- Links all the needed trigger, except bunker silos to trigger wrappers.
+---@class TriggerManager
TriggerManager = CpObject()
function TriggerManager:init()
- self.unloadSilos = {}
+ ---@type table
+ self.unloadTriggers = {}
+ ---@type table
+ self.dischargeableUnloadTriggers = {}
end
function TriggerManager:addUnloadingSilo(silo)
if silo.exactFillRootNode ~= nil then
- self.unloadSilos[silo.exactFillRootNode] = CpTrigger(silo, silo.exactFillRootNode)
+ self.unloadTriggers[silo.exactFillRootNode] = CpTrigger(silo, silo.exactFillRootNode)
+ if silo:getIsToolTypeAllowed(ToolType.DISCHARGEABLE) then
+ self.dischargeableUnloadTriggers[silo.exactFillRootNode] = self.unloadTriggers[silo.exactFillRootNode]
+ end
end
end
function TriggerManager:removeUnloadingSilo(silo)
if silo.exactFillRootNode ~= nil then
- if self.unloadSilos[silo.exactFillRootNode] then
- self.unloadSilos[silo.exactFillRootNode]:delete()
- self.unloadSilos[silo.exactFillRootNode] = nil
+ if self.unloadTriggers[silo.exactFillRootNode] then
+ self.unloadTriggers[silo.exactFillRootNode]:delete()
+ self.unloadTriggers[silo.exactFillRootNode] = nil
+ self.dischargeableUnloadTriggers[silo.exactFillRootNode] = nil
end
end
end
function TriggerManager:getUnloadTriggerForNode(node)
- return self.unloadSilos[node]
+ return self.unloadTriggers[node]
+end
+
+--- Gets the first trigger found in the defined area.
+---@param triggers table
+---@param x number
+---@param z number
+---@param dirX number
+---@param dirZ number
+---@param width number
+---@param length number
+---@return boolean
+---@return table|nil
+---@return table|nil
+function TriggerManager:getTriggerAt(triggers, x, z, dirX, dirZ, width, length)
+ local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
+ local dirWX, dirWZ = MathUtil.getDirectionFromYRotation(angle + math.pi/2)
+ local sx, sz = x + dirWX * width/2, z + dirWZ * width/2
+
+ local area = {
+ {
+ x = sx,
+ z = sz
+ },
+ {
+ x = sx - dirWX * width,
+ z = sz - dirWZ * width
+ },
+ {
+ x = sx - dirWX * width + dirX * length,
+ z = sz - dirWZ * width + dirZ * length
+ },
+ {
+ x = sx + dirX * length,
+ z = sz + dirZ * length
+ },
+ {
+ x = sx,
+ z = sz
+ },
+ }
+ local dx, _, dz
+ for node, trigger in pairs(triggers) do
+ dx, _, dz = getWorldTranslation(node)
+ if CpMathUtil.isPointInPolygon(area, dx, dz) then
+ return true, trigger, trigger:getTrigger():getTarget()
+ end
+ end
+ return false
end
+--- Gets the first unload trigger found in the defined area.
+---@param x number
+---@param z number
+---@param dirX number
+---@param dirZ number
+---@param width number
+---@param length number
+---@return boolean
+---@return table|nil
+---@return table|nil
+function TriggerManager:getUnloadTriggerAt(x, z, dirX, dirZ, width, length)
+ return self:getTriggerAt(self.unloadTriggers, x, z, dirX, dirZ, width, length)
+end
+
+--- Gets the first dischargeable unload trigger found in the defined area.
+---@param x number
+---@param z number
+---@param dirX number
+---@param dirZ number
+---@param width number
+---@param length number
+---@return boolean
+---@return table|nil
+---@return table|nil
+function TriggerManager:getDischargeableUnloadTriggerAt(x, z, dirX, dirZ, width, length)
+ return self:getTriggerAt(self.dischargeableUnloadTriggers, x, z, dirX, dirZ, width, length)
+end
+
+function TriggerManager:update(dt)
+
+end
+
+--- Draws all bunker silos onto the ai map.
+---@param map table map to draw to.
+---@param selected CpTrigger silo that gets highlighted.
+function TriggerManager:drawUnloadTriggers(map, selected)
+ for _, trigger in pairs(self.unloadTriggers) do
+ trigger:drawPlot(map, selected)
+ end
+end
+
+--- Draws all bunker silos onto the ai map.
+---@param map table map to draw to.
+---@param selected CpTrigger silo that gets highlighted.
+function TriggerManager:drawDischargeableTriggers(map, selected)
+ for _, trigger in pairs(self.dischargeableUnloadTriggers) do
+ trigger:drawPlot(map, selected)
+ end
+end
+
+function TriggerManager:draw()
+ for node, trigger in pairs(self.unloadTriggers) do
+ local text = string.format("%s:\n %d", getName(node), node )
+ CpUtil.drawDebugNode(node, false, 2, text)
+ end
+end
g_triggerManager = TriggerManager()
diff --git a/scripts/trigger/TriggerWrapper.lua b/scripts/trigger/TriggerWrapper.lua
index 6729789f1..6fc538f0e 100644
--- a/scripts/trigger/TriggerWrapper.lua
+++ b/scripts/trigger/TriggerWrapper.lua
@@ -5,6 +5,7 @@ CpTrigger = CpObject()
function CpTrigger:init(trigger, node)
self.trigger = trigger
self.node = node
+ self.plot = UnloadingTriggerPlot(self.node)
end
function CpTrigger:delete()
@@ -17,4 +18,9 @@ end
function CpTrigger:getTrigger()
return self.trigger
+end
+
+function CpTrigger:drawPlot(map, selectedTrigger)
+ self.plot:setHighlighted(self == selectedTrigger)
+ self.plot:draw(map)
end
\ No newline at end of file
From 9148e2025d4551528eb279bb8162b1485d33f1f8 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 7 Jul 2023 22:06:24 +0200
Subject: [PATCH 009/107] Adjustment and tries to fix bug
---
.../ai/AIDriveStrategyShovelSiloLoader.lua | 5 +--
scripts/ai/ImplementUtil.lua | 6 ++--
scripts/ai/jobs/CpAIJobSiloLoader.lua | 35 +++++++++++--------
scripts/silo/BunkerSiloVehicleController.lua | 4 +--
scripts/specializations/CpShovelPositions.lua | 35 ++++++++++++++++---
5 files changed, 59 insertions(+), 26 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index bb5b13975..12ecd1824 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -86,8 +86,9 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
self.jobParameters = jobParameters
local position = jobParameters.unloadPosition
- self.unloadPositionNode = CpUtil.createNode("unloadPositionNode", position.x, position.z, position.angle )
-
+ if position.x and position.angle then
+ self.unloadPositionNode = CpUtil.createNode("unloadPositionNode", position.x, position.z, position.angle )
+ end
if self.bunkerSilo ~= nil then
self:debug("Bunker silo was found.")
self.silo = self.bunkerSilo
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index c7cf60699..32af4adc4 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -435,8 +435,10 @@ function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, di
local function debug(str, ...)
if not suppressLog then
- CpUtil.debugVehicle(CpDebug.DBG_SILO, implementToLoadFrom.rootVehicle,
- str, ...)
+ if g_updateLoopIndex % 100 == 0 then
+ CpUtil.debugVehicle(CpDebug.DBG_SILO, implementToLoadFrom.rootVehicle,
+ str, ...)
+ end
end
end
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index bffb77301..07b75d236 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -132,26 +132,31 @@ function CpAIJobSiloLoader:validate(farmId)
else
return false, g_i18n:getText("CP_error_no_heap_found")
end
-
- if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
- --- Validate the trigger setup
- local found, unloadTrigger, unloadStation = self:getUnloadTriggerAt(self.cpJobParameters.unloadPosition)
- if found then
- self.unloadStation = unloadStation
- self.unloadTrigger = unloadTrigger
- if unloadStation == nil then
+ if not AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) then
+ if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
+ --- Validate the trigger setup
+ local found, unloadTrigger, unloadStation = self:getUnloadTriggerAt(self.cpJobParameters.unloadPosition)
+ if found then
+ self.unloadStation = unloadStation
+ self.unloadTrigger = unloadTrigger
+ if unloadStation == nil then
+ return false, g_i18n:getText("CP_error_no_unload_trigger_found")
+ end
+ local id = NetworkUtil.getObjectId(unloadStation)
+ if id ~= nil then
+ self:getCpJobParameters().unloadStation:setValue(id)
+ self:getCpJobParameters().unloadStation:validateUnloadingStation()
+ end
+ else
return false, g_i18n:getText("CP_error_no_unload_trigger_found")
end
- local id = NetworkUtil.getObjectId(unloadStation)
- if id ~= nil then
- self:getCpJobParameters().unloadStation:setValue(id)
- self:getCpJobParameters().unloadStation:validateUnloadingStation()
- end
- else
+ end
+ local unloadPosition = self:getCpJobParameters()
+ if unloadPosition.x == nil or unloadPosition.angle == nil then
return false, g_i18n:getText("CP_error_no_unload_trigger_found")
end
+
end
-
return isValid, errorMessage
end
diff --git a/scripts/silo/BunkerSiloVehicleController.lua b/scripts/silo/BunkerSiloVehicleController.lua
index f7fa57df0..ff013ec0f 100644
--- a/scripts/silo/BunkerSiloVehicleController.lua
+++ b/scripts/silo/BunkerSiloVehicleController.lua
@@ -321,12 +321,12 @@ function CpBunkerSiloLoaderController:init(silo, vehicle, driveStrategy)
self.isInverted = false
if MathUtil.vector2Length(sx-dx, sz-dz) < MathUtil.vector2Length(hx-dx, hz-dz) then
- if self.silo.siloMode == self.silo.SIDE_MODES.ONE_SIDED_INVERTED then
+ if self.silo.siloMode == CpBunkerSilo.SIDE_MODES.ONE_SIDED_INVERTED then
self.isInverted = true
end
else
self.isInverted = true
- if self.silo.siloMode == self.silo.SIDE_MODES.ONE_SIDED then
+ if self.silo.siloMode == CpBunkerSilo.SIDE_MODES.ONE_SIDED then
self.isInverted = false
end
end
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 2873e8eac..0ff2ed870 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -55,7 +55,7 @@ CpShovelPositions = {
5
},
},
- DEBUG = false
+ DEBUG = true
}
CpShovelPositions.MOD_NAME = g_currentModName
CpShovelPositions.NAME = ".cpShovelPositions"
@@ -258,12 +258,37 @@ function CpShovelPositions.setShovelPosition(dt, spec, shovel, shovelNode, angle
dyRot = yRot
end
+ local tool = spec.shovelTool
+ if tool.rotSpeed == nil then
+ return
+ end
+
+ local spec = shovel.spec_cylindered
+ tool.curRot[1], tool.curRot[2], tool.curRot[3] = getRotation(tool.node)
+ local rotSpeed = MathUtil.clamp(dyRot * tool.rotSpeed, tool.rotSpeed/3, 0.5)
+ if dyRot < 0 then
+ rotSpeed=rotSpeed*(-1)
+ end
+
CpShovelPositions.debug(shovel,
- "Shovel position(%d) angle: %.2f, targetAngle: %.2f, yRot: %.2f, oldRot: %.2f",
- spec.state, math.deg(angle), math.deg(targetAngle), math.deg(dyRot), math.deg(oldRot))
+ "Shovel position angle: %.2f, targetAngle: %.2f, yRot: %.2f, oldRot: %.2f, rotSpeed: %.5f, rotMin: %.2f, rotMax: %.2f",
+ math.deg(angle), math.deg(targetAngle), math.deg(dyRot), math.deg(oldRot),
+ rotSpeed, math.deg(tool.rotMin), math.deg(tool.rotMax))
+
+ if math.abs(dyRot) < math.pi/(2*180) or rotSpeed == 0 then
+ ImplementUtil.stopMovingTool(shovel, tool)
+ return false
+ end
+ if Cylindered.setToolRotation(shovel, tool, rotSpeed, dt, dyRot) then
+ Cylindered.setDirty(shovel, tool)
+
+ shovel:raiseDirtyFlags(tool.dirtyFlag)
+ shovel:raiseDirtyFlags(spec.cylinderedDirtyFlag)
+ return true
+ end
- return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle, spec.shovelTool, dt,
- MathUtil.clamp(oldRot + dyRot , spec.shovelTool.rotMin, spec.shovelTool.rotMax))
+ -- return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle, spec.shovelTool, dt,
+ -- MathUtil.clamp(oldRot + dyRot , spec.shovelTool.rotMin, spec.shovelTool.rotMax))
end
--- Changes the front loader angle dependent on the selected position, relative to a target height.
From 146f44d33e969a84a26af87b76ce78e556811131 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 9 Jul 2023 13:41:19 +0200
Subject: [PATCH 010/107] Multiple adjustements and unload trigger support
---
config/VehicleConfigurations.xml | 5 +
.../ai/AIDriveStrategyShovelSiloLoader.lua | 222 ++++++++++++++----
scripts/ai/jobs/CpAIJobSiloLoader.lua | 2 +-
scripts/ai/jobs/CpJobParameters.lua | 2 +-
.../parameters/CpAIParameterPositionAngle.lua | 2 +-
scripts/ai/tasks/CpAITaskSiloLoader.lua | 4 +-
scripts/gui/CpAIFrameExtended.lua | 183 ++++++++-------
.../specializations/CpAISiloLoaderWorker.lua | 3 +-
scripts/specializations/CpShovelPositions.lua | 7 +-
scripts/trigger/TriggerManager.lua | 6 +-
10 files changed, 283 insertions(+), 153 deletions(-)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index b58b8e625..73f809328 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -314,6 +314,11 @@ You can define the following custom settings:
ignoreCollisionBoxesWhenFolded = "true"
/>
+
+
+
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 12ecd1824..d9cd0bdce 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -36,17 +36,24 @@ local AIDriveStrategyShovelSiloLoader_mt = Class(AIDriveStrategyShovelSiloLoader
AIDriveStrategyShovelSiloLoader.myStates = {
DRIVING_ALIGNMENT_COURSE = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+
DRIVING_INTO_SILO = {shovelPosition = ShovelController.POSITIONS.LOADING, shovelMovingSpeed = 0},
DRIVING_OUT_OF_SILO = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+
WAITING_FOR_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+
DRIVING_TO_UNLOAD_POSITION = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
+ DRIVING_TO_UNLOAD_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
DRIVING_TO_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
UNLOADING = {shovelPosition = ShovelController.POSITIONS.UNLOADING, shovelMovingSpeed = 0},
REVERSING_AWAY_FROM_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
}
AIDriveStrategyShovelSiloLoader.safeSpaceToTrailer = 5
-AIDriveStrategyShovelSiloLoader.maxValidTrailerDistance = 30
+AIDriveStrategyShovelSiloLoader.maxValidTrailerDistanceToSiloFront = 30
+AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 15
+AIDriveStrategyShovelSiloLoader.distShovelTrailerPreUnload = 7
+AIDriveStrategyShovelSiloLoader.distShovelUnloadStationPreUnload = 7
function AIDriveStrategyShovelSiloLoader.new(customMt)
if customMt == nil then
@@ -65,19 +72,28 @@ function AIDriveStrategyShovelSiloLoader:delete()
self.siloController = nil
end
CpUtil.destroyNode(self.heapNode)
- CpUtil.destroyNode(self.unloadNode)
CpUtil.destroyNode(self.unloadPositionNode)
+ CpUtil.destroyNode(self.siloFrontNode)
end
function AIDriveStrategyShovelSiloLoader:getGeneratedCourse(jobParameters)
return nil
end
+---@param bunkerSilo CpBunkerSilo
+---@param heapSilo CpHeapBunkerSilo
function AIDriveStrategyShovelSiloLoader:setSiloAndHeap(bunkerSilo, heapSilo)
self.bunkerSilo = bunkerSilo
self.heapSilo = heapSilo
end
+---@param unloadTrigger CpTrigger
+---@param unloadStation table
+function AIDriveStrategyShovelSiloLoader:setUnloadTriggerAndStation(unloadTrigger, unloadStation)
+ self.unloadTrigger = unloadTrigger
+ self.unloadStation = unloadStation
+end
+
function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
-- to always have a valid course (for the traffic conflict detector mainly)
@@ -85,9 +101,20 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
self:startCourse(self.course, 1)
self.jobParameters = jobParameters
- local position = jobParameters.unloadPosition
- if position.x and position.angle then
- self.unloadPositionNode = CpUtil.createNode("unloadPositionNode", position.x, position.z, position.angle )
+ self.unloadPositionNode = CpUtil.createNode("unloadPositionNode", 0, 0, 0)
+
+ self.isUnloadingAtTrailerActive = jobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRAILER
+ if not self.isUnloadingAtTrailerActive then
+ self:debug("Starting shovel silo to unload into unload trigger.")
+ local x, y, z = getWorldTranslation(self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode())
+ setTranslation(self.unloadPositionNode, x, y, z)
+ local position = jobParameters.unloadPosition
+ local dirX, dirZ = position:getDirection()
+ setDirection(self.unloadPositionNode, dirX, 0, dirZ, 0, 0, 1)
+ local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -self.distShovelUnloadStationPreUnload)
+ setTranslation(self.unloadPositionNode, dx, dy, dz)
+ else
+ self:debug("Starting shovel silo to unload into trailer.")
end
if self.bunkerSilo ~= nil then
self:debug("Bunker silo was found.")
@@ -97,6 +124,9 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
self.silo = self.heapSilo
end
+ local cx, cz = self.silo:getFrontCenter()
+ self.siloFrontNode = CpUtil.createNode("siloFrontNode", cx, cz, 0)
+
self.siloController = CpBunkerSiloLoaderController(self.silo, self.vehicle, self)
end
@@ -128,7 +158,8 @@ function AIDriveStrategyShovelSiloLoader:setAllStaticParameters()
self.siloEndProximitySensor = SingleForwardLookingProximitySensorPack(self.vehicle, self.shovelController:getShovelNode(), 5, 1)
self.heapNode = CpUtil.createNode("heapNode", 0, 0, 0, nil)
- self.unloadNode = CpUtil.createNode("unloadNode", 0, 0, 0, nil)
+
+ self.lastTrailerSearch = 0
end
-----------------------------------------------------------------------------------------------------------------------
@@ -139,20 +170,26 @@ function AIDriveStrategyShovelSiloLoader:onWaypointPassed(ix, course)
if self.state == self.states.DRIVING_ALIGNMENT_COURSE then
local course = self:getRememberedCourseAndIx()
self:startCourse(course, 1)
- self.state = self.states.DRIVING_INTO_SILO
+ self:setNewState(self.states.DRIVING_INTO_SILO)
elseif self.state == self.states.DRIVING_INTO_SILO then
self:startDrivingOutOfSilo()
elseif self.state == self.states.DRIVING_OUT_OF_SILO then
- self:startPathfindingToUnloadPosition()
+ if self.isUnloadingAtTrailerActive then
+ self:setNewState(self.states.WAITING_FOR_TRAILER)
+ else
+ self:startPathfindingToUnloadPosition()
+ end
+ elseif self.state == self.states.DRIVING_TO_UNLOAD_TRAILER then
+ self:approachTrailerForUnloading()
elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
- self.state = self.states.WAITING_FOR_TRAILER
+ self:approachUnloadStationForUnloading()
elseif self.state == self.states.DRIVING_TO_UNLOAD then
- self.state = self.states.UNLOADING
+ self:setNewState(self.states.UNLOADING)
elseif self.state == self.states.REVERSING_AWAY_FROM_UNLOAD then
if self.shovelController:isEmpty() then
self:startDrivingToSilo()
else
- self.state = self.states.WAITING_FOR_TRAILER
+ self:setNewState(self.states.WAITING_FOR_TRAILER)
end
--self.vehicle:stopCurrentAIJob(AIMessageSuccessFinishedJob.new())
end
@@ -165,7 +202,7 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:updateLowFrequencyImplementControllers()
local moveForwards = not self.ppc:isReversing()
- local gx, gz
+ local gx, gz, _
----------------------------------------------------------------
if not moveForwards then
@@ -210,19 +247,30 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:setMaxSpeed(self.settings.fieldSpeed:getValue())
elseif self.state == self.states.WAITING_FOR_TRAILER then
self:setMaxSpeed(0)
- self:searchForTrailerToUnloadInto()
+ if (g_time - self.lastTrailerSearch) > self.searchForTrailerDelaySec * 1000 then
+ self:searchForTrailerToUnloadInto()
+ self.lastTrailerSearch = g_time
+ end
elseif self.state == self.states.DRIVING_TO_UNLOAD then
self:setMaxSpeed(self.settings.reverseSpeed:getValue())
- if self.targetTrailer then
- if self.shovelController:isShovelOverTrailer(self.targetTrailer.exactFillRootNode) then
- self.state = self.states.UNLOADING
- self:setMaxSpeed(0)
- end
+ local refNode
+ if self.isUnloadingAtTrailerActive then
+ refNode = self.targetTrailer.exactFillRootNode
+ else
+ refNode = self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode()
+ end
+ if self.shovelController:isShovelOverTrailer(refNode) then
+ self:setNewState(self.states.UNLOADING)
+ self:setMaxSpeed(0)
end
elseif self.state == self.states.UNLOADING then
self:setMaxSpeed(0)
- if self:hasFinishedUnloading() then
- self:startReversingAwayFromUnloading()
+ if self:hasFinishedUnloading() then
+ if self.isUnloadingAtTrailerActive then
+ self:startReversingAwayFromUnloading()
+ else
+ self:startDrivingToSilo()
+ end
end
elseif self.state == self.states.REVERSING_AWAY_FROM_UNLOAD then
self:setMaxSpeed(self.settings.fieldSpeed:getValue())
@@ -255,7 +303,6 @@ function AIDriveStrategyShovelSiloLoader:update(dt)
CpUtil.drawDebugNode(self.heapNode, false, 3)
end
if self.targetTrailer then
- CpUtil.drawDebugNode(self.unloadNode, false, 3)
CpUtil.drawDebugNode(self.targetTrailer.exactFillRootNode, false, 3, "ExactFillRootNode")
end
CpUtil.drawDebugNode(self.unloadPositionNode, false, 3)
@@ -278,6 +325,11 @@ function AIDriveStrategyShovelSiloLoader:getProximitySensorWidth()
return self.vehicle.size.width - 0.5
end
+function AIDriveStrategyShovelSiloLoader:setNewState(newState)
+ self:debug("Changed State from %s to %s", self.state.name, newState.name)
+ self.state = newState
+end
+
----------------------------------------------------------------
--- Pathfinding
----------------------------------------------------------------
@@ -286,10 +338,8 @@ end
---@param course table heap course
function AIDriveStrategyShovelSiloLoader:startPathfindingToStart(course)
if not self.pathfinder or not self.pathfinder:isActive() then
- self.state = self.states.WAITING_FOR_PATHFINDER
+ self:setNewState(self.states.WAITING_FOR_PATHFINDER)
self:rememberCourse(course, 1)
-
- self.pathfindingStartedAt = g_currentMission.time
local done, path
local fm = self:getFrontAndBackMarkers()
self.pathfinder, done, path = PathfinderUtil.startPathfindingFromVehicleToWaypoint(
@@ -311,24 +361,24 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToStart(path)
self:debug("Found alignment path to the course for the heap.")
local alignmentCourse = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
self:startCourse(alignmentCourse, 1)
- self.state = self.states.DRIVING_ALIGNMENT_COURSE
+ self:setNewState(self.states.DRIVING_ALIGNMENT_COURSE)
else
local course = self:getRememberedCourseAndIx()
self:debug("No alignment path found!")
self:startCourse(course, 1)
- self.state = self.states.DRIVING_INTO_SILO
+ self:setNewState(self.states.DRIVING_INTO_SILO)
end
end
function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
- self:debugSparse("Searching for an trailer nearby.")
+ self:debug("Searching for an trailer nearby.")
local function getClosestTrailerAndDistance()
local closestDistance = math.huge
local closestTrailer = nil
for i, vehicle in pairs(g_currentMission.vehicles) do
if SpecializationUtil.hasSpecialization(Trailer, vehicle.specializations) and AIUtil.isStopped(vehicle.rootVehicle) then
- local dist = calcDistanceFrom(vehicle.rootNode, self.unloadPositionNode)
+ local dist = calcDistanceFrom(vehicle.rootNode, self.siloFrontNode)
if dist < closestDistance then
closestDistance = dist
closestTrailer = vehicle
@@ -339,9 +389,11 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
end
local trailer, dist = getClosestTrailerAndDistance()
if not trailer then
+ self:debug("No valid trailer found anywhere!")
return
end
- if dist > 20 then
+ if dist > self.maxValidTrailerDistanceToSiloFront then
+ self:debug("No Trailer with the max distance found, closest: %.2f", dist)
return
end
self:debug("Found a trailer %s within distance %.2f", CpUtil.getName(trailer), dist)
@@ -354,29 +406,36 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
exactFillRootNode = exactFillRootNode,
trailer = trailer
}
- local dx, _, dz = getWorldTranslation(exactFillRootNode)
- local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
- local course = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
- 0, -3, 0, 3, false)
- local firstWpIx = course:getNearestWaypoints(self.vehicle:getAIDirectionNode())
- self:startCourse(course, firstWpIx)
- self.state = self.states.DRIVING_TO_UNLOAD
+
+ local _, _, distShovelDirectionNode = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
+ --self.distShovelTrailerPreUnload
+ local dirX, _, dirZ = localDirectionToWorld(trailer.rootNode, 0, 0, 1)
+ local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
+ local dx, _, dz = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
+ if dx > 0 then
+ local x, y, z = localToWorld(trailer.rootNode, dx + distShovelDirectionNode + self.distShovelTrailerPreUnload, 0, 0)
+ setTranslation(self.unloadPositionNode, x, y, z)
+ setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
+
+ else
+ local x, y, z = localToWorld(trailer.rootNode, dx - distShovelDirectionNode -self.distShovelTrailerPreUnload, 0, 0)
+ setTranslation(self.unloadPositionNode, x, y, z)
+ setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
+ end
+ self:startPathfindingToTrailer()
+
end
end
function AIDriveStrategyShovelSiloLoader:startPathfindingToUnloadPosition()
if not self.pathfinder or not self.pathfinder:isActive() then
- self.state = self.states.WAITING_FOR_PATHFINDER
-
-
- local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
- self.pathfindingStartedAt = g_currentMission.time
+ self:setNewState(self.states.WAITING_FOR_PATHFINDER)
local done, path, goalNodeInvalid
self.pathfinder, done, path, goalNodeInvalid = PathfinderUtil.startPathfindingFromVehicleToNode(
self.vehicle, self.unloadPositionNode,
- 0, -2*spaceToTrailer, true,
+ 0, 0, true,
nil, {}, nil,
- 0, nil, true
+ 0, nil, false
)
if done then
return self:onPathfindingDoneToUnloadPosition(path, goalNodeInvalid)
@@ -394,13 +453,45 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path,
self:debug("Found path to unloading station.")
local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
self:startCourse(course, 1)
- self.state = self.states.DRIVING_TO_UNLOAD_POSITION
+ self:setNewState(self.states.DRIVING_TO_UNLOAD_POSITION)
else
self:debug("Failed to drive close to unload position.")
- self.state = self.states.WAITING_FOR_TRAILER
+ --self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
end
end
+function AIDriveStrategyShovelSiloLoader:startPathfindingToTrailer()
+ if not self.pathfinder or not self.pathfinder:isActive() then
+ self:setNewState(self.states.WAITING_FOR_PATHFINDER)
+ local done, path, goalNodeInvalid
+ self.pathfinder, done, path, goalNodeInvalid = PathfinderUtil.startPathfindingFromVehicleToNode(
+ self.vehicle, self.unloadPositionNode,
+ 0, 0, true,
+ nil, {}, nil,
+ 0, nil, false
+ )
+ if done then
+ return self:onPathfindingDoneToTrailer(path, goalNodeInvalid)
+ else
+ self:setPathfindingDoneCallback(self, self.onPathfindingDoneToTrailer)
+ end
+ else
+ self:debug('Pathfinder already active')
+ end
+ return true
+end
+
+function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToTrailer(path, goalNodeInvalid)
+ if path and #path > 2 then
+ self:debug("Found path to unloading station.")
+ local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
+ self:startCourse(course, 1)
+ self:setNewState(self.states.DRIVING_TO_UNLOAD_TRAILER)
+ else
+ self:debug("Failed to find path to trailer!")
+ self:setNewState(self.states.WAITING_FOR_TRAILER)
+ end
+end
----------------------------------------------------------------
--- Silo work
----------------------------------------------------------------
@@ -416,13 +507,13 @@ function AIDriveStrategyShovelSiloLoader:startDrivingToSilo()
local distance = siloCourse:getDistanceBetweenVehicleAndWaypoint(self.vehicle, 1)
- if distance > 2 * self.turningRadius then
+ if distance > 1.5 * self.turningRadius then
self:debug("Start driving to silo with pathfinder.")
self:startPathfindingToStart(siloCourse)
else
self:debug("Start driving into the silo.")
self:startCourse(siloCourse, 1)
- self.state = self.states.DRIVING_INTO_SILO
+ self:setNewState(self.states.DRIVING_INTO_SILO)
end
end
@@ -438,7 +529,27 @@ function AIDriveStrategyShovelSiloLoader:startDrivingOutOfSilo()
ix = reverseCourse:getNumberOfWaypoints()
end
self:startCourse(reverseCourse, ix)
- self.state = self.states.DRIVING_OUT_OF_SILO
+ self:setNewState(self.states.DRIVING_OUT_OF_SILO)
+end
+
+function AIDriveStrategyShovelSiloLoader:approachTrailerForUnloading()
+ local dx, _, dz = getWorldTranslation(self.targetTrailer.exactFillRootNode)
+ local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
+ local course = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
+ 0, -3, 0, 3, false)
+ local firstWpIx = course:getNearestWaypoints(self.vehicle:getAIDirectionNode())
+ self:startCourse(course, firstWpIx)
+ self:setNewState(self.states.DRIVING_TO_UNLOAD)
+end
+
+function AIDriveStrategyShovelSiloLoader:approachUnloadStationForUnloading()
+ local dx, _, dz = getWorldTranslation(self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode())
+ local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
+ local course = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
+ 0, -3, 0, 3, false)
+ local firstWpIx = course:getNearestWaypoints(self.vehicle:getAIDirectionNode())
+ self:startCourse(course, firstWpIx)
+ self:setNewState(self.states.DRIVING_TO_UNLOAD)
end
function AIDriveStrategyShovelSiloLoader:getWorkWidth()
@@ -449,9 +560,16 @@ end
--- Unloading
----------------------------------------------------------------
function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
- if self.targetTrailer and self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
- self:debug("Trailer is full, abort unloading into trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
- return true
+ if self.isUnloadingAtTrailerActive then
+ if self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
+ self:debug("Trailer is full, abort unloading into trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
+ return true
+ end
+ else
+ if self.unloadTrigger:getTrigger():getFillUnitFreeCapacity(1, self.shovelController:getDischargeFillType(), self.vehicle:getOwnerFarmId()) then
+ self:debug("Unload Trigger is full.")
+ return true
+ end
end
if self.shovelController:isEmpty() then
self:debug("Finished unloading, as the shovel is empty.")
@@ -465,5 +583,5 @@ function AIDriveStrategyShovelSiloLoader:startReversingAwayFromUnloading()
local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
local course = Course.createStraightReverseCourse(self.vehicle, 2*spaceToTrailer, 0 )
self:startCourse(course, 1)
- self.state = self.states.REVERSING_AWAY_FROM_UNLOAD
+ self:setNewState(self.states.REVERSING_AWAY_FROM_UNLOAD)
end
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 07b75d236..2f290a512 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -151,7 +151,7 @@ function CpAIJobSiloLoader:validate(farmId)
return false, g_i18n:getText("CP_error_no_unload_trigger_found")
end
end
- local unloadPosition = self:getCpJobParameters()
+ local unloadPosition = self:getCpJobParameters().unloadPosition
if unloadPosition.x == nil or unloadPosition.angle == nil then
return false, g_i18n:getText("CP_error_no_unload_trigger_found")
end
diff --git a/scripts/ai/jobs/CpJobParameters.lua b/scripts/ai/jobs/CpJobParameters.lua
index 5aff5addb..7f41b3964 100644
--- a/scripts/ai/jobs/CpJobParameters.lua
+++ b/scripts/ai/jobs/CpJobParameters.lua
@@ -347,7 +347,7 @@ function CpSiloLoaderJobParameters:isShovelSiloLoadDisabled()
end
function CpSiloLoaderJobParameters:isUnloadPositionDisabled()
- return false --self:isShovelSiloLoadDisabled() or self.unloadAt == CpSiloLoaderJobParameters.UNLOAD_TRAILER
+ return self:isShovelSiloLoadDisabled() or self.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRAILER
end
function CpSiloLoaderJobParameters:isUnloadStationDisabled()
diff --git a/scripts/ai/parameters/CpAIParameterPositionAngle.lua b/scripts/ai/parameters/CpAIParameterPositionAngle.lua
index dbdac4b0a..8561c3698 100644
--- a/scripts/ai/parameters/CpAIParameterPositionAngle.lua
+++ b/scripts/ai/parameters/CpAIParameterPositionAngle.lua
@@ -109,7 +109,7 @@ end
function CpAIParameterPosition:isAlmostEqualTo(otherPosition)
local x, z = otherPosition:getPosition()
if x ~= nil and self.x ~= nil then
- return MathUtil.vector2Length(self.x - x, self.z - z) <= 1
+ return MathUtil.vector2Length(self.x - x, self.z - z) <= 1
end
return false
end
diff --git a/scripts/ai/tasks/CpAITaskSiloLoader.lua b/scripts/ai/tasks/CpAITaskSiloLoader.lua
index b4a6feb0c..ddfc5333a 100644
--- a/scripts/ai/tasks/CpAITaskSiloLoader.lua
+++ b/scripts/ai/tasks/CpAITaskSiloLoader.lua
@@ -1,5 +1,6 @@
--- Bunker silo task
---@class CpAITaskSiloLoader
+---@field job table
CpAITaskSiloLoader = {}
local CpAITaskSiloLoader_mt = Class(CpAITaskSiloLoader, AITask)
@@ -32,7 +33,8 @@ end
function CpAITaskSiloLoader:start()
if self.isServer then
- self.vehicle:startCpSiloLoaderWorker(self.job:getCpJobParameters(), self.silo, self.heap)
+ local _, unloadTrigger, unloadStation = self.job:getUnloadTriggerAt(self.job:getCpJobParameters().unloadPosition)
+ self.vehicle:startCpSiloLoaderWorker(self.job:getCpJobParameters(), self.silo, self.heap, unloadTrigger, unloadStation)
end
CpAITaskSiloLoader:superClass().start(self)
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index 3ce7d0915..21f4cb161 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -101,7 +101,7 @@ function CpInGameMenuAIFrameExtended:onAIFrameLoadMapFinished()
g_messageCenter:subscribe(MessageType.GUI_AFTER_CLOSE, onCloseInGameMenu, g_currentMission.inGameMenu)
g_messageCenter:subscribe(MessageType.GUI_BEFORE_OPEN, onOpenInGameMenu, g_currentMission.inGameMenu)
--- Closes the course generator settings with the back button.
- local function onClickBack(pageAI,superFunc)
+ local function onClickBack(pageAI,superFunc)
if pageAI.mode == CpInGameMenuAIFrameExtended.MODE_COURSE_GENERATOR then
pageAI:onClickOpenCloseCourseGenerator()
return
@@ -111,19 +111,27 @@ function CpInGameMenuAIFrameExtended:onAIFrameLoadMapFinished()
return
end
CpInGameMenuAIFrameExtended.resetHotspots(self)
- return superFunc(pageAI)
+ superFunc(pageAI)
+ if pageAI:getIsPicking() then
+ self:updateParameterValueTexts()
+ end
+
end
- self.buttonBack.onClickCallback = Utils.overwrittenFunction(self.buttonBack.onClickCallback,onClickBack)
- self.ingameMapBase.drawHotspotsOnly = Utils.appendedFunction(self.ingameMapBase.drawHotspotsOnly , CpInGameMenuAIFrameExtended.draw)
+ self.buttonBack.onClickCallback = Utils.overwrittenFunction(
+ self.buttonBack.onClickCallback,onClickBack)
+
+ self.ingameMapBase.drawHotspotsOnly = Utils.appendedFunction(
+ self.ingameMapBase.drawHotspotsOnly , CpInGameMenuAIFrameExtended.draw)
- --- Adds a second map hotspot for field position.
+ --- Adds the ai target hotspot.
+ self.driveToAiTargetMapHotspot = AITargetHotspot.new()
self.fieldSiloAiTargetMapHotspot = AITargetHotspot.new()
self.fieldSiloAiTargetMapHotspot.icon:setUVs(CpInGameMenuAIFrameExtended.positionUvs) --- Without angle
-
self.unloadAiTargetMapHotspot = AITargetHotspot.new()
-
self.loadAiTargetMapHotspot = AITargetHotspot.new()
+ self.rawAiTargetMapHotspot = self.aiTargetMapHotspot
+
self.ingameMap.onClickHotspotCallback = Utils.appendedFunction(self.ingameMap.onClickHotspotCallback,
CpInGameMenuAIFrameExtended.onClickHotspot)
@@ -197,6 +205,17 @@ end
InGameMenuAIFrame.updateContextInputBarVisibility = Utils.appendedFunction(InGameMenuAIFrame.updateContextInputBarVisibility,CpInGameMenuAIFrameExtended.updateContextInputBarVisibility)
+function CpInGameMenuAIFrameExtended:setJobMenuVisible(visible)
+ if not visible then
+ g_currentMission:removeMapHotspot(self.driveToAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
+ g_currentMission:removeMapHotspot(self.aiTargetMapHotspot)
+ end
+end
+InGameMenuAIFrame.setJobMenuVisible = Utils.appendedFunction(InGameMenuAIFrame.setJobMenuVisible, CpInGameMenuAIFrameExtended.setJobMenuVisible)
+
function CpInGameMenuAIFrameExtended:isCreateFieldBorderBtnVisible()
local visible = self.mode == CpInGameMenuAIFrameExtended.MODE_DRAW_FIELD_BORDER or
self.mode == InGameMenuAIFrame.MODE_OVERVIEW and self.currentHotspot == nil
@@ -321,64 +340,64 @@ end
--- Updates the visibility of the vehicle settings on select/unselect of a vehicle in the ai menu page.
--- Also updates the field position map hotspot.
function CpInGameMenuAIFrameExtended:setMapSelectionItem(hotspot)
+ g_currentMission:removeMapHotspot(self.driveToAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.aiTargetMapHotspot)
- if hotspot ~= nil then
- local vehicle = InGameMenuMapUtil.getHotspotVehicle(hotspot)
- self.lastVehicle = vehicle
- self.hudVehicle = nil
- if vehicle then
- if vehicle.getJob ~= nil then
- local job = vehicle:getJob()
-
- if job ~= nil then
- if job.getCpJobParameters ~= nil then
- local parameters = job:getCpJobParameters():getAiTargetMapHotspotParameters()
- for i, param in pairs(parameters) do
- if param:is_a(CpAIParameterPosition) then
- if param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
- if param:applyToMapHotspot(self.aiTargetMapHotspot) then
- g_currentMission:addMapHotspot(self.aiTargetMapHotspot)
- end
- elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
- if param:applyToMapHotspot(self.fieldSiloAiTargetMapHotspot) then
- g_currentMission:addMapHotspot(self.fieldSiloAiTargetMapHotspot)
- end
- elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
- if param:applyToMapHotspot(self.loadAiTargetMapHotspot) then
- g_currentMission:addMapHotspot(self.loadAiTargetMapHotspot)
- end
- elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD then
- if param:applyToMapHotspot(self.unloadAiTargetMapHotspot) then
- g_currentMission:addMapHotspot(self.unloadAiTargetMapHotspot)
- end
- end
- elseif param:is_a(CpAIParameterUnloadingStation) then
- g_currentMission:removeMapHotspot(self.aiUnloadingMarkerHotspot)
- if param:applyToMapHotspot(self.aiUnloadingMarkerHotspot) then
- g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
- end
- end
- end
+ if hotspot == nil then
+ return
+ end
+ local vehicle = InGameMenuMapUtil.getHotspotVehicle(hotspot)
+ self.lastVehicle = vehicle
+ self.hudVehicle = nil
+ if vehicle == nil or vehicle.getJob == nil then
+ return
+ end
+ local job = vehicle:getJob()
+ if job == nil or job.getCpJobParameters == nil then
+ return
+ end
+ if vehicle:getIsCpActive() then
+ local parameters = job:getCpJobParameters():getAiTargetMapHotspotParameters()
+ for i, param in pairs(parameters) do
+ if param:is_a(CpAIParameterPosition) then
+ if param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
+ if param:applyToMapHotspot(self.driveToAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.driveToAiTargetMapHotspot)
end
- if job.getTarget ~= nil then
- local x, z, rot = job:getTarget()
-
- self.aiTargetMapHotspot:setWorldPosition(x, z)
-
- if rot ~= nil then
- self.aiTargetMapHotspot:setWorldRotation(rot + math.pi)
- end
-
- g_currentMission:addMapHotspot(self.aiTargetMapHotspot)
+ elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
+ if param:applyToMapHotspot(self.fieldSiloAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.fieldSiloAiTargetMapHotspot)
+ end
+ elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
+ if param:applyToMapHotspot(self.loadAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.loadAiTargetMapHotspot)
+ end
+ elseif param:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD then
+ if param:applyToMapHotspot(self.unloadAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.unloadAiTargetMapHotspot)
end
end
-
+ elseif param:is_a(CpAIParameterUnloadingStation) then
+ g_currentMission:removeMapHotspot(self.aiUnloadingMarkerHotspot)
+ if param:applyToMapHotspot(self.aiUnloadingMarkerHotspot) then
+ g_currentMission:addMapHotspot(self.aiUnloadingMarkerHotspot)
+ end
end
end
end
+ if job.getTarget ~= nil then
+ local x, z, rot = job:getTarget()
+
+ self.aiTargetMapHotspot:setWorldPosition(x, z)
+
+ if rot ~= nil then
+ self.aiTargetMapHotspot:setWorldRotation(rot + math.pi)
+ end
+
+ g_currentMission:addMapHotspot(self.aiTargetMapHotspot)
+ end
g_currentMission.inGameMenu:updatePages()
end
InGameMenuAIFrame.setMapSelectionItem = Utils.appendedFunction(InGameMenuAIFrame.setMapSelectionItem, CpInGameMenuAIFrameExtended.setMapSelectionItem)
@@ -406,6 +425,7 @@ function CpInGameMenuAIFrameExtended:onAIFrameClose()
self.courseGeneratorLayout:setVisible(false)
self.contextBox:setVisible(true)
self.lastHotspot = self.currentHotspot
+ g_currentMission:removeMapHotspot(self.driveToAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
@@ -470,20 +490,20 @@ function CpInGameMenuAIFrameExtended:draw()
end
function CpInGameMenuAIFrameExtended:delete()
+ if self.driveToAiTargetMapHotspot then
+ self.driveToAiTargetMapHotspot:delete()
+ self.driveToAiTargetMapHotspot = nil
+ end
if self.fieldSiloAiTargetMapHotspot ~= nil then
self.fieldSiloAiTargetMapHotspot:delete()
-
self.fieldSiloAiTargetMapHotspot = nil
end
-
if self.unloadAiTargetMapHotspot ~= nil then
self.unloadAiTargetMapHotspot:delete()
-
self.unloadAiTargetMapHotspot = nil
end
if self.loadAiTargetMapHotspot ~= nil then
self.loadAiTargetMapHotspot:delete()
-
self.loadAiTargetMapHotspot = nil
end
end
@@ -499,16 +519,8 @@ function CpInGameMenuAIFrameExtended:onClickPositionParameter(superFunc, element
end
InGameMenuAIFrame.onClickPositionParameter = Utils.overwrittenFunction(
InGameMenuAIFrame.onClickPositionParameter, CpInGameMenuAIFrameExtended.onClickPositionParameter)
-
-function CpInGameMenuAIFrameExtended:onClickPositionRotationParameter(superFunc, element, ...)
- local parameter = element.aiParameter
- if parameter:getCanBeChanged() then
- --- Checks if the position setting is not disabled
- superFunc(self, element, ...)
- end
-end
InGameMenuAIFrame.onClickPositionRotationParameter = Utils.overwrittenFunction(
- InGameMenuAIFrame.onClickPositionRotationParameter, CpInGameMenuAIFrameExtended.onClickPositionRotationParameter)
+ InGameMenuAIFrame.onClickPositionRotationParameter, CpInGameMenuAIFrameExtended.onClickPositionParameter)
--- Ugly hack to swap the main AI hotspot with the field position hotspot,
@@ -517,25 +529,23 @@ function CpInGameMenuAIFrameExtended:startPickingPosition(superFunc, parameter,
if parameter and parameter.getPositionType then
CpInGameMenuAIFrameExtended.resetHotspots(self)
- if parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
- local mapHotspot = self.aiTargetMapHotspot
+ if parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
+ self.aiTargetMapHotspot = self.driveToAiTargetMapHotspot
+ self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO
+ elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
self.aiTargetMapHotspot = self.fieldSiloAiTargetMapHotspot
- self.fieldSiloAiTargetMapHotspot = mapHotspot
self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO
elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD then
- local mapHotspot = self.aiTargetMapHotspot
self.aiTargetMapHotspot = self.unloadAiTargetMapHotspot
- self.unloadAiTargetMapHotspot = mapHotspot
self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD
elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
- local mapHotspot = self.aiTargetMapHotspot
self.aiTargetMapHotspot = self.loadAiTargetMapHotspot
- self.loadAiTargetMapHotspot = mapHotspot
self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.LOAD
end
end
callback = Utils.appendedFunction(callback,function (finished, x, z)
CpInGameMenuAIFrameExtended.resetHotspots(self)
+ self:updateParameterValueTexts()
end)
superFunc(self, parameter, callback, ...)
@@ -547,20 +557,10 @@ InGameMenuAIFrame.startPickPositionAndRotation = Utils.overwrittenFunction(InGam
CpInGameMenuAIFrameExtended.startPickingPosition)
function CpInGameMenuAIFrameExtended:resetHotspots()
- if self.currentPickingMapHotspotType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
- local mapHotspot = self.aiTargetMapHotspot
- self.aiTargetMapHotspot = self.fieldSiloAiTargetMapHotspot
- self.fieldSiloAiTargetMapHotspot = mapHotspot
- self.currentPickingMapHotspotType = nil
- elseif self.currentPickingMapHotspotType == CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD then
- local mapHotspot = self.aiTargetMapHotspot
- self.aiTargetMapHotspot = self.unloadAiTargetMapHotspot
- self.unloadAiTargetMapHotspot = mapHotspot
- self.currentPickingMapHotspotType = nil
- end
+ self.aiTargetMapHotspot = self.rawAiTargetMapHotspot
+ self.currentPickingMapHotspotType = nil
end
-
--- Added support for the cp field target position.
function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
if self.currentJobElements == nil then
@@ -569,6 +569,7 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
g_currentMission:removeMapHotspot(self.aiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.aiLoadingMarkerHotspot)
g_currentMission:removeMapHotspot(self.aiUnloadingMarkerHotspot)
+ g_currentMission:removeMapHotspot(self.driveToAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.loadAiTargetMapHotspot)
@@ -583,8 +584,8 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
elseif parameter.is_a and parameter:is_a(CpAIParameterPosition) then
element:setText(parameter:getString())
if parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
- if parameter:applyToMapHotspot(self.aiTargetMapHotspot) then
- g_currentMission:addMapHotspot(self.aiTargetMapHotspot)
+ if parameter:applyToMapHotspot(self.driveToAiTargetMapHotspot) then
+ g_currentMission:addMapHotspot(self.driveToAiTargetMapHotspot)
end
elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
if parameter:applyToMapHotspot(self.fieldSiloAiTargetMapHotspot) then
@@ -676,6 +677,10 @@ end
InGameMenuAIFrame.updateWarnings = Utils.appendedFunction(InGameMenuAIFrame.updateWarnings,
CpInGameMenuAIFrameExtended.updateWarnings)
+--------------------------------------------
+--- Custom fields
+--------------------------------------------
+
--- Enables clickable field hotspots.
function CpInGameMenuAIFrameExtended:onClickHotspot(element,hotspot)
if hotspot then
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index 0b8771950..58d485318 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -178,7 +178,7 @@ function CpAISiloLoaderWorker:startCpAtLastWp(superFunc, ...)
end
end
-function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap)
+function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap, unloadTrigger, unloadStation)
if self.isServer then
local strategy
if AIUtil.hasAIImplementWithSpecialization(self, ConveyorBelt) then
@@ -189,6 +189,7 @@ function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo,
strategy = AIDriveStrategyShovelSiloLoader.new()
end
strategy:setSiloAndHeap(bunkerSilo, heap)
+ strategy:setUnloadTriggerAndStation(unloadTrigger, unloadStation)
strategy:setAIVehicle(self, jobParameters)
self:startCpWithStrategy(strategy)
end
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 0ff2ed870..cf7c8c27d 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -55,7 +55,7 @@ CpShovelPositions = {
5
},
},
- DEBUG = true
+ DEBUG = false
}
CpShovelPositions.MOD_NAME = g_currentModName
CpShovelPositions.NAME = ".cpShovelPositions"
@@ -64,9 +64,8 @@ CpShovelPositions.KEY = "." .. CpShovelPositions.SPEC_NAME
function CpShovelPositions.initSpecialization()
local schema = Vehicle.xmlSchemaSavegame
- if CpShovelPositions.DEBUG then
- g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelState', 'cpSetShovelState', 'consoleCommandSetShovelState', CpShovelPositions)
- end
+ g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelState', 'cpSetShovelState', 'consoleCommandSetShovelState', CpShovelPositions)
+
end
function CpShovelPositions.prerequisitesPresent(specializations)
diff --git a/scripts/trigger/TriggerManager.lua b/scripts/trigger/TriggerManager.lua
index 401fdfa08..3c84f4c22 100644
--- a/scripts/trigger/TriggerManager.lua
+++ b/scripts/trigger/TriggerManager.lua
@@ -101,9 +101,9 @@ end
---@param dirZ number
---@param width number
---@param length number
----@return boolean
----@return table|nil
----@return table|nil
+---@return boolean found?
+---@return table|nil unload trigger
+---@return table|nil unload station/placeable
function TriggerManager:getDischargeableUnloadTriggerAt(x, z, dirX, dirZ, width, length)
return self:getTriggerAt(self.dischargeableUnloadTriggers, x, z, dirX, dirZ, width, length)
end
From 5c43613fffa6a2ac2339e87c89f26e8fa56aa0ed Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 9 Jul 2023 14:12:23 +0200
Subject: [PATCH 011/107] Bug fix and adjustments for unloading into trailer
---
.../ai/AIDriveStrategyShovelSiloLoader.lua | 22 +++++++++++++------
scripts/ai/jobs/CpAIJobSiloLoader.lua | 9 ++++----
scripts/silo/BunkerSiloWrapper.lua | 4 ++++
3 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index d9cd0bdce..a37c47c17 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -62,6 +62,7 @@ function AIDriveStrategyShovelSiloLoader.new(customMt)
local self = AIDriveStrategyCourse.new(customMt)
AIDriveStrategyCourse.initStates(self, AIDriveStrategyShovelSiloLoader.myStates)
self.state = self.states.INITIAL
+ self.debugChannel = CpDebug.DBG_SILO
return self
end
@@ -219,7 +220,11 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
return
end
if self.shovelController:isFull() then
- self:startPathfindingToUnloadPosition()
+ if self.isUnloadingAtTrailerActive then
+ self:setNewState(self.states.WAITING_FOR_TRAILER)
+ else
+ self:startPathfindingToUnloadPosition()
+ end
else
self:startDrivingToSilo()
end
@@ -245,6 +250,8 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
self:setMaxSpeed(self.settings.fieldSpeed:getValue())
+ elseif self.state == self.states.DRIVING_TO_UNLOAD_TRAILER then
+ self:setMaxSpeed(self.settings.fieldSpeed:getValue())
elseif self.state == self.states.WAITING_FOR_TRAILER then
self:setMaxSpeed(0)
if (g_time - self.lastTrailerSearch) > self.searchForTrailerDelaySec * 1000 then
@@ -406,24 +413,25 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
exactFillRootNode = exactFillRootNode,
trailer = trailer
}
-
+ self:debug("Unloading to trailer %s in distance %.2f.", CpUtil.getName(trailer), dist)
local _, _, distShovelDirectionNode = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
--self.distShovelTrailerPreUnload
local dirX, _, dirZ = localDirectionToWorld(trailer.rootNode, 0, 0, 1)
local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
local dx, _, dz = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
if dx > 0 then
- local x, y, z = localToWorld(trailer.rootNode, dx + distShovelDirectionNode + self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, dx - distShovelDirectionNode - self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
- setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
+ setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
else
- local x, y, z = localToWorld(trailer.rootNode, dx - distShovelDirectionNode -self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, dx + distShovelDirectionNode + self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
- setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
+ setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
end
self:startPathfindingToTrailer()
-
+ else
+ self:debug("Unloading into trailer %s not possible.", CpUtil.getName(trailer))
end
end
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 2f290a512..914e2eac5 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -150,12 +150,11 @@ function CpAIJobSiloLoader:validate(farmId)
else
return false, g_i18n:getText("CP_error_no_unload_trigger_found")
end
+ local unloadPosition = self:getCpJobParameters().unloadPosition
+ if unloadPosition.x == nil or unloadPosition.angle == nil then
+ return false, g_i18n:getText("CP_error_no_unload_trigger_found")
+ end
end
- local unloadPosition = self:getCpJobParameters().unloadPosition
- if unloadPosition.x == nil or unloadPosition.angle == nil then
- return false, g_i18n:getText("CP_error_no_unload_trigger_found")
- end
-
end
return isValid, errorMessage
end
diff --git a/scripts/silo/BunkerSiloWrapper.lua b/scripts/silo/BunkerSiloWrapper.lua
index 5eeb15573..2ddfe1a4f 100644
--- a/scripts/silo/BunkerSiloWrapper.lua
+++ b/scripts/silo/BunkerSiloWrapper.lua
@@ -205,6 +205,10 @@ function CpSilo:getTotalFillLevel()
return 0
end
+function CpSilo:isTheSameSilo()
+ --- override
+end
+
--- Heap Bunker Silo
--- Wrapper for a heap.
---@class CpHeapBunkerSilo :CpSilo
From 6b17e4c68df60d66eca23d72515a2145666dc92e Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 9 Jul 2023 14:20:20 +0200
Subject: [PATCH 012/107] Small adjustment
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index a37c47c17..19e42e23c 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -420,12 +420,12 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
local dx, _, dz = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
if dx > 0 then
- local x, y, z = localToWorld(trailer.rootNode, dx - distShovelDirectionNode - self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, dx + math.abs(distShovelDirectionNode) + self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
else
- local x, y, z = localToWorld(trailer.rootNode, dx + distShovelDirectionNode + self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, dx - math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
end
@@ -491,7 +491,7 @@ end
function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToTrailer(path, goalNodeInvalid)
if path and #path > 2 then
- self:debug("Found path to unloading station.")
+ self:debug("Found path to trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
self:startCourse(course, 1)
self:setNewState(self.states.DRIVING_TO_UNLOAD_TRAILER)
From 6a08ca735e523b58d8bee5b7980b3f5c3dcaab5b Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 9 Jul 2023 14:21:34 +0200
Subject: [PATCH 013/107] Another stupid fix ..
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 19e42e23c..0c0f4300f 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -415,17 +415,16 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
}
self:debug("Unloading to trailer %s in distance %.2f.", CpUtil.getName(trailer), dist)
local _, _, distShovelDirectionNode = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
- --self.distShovelTrailerPreUnload
local dirX, _, dirZ = localDirectionToWorld(trailer.rootNode, 0, 0, 1)
local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
local dx, _, dz = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
if dx > 0 then
- local x, y, z = localToWorld(trailer.rootNode, dx + math.abs(distShovelDirectionNode) + self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, math.abs(distShovelDirectionNode) + self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
else
- local x, y, z = localToWorld(trailer.rootNode, dx - math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, - math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
end
From 2cf45fe06afb95f914154a8740e1143ee915f51e Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 10 Jul 2023 17:02:12 +0200
Subject: [PATCH 014/107] Adjustments
---
.../ai/AIDriveStrategyShovelSiloLoader.lua | 26 +-
scripts/ai/controllers/ShovelController.lua | 9 +
scripts/specializations/CpShovelPositions.lua | 231 +++++++++++-------
3 files changed, 164 insertions(+), 102 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 0c0f4300f..2a8b90c82 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -267,17 +267,20 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
refNode = self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode()
end
if self.shovelController:isShovelOverTrailer(refNode) then
- self:setNewState(self.states.UNLOADING)
- self:setMaxSpeed(0)
+ -- self:setNewState(self.states.UNLOADING)
+ -- self:setMaxSpeed(0)
+ end
+ if not self.isUnloadingAtTrailerActive then
+ if self.shovelController:isShovelOverTrailer(refNode, 3) and self.shovelController:canDischarge() then
+ self:setNewState(self.states.UNLOADING)
+ self:setMaxSpeed(0)
+ end
end
+
elseif self.state == self.states.UNLOADING then
self:setMaxSpeed(0)
if self:hasFinishedUnloading() then
- if self.isUnloadingAtTrailerActive then
- self:startReversingAwayFromUnloading()
- else
- self:startDrivingToSilo()
- end
+ self:startReversingAwayFromUnloading()
end
elseif self.state == self.states.REVERSING_AWAY_FROM_UNLOAD then
self:setMaxSpeed(self.settings.fieldSpeed:getValue())
@@ -422,9 +425,8 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
local x, y, z = localToWorld(trailer.rootNode, math.abs(distShovelDirectionNode) + self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
-
else
- local x, y, z = localToWorld(trailer.rootNode, - math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
+ local x, y, z = localToWorld(trailer.rootNode, -math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
setTranslation(self.unloadPositionNode, x, y, z)
setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
end
@@ -553,7 +555,7 @@ function AIDriveStrategyShovelSiloLoader:approachUnloadStationForUnloading()
local dx, _, dz = getWorldTranslation(self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode())
local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
local course = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
- 0, -3, 0, 3, false)
+ 0, -3, 3, 2, false)
local firstWpIx = course:getNearestWaypoints(self.vehicle:getAIDirectionNode())
self:startCourse(course, firstWpIx)
self:setNewState(self.states.DRIVING_TO_UNLOAD)
@@ -573,9 +575,9 @@ function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
return true
end
else
- if self.unloadTrigger:getTrigger():getFillUnitFreeCapacity(1, self.shovelController:getDischargeFillType(), self.vehicle:getOwnerFarmId()) then
+ if self.unloadTrigger:getTrigger():getFillUnitFreeCapacity(1, self.shovelController:getDischargeFillType(), self.vehicle:getOwnerFarmId()) <= 0 then
self:debug("Unload Trigger is full.")
- return true
+ return false
end
end
if self.shovelController:isEmpty() then
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index f4e193e03..96ac9da32 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -56,6 +56,15 @@ function ShovelController:getDischargeNode()
return self.implement:getCurrentDischargeNode()
end
+function ShovelController:canDischarge()
+ local dischargeNode = self:getDischargeNode()
+ local spec = self.implement.spec_dischargeable
+ if not spec.isAsyncRaycastActive then
+ self.implement:updateRaycast(dischargeNode)
+ end
+ return dischargeNode.dischargeHit
+end
+
--- Is the shovel node over the trailer?
---@param refNode number
---@param margin number|nil
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index cf7c8c27d..8d24151c4 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -41,8 +41,8 @@ CpShovelPositions = {
},
PRE_UNLOAD_POSITION = {
ARM_LIMITS = {
- 3,
- 4
+ 7,
+ 7
},
SHOVEL_LIMITS = {
43,
@@ -51,11 +51,11 @@ CpShovelPositions = {
},
UNLOADING_POSITION = {
ARM_LIMITS = {
- 4,
- 5
+ 7,
+ 7
},
},
- DEBUG = false
+ DEBUG = true
}
CpShovelPositions.MOD_NAME = g_currentModName
CpShovelPositions.NAME = ".cpShovelPositions"
@@ -65,7 +65,7 @@ CpShovelPositions.KEY = "." .. CpShovelPositions.SPEC_NAME
function CpShovelPositions.initSpecialization()
local schema = Vehicle.xmlSchemaSavegame
g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelState', 'cpSetShovelState', 'consoleCommandSetShovelState', CpShovelPositions)
-
+ g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelArmLimit', 'cpSetShovelArmLimit', 'consoleCommandSetPreUnloadArmLimit', CpShovelPositions)
end
function CpShovelPositions.prerequisitesPresent(specializations)
@@ -120,26 +120,45 @@ function CpShovelPositions:onDraw()
end
end
-function CpShovelPositions:consoleCommandSetShovelState(state)
+local function executeConsoleCommand(func, ...)
local vehicle = g_currentMission.controlledVehicle
if not vehicle then
CpUtil.info("Not entered a valid vehicle!")
+ return false
end
- state = tonumber(state)
- if state == nil or state < 0 or state > CpShovelPositions.NUM_STATES then
- CpUtil.infoVehicle(vehicle, "No valid state(0 - %d) was given!", CpShovelPositions.NUM_STATES)
- return
- end
- if not vehicle:getIsAIActive() then
- local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(vehicle, Shovel)
- if found then
- shovels[1]:cpSetShovelState(state)
- else
- CpUtil.infoVehicle(vehicle, "No valid vehicle/implement with a shovel was found!")
- end
- else
+ if vehicle:getIsAIActive() then
CpUtil.infoVehicle(vehicle, "Error, AI is active!")
+ return false
+ end
+ local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(vehicle, Shovel)
+ if not found then
+ CpUtil.infoVehicle(vehicle, "No shovel implement found!")
+ return false
end
+ return func(shovels[1], ...)
+end
+
+function CpShovelPositions:consoleCommandSetShovelState(state)
+ return executeConsoleCommand(function(shovelImplement, state)
+ state = tonumber(state)
+ if state == nil or state < 0 or state > CpShovelPositions.NUM_STATES then
+ CpUtil.infoVehicle(shovelImplement, "No valid state(0 - %d) was given!", CpShovelPositions.NUM_STATES)
+ return false
+ end
+ shovelImplement:cpSetShovelState(state)
+ end, state)
+end
+
+function CpShovelPositions:consoleCommandSetPreUnloadArmLimit(min, max)
+ return executeConsoleCommand(function(shovelImplement, min, max)
+ min = tonumber(min)
+ max = tonumber(max)
+ if min == nil or max == nil then
+ CpUtil.infoVehicle(shovelImplement, "No valid limits given! min: %s, max: %s", tostring(min), tostring(max))
+ return false
+ end
+ CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS = { min, max }
+ end, min, max)
end
--- Changes the current shovel state position.
@@ -186,7 +205,9 @@ function CpShovelPositions:cpSetupShovelPositions()
spec.armTool = tool
spec.armVehicle = vehicle
spec.armProjectionNode = CpUtil.createNode("CpShovelArmProjectionNode",
- 0, 0, 0, getParent(tool.node))
+ 0, 0, 0, vehicle.rootNode)
+ spec.armToolRefNode = CpUtil.createNode("CpShovelArmToolRefNode",
+ 0, 0, 0, vehicle.rootNode)
elseif tool.axis == "AXIS_FRONTLOADER_TOOL" then
spec.shovelToolIx = i
spec.shovelTool = tool
@@ -220,74 +241,101 @@ end
function CpShovelPositions.setShovelPosition(dt, spec, shovel, shovelNode, angle, limits)
local min, max = unpack(limits)
local targetAngle = math.rad(min) + math.rad(max - min)/2
- if math.deg(angle) < max and math.deg(angle) > min then
- ImplementUtil.stopMovingTool(spec.shovelVehicle, spec.shovelTool)
- return false
- end
-
-
+ local deltaAngle = targetAngle - angle
local curRot = {}
curRot[1], curRot[2], curRot[3] = getRotation(spec.shovelTool.node)
local oldRot = curRot[spec.shovelTool.rotationAxis]
- local radius = calcDistanceFrom(shovelNode, spec.shovelTool.node)
- local x, y, z = getTranslation(spec.shovelTool.node)
-
- setTranslation(spec.shovelProjectionNode, x, y, z)
-
- setRotation(spec.shovelProjectionNode, targetAngle - math.pi/2, 0, 0)
+ local goalAngle = MathUtil.clamp(oldRot + deltaAngle, spec.shovelTool.rotMin, spec.shovelTool.rotMax)
+ return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle, spec.shovelTool, dt,
+ goalAngle)
+end
- local sx, sy, sz = getWorldTranslation(shovelNode)
- local tx, _, tz = getWorldTranslation(spec.shovelTool.node)
- local px, py, pz = localToWorld(spec.shovelProjectionNode, 0, 0, radius)
-
- if CpShovelPositions.DEBUG then
- DebugUtil.drawDebugCircleAtNode(spec.shovelTool.node, radius, 30, nil, true)
+function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits)
+ local min, max = unpack(shovelLimits)
+ local targetAngle = math.rad(min) + math.rad(max - min)/2
+ min, max = unpack(armLimits)
+ local targetHeight = min + (max - min)/2
- DebugUtil.drawDebugLine(px, py, pz, sx, sy, sz)
- DebugUtil.drawDebugLine(px, py, pz, tx, py, tz)
- end
+ local shovelTool = self.spec_cpShovelPositions.shovelTool
+ local armTool = self.spec_cpShovelPositions.armTool
+ local shovelVehicle = self.spec_cpShovelPositions.shovelVehicle
+ local armVehicle = self.spec_cpShovelPositions.armVehicle
- local yRot = math.atan2(MathUtil.vector3Length(px - sx, py - sy, pz - sz),
- MathUtil.vector3Length(px - tx, py - py, pz - tz))
+ local curRot = {}
+ curRot[1], curRot[2], curRot[3] = getRotation(shovelTool.node)
+ local oldShovelRot = curRot[shovelTool.rotationAxis]
- local dyRot = 0
- if angle > targetAngle then
- dyRot = -yRot
- else
- dyRot = yRot
- end
+ local curRot = {}
+ curRot[1], curRot[2], curRot[3] = getRotation(armTool.node)
+ local oldArmRot = curRot[armTool.rotationAxis]
+ local armProjectionNode = self.spec_cpShovelPositions.armProjectionNode
+ local armToolRefNode = self.spec_cpShovelPositions.armToolRefNode
+ local radius = calcDistanceFrom(shovelTool.node, armTool.node)
- local tool = spec.shovelTool
- if tool.rotSpeed == nil then
- return
- end
-
- local spec = shovel.spec_cylindered
- tool.curRot[1], tool.curRot[2], tool.curRot[3] = getRotation(tool.node)
- local rotSpeed = MathUtil.clamp(dyRot * tool.rotSpeed, tool.rotSpeed/3, 0.5)
- if dyRot < 0 then
- rotSpeed=rotSpeed*(-1)
- end
-
- CpShovelPositions.debug(shovel,
- "Shovel position angle: %.2f, targetAngle: %.2f, yRot: %.2f, oldRot: %.2f, rotSpeed: %.5f, rotMin: %.2f, rotMax: %.2f",
- math.deg(angle), math.deg(targetAngle), math.deg(dyRot), math.deg(oldRot),
- rotSpeed, math.deg(tool.rotMin), math.deg(tool.rotMax))
-
- if math.abs(dyRot) < math.pi/(2*180) or rotSpeed == 0 then
- ImplementUtil.stopMovingTool(shovel, tool)
- return false
+ local attacherJointNode = self.spec_attachable.attacherJoint.node
+ local angle, shovelNode = CpShovelPositions.getShovelData(self)
+ local _, shovelY, _ = localToLocal(shovelNode, attacherJointNode, 0, 0, 0)
+
+ local _, ty, tz = localToLocal(getChildAt(armTool.node, 0), armVehicle.rootNode, 0, 0, 0)
+ local ax, ay, az = localToLocal(armTool.node, armVehicle.rootNode, 0, 0, 0)
+ local sx, sy, sz = 0, targetHeight - shovelY, 0
+ local ex, ey, ez = 0, targetHeight - shovelY, 20
+ local yMax = ay + radius
+ if sy > yMax then
+ sy = yMax - 0.01
+ ey = yMax - 0.01
end
- if Cylindered.setToolRotation(shovel, tool, rotSpeed, dt, dyRot) then
- Cylindered.setDirty(shovel, tool)
-
- shovel:raiseDirtyFlags(tool.dirtyFlag)
- shovel:raiseDirtyFlags(spec.cylinderedDirtyFlag)
- return true
+ local hasIntersection, i1z, i1y, i2z, i2y = MathUtil.getCircleLineIntersection(az, ay, radius,
+ sz, sy, ez, ey)
+ local wsx, wsy, wsz = localToWorld(armVehicle.rootNode, sx, sy, sz)
+ local wex, wey, wez = localToWorld(armVehicle.rootNode, ex, ey, ez)
+ DebugUtil.drawDebugLine(wsx, wsy, wsz, wex, wey, wez)
+
+ DebugUtil.drawDebugCircleAtNode(armVehicle.rootNode, radius, 30, nil,
+ true, {ax, ay, az})
+ CpUtil.drawDebugNode(armVehicle.rootNode)
+ CpUtil.drawDebugNode(armTool.node)
+ CpUtil.drawDebugNode(shovelTool.node)
+ local isDirty
+ if hasIntersection then
+ setTranslation(armProjectionNode, 0, i1y, i1z)
+ setTranslation(armToolRefNode, ax, ay, az)
+ local _, shy, shz = localToLocal(shovelTool.node, armVehicle.rootNode, 0, 0, 0)
+ local dirZ, dirY = MathUtil.vector2Normalize(shz - az, shy - ay)
+ local yRot = MathUtil.getYRotationFromDirection(-dirZ, dirY) + math.pi/2
+
+ CpUtil.drawDebugNode(armProjectionNode)
+ CpUtil.drawDebugNode(armToolRefNode)
+ local alpha = math.atan2(i1y - ay, i1z - az)
+ local beta = -math.atan2(i2y - ay, i2z - az)
+ local debugData = {
+ {
+ name = "alpha", value = math.deg(alpha)
+ },
+ {
+ name = "deltaAlphaOld", value = math.deg(MathUtil.getAngleDifference(alpha, oldArmRot))
+ },
+ {
+ name = "old", value = math.deg(oldArmRot)
+ },
+ {
+ name = "deltaAlpha", value = math.deg(MathUtil.getAngleDifference(alpha, yRot))
+ },
+ {
+ name = "dirRot", value = math.deg(yRot)
+ },
+ {
+ name = "distAlpha", value = MathUtil.vector2Length(i1z - tz, i1y - ty)
+ },
+ }
+ DebugUtil.renderTable(0.4, 0.4, 0.018, debugData, 0)
+ local angle = MathUtil.clamp(oldArmRot - MathUtil.getAngleDifference(alpha, yRot), armTool.rotMin, armTool.rotMax)
+ isDirty = ImplementUtil.moveMovingToolToRotation(armVehicle, armTool, dt, angle)
end
-
- -- return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle, spec.shovelTool, dt,
- -- MathUtil.clamp(oldRot + dyRot , spec.shovelTool.rotMin, spec.shovelTool.rotMax))
+ local deltaAngle = targetAngle - angle
+ local goalAngle = MathUtil.clamp(oldShovelRot + deltaAngle, shovelTool.rotMin, shovelTool.rotMax)
+ isDirty = isDirty or ImplementUtil.moveMovingToolToRotation(shovelVehicle, shovelTool, dt, goalAngle)
+ return isDirty
end
--- Changes the front loader angle dependent on the selected position, relative to a target height.
@@ -316,10 +364,8 @@ function CpShovelPositions.setArmPosition(dt, spec, shovel, shovelNode, limits)
curRot[1], curRot[2], curRot[3] = getRotation(spec.armTool.node)
local oldRot = curRot[spec.armTool.rotationAxis]
-
setWorldTranslation(spec.armProjectionNode, x, targetAttacherHeight, z)
-
local _, ay, _ = localToLocal(spec.armTool.node, spec.armVehicle.rootNode, 0, 0, 0)
local nodeDiff = MathUtil.clamp( targetHeight - ay , -shovelR, shovelR) + ay
@@ -357,8 +403,9 @@ function CpShovelPositions:updateLoadingPosition(dt)
local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
local isDirty
if angle then
- isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS)
- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
+ isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
+ -- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
end
spec.isDirty = isDirty
end
@@ -368,8 +415,10 @@ function CpShovelPositions:updateTransportPosition(dt)
local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
local isDirty
if angle then
- isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS)
- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
+ isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
+ -- isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS)
+ -- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
end
spec.isDirty = isDirty
end
@@ -378,9 +427,11 @@ function CpShovelPositions:updatePreUnloadPosition(dt)
local spec = self.spec_cpShovelPositions
local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
local isDirty
- if angle then
- isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS)
- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, self:getCpShovelUnloadingPositionHeight())
+ if angle then
+ isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS, CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS)
+ --isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS)
+ --isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, self:getCpShovelUnloadingPositionHeight())
end
spec.isDirty = isDirty
end
@@ -390,8 +441,8 @@ function CpShovelPositions:updateUnloadingPosition(dt)
local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
local isDirty
if angle and maxAngle then
- isDirty = CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, self:getCpShovelUnloadingPositionHeight())
- isDirty = isDirty or CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, {math.deg(maxAngle), math.deg(maxAngle) + 2})
+ isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ {math.deg(maxAngle), math.deg(maxAngle) + 2}, CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS)
end
spec.isDirty = isDirty
end
From 3217780d7d4dddc713490eae3ee6eaf3c9f56718 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 10 Jul 2023 17:02:55 +0200
Subject: [PATCH 015/107] small fix
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 2a8b90c82..116cf4ad1 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -267,8 +267,8 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
refNode = self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode()
end
if self.shovelController:isShovelOverTrailer(refNode) then
- -- self:setNewState(self.states.UNLOADING)
- -- self:setMaxSpeed(0)
+ self:setNewState(self.states.UNLOADING)
+ self:setMaxSpeed(0)
end
if not self.isUnloadingAtTrailerActive then
if self.shovelController:isShovelOverTrailer(refNode, 3) and self.shovelController:canDischarge() then
From 3f09f3f20cba21a3aa78cf56d554cab1c1bac07f Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:32:51 +0200
Subject: [PATCH 016/107] Maybe this one works better
---
scripts/ai/controllers/ShovelController.lua | 3 +++
1 file changed, 3 insertions(+)
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 96ac9da32..6f9d52055 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -60,7 +60,10 @@ function ShovelController:canDischarge()
local dischargeNode = self:getDischargeNode()
local spec = self.implement.spec_dischargeable
if not spec.isAsyncRaycastActive then
+ local oldNode = dischargeNode.raycast.node
+ dischargeNode.raycast.node = self.implement.spec_attachable.attacherJoint.node
self.implement:updateRaycast(dischargeNode)
+ dischargeNode.raycast.node = oldNode
end
return dischargeNode.dischargeHit
end
From b258ab08bcf560e7b571bf81dbc9b2ec05d14b73 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:36:24 +0200
Subject: [PATCH 017/107] logic fix
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 116cf4ad1..26f3c728b 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -569,6 +569,10 @@ end
--- Unloading
----------------------------------------------------------------
function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
+ if self.shovelController:isEmpty() then
+ self:debug("Finished unloading, as the shovel is empty.")
+ return true
+ end
if self.isUnloadingAtTrailerActive then
if self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
self:debug("Trailer is full, abort unloading into trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
@@ -580,10 +584,6 @@ function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
return false
end
end
- if self.shovelController:isEmpty() then
- self:debug("Finished unloading, as the shovel is empty.")
- return true
- end
return false
end
From ac1a0cd2fefafd4b0dc5a9c05418e4f07902f882 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 10 Jul 2023 18:48:38 +0200
Subject: [PATCH 018/107] Added debug infos
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 26f3c728b..42efcac54 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -309,6 +309,7 @@ function AIDriveStrategyShovelSiloLoader:update(dt)
if self.silo then
self.silo:drawDebug()
end
+ self.siloController:draw()
if self.heapSilo then
CpUtil.drawDebugNode(self.heapNode, false, 3)
end
@@ -465,7 +466,7 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path,
self:setNewState(self.states.DRIVING_TO_UNLOAD_POSITION)
else
self:debug("Failed to drive close to unload position.")
- --self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
+ self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
end
end
@@ -509,13 +510,9 @@ function AIDriveStrategyShovelSiloLoader:startDrivingToSilo()
local startPos, endPos = self.siloController:getTarget(self:getWorkWidth())
local x, z = unpack(startPos)
local dx, dz = unpack(endPos)
-
local siloCourse = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
0, 0, 3, 3, false)
-
-
local distance = siloCourse:getDistanceBetweenVehicleAndWaypoint(self.vehicle, 1)
-
if distance > 1.5 * self.turningRadius then
self:debug("Start driving to silo with pathfinder.")
self:startPathfindingToStart(siloCourse)
@@ -530,7 +527,6 @@ function AIDriveStrategyShovelSiloLoader:startDrivingOutOfSilo()
local startPos, endPos = self.siloController:getLastTarget()
local x, z = unpack(endPos)
local dx, dz = unpack(startPos)
-
local reverseCourse = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
0, 0, 6, 3, true)
local ix = reverseCourse:getNextRevWaypointIxFromVehiclePosition(1, self.vehicle:getAIDirectionNode(), 10)
@@ -584,7 +580,6 @@ function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
return false
end
end
-
return false
end
From d455c35b6f6a354d5e87c5d64763c32b6d96cac2 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 11 Jul 2023 15:06:21 +0200
Subject: [PATCH 019/107] Diff unload station improvements and added high rise
shovel unload
---
config/VehicleConfigurations.xml | 7 +-
.../ai/AIDriveStrategyShovelSiloLoader.lua | 206 +++++++++++-------
scripts/ai/ImplementUtil.lua | 56 +++--
scripts/ai/controllers/ShovelController.lua | 7 +
scripts/ai/jobs/CpAIJobSiloLoader.lua | 28 ++-
scripts/ai/tasks/CpAITaskSiloLoader.lua | 4 +-
scripts/config/VehicleConfigurations.lua | 1 +
scripts/gui/CpAIFrameExtended.lua | 8 +-
scripts/gui/UnloadingTriggerPlot.lua | 14 +-
.../specializations/CpAIBunkerSiloWorker.lua | 3 +-
.../specializations/CpAISiloLoaderWorker.lua | 4 +-
scripts/specializations/CpShovelPositions.lua | 22 +-
scripts/trigger/TriggerManager.lua | 31 ++-
scripts/trigger/TriggerWrapper.lua | 31 ++-
14 files changed, 286 insertions(+), 136 deletions(-)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index 73f809328..778c285c4 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -97,6 +97,9 @@ You can define the following custom settings:
Overrides the automatic selection of a moving tool for example for the shield controller of a snowcat.
Used to control the target tilt.
+- shovelMovingToolIx: number
+ If the shovel is a high dump shovel then this moving tool ix is needed.
+
- modName: Name of the .zip file (without '.zip')
In case a Mod has the same .xml filename for the vehicle/implement, as a default giants vehicle/implement,
add the name of the .zip file to prevent conflicts. For example: "FS22_exampleMod".
@@ -317,7 +320,9 @@ You can define the following custom settings:
-
+
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 42efcac54..6308574f2 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -89,10 +89,8 @@ function AIDriveStrategyShovelSiloLoader:setSiloAndHeap(bunkerSilo, heapSilo)
end
---@param unloadTrigger CpTrigger
----@param unloadStation table
-function AIDriveStrategyShovelSiloLoader:setUnloadTriggerAndStation(unloadTrigger, unloadStation)
+function AIDriveStrategyShovelSiloLoader:setUnloadTrigger(unloadTrigger)
self.unloadTrigger = unloadTrigger
- self.unloadStation = unloadStation
end
function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
@@ -104,15 +102,19 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
self.jobParameters = jobParameters
self.unloadPositionNode = CpUtil.createNode("unloadPositionNode", 0, 0, 0)
+ --- Is the unload target a trailer?
self.isUnloadingAtTrailerActive = jobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRAILER
if not self.isUnloadingAtTrailerActive then
self:debug("Starting shovel silo to unload into unload trigger.")
- local x, y, z = getWorldTranslation(self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode())
+ --- Uses the exactFillRootNode from the trigger
+ --- and the direction of the unload position marker
+ --- to place the unload position node slightly in front.
+ local x, y, z = getWorldTranslation(self.unloadTrigger:getFillUnitExactFillRootNode())
setTranslation(self.unloadPositionNode, x, y, z)
local position = jobParameters.unloadPosition
local dirX, dirZ = position:getDirection()
setDirection(self.unloadPositionNode, dirX, 0, dirZ, 0, 0, 1)
- local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -self.distShovelUnloadStationPreUnload)
+ local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -math.max(self.distShovelTrailerPreUnload, self.turningRadius))
setTranslation(self.unloadPositionNode, dx, dy, dz)
else
self:debug("Starting shovel silo to unload into trailer.")
@@ -192,7 +194,6 @@ function AIDriveStrategyShovelSiloLoader:onWaypointPassed(ix, course)
else
self:setNewState(self.states.WAITING_FOR_TRAILER)
end
- --self.vehicle:stopCurrentAIJob(AIMessageSuccessFinishedJob.new())
end
end
end
@@ -258,13 +259,17 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:searchForTrailerToUnloadInto()
self.lastTrailerSearch = g_time
end
+ if CpDebug:isChannelActive(CpDebug.DBG_SILO, self.vehicle) then
+ DebugUtil.drawDebugCircleAtNode(self.siloFrontNode, self.maxValidTrailerDistanceToSiloFront,
+ math.ceil(self.maxValidTrailerDistanceToSiloFront), nil, false, {0, 3, 0})
+ end
elseif self.state == self.states.DRIVING_TO_UNLOAD then
self:setMaxSpeed(self.settings.reverseSpeed:getValue())
local refNode
if self.isUnloadingAtTrailerActive then
refNode = self.targetTrailer.exactFillRootNode
else
- refNode = self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode()
+ refNode = self.unloadTrigger:getFillUnitExactFillRootNode()
end
if self.shovelController:isShovelOverTrailer(refNode) then
self:setNewState(self.states.UNLOADING)
@@ -336,17 +341,111 @@ function AIDriveStrategyShovelSiloLoader:getProximitySensorWidth()
return self.vehicle.size.width - 0.5
end
+function AIDriveStrategyShovelSiloLoader:getWorkWidth()
+ return self.settings.bunkerSiloWorkWidth:getValue()
+end
+
function AIDriveStrategyShovelSiloLoader:setNewState(newState)
self:debug("Changed State from %s to %s", self.state.name, newState.name)
self.state = newState
end
+--- Is the trailer valid or not?
+---@param trailer table
+---@param trailerToIgnore table|nil
+---@return boolean
+---@return table|nil
+function AIDriveStrategyShovelSiloLoader:isValidTrailer(trailer, trailerToIgnore)
+ local function debug(...)
+ self:debug("%s attached to: %s => %s", CpUtil.getName(trailer),
+ trailer.rootVehicle and CpUtil.getName(trailer.rootVehicle) or "no root vehicle", string.format(...))
+ end
+ if not SpecializationUtil.hasSpecialization(Trailer, trailer.specializations) then
+ return false
+ end
+ if trailer.rootVehicle and not AIUtil.isStopped(trailer.rootVehicle) then
+ self:debug("is not stopped!", CpUtil.getName(trailer))
+ return false
+ end
+ if trailerToIgnore and table.hasElement(trailerToIgnore, trailer) then
+ debug("will be ignored!", CpUtil.getName(trailer))
+ return false
+ end
+ local canLoad, fillUnitIndex, fillType, exactFillRootNode =
+ ImplementUtil.getCanLoadTo(trailer, self.shovelImplement,
+ nil, debug)
+ if not canLoad or exactFillRootNode == nil then
+ debug("can't be used!", CpUtil.getName(trailer))
+ return false
+ end
+ return true, { fillUnitIndex = fillUnitIndex,
+ fillType = fillType,
+ exactFillRootNode = exactFillRootNode,
+ trailer = trailer }
+end
+
+--- Gets the closest trailer data with the distance
+---@param trailerToIgnore table|nil optional trailers that will be ignored.
+---@return table|nil
+---@return number
+function AIDriveStrategyShovelSiloLoader:getClosestTrailerAndDistance(trailerToIgnore)
+ local closestDistance = math.huge
+ local closestTrailerData = nil
+ for i, vehicle in pairs(g_currentMission.vehicles) do
+ local dist = calcDistanceFrom(vehicle.rootNode, self.siloFrontNode)
+ if dist < closestDistance then
+ local valid, trailerData = self:isValidTrailer(vehicle, trailerToIgnore)
+ if valid then
+ closestDistance = dist
+ closestTrailerData = trailerData
+ end
+ end
+ end
+ return closestTrailerData, closestDistance
+end
+
+--- Searches for trailer to unload into in a maximum radius relative to the silo front center.
+function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
+ self:debug("Searching for an trailer nearby.")
+ local trailerData, dist = self:getClosestTrailerAndDistance({})
+ if not trailerData then
+ self:debug("No valid trailer found anywhere!")
+ return
+ end
+ local trailer = trailerData.trailer
+ if dist > self.maxValidTrailerDistanceToSiloFront then
+ self:debug("Closest Trailer %s attached to %s with the distance %.2fm/%.2fm found is to far away!",
+ CpUtil.getName(trailer), trailer.rootVehicle and CpUtil.getName(trailer.rootVehicle) or "no root vehicle",
+ dist, self.maxValidTrailerDistanceToSiloFront)
+ return
+ end
+ --- Sets the unload position node in front of the closest side of the trailer.
+ self:debug("Found a valid trailer %s within distance %.2f", CpUtil.getName(trailer), dist)
+ self.targetTrailer = trailerData
+ local _, _, distShovelDirectionNode = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
+ local dirX, _, dirZ = localDirectionToWorld(trailer.rootNode, 0, 0, 1)
+ local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
+ local dx, _, dz = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
+ if dx > 0 then
+ local x, y, z = localToWorld(trailer.rootNode, math.abs(distShovelDirectionNode) + self.distShovelTrailerPreUnload, 0, 0)
+ setTranslation(self.unloadPositionNode, x, y, z)
+ setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
+ else
+ local x, y, z = localToWorld(trailer.rootNode, -math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
+ setTranslation(self.unloadPositionNode, x, y, z)
+ setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
+ end
+ self:startPathfindingToTrailer()
+end
+
+
+
----------------------------------------------------------------
--- Pathfinding
----------------------------------------------------------------
---- Find an alignment path to the heap course.
----@param course table heap course
+--- Find an alignment path to the silo lane course.
+---@param course table silo lane course
function AIDriveStrategyShovelSiloLoader:startPathfindingToStart(course)
if not self.pathfinder or not self.pathfinder:isActive() then
self:setNewState(self.states.WAITING_FOR_PATHFINDER)
@@ -369,74 +468,19 @@ end
function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToStart(path)
if path and #path > 2 then
- self:debug("Found alignment path to the course for the heap.")
+ self:debug("Found alignment path to the course for the silo.")
local alignmentCourse = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
self:startCourse(alignmentCourse, 1)
self:setNewState(self.states.DRIVING_ALIGNMENT_COURSE)
else
local course = self:getRememberedCourseAndIx()
- self:debug("No alignment path found!")
+ self:debug("No alignment path found, so driving directly to the course!")
self:startCourse(course, 1)
self:setNewState(self.states.DRIVING_INTO_SILO)
end
end
-
-function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
- self:debug("Searching for an trailer nearby.")
- local function getClosestTrailerAndDistance()
- local closestDistance = math.huge
- local closestTrailer = nil
- for i, vehicle in pairs(g_currentMission.vehicles) do
- if SpecializationUtil.hasSpecialization(Trailer, vehicle.specializations) and AIUtil.isStopped(vehicle.rootVehicle) then
- local dist = calcDistanceFrom(vehicle.rootNode, self.siloFrontNode)
- if dist < closestDistance then
- closestDistance = dist
- closestTrailer = vehicle
- end
- end
- end
- return closestTrailer, closestDistance
- end
- local trailer, dist = getClosestTrailerAndDistance()
- if not trailer then
- self:debug("No valid trailer found anywhere!")
- return
- end
- if dist > self.maxValidTrailerDistanceToSiloFront then
- self:debug("No Trailer with the max distance found, closest: %.2f", dist)
- return
- end
- self:debug("Found a trailer %s within distance %.2f", CpUtil.getName(trailer), dist)
- local canLoad, fillUnitIndex, fillType, exactFillRootNode =
- ImplementUtil.getCanLoadTo(trailer, self.shovelImplement)
- if canLoad and exactFillRootNode ~= nil then
- self.targetTrailer = {
- fillUnitIndex = fillUnitIndex,
- fillType = fillType,
- exactFillRootNode = exactFillRootNode,
- trailer = trailer
- }
- self:debug("Unloading to trailer %s in distance %.2f.", CpUtil.getName(trailer), dist)
- local _, _, distShovelDirectionNode = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
- local dirX, _, dirZ = localDirectionToWorld(trailer.rootNode, 0, 0, 1)
- local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
- local dx, _, dz = localToLocal(self.shovelController:getShovelNode(), trailer.rootNode, 0, 0, 0)
- if dx > 0 then
- local x, y, z = localToWorld(trailer.rootNode, math.abs(distShovelDirectionNode) + self.distShovelTrailerPreUnload, 0, 0)
- setTranslation(self.unloadPositionNode, x, y, z)
- setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot - math.pi/2), 0)
- else
- local x, y, z = localToWorld(trailer.rootNode, -math.abs(distShovelDirectionNode) - self.distShovelTrailerPreUnload, 0, 0)
- setTranslation(self.unloadPositionNode, x, y, z)
- setRotation(self.unloadPositionNode, 0, MathUtil.getValidLimit(yRot + math.pi/2), 0)
- end
- self:startPathfindingToTrailer()
- else
- self:debug("Unloading into trailer %s not possible.", CpUtil.getName(trailer))
- end
-end
-
+--- Starts Pathfinding to the position node in front of a unload trigger.
function AIDriveStrategyShovelSiloLoader:startPathfindingToUnloadPosition()
if not self.pathfinder or not self.pathfinder:isActive() then
self:setNewState(self.states.WAITING_FOR_PATHFINDER)
@@ -466,10 +510,11 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path,
self:setNewState(self.states.DRIVING_TO_UNLOAD_POSITION)
else
self:debug("Failed to drive close to unload position.")
- self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
+ -- self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
end
end
+--- Starts Pathfinding to the position node in front of the trailer side.
function AIDriveStrategyShovelSiloLoader:startPathfindingToTrailer()
if not self.pathfinder or not self.pathfinder:isActive() then
self:setNewState(self.states.WAITING_FOR_PATHFINDER)
@@ -506,24 +551,27 @@ end
--- Silo work
----------------------------------------------------------------
+--- Starts driving into the silo lane
function AIDriveStrategyShovelSiloLoader:startDrivingToSilo()
+ --- Creates a straight course in the silo.
local startPos, endPos = self.siloController:getTarget(self:getWorkWidth())
local x, z = unpack(startPos)
local dx, dz = unpack(endPos)
local siloCourse = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
0, 0, 3, 3, false)
local distance = siloCourse:getDistanceBetweenVehicleAndWaypoint(self.vehicle, 1)
- if distance > 1.5 * self.turningRadius then
+ if distance > self.turningRadius then
self:debug("Start driving to silo with pathfinder.")
self:startPathfindingToStart(siloCourse)
else
- self:debug("Start driving into the silo.")
+ self:debug("Start driving into the silo directly.")
self:startCourse(siloCourse, 1)
self:setNewState(self.states.DRIVING_INTO_SILO)
end
end
function AIDriveStrategyShovelSiloLoader:startDrivingOutOfSilo()
+ --- Creates the straight reverse course.
local startPos, endPos = self.siloController:getLastTarget()
local x, z = unpack(endPos)
local dx, dz = unpack(startPos)
@@ -537,6 +585,7 @@ function AIDriveStrategyShovelSiloLoader:startDrivingOutOfSilo()
self:setNewState(self.states.DRIVING_OUT_OF_SILO)
end
+--- Drives from the position node in front of the trailer to the trailer, so the unloading can begin after that.
function AIDriveStrategyShovelSiloLoader:approachTrailerForUnloading()
local dx, _, dz = getWorldTranslation(self.targetTrailer.exactFillRootNode)
local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
@@ -547,8 +596,9 @@ function AIDriveStrategyShovelSiloLoader:approachTrailerForUnloading()
self:setNewState(self.states.DRIVING_TO_UNLOAD)
end
+--- Drives from the position node in front of the trigger to the unload trigger, so the unloading can begin after that.
function AIDriveStrategyShovelSiloLoader:approachUnloadStationForUnloading()
- local dx, _, dz = getWorldTranslation(self.unloadTrigger:getTrigger():getFillUnitExactFillRootNode())
+ local dx, _, dz = getWorldTranslation(self.unloadTrigger:getFillUnitExactFillRootNode())
local x, _, z = getWorldTranslation(self.vehicle:getAIDirectionNode())
local course = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
0, -3, 3, 2, false)
@@ -557,13 +607,12 @@ function AIDriveStrategyShovelSiloLoader:approachUnloadStationForUnloading()
self:setNewState(self.states.DRIVING_TO_UNLOAD)
end
-function AIDriveStrategyShovelSiloLoader:getWorkWidth()
- return self.settings.bunkerSiloWorkWidth:getValue()
-end
-
----------------------------------------------------------------
--- Unloading
----------------------------------------------------------------
+
+--- Is the unloading finished?
+---@return boolean
function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
if self.shovelController:isEmpty() then
self:debug("Finished unloading, as the shovel is empty.")
@@ -572,17 +621,18 @@ function AIDriveStrategyShovelSiloLoader:hasFinishedUnloading()
if self.isUnloadingAtTrailerActive then
if self.targetTrailer.trailer:getFillUnitFreeCapacity(self.targetTrailer.fillUnitIndex) <= 0 then
self:debug("Trailer is full, abort unloading into trailer %s.", CpUtil.getName(self.targetTrailer.trailer))
+ self.targetTrailer = nil
return true
end
else
- if self.unloadTrigger:getTrigger():getFillUnitFreeCapacity(1, self.shovelController:getDischargeFillType(), self.vehicle:getOwnerFarmId()) <= 0 then
- self:debug("Unload Trigger is full.")
- return false
+ if self.unloadTrigger:getFillUnitFreeCapacity(1, self.shovelController:getDischargeFillType(), self.vehicle:getOwnerFarmId()) <= 0 then
+ self:debugSparse("Unload Trigger is full.")
end
end
return false
end
+--- Starts reverse straight to make some space to the trailer or unload trigger.
function AIDriveStrategyShovelSiloLoader:startReversingAwayFromUnloading()
local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
local course = Course.createStraightReverseCourse(self.vehicle, 2*spaceToTrailer, 0 )
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index 32af4adc4..1d58762ec 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -431,14 +431,11 @@ end
---@return number|nil target implement fill unit ix to load into.
---@return number|nil fill type to load
---@return number|nil target exact fill root node
-function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, dischargeNode, suppressLog)
+function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, dischargeNode, debugFunc)
local function debug(str, ...)
- if not suppressLog then
- if g_updateLoopIndex % 100 == 0 then
- CpUtil.debugVehicle(CpDebug.DBG_SILO, implementToLoadFrom.rootVehicle,
- str, ...)
- end
+ if debugFunc then
+ debugFunc(str, ...)
end
end
@@ -457,24 +454,39 @@ function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, di
return false, nil, nil, nil
end
+ --- Is the fill unit a valid load target?
+ ---@param fillUnitIndex number
+ ---@return boolean
+ ---@return number|nil
+ ---@return number|nil
+ local function canLoad(fillUnitIndex)
+ if not loadTargetImplement:getFillUnitSupportsFillType(fillUnitIndex, fillType) then
+ debug("Fill unit(%d) doesn't support fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeNameByIndex(fillType))
+ return false
+ end
+ if not loadTargetImplement:getFillUnitAllowsFillType(fillUnitIndex, fillType) then
+ debug("Fill unit(%d) doesn't allow fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeNameByIndex(fillType))
+ return false
+ end
+ if loadTargetImplement.getFillUnitFreeCapacity and
+ loadTargetImplement:getFillUnitFreeCapacity(fillUnitIndex, fillType, implementToLoadFrom:getActiveFarm()) <= 0 then
+ debug("Fill unit(%d) is full with fill type %s!", fillUnitIndex, g_fillTypeManager:getFillTypeNameByIndex(fillType))
+ return false
+ end
+ if loadTargetImplement.getIsFillAllowedFromFarm and
+ not loadTargetImplement:getIsFillAllowedFromFarm(implementToLoadFrom:getActiveFarm()) then
+ debug("Fill unit(%d) filling to target farm %s from %s not allowed!",
+ fillUnitIndex, loadTargetImplement:getOwnerFarmId(), implementToLoadFrom:getActiveFarm())
+ return false
+ end
+ return true, fillUnitIndex, loadTargetImplement:getFillUnitExactFillRootNode(fillUnitIndex)
+ end
+
local validTarget, targetFillUnitIndex, exactFillRootNode
for fillUnitIndex, fillUnit in pairs(loadTargetImplement:getFillUnits()) do
- if loadTargetImplement:getFillUnitSupportsFillType(fillUnitIndex, fillType) then
- if loadTargetImplement:getFillUnitAllowsFillType(fillUnitIndex, fillType) then
- if loadTargetImplement.getFillUnitFreeCapacity == nil or loadTargetImplement:getFillUnitFreeCapacity(fillUnitIndex, fillType, implementToLoadFrom:getActiveFarm()) > 0 then
- if loadTargetImplement.getIsFillAllowedFromFarm == nil or loadTargetImplement:getIsFillAllowedFromFarm(implementToLoadFrom:getActiveFarm()) then
- validTarget, targetFillUnitIndex, exactFillRootNode = true, fillUnitIndex, loadTargetImplement:getFillUnitExactFillRootNode(fillUnitIndex)
- else
- debug("Fill unit(%d) filling to target farm %s from %s not allowed!", fillUnitIndex, loadTargetImplement:getOwnerFarmId(), implementToLoadFrom:getActiveFarm())
- end
- else
- debug("Fill unit(%d) is full with fill type %s!", fillUnitIndex, g_fillTypeManager:getFillTypeTitleByIndex(fillType))
- end
- else
- debug("Fill unit(%d) doesn't allow fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeTitleByIndex(fillType))
- end
- else
- debug("Fill unit(%d) doesn't support fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeTitleByIndex(fillType))
+ validTarget, targetFillUnitIndex, exactFillRootNode = canLoad(fillUnitIndex)
+ if validTarget then
+ break
end
end
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 6f9d52055..a1ec9020d 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -77,9 +77,16 @@ function ShovelController:isShovelOverTrailer(refNode, margin)
local _, _, distShovelToRoot = localToLocal(node, self.implement.rootVehicle:getAIDirectionNode(), 0, 0, 0)
local _, _, distTrailerToRoot = localToLocal(refNode, self.implement.rootVehicle:getAIDirectionNode(), 0, 0, 0)
margin = margin or 0
+ if self:isHighDumpShovel() then
+ margin = margin + 1
+ end
return ( distTrailerToRoot - distShovelToRoot ) < margin
end
+function ShovelController:isHighDumpShovel()
+ return g_vehicleConfigurations:get(self.implement, "shovelMovingToolIx") ~= nil
+end
+
function ShovelController:moveShovelToLoadingPosition()
return self:moveShovelToPosition(self.POSITIONS.LOADING)
end
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 914e2eac5..90d5c427a 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -186,31 +186,47 @@ end
---@param unloadPosition CpAIParameterPositionAngle
---@return boolean
---@return table|nil
+---@return table|nil
function CpAIJobSiloLoader:getUnloadTriggerAt(unloadPosition)
local x, z = unloadPosition:getPosition()
local dirX, dirZ = unloadPosition:getDirection()
if x == nil or dirX == nil then
return false
end
- return g_triggerManager:getDischargeableUnloadTriggerAt( x, z, dirX, dirZ, 5, 5)
+ local fillType
+ local silo = self.heap or self.bunkerSilo
+ if silo then
+ fillType = silo:getFillType()
+ end
+ local found, trigger, station = g_triggerManager:getDischargeableUnloadTriggerAt( x, z, dirX, dirZ, 5, 25)
+ if found and fillType~=nil then
+ if not trigger:getIsFillTypeAllowed(fillType) then
+ --- Fill type is not supported by the trigger.
+ return false
+ end
+ end
+ return found, trigger, station
end
function CpAIJobSiloLoader:drawSilos(map)
self.heapPlot:draw(map)
g_bunkerSiloManager:drawSilos(map, self.bunkerSilo)
if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
- g_triggerManager:drawDischargeableTriggers(map, self.unloadTrigger)
+ local fillType
+ local silo = self.heap or self.bunkerSilo
+ if silo then
+ fillType = silo:getFillType()
+ end
+ g_triggerManager:drawDischargeableTriggers(map, self.unloadTrigger, fillType)
end
end
---- Gets the giants unload station.
+--- Gets the unload station.
function CpAIJobSiloLoader:getUnloadingStations()
local unloadingStations = {}
for _, unloadingStation in pairs(g_currentMission.storageSystem:getUnloadingStations()) do
- if g_currentMission.accessHandler:canPlayerAccess(unloadingStation) and unloadingStation:isa(UnloadingStation) then
- table.insert(unloadingStations, unloadingStation)
- end
+ table.insert(unloadingStations, unloadingStation)
end
return unloadingStations
end
diff --git a/scripts/ai/tasks/CpAITaskSiloLoader.lua b/scripts/ai/tasks/CpAITaskSiloLoader.lua
index ddfc5333a..31f856bbe 100644
--- a/scripts/ai/tasks/CpAITaskSiloLoader.lua
+++ b/scripts/ai/tasks/CpAITaskSiloLoader.lua
@@ -33,8 +33,8 @@ end
function CpAITaskSiloLoader:start()
if self.isServer then
- local _, unloadTrigger, unloadStation = self.job:getUnloadTriggerAt(self.job:getCpJobParameters().unloadPosition)
- self.vehicle:startCpSiloLoaderWorker(self.job:getCpJobParameters(), self.silo, self.heap, unloadTrigger, unloadStation)
+ local _, unloadTrigger, _ = self.job:getUnloadTriggerAt(self.job:getCpJobParameters().unloadPosition)
+ self.vehicle:startCpSiloLoaderWorker(self.job:getCpJobParameters(), self.silo, self.heap, unloadTrigger)
end
CpAITaskSiloLoader:superClass().start(self)
diff --git a/scripts/config/VehicleConfigurations.lua b/scripts/config/VehicleConfigurations.lua
index fb8a8509b..d5fe91b0e 100644
--- a/scripts/config/VehicleConfigurations.lua
+++ b/scripts/config/VehicleConfigurations.lua
@@ -47,6 +47,7 @@ VehicleConfigurations.attributes = {
useVehicleSizeForMarkers = XMLValueType.BOOL,
armMovingToolIx = XMLValueType.INT,
movingToolIx = XMLValueType.INT,
+ shovelMovingToolIx = XMLValueType.INT,
ignoreBaleCollisionForward = XMLValueType.BOOL,
}
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index 21f4cb161..3737974d1 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -547,7 +547,7 @@ function CpInGameMenuAIFrameExtended:startPickingPosition(superFunc, parameter,
CpInGameMenuAIFrameExtended.resetHotspots(self)
self:updateParameterValueTexts()
end)
-
+ g_currentMission:removeMapHotspot(self.aiTargetMapHotspot)
superFunc(self, parameter, callback, ...)
end
InGameMenuAIFrame.startPickPosition = Utils.overwrittenFunction(InGameMenuAIFrame.startPickPosition,
@@ -603,16 +603,16 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
elseif parameterType == AIParameterType.POSITION or parameterType == AIParameterType.POSITION_ANGLE then
element:setText(parameter:getString())
- g_currentMission:addMapHotspot(self.aiTargetMapHotspot)
+ g_currentMission:addMapHotspot(self.rawAiTargetMapHotspot)
local x, z = parameter:getPosition()
- self.aiTargetMapHotspot:setWorldPosition(x, z)
+ self.rawAiTargetMapHotspot:setWorldPosition(x, z)
if parameterType == AIParameterType.POSITION_ANGLE then
local angle = parameter:getAngle() + math.pi
- self.aiTargetMapHotspot:setWorldRotation(angle)
+ self.rawAiTargetMapHotspot:setWorldRotation(angle)
end
end
end
diff --git a/scripts/gui/UnloadingTriggerPlot.lua b/scripts/gui/UnloadingTriggerPlot.lua
index b8f84607a..c2913504b 100644
--- a/scripts/gui/UnloadingTriggerPlot.lua
+++ b/scripts/gui/UnloadingTriggerPlot.lua
@@ -5,13 +5,14 @@ UnloadingTriggerPlot = CpObject()
function UnloadingTriggerPlot:init(node)
self.courseOverlayId = createImageOverlay('dataS/scripts/shared/graph_pixel.dds')
self.isVisible = false
- -- the normal FS22 blue
- self.color = {CpGuiUtil.getNormalizedRgb(42, 193, 237)}
+ -- the normal FS22 blue -- 0.9900 0.4640 0.0010 1
+ --self.color = {CpGuiUtil.getNormalizedRgb(42, 193, 237)}
+ self.color = {CpGuiUtil.getNormalizedRgb(255, 128, 0)}
-- a lighter shade of the same color
- self.lightColor = {CpGuiUtil.getNormalizedRgb(45, 207, 255)}
+ self.lightColor = {CpGuiUtil.getNormalizedRgb(213, 255, 0)}
-- a darker shade of the same color
self.darkColor = {CpGuiUtil.getNormalizedRgb(19, 87, 107)}
- self.lineThickness = 2 / g_screenHeight -- 2 pixels
+ self.lineThickness = 4 / g_screenHeight -- 4 pixels
self.isHighlighted = false
local _
self.x, _, self.z = getWorldTranslation(node)
@@ -19,8 +20,11 @@ end
function UnloadingTriggerPlot:draw(map)
local r, g, b = unpack(self.color)
+ if self.isHighlighted then
+ r, g, b = unpack(self.lightColor)
+ end
setOverlayColor( self.courseOverlayId, r, g, b, 0.8 )
- local x, y = CpGuiUtil.worldToScreen(map, self.x, self.z, false)
+ -- local x, y = CpGuiUtil.worldToScreen(map, self.x, self.z, false)
local s1x, s1y = CpGuiUtil.worldToScreen(map, self.x - 5, self.z - 5, false)
local e1x, e1y = CpGuiUtil.worldToScreen(map, self.x + 5, self.z + 5, false)
diff --git a/scripts/specializations/CpAIBunkerSiloWorker.lua b/scripts/specializations/CpAIBunkerSiloWorker.lua
index 2a6828256..0a66d1596 100644
--- a/scripts/specializations/CpAIBunkerSiloWorker.lua
+++ b/scripts/specializations/CpAIBunkerSiloWorker.lua
@@ -101,8 +101,7 @@ function CpAIBunkerSiloWorker:getCanStartCpBunkerSiloWorker()
and (not self:hasCpCourse() or
AIUtil.hasChildVehicleWithSpecialization(self, Leveler))
- and not (AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
- and AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt))
+ and not AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
end
function CpAIBunkerSiloWorker:getCanStartCp(superFunc)
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index 58d485318..252cec82f 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -178,7 +178,7 @@ function CpAISiloLoaderWorker:startCpAtLastWp(superFunc, ...)
end
end
-function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap, unloadTrigger, unloadStation)
+function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap, unloadTrigger)
if self.isServer then
local strategy
if AIUtil.hasAIImplementWithSpecialization(self, ConveyorBelt) then
@@ -187,9 +187,9 @@ function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo,
else
CpUtil.debugVehicle(CpDebug.DBG_SILO, self, "Starting a shovel silo loader strategy.")
strategy = AIDriveStrategyShovelSiloLoader.new()
+ strategy:setUnloadTrigger(unloadTrigger)
end
strategy:setSiloAndHeap(bunkerSilo, heap)
- strategy:setUnloadTriggerAndStation(unloadTrigger, unloadStation)
strategy:setAIVehicle(self, jobParameters)
self:startCpWithStrategy(strategy)
end
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 8d24151c4..092d41467 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -250,7 +250,7 @@ function CpShovelPositions.setShovelPosition(dt, spec, shovel, shovelNode, angle
goalAngle)
end
-function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits)
+function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits, useHighDumpShovel)
local min, max = unpack(shovelLimits)
local targetAngle = math.rad(min) + math.rad(max - min)/2
min, max = unpack(armLimits)
@@ -332,9 +332,24 @@ function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits)
local angle = MathUtil.clamp(oldArmRot - MathUtil.getAngleDifference(alpha, yRot), armTool.rotMin, armTool.rotMax)
isDirty = ImplementUtil.moveMovingToolToRotation(armVehicle, armTool, dt, angle)
end
+
+ local highDumpShovelIx = g_vehicleConfigurations:get(self, "shovelMovingToolIx")
+ if highDumpShovelIx then
+ local tool = self.spec_cylindered.movingTools[highDumpShovelIx]
+ if useHighDumpShovel then
+ local _, dy, _ = localDirectionToWorld(getParent(tool.node), 0, 0, 1)
+ angle = math.acos(dy)
+ targetAngle = math.pi/2
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt, tool.rotMax) or isDirty
+ else
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt, tool.rotMin) or isDirty
+ end
+ end
local deltaAngle = targetAngle - angle
local goalAngle = MathUtil.clamp(oldShovelRot + deltaAngle, shovelTool.rotMin, shovelTool.rotMax)
- isDirty = isDirty or ImplementUtil.moveMovingToolToRotation(shovelVehicle, shovelTool, dt, goalAngle)
+ isDirty = ImplementUtil.moveMovingToolToRotation(shovelVehicle,
+ shovelTool, dt, goalAngle) or isDirty
+
return isDirty
end
@@ -442,7 +457,8 @@ function CpShovelPositions:updateUnloadingPosition(dt)
local isDirty
if angle and maxAngle then
isDirty = CpShovelPositions.setShovelPosition2(self, dt,
- {math.deg(maxAngle), math.deg(maxAngle) + 2}, CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS)
+ {math.deg(maxAngle), math.deg(maxAngle) + 2},
+ CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, true)
end
spec.isDirty = isDirty
end
diff --git a/scripts/trigger/TriggerManager.lua b/scripts/trigger/TriggerManager.lua
index 3c84f4c22..31a8e111f 100644
--- a/scripts/trigger/TriggerManager.lua
+++ b/scripts/trigger/TriggerManager.lua
@@ -1,7 +1,8 @@
---- Links all the needed trigger, except bunker silos to trigger wrappers.
+--- Stores all the relevant giants triggers expect bunker silos.
+--- For now only unload triggers are supported.
---@class TriggerManager
TriggerManager = CpObject()
-
+TriggerManager.DEBUG = true
function TriggerManager:init()
---@type table
self.unloadTriggers = {}
@@ -9,6 +10,8 @@ function TriggerManager:init()
self.dischargeableUnloadTriggers = {}
end
+--- Adds an unload trigger.
+---@param silo table UnloadTrigger
function TriggerManager:addUnloadingSilo(silo)
if silo.exactFillRootNode ~= nil then
self.unloadTriggers[silo.exactFillRootNode] = CpTrigger(silo, silo.exactFillRootNode)
@@ -18,6 +21,8 @@ function TriggerManager:addUnloadingSilo(silo)
end
end
+--- Removes the unload trigger, as it got removed for example sold.
+---@param silo table UnloadTrigger
function TriggerManager:removeUnloadingSilo(silo)
if silo.exactFillRootNode ~= nil then
if self.unloadTriggers[silo.exactFillRootNode] then
@@ -28,6 +33,9 @@ function TriggerManager:removeUnloadingSilo(silo)
end
end
+--- Gets the unload trigger from the exactFillRootNode.
+---@param node number exactFillRootNode
+---@return CpTrigger
function TriggerManager:getUnloadTriggerForNode(node)
return self.unloadTriggers[node]
end
@@ -41,7 +49,7 @@ end
---@param width number
---@param length number
---@return boolean
----@return table|nil
+---@return CpTrigger|nil
---@return table|nil
function TriggerManager:getTriggerAt(triggers, x, z, dirX, dirZ, width, length)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
@@ -74,7 +82,7 @@ function TriggerManager:getTriggerAt(triggers, x, z, dirX, dirZ, width, length)
for node, trigger in pairs(triggers) do
dx, _, dz = getWorldTranslation(node)
if CpMathUtil.isPointInPolygon(area, dx, dz) then
- return true, trigger, trigger:getTrigger():getTarget()
+ return true, trigger, trigger:getTarget()
end
end
return false
@@ -88,7 +96,7 @@ end
---@param width number
---@param length number
---@return boolean
----@return table|nil
+---@return CpTrigger|nil
---@return table|nil
function TriggerManager:getUnloadTriggerAt(x, z, dirX, dirZ, width, length)
return self:getTriggerAt(self.unloadTriggers, x, z, dirX, dirZ, width, length)
@@ -102,7 +110,7 @@ end
---@param width number
---@param length number
---@return boolean found?
----@return table|nil unload trigger
+---@return CpTrigger|nil unload trigger
---@return table|nil unload station/placeable
function TriggerManager:getDischargeableUnloadTriggerAt(x, z, dirX, dirZ, width, length)
return self:getTriggerAt(self.dischargeableUnloadTriggers, x, z, dirX, dirZ, width, length)
@@ -124,16 +132,19 @@ end
--- Draws all bunker silos onto the ai map.
---@param map table map to draw to.
---@param selected CpTrigger silo that gets highlighted.
-function TriggerManager:drawDischargeableTriggers(map, selected)
+---@param fillType number|nil fill type that needs to be supported.
+function TriggerManager:drawDischargeableTriggers(map, selected, fillType)
for _, trigger in pairs(self.dischargeableUnloadTriggers) do
- trigger:drawPlot(map, selected)
+ trigger:drawPlot(map, selected, fillType)
end
end
function TriggerManager:draw()
for node, trigger in pairs(self.unloadTriggers) do
- local text = string.format("%s:\n %d", getName(node), node )
- CpUtil.drawDebugNode(node, false, 2, text)
+ if self.DEBUG then
+ local text = string.format("%s:\n %d", getName(node), node )
+ CpUtil.drawDebugNode(node, false, 2, text)
+ end
end
end
diff --git a/scripts/trigger/TriggerWrapper.lua b/scripts/trigger/TriggerWrapper.lua
index 6fc538f0e..c22283690 100644
--- a/scripts/trigger/TriggerWrapper.lua
+++ b/scripts/trigger/TriggerWrapper.lua
@@ -1,4 +1,5 @@
+--- Wrapper for a trigger.
---@class CpTrigger
CpTrigger = CpObject()
@@ -20,7 +21,35 @@ function CpTrigger:getTrigger()
return self.trigger
end
-function CpTrigger:drawPlot(map, selectedTrigger)
+function CpTrigger:getTarget()
+ return self.trigger:getTarget()
+end
+
+function CpTrigger:getFillUnitExactFillRootNode(fillUnitIndex)
+ return self.trigger:getFillUnitExactFillRootNode(fillUnitIndex)
+end
+
+function CpTrigger:getFillUnitFreeCapacity(fillUnitIndex, fillTypeIndex, farmId)
+ return self.trigger:getFillUnitFreeCapacity(fillUnitIndex, fillTypeIndex, farmId)
+end
+
+--- Is the fill type allowed ?
+---@param fillType any
+---@return boolean
+function CpTrigger:getIsFillTypeAllowed(fillType)
+ return self.trigger:getIsFillTypeAllowed(fillType)
+end
+
+---@param map table
+---@param selectedTrigger CpTrigger
+---@param fillType number|nil
+function CpTrigger:drawPlot(map, selectedTrigger, fillType)
+ if fillType and fillType ~= FillType.UNKNOWN then
+ if not self.trigger:getIsFillTypeAllowed(fillType) then
+ --- Fill type is not allowed.
+ return
+ end
+ end
self.plot:setHighlighted(self == selectedTrigger)
self.plot:draw(map)
end
\ No newline at end of file
From 0775bc016ee8f3565f71c5d84a98e976ab933e50 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 11 Jul 2023 15:33:19 +0200
Subject: [PATCH 020/107] Some more shovel position adjustments and technical
debt reduction
---
scripts/specializations/CpShovelPositions.lua | 299 ++++++++----------
1 file changed, 128 insertions(+), 171 deletions(-)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 092d41467..4898229c4 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -95,30 +95,9 @@ function CpShovelPositions.registerFunctions(vehicleType)
SpecializationUtil.registerFunction(vehicleType, "getCpShovelUnloadingPositionHeight", CpShovelPositions.getCpShovelUnloadingPositionHeight)
end
-
-function CpShovelPositions:onLoad(savegame)
- --- Register the spec: spec_ShovelPositions
- self.spec_cpShovelPositions = self["spec_" .. CpShovelPositions.SPEC_NAME]
- local spec = self.spec_cpShovelPositions
- --- Current shovel state.
- spec.state = CpShovelPositions.DEACTIVATED
- spec.isDirty = false
-end
-
-function CpShovelPositions:onPostAttach()
- if self.spec_cpShovelPositions then
- CpShovelPositions.cpSetupShovelPositions(self)
- end
-end
-
-function CpShovelPositions:onDraw()
- if CpShovelPositions.DEBUG and self:getRootVehicle() then
- local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
- if shovelNode then
- DebugUtil.drawDebugNode(shovelNode, "shovelNode")
- end
- end
-end
+--------------------------------------------
+--- Console Commands
+--------------------------------------------
local function executeConsoleCommand(func, ...)
local vehicle = g_currentMission.controlledVehicle
@@ -161,6 +140,50 @@ function CpShovelPositions:consoleCommandSetPreUnloadArmLimit(min, max)
end, min, max)
end
+--------------------------------------------
+--- Event Listener
+--------------------------------------------
+
+function CpShovelPositions:onLoad(savegame)
+ --- Register the spec: spec_ShovelPositions
+ self.spec_cpShovelPositions = self["spec_" .. CpShovelPositions.SPEC_NAME]
+ local spec = self.spec_cpShovelPositions
+ --- Current shovel state.
+ spec.state = CpShovelPositions.DEACTIVATED
+ spec.isDirty = false
+end
+
+function CpShovelPositions:onPostAttach()
+ if self.spec_cpShovelPositions then
+ CpShovelPositions.cpSetupShovelPositions(self)
+ end
+end
+
+function CpShovelPositions:onDraw()
+ if CpShovelPositions.DEBUG and self:getRootVehicle() then
+ local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ if shovelNode then
+ DebugUtil.drawDebugNode(shovelNode, "shovelNode")
+ end
+ end
+end
+
+function CpShovelPositions:onUpdateTick(dt)
+ local spec = self.spec_cpShovelPositions
+ if spec.shovelToolIx == nil or spec.armToolIx == nil then
+ return
+ end
+ if spec.state == CpShovelPositions.LOADING then
+ CpShovelPositions.updateLoadingPosition(self, dt)
+ elseif spec.state == CpShovelPositions.TRANSPORT then
+ CpShovelPositions.updateTransportPosition(self, dt)
+ elseif spec.state == CpShovelPositions.PRE_UNLOAD then
+ CpShovelPositions.updatePreUnloadPosition(self, dt)
+ elseif spec.state == CpShovelPositions.UNLOADING then
+ CpShovelPositions.updateUnloadingPosition(self, dt)
+ end
+end
+
--- Changes the current shovel state position.
function CpShovelPositions:cpSetShovelState(state)
local spec = self.spec_cpShovelPositions
@@ -182,6 +205,7 @@ function CpShovelPositions:cpResetShovelState()
ImplementUtil.stopMovingTool(spec.shovelVehicle, spec.shovelTool)
end
+--- Is the current target shovel position not yet reached?
function CpShovelPositions:areCpShovelPositionsDirty()
local spec = self.spec_cpShovelPositions
return spec.isDirty
@@ -212,8 +236,6 @@ function CpShovelPositions:cpSetupShovelPositions()
spec.shovelToolIx = i
spec.shovelTool = tool
spec.shovelVehicle = vehicle
- spec.shovelProjectionNode = CpUtil.createNode("CpShovelProjectionNode",
- 0, 0, 0, getParent(tool.node))
end
end
end
@@ -221,39 +243,19 @@ function CpShovelPositions:cpSetupShovelPositions()
end
end
-function CpShovelPositions:onUpdateTick(dt)
- local spec = self.spec_cpShovelPositions
- if spec.shovelToolIx == nil or spec.armToolIx == nil then
- return
- end
- if spec.state == CpShovelPositions.LOADING then
- CpShovelPositions.updateLoadingPosition(self, dt)
- elseif spec.state == CpShovelPositions.TRANSPORT then
- CpShovelPositions.updateTransportPosition(self, dt)
- elseif spec.state == CpShovelPositions.PRE_UNLOAD then
- CpShovelPositions.updatePreUnloadPosition(self, dt)
- elseif spec.state == CpShovelPositions.UNLOADING then
- CpShovelPositions.updateUnloadingPosition(self, dt)
- end
-end
-
---- Changes the shovel angle dependent on the selected position.
-function CpShovelPositions.setShovelPosition(dt, spec, shovel, shovelNode, angle, limits)
- local min, max = unpack(limits)
- local targetAngle = math.rad(min) + math.rad(max - min)/2
- local deltaAngle = targetAngle - angle
- local curRot = {}
- curRot[1], curRot[2], curRot[3] = getRotation(spec.shovelTool.node)
- local oldRot = curRot[spec.shovelTool.rotationAxis]
- local goalAngle = MathUtil.clamp(oldRot + deltaAngle, spec.shovelTool.rotMin, spec.shovelTool.rotMax)
- return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle, spec.shovelTool, dt,
- goalAngle)
-end
-
-function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits, useHighDumpShovel)
+--- Sets the current shovel position values, like the arm and shovel rotations.
+---@param dt number
+---@param shovelLimits table
+---@param armLimits table
+---@param useHighDumpShovel boolean|nil
+---@return boolean|nil
+function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHighDumpShovel)
local min, max = unpack(shovelLimits)
+ --- Target angle of the shovel node, which is at the end of the shovel.
local targetAngle = math.rad(min) + math.rad(max - min)/2
min, max = unpack(armLimits)
+ --- Target height of the arm.
+ --- This is relative to the attacher joint of the shovel.
local targetHeight = min + (max - min)/2
local shovelTool = self.spec_cpShovelPositions.shovelTool
@@ -265,71 +267,45 @@ function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits, useHi
curRot[1], curRot[2], curRot[3] = getRotation(shovelTool.node)
local oldShovelRot = curRot[shovelTool.rotationAxis]
- local curRot = {}
+ curRot = {}
curRot[1], curRot[2], curRot[3] = getRotation(armTool.node)
local oldArmRot = curRot[armTool.rotationAxis]
+
local armProjectionNode = self.spec_cpShovelPositions.armProjectionNode
local armToolRefNode = self.spec_cpShovelPositions.armToolRefNode
- local radius = calcDistanceFrom(shovelTool.node, armTool.node)
+
+ local radiusArmToolToShovelTool = calcDistanceFrom(shovelTool.node, armTool.node)
local attacherJointNode = self.spec_attachable.attacherJoint.node
local angle, shovelNode = CpShovelPositions.getShovelData(self)
local _, shovelY, _ = localToLocal(shovelNode, attacherJointNode, 0, 0, 0)
+ --- All values will be calculated in the coordinate system from the vehicle root node.
+
local _, ty, tz = localToLocal(getChildAt(armTool.node, 0), armVehicle.rootNode, 0, 0, 0)
local ax, ay, az = localToLocal(armTool.node, armVehicle.rootNode, 0, 0, 0)
local sx, sy, sz = 0, targetHeight - shovelY, 0
local ex, ey, ez = 0, targetHeight - shovelY, 20
- local yMax = ay + radius
+ local yMax = ay + radiusArmToolToShovelTool
if sy > yMax then
+ --- Makes sure the target height is still reachable
sy = yMax - 0.01
ey = yMax - 0.01
end
- local hasIntersection, i1z, i1y, i2z, i2y = MathUtil.getCircleLineIntersection(az, ay, radius,
+ local hasIntersection, i1z, i1y, i2z, i2y = MathUtil.getCircleLineIntersection(az, ay, radiusArmToolToShovelTool,
sz, sy, ez, ey)
- local wsx, wsy, wsz = localToWorld(armVehicle.rootNode, sx, sy, sz)
- local wex, wey, wez = localToWorld(armVehicle.rootNode, ex, ey, ez)
- DebugUtil.drawDebugLine(wsx, wsy, wsz, wex, wey, wez)
-
- DebugUtil.drawDebugCircleAtNode(armVehicle.rootNode, radius, 30, nil,
- true, {ax, ay, az})
- CpUtil.drawDebugNode(armVehicle.rootNode)
- CpUtil.drawDebugNode(armTool.node)
- CpUtil.drawDebugNode(shovelTool.node)
- local isDirty
+
+ local isDirty, alpha, oldRotRelativeArmRot
if hasIntersection then
setTranslation(armProjectionNode, 0, i1y, i1z)
setTranslation(armToolRefNode, ax, ay, az)
local _, shy, shz = localToLocal(shovelTool.node, armVehicle.rootNode, 0, 0, 0)
local dirZ, dirY = MathUtil.vector2Normalize(shz - az, shy - ay)
- local yRot = MathUtil.getYRotationFromDirection(-dirZ, dirY) + math.pi/2
+ oldRotRelativeArmRot = MathUtil.getYRotationFromDirection(-dirZ, dirY) + math.pi/2
- CpUtil.drawDebugNode(armProjectionNode)
- CpUtil.drawDebugNode(armToolRefNode)
- local alpha = math.atan2(i1y - ay, i1z - az)
+ alpha = math.atan2(i1y - ay, i1z - az)
local beta = -math.atan2(i2y - ay, i2z - az)
- local debugData = {
- {
- name = "alpha", value = math.deg(alpha)
- },
- {
- name = "deltaAlphaOld", value = math.deg(MathUtil.getAngleDifference(alpha, oldArmRot))
- },
- {
- name = "old", value = math.deg(oldArmRot)
- },
- {
- name = "deltaAlpha", value = math.deg(MathUtil.getAngleDifference(alpha, yRot))
- },
- {
- name = "dirRot", value = math.deg(yRot)
- },
- {
- name = "distAlpha", value = MathUtil.vector2Length(i1z - tz, i1y - ty)
- },
- }
- DebugUtil.renderTable(0.4, 0.4, 0.018, debugData, 0)
- local angle = MathUtil.clamp(oldArmRot - MathUtil.getAngleDifference(alpha, yRot), armTool.rotMin, armTool.rotMax)
+ local angle = MathUtil.clamp(oldArmRot - MathUtil.getAngleDifference(alpha, oldRotRelativeArmRot), armTool.rotMin, armTool.rotMax)
isDirty = ImplementUtil.moveMovingToolToRotation(armVehicle, armTool, dt, angle)
end
@@ -339,7 +315,7 @@ function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits, useHi
if useHighDumpShovel then
local _, dy, _ = localDirectionToWorld(getParent(tool.node), 0, 0, 1)
angle = math.acos(dy)
- targetAngle = math.pi/2
+ targetAngle = math.pi/2 - math.pi/8
isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt, tool.rotMax) or isDirty
else
isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt, tool.rotMin) or isDirty
@@ -350,113 +326,96 @@ function CpShovelPositions:setShovelPosition2(dt, shovelLimits, armLimits, useHi
isDirty = ImplementUtil.moveMovingToolToRotation(shovelVehicle,
shovelTool, dt, goalAngle) or isDirty
- return isDirty
-end
-
---- Changes the front loader angle dependent on the selected position, relative to a target height.
-function CpShovelPositions.setArmPosition(dt, spec, shovel, shovelNode, limits)
- --- Interval in which the shovel height should be in.
- local min, max = unpack(limits)
- local targetHeight = min + (max - min)/2
-
- local attacherJointNode = shovel.spec_attachable.attacherJoint.node
- local _, shovelY, shovelR = localToLocal(attacherJointNode, shovelNode, 0, 0, 0)
-
- local x, y, z = getWorldTranslation(attacherJointNode)
- local dy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z)
-
- local targetAttacherHeight = dy + shovelY + targetHeight
- local diff = targetAttacherHeight - y
-
- CpShovelPositions.debug(shovel, "shovel => y: %.2f, z: %.2f, targetAttacherHeight: %.2f", shovelY, shovelR, targetAttacherHeight)
-
- if math.abs(diff) < (max - min)/2 then
- ImplementUtil.stopMovingTool(spec.armVehicle, spec.armTool)
- return false
- end
-
- local curRot = {}
- curRot[1], curRot[2], curRot[3] = getRotation(spec.armTool.node)
- local oldRot = curRot[spec.armTool.rotationAxis]
-
- setWorldTranslation(spec.armProjectionNode, x, targetAttacherHeight, z)
-
- local _, ay, _ = localToLocal(spec.armTool.node, spec.armVehicle.rootNode, 0, 0, 0)
-
- local nodeDiff = MathUtil.clamp( targetHeight - ay , -shovelR, shovelR) + ay
-
- local ax, _, az = getWorldTranslation(spec.armTool.node)
- local sx, sy, sz = getWorldTranslation(spec.shovelTool.node)
-
- if CpShovelPositions.DEBUG then
- DebugUtil.drawDebugCircleAtNode(spec.armTool.node, shovelR, 30, nil, true)
-
- DebugUtil.drawDebugNode(spec.armProjectionNode, "Projection node", false, 0)
-
- DebugUtil.drawDebugLine(x, targetAttacherHeight, z, sx, sy, sz)
- DebugUtil.drawDebugLine(x, targetAttacherHeight, z, ax, targetAttacherHeight, az) -- y
- end
- local yRot = math.atan2(MathUtil.vector3Length(x - sx, targetAttacherHeight - sy, z - sz),
- MathUtil.vector3Length(x - ax, 0, z - az))
+ --- Debug information
+ local wsx, wsy, wsz = localToWorld(armVehicle.rootNode, sx, sy, sz)
+ local wex, wey, wez = localToWorld(armVehicle.rootNode, ex, ey, ez)
+ if g_currentMission.controlledVehicle == self.rootVehicle and CpDebug:isChannelActive(CpDebug.DBG_SILO) then
+ DebugUtil.drawDebugLine(wsx, wsy, wsz, wex, wey, wez)
+ DebugUtil.drawDebugCircleAtNode(armVehicle.rootNode, radiusArmToolToShovelTool, 30, nil,
+ true, {ax, ay, az})
+ CpUtil.drawDebugNode(armVehicle.rootNode)
+ CpUtil.drawDebugNode(armTool.node)
+ CpUtil.drawDebugNode(shovelTool.node)
+ CpUtil.drawDebugNode(armProjectionNode)
+ CpUtil.drawDebugNode(armToolRefNode)
- if diff < 0 then
- yRot = yRot
- else
- yRot = -yRot
+ local debugData = {}
+ if hasIntersection then
+ table.insert(debugData, {
+ value = "",
+ name = "Arm Rotation" })
+ table.insert(debugData, {
+ name = "alpha", value = math.deg(alpha) })
+ table.insert(debugData, {
+ name = "deltaAlphaOld", value = math.deg(MathUtil.getAngleDifference(alpha, oldArmRot)) })
+ table.insert(debugData, {
+ name = "old", value = math.deg(oldArmRot) })
+ table.insert(debugData, {
+ name = "deltaAlpha", value = math.deg(MathUtil.getAngleDifference(alpha, oldRotRelativeArmRot)) })
+ table.insert(debugData, {
+ name = "dirRot", value = math.deg(oldRotRelativeArmRot) })
+ table.insert(debugData, {
+ name = "distAlpha", value = MathUtil.vector2Length(i1z - tz, i1y - ty) })
+
+ table.insert(debugData, {
+ value = "",
+ name = "",
+ columnOffset = 0.12
+ })
+ end
+ table.insert(debugData, {
+ value = "",
+ name = "Shovel Rotation" })
+ table.insert(debugData, {
+ name = "angle", value = math.deg(angle) })
+ table.insert(debugData, {
+ name = "deltaAngle", value = math.deg(deltaAngle) })
+ table.insert(debugData, {
+ name = "targetAngle", value = math.deg(targetAngle) })
+ DebugUtil.renderTable(0.4, 0.4, 0.018, debugData, 0)
end
-
- CpShovelPositions.debug(shovel,
- "Arm position(%d) height diff: %.2f, targetHeight: %.2f, old angle: %.2f, yRot: %.2f",
- spec.state, diff, targetHeight, math.deg(oldRot), math.deg(yRot))
-
- return ImplementUtil.moveMovingToolToRotation(spec.armVehicle, spec.armTool, dt,
- MathUtil.clamp(oldRot + yRot , spec.armTool.rotMin, spec.armTool.rotMax))
+ return isDirty
end
function CpShovelPositions:updateLoadingPosition(dt)
local spec = self.spec_cpShovelPositions
- local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local angle = CpShovelPositions.getShovelData(self)
local isDirty
if angle then
- isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
- -- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
end
spec.isDirty = isDirty
end
function CpShovelPositions:updateTransportPosition(dt)
local spec = self.spec_cpShovelPositions
- local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local angle = CpShovelPositions.getShovelData(self)
local isDirty
if angle then
- isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
- -- isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS)
- -- isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
end
spec.isDirty = isDirty
end
function CpShovelPositions:updatePreUnloadPosition(dt)
local spec = self.spec_cpShovelPositions
- local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local angle = CpShovelPositions.getShovelData(self)
local isDirty
if angle then
- isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS, CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS)
- --isDirty = CpShovelPositions.setShovelPosition(dt, spec, self, shovelNode, angle, CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS)
- --isDirty = isDirty or CpShovelPositions.setArmPosition(dt, spec, self, shovelNode, self:getCpShovelUnloadingPositionHeight())
end
spec.isDirty = isDirty
end
function CpShovelPositions:updateUnloadingPosition(dt)
local spec = self.spec_cpShovelPositions
- local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
+ local angle, _, maxAngle = CpShovelPositions.getShovelData(self)
local isDirty
if angle and maxAngle then
- isDirty = CpShovelPositions.setShovelPosition2(self, dt,
+ isDirty = CpShovelPositions.setShovelPosition(self, dt,
{math.deg(maxAngle), math.deg(maxAngle) + 2},
CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, true)
end
@@ -504,8 +463,6 @@ function CpShovelPositions:getShovelData()
return angle, shovelSpec.shovelNodes[1].node, info.maxSpeedAngle, info.minSpeedAngle, factor
end
-
-
function CpShovelPositions.debug(implement, ...)
if CpShovelPositions.DEBUG then
CpUtil.infoImplement(implement, ...)
From 10f3013607eda265fd78344bf2d9da28d68d4842 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 11 Jul 2023 19:55:35 +0200
Subject: [PATCH 021/107] Fix silo loader bug
---
scripts/ai/controllers/ShovelController.lua | 23 +++++--------------
.../specializations/CpAISiloLoaderWorker.lua | 2 +-
2 files changed, 7 insertions(+), 18 deletions(-)
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index a1ec9020d..d1bb49bf4 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -87,29 +87,18 @@ function ShovelController:isHighDumpShovel()
return g_vehicleConfigurations:get(self.implement, "shovelMovingToolIx") ~= nil
end
-function ShovelController:moveShovelToLoadingPosition()
- return self:moveShovelToPosition(self.POSITIONS.LOADING)
-end
-
-function ShovelController:moveShovelToTransportPosition()
- return self:moveShovelToPosition(self.POSITIONS.TRANSPORT)
-end
-
-function ShovelController:moveShovelToPreUnloadPosition()
- return self:moveShovelToPosition(self.POSITIONS.PRE_UNLOADING)
-end
-
-function ShovelController:moveShovelToUnloadPosition()
- return self:moveShovelToPosition(self.POSITIONS.UNLOADING)
-end
-
function ShovelController:onFinished()
- self.implement:cpResetShovelState()
+ if self.implement.cpResetShovelState then
+ self.implement:cpResetShovelState()
+ end
end
---@param pos number shovel position 1-4
---@return boolean reached?
function ShovelController:moveShovelToPosition(pos)
+ if self.implement.cpSetShovelState == nil then
+ return false
+ end
self.implement:cpSetShovelState(pos)
return self.implement:areCpShovelPositionsDirty()
end
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index 252cec82f..fe2ff2eca 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -181,7 +181,7 @@ end
function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap, unloadTrigger)
if self.isServer then
local strategy
- if AIUtil.hasAIImplementWithSpecialization(self, ConveyorBelt) then
+ if SpecializationUtil.hasSpecialization(ConveyorBelt, self.specializations) then
CpUtil.debugVehicle(CpDebug.DBG_SILO, self, "Starting a silo loader strategy.")
strategy = AIDriveStrategySiloLoader.new()
else
From a23d87b60f75015ddcbf116d4c7168cdde40e8c2 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 11 Jul 2023 20:42:34 +0200
Subject: [PATCH 022/107] Hopefully fixes hud bugs and WIP sugarbeet shovel
---
scripts/ai/controllers/ShovelController.lua | 15 +++++++++++++++
scripts/gui/hud/CpBaseHud.lua | 8 ++++----
scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua | 4 +++-
scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua | 5 ++++-
scripts/specializations/CpAIBunkerSiloWorker.lua | 5 ++---
5 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index d1bb49bf4..1de8d6c27 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -13,6 +13,7 @@ function ShovelController:init(vehicle, implement)
ImplementController.init(self, vehicle, implement)
self.shovelSpec = self.implement.spec_shovel
self.shovelNode = self.shovelSpec.shovelNodes[1]
+ self.turnOnSpec = self.implement.spec_turnOnVehicle
end
function ShovelController:update()
@@ -96,6 +97,20 @@ end
---@param pos number shovel position 1-4
---@return boolean reached?
function ShovelController:moveShovelToPosition(pos)
+ if self.turnOnSpec then
+ if pos == ShovelController.POSITIONS.UNLOADING then
+ if not self.implement:getIsTurnedOn() and self.implement:getCanBeTurnedOn() then
+ self.implement:setIsTurnedOn(true)
+ self:debug("Turning on the shovel.")
+ end
+ return false
+ else
+ if self.implement:getIsTurnedOn() then
+ self.implement:setIsTurnedOn(false)
+ self:debug("turning off the shovel.")
+ end
+ end
+ end
if self.implement.cpSetShovelState == nil then
return false
end
diff --git a/scripts/gui/hud/CpBaseHud.lua b/scripts/gui/hud/CpBaseHud.lua
index e4383ef88..310330a20 100644
--- a/scripts/gui/hud/CpBaseHud.lua
+++ b/scripts/gui/hud/CpBaseHud.lua
@@ -424,14 +424,14 @@ function CpBaseHud:getActiveHudPage(vehicle)
return self.combineUnloaderLayout
elseif vehicle:getCanStartCpBaleFinder() and not vehicle:hasCpCourse() then
return self.baleFinderLayout
- elseif vehicle:getCanStartCpBunkerSiloWorker() and vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
- or (AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
- and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)) then
- return self.bunkerSiloWorkerLayout
elseif vehicle:getCanStartCpSiloLoaderWorker() and
(AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) or
vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING) then
return self.siloLoaderWorkerLayout
+ elseif vehicle:getCanStartCpBunkerSiloWorker() and vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
+ or (AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
+ and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)) then
+ return self.bunkerSiloWorkerLayout
else
return self.fieldworkLayout
end
diff --git a/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua b/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua
index dc5489420..60e60011a 100644
--- a/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua
+++ b/scripts/gui/hud/CpBunkerSiloWorkerHudPage.lua
@@ -103,9 +103,11 @@ end
function CpBunkerSiloWorkerHudPageElement:isStartingPointBtnDisabled(vehicle)
return AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)
-
end
function CpBunkerSiloWorkerHudPageElement:getStartingPointBtnText(vehicle)
+ if self:isStartingPointBtnDisabled(vehicle) then
+ return vehicle:getCpStartText()
+ end
return vehicle:getCpStartingPointSetting():getString()
end
\ No newline at end of file
diff --git a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
index e8e7aaec6..6382aae28 100644
--- a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
+++ b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
@@ -148,9 +148,12 @@ function CpSiloLoaderWorkerHudPageElement:arePositionEqual(parameters, otherPara
end
function CpSiloLoaderWorkerHudPageElement:isStartingPointBtnDisabled(vehicle)
- return AIUtil.hasAIImplementWithSpecialization(vehicle, ConveyorBelt)
+ return AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt)
end
function CpSiloLoaderWorkerHudPageElement:getStartingPointBtnText(vehicle)
+ if self:isStartingPointBtnDisabled(vehicle) then
+ return vehicle:getCpStartText()
+ end
return vehicle:getCpStartingPointSetting():getString()
end
\ No newline at end of file
diff --git a/scripts/specializations/CpAIBunkerSiloWorker.lua b/scripts/specializations/CpAIBunkerSiloWorker.lua
index 0a66d1596..cb3759fe0 100644
--- a/scripts/specializations/CpAIBunkerSiloWorker.lua
+++ b/scripts/specializations/CpAIBunkerSiloWorker.lua
@@ -98,9 +98,8 @@ function CpAIBunkerSiloWorker:getCanStartCpBunkerSiloWorker()
return not self:getCanStartCpFieldWork()
and not self:getCanStartCpBaleFinder()
and not self:getCanStartCpCombineUnloader()
-
- and (not self:hasCpCourse() or
- AIUtil.hasChildVehicleWithSpecialization(self, Leveler))
+ and not self:getCanStartCpSiloLoaderWorker()
+ and (not self:hasCpCourse() or AIUtil.hasChildVehicleWithSpecialization(self, Leveler))
and not AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
end
From 27bc77cef900f8ecdc637fc4ee9ce2c648383f20 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 11 Jul 2023 21:13:27 +0200
Subject: [PATCH 023/107] Improvement and bug fixes
---
scripts/gui/hud/CpBaseHud.lua | 10 ++++------
.../specializations/CpAIBunkerSiloWorker.lua | 8 +++-----
.../specializations/CpAISiloLoaderWorker.lua | 19 +++++++++----------
scripts/specializations/CpShovelPositions.lua | 13 ++++++++++---
4 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/scripts/gui/hud/CpBaseHud.lua b/scripts/gui/hud/CpBaseHud.lua
index 310330a20..ef3812608 100644
--- a/scripts/gui/hud/CpBaseHud.lua
+++ b/scripts/gui/hud/CpBaseHud.lua
@@ -424,13 +424,11 @@ function CpBaseHud:getActiveHudPage(vehicle)
return self.combineUnloaderLayout
elseif vehicle:getCanStartCpBaleFinder() and not vehicle:hasCpCourse() then
return self.baleFinderLayout
- elseif vehicle:getCanStartCpSiloLoaderWorker() and
- (AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) or
- vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING) then
+ elseif vehicle:getCanStartCpSiloLoaderWorker() and (vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING
+ or AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt)) then
return self.siloLoaderWorkerLayout
- elseif vehicle:getCanStartCpBunkerSiloWorker() and vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
- or (AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
- and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)) then
+ elseif vehicle:getCanStartCpBunkerSiloWorker() and (vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
+ or AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)) then
return self.bunkerSiloWorkerLayout
else
return self.fieldworkLayout
diff --git a/scripts/specializations/CpAIBunkerSiloWorker.lua b/scripts/specializations/CpAIBunkerSiloWorker.lua
index cb3759fe0..fb07d3732 100644
--- a/scripts/specializations/CpAIBunkerSiloWorker.lua
+++ b/scripts/specializations/CpAIBunkerSiloWorker.lua
@@ -95,12 +95,13 @@ end
--- Is the bunker silo allowed?
function CpAIBunkerSiloWorker:getCanStartCpBunkerSiloWorker()
+ if AIUtil.hasChildVehicleWithSpecialization(self, Shovel) then
+ return false
+ end
return not self:getCanStartCpFieldWork()
and not self:getCanStartCpBaleFinder()
and not self:getCanStartCpCombineUnloader()
and not self:getCanStartCpSiloLoaderWorker()
- and (not self:hasCpCourse() or AIUtil.hasChildVehicleWithSpecialization(self, Leveler))
- and not AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
end
function CpAIBunkerSiloWorker:getCanStartCp(superFunc)
@@ -110,9 +111,6 @@ end
function CpAIBunkerSiloWorker:getCpStartableJob(superFunc, isStartedByHud)
local spec = self.spec_cpAIBunkerSiloWorker
local job = self:getCanStartCpBunkerSiloWorker() and spec.cpJob
- if isStartedByHud then
- job = self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO and job
- end
return superFunc(self, isStartedByHud) or job
end
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index fe2ff2eca..0425953b8 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -97,7 +97,6 @@ end
function CpAISiloLoaderWorker:getCanStartCpSiloLoaderWorker()
return not self:getCanStartCpFieldWork()
and not self:getCanStartCpBaleFinder()
- and (not self:hasCpCourse() or AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt))
and not self:getCanStartCpCombineUnloader()
and AIUtil.hasChildVehicleWithSpecialization(self, Shovel)
end
@@ -108,16 +107,16 @@ end
function CpAISiloLoaderWorker:getCpStartableJob(superFunc, isStartedByHud)
local spec = self.spec_cpAISiloLoaderWorker
- if AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt) then
- return superFunc(self, isStartedByHud) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
- elseif isStartedByHud then
- if self:getCanStartCpSiloLoaderWorker()
- and self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING then
- return superFunc(self, isStartedByHud) or spec.cpJob
- end
+ -- if AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt) then
+ -- return superFunc(self, isStartedByHud) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
+ -- elseif isStartedByHud then
+ -- if self:getCanStartCpSiloLoaderWorker()
+ -- and self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING then
+ -- return superFunc(self, isStartedByHud) or spec.cpJob
+ -- end
- end
- return superFunc(self, isStartedByHud)
+ -- end
+ return superFunc(self, isStartedByHud) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
end
function CpAISiloLoaderWorker:getCpStartText(superFunc)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 4898229c4..a24785177 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -278,14 +278,21 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
local attacherJointNode = self.spec_attachable.attacherJoint.node
local angle, shovelNode = CpShovelPositions.getShovelData(self)
- local _, shovelY, _ = localToLocal(shovelNode, attacherJointNode, 0, 0, 0)
+ local _, shovelY, _ = localToLocal(self.rootNode, attacherJointNode, 0, 0, 0)
+ --- local tempNode = createTransformGroup("tempVehicleSizeCenter")
+ -- link(vehicle.rootNode, tempNode)
+ -- setTranslation(tempNode, vehicle.size.widthOffset, vehicle.size.heightOffset + vehicle.size.height / 2, vehicle.size.lengthOffset)
+ -- DebugUtil.drawDebugCube(tempNode, vehicle.size.width, vehicle.size.height, vehicle.size.length, 0, 0, 1)
+ -- delete(tempNode)
+
+
--- All values will be calculated in the coordinate system from the vehicle root node.
local _, ty, tz = localToLocal(getChildAt(armTool.node, 0), armVehicle.rootNode, 0, 0, 0)
local ax, ay, az = localToLocal(armTool.node, armVehicle.rootNode, 0, 0, 0)
- local sx, sy, sz = 0, targetHeight - shovelY, 0
- local ex, ey, ez = 0, targetHeight - shovelY, 20
+ local sx, sy, sz = 0, targetHeight - shovelY - self.size.heightOffset, 0
+ local ex, ey, ez = 0, targetHeight - shovelY - self.size.heightOffset, 20
local yMax = ay + radiusArmToolToShovelTool
if sy > yMax then
--- Makes sure the target height is still reachable
From a9fc27235eb7dfb86c6aea1950fa5211edd56b98 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 11 Jul 2023 21:36:39 +0200
Subject: [PATCH 024/107] Minor adjustment
---
scripts/ai/ImplementUtil.lua | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index 1d58762ec..9f36aa676 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -431,6 +431,7 @@ end
---@return number|nil target implement fill unit ix to load into.
---@return number|nil fill type to load
---@return number|nil target exact fill root node
+---@return number|nil alternative fill type, when the implement gets turned on
function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, dischargeNode, debugFunc)
local function debug(str, ...)
@@ -448,7 +449,15 @@ function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, di
end
local fillType = implementToLoadFrom:getDischargeFillType(dischargeNode)
-
+ local alternativeFillType
+ if implementToLoadFrom.spec_turnOnVehicle then
+ --- The discharge node flips when the implement gets turned on.
+ --- The fill type might be different then.
+ local turnOnDischargeNode = implementToLoadFrom.spec_turnOnVehicle.activateableDischargeNode
+ if turnOnDischargeNode then
+ alternativeFillType = implementToLoadFrom:getDischargeFillType(turnOnDischargeNode)
+ end
+ end
if fillType == nil or fillType == FillType.UNKNOWN then
debug("No valid fill type to load!")
return false, nil, nil, nil
@@ -460,16 +469,19 @@ function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, di
---@return number|nil
---@return number|nil
local function canLoad(fillUnitIndex)
- if not loadTargetImplement:getFillUnitSupportsFillType(fillUnitIndex, fillType) then
+ if not loadTargetImplement:getFillUnitSupportsFillType(fillUnitIndex, fillType) and
+ not loadTargetImplement:getFillUnitSupportsFillType(fillUnitIndex, alternativeFillType) then
debug("Fill unit(%d) doesn't support fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeNameByIndex(fillType))
return false
end
- if not loadTargetImplement:getFillUnitAllowsFillType(fillUnitIndex, fillType) then
+ if not loadTargetImplement:getFillUnitAllowsFillType(fillUnitIndex, fillType) and
+ not loadTargetImplement:getFillUnitAllowsFillType(fillUnitIndex, alternativeFillType) then
debug("Fill unit(%d) doesn't allow fill type %s", fillUnitIndex, g_fillTypeManager:getFillTypeNameByIndex(fillType))
return false
end
if loadTargetImplement.getFillUnitFreeCapacity and
- loadTargetImplement:getFillUnitFreeCapacity(fillUnitIndex, fillType, implementToLoadFrom:getActiveFarm()) <= 0 then
+ loadTargetImplement:getFillUnitFreeCapacity(fillUnitIndex, fillType, implementToLoadFrom:getActiveFarm()) <= 0 and
+ loadTargetImplement:getFillUnitFreeCapacity(fillUnitIndex, alternativeFillType, implementToLoadFrom:getActiveFarm()) <= 0 then
debug("Fill unit(%d) is full with fill type %s!", fillUnitIndex, g_fillTypeManager:getFillTypeNameByIndex(fillType))
return false
end
@@ -490,6 +502,6 @@ function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, di
end
end
- return validTarget, targetFillUnitIndex, fillType, exactFillRootNode
+ return validTarget, targetFillUnitIndex, fillType, exactFillRootNode, alternativeFillType
end
From 9c2434cfa62530f9a00a881b9c78be048143f7bb Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 10:33:51 +0200
Subject: [PATCH 025/107] Some more bug fixes
---
Courseplay.lua | 14 ++--
scripts/specializations/CourseplaySpec.lua | 5 +-
scripts/specializations/CpAIBaleFinder.lua | 2 +-
.../specializations/CpAIBunkerSiloWorker.lua | 5 +-
scripts/specializations/CpAIFieldWorker.lua | 19 +++--
.../specializations/CpAISiloLoaderWorker.lua | 15 ++--
scripts/specializations/CpAIWorker.lua | 12 ----
.../CpCourseGeneratorSettings.lua | 15 ++--
scripts/specializations/CpCourseManager.lua | 16 +++--
scripts/specializations/CpGamePadHud.lua | 2 +-
scripts/specializations/CpHud.lua | 2 +-
scripts/specializations/CpInfoTexts.lua | 2 +-
scripts/specializations/CpVehicleSettings.lua | 71 +++++++++----------
13 files changed, 80 insertions(+), 100 deletions(-)
diff --git a/Courseplay.lua b/Courseplay.lua
index ff40bf12d..5622fef55 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -325,19 +325,13 @@ end
function Courseplay.register(typeManager)
--- TODO: make this function async.
for typeName, typeEntry in pairs(typeManager.types) do
+ CpAIWorker.register(typeManager, typeName, typeEntry.specializations)
if CourseplaySpec.prerequisitesPresent(typeEntry.specializations) then
typeManager:addSpecialization(typeName, Courseplay.MOD_NAME .. ".courseplaySpec")
end
- if CpVehicleSettings.prerequisitesPresent(typeEntry.specializations) then
- typeManager:addSpecialization(typeName, Courseplay.MOD_NAME .. ".cpVehicleSettings")
- end
- if CpCourseGeneratorSettings.prerequisitesPresent(typeEntry.specializations) then
- typeManager:addSpecialization(typeName, Courseplay.MOD_NAME .. ".cpCourseGeneratorSettings")
- end
- if CpCourseManager.prerequisitesPresent(typeEntry.specializations) then
- typeManager:addSpecialization(typeName, Courseplay.MOD_NAME .. ".cpCourseManager")
- end
- CpAIWorker.register(typeManager, typeName, typeEntry.specializations)
+ CpVehicleSettings.register(typeManager, typeName, typeEntry.specializations)
+ CpCourseGeneratorSettings.register(typeManager, typeName, typeEntry.specializations)
+ CpCourseManager.register(typeManager, typeName, typeEntry.specializations)
CpAIFieldWorker.register(typeManager, typeName, typeEntry.specializations)
CpAIBaleFinder.register(typeManager, typeName, typeEntry.specializations)
CpAICombineUnloader.register(typeManager, typeName, typeEntry.specializations)
diff --git a/scripts/specializations/CourseplaySpec.lua b/scripts/specializations/CourseplaySpec.lua
index 8894d1472..cf3bae77a 100644
--- a/scripts/specializations/CourseplaySpec.lua
+++ b/scripts/specializations/CourseplaySpec.lua
@@ -12,7 +12,7 @@ function CourseplaySpec.initSpecialization()
end
function CourseplaySpec.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(AIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CourseplaySpec.registerEventListeners(vehicleType)
@@ -34,13 +34,10 @@ function CourseplaySpec.registerOverwrittenFunctions(vehicleType)
end
-
function CourseplaySpec:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
end
-
-
------------------------------------------------------------------------------------------------------------------------
--- Event listeners
---------------------------------------------------------------------------------------------------------------------------
diff --git a/scripts/specializations/CpAIBaleFinder.lua b/scripts/specializations/CpAIBaleFinder.lua
index d0ba354c3..51adf5f96 100644
--- a/scripts/specializations/CpAIBaleFinder.lua
+++ b/scripts/specializations/CpAIBaleFinder.lua
@@ -19,7 +19,7 @@ function CpAIBaleFinder.initSpecialization()
end
function CpAIBaleFinder.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(CpAIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpAIBaleFinder.register(typeManager,typeName,specializations)
diff --git a/scripts/specializations/CpAIBunkerSiloWorker.lua b/scripts/specializations/CpAIBunkerSiloWorker.lua
index fb07d3732..1132a81f2 100644
--- a/scripts/specializations/CpAIBunkerSiloWorker.lua
+++ b/scripts/specializations/CpAIBunkerSiloWorker.lua
@@ -18,7 +18,7 @@ function CpAIBunkerSiloWorker.initSpecialization()
end
function CpAIBunkerSiloWorker.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(CpAIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpAIBunkerSiloWorker.register(typeManager,typeName,specializations)
@@ -111,6 +111,9 @@ end
function CpAIBunkerSiloWorker:getCpStartableJob(superFunc, isStartedByHud)
local spec = self.spec_cpAIBunkerSiloWorker
local job = self:getCanStartCpBunkerSiloWorker() and spec.cpJob
+ if isStartedByHud and not AIUtil.hasChildVehicleWithSpecialization(self, Leveler) then
+ job = self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO and job
+ end
return superFunc(self, isStartedByHud) or job
end
diff --git a/scripts/specializations/CpAIFieldWorker.lua b/scripts/specializations/CpAIFieldWorker.lua
index c16ef3294..1c6a9bb2c 100644
--- a/scripts/specializations/CpAIFieldWorker.lua
+++ b/scripts/specializations/CpAIFieldWorker.lua
@@ -39,8 +39,7 @@ function CpAIFieldWorker.registerEventListeners(vehicleType)
SpecializationUtil.registerEventListener(vehicleType, "onCpFull", CpAIFieldWorker)
SpecializationUtil.registerEventListener(vehicleType, "onCpFinished", CpAIFieldWorker)
- SpecializationUtil.registerEventListener(vehicleType, "onPostDetachImplement", CpAIFieldWorker)
- SpecializationUtil.registerEventListener(vehicleType, "onPostAttachImplement", CpAIFieldWorker)
+ SpecializationUtil.registerEventListener(vehicleType, "onStateChange", CpAIFieldWorker)
SpecializationUtil.registerEventListener(vehicleType, 'onCpCourseChange', CpAIFieldWorker)
SpecializationUtil.registerEventListener(vehicleType, 'onCpADStartedByPlayer', CpAIFieldWorker)
@@ -107,22 +106,20 @@ function CpAIFieldWorker:saveToXMLFile(xmlFile, baseKey, usedModNames)
spec.cpJobStartAtLastWp:getCpJobParameters():saveToXMLFile(xmlFile, baseKey.. ".cpJobStartAtLastWp")
end
-function CpAIFieldWorker:onCpCourseChange()
- local spec = self.spec_cpAIFieldWorker
- spec.cpJob:getCpJobParameters():validateSettings()
-end
-
-function CpAIFieldWorker:onPostDetachImplement()
+function CpAIFieldWorker:onStateChange(state, data)
local spec = self.spec_cpAIFieldWorker
- spec.cpJob:getCpJobParameters():validateSettings()
+ if state == Vehicle.STATE_CHANGE_ATTACH then
+ spec.cpJob:getCpJobParameters():validateSettings()
+ elseif state == Vehicle.STATE_CHANGE_DETACH then
+ spec.cpJob:getCpJobParameters():validateSettings()
+ end
end
-function CpAIFieldWorker:onPostAttachImplement()
+function CpAIFieldWorker:onCpCourseChange()
local spec = self.spec_cpAIFieldWorker
spec.cpJob:getCpJobParameters():validateSettings()
end
-
function CpAIFieldWorker:getCpStartingPointSetting()
local spec = self.spec_cpAIFieldWorker
return spec.cpJob:getCpJobParameters().startAt
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index 0425953b8..c470e7af9 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -107,16 +107,11 @@ end
function CpAISiloLoaderWorker:getCpStartableJob(superFunc, isStartedByHud)
local spec = self.spec_cpAISiloLoaderWorker
- -- if AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt) then
- -- return superFunc(self, isStartedByHud) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
- -- elseif isStartedByHud then
- -- if self:getCanStartCpSiloLoaderWorker()
- -- and self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING then
- -- return superFunc(self, isStartedByHud) or spec.cpJob
- -- end
-
- -- end
- return superFunc(self, isStartedByHud) or self:getCanStartCpSiloLoaderWorker() and spec.cpJob
+ local job = self:getCanStartCpSiloLoaderWorker() and spec.cpJob
+ if isStartedByHud and not AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt) then
+ job = self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING and job
+ end
+ return superFunc(self, isStartedByHud) or job
end
function CpAISiloLoaderWorker:getCpStartText(superFunc)
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index a600e569d..5b3ca1ca9 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -42,8 +42,6 @@ function CpAIWorker.registerEventListeners(vehicleType)
SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onLoad", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onLoadFinished", CpAIWorker)
- SpecializationUtil.registerEventListener(vehicleType, "onPreDetachImplement", CpAIWorker)
- SpecializationUtil.registerEventListener(vehicleType, "onPostAttachImplement", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onUpdate", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", CpAIWorker)
@@ -93,16 +91,6 @@ function CpAIWorker:onLoadFinished()
end
-function CpAIWorker:onPreDetachImplement(implement)
- local spec = self.spec_cpAIWorker
-end
-
-function CpAIWorker:onPostAttachImplement(object)
- local spec = self.spec_cpAIWorker
-
-end
-
-
function CpAIWorker:onLeaveVehicle(wasEntered)
if wasEntered then
CpJobSyncOnLeaveEvent.sendEvent(self)
diff --git a/scripts/specializations/CpCourseGeneratorSettings.lua b/scripts/specializations/CpCourseGeneratorSettings.lua
index b443bfc22..7b23a4b9c 100644
--- a/scripts/specializations/CpCourseGeneratorSettings.lua
+++ b/scripts/specializations/CpCourseGeneratorSettings.lua
@@ -6,9 +6,12 @@
CpCourseGeneratorSettings = {}
CpCourseGeneratorSettings.MOD_NAME = g_currentModName
-CpCourseGeneratorSettings.KEY = "."..CpCourseGeneratorSettings.MOD_NAME..".cpCourseGeneratorSettings"
CpCourseGeneratorSettings.SETTINGS_KEY = ".settings"
CpCourseGeneratorSettings.VINE_SETTINGS_KEY = ".vineSettings"
+CpCourseGeneratorSettings.NAME = ".cpCourseGeneratorSettings"
+CpCourseGeneratorSettings.SPEC_NAME = CpCourseGeneratorSettings.MOD_NAME .. CpCourseGeneratorSettings.NAME
+CpCourseGeneratorSettings.KEY = "." .. CpCourseGeneratorSettings.MOD_NAME .. CpCourseGeneratorSettings.NAME
+
function CpCourseGeneratorSettings.initSpecialization()
local schema = Vehicle.xmlSchemaSavegame
--- Old save format
@@ -27,9 +30,14 @@ function CpCourseGeneratorSettings.initSpecialization()
CpCourseGeneratorSettings.registerConsoleCommands()
end
+function CpCourseGeneratorSettings.register(typeManager,typeName,specializations)
+ if CpCourseGeneratorSettings.prerequisitesPresent(specializations) then
+ typeManager:addSpecialization(typeName, CpCourseGeneratorSettings.SPEC_NAME)
+ end
+end
function CpCourseGeneratorSettings.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(AIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpCourseGeneratorSettings.registerEvents(vehicleType)
@@ -79,8 +87,7 @@ end
function CpCourseGeneratorSettings:onLoad(savegame)
--- Register the spec: spec_cpCourseGeneratorSettings
- local specName = CpCourseGeneratorSettings.MOD_NAME .. ".cpCourseGeneratorSettings"
- self.spec_cpCourseGeneratorSettings = self["spec_" .. specName]
+ self.spec_cpCourseGeneratorSettings = self["spec_" .. CpCourseGeneratorSettings.SPEC_NAME]
local spec = self.spec_cpCourseGeneratorSettings
spec.gui = g_currentMission.inGameMenu.pageAI
--- Clones the generic settings to create different settings containers for each vehicle.
diff --git a/scripts/specializations/CpCourseManager.lua b/scripts/specializations/CpCourseManager.lua
index 25ede6744..1a1ef23bf 100644
--- a/scripts/specializations/CpCourseManager.lua
+++ b/scripts/specializations/CpCourseManager.lua
@@ -5,8 +5,9 @@
CpCourseManager = {}
CpCourseManager.MOD_NAME = g_currentModName
-
-CpCourseManager.KEY = "."..CpCourseManager.MOD_NAME..".cpCourseManager"
+CpCourseManager.NAME = ".cpCourseManager"
+CpCourseManager.SPEC_NAME = CpCourseManager.MOD_NAME .. CpCourseManager.NAME
+CpCourseManager.KEY = "." .. CpCourseManager.MOD_NAME .. CpCourseManager.NAME
CpCourseManager.xmlKey = "Course"
CpCourseManager.rootKey = "AssignedCourses"
CpCourseManager.rootKeyFileManager = "Courses"
@@ -43,8 +44,14 @@ function CpCourseManager.initSpecialization()
schema:register(XMLValueType.INT, key .. "#assignedCoursesID", "Assigned Courses id.")
end
+function CpCourseManager.register(typeManager,typeName,specializations)
+ if CpCourseManager.prerequisitesPresent(specializations) then
+ typeManager:addSpecialization(typeName, CpCourseManager.SPEC_NAME)
+ end
+end
+
function CpCourseManager.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(AIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpCourseManager.registerEventListeners(vehicleType)
@@ -113,8 +120,7 @@ end
function CpCourseManager:onLoad(savegame)
--- Register the spec: spec_cpCourseManager
- local specName = CpCourseManager.MOD_NAME .. ".cpCourseManager"
- self.spec_cpCourseManager = self["spec_" .. specName]
+ self.spec_cpCourseManager = self["spec_" .. CpCourseManager.SPEC_NAME]
local spec = self.spec_cpCourseManager
spec.coursePlot = CoursePlot(g_currentMission.inGameMenu.ingameMap)
diff --git a/scripts/specializations/CpGamePadHud.lua b/scripts/specializations/CpGamePadHud.lua
index 9837bdb2e..d608cf851 100644
--- a/scripts/specializations/CpGamePadHud.lua
+++ b/scripts/specializations/CpGamePadHud.lua
@@ -44,7 +44,7 @@ function CpGamePadHud.initSpecialization()
end
function CpGamePadHud.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(AIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpGamePadHud.register(typeManager, typeName, specializations)
diff --git a/scripts/specializations/CpHud.lua b/scripts/specializations/CpHud.lua
index fbef606ef..23f7b63df 100644
--- a/scripts/specializations/CpHud.lua
+++ b/scripts/specializations/CpHud.lua
@@ -16,7 +16,7 @@ function CpHud.initSpecialization()
end
function CpHud.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(CpAIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpHud.register(typeManager,typeName,specializations)
diff --git a/scripts/specializations/CpInfoTexts.lua b/scripts/specializations/CpInfoTexts.lua
index 9aaf790e9..8b78daecc 100644
--- a/scripts/specializations/CpInfoTexts.lua
+++ b/scripts/specializations/CpInfoTexts.lua
@@ -19,7 +19,7 @@ end
function CpInfoTexts.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(CpAIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpInfoTexts.registerEventListeners(vehicleType)
diff --git a/scripts/specializations/CpVehicleSettings.lua b/scripts/specializations/CpVehicleSettings.lua
index 8ee13db07..6a6b1616d 100644
--- a/scripts/specializations/CpVehicleSettings.lua
+++ b/scripts/specializations/CpVehicleSettings.lua
@@ -6,9 +6,12 @@
CpVehicleSettings = {}
CpVehicleSettings.MOD_NAME = g_currentModName
-CpVehicleSettings.KEY = "."..CpVehicleSettings.MOD_NAME..".cpVehicleSettings"
CpVehicleSettings.SETTINGS_KEY = ".settings"
CpVehicleSettings.USER_KEY = ".users"
+CpVehicleSettings.NAME = ".cpVehicleSettings"
+CpVehicleSettings.SPEC_NAME = CpVehicleSettings.MOD_NAME .. CpVehicleSettings.NAME
+CpVehicleSettings.KEY = "." .. CpVehicleSettings.MOD_NAME .. CpVehicleSettings.NAME
+
function CpVehicleSettings.initSpecialization()
local schema = Vehicle.xmlSchemaSavegame
--- Old xml schema for settings
@@ -30,9 +33,14 @@ function CpVehicleSettings.initSpecialization()
CpVehicleSettings.registerConsoleCommands()
end
+function CpVehicleSettings.register(typeManager,typeName,specializations)
+ if CpVehicleSettings.prerequisitesPresent(specializations) then
+ typeManager:addSpecialization(typeName, CpVehicleSettings.SPEC_NAME)
+ end
+end
function CpVehicleSettings.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(AIFieldWorker, specializations)
+ return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
end
function CpVehicleSettings.registerEvents(vehicleType)
@@ -44,8 +52,6 @@ function CpVehicleSettings.registerEventListeners(vehicleType)
-- SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onLoad", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onLoadFinished", CpVehicleSettings)
- SpecializationUtil.registerEventListener(vehicleType, "onPreDetachImplement", CpVehicleSettings)
- SpecializationUtil.registerEventListener(vehicleType, "onPostAttachImplement", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onCpUnitChanged", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onReadStream", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", CpVehicleSettings)
@@ -74,8 +80,7 @@ end
function CpVehicleSettings:onLoad(savegame)
--- Register the spec: spec_CpVehicleSettings
- local specName = CpVehicleSettings.MOD_NAME .. ".cpVehicleSettings"
- self.spec_cpVehicleSettings = self["spec_" .. specName]
+ self.spec_cpVehicleSettings = self["spec_" .. CpVehicleSettings.SPEC_NAME]
local spec = self.spec_cpVehicleSettings
--- Clones the generic settings to create different settings containers for each vehicle.
@@ -90,43 +95,11 @@ function CpVehicleSettings:onLoadFinished()
spec.wasLoaded = nil
end
---- TODO: These are only applied on a implement an not on a single vehicle.
---- This means self driving vehicle are not getting these vehicle configuration values.
-function CpVehicleSettings:onPostAttachImplement(object)
- --- Only apply these values, if were are not loading from a savegame.
- local spec = self.spec_cpVehicleSettings
- if spec.wasLoaded then
- return
- end
-
- CpVehicleSettings.setAutomaticWorkWidthAndOffset(self)
- CpVehicleSettings.setAutomaticBunkerSiloWorkWidth(self)
- CpVehicleSettings.setAutomaticBaleCollectorOffset(self)
-
- CpVehicleSettings.setFromVehicleConfiguration(self, object, spec.raiseImplementLate, 'raiseLate')
- CpVehicleSettings.setFromVehicleConfiguration(self, object, spec.lowerImplementEarly, 'lowerEarly')
- CpVehicleSettings.setFromVehicleConfiguration(self, object, spec.bunkerSiloWorkWidth, 'workingWidth')
- CpVehicleSettings.validateSettings(self)
-end
-
-function CpVehicleSettings:onPreDetachImplement(implement)
- --- Only apply these values, if were are not loading from a savegame.
- local spec = self.spec_cpVehicleSettings
- if spec.wasLoaded then
- return
- end
-
- CpVehicleSettings.setAutomaticWorkWidthAndOffset(self, implement.object)
- CpVehicleSettings.setAutomaticBunkerSiloWorkWidth(self, implement.object)
-
- CpVehicleSettings.resetToDefault(self, implement.object, spec.raiseImplementLate, 'raiseLate', false)
- CpVehicleSettings.resetToDefault(self, implement.object, spec.lowerImplementEarly, 'lowerEarly', false)
- CpVehicleSettings.validateSettings(self)
-end
--- Changes the sprayer work width on fill type change, as it might depend on the loaded fill type.
--- For example Lime and Fertilizer might have a different work width.
function CpVehicleSettings:onStateChange(state, data)
+ local spec = self.spec_cpVehicleSettings
if state == Vehicle.STATE_CHANGE_FILLTYPE_CHANGE and self:getIsSynchronized() then
local _, hasSprayer = AIUtil.getAllChildVehiclesWithSpecialization(self, Sprayer, nil)
if hasSprayer then
@@ -137,6 +110,26 @@ function CpVehicleSettings:onStateChange(state, data)
self:getCourseGeneratorSettings().workWidth:setFloatValue(width)
end
end
+ elseif state == Vehicle.STATE_CHANGE_ATTACH then
+ CpVehicleSettings.setAutomaticWorkWidthAndOffset(self)
+ CpVehicleSettings.setAutomaticBunkerSiloWorkWidth(self)
+ CpVehicleSettings.setAutomaticBaleCollectorOffset(self)
+ CpVehicleSettings.setFromVehicleConfiguration(self, data.attachedVehicle,
+ spec.raiseImplementLate, 'raiseLate')
+ CpVehicleSettings.setFromVehicleConfiguration(self, data.attachedVehicle,
+ spec.lowerImplementEarly, 'lowerEarly')
+ CpVehicleSettings.setFromVehicleConfiguration(self, data.attachedVehicle,
+ spec.bunkerSiloWorkWidth, 'workingWidth')
+ CpVehicleSettings.validateSettings(self)
+ elseif state == Vehicle.STATE_CHANGE_DETACH then
+ CpVehicleSettings.setAutomaticWorkWidthAndOffset(self, data.attachedVehicle)
+ CpVehicleSettings.setAutomaticBunkerSiloWorkWidth(self, data.attachedVehicle)
+
+ CpVehicleSettings.resetToDefault(self, data.attachedVehicle, spec.raiseImplementLate,
+ 'raiseLate', false)
+ CpVehicleSettings.resetToDefault(self, data.attachedVehicle, spec.lowerImplementEarly,
+ 'lowerEarly', false)
+ CpVehicleSettings.validateSettings(self)
end
end
From 225946ad09acf5891dd092d14e3e68bc5a04c9eb Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 11:43:51 +0200
Subject: [PATCH 026/107] Some Adjustments
---
.../ai/AIDriveStrategyShovelSiloLoader.lua | 19 ++++++++++++-------
scripts/ai/controllers/ShovelController.lua | 3 +++
scripts/pathfinder/PathfinderUtil.lua | 12 ++++++------
3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 6308574f2..de270f980 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -128,7 +128,11 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
end
local cx, cz = self.silo:getFrontCenter()
- self.siloFrontNode = CpUtil.createNode("siloFrontNode", cx, cz, 0)
+ local dirX, dirZ = self.silo:getLengthDirection()
+ local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
+ self.siloFrontNode = CpUtil.createNode("siloFrontNode", cx, cz, yRot)
+ self.siloAreaToAvoid = PathfinderUtil.NodeArea(self.siloFrontNode, -self.silo:getWidth()/2,
+ 0, self.silo:getWidth(), self.silo:getLength())
self.siloController = CpBunkerSiloLoaderController(self.silo, self.vehicle, self)
end
@@ -313,6 +317,7 @@ function AIDriveStrategyShovelSiloLoader:update(dt)
end
if self.silo then
self.silo:drawDebug()
+ self.siloAreaToAvoid:drawDebug()
end
self.siloController:draw()
if self.heapSilo then
@@ -438,8 +443,6 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
self:startPathfindingToTrailer()
end
-
-
----------------------------------------------------------------
--- Pathfinding
----------------------------------------------------------------
@@ -454,7 +457,8 @@ function AIDriveStrategyShovelSiloLoader:startPathfindingToStart(course)
local fm = self:getFrontAndBackMarkers()
self.pathfinder, done, path = PathfinderUtil.startPathfindingFromVehicleToWaypoint(
self.vehicle, course, 1, 0, -(fm + 4),
- true, nil)
+ true, nil, nil,
+ nil, 0, self.siloAreaToAvoid)
if done then
return self:onPathfindingDoneToStart(path)
else
@@ -489,7 +493,7 @@ function AIDriveStrategyShovelSiloLoader:startPathfindingToUnloadPosition()
self.vehicle, self.unloadPositionNode,
0, 0, true,
nil, {}, nil,
- 0, nil, false
+ 0, self.siloAreaToAvoid, false
)
if done then
return self:onPathfindingDoneToUnloadPosition(path, goalNodeInvalid)
@@ -523,7 +527,7 @@ function AIDriveStrategyShovelSiloLoader:startPathfindingToTrailer()
self.vehicle, self.unloadPositionNode,
0, 0, true,
nil, {}, nil,
- 0, nil, false
+ 0, self.siloAreaToAvoid, false
)
if done then
return self:onPathfindingDoneToTrailer(path, goalNodeInvalid)
@@ -635,7 +639,8 @@ end
--- Starts reverse straight to make some space to the trailer or unload trigger.
function AIDriveStrategyShovelSiloLoader:startReversingAwayFromUnloading()
local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
- local course = Course.createStraightReverseCourse(self.vehicle, 2*spaceToTrailer, 0 )
+ local course = Course.createStraightReverseCourse(self.vehicle, 2*spaceToTrailer,
+ 0, self.vehicle.rootNode )
self:startCourse(course, 1)
self:setNewState(self.states.REVERSING_AWAY_FROM_UNLOAD)
end
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 1de8d6c27..47b2e73e1 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -103,6 +103,9 @@ function ShovelController:moveShovelToPosition(pos)
self.implement:setIsTurnedOn(true)
self:debug("Turning on the shovel.")
end
+ if not self.implement:getDischargeState() ~= Dischargeable.DISCHARGE_STATE_OBJECT then
+ self.implement:setDischargeState(Dischargeable.DISCHARGE_STATE_OBJECT)
+ end
return false
else
if self.implement:getIsTurnedOn() then
diff --git a/scripts/pathfinder/PathfinderUtil.lua b/scripts/pathfinder/PathfinderUtil.lua
index 4565bfa01..a2423dfae 100644
--- a/scripts/pathfinder/PathfinderUtil.lua
+++ b/scripts/pathfinder/PathfinderUtil.lua
@@ -914,13 +914,13 @@ end
---@param xOffset number side offset of the goal from the goalWaypoint
---@param zOffset number length offset of the goal from the goalWaypoint
---@param allowReverse boolean allow reverse driving
----@param fieldNum number if > 0, the pathfinding is restricted to the given field and its vicinity. Otherwise the
+---@param fieldNum number|nil if > 0, the pathfinding is restricted to the given field and its vicinity. Otherwise the
--- pathfinding considers any collision-free path valid, also outside of the field.
----@param vehiclesToIgnore table[] list of vehicles to ignore for the collision detection (optional)
----@param maxFruitPercent number maximum percentage of fruit present before a node is marked as invalid (optional)
----@param offFieldPenalty number penalty to apply to nodes off the field
----@param areaToAvoid PathfinderUtil.NodeArea nodes in this area will be penalized so the path will most likely avoid it
----@param areaToIgnoreFruit PathfinderUtil.Area area to ignore fruit
+---@param vehiclesToIgnore table[]|nil list of vehicles to ignore for the collision detection (optional)
+---@param maxFruitPercent number|nil maximum percentage of fruit present before a node is marked as invalid (optional)
+---@param offFieldPenalty number|nil penalty to apply to nodes off the field
+---@param areaToAvoid PathfinderUtil.NodeArea|nil nodes in this area will be penalized so the path will most likely avoid it
+---@param areaToIgnoreFruit PathfinderUtil.Area|nil area to ignore fruit
---@return PathfinderInterface pathfinder
---@return boolean done finished pathfinding?
---@return table|nil path that was found?
From 7a6275043193aab0c06726eb7e46677ac0005fac Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 12:15:48 +0200
Subject: [PATCH 027/107] Gamepad hud bug fixes
---
config/gamePadHud/SiloLoaderGamePadHudPage.xml | 1 +
config/jobParameters/JobParameterSetup.xml | 6 +++---
scripts/ai/jobs/CpJobParameters.lua | 12 ++++++++++++
scripts/gui/CpGamePadHudScreen.lua | 3 +++
scripts/gui/hud/CpBaseHud.lua | 5 +++--
scripts/specializations/CpGamePadHud.lua | 11 ++++++-----
6 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/config/gamePadHud/SiloLoaderGamePadHudPage.xml b/config/gamePadHud/SiloLoaderGamePadHudPage.xml
index c406daddd..0969a7251 100644
--- a/config/gamePadHud/SiloLoaderGamePadHudPage.xml
+++ b/config/gamePadHud/SiloLoaderGamePadHudPage.xml
@@ -5,5 +5,6 @@
-->
+
diff --git a/config/jobParameters/JobParameterSetup.xml b/config/jobParameters/JobParameterSetup.xml
index 4d7c917dc..ef081c84c 100644
--- a/config/jobParameters/JobParameterSetup.xml
+++ b/config/jobParameters/JobParameterSetup.xml
@@ -15,9 +15,9 @@
- 1
- 2
- 3
+ 1
+ 2
+ 3
4
5
diff --git a/scripts/ai/jobs/CpJobParameters.lua b/scripts/ai/jobs/CpJobParameters.lua
index 7f41b3964..39f871a82 100644
--- a/scripts/ai/jobs/CpJobParameters.lua
+++ b/scripts/ai/jobs/CpJobParameters.lua
@@ -137,6 +137,18 @@ function CpJobParameters:isSiloLoadingHudModeDisabled()
return self:isAIMenuJob()
end
+function CpJobParameters:isFieldWorkHudModeDisabled()
+ local vehicle = self.job:getVehicle()
+ if vehicle then
+ if (AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler) and
+ not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel)) or
+ AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) then
+ return true
+ end
+ end
+ return false
+end
+
--- Callback raised by a setting and executed as an vehicle event.
---@param callbackStr string event to be raised
---@param setting AIParameterSettingList setting that raised the callback.
diff --git a/scripts/gui/CpGamePadHudScreen.lua b/scripts/gui/CpGamePadHudScreen.lua
index f5950b3e9..836c11611 100644
--- a/scripts/gui/CpGamePadHudScreen.lua
+++ b/scripts/gui/CpGamePadHudScreen.lua
@@ -192,6 +192,9 @@ function CpGamePadHudFieldWorkScreen:update(dt, ...)
if self.vehicle:getCanStartCpBunkerSiloWorker() and self.vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
and not AIUtil.hasChildVehicleWithSpecialization(self.vehicle, Leveler) then
self.vehicle:reopenCpGamePadHud()
+ elseif self.vehicle:getCanStartCpSiloLoaderWorker() and self.vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING
+ and not AIUtil.hasChildVehicleWithSpecialization(self.vehicle, ConveyorBelt) then
+ self.vehicle:reopenCpGamePadHud()
end
end
diff --git a/scripts/gui/hud/CpBaseHud.lua b/scripts/gui/hud/CpBaseHud.lua
index ef3812608..5c1e2284b 100644
--- a/scripts/gui/hud/CpBaseHud.lua
+++ b/scripts/gui/hud/CpBaseHud.lua
@@ -427,8 +427,9 @@ function CpBaseHud:getActiveHudPage(vehicle)
elseif vehicle:getCanStartCpSiloLoaderWorker() and (vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING
or AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt)) then
return self.siloLoaderWorkerLayout
- elseif vehicle:getCanStartCpBunkerSiloWorker() and (vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
- or AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)) then
+ elseif vehicle:getCanStartCpBunkerSiloWorker() and (vehicle:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO or
+ (AIUtil.hasChildVehicleWithSpecialization(vehicle, Leveler)
+ and not AIUtil.hasChildVehicleWithSpecialization(vehicle, Shovel))) then
return self.bunkerSiloWorkerLayout
else
return self.fieldworkLayout
diff --git a/scripts/specializations/CpGamePadHud.lua b/scripts/specializations/CpGamePadHud.lua
index d608cf851..c9fdc8994 100644
--- a/scripts/specializations/CpGamePadHud.lua
+++ b/scripts/specializations/CpGamePadHud.lua
@@ -194,12 +194,13 @@ function CpGamePadHud:actionEventOpenCloseDisplay()
page = CpGamePadHud.UNLOADER_PAGE
elseif self:getCanStartCpBaleFinder() then
page = CpGamePadHud.BALE_LOADER_PAGE
- elseif self:getCanStartCpBunkerSiloWorker() and self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
- or AIUtil.hasChildVehicleWithSpecialization(self, Leveler) then
- page = CpGamePadHud.BUNKER_SILO_PAGE
- elseif self:getCanStartCpSiloLoaderWorker() and ( AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt)
- or self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING) then
+ elseif self:getCanStartCpSiloLoaderWorker() and (self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_SILO_LOADING or
+ AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt)) then
page = CpGamePadHud.SILO_LOADER_PAGE
+ elseif self:getCanStartCpBunkerSiloWorker() and (self:getCpStartingPointSetting():getValue() == CpJobParameters.START_AT_BUNKER_SILO
+ or (AIUtil.hasChildVehicleWithSpecialization(self, Leveler)
+ and not AIUtil.hasChildVehicleWithSpecialization(self, Shovel))) then
+ page = CpGamePadHud.BUNKER_SILO_PAGE
else
page = CpGamePadHud.FIELDWORK_PAGE
end
From 9c919201211cd72710e34f6df35d4cb16fc9071b Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 19:30:22 +0200
Subject: [PATCH 028/107] PR fixes
---
modDesc.xml | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/modDesc.xml b/modDesc.xml
index b0d9fc3e8..57a5b1f9a 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -343,16 +343,6 @@ Changelog 7.1.0.0:
-
-
-
-
-
-
-
-
-
-
From 7b52833b33b85490a7afc8d9f0359f6fe91d2a19 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 19:32:18 +0200
Subject: [PATCH 029/107] Rebase Fixes 2
---
modDesc.xml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/modDesc.xml b/modDesc.xml
index 57a5b1f9a..ecfa9d4d5 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -286,6 +286,13 @@ Changelog 7.1.0.0:
+
+
+
+
+
+
+
From f586bddb23bfc8c9f61eba08b0fc6d1a5a815278 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 20:07:49 +0200
Subject: [PATCH 030/107] Some more code improvements
TODO: Is the collision Strategy even needed ?
---
Courseplay.lua | 3 -
modDesc.xml | 1 -
scripts/ai/AIDriveStrategyCourse.lua | 4 +-
scripts/specializations/CpAIWorker.lua | 204 ++++++++++++++++---------
4 files changed, 130 insertions(+), 82 deletions(-)
diff --git a/Courseplay.lua b/Courseplay.lua
index 5622fef55..8f538ee57 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -326,9 +326,6 @@ function Courseplay.register(typeManager)
--- TODO: make this function async.
for typeName, typeEntry in pairs(typeManager.types) do
CpAIWorker.register(typeManager, typeName, typeEntry.specializations)
- if CourseplaySpec.prerequisitesPresent(typeEntry.specializations) then
- typeManager:addSpecialization(typeName, Courseplay.MOD_NAME .. ".courseplaySpec")
- end
CpVehicleSettings.register(typeManager, typeName, typeEntry.specializations)
CpCourseGeneratorSettings.register(typeManager, typeName, typeEntry.specializations)
CpCourseManager.register(typeManager, typeName, typeEntry.specializations)
diff --git a/modDesc.xml b/modDesc.xml
index ecfa9d4d5..3122d9935 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -418,7 +418,6 @@ Changelog 7.1.0.0:
-
diff --git a/scripts/ai/AIDriveStrategyCourse.lua b/scripts/ai/AIDriveStrategyCourse.lua
index 283a110fd..4396dcfe0 100644
--- a/scripts/ai/AIDriveStrategyCourse.lua
+++ b/scripts/ai/AIDriveStrategyCourse.lua
@@ -602,13 +602,13 @@ end
---------------------------------------------------------------------------------------------------------------------------
function AIDriveStrategyCourse:disableCollisionDetection()
if self.vehicle then
- CourseplaySpec.disableCollisionDetection(self.vehicle)
+ CpAIWorker.disableCollisionDetection(self.vehicle)
end
end
function AIDriveStrategyCourse:enableCollisionDetection()
if self.vehicle then
- CourseplaySpec.enableCollisionDetection(self.vehicle)
+ CpAIWorker.enableCollisionDetection(self.vehicle)
end
end
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 5b3ca1ca9..aa7ca137f 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -28,6 +28,9 @@ function CpAIWorker.register(typeManager, typeName, specializations)
end
function CpAIWorker.registerEvents(vehicleType)
+ SpecializationUtil.registerEvent(vehicleType, "onCpUnitChanged")
+ SpecializationUtil.registerEvent(vehicleType, "onCpDrawHudMap")
+
SpecializationUtil.registerEvent(vehicleType, "onCpFinished")
SpecializationUtil.registerEvent(vehicleType, "onCpEmpty")
SpecializationUtil.registerEvent(vehicleType, "onCpFull")
@@ -68,6 +71,7 @@ function CpAIWorker.registerFunctions(vehicleType)
SpecializationUtil.registerFunction(vehicleType, "cpHold", CpAIWorker.cpHold)
SpecializationUtil.registerFunction(vehicleType, "cpBrakeToStop", CpAIWorker.cpBrakeToStop)
SpecializationUtil.registerFunction(vehicleType, "getCpDriveStrategy", CpAIWorker.getCpDriveStrategy)
+ SpecializationUtil.registerFunction(vehicleType, 'getCpReverseDrivingDirectionNode', CpAIWorker.getCpReverseDrivingDirectionNode)
end
function CpAIWorker.registerOverwrittenFunctions(vehicleType)
@@ -75,9 +79,11 @@ function CpAIWorker.registerOverwrittenFunctions(vehicleType)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'getCanMotorRun', CpAIWorker.getCanMotorRun)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'stopFieldWorker', CpAIWorker.stopFieldWorker)
end
-------------------------------------------------------------------------------------------------------------------------
+
+---------------------------------------------------
--- Event listeners
----------------------------------------------------------------------------------------------------------------------------
+---------------------------------------------------
+
function CpAIWorker:onLoad(savegame)
--- Register the spec: spec_CpAIWorker
self.spec_cpAIWorker = self["spec_" .. CpAIWorker.SPEC_NAME]
@@ -85,6 +91,13 @@ function CpAIWorker:onLoad(savegame)
--- Flag to make sure the motor isn't being turned on again by giants code, when we want it turned off.
spec.motorDisabled = false
spec.driveStrategy = nil
+ g_messageCenter:subscribe(MessageType.SETTING_CHANGED[GameSettings.SETTING.USE_MILES], CpAIWorker.onUnitChanged, self)
+ g_messageCenter:subscribe(MessageType.SETTING_CHANGED[GameSettings.SETTING.USE_ACRE], CpAIWorker.onUnitChanged, self)
+ g_messageCenter:subscribe(MessageType.CP_DISTANCE_UNIT_CHANGED, CpAIWorker.onUnitChanged, self)
+end
+
+function CpAIWorker:onUnitChanged()
+ SpecializationUtil.raiseEvent(self,"onCpUnitChanged")
end
function CpAIWorker:onLoadFinished()
@@ -136,6 +149,14 @@ function CpAIWorker:onRegisterActionEvents(isActiveForInput, isActiveForInputIgn
end
end
+function CpAIWorker:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
+ CpAIWorker.updateActionEvents(self)
+end
+
+-----------------------------------------------
+--- Action input events
+-----------------------------------------------
+
--- Updates the action event visibility and text.
function CpAIWorker:updateActionEvents()
local spec = self.spec_cpAIWorker
@@ -173,72 +194,6 @@ function CpAIWorker:updateActionEvents()
end
end
-function CpAIWorker:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
- CpAIWorker.updateActionEvents(self)
-end
-
-
---- Used to enable/disable release of the helper
---- and handles post release functionality with for example auto drive.
---- TODO: This function is a mess and desperately needs a better solution!
-function CpAIWorker:stopCurrentAIJob(superFunc, message, ...)
- if message then
- CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, "stop message: %s", message:getMessage())
- else
- CpUtil.infoVehicle(self, "no stop message was given.")
- return superFunc(self, message, ...)
- end
- local releaseMessage, hasFinished, event, isOnlyShownOnPlayerStart = g_infoTextManager:getInfoTextDataByAIMessage(message)
-
- CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, "finished: %s, event: %s",
- tostring(hasFinished), tostring(event))
-
- local wasCpActive = self:getIsCpActive()
- if wasCpActive then
- local driveStrategy = self:getCpDriveStrategy()
- if driveStrategy then
- -- TODO: this isn't needed if we do not return a 0 < maxSpeed < 0.5, should either be exactly 0 or greater than 0.5
- local maxSpeed = driveStrategy and driveStrategy:getMaxSpeed()
- if message:isa(AIMessageErrorBlockedByObject) then
- if self.spec_aiFieldWorker.didNotMoveTimer and self.spec_aiFieldWorker.didNotMoveTimer < 0 then
- if maxSpeed and maxSpeed < 1 then
- -- disable the Giants timeout which dismisses the AI worker if it does not move for 5 seconds
- -- since we often stop for instance in convoy mode when waiting for another vehicle to turn
- -- (when we do this, we set our maxSpeed to 0). So we also check our maxSpeed, this way the Giants timer will
- -- fire if we are blocked (thus have a maxSpeed > 0 but not moving)
- CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, 'Overriding the Giants did not move timer, with speed: %.2f', maxSpeed)
- return
- else
- CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, 'Giants did not move timer triggered, with speed: %.2f!', maxSpeed)
- end
- end
- end
- driveStrategy:onFinished()
- end
- end
- self:resetCpAllActiveInfoTexts()
- --- Only add the info text, if it's available and nobody is in the vehicle.
- if not self:getIsControlled() and releaseMessage and not isOnlyShownOnPlayerStart then
- self:setCpInfoTextActive(releaseMessage)
- end
- superFunc(self, message,...)
- if wasCpActive then
- if event then
- SpecializationUtil.raiseEvent(self, event)
- end
- if hasFinished and self:getCpSettings().foldImplementAtEnd:getValue() then
- --- Folds implements at the end if the setting is active.
- self:prepareForAIDriving()
- end
-
- end
-end
-
-
------------------------------------------------
---- Action input events
------------------------------------------------
-
function CpAIWorker:changeStartingPoint()
local startingPointSetting = self:getCpStartingPointSetting()
startingPointSetting:setNextItem()
@@ -289,6 +244,10 @@ function CpAIWorker:cpStartStopDriver(isStartedByHud)
end
end
+-----------------------------------------------
+--- Status getter functions
+-----------------------------------------------
+
--- Is a cp worker active ?
--- Every cp job should be an instance of type CpAIJob.
function CpAIWorker:getIsCpActive()
@@ -297,23 +256,24 @@ end
--- Is cp drive to field work active
function CpAIWorker:getIsCpDriveToFieldWorkActive()
- return self:getIsCpActive() and self.driveToFieldWorkStartStrategy ~= nil
+ local spec = self.spec_cpAIWorker
+ return self:getIsCpActive() and spec.driveToTask ~=nil
end
--- Is a cp job ready to be started?
function CpAIWorker:getCanStartCp()
- return false
+ --- override
end
--- Gets the job to be started by the hud or the keybinding.
function CpAIWorker:getCpStartableJob()
-
+ --- override
end
--- Gets the additional action event start text,
--- for example the starting point.
function CpAIWorker:getCpStartText()
- return ""
+ --- override
end
--- Makes sure giants isn't turning the motor back on, when we have turned it off.
@@ -324,6 +284,64 @@ function CpAIWorker:getCanMotorRun(superFunc, ...)
return superFunc(self, ...)
end
+-----------------------------------------------
+--- Strategy handling
+-----------------------------------------------
+
+
+--- Used to enable/disable release of the helper
+--- and handles post release functionality with for example auto drive.
+function CpAIWorker:stopCurrentAIJob(superFunc, message, ...)
+ if message then
+ CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, "stop message: %s", message:getMessage())
+ else
+ CpUtil.infoVehicle(self, "no stop message was given.")
+ return superFunc(self, message, ...)
+ end
+ local releaseMessage, hasFinished, event, isOnlyShownOnPlayerStart = g_infoTextManager:getInfoTextDataByAIMessage(message)
+
+ CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, "finished: %s, event: %s",
+ tostring(hasFinished), tostring(event))
+ local wasCpActive = self:getIsCpActive()
+ if wasCpActive then
+ local driveStrategy = self:getCpDriveStrategy()
+ if driveStrategy then
+ -- TODO: this isn't needed if we do not return a 0 < maxSpeed < 0.5, should either be exactly 0 or greater than 0.5
+ local maxSpeed = driveStrategy and driveStrategy:getMaxSpeed()
+ if message:isa(AIMessageErrorBlockedByObject) then
+ if self.spec_aiFieldWorker.didNotMoveTimer and self.spec_aiFieldWorker.didNotMoveTimer < 0 then
+ if maxSpeed and maxSpeed < 1 then
+ -- disable the Giants timeout which dismisses the AI worker if it does not move for 5 seconds
+ -- since we often stop for instance in convoy mode when waiting for another vehicle to turn
+ -- (when we do this, we set our maxSpeed to 0). So we also check our maxSpeed, this way the Giants timer will
+ -- fire if we are blocked (thus have a maxSpeed > 0 but not moving)
+ CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, 'Overriding the Giants did not move timer, with speed: %.2f', maxSpeed)
+ return
+ else
+ CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, 'Giants did not move timer triggered, with speed: %.2f!', maxSpeed)
+ end
+ end
+ end
+ driveStrategy:onFinished()
+ end
+ end
+ self:resetCpAllActiveInfoTexts()
+ --- Only add the info text, if it's available and nobody is in the vehicle.
+ if not self:getIsControlled() and releaseMessage and not isOnlyShownOnPlayerStart then
+ self:setCpInfoTextActive(releaseMessage)
+ end
+ superFunc(self, message,...)
+ if wasCpActive then
+ if event then
+ SpecializationUtil.raiseEvent(self, event)
+ end
+ if hasFinished and self:getCpSettings().foldImplementAtEnd:getValue() then
+ --- Folds implements at the end if the setting is active.
+ self:prepareForAIDriving()
+ end
+ end
+end
+
function CpAIWorker:startCpDriveTo(task, jobParameters)
local spec = self.spec_cpAIWorker
spec.driveToTask = task
@@ -452,12 +470,10 @@ function CpAIWorker:stopCpDriver()
--- Reset the flag.
local spec = self.spec_cpAIWorker
spec.motorDisabled = false
-
if spec.driveStrategy then
spec.driveStrategy:delete()
spec.driveStrategy = nil
end
-
if self.isServer then
WheelsUtil.updateWheelsPhysics(self, 0, 0, 0, true, true)
end
@@ -472,9 +488,7 @@ function CpAIWorker:stopCpDriver()
if actionController ~= nil then
actionController:resetCurrentState()
end
-
self:raiseAIEvent("onAIFieldWorkerEnd", "onAIImplementEnd")
-
end
function CpAIWorker:getCpDriveStrategy()
@@ -482,6 +496,44 @@ function CpAIWorker:getCpDriveStrategy()
return spec.driveStrategy
end
+function CpAIWorker:getCpReverseDrivingDirectionNode()
+ local spec = self.spec_cpAIWorker
+ if not spec.reverseDrivingDirectionNode and SpecializationUtil.hasSpecialization(ReverseDriving, self.specializations) then
+ spec.reverseDrivingDirectionNode =
+ CpUtil.createNewLinkedNode(self, "realReverseDrivingDirectionNode", self:getAIDirectionNode())
+ setRotation(spec.reverseDrivingDirectionNode, 0, math.pi, 0)
+ end
+ return spec.reverseDrivingDirectionNode
+end
+
+--- TODO: Do we really need the AIDriveStrategyCollision from giants, as this one is only active for fieldwork?
+function CpAIWorker:isCollisionDetectionEnabled()
+ local spec = self.spec_cpAIWorker
+ return spec.collisionDetectionEnabled
+end
+
+function CpAIWorker:enableCollisionDetection()
+ local spec = self.spec_cpAIWorker
+ spec.collisionDetectionEnabled = true
+end
+
+function CpAIWorker:disableCollisionDetection()
+ local spec = self.spec_cpAIWorker
+ spec.collisionDetectionEnabled = false
+end
+
+function CpAIWorker:getCollisionCheckActive(superFunc,...)
+ local spec = self.spec_cpAIWorker
+ if spec.collisionDetectionEnabled then
+ return superFunc(self,...)
+ else
+ return false
+ end
+end
+AIDriveStrategyCollision.getCollisionCheckActive = Utils.overwrittenFunction(
+ AIDriveStrategyCollision.getCollisionCheckActive, CpAIWorker.getCollisionCheckActive
+)
+
function CpAIWorker:stopFieldWorker(superFunc, ...)
--- Reset the flag.
self.spec_cpAIWorker.motorDisabled = false
From bf8f6ad0c83c712148b7f4eefc976ec2214eb431 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 20:23:43 +0200
Subject: [PATCH 031/107] Small delete bug fix
---
scripts/ai/Markers.lua | 2 +-
scripts/specializations/CpAIWorker.lua | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/scripts/ai/Markers.lua b/scripts/ai/Markers.lua
index 764d04301..e0674a111 100644
--- a/scripts/ai/Markers.lua
+++ b/scripts/ai/Markers.lua
@@ -119,4 +119,4 @@ function Markers.getMarkerNodes(vehicle)
local frontMarker = Markers.getFrontMarkerNode(vehicle)
local backMarker = Markers.getBackMarkerNode(vehicle)
return frontMarker, backMarker, g_vehicleMarkers[vehicle].frontMarkerOffset, g_vehicleMarkers[vehicle].backMarkerOffset
-end
+end
\ No newline at end of file
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index aa7ca137f..95a27b95c 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -48,6 +48,7 @@ function CpAIWorker.registerEventListeners(vehicleType)
SpecializationUtil.registerEventListener(vehicleType, "onUpdate", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", CpAIWorker)
+ SpecializationUtil.registerEventListener(vehicleType, "onPreDelete", CpAIWorker)
--- Autodrive events
SpecializationUtil.registerEventListener(vehicleType, "onStopAutoDrive", CpAIWorker)
SpecializationUtil.registerEventListener(vehicleType, "onStartAutoDrive", CpAIWorker)
@@ -153,6 +154,10 @@ function CpAIWorker:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSel
CpAIWorker.updateActionEvents(self)
end
+function CpAIWorker:onPreDelete()
+
+end
+
-----------------------------------------------
--- Action input events
-----------------------------------------------
From 10173cafe3712c237d899b6f153e479f378c843b Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 20:34:05 +0200
Subject: [PATCH 032/107] fix
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index de270f980..921ddfcbd 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -53,7 +53,7 @@ AIDriveStrategyShovelSiloLoader.safeSpaceToTrailer = 5
AIDriveStrategyShovelSiloLoader.maxValidTrailerDistanceToSiloFront = 30
AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 15
AIDriveStrategyShovelSiloLoader.distShovelTrailerPreUnload = 7
-AIDriveStrategyShovelSiloLoader.distShovelUnloadStationPreUnload = 7
+AIDriveStrategyShovelSiloLoader.distShovelUnloadStationPreUnload = 8
function AIDriveStrategyShovelSiloLoader.new(customMt)
if customMt == nil then
@@ -114,7 +114,7 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
local position = jobParameters.unloadPosition
local dirX, dirZ = position:getDirection()
setDirection(self.unloadPositionNode, dirX, 0, dirZ, 0, 0, 1)
- local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -math.max(self.distShovelTrailerPreUnload, self.turningRadius))
+ local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -math.max(self.distShovelUnloadStationPreUnload, self.turningRadius))
setTranslation(self.unloadPositionNode, dx, dy, dz)
else
self:debug("Starting shovel silo to unload into trailer.")
From a412157db47f4a5c130a7041af7ef8e5164b4517 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 20:49:40 +0200
Subject: [PATCH 033/107] Might improve trigger unload
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 13 ++-----------
scripts/ai/controllers/ShovelController.lua | 8 +++++++-
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 921ddfcbd..b824b3dae 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -49,9 +49,8 @@ AIDriveStrategyShovelSiloLoader.myStates = {
REVERSING_AWAY_FROM_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
}
-AIDriveStrategyShovelSiloLoader.safeSpaceToTrailer = 5
AIDriveStrategyShovelSiloLoader.maxValidTrailerDistanceToSiloFront = 30
-AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 15
+AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 30
AIDriveStrategyShovelSiloLoader.distShovelTrailerPreUnload = 7
AIDriveStrategyShovelSiloLoader.distShovelUnloadStationPreUnload = 8
@@ -161,11 +160,8 @@ function AIDriveStrategyShovelSiloLoader:setAllStaticParameters()
self.proximityController = ProximityController(self.vehicle, self:getWorkWidth())
self.proximityController:registerIgnoreObjectCallback(self, self.ignoreProximityObject)
self:setFrontAndBackMarkers()
-
self.siloEndProximitySensor = SingleForwardLookingProximitySensorPack(self.vehicle, self.shovelController:getShovelNode(), 5, 1)
-
self.heapNode = CpUtil.createNode("heapNode", 0, 0, 0, nil)
-
self.lastTrailerSearch = 0
end
@@ -206,11 +202,8 @@ end
--- implements are started/lowered etc.
function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:updateLowFrequencyImplementControllers()
-
local moveForwards = not self.ppc:isReversing()
local gx, gz, _
-
- ----------------------------------------------------------------
if not moveForwards then
local maxSpeed
gx, gz, maxSpeed = self:getReverseDriveData()
@@ -280,12 +273,11 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:setMaxSpeed(0)
end
if not self.isUnloadingAtTrailerActive then
- if self.shovelController:isShovelOverTrailer(refNode, 3) and self.shovelController:canDischarge() then
+ if self.shovelController:isShovelOverTrailer(refNode, 3) and self.shovelController:canDischarge(self.unloadTrigger) then
self:setNewState(self.states.UNLOADING)
self:setMaxSpeed(0)
end
end
-
elseif self.state == self.states.UNLOADING then
self:setMaxSpeed(0)
if self:hasFinishedUnloading() then
@@ -301,7 +293,6 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
end
end
end
-
self:limitSpeed()
return gx, gz, moveForwards, self.maxSpeed, 100
end
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 47b2e73e1..f9de73a72 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -57,7 +57,10 @@ function ShovelController:getDischargeNode()
return self.implement:getCurrentDischargeNode()
end
-function ShovelController:canDischarge()
+--- Checks if the shovel raycast has found an unload target.
+---@param targetTrigger any
+---@return boolean
+function ShovelController:canDischarge(targetTrigger)
local dischargeNode = self:getDischargeNode()
local spec = self.implement.spec_dischargeable
if not spec.isAsyncRaycastActive then
@@ -66,6 +69,9 @@ function ShovelController:canDischarge()
self.implement:updateRaycast(dischargeNode)
dischargeNode.raycast.node = oldNode
end
+ if targetTrigger and targetTrigger ~= self.implement:getDischargeTargetObject(dischargeNode) then
+ return false
+ end
return dischargeNode.dischargeHit
end
From b47776c47bb74a97bd5b511ae29f3e0b6b9bc57d Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 12 Jul 2023 20:53:09 +0200
Subject: [PATCH 034/107] Minor Adjustment
---
scripts/ai/controllers/ShovelController.lua | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index f9de73a72..1fae21c4c 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -58,7 +58,7 @@ function ShovelController:getDischargeNode()
end
--- Checks if the shovel raycast has found an unload target.
----@param targetTrigger any
+---@param targetTrigger CpTrigger|nil
---@return boolean
function ShovelController:canDischarge(targetTrigger)
local dischargeNode = self:getDischargeNode()
@@ -69,7 +69,7 @@ function ShovelController:canDischarge(targetTrigger)
self.implement:updateRaycast(dischargeNode)
dischargeNode.raycast.node = oldNode
end
- if targetTrigger and targetTrigger ~= self.implement:getDischargeTargetObject(dischargeNode) then
+ if targetTrigger and targetTrigger:getTrigger() ~= self.implement:getDischargeTargetObject(dischargeNode) then
return false
end
return dischargeNode.dischargeHit
From 67856d9423653a6f6be93bfdd802e329b621ab47 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 13 Jul 2023 16:03:09 +0200
Subject: [PATCH 035/107] Added loading position offset setting with vehicle
configuration.
Added a setting to control the height of the loading shovel position, similar to the xOffset in the fieldwork mode.
---
config/MasterTranslations.xml | 8 +++++++
config/VehicleConfigurations.xml | 3 +++
config/VehicleSettingsSetup.xml | 1 +
.../gamePadHud/SiloLoaderGamePadHudPage.xml | 1 +
scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua | 7 ++++++
scripts/specializations/CpShovelPositions.lua | 23 ++++++++++++++-----
scripts/specializations/CpVehicleSettings.lua | 9 +++++++-
7 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index 518eaa41e..fba7fcaaa 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -613,6 +613,14 @@
+
+
+
+
+
+
+
+
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index 778c285c4..274ab95f1 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -97,6 +97,9 @@ You can define the following custom settings:
Overrides the automatic selection of a moving tool for example for the shield controller of a snowcat.
Used to control the target tilt.
+- loadingShovelOffset: number -1 : 1
+ Offset relative to the calculated loading shovel position, needs to be set for a shovel implement.
+
- shovelMovingToolIx: number
If the shovel is a high dump shovel then this moving tool ix is needed.
diff --git a/config/VehicleSettingsSetup.xml b/config/VehicleSettingsSetup.xml
index aeb5cb720..c4f5e46ee 100644
--- a/config/VehicleSettingsSetup.xml
+++ b/config/VehicleSettingsSetup.xml
@@ -76,6 +76,7 @@
+
diff --git a/config/gamePadHud/SiloLoaderGamePadHudPage.xml b/config/gamePadHud/SiloLoaderGamePadHudPage.xml
index 0969a7251..34fc6f86f 100644
--- a/config/gamePadHud/SiloLoaderGamePadHudPage.xml
+++ b/config/gamePadHud/SiloLoaderGamePadHudPage.xml
@@ -7,4 +7,5 @@
+
diff --git a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
index 6382aae28..4e840ff02 100644
--- a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
+++ b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
@@ -43,6 +43,9 @@ function CpSiloLoaderWorkerHudPageElement:setupElements(baseHud, vehicle, lines,
local x, y = unpack(lines[4].right)
self.fillLevelProgressText = CpTextHudElement.new(self, x, y, CpBaseHud.defaultFontSize, RenderText.ALIGN_RIGHT)
+ --- Shovel loading height offset.
+ self.loadingShovelHeightOffsetBtn = baseHud:addLineTextButton(self, 2, CpBaseHud.defaultFontSize,
+ vehicle:getCpSettings().loadingShovelHeightOffset)
CpGuiUtil.addCopyAndPasteButtons(self, baseHud,
vehicle, lines, wMargin, hMargin, 1)
@@ -85,6 +88,10 @@ function CpSiloLoaderWorkerHudPageElement:updateContent(vehicle, status)
self.workWidthBtn:setTextDetails(workWidth:getTitle(), workWidth:getString())
self.workWidthBtn:setVisible(workWidth:getIsVisible())
+ local loadingHeightOffset = vehicle:getCpSettings().loadingShovelHeightOffset
+ self.loadingShovelHeightOffsetBtn:setTextDetails(loadingHeightOffset:getTitle(), loadingHeightOffset:getString())
+ self.loadingShovelHeightOffsetBtn:setVisible(loadingHeightOffset:getIsVisible())
+
self.fillLevelProgressText:setTextDetails(status:getSiloFillLevelPercentageLeftOver())
--- Update copy and paste buttons
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index a24785177..f0eef4cdb 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -170,7 +170,7 @@ end
function CpShovelPositions:onUpdateTick(dt)
local spec = self.spec_cpShovelPositions
- if spec.shovelToolIx == nil or spec.armToolIx == nil then
+ if spec.shovelToolIx == nil or spec.armToolIx == nil or self.rootVehicle == nil then
return
end
if spec.state == CpShovelPositions.LOADING then
@@ -248,8 +248,9 @@ end
---@param shovelLimits table
---@param armLimits table
---@param useHighDumpShovel boolean|nil
+---@param heightOffset number|nil
---@return boolean|nil
-function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHighDumpShovel)
+function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHighDumpShovel, heightOffset)
local min, max = unpack(shovelLimits)
--- Target angle of the shovel node, which is at the end of the shovel.
local targetAngle = math.rad(min) + math.rad(max - min)/2
@@ -279,7 +280,8 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
local attacherJointNode = self.spec_attachable.attacherJoint.node
local angle, shovelNode = CpShovelPositions.getShovelData(self)
local _, shovelY, _ = localToLocal(self.rootNode, attacherJointNode, 0, 0, 0)
-
+ heightOffset = heightOffset or 0
+
--- local tempNode = createTransformGroup("tempVehicleSizeCenter")
-- link(vehicle.rootNode, tempNode)
-- setTranslation(tempNode, vehicle.size.widthOffset, vehicle.size.heightOffset + vehicle.size.height / 2, vehicle.size.lengthOffset)
@@ -291,14 +293,20 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
local _, ty, tz = localToLocal(getChildAt(armTool.node, 0), armVehicle.rootNode, 0, 0, 0)
local ax, ay, az = localToLocal(armTool.node, armVehicle.rootNode, 0, 0, 0)
- local sx, sy, sz = 0, targetHeight - shovelY - self.size.heightOffset, 0
- local ex, ey, ez = 0, targetHeight - shovelY - self.size.heightOffset, 20
+ local sx, sy, sz = 0, targetHeight - shovelY - self.size.heightOffset + heightOffset, 0
+ local ex, ey, ez = 0, targetHeight - shovelY - self.size.heightOffset + heightOffset, 20
local yMax = ay + radiusArmToolToShovelTool
+ local yMin = ay - radiusArmToolToShovelTool
if sy > yMax then
--- Makes sure the target height is still reachable
sy = yMax - 0.01
ey = yMax - 0.01
end
+ if sy < yMin then
+ --- Makes sure the target height is still reachable
+ sy = yMin + 0.01
+ ey = yMin + 0.01
+ end
local hasIntersection, i1z, i1y, i2z, i2y = MathUtil.getCircleLineIntersection(az, ay, radiusArmToolToShovelTool,
sz, sy, ez, ey)
@@ -387,10 +395,13 @@ end
function CpShovelPositions:updateLoadingPosition(dt)
local spec = self.spec_cpShovelPositions
local angle = CpShovelPositions.getShovelData(self)
+ local heightOffset = self.rootVehicle.getCpSettings and self.rootVehicle:getCpSettings().loadingShovelHeightOffset:getValue()
local isDirty
if angle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
- CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS, CpShovelPositions.LOADING_POSITION.ARM_LIMITS)
+ CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS,
+ CpShovelPositions.LOADING_POSITION.ARM_LIMITS,
+ nil, heightOffset)
end
spec.isDirty = isDirty
end
diff --git a/scripts/specializations/CpVehicleSettings.lua b/scripts/specializations/CpVehicleSettings.lua
index 6a6b1616d..e1b321eb3 100644
--- a/scripts/specializations/CpVehicleSettings.lua
+++ b/scripts/specializations/CpVehicleSettings.lua
@@ -120,6 +120,9 @@ function CpVehicleSettings:onStateChange(state, data)
spec.lowerImplementEarly, 'lowerEarly')
CpVehicleSettings.setFromVehicleConfiguration(self, data.attachedVehicle,
spec.bunkerSiloWorkWidth, 'workingWidth')
+ CpVehicleSettings.setFromVehicleConfiguration(self, data.attachedVehicle,
+ spec.loadingShovelHeightOffset, 'loadingShovelOffset')
+
CpVehicleSettings.validateSettings(self)
elseif state == Vehicle.STATE_CHANGE_DETACH then
CpVehicleSettings.setAutomaticWorkWidthAndOffset(self, data.attachedVehicle)
@@ -362,7 +365,7 @@ function CpVehicleSettings:areCourseSettingsVisible()
end
function CpVehicleSettings:areBunkerSiloSettingsVisible()
- return self:getCanStartCpBunkerSiloWorker()
+ return self:getCanStartCpBunkerSiloWorker() or self:getCanStartCpSiloLoaderWorker()
end
function CpVehicleSettings:areCombineUnloaderSettingsVisible()
@@ -387,6 +390,10 @@ function CpVehicleSettings:setAutomaticBaleCollectorOffset()
spec.baleCollectorOffset:setFloatValue(offset)
end
+function CpVehicleSettings:isLoadingShovelOffsetSettingVisible()
+ return self:getCanStartCpSiloLoaderWorker() and not AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt)
+end
+
--- Saves the user value changed on the server.
function CpVehicleSettings:onCpUserSettingChanged(setting)
if not self.isServer then
From 76881f4d0f7a84c2144d6ed3e9b94658da3e4fc3 Mon Sep 17 00:00:00 2001
From: schwiti6190
Date: Thu, 13 Jul 2023 14:03:33 +0000
Subject: [PATCH 036/107] Updated translations
---
translations/translation_br.xml | 2 ++
translations/translation_cs.xml | 2 ++
translations/translation_ct.xml | 2 ++
translations/translation_cz.xml | 2 ++
translations/translation_da.xml | 2 ++
translations/translation_de.xml | 2 ++
translations/translation_ea.xml | 2 ++
translations/translation_en.xml | 2 ++
translations/translation_es.xml | 2 ++
translations/translation_fc.xml | 2 ++
translations/translation_fi.xml | 2 ++
translations/translation_fr.xml | 2 ++
translations/translation_hu.xml | 2 ++
translations/translation_it.xml | 2 ++
translations/translation_jp.xml | 2 ++
translations/translation_kr.xml | 2 ++
translations/translation_nl.xml | 2 ++
translations/translation_no.xml | 2 ++
translations/translation_pl.xml | 2 ++
translations/translation_pt.xml | 2 ++
translations/translation_ro.xml | 2 ++
translations/translation_ru.xml | 2 ++
translations/translation_sv.xml | 2 ++
translations/translation_tr.xml | 2 ++
24 files changed, 48 insertions(+)
diff --git a/translations/translation_br.xml b/translations/translation_br.xml
index b4e68c90f..be6bef151 100644
--- a/translations/translation_br.xml
+++ b/translations/translation_br.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_cs.xml b/translations/translation_cs.xml
index 37d34c151..6610bdefa 100644
--- a/translations/translation_cs.xml
+++ b/translations/translation_cs.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_ct.xml b/translations/translation_ct.xml
index 29f9b8820..a3a918d83 100644
--- a/translations/translation_ct.xml
+++ b/translations/translation_ct.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml
index e5bfe8b43..7fef8dbae 100644
--- a/translations/translation_cz.xml
+++ b/translations/translation_cz.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_da.xml b/translations/translation_da.xml
index 71b70cb3e..c00a87de7 100644
--- a/translations/translation_da.xml
+++ b/translations/translation_da.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 6893d93a0..086fd4f34 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_ea.xml b/translations/translation_ea.xml
index 487297825..2762891d8 100644
--- a/translations/translation_ea.xml
+++ b/translations/translation_ea.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 454e60989..8984a854f 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_es.xml b/translations/translation_es.xml
index d9278b066..f738f12bd 100644
--- a/translations/translation_es.xml
+++ b/translations/translation_es.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_fc.xml b/translations/translation_fc.xml
index 1e82fa96b..910fff456 100644
--- a/translations/translation_fc.xml
+++ b/translations/translation_fc.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_fi.xml b/translations/translation_fi.xml
index 15f07d006..215325630 100644
--- a/translations/translation_fi.xml
+++ b/translations/translation_fi.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_fr.xml b/translations/translation_fr.xml
index b7aca1aa1..29b037550 100644
--- a/translations/translation_fr.xml
+++ b/translations/translation_fr.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index 7e9e1e8a0..5c0a73d12 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_it.xml b/translations/translation_it.xml
index bb65ac788..947fe7e9a 100644
--- a/translations/translation_it.xml
+++ b/translations/translation_it.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_jp.xml b/translations/translation_jp.xml
index 32edfee7c..f73714129 100644
--- a/translations/translation_jp.xml
+++ b/translations/translation_jp.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_kr.xml b/translations/translation_kr.xml
index 75bb4f709..12cbcccc5 100644
--- a/translations/translation_kr.xml
+++ b/translations/translation_kr.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_nl.xml b/translations/translation_nl.xml
index 89bb6efb2..69089d31a 100644
--- a/translations/translation_nl.xml
+++ b/translations/translation_nl.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_no.xml b/translations/translation_no.xml
index 4491229ea..80f1b0d33 100644
--- a/translations/translation_no.xml
+++ b/translations/translation_no.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_pl.xml b/translations/translation_pl.xml
index fdf218218..264d59ebb 100644
--- a/translations/translation_pl.xml
+++ b/translations/translation_pl.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_pt.xml b/translations/translation_pt.xml
index 44394a95f..c62f0264d 100644
--- a/translations/translation_pt.xml
+++ b/translations/translation_pt.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_ro.xml b/translations/translation_ro.xml
index 0cbfb5ef2..e56c21353 100644
--- a/translations/translation_ro.xml
+++ b/translations/translation_ro.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_ru.xml b/translations/translation_ru.xml
index 6b842b5d0..af5aa6612 100644
--- a/translations/translation_ru.xml
+++ b/translations/translation_ru.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_sv.xml b/translations/translation_sv.xml
index 4f125e18a..a3b8d6baa 100644
--- a/translations/translation_sv.xml
+++ b/translations/translation_sv.xml
@@ -181,6 +181,8 @@
+
+
diff --git a/translations/translation_tr.xml b/translations/translation_tr.xml
index c2b85d87c..574be7dff 100644
--- a/translations/translation_tr.xml
+++ b/translations/translation_tr.xml
@@ -181,6 +181,8 @@
+
+
From 4f5143f6b297d8ccf655d40c9414bdf9594c7c35 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 13 Jul 2023 19:51:54 +0200
Subject: [PATCH 037/107] Open shovels, which need to be opened and apply
height offset also for Transport position
---
scripts/specializations/CpShovelPositions.lua | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index f0eef4cdb..eaca48dc9 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -331,9 +331,19 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
local _, dy, _ = localDirectionToWorld(getParent(tool.node), 0, 0, 1)
angle = math.acos(dy)
targetAngle = math.pi/2 - math.pi/8
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt, tool.rotMax) or isDirty
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
else
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt, tool.rotMin) or isDirty
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMax or tool.rotMin) or isDirty
+ end
+ else
+ for i, tool in pairs(self.spec_cylindered.movingTools) do
+ if tool.axis then
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
+ break
+ end
end
end
local deltaAngle = targetAngle - angle
@@ -409,10 +419,13 @@ end
function CpShovelPositions:updateTransportPosition(dt)
local spec = self.spec_cpShovelPositions
local angle = CpShovelPositions.getShovelData(self)
+ local heightOffset = self.rootVehicle.getCpSettings and self.rootVehicle:getCpSettings().loadingShovelHeightOffset:getValue()
local isDirty
if angle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
- CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS, CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS)
+ CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS,
+ CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS,
+ nil, heightOffset)
end
spec.isDirty = isDirty
end
From b54bb53330d7e2f92c1db5c1525ad74ee1a990d3 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 14 Jul 2023 08:27:04 +0200
Subject: [PATCH 038/107] Makes map hotspots invisible, while picking an unload
trigger.
---
scripts/gui/CpAIFrameExtended.lua | 59 +++++++++++++++++++------------
scripts/gui/CpGuiUtil.lua | 19 ++++++++++
2 files changed, 56 insertions(+), 22 deletions(-)
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index 3737974d1..55490b208 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -16,17 +16,31 @@ CpInGameMenuAIFrameExtended.DELAY = 1
CpInGameMenuAIFrameExtended.hotspotFilterState = {}
CpInGameMenuAIFrameExtended.validCustomFieldCreationHotspots = {
--- Hotspots visible, while drawing a custom field border.
- MapHotspot.CATEGORY_FIELD,
--- MapHotspot.CATEGORY_UNLOADING,
--- MapHotspot.CATEGORY_LOADING,
--- MapHotspot.CATEGORY_PRODUCTION,
- MapHotspot.CATEGORY_AI,
- MapHotspot.CATEGORY_COMBINE,
- MapHotspot.CATEGORY_STEERABLE,
- MapHotspot.CATEGORY_PLAYER,
--- MapHotspot.CATEGORY_SHOP,
--- MapHotspot.CATEGORY_OTHER
- CustomFieldHotspot.CATEGORY
+ [MapHotspot.CATEGORY_FIELD] = true,
+-- [MapHotspot.CATEGORY_UNLOADING] = true,
+-- [MapHotspot.CATEGORY_LOADING] = true,
+-- [MapHotspot.CATEGORY_PRODUCTION] = true,
+ [MapHotspot.CATEGORY_AI] = true,
+ [MapHotspot.CATEGORY_COMBINE] = true,
+ [MapHotspot.CATEGORY_STEERABLE] = true,
+ [MapHotspot.CATEGORY_PLAYER] = true,
+-- MapHotspot.CATEGORY_SHOP] = true,
+-- MapHotspot.CATEGORY_OTHER] = true,
+ [CustomFieldHotspot.CATEGORY] = true
+}
+
+CpInGameMenuAIFrameExtended.validPickingLoadingPositionHotspots = {
+ --- Hotspots visible, while picking a loading position.
+ [MapHotspot.CATEGORY_FIELD] = true,
+-- [MapHotspot.CATEGORY_UNLOADING] = true,
+-- [MapHotspot.CATEGORY_LOADING] = true,
+-- [MapHotspot.CATEGORY_PRODUCTION] = true,
+ [MapHotspot.CATEGORY_AI] = true,
+ [MapHotspot.CATEGORY_COMBINE] = true,
+ [MapHotspot.CATEGORY_STEERABLE] = true,
+ [MapHotspot.CATEGORY_PLAYER] = true,
+-- MapHotspot.CATEGORY_SHOP] = true,
+-- MapHotspot.CATEGORY_OTHER] = true,
}
function CpInGameMenuAIFrameExtended:onAIFrameLoadMapFinished()
@@ -538,6 +552,9 @@ function CpInGameMenuAIFrameExtended:startPickingPosition(superFunc, parameter,
elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD then
self.aiTargetMapHotspot = self.unloadAiTargetMapHotspot
self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.UNLOAD
+ CpInGameMenuAIFrameExtended.hotspotFilterState = {}
+ CpGuiUtil.saveAndDisableHotspotFilters(self.ingameMapBase, CpInGameMenuAIFrameExtended.hotspotFilterState)
+ CpGuiUtil.applyHotspotFilters(self.ingameMapBase, CpInGameMenuAIFrameExtended.validPickingLoadingPositionHotspots)
elseif parameter:getPositionType() == CpAIParameterPositionAngle.POSITION_TYPES.LOAD then
self.aiTargetMapHotspot = self.loadAiTargetMapHotspot
self.currentPickingMapHotspotType = CpAIParameterPositionAngle.POSITION_TYPES.LOAD
@@ -559,6 +576,10 @@ InGameMenuAIFrame.startPickPositionAndRotation = Utils.overwrittenFunction(InGam
function CpInGameMenuAIFrameExtended:resetHotspots()
self.aiTargetMapHotspot = self.rawAiTargetMapHotspot
self.currentPickingMapHotspotType = nil
+ if CpInGameMenuAIFrameExtended.hotspotFilterState then
+ CpGuiUtil.applyHotspotFilters(self.ingameMapBase, CpInGameMenuAIFrameExtended.hotspotFilterState)
+ end
+ CpInGameMenuAIFrameExtended.hotspotFilterState = nil
end
--- Added support for the cp field target position.
@@ -721,24 +742,18 @@ function InGameMenuAIFrame:onClickCreateFieldBorder()
g_customFieldManager:addField(CpInGameMenuAIFrameExtended.curDrawPositions)
CpInGameMenuAIFrameExtended.curDrawPositions = {}
--- Restore hotspot filters here:
- for k, v in pairs(self.ingameMapBase.filter) do
- self.ingameMapBase:setHotspotFilter(k, CpInGameMenuAIFrameExtended.hotspotFilterState[k])
+ if CpInGameMenuAIFrameExtended.hotspotFilterState then
+ CpGuiUtil.applyHotspotFilters(self.ingameMapBase, CpInGameMenuAIFrameExtended.hotspotFilterState)
end
-
+ CpInGameMenuAIFrameExtended.hotspotFilterState = nil
else
CpInGameMenuAIFrameExtended.curDrawPositions = {}
self.drawingCustomFieldHeader:setVisible(true)
self.mode = CpInGameMenuAIFrameExtended.MODE_DRAW_FIELD_BORDER
CpInGameMenuAIFrameExtended.hotspotFilterState = {}
--- Change the hotspot filter here:
- for k, v in pairs(self.ingameMapBase.filter) do
- CpInGameMenuAIFrameExtended.hotspotFilterState[k] = v
-
- self.ingameMapBase:setHotspotFilter(k, false)
- end
- for _,v in ipairs(CpInGameMenuAIFrameExtended.validCustomFieldCreationHotspots) do
- self.ingameMapBase:setHotspotFilter(v, true)
- end
+ CpGuiUtil.saveAndDisableHotspotFilters(self.ingameMapBase, CpInGameMenuAIFrameExtended.hotspotFilterState)
+ CpGuiUtil.applyHotspotFilters(self.ingameMapBase, CpInGameMenuAIFrameExtended.validCustomFieldCreationHotspots)
end
end
diff --git a/scripts/gui/CpGuiUtil.lua b/scripts/gui/CpGuiUtil.lua
index 7922faf61..7d920a159 100644
--- a/scripts/gui/CpGuiUtil.lua
+++ b/scripts/gui/CpGuiUtil.lua
@@ -214,6 +214,25 @@ function CpGuiUtil.setTarget(element, target)
element.targetName = target.name
end
+--- Apply the defined filter to the map.
+---@param map table ingame menu map
+---@param hotspots table
+function CpGuiUtil.applyHotspotFilters(map, hotspots)
+ for k, v in pairs(hotspots) do
+ map:setHotspotFilter(k, v)
+ end
+end
+
+--- Saves the hotspot filters and disables these on the map.
+---@param map table
+---@param hotspots table
+function CpGuiUtil.saveAndDisableHotspotFilters(map, hotspots)
+ for k, v in pairs(map.filter) do
+ map:setHotspotFilter(k, false)
+ hotspots[k] = v
+ end
+end
+
------------------------------------------------
--- Plots
------------------------------------------------
From 010520dae246b70f56090518b3fd6a85f0c76f8d Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 14 Jul 2023 16:12:35 +0200
Subject: [PATCH 039/107] minior bug fix
---
scripts/ai/AIDriveStrategyCourse.lua | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyCourse.lua b/scripts/ai/AIDriveStrategyCourse.lua
index 4396dcfe0..6012b541d 100644
--- a/scripts/ai/AIDriveStrategyCourse.lua
+++ b/scripts/ai/AIDriveStrategyCourse.lua
@@ -111,8 +111,7 @@ function AIDriveStrategyCourse:setAIVehicle(vehicle, jobParameters)
self:initializeImplementControllers(vehicle)
self.ppc = PurePursuitController(vehicle)
self.ppc:registerListeners(self, 'onWaypointPassed', 'onWaypointChange')
- -- TODO_22 properly implement this in courseplaySpec
- self.storage = vehicle.spec_courseplaySpec
+ self.storage = vehicle.spec_cpAIWorker
self.settings = vehicle:getCpSettings()
self.courseGeneratorSettings = vehicle:getCourseGeneratorSettings()
From 0f002b4108898d74f8d730675729f76825eb54bb Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Fri, 14 Jul 2023 16:56:41 +0200
Subject: [PATCH 040/107] Update MasterTranslations.xml
---
config/MasterTranslations.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index fba7fcaaa..56c677f85 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -614,12 +614,12 @@
-
-
+
+
-
-
+
+
From 1b46596cca89af9eda2ccda1977808993346d3f7 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Fri, 14 Jul 2023 14:56:58 +0000
Subject: [PATCH 041/107] Updated translations
---
translations/translation_de.xml | 4 ++--
translations/translation_en.xml | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 086fd4f34..69ffb7756 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -181,8 +181,8 @@
-
-
+
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 8984a854f..baa42d9e3 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -181,8 +181,8 @@
-
-
+
+
From 8a3c014f29d32946999a44381332425e04c4516a Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 14 Jul 2023 19:00:43 +0200
Subject: [PATCH 042/107] Adjustment for filltype converter
---
scripts/ai/ImplementUtil.lua | 2 +-
scripts/ai/jobs/CpAIJobSiloLoader.lua | 33 +++++++++++++++++++++++----
scripts/gui/CpAIFrameExtended.lua | 4 ++--
scripts/trigger/TriggerManager.lua | 6 ++---
scripts/trigger/TriggerWrapper.lua | 15 ++++++++----
5 files changed, 45 insertions(+), 15 deletions(-)
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index 9f36aa676..1fa1db3fa 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -426,7 +426,7 @@ end
---@param loadTargetImplement table
---@param implementToLoadFrom table
---@param dischargeNode table|nil optional otherwise the current selected node is used.
----@param suppressLog boolean|nil
+---@param debugFunc function|nil
---@return boolean is loading possible?
---@return number|nil target implement fill unit ix to load into.
---@return number|nil fill type to load
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 90d5c427a..9a9d5b74f 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -202,7 +202,15 @@ function CpAIJobSiloLoader:getUnloadTriggerAt(unloadPosition)
if found and fillType~=nil then
if not trigger:getIsFillTypeAllowed(fillType) then
--- Fill type is not supported by the trigger.
- return false
+ found = false
+ local convertedOutputFillTypes = self:getConvertedFillTypes()
+ for _, convertedFillType in ipairs(convertedOutputFillTypes) do
+ --- Checks possible found fill type conversions
+ if trigger:getIsFillTypeAllowed(convertedFillType) then
+ found = true
+ break
+ end
+ end
end
end
return found, trigger, station
@@ -212,12 +220,12 @@ function CpAIJobSiloLoader:drawSilos(map)
self.heapPlot:draw(map)
g_bunkerSiloManager:drawSilos(map, self.bunkerSilo)
if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
- local fillType
+ local fillTypes = self:getConvertedFillTypes()
local silo = self.heap or self.bunkerSilo
if silo then
- fillType = silo:getFillType()
+ table.insert(fillTypes, silo:getFillType())
end
- g_triggerManager:drawDischargeableTriggers(map, self.unloadTrigger, fillType)
+ g_triggerManager:drawDischargeableTriggers(map, self.unloadTrigger, fillTypes)
end
end
@@ -230,3 +238,20 @@ function CpAIJobSiloLoader:getUnloadingStations()
end
return unloadingStations
end
+
+--- Gets converted fill types if there are any.
+---@return table
+function CpAIJobSiloLoader:getConvertedFillTypes()
+ local fillTypes = {}
+ local vehicle = self:getVehicle()
+ if vehicle then
+ local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(vehicle, Shovel)
+ local spec = found and shovels[1].spec_turnOnVehicle
+ if spec and spec.activateableDischargeNode and spec.activateableDischargeNode.fillTypeConverter then
+ for _, data in pairs(spec.activateableDischargeNode.fillTypeConverter) do
+ table.insert(fillTypes, data.targetFillTypeIndex)
+ end
+ end
+ end
+ return fillTypes
+end
\ No newline at end of file
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index 55490b208..3038501f9 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -588,8 +588,6 @@ function CpInGameMenuAIFrameExtended:updateParameterValueTexts(superFunc, ...)
return
end
g_currentMission:removeMapHotspot(self.aiTargetMapHotspot)
- g_currentMission:removeMapHotspot(self.aiLoadingMarkerHotspot)
- g_currentMission:removeMapHotspot(self.aiUnloadingMarkerHotspot)
g_currentMission:removeMapHotspot(self.driveToAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
@@ -642,6 +640,8 @@ InGameMenuAIFrame.updateParameterValueTexts = Utils.overwrittenFunction(InGameMe
CpInGameMenuAIFrameExtended.updateParameterValueTexts)
function CpInGameMenuAIFrameExtended:updateWarnings()
+ g_currentMission:removeMapHotspot(self.aiLoadingMarkerHotspot)
+ g_currentMission:removeMapHotspot(self.aiUnloadingMarkerHotspot)
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
local parameterType = parameter:getType()
diff --git a/scripts/trigger/TriggerManager.lua b/scripts/trigger/TriggerManager.lua
index 31a8e111f..d841002da 100644
--- a/scripts/trigger/TriggerManager.lua
+++ b/scripts/trigger/TriggerManager.lua
@@ -132,10 +132,10 @@ end
--- Draws all bunker silos onto the ai map.
---@param map table map to draw to.
---@param selected CpTrigger silo that gets highlighted.
----@param fillType number|nil fill type that needs to be supported.
-function TriggerManager:drawDischargeableTriggers(map, selected, fillType)
+---@param fillTypes table|nil fill type that needs to be supported.
+function TriggerManager:drawDischargeableTriggers(map, selected, fillTypes)
for _, trigger in pairs(self.dischargeableUnloadTriggers) do
- trigger:drawPlot(map, selected, fillType)
+ trigger:drawPlot(map, selected, fillTypes)
end
end
diff --git a/scripts/trigger/TriggerWrapper.lua b/scripts/trigger/TriggerWrapper.lua
index c22283690..f9b7966f5 100644
--- a/scripts/trigger/TriggerWrapper.lua
+++ b/scripts/trigger/TriggerWrapper.lua
@@ -42,11 +42,16 @@ end
---@param map table
---@param selectedTrigger CpTrigger
----@param fillType number|nil
-function CpTrigger:drawPlot(map, selectedTrigger, fillType)
- if fillType and fillType ~= FillType.UNKNOWN then
- if not self.trigger:getIsFillTypeAllowed(fillType) then
- --- Fill type is not allowed.
+---@param fillTypes table|nil
+function CpTrigger:drawPlot(map, selectedTrigger, fillTypes)
+ if fillTypes then
+ local found = false
+ for i, fillType in pairs(fillTypes) do
+ if self.trigger:getIsFillTypeAllowed(fillType) then
+ found = true
+ end
+ end
+ if not found then
return
end
end
From 51be63d009325adefa125d6da020c2eda92f3ec1 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 14 Jul 2023 19:07:24 +0200
Subject: [PATCH 043/107] Slightly reduces unloading arm height
---
scripts/specializations/CpShovelPositions.lua | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index eaca48dc9..691cfbfca 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -41,8 +41,8 @@ CpShovelPositions = {
},
PRE_UNLOAD_POSITION = {
ARM_LIMITS = {
- 7,
- 7
+ 2.7,
+ 2.8
},
SHOVEL_LIMITS = {
43,
@@ -51,8 +51,8 @@ CpShovelPositions = {
},
UNLOADING_POSITION = {
ARM_LIMITS = {
- 7,
- 7
+ 2.7,
+ 2.8
},
},
DEBUG = true
From acfdbdcd2b0f4b97ac510c4030473f56f172e4bc Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 14 Jul 2023 19:43:07 +0200
Subject: [PATCH 044/107] Only enable change, when the vehicle is stopped
---
config/VehicleSettingsSetup.xml | 3 ++-
scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua | 1 +
scripts/specializations/CpVehicleSettings.lua | 4 ++++
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/config/VehicleSettingsSetup.xml b/config/VehicleSettingsSetup.xml
index c4f5e46ee..9ac6b2868 100644
--- a/config/VehicleSettingsSetup.xml
+++ b/config/VehicleSettingsSetup.xml
@@ -76,7 +76,8 @@
-
+
diff --git a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
index 4e840ff02..91ebc0aa3 100644
--- a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
+++ b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
@@ -91,6 +91,7 @@ function CpSiloLoaderWorkerHudPageElement:updateContent(vehicle, status)
local loadingHeightOffset = vehicle:getCpSettings().loadingShovelHeightOffset
self.loadingShovelHeightOffsetBtn:setTextDetails(loadingHeightOffset:getTitle(), loadingHeightOffset:getString())
self.loadingShovelHeightOffsetBtn:setVisible(loadingHeightOffset:getIsVisible())
+ self.loadingShovelHeightOffsetBtn:setDisabled(loadingHeightOffset:getIsDisabled())
self.fillLevelProgressText:setTextDetails(status:getSiloFillLevelPercentageLeftOver())
diff --git a/scripts/specializations/CpVehicleSettings.lua b/scripts/specializations/CpVehicleSettings.lua
index e1b321eb3..7e3c60375 100644
--- a/scripts/specializations/CpVehicleSettings.lua
+++ b/scripts/specializations/CpVehicleSettings.lua
@@ -394,6 +394,10 @@ function CpVehicleSettings:isLoadingShovelOffsetSettingVisible()
return self:getCanStartCpSiloLoaderWorker() and not AIUtil.hasChildVehicleWithSpecialization(self, ConveyorBelt)
end
+function CpVehicleSettings:isLoadingShovelOffsetSettingDisabled()
+ return not AIUtil.isStopped(self)
+end
+
--- Saves the user value changed on the server.
function CpVehicleSettings:onCpUserSettingChanged(setting)
if not self.isServer then
From c99bdc8f5b97264907a872b7813d54297e45e4d8 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Fri, 14 Jul 2023 19:52:07 +0200
Subject: [PATCH 045/107] Increase the map zoom.
---
Courseplay.lua | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/Courseplay.lua b/Courseplay.lua
index 8f538ee57..cb8a022f9 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -192,9 +192,21 @@ end
FSCareerMissionInfo.saveToXMLFile = Utils.prependedFunction(FSCareerMissionInfo.saveToXMLFile, Courseplay.saveToXMLFile)
function Courseplay:update(dt)
- g_devHelper:update()
- g_bunkerSiloManager:update(dt)
- g_triggerManager:update(dt)
+ g_devHelper:update()
+ g_bunkerSiloManager:update(dt)
+ g_triggerManager:update(dt)
+ if not self.postInit then
+ -- Doubles the map zoom. Mainly to make it easier to set targets for unload triggers.
+ self.postInit = true
+ local function setIngameMapFix(mapElement)
+ local factor = 2*mapElement.terrainSize/2048
+ mapElement.zoomMax = mapElement.zoomMax * factor
+ mapElement.zoomDefault = mapElement.zoomDefault * factor
+ mapElement.mapZoom = mapElement.zoomDefault
+ end
+ setIngameMapFix(g_currentMission.inGameMenu.pageAI.ingameMap)
+ setIngameMapFix(g_currentMission.inGameMenu.pageMapOverview.ingameMap)
+ end
end
function Courseplay:draw()
From 8f2c6a43c6012adaefb1d70f226b61385c80050c Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Wed, 19 Jul 2023 18:24:57 +0200
Subject: [PATCH 046/107] Rebase fix
---
Courseplay.lua | 2 +-
scripts/specializations/CourseplaySpec.lua | 106 ---------------------
2 files changed, 1 insertion(+), 107 deletions(-)
delete mode 100644 scripts/specializations/CourseplaySpec.lua
diff --git a/Courseplay.lua b/Courseplay.lua
index cb8a022f9..d9c7192bc 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -157,7 +157,7 @@ end
function Courseplay.drawHudMap(map)
if g_Courseplay.globalSettings.drawOntoTheHudMap:getValue() then
local vehicle = g_currentMission.controlledVehicle
- if vehicle and vehicle:getIsEntered() and not g_gui:getIsGuiVisible() and vehicle.spec_courseplaySpec and not vehicle.spec_locomotive then
+ if vehicle and vehicle:getIsEntered() and not g_gui:getIsGuiVisible() and vehicle.spec_cpAIWorker and not vehicle.spec_locomotive then
SpecializationUtil.raiseEvent(vehicle, "onCpDrawHudMap", map)
end
end
diff --git a/scripts/specializations/CourseplaySpec.lua b/scripts/specializations/CourseplaySpec.lua
deleted file mode 100644
index cf3bae77a..000000000
--- a/scripts/specializations/CourseplaySpec.lua
+++ /dev/null
@@ -1,106 +0,0 @@
---- Cp ai driver spec
-
----@class CourseplaySpec
-CourseplaySpec = {}
-
-CourseplaySpec.MOD_NAME = g_currentModName
-
-CourseplaySpec.KEY = "."..CourseplaySpec.MOD_NAME..".courseplaySpec."
-
-function CourseplaySpec.initSpecialization()
- local schema = Vehicle.xmlSchemaSavegame
-end
-
-function CourseplaySpec.prerequisitesPresent(specializations)
- return SpecializationUtil.hasSpecialization(CpAIWorker, specializations)
-end
-
-function CourseplaySpec.registerEventListeners(vehicleType)
- SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", CourseplaySpec)
- SpecializationUtil.registerEventListener(vehicleType, "onLoad", CourseplaySpec)
- SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", CourseplaySpec)
- SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", CourseplaySpec)
- SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", CourseplaySpec)
- SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", CourseplaySpec)
- SpecializationUtil.registerEventListener(vehicleType, "onDraw", CourseplaySpec)
-end
-
-function CourseplaySpec.registerEvents(vehicleType)
- SpecializationUtil.registerEvent(vehicleType, "onCpUnitChanged")
- SpecializationUtil.registerEvent(vehicleType, "onCpDrawHudMap")
-end
-
-function CourseplaySpec.registerOverwrittenFunctions(vehicleType)
-
-end
-
-function CourseplaySpec:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
-
-end
-
-------------------------------------------------------------------------------------------------------------------------
---- Event listeners
----------------------------------------------------------------------------------------------------------------------------
-function CourseplaySpec:onLoad(savegame)
- --- Register the spec: spec_courseplaySpec
- local specName = CourseplaySpec.MOD_NAME .. ".courseplaySpec"
- self.spec_courseplaySpec = self["spec_" .. specName]
- g_messageCenter:subscribe(MessageType.SETTING_CHANGED[GameSettings.SETTING.USE_MILES], CourseplaySpec.onUnitChanged, self)
- g_messageCenter:subscribe(MessageType.SETTING_CHANGED[GameSettings.SETTING.USE_ACRE], CourseplaySpec.onUnitChanged, self)
- g_messageCenter:subscribe(MessageType.CP_DISTANCE_UNIT_CHANGED, CourseplaySpec.onUnitChanged, self)
-end
-
-function CourseplaySpec:onUnitChanged()
- SpecializationUtil.raiseEvent(self,"onCpUnitChanged")
-end
-
-function CourseplaySpec:onPostLoad(savegame)
-
-end
-
-function CourseplaySpec:saveToXMLFile(xmlFile, baseKey, usedModNames)
-
-end
-
-function CourseplaySpec:onEnterVehicle(isControlling)
-
-end
-
-function CourseplaySpec:onLeaveVehicle(wasEntered)
-
-end
-
-function CourseplaySpec:isCollisionDetectionEnabled()
- return self.collisionDetectionEnabled
-end
-
-function CourseplaySpec:enableCollisionDetection()
- self.collisionDetectionEnabled = true
-end
-
-function CourseplaySpec:disableCollisionDetection()
- self.collisionDetectionEnabled = false
-end
-
---- This is to be able to disable the built-in AIDriveStrategyCollision check from our drive strategies
-function CourseplaySpec:getCollisionCheckActive(superFunc,...)
- if self.collisionDetectionEnabled then
- return superFunc(self,...)
- else
- return false
- end
-end
-
---- Enriches the status data for the hud here.
-function CourseplaySpec:onUpdateTick()
-
-end
-
-function CourseplaySpec:onDraw()
-
-end
-
-
-AIDriveStrategyCollision.getCollisionCheckActive = Utils.overwrittenFunction(
- AIDriveStrategyCollision.getCollisionCheckActive, CourseplaySpec.getCollisionCheckActive
-)
From 154ca1bc03c895da06b4eb57985a2870e85734f1 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 20 Jul 2023 11:53:50 +0200
Subject: [PATCH 047/107] Small fix
---
scripts/ai/Markers.lua | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/ai/Markers.lua b/scripts/ai/Markers.lua
index e0674a111..2aeb6d8b2 100644
--- a/scripts/ai/Markers.lua
+++ b/scripts/ai/Markers.lua
@@ -36,23 +36,23 @@ local function setBackMarkerNode(vehicle, measuredBackDistance)
if AIUtil.hasImplementsOnTheBack(vehicle) then
local lastImplement
lastImplement, backMarkerOffset = AIUtil.getLastAttachedImplement(vehicle)
- referenceNode = AIUtil.getDirectionNode(vehicle)
+ referenceNode = AIUtil.getDirectionNode(vehicle)
CpUtil.debugVehicle(CpDebug.DBG_IMPLEMENTS, vehicle, 'Using the last implement\'s rear distance for the back marker node, %d m from root node', backMarkerOffset)
elseif measuredBackDistance then
- referenceNode = AIUtil.getDirectionNode(vehicle)
+ referenceNode = AIUtil.getDirectionNode(vehicle)
backMarkerOffset = -measuredBackDistance
CpUtil.debugVehicle(CpDebug.DBG_IMPLEMENTS, vehicle, 'back marker node on measured back distance %.1f', measuredBackDistance)
elseif reverserNode then
-- if there is a reverser node, use that, mainly because that most likely will turn with an implement
-- or with the back component of an articulated vehicle. Just need to find out the distance correctly
- local dx, _, dz = localToLocal(reverserNode, AIUtil.getDirectionNode(vehicle), 0, 0, 0)
+ local dx, _, dz = localToLocal(reverserNode, AIUtil.getDirectionNode(vehicle), 0, 0, 0)
local dBetweenRootAndReverserNode = MathUtil.vector2Length(dx, dz)
backMarkerOffset = dBetweenRootAndReverserNode - vehicle.size.length / 2 - vehicle.size.lengthOffset
referenceNode = reverserNode
CpUtil.debugVehicle(CpDebug.DBG_IMPLEMENTS, vehicle, 'Using the %s node for the back marker node %d m from root node (%d m between root and reverser)',
debugText, backMarkerOffset, dBetweenRootAndReverserNode)
else
- referenceNode = AIUtil.getDirectionNode(vehicle)
+ referenceNode = AIUtil.getDirectionNode(vehicle)
backMarkerOffset = - vehicle.size.length / 2 + vehicle.size.lengthOffset
CpUtil.debugVehicle(CpDebug.DBG_IMPLEMENTS, vehicle, 'Using the vehicle\'s root node for the back marker node, %d m from root node', backMarkerOffset)
end
From dcf92079d29a599b8911e55199562845ec9b6d57 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 20 Jul 2023 12:15:26 +0200
Subject: [PATCH 048/107] Added closing of foldable shovels during transport
---
.../ai/AIDriveStrategyShovelSiloLoader.lua | 4 +-
scripts/specializations/CpShovelPositions.lua | 48 ++++++++++++-------
2 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index b824b3dae..8ad3724df 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -130,8 +130,8 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
local dirX, dirZ = self.silo:getLengthDirection()
local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
self.siloFrontNode = CpUtil.createNode("siloFrontNode", cx, cz, yRot)
- self.siloAreaToAvoid = PathfinderUtil.NodeArea(self.siloFrontNode, -self.silo:getWidth()/2,
- 0, self.silo:getWidth(), self.silo:getLength())
+ self.siloAreaToAvoid = PathfinderUtil.NodeArea(self.siloFrontNode, -self.silo:getWidth()/2 - 1,
+ -1, self.silo:getWidth() + 2, self.silo:getLength() + 2)
self.siloController = CpBunkerSiloLoaderController(self.silo, self.vehicle, self)
end
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 691cfbfca..79e6c73fe 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -247,10 +247,11 @@ end
---@param dt number
---@param shovelLimits table
---@param armLimits table
----@param useHighDumpShovel boolean|nil
+---@param isLoading boolean|nil
---@param heightOffset number|nil
+---@param isUnloading boolean|nil
---@return boolean|nil
-function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHighDumpShovel, heightOffset)
+function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, isLoading, heightOffset, isUnloading)
local min, max = unpack(shovelLimits)
--- Target angle of the shovel node, which is at the end of the shovel.
local targetAngle = math.rad(min) + math.rad(max - min)/2
@@ -312,6 +313,7 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
local isDirty, alpha, oldRotRelativeArmRot
if hasIntersection then
+ --- Controls the arm height
setTranslation(armProjectionNode, 0, i1y, i1z)
setTranslation(armToolRefNode, ax, ay, az)
local _, shy, shz = localToLocal(shovelTool.node, armVehicle.rootNode, 0, 0, 0)
@@ -324,24 +326,31 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
isDirty = ImplementUtil.moveMovingToolToRotation(armVehicle, armTool, dt, angle)
end
+ local highDumpShovelTool
local highDumpShovelIx = g_vehicleConfigurations:get(self, "shovelMovingToolIx")
- if highDumpShovelIx then
- local tool = self.spec_cylindered.movingTools[highDumpShovelIx]
- if useHighDumpShovel then
- local _, dy, _ = localDirectionToWorld(getParent(tool.node), 0, 0, 1)
+ if highDumpShovelIx ~= nil then
+ highDumpShovelTool = self.spec_cylindered.movingTools[highDumpShovelIx]
+ if isUnloading then
+ --- Makes sure the shovel is almost vertical for the high dump functionality
+ local _, dy, _ = localDirectionToWorld(getParent(highDumpShovelTool.node), 0, 0, 1)
angle = math.acos(dy)
- targetAngle = math.pi/2 - math.pi/8
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
+ targetAngle = math.pi/2 - math.pi/6
else
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMax or tool.rotMin) or isDirty
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
+ highDumpShovelTool.invertAxis and highDumpShovelTool.rotMax or highDumpShovelTool.rotMin) or isDirty
end
else
for i, tool in pairs(self.spec_cylindered.movingTools) do
if tool.axis then
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
+ if isLoading or isUnloading then
+ --- Opens the shovel for loading and unloading
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
+ else
+ --- Closes the shovel after loading
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMax or tool.rotMin) or isDirty
+ end
break
end
end
@@ -351,6 +360,12 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, useHig
isDirty = ImplementUtil.moveMovingToolToRotation(shovelVehicle,
shovelTool, dt, goalAngle) or isDirty
+ if isUnloading and highDumpShovelTool then
+ --- Uses the high dump shovel functionality.
+ isDirty = isDirty or ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
+ highDumpShovelTool.invertAxis and highDumpShovelTool.rotMin or highDumpShovelTool.rotMax)
+ end
+
--- Debug information
local wsx, wsy, wsz = localToWorld(armVehicle.rootNode, sx, sy, sz)
local wex, wey, wez = localToWorld(armVehicle.rootNode, ex, ey, ez)
@@ -411,7 +426,7 @@ function CpShovelPositions:updateLoadingPosition(dt)
isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS,
CpShovelPositions.LOADING_POSITION.ARM_LIMITS,
- nil, heightOffset)
+ true, heightOffset)
end
spec.isDirty = isDirty
end
@@ -425,7 +440,7 @@ function CpShovelPositions:updateTransportPosition(dt)
isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS,
CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS,
- nil, heightOffset)
+ false, heightOffset)
end
spec.isDirty = isDirty
end
@@ -448,7 +463,8 @@ function CpShovelPositions:updateUnloadingPosition(dt)
if angle and maxAngle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
{math.deg(maxAngle), math.deg(maxAngle) + 2},
- CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, true)
+ CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, false,
+ nil, true)
end
spec.isDirty = isDirty
end
From 30e6624ba029b1ebc5956fa216dcdcbf83eaaf72 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Sun, 20 Aug 2023 14:31:43 +0200
Subject: [PATCH 049/107] expand the reverse/forward change path of the
pathfinder by 2m
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 2 ++
1 file changed, 2 insertions(+)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 8ad3724df..c644c8128 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -465,6 +465,7 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToStart(path)
if path and #path > 2 then
self:debug("Found alignment path to the course for the silo.")
local alignmentCourse = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
+ alignmentCourse:adjustForTowedImplements(2)
self:startCourse(alignmentCourse, 1)
self:setNewState(self.states.DRIVING_ALIGNMENT_COURSE)
else
@@ -501,6 +502,7 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path,
if path and #path > 2 then
self:debug("Found path to unloading station.")
local course = Course(self.vehicle, CourseGenerator.pointsToXzInPlace(path), true)
+ course:adjustForTowedImplements(2)
self:startCourse(course, 1)
self:setNewState(self.states.DRIVING_TO_UNLOAD_POSITION)
else
From 9f97f31253e35f2d7e08239a8ec0b6608a006082 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 21 Aug 2023 12:33:19 +0200
Subject: [PATCH 050/107] Fix for shovels and more debug options
---
config/VehicleConfigurations.xml | 3 +
scripts/ai/ImplementUtil.lua | 6 +-
scripts/ai/controllers/ShovelController.lua | 35 +++++++-
scripts/specializations/CpShovelPositions.lua | 83 +++++++++++++++----
4 files changed, 110 insertions(+), 17 deletions(-)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index 274ab95f1..818f02d98 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -340,6 +340,9 @@ You can define the following custom settings:
+
open factor: %.2f, inverted: %s",
+ self.shovelNode.movingToolActivation.openFactor,
+ tostring(self.shovelNode.movingToolActivation.isInverted))
+ end
+ if self.shovelSpec.shovelDischargeInfo.node then
+ self:debug("min angle: %.2f, max angle: %.2f",
+ math.deg(self.shovelSpec.shovelDischargeInfo.minSpeedAngle),
+ math.deg(self.shovelSpec.shovelDischargeInfo.maxSpeedAngle))
+ end
+ end
+ self:debug("--Shovel Debug finished--")
+end
+
+function ShovelController:debug(...)
+ if self.isConsoleCommand then
+ --- Ignore vehicle debug setting, if the pipe controller was created by a console command.
+ self:info(...)
+ return
+ end
+ ImplementController.debug(self, ...)
+end
\ No newline at end of file
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 79e6c73fe..ad93e568a 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -64,8 +64,16 @@ CpShovelPositions.KEY = "." .. CpShovelPositions.SPEC_NAME
function CpShovelPositions.initSpecialization()
local schema = Vehicle.xmlSchemaSavegame
- g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelState', 'cpSetShovelState', 'consoleCommandSetShovelState', CpShovelPositions)
- g_devHelper.consoleCommands:registerConsoleCommand('cpSetShovelArmLimit', 'cpSetShovelArmLimit', 'consoleCommandSetPreUnloadArmLimit', CpShovelPositions)
+
+ g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsPrintShovelDebug",
+ "Prints debug information for the shovel",
+ "consoleCommandPrintShovelDebug", CpShovelPositions)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsSetState",
+ "Set's the current shovel state",
+ "consoleCommandSetShovelState", CpShovelPositions)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsSetArmLimit",
+ "Set's the arm max limit",
+ "consoleCommandSetPreUnloadArmLimit", CpShovelPositions)
end
function CpShovelPositions.prerequisitesPresent(specializations)
@@ -140,6 +148,49 @@ function CpShovelPositions:consoleCommandSetPreUnloadArmLimit(min, max)
end, min, max)
end
+function CpShovelPositions:consoleCommandPrintShovelDebug(cylinderedDepth)
+ return executeConsoleCommand(function(shovelImplement)
+ --- Position debug
+ CpUtil.infoImplement(shovelImplement, "-- Position debug --")
+ local spec = shovelImplement.spec_cpShovelPositions
+ if spec then
+ CpUtil.infoImplement(shovelImplement, " arm tool %s -> %s",
+ CpUtil.getName(spec.armVehicle), tostring(spec.armToolIx))
+ CpUtil.infoImplement(shovelImplement, " shovel tool %s -> %s",
+ CpUtil.getName(spec.shovelVehicle), tostring(spec.shovelToolIx))
+ local highDumpShovelIx = g_vehicleConfigurations:get(shovelImplement, "shovelMovingToolIx")
+ CpUtil.infoImplement(shovelImplement, " shovel high dump %s -> %s",
+ CpUtil.getName(shovelImplement), tostring(highDumpShovelIx))
+ end
+
+ CpUtil.infoImplement(shovelImplement, "-- Position debug --")
+ --- Shovel debug
+ local controller = ShovelController(shovelImplement.rootVehicle, shovelImplement, true)
+ controller:printShovelDebug()
+ controller:delete()
+ --- Cylindered debug here
+ CpUtil.infoImplement(shovelImplement, "-- Cylindered debug --")
+ cylinderedDepth = cylinderedDepth and tonumber(cylinderedDepth) or 0
+
+ local childVehicles = shovelImplement.rootVehicle:getChildVehicles()
+ for _, vehicle in ipairs(childVehicles) do
+ if vehicle.spec_cylindered then
+ for ix, tool in pairs(vehicle.spec_cylindered.movingTools) do
+ CpUtil.infoImplement(shovelImplement, " %s => ix: %d ",
+ CpUtil.getName(vehicle), ix)
+ if cylinderedDepth > 0 then
+ CpUtil.infoImplement(shovelImplement, " %s",
+ DebugUtil.debugTableToString(tool, " ", 0, cylinderedDepth))
+ end
+ CpUtil.infoImplement(shovelImplement, " %s => ix: %d finished",
+ CpUtil.getName(vehicle), ix)
+ end
+ end
+ end
+ CpUtil.infoImplement(shovelImplement, "-- Cylindered debug finished --")
+ end)
+end
+
--------------------------------------------
--- Event Listener
--------------------------------------------
@@ -339,19 +390,23 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, isLoad
isDirty = ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
highDumpShovelTool.invertAxis and highDumpShovelTool.rotMax or highDumpShovelTool.rotMin) or isDirty
end
- else
- for i, tool in pairs(self.spec_cylindered.movingTools) do
- if tool.axis then
- if isLoading or isUnloading then
- --- Opens the shovel for loading and unloading
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
- else
- --- Closes the shovel after loading
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMax or tool.rotMin) or isDirty
+ else
+ local shovelData = ImplementUtil.getShovelNode(self)
+ if shovelData.movingToolActivation then
+ --- The shovel has a moving tool for grabbing.
+ for i, tool in pairs(self.spec_cylindered.movingTools) do
+ if tool.axis then
+ if isLoading or isUnloading then
+ --- Opens the shovel for loading and unloading
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
+ else
+ --- Closes the shovel after loading
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMax or tool.rotMin) or isDirty
+ end
+ break
end
- break
end
end
end
From 2d4c0242ac9625872845cca84ec6922e5c5139e1 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 14:02:46 +0200
Subject: [PATCH 051/107] WIP Help Menu
---
config/HelpMenu.xml | 14 ++++++++++++++
config/MasterTranslations.xml | 27 +++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/config/HelpMenu.xml b/config/HelpMenu.xml
index 15eb062bd..9785ee2a5 100644
--- a/config/HelpMenu.xml
+++ b/config/HelpMenu.xml
@@ -222,5 +222,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index 56c677f85..fe68114b7 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2496,6 +2496,33 @@ Anschließend kann der Helfer gestartet werden.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From cb3ef13739dd65efca354b1db3dc9d0c3b58d459 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 14:06:02 +0200
Subject: [PATCH 052/107] Update MasterTranslations.xml
---
config/MasterTranslations.xml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index fe68114b7..6992e540a 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2507,14 +2507,14 @@ Now it's possible to start the helper.
Radlader wie er funktioniert und was er kann.
]]>
@@ -2522,7 +2522,7 @@ So wird er eingestellt und gestartet.
Zusatzinfos zum Trigger mit Bild.
]]>
From 84379ec900d60e1b60f8bb99f35c4235ade6722e Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 14:07:58 +0200
Subject: [PATCH 053/107] Update MasterTranslations.xml
---
config/MasterTranslations.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index 6992e540a..afbbc689a 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2509,6 +2509,7 @@ Radlader wie er funktioniert und was er kann.
+
Date: Thu, 24 Aug 2023 12:08:20 +0000
Subject: [PATCH 054/107] Updated translations
---
translations/translation_br.xml | 10 ++++++++++
translations/translation_cs.xml | 10 ++++++++++
translations/translation_ct.xml | 10 ++++++++++
translations/translation_cz.xml | 10 ++++++++++
translations/translation_da.xml | 10 ++++++++++
translations/translation_de.xml | 10 ++++++++++
translations/translation_ea.xml | 10 ++++++++++
translations/translation_en.xml | 10 ++++++++++
translations/translation_es.xml | 10 ++++++++++
translations/translation_fc.xml | 10 ++++++++++
translations/translation_fi.xml | 10 ++++++++++
translations/translation_fr.xml | 10 ++++++++++
translations/translation_hu.xml | 10 ++++++++++
translations/translation_it.xml | 10 ++++++++++
translations/translation_jp.xml | 10 ++++++++++
translations/translation_kr.xml | 10 ++++++++++
translations/translation_nl.xml | 10 ++++++++++
translations/translation_no.xml | 10 ++++++++++
translations/translation_pl.xml | 10 ++++++++++
translations/translation_pt.xml | 10 ++++++++++
translations/translation_ro.xml | 10 ++++++++++
translations/translation_ru.xml | 10 ++++++++++
translations/translation_sv.xml | 10 ++++++++++
translations/translation_tr.xml | 10 ++++++++++
24 files changed, 240 insertions(+)
diff --git a/translations/translation_br.xml b/translations/translation_br.xml
index be6bef151..944682db2 100644
--- a/translations/translation_br.xml
+++ b/translations/translation_br.xml
@@ -822,6 +822,16 @@ A carreta pode ser descarregado usando Courseplay
Para iniciar, o marcador de carregamento no menu AI precisa ser definido.
O marcador detecta montes ou silos e os destaca no mapa.
Agora é possível iniciar o auxiliar.
+"/>
+
+
+
+
diff --git a/translations/translation_cs.xml b/translations/translation_cs.xml
index 6610bdefa..d5940bfa2 100644
--- a/translations/translation_cs.xml
+++ b/translations/translation_cs.xml
@@ -806,6 +806,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_ct.xml b/translations/translation_ct.xml
index a3a918d83..f228f09fd 100644
--- a/translations/translation_ct.xml
+++ b/translations/translation_ct.xml
@@ -805,6 +805,16 @@ Courseplay能夠在青貯筒倉中壓實或分佈糠秕,或在楔形筒倉中
要啟動AI選單上的裝載標記,需要進行設定。
這個標記可以檢測到堆或筒倉,並在地圖上突出顯示它們。
那麼現在可以啟用小幫手了。
+"/>
+
+
+
+
diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml
index 7fef8dbae..0054bb17a 100644
--- a/translations/translation_cz.xml
+++ b/translations/translation_cz.xml
@@ -803,6 +803,16 @@ Nakladač může být vyložen pomocí CP.
Chcete-li spustit nakládací značku v nabídce AI, je třeba ji nastavit.
Značka detekuje hromady nebo silážní jámy a zvýrazňuje je na mapě.
Nyní je možné spustit pracovníka.
+"/>
+
+
+
+
diff --git a/translations/translation_da.xml b/translations/translation_da.xml
index c00a87de7..4a0da7b09 100644
--- a/translations/translation_da.xml
+++ b/translations/translation_da.xml
@@ -816,6 +816,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 69ffb7756..93770f193 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -829,6 +829,16 @@ Bedenkt dabei, dass das automatische Abtanken mit CP in Fahrtrichtung des Laders
Als erstes muss auf der Helferkarte der Lade-Marker gesetzt werden.
Dieses erkennt vorhandende Haufen oder Silos und markiert den ausgewählten.
Anschließend kann der Helfer gestartet werden.
+"/>
+
+
+
+
diff --git a/translations/translation_ea.xml b/translations/translation_ea.xml
index 2762891d8..858cb1456 100644
--- a/translations/translation_ea.xml
+++ b/translations/translation_ea.xml
@@ -815,6 +815,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index baa42d9e3..b1bf7ddca 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -829,6 +829,16 @@ Keep in mind that the automatic unloading with CP goes in the same direction as
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_es.xml b/translations/translation_es.xml
index f738f12bd..921039eb2 100644
--- a/translations/translation_es.xml
+++ b/translations/translation_es.xml
@@ -814,6 +814,16 @@ El cargador se puede descargar con un descargador de Courseplay.
Para iniciar el marcador de carga, en el menú AI debe configurarse.
El marcador detecta montones o silos y los resalta en el mapa.
Ahora es posible iniciar el ayudante.
+"/>
+
+
+
+
diff --git a/translations/translation_fc.xml b/translations/translation_fc.xml
index 910fff456..4c3014c70 100644
--- a/translations/translation_fc.xml
+++ b/translations/translation_fc.xml
@@ -815,6 +815,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_fi.xml b/translations/translation_fi.xml
index 215325630..cbf81baeb 100644
--- a/translations/translation_fi.xml
+++ b/translations/translation_fi.xml
@@ -815,6 +815,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_fr.xml b/translations/translation_fr.xml
index 29b037550..b1c0c8bfb 100644
--- a/translations/translation_fr.xml
+++ b/translations/translation_fr.xml
@@ -794,6 +794,16 @@ La chargeuse peut être vidée par une tâche de déchargement Courseplay.
+
+
+
+
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index 5c0a73d12..f1e87e787 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -812,6 +812,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_it.xml b/translations/translation_it.xml
index 947fe7e9a..6e23a5e16 100644
--- a/translations/translation_it.xml
+++ b/translations/translation_it.xml
@@ -818,6 +818,16 @@ Il caricatore può essere scaricato con uno scaricatore Courseplay.
Per avviare l'indicatore di caricamento nel menu AI è necessario impostare.
Il marcatore rileva cumuli o silos e li evidenzia sulla mappa.
Ora è possibile avviare l'helper.
+"/>
+
+
+
+
diff --git a/translations/translation_jp.xml b/translations/translation_jp.xml
index f73714129..a5720e9bf 100644
--- a/translations/translation_jp.xml
+++ b/translations/translation_jp.xml
@@ -812,6 +812,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_kr.xml b/translations/translation_kr.xml
index 12cbcccc5..cf23f5518 100644
--- a/translations/translation_kr.xml
+++ b/translations/translation_kr.xml
@@ -815,6 +815,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_nl.xml b/translations/translation_nl.xml
index 69089d31a..5efc6fbe4 100644
--- a/translations/translation_nl.xml
+++ b/translations/translation_nl.xml
@@ -812,6 +812,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_no.xml b/translations/translation_no.xml
index 80f1b0d33..7a0f717f4 100644
--- a/translations/translation_no.xml
+++ b/translations/translation_no.xml
@@ -815,6 +815,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_pl.xml b/translations/translation_pl.xml
index 264d59ebb..ac53e7c7b 100644
--- a/translations/translation_pl.xml
+++ b/translations/translation_pl.xml
@@ -810,6 +810,16 @@ Załadunkowy możne zostać rozładowany poprzez rozładunkowego Courseplay.
Aby rozpocząć załadunek, punkt załadunkowy musi zostać ustawiony w menu SI.
Znacznik wykrywa pryzmę lub silos i podświetla to na mapie.
Terze możesz rozpocząć pracę pomocnika.
+"/>
+
+
+
+
diff --git a/translations/translation_pt.xml b/translations/translation_pt.xml
index c62f0264d..a767432e6 100644
--- a/translations/translation_pt.xml
+++ b/translations/translation_pt.xml
@@ -807,6 +807,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_ro.xml b/translations/translation_ro.xml
index e56c21353..fb5282a21 100644
--- a/translations/translation_ro.xml
+++ b/translations/translation_ro.xml
@@ -815,6 +815,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
diff --git a/translations/translation_ru.xml b/translations/translation_ru.xml
index af5aa6612..79d07c5dd 100644
--- a/translations/translation_ru.xml
+++ b/translations/translation_ru.xml
@@ -815,6 +815,16 @@ Courseplay способен прессовать или распределять
Чтобы начать необходимо установить погрузочный маркер в меню ИИ.
Маркер обнаруживает кучи или бункеры и выделяет их на карте.
Теперь можно запускать помощника.
+"/>
+
+
+
+
diff --git a/translations/translation_sv.xml b/translations/translation_sv.xml
index a3b8d6baa..16b167639 100644
--- a/translations/translation_sv.xml
+++ b/translations/translation_sv.xml
@@ -810,6 +810,16 @@ Lastaren kan lossas med en Courseplay-avlastare.
För att starta laddningsmarkören på AI-menyn måste ställas in.
Markören upptäcker högar eller silos och markerar dem på kartan.
Nu är det möjligt att starta hjälparen.
+"/>
+
+
+
+
diff --git a/translations/translation_tr.xml b/translations/translation_tr.xml
index 574be7dff..74aba105c 100644
--- a/translations/translation_tr.xml
+++ b/translations/translation_tr.xml
@@ -812,6 +812,16 @@ The loader can be unloaded with an Courseplay unloader.
To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
+"/>
+
+
+
+
From 4def8fbcccc8ed25da00e40908378c700520e61b Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 14:28:49 +0200
Subject: [PATCH 055/107] WIP DE
---
config/HelpMenu.xml | 2 +-
config/MasterTranslations.xml | 27 ++++++++++++++++++++++-----
img/helpmenu/shovelloadertrigger.dds | Bin 0 -> 524416 bytes
3 files changed, 23 insertions(+), 6 deletions(-)
create mode 100644 img/helpmenu/shovelloadertrigger.dds
diff --git a/config/HelpMenu.xml b/config/HelpMenu.xml
index 9785ee2a5..f6667d36b 100644
--- a/config/HelpMenu.xml
+++ b/config/HelpMenu.xml
@@ -232,7 +232,7 @@
-
+
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index afbbc689a..6068736c8 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2499,12 +2499,18 @@ Now it's possible to start the helper.
]]>
-
-
+
+
dM?a_^lp_qJUVgvueN?Cg$t<7$cqMCAlQ%t_)C#7y`f^pD^YGvL4I-=}$rU}N<4
z?7a2V4ZoN4_wUx0xr{8lu*BB^KL_}Cfaifba~^P&)fyXHj)ss#zw=KcySH~2pzS}2
ztToz<47@&44l;u_2HXC_jmU1
z9^YSle=+Z|-hZ?Ce?9jn#+d)p%g=!Mfcb#=fcb#ufjfI1!2F+HTt;*9jr{dD`+fYo
zzq5b$`2OPii}gFK-(mhw4Nq@2pC@~Nm=Bl_m=Bl_cpkX3=K;)r%>Ntt6Y%f;&i>uw
z`-|@{*6*->hxw2BkNJ=10jv*TeE{nNpTBwFZ~Qmb8ri|oK{Q6s!6%XL&+kXuf7BS~
z|4lDF1M>j$0Q2DU#{>Mk|9t)KC-{%<`_R#$p-;m73H{)scz?Y+!MzkN+5z`O0;Y-n6EW9K;%ygko%^5zZ9|LMhL#Lyf0>u>h^pSRxu{(CW(uzm`D
zU!y}tTwS;BOqqisSem|bnP%UWYLiT=J?W6=lXnKJA6-#xbdo%8p9vis>8
zzwdu9$FHApwSq{PG2?ps{^Q2j{+}9d-z+@<^APh8^KkO)uG{tZMdU&*&bQ5x7pIvpTJQ7hJ#X
zk?oP|CAtp9eZ_q);QtJGeH`zv{~Yrl^B?o%^T(6hm2>#KZmi!<6aF^>k4U209z8yq%QApWaV;bp-rF_+%KT22T>gm=5CbfH*8NHV+|
zZ%$M*kJa(IHrQ!O#)Fz4=M&f(|##?SYy=Re|nGVu0Q5@d24
z_^EqiO#>HYMI>`NREc=(eUJC9IM?fgnrvjh+e4Lz--MH;`;cAVSU?{a5`?Hir9zUB
zgz0+Ve5qPRFV<&qJ)Tr)N7-gYSv^5qE);V$CQ}~T&XehoBK|i>$-T&r;DZ<9KaWR}
znE#mn@Fd+f>-0>PUV!Jv8_$pUy5Q?_C+kJGivMlES4PmMM)rMGu!3$w_Wekt8~ODu
zm8!U3e>lpr<8ga;5&2}2-5J&N0p=~k8r2Dq6?FLPq=F!5zmGGZ2D_eRh%@S{B)W-D
zNJ}+{t>;RPi7A_3vG_d`>&~_4D#Isxi*{GP1$0CoI8=g(OT)
zOcUhg!8qMVuLS=-%Hy9IkK6m_4}e`C_DVR&fA5wc?w?U7LqcCi*(S&fjH>49;rq_f
z$}?cs6G4_;o%>R$>`!`Vsfb;*Sm%f2HhdFmAa}Gb>
zH-5gSj{ka+Uv*rE?CR*~DCFh$i2{8l6Y{?s%GIMOzcV
zBIYG}{X^jYx7dp-_ZhRe9DY+cz8`{<*l6U+O{M_E4a8inR&y2Q31W&FK925{VR@
zZxhM~fOr7Z1y0+1Ky3d{FCI^ppZ~-5i|5B1&yV=J;OlZH>qV2z|FL|&<`=>4r*x*g
z3S?Km9BPafkyS}SlUa@O@L%vPTC~qNQ|yuQ1RZ55Vok_GJXTVbMza=Yp>k>5V-<8x4*pO>)_*<`)Y6tG(o#K^xt8cY$3xDpRtiS&zr
zx`0OCTaxLg=Yswqn3v({fcOE2!zUY!yD78DU_U8?@6oD!v|oXQgm?h>0gev15&tti
zp1SE;7l`?f`41j4?Ei;8pm*|oj`bCMe?QIhJ=y$^bEk2z5#{$q&E{d`_xC}4eKy$b
z!v=!^@jtVUrkl#Dk^};;zoRUeMG$;1^4AANRdK)lr9MkC;2$llB1n##?ZX<@eL}|71onKNus9gBptyrZlV`Fi;ds(iINljGhr=QFg5SYp
z3dZvRJk2k?f&2;*2`NSAU0KPpC?8NDnb$Dg@&GXZG5<0DG5<0DG5@EQ|6_G?C=O6k
zA_abCla)Q!g2=C4!5n3feXT8a+M$l0YmN?^kpCUjm8r~dmx}olZ&|)
z=-)q640Qk+e>_hR%K3QgX+m}j${!4O=9?Bm
zA0UAsQCdW1lf}iCcA&mMYLlrHvIhz2viX^fMw^lcud6%zWo8rPC4m0W+4<(1$e+Ly
zjPV~`H^hIbbo%81VE$wNWBz0QWBz0Q-wOUu*vqKyzv6L5f;dX6H0u$M&7tDrg}`aR
zZXRU!#r^snWtR(QNCf0Q$kT`Shmn5(HeU~V0ugpg1=(QF?>%$871{ZD`RDQmATL15
z%aEcvKdGRW94fOZO}bzZ?GN?&LHo~uety7nAz=xCK7fv=(H?<#0>lBr9c5hkJZU0t
zpK;F8QqVV$UXY)kn~VAkB}#eF7ZBAcju$v3JuB!RM9aqO)et*b(!fMWi?>`C&cp)0|pZuPeiEvoo^ufKaq5MP=8@t
zb-FvA2jF8_6wh!;9iRuaQ_0B^&}Tl_ALydYA=|e0v2EACf2+or|Cs-n|Cs-n|Cs-`
zlK&_U@S?Zb2mB=0<&~Sq?CLT8qqsZbe`abO-DvEW2?RW_T}Sf$|JUKB_waeFG8|5dYs;zy31HGvG`8G&(Lny~&H>70EX6|3my@
zxz8Ix{tRb*ZO!#uM}OzHI=8l<
zc>p2j%R$6v$iHtz^?7w)I+y>raU;a*rQpw>t2gvj*-#$$tsn1HzmNHk`H%UJ`H%UJ`F|_<{~q_ORB5Rp
zh}P>JjYc6KFhOkS3)UlhT?2st)Q?BHtga6A`{O|0osP1@lsRa(YzBWm4T^vm`uq6l
zchlnig8Tz~WT#8Keu(pfoi53U*X<=sTqxgPB&rX=I)EasJ!r1{!!u$oP17}BaBSrI
z!yZnTXRbcn%@XS!jFQ#%a<{n$)T}>DyyWR9qv;_c;+-khXrnORm_*Y);up^(i0k|u
z;@@5>D&FBwZ>$)CJO-9iKhom>NsPYh1<4SjEZZ)F_XRtKU`*!@J7g=tgFzgA@9+O$
zykN55$Nb0q$Nb0q$Nb0qzm@!-u>X-94UNFMIz^PG!fZlufFafgb%7hXra-^~{&r%1
zmr9G)@!`+&0*%k8?Hqx$3HtqNg2+$5kxO^Ah?>fFQ}jqZ63&$Z)$gAV%Ium-_Pg!e
zr7Z1V^2g4gte5Vv-Q8lr8Ff5mVxa2O~l^{Akae-^~w-G0;$5c&gwzkY2=*RgcYP+3#i!oE|5sNcWI
z(v=mcj_?rW
zYGI}<9)S6e`H%UJ`H%UJ`9HP%Z=;f{`$8yA&L=_@halen@+e!0;{F5^YDD?;%uyD&
zpDj+SPqvNa1G2Fq^1R4oueKnsxi%WKABViXR8LO@qlCPG47Ug61qetU^aqrdSVT?}
zTKBJ!%LPBdT)oCZh>#4Y6P$g;st51{rC4z>z8#XIEzxvttTuKL(pG(u56%L9hpy?bW{oBGe
z^Z+Emu|U@-K*HDszel2X$Y8Ve6L$Gj
zNz8xDf6RZ(f6RZ(|Ec7EocmSBS0K&@het=Dj!rD93Yv=`A5Y|rYEXYY!sZI6fc?Kc
z(mOiN|Dg$qwu3&wCX}~tGQD~3F|hONpz#l~|9J^jt^17iN%p`s%^6r9kbw1rQNA9L
z+~i*ic0a+4YS%(Pzu_nwCgmrDXTI@`Z=k+DrF7VHQnry>BNit-t`Eu_?o=sc|I6nu
zS#s~(4eitnc+K5#SQgM-4bGA8B4gV^{5f(5<&O;!O-6|8$E5D0aug3}4P7pTanv5D
zDZB_{g3rLXfOY;%pr0w;`j@|K<;r)Hw)*BYQst
z{%*9sFSOsuL-xGAM-@Rby(!j(`s~2^dfqtqN7-v*{6}?x^+JQGG#=M~`B(3DH9|ii
zDHP<#`vKbn#WwKw!*aqZ=;}jsZ*wIeJ%Oe*7L*Sdqr-yBh0qru>}9#~^TKbOIdiE9
z`u=&FY($!TA=w~4c<`;xV#S3^`tx%)^vjk%c<*zIH(Zn<{!8^a%JRHYT}?4pK}TJJ
z8sNHikRj%7Sfr>CxN0w}Azv_B(Xv+GF6%2ao7aG!fM{wg*sN^J5)DU{jQVZi*1uf)
z3$p*W`NQ*DI){vR-Fw&9x4}w6-}?TyzBy;+Wf@B;3rV#c>D$h+D`Qk
z`wRY_|5nmjoo?Ti<)F4lwnwg)C_kaNuei@;T&+OYV`5$3Pb%^Hztc%+k;F*m~-13x_U11{cPfa(QDU-YCF!FJxJ
z3_%guCn{hVsQc>^h6n4pyP>Wi_5RT5ld?WhZLK%1UqsD5#VL@8Kte&9+;~?
zqx?QJESjs|tgPgxGyC>zR?-;})^v6grP6)_q7W%!--6}rTb)vnAhXzA~D88VC7g{%=zB;*j4Q#i5eXi>L+cATmK5yXf`G1HyI&yU6dhSn*
zr;7iz#*z|CwVhLIEH*OmnviHN`Y3x9e|~eX51#KoAM-uF&-gy0xpU$hkjm@QA>&zP}RKSypVH6MGt
zq+RBZRW9v-m4~2Q;Ob)FeaO`u8&JQl93BqxA1^thtg8zzkhQzi^!IC&t(q{QX1`C(jzl+k+ngFVQ0M5nh01*Gz
zD6G`)f4}ATgo5&y7
z1bKw79Q)Oq{jvmc)p>WUAJ!id46sLw6>YMg|D5{y+7eQ}um9xg&5CxJDwnx$@rF6_
z88Z?RE~|6oub6^=L3#hZ|C9NmRBux@x`$(PH@K9l&|3p*K@aHNpPBer$?M8{j~(m!
z!!u`;_h)3Je%rcOe^>ASz4wd9jte!K)2DyDXBFwERs5Dtn?fSVT>k9Yrxa&*w_ogK
z@2jIVI}?&RPEfgK#?IXvkNf8X?`0b{Yyj{7tFUfjax#hoEbH#>MiSxxd7o7exP9$^
z%>UcL&w=OpJA0nT_ZQ#a8|ihE%Kt&&f4tAXSsmxG&*xi+_&Oa$Yee3Umpz;xCy=u1oRbkFvwNAP(_$_ujp8^$yDGUAF9<
z=jSX{Rc_HS;OCF|Y&}x_Nm)G+3MX#JQM^lBiG8!ASP>&)s;5hG6h4BX|JhosV1st=
z?~DU#?*JkA&tonnO)punq&-v^t_)cI>6z8)|B!v@U*7f3kt-D6RJ`;2V!c%A^^Wvh
zR^NN?g3K<@D)H+NKm713kpQf2DDmze>NpQ84QYNdB>Jv7SSz@{?xM_Jpjv+h@(F%;
zrjBj^`Cav!-KRk>$hr_2ivt|Jll=df|Cs;p`6Dr>FsE+BDg0ba&T}!T{73db__xdR
zH5KvrzmJWf_`adkWJ2rif%)%1d3*v`Uw5qkF2f*M9Aa9Az~2u2{-Ayz`~jM%{V;{%
z|9&T0AAqJSIq`LUX^-f#Ya@47D$V*mnF!{z_qGb!TC1zkN)v_n4t
zf*>pVmVt`tU9}!vW#jA=2`o5
zz9bbxA0V#$wBmFK^%eAbUiy`~U$Oz>9g>Lm5fbqK@T$6#lv|pb>Wf_1<4WKqvXQTy
z-CK2Bab}N|$}cZ2jIWbaU0ibO=0@mjt6AGN_an5F8o5NFFs`L+Q*(P7+8vD)F*wfZAev_{(OQdT8t
z&k657Y;B-?%MugXteX`&-4>He8I-+nkjXe}49WyUUA;-=yQ!}{%`W-zGezVUHhR86
zd04gu4*Wzr)co;BQlT@K`
zg9`c#h}j*!pe}GdcmY0J
z-(bvt%>R$_Ghj|(PTkI&!q4aAJfD-r|1nO5ApQ^be}!p$oj(@V?L+)GMUg!}Khxvi
zXKbfnoj>T~1MBZNk=>8h;Thxq^|I+h-j6a&2;~vzET=1MiX+r9<(hdXt&7MAfd7Iu
zb?XnHfzPU~ugOZ^9F3e&7AwA%>6W^byUFL1($Y37XNq?Z2cTczZmNo=M^U~WvGzsi
zBbX}wb8lDX?7geyvv>(a`<^z1#S+ymlD{f^*(s6T)q7Hw@Y?1AuKX}Hxbbh=*G$>e{iG1Q3oZ#J3Z{P%%^nGJD!L#eJb1^V-Y`M;nM
z>~J=Sj(COFGTCrGPnB*L;P~}*&xXt0Z%nQ~>Lg_VC2~GisZ%!8HJV12&PsU7ij4_pUSN=h_sj$WT>CU9FfYjt$zyGhDPg$RR_Sv*QpFK&v6%9Fs?GMHM|D^nsjE3zuE1a??
zL(#Wf%9FCHs+OPH6pv8$#;ArXhrWe`FEdR(Q(SLp+J^clyvQ&IJ}vhrw#WR({Kx#q
z{GYCz!sk6Xddp<;pBV)H1Gl1E48!C7e_Bvpo~hKJL-G41&COl=j49%={J)MeC-YJE
z|7A7IU%H_(7gP>9A
rMR!Jd
zUg%%Gul9_(SkdfuOI)x$(Ym5^y(2{&i+Pvtg}(i$A8&sa)F&3b$~|i?i@^EWY5IZw
z#0{2KntrSEn|eOK!T-n3H44Hs%#8F5sQ=H5gvOto<;o43TveK!D`#pO50dgnNTKlV
zFSwLk`A?5MeVCMIlX?01xoMz>EWc-4LA&g2(GQCr-O(mX5yOj|;Q6POnE#mnnE#mn
zn4^=!(dl|!Czt;yPrZmV4M&40|1ZME!qCr$8wltEi2wfi^P5qBelY(Nk=@_ma>e8R
zAGGr);sKi|9YKhiKwqG9OARSd|JM*HKCqCSDGs$Xg)Ukbisz>$?o5IFc_$N6w?o~2
zUT)YU08an!v7a>|yWcess-UbX;>z5}Z}}U7S@%||o_@@@iG+SW6$ZsD@zGzqr5E=+
zML|6xf$aXCE1i}|Cs-n
z|Cs;Nl~ee-cuzfWqYa%z+*;`v<~)n>(c
zVVA0`s#pP>rhP;)ybtyHcBBV@8UXc&3F3R%%I?>J`<$IMzkOW4o8mMLxgRTmb%=(w
z8!p58K%$>|*vk-q$nQey2pyqp2M<1JQ})YLe3uR7BWTO(p-;govUiDZIm!ckOrd~o
zfbsmlqZ3^Jq!RNV^B?mc^B;3`ayU9&uj}OVAL`f4W)tGS^S^^HBmcin7YLxfy$ind
z;4}M-GsW|y(lPtL!TCP>AFb3A0Pd%VOH0{U5bWaA7hBTOF^(Bc$WXZ+D)RFBGdB8G-?2f_R?iS8r_6FC^0$wku`pZfdl7
zS!PlBL;4kKg29K%dE$!EmisU4nH~4{U)WQm*9Dx{W^LszC0bjdFThN(+5G1rWS3|9
z&6XT_in#c=Tau%II)GUOv>k(OMBClpw`OK}?ws&b?EqRJ6ee;>GrEE=G
zy0SD+^L;(d%6_zNedUw#6;eVl&v#24F6YO)dg!XYf;9$
z#94b&%I(fj@v8DyORk-Zbj{hih}4-bL)P92p|q~Dm;~-St0e9;`P(9XYDQzR;*^YU
zY6i}qlrbF3NRA>X+xN;~j4Kbysvc&3jp_(=B2je?@PGandq!>GA6R~*xmgN*hNEeX
z=F93;;%F<=-Jg>q@9mD>vf$9{+kV@rB<;2qoc6?FYw9?af)gd&FX&bgGks3Y#dph5wDb`B@;3fSWh_V3!&0r`EUPv{HN));zH4@
z)|pFd4%Ra>x3*E1R$XbE^{|2m4S(CLua@Xa*O_)(9g0w~`9Vf`LU^L-r7pzr?G;x~
z^vlkRq`vg@G_cG4NB+7z2kHs7N9rpP|6}P)Q<}VA78|`*f$VnXa<3N2^o%B7f7Wg)
zH}{&3D^DT6^vv^boKZhQZh7b6&K$*IN-D9Xqwn{vSyQ+f#(g>qvGU2F%wJcRn#v?^
z4mH>L+n+#sfNK4ovLZ5Z@0GGeP#3sfMQ{70+@IKPn(*I=`~Tk>J!QJiU--N+&v4&@
zu=_1^-R3;2+}uXfzrvf`0ruL#YAz|1}kFzWG?m+ajqu7G7Jjk!!JsD#3bAI_7az
z?WWEPAN=>L#c18$Kih1uO3x$Y0k)~+uzr@fxA(dEZPvGq!*7}^7H`-@-R(Paq*eiT
zvU#*(Gx*&Tc^uAwI)UWR``UvKm+YqcMy?gCDu0xG@wr8rhk*0t*EE%{mRLzsdC!Zp
z_O9AmQ_C<8ct5{f(|K5*&3*aYwcuf@KB;T?;6bE+@JaWPU{-z7v2*r%66*bH-}ylu
zs{4Q1CoUvG-w;$adK{a%OSg6JU$*+E3v-$hqTB2L2e_@$KzE}f)RrygEhwKa&$Q08
zR=Nq%DcLv0-g|EFJ;
z3$Gw_1cWvQpStdUI`Q8LFU)_;e>|Um_W2y^Ls%dBG{2w8=D$^j`s{nWasH1E4i`aQ
zoXHT>q4oRn^YbepOCGKJOJ_s1dugRV3{~(+0*RXhUXtdPdQQJ=Ch28rgTbsvNcEB{
zBfHAq7A;wjIV*eXeI(fLY8T|k)gCxdpCdmk8=QB3;IR^}JjV7)-!^Vmrp`(fSoJf-
zl|RhSvz8Z;sfmeCzFo3#sRau8ca^7zUtGRq3B>!$>+Ac9As;}_J*_a*fWQ9bo=#Oz
z_7K@KeBOOTc3$|BI?6@y2itGGOqzT*<^JpFk{sZ^%42h)c)#CJ9Q;!$7xn*1-1(#5
ztnvLd))uhCItJ!YCOvI(YEahIScTr+j3;Hx4#JJ;j~d{}1z@Akc63qx|%f^*QDS
z=EkSt27X@djOS&t`H%Y88i4n4|NrplHMCBzVM{R72mG(dE6+oD0JJ|W-36=QhP_Ra
zAMeQ)$JnQRYxR#%&7<}Z^u?jhaTo^W*U>OL7VA&RW{t9}4dU-x2?p}yN%@~GY&`$2
zpgzJr2J7@B`e-`Gnxi<#((`Ne2Zedj`w54&MtLBnqA%=mP-b;uiNk75%1BHUwCzdR
zx?;r&-N6#*@1xVT_REe7znL59I}CAufwcKq6o;tSDVU(_gs{q$nSuNek`~5{^nk#d
zb*uFB|DD@3x!zzbkb&G*}Px<+Vk8%inHT_~iV1WIs8)k^7Yx`|hv$Wt%AdH-6*m
z2fZdWbIEga_5Cu9_Lm8BH=LAt>ljN=wu$5~niV_L(4U3)Kf7h;ftYLO&e<&|vU3q^Ptz=T-#3As?RmZ*^8WL;zWsU)#Mu*g
zJl>k}rzn=nE7e-Mu5>rp{TVOxtV8vF7LG*9g?xYQ
z(6H$+l}gT;5eR@CPd3k5=0kOe>FF&m45KRBmF|093cCz<_=
zod@XdqxG|G{W8G!dbHnj`T3eTkWT>B2C19DZ%{CFWpy#g`Sa(~!K_u}^7)>wLq9($
zON4a+?>m0z*Xh0&WpnD=W$SZQpE>S7p(kMeWBz|sTmf?hbLD1o1wT*I<9V8V{#&WQ
zRlD5^eAk%P1yCIzdd`YKA2>GH*n;!|;J&Y2wvxQZw;_b=;6rH%iC}+=dV9`6-hVb}
z(#g-KeJ54C4EpMEm(CRbM~kN$)y4hrhZ@ac3heRWH%)UOAMeUf8%1A1fH2Wg6_O@A{I9Jg-&i~R^OCF(0uU>`yoDeF1
zH&BCkE%iJHdHhvLrF}NZ5u_KSra95^(zm<-aex$Zxl7Z`g+2hzgAMf;er>J!(}4pA
zRv&LW06f2EbxT{r(I5TC*VmX2i?5ZJS6IRR&&|zSH%DHdl$yC9W&?eM`8q$mSbtu`
z5K(O!?C)34Eb&_p^vhB+>*(3XgISg}I_(@-|2H)J?z90G
zPt|>zeEuJz;_CpxIsoRNg>Znq-phvK`T!mF5omp&@DWM+E?FBDYGDVFe>~%BUt7{I
zJ0V(ETB<{Nc7Ofl|9)o{@KM$I#b?het)!+m5JGizZ<)4iK|D4YilI(m6FE@R@Z@3e
z+iStz<}5uSj6G2U{q!6%ZDqx^8s$O~@SmFc%Nm8h;0Hgru;;vzNSr6Qu;+x(9x!Pf
zQ154g#(m)LPZCHyVU+i;F$H!aJ%EhSzD*RYGjMcS;t}uzoY(l8k)D$2T@HDGCuQb}
zEu)8iepJuc2DwXjQGuWV`X8MTmabc;gSrBtG}Es-3CD@N
zVRom8>xID>^yZ!N$v1J}dVpzK8jb`H%UJ
z`9D=$!N-{%dd5`npBY5!0KAvCKBf=sA_vomYLp+C&e-F6fTeFxlmmTrm!#J|)t~jY
z2-*b0y1e}|_bxZzrQAfRVl3f={P|+D7W(jQqReKq9rEeKm6eqNluv)@wM#CpJVC4p
z)jGeSPawUS3l?lvw9BAfPC2swQ&Ur=kD6$N?4Wuc+-uHy*97R=<*;IID6IqpHv9x4vf`0$YWWMMwDped>>N|?`j_Ncf
z)!K06pA!TE!G+%(`g!=*%Z^?6HTNq}W&l+IE6L&E;i#2bC|;vG&P@>4CyltfOf$t#
zCb7Nsg7YG%cc|`rW2X3^FzR)?P~HJ&VPY!e8Bo>rFTV)ahfJtO*Xh0Mcm4JJBxB5f
z%zw;(%zw<~>A~fxx=*))|6{zeLjRqY^AAy*C?*tQAwEDk?RMtd)?L)LZQBwr1FwC(
zFH|$i97S*WXl%10M^Sk+nUAE)Rv(u~8GBj{^u(9+LOlR%cYh_S3&>H}V=OC$`uYWx
zmF#Bl9}Hg}HQP|#U1H*_A&3w_9zo{M_Uxj*qgCai<1$PmGa=KUZ}8Ca-bxbee>!*F
znPAp&VTRXF9|rsV+HjA56|6TT;=MMM4buKI-vH|46N_E>P1~RcL0k>JS$68Zwv9vJeT%IcSOYPH+v6hfsSy}bbS|AV&u+IH}7
zupj>ORrZrWo4}{`Atkt4s~p{|P*)r$K3@bcS5j#PR-KW|MN8vkK+w
z(W?AX@XIGz$))5c&ly0>dB0?U`$@yoB@sx|w|u
z)iDH0?M{cRolH)yPX45vo~-RK|1tkD|1tlkiYxdy(?idga{dF~3Fo`cHt>rxN4tAb
z{+}h8WgReXA$((T0B7)T{&>Xa<8l9dpRmFrBCODt*Y6@gZ>UdFL8mm3LVpvICxj{|
z!EK`!l2?une&GAy-%m&T*ZKq;bUc;~S`Nh}8~S_xPxvDaCg}o}`2J&bZZHAj^}Qk6
z(euKMNtUYUn<#F7tTBVP3j6{YzL84E=M!@Ii4IgZNUS(5ZI>++?-Yw|lg0B-yI;(I
z%zw;(%zw<~>A~fxx=&Ni|G&kvt>kIs4@Vpx9c~@xFz3U0Ji+A;mwW&{+Fumv3t>NG
zeLeK`hw<_ZLB@@EIhKcLB|~w)d=WJ&Lh*JupXzZr2ok=p9YSO12gIOpRgx+?CM%yn
zvOb9pBY9AGp%x_M^^+VV4^f{aFK?>0n`-{MjJ3uBRe`G3XfrbKx}k);P{2<6|~H_GKi1{P5%5PMn^s^Thne_CL1&@qGVz=Npvk!@%@;Z
z`*FMRzhbCOM*A~8JBD^qG)tuK7_uU1e<1?zYfH`hBkk~cDsRV-Lk8vY%(2L9Ijt%^
z{)gvb?4Lh>Kl*-r`-?KVl1RV1AKs^P^L7luc-w0=>-L~AJ^xr_j+_oB*yH<&66wd#
z{$aZZ`r&xt#KZ^C_f&bMKZtKXfBpmg@HvdfdH(ngbR62lyQ?40r=Yb}*zTZcIB}MR
z{l+-KUdU*qD*}SMdqL9vCHv9&h6ThnH*BYZ28HhU`}5)aDEPbb9I{u*i1=i8~7Z$IbPSzBB7I?4yixLl?vVK}TR(VAYuSXg>O
zz7FqK6AbNwe4uJea$;@S8MJ-#=lr@&TAsq~#{Wg~A}RwWMcUma%Y;Vy$08SHdGK1K
zuu@mUy-Ru`yQrOgg@tIlH=xhYj-f?zUgE4-Uv;#}7JTuGU+87q;@iLE*+pg6)y+pd
z&NJoZvFv8$Yw&sjxII5JGxb=+Av5LY=f3m2mCA%V|6ZsREG;Z7e4rot55NoYUw6EA
z9?}=!G`@Iu|4Op7v~=AVM;iz0fa5zsk;v~~T(UAND{IG45tRuI29chUpPQSD^cUzh
zoLc88BJcZ4em>{})cr7i$>WHx2UGx`XQn3BAiW~Lv#YKLzNdx16Z5|~o-cU2aPjkU
z9(aDm{729F&3_IMzeAzRWhF+JtIzziGM+wAp{3JHczU8TvYiCUK)v^bRKVEf-|lz8
zb{R3hAL#>@ojmE79?;~z`RDifzV8$KZwG&Rq_-)(4P@_*7W=DNXxv>nSv>l<{UZJY
zcY*(7JYOUS4%gMyp-RC*0QK1ST}Kh$0jqKTe*s>-kwuDOB9QmO&?1Gz!q05!bjb2@
zRrxGiGtPep1>2{#bhaT5=c7Er))f{4z9%nSSy-4q&VS^0ShVE1F61}pJoo1B#`wQ(
z!v6o8pB?cZ@SnwkUIOj^=m+}yMEQ22=~yI9ktz@^de-Bh@?imA>)Ex?~tK&+uxIIGJ@aaP1m0)WNa>Xt&yi+<_&`$
zP+Z~+HeH#l^PFb;t-M@jGxkP?Rv`U|NoES-vYMekS~iY
z^>UWz_5kXC$4N(&Eh70YPZ;&BBa*A2eh&Gklc8=O=?BfVZIGYe$P}+@gYB5)k?rr3
zl+DR@!}t?Rh7owi^pD|=3GS`Gj{go=AE@tCax&s-;R&Afg$VMuj}rTb=ExIyRk|;L
z{r|-U^XK=D`wNi$4)(wQ7$+YWj~o~B@&
z|Bpd`z&AiaKz4flPF^CaC^VT&*W2ff`TY;a`JajW`VfGK$1NZL!LqaEsfo3Lcb<2|
z`wUL-|5?x2en)zCQJfe}kMux41Rv6C=E&`!03c2u9ccWUelc-9ZiXDIcRWNL9XUFJ
z_J`yy(DOk3j$AKM{Y7zKai7b$S}_A&uCiKV_xA3BPb^XWANK#>Hu3$B(<`Rg{5J`9
zD(3&qwf~XbAB`d&g|3#WkzN1B4^_Q9{cO2C5HziZuC2~!Zth{|cg}3{@=*VjLAs)K
zwp>J{`~3b(>NXi)KuVFHpt(C7d%cX*XUvm&UWa)I`nR0^{5`L5Jwq)m$S)!aRA`W1
z)T-^GN&Rbu1Y>IN41vJwhaL7m*9eWUj3V)z!^Qba)W=eaof1Hdv?E9w_fc
zdIGAm&mLRPx2lNDCK;xM9v`QVOYVf6_tez4y`PVn#d&j8n9+~oy5aT`s4)#0Gfx_x^mws(weANLo)`+o-h>OcaAWi=q%
zWV@*EF@uc|hnMmEG~MZibqG{69a4i|9zOp)Y?lb~v>Lb#@?T+psUYDvA2^Tk^Jzr;
zJprH3vyPqb#CdgkA-(|bqwQQR%pi*Qqy3yM8#~U#-}6|>_}_Ws{ZEP>fcbyx>g+#`
z!?)`5&)dF!l)jA4%gH#-#PxyE;SV{VDc2Lx
zb!ud4S6tai>O-7lRa`=U`U#n6CG|%w4CFi9K*Dvtyfa-NA{amV`x-+`>Sg%*dSly%
zUoT59;a3IC=sK3Oy#<#Fq0g-)Xu4D=B9Q;&JqcO8XsjNSr{c1b2I|M(e^imhg~QND
z|3dOY7C~H9)AVjiL;#+6u(}Q5sjE9z1buA;l6g`Ga6Y4nEgR#0@Ae{C$1d#@W5_09
ze|EEGp&0F#rW4|_fd1fk;{Eqz{PRJ2Y&(!ENfDQ5^7xCWJ|V{@Ame(#yu>5O-cPQU
zOjP+%RIfnyDiQoyDtXu`C22>GSDz~zkI$kh)+y37i|~RXye}>?%AP=
z+nWH2ONCa7usF3(Df>i$U{sqT7I7CpaNnXGLzmS&c(Lp|&%=7Jx-@xJQa-#MRXz#)
zX^O?a$9IK!`qc`8;6q%1r|*yW>7T)IGCXm8pv1!X!sE})E!G2kKJ@noG%6LT53219
zQ$gx46*4UhTn~tQFi1jNqdt8*NHzHFE5~K`xP;GNQ*#(w*ah~zl->q;kdPXs6~{R_JoWg&Mjk0$^K{5dd>QCZEO^lyLHiX*NC)yOH2GMFI~0+U
z46kRL&$mq--JPH>VE$wNWByMKXKxdI=4dhEeT;2#8Of4rCR&O7$M#TVJP*$V>!9&~
zPcR*u5R)Ax5K?&Kji0^@Lg_?!73?XEAM?SyO*!u
zv6J9rcU>w(byQ=#515^5ST{X5s)AMAh|ye?WbTHIT-xvF@A0>B{oV}zcUj#*9-j{p
zXWFgP1p>5trdU-Gv`b4iCehklOMKNgKOIE+0AJt*I~OcSj>Jvso$6#p(2!HYsQKyX
z#j72!t64VuyRqv%8vVHIe(DvM5$xSvE@O!i;@Y(zxBbU`j_MT(O()
zA7Q^LAM_3`CxJ{wdO(JcjiLAhCqW>%6S#YWJ^_>B-~YJdVE$wNWB%XK{2xL*O0JG-
zTtSv%WRj8|lg`we&<5
z9Md`p{;|lv?pM`YhzI)5sI}&xg?4Y`s#H#Vj#b;8m$ksn3fz{0whO*K6v!R9-@M
zZ%&DB#k%z_6c@;Fd&YVFcYOq`S89R#b*a0q)Ryo#gk{r(T4QeBdivw|{&An9>%GOW
z#e}Z!4*{Unz(;Ur=vq3flERME)ZR#=k!Bgl2kIz8vS0{Fg2?Y5lPo&~<9Zk$6l$ZV
zEMK;+;D)<2`IpoyN#I{1=sU_PCJJ%;i&+6(G1%d8{^$Rr{J%EN|9kF_NfqFrxaWR?
z(3k?2P2>u$+wFd3A*^#}sczM#!111YZozXMWt&JTIA(^*7VGN)-5ns|9AZOdYavcV
z_=n2&85@aY$50vkUFi%Hm&qS4(f85w(r7#=)R+t_P<#NE)AJNj31VBVqz3Vyl)Awm
zU?qv_bQjhG{_(m1%zw;(%>O%z|084ey)Pr4AI6Nv?fc;<_~C&^!;xN;cV8G9j8?|;
z?kz#{DK&U-?IG1_#YQf;5am`gp=dErzff$k8_d6HuS!aoGoQ}x-I;{u^_Iw>+ARUo
zm;Gapq`uG80~{nkFJajng@qZUy^-%3t02+udG>U;vNFGPe`Mt=92Z-;V+dK6E>BP7
ziL(}tKzc0l?LFq8o%rtAEUwCI2t3(al~k9Rn2_8Bae>y-^)<%V)YoEc%!d5t-dGsv
z0XDv5JU#*0+wXDTh`7J&imPlzUhY54{RzFmWmJ>|gNC^MugTTqJ~hUFgRp%gH`NiQ
ze{vSqg@d^KPdg{%d03~Gh4)Xyu8Q?QP0Yiq!~GS2_}+?&aNz(4T+ob(hpL}H*9AU)tD#OJ|J;!FW9`{{z}!xZ@G
zW3=`p*z1IgrE|a^Krj&+-7WO@>@$K)XX&A``Xm^KhsqwI(ECGW@Qt_xj}GI5F?^G8
zf&PFz3h6LjMS{9ic3dbTmVE7{2+BX;@8ri)AiuDya{IMI;17_vnxQTM^ni4JE!G1*
zyB>h~kNJ=JKb`sS^8s&+qAI4M7X0}{z^p}fxP4SrfcPBf*%3)c{_%RoOzJPnEY-ov
zYVe;E_Gra@VBf=b{(VLfp`v3FVS8axINStvP#tAqseseVzT^qlx3>Og`%JM;XEM*0
zui!R&GBc6hAe9I>DE=Pl-4Q{@iB@)lK5?JiVhI3fEMJJe`kHmf`Ys$R7}>py^G(uUA+RxT9FD;K7w`{g(g@;6zf)$>l@7lxn?cN#Howc$Ux0c6o*VMu
z3ni|jP3XD^cp09e>$raiGy~l@_ebGJFv0JCR3iQx3?>88xAM#L^Q*!CZzwhB5D#f^
z0DRdBvX>#^66}9!4~#)hj2DAn+ynOhvB=sI#QQ(?tRhjKq(dg=W_W2ol9ni4iTvxSj+4=Wz{_#8g
zbIgCtf6V`B#DAZ!$p!g!B3sCe^1$rOXxyJ4d`s&`9DW>l%!9l!2soQ~`XZ9BgernC
z4_lm3`U1q8gJvxqpO^jKWlw-#9@+Q3>?YFNlni#c>?|qZfIJoflMnpwFL_$Q5KFRd
z)ld;pcmr#
z93oJ9f7k9Lg1b~J?h1cKf+I*j7uG#j)#An!Z|9CT1(ZY9WFKU+v-cC$@c
z7YwlH8HwTx$wX(Ku60fC9B~Ht`F}s;_dwRzefuNS9#b%20X>GRsxTRVw_Ls?!@~o;
zhr>zWS+DT*$j@)RQXIGUS9O;dTi30pQQl(1pzGKFDDSWT{sjM#pT%Gp4my=tT!X39
z&{3AfMSWksY)!Jx;7Mz!Jzuu6P)I!?{~5+%D3o4X0`(Ai`FZ=n?*V=m>Bu<$M|#9u
ze>gLhWe-zyWvDeCSND6C{N<3COS62=JI@1eA&&3`$AsKCKE7VUeTVI6H*8lqZ20jr
zRY~5=%*>I&rL)-R)vJHc{|P-{EG}@>c+dSDUTPik=QE6}aZHZ+^^x9y#-kuR%2LFo
z@cbN+ZREo4Gl$9s)Z~mAJQNq$VCRZZoIurL;da3LD$pA`%52IpNh-!C=S2jO+5Ez}BJ#Kp^gABJ14#EW&qQ9}Es38`cl`kKAM+pc|F-16uOyzA9|7Jg
zN}SbE?O2{(G;ZGqS-Jr6g?V|vtN_kIJviivwaF~bptf4Mk!yj(d*D407^OXbKwN-^
z<1L-5$grm=xhIlj4L9*QEF1B9)6w(a%O-%S{oZrX6R}uUw2t%)sO`G)d}JT4@9fM#
zet)+_kbrpaIvT0~zk)Kk8r6~CrvSSj{0SniDKAgm(n%0r;8sth%bO^$RXxy8Dgpt6
znE@{6_4xfK&Zd$xW@WP3T@7la2c&d4q3R6s1l6P2+{Qg=_}r=7avXKJ1R|GC+q(?J#kk(udfPW5w_
z#$q1e{-r|X=g)@yKw1Ee{3B$uzuN`%4t!U}ht)5BW`DpK|A!6f#q*?W&J?DiS
z&Jg{F=U0&gcLeIwQ%U4spO8P;b5KYSgY=J|0Y5xg*uMbY6V)T&XNNq#s}=sQI!*{P
zGo^yNBKfnf4x2_livNi3=Q8iPfB*LG?bqo6hpyKHI?7U!A76Kv8sk6WJnA2F{dONe
z-mF0RpeVk8@)3*3CzDW}2#NzN_bzW9?~{k?0zQKu4Sn(A2^O1cI
zS^7jUSJm`oE5z-?Zpj1vGsQG3;k*!;t9MI~T|d&}=KRgR|A^=9yJt~7xv)J8c%H9$
zNFn9|&l6F;Ih2Ljc={9)?0oa13KT~;2KD1lCW(MIbL1Pjnx5yN@7W_1;6LLSaJjX$
zb;Tc^FH8!W%GZN8foFgl;_P-OE3FFH<*LG2cUld;zWX9&-JTb
z%-DEk7m2ukB786@Fx&(60>>e)j_L(oQ!}}MsfYTBJkUSj`o<)JMkDBh+F|HNSC!t7Wmw1YV}UqwGJ|65v*tkY9T&JIib~TmE(N#w5Sr
zPlU{QwA1NSO?>`IrC{e0Iz2s|{+Dbb3HVR^SwaY7u`sccTE7?_&nnycRV*j(I&A$a
ztb;_;#Qo(DDH|FNI6raUKk%=``viVe|3A$CkC=yVjUI5b=0UulPp3B^zrHhQGNHWj
zVN;hj9qPszW>5`v^I-W{G^d~s8PRHjx_J@T64GebfW2+53`@V@fP5^!k3Z6rCilBD
zAg}%hd%_Ijd`qWP@_xJi`r^2wDjA1MBIFJZZD~?PjXA85>j8S422AZ
z)yn!Lz?pe%3Gyp=GPb$j7NI!pOP&-loCoCdHyUAcKFZ$@7)-$~@7to>+={?S@JH17
zd*6h9KBPb@O+|T!(EiV~uuGpLn3Wke^nSkt`2)7~U&*SB2JPq1W^?Nn35evbi(v0x
zeWSQ!6BUe_%`1Nd67N*$DX%3nWK%a
zKlVgBlVLf$w>qEojOht8#i%|o$$CVFw)?VmET7;Dj`}3zmq+=S@|E(H%$94*zN7pb
z|0Cm^kHo;q={D>f!A
zf!8RD@(U8B``Lk5H(S1LDcc_#j)iHKz5m_1#DxFX-rI+@b)ISBC!*=-qpay}yag6)xP_e|~{O;#S0{lU2{6VmJ^v`Pvd~`VH
zJ@@^5-Ve?L=i?IG8{S;6FUR-%X2na{1vlS(b25&RsUiLk_yPgqYt0Wemz@9U{#h%A
zH=W7@s4e>nVQ@c+H2L!|qG@C&?ZQKUY7iq{Os
z<78i8f5~wg6n?(zFycmh?~1_#uffN)ycB|pT^6pbG=ge
z^GZK&(&Mq)$D+hb&9*S=_dJ#=w;)ixy*1_%jso}0Xne!89KmcIcYUe`{NEe2^&iYr
zYrTo!XTx3#>BNNPFTMiR#Q!PZAV_mNYRg}K
zDccowmQlRocf;YJ$D;7R?o}l(ZjbyPap(dZ=Z8l|EU4?scDrj-Y+{y(i#>-qwwS4Y1zV(f8aF8t9^F=#7aEa%n1IPb=>HU|E|D$T7)ao3IQhvtnu-8uc
z|0lNSGP=%#|2tFu|Feq!|HUN#o5IjXB>w*q_!{~DP(S)5R4PgAKS&kyw31R%a&@_4
z$n(QqD|eblHolAd=o5E0ty4!%ILyyKQ4Rm!-!02Oe!|t(vzsFDh<7|%;meKb)xM~&kqtg7|qt##5XX-VYt|pJAQ0fmU
z`qHWa=qelPrJl#3lU&y%?;Agvx*yM_?+dS|`dP%|yZiUWi0{Yy$H(bC-JA1SmAHO7
zzJIQjCe?gdpgJtuvy1D$iER=$6W@jl`T%x+a0KG
zm3k!d$DI+kKy_u#akoHv?m;=`{sH3gg`#L)i~4WX9f8s7kDy`-dbwfwyI=~PPnLH;
zUq^RN91qJ+`t3OW7tyb7wU$?)K3|<_^aUsn(blEYklwsK>UQ0jiv%~Ufq$Z#?|j#3l}!y+PwGL)Me#WI8WG1vZSIu17ndE_LRqhenf%t
z|Nellfb@FwgOL#{pYH!3whkYF{RFrA0{H*iB@`#AIPwc+PD1u1|9_^J_@C;hm_HsEcI3
z4751JGf)ZO(>M=eDVex&>AkwuYKRo`ec
z>0k&3%#T#!j03kM^{}KJsr!9~F4U#k2lM?n%>Sp_tCyNbuhiqs_kFt{&ToM1@RE8*
ztV0cZpvFAW<3{&dO^b7UP>Bzihx(}w-!U%5sPEnx6%Ze|Q4d)>7wN&PK!4oUJo9@Kt03<*7gbz&`re${Acddu)GSyO@3sBeJnzKc}05eWu@^pM})-5nZ>
zLSIl-Sk&8&%7P$td%leNf5iDKJeIHM%OoM!16>_SeTOvHm59Gko!7P1lweZ$I+6ysFw-$0vg8)QeGYR`VY8fKVT>
zWz=IaS2Vha_l;UXP_AESN0ArTv$(I&aH;pxnf(7E@xT4?reyuz()N$`|4Ao+@+6fb
zcb~%ld(iDz06{!i?kpV~jI~l9{qp5|L$~%myG*O~qTWC0|KHmCiV_F7wHNmraRB;x
za-~iVdjBnD{r%H<>PTeVc4EuVvKKEl6?`~cSK3$=9lslWp60T(Yw3S2zTeKHe%QXPr#kHc|eeUkq_k!QM%>I|L)|7&*1awY6gn2yQ#lsUDg-(%f?`csc>
zKl)E`zF0q1GZ?9JejEFGY+|p!qqKLKW~;ZJ>|R&IVy0?P;f0{6=vd)8P@D{^1VKf&
zTG0AR&?mEKU?f5Iw0ojO>HjdqgOzmuwSE2}x?e)4A!Q#doIE7+|4jRLVSj$9@sN*q
zaq$FtPRDom?gW(C
z&n~t|?yd0SixM{L|Aqgj!d%_kkKD3aTi6#Ij`tznF8L{s55IXbKCnN2Yp*@BYVh;O
zGnmUZ*^$Sle!F7o|Mz+e|0Ui3Px`@C_&)lcas&o;H{}YMzCfJ(M&u2AJL8KsRYhFF
zJFp87*BHAdv?Z&%AX9Z?2+H-)>-%=oyV;&`S^VT`^b<%UsZ|y|mKU>Cg?-|d_o7+y
zhtCw`%3o=_MrVlC9NAjB3VDHd;-9)7Wro7e_+OrO4Mu9Ip1s!LG(T3lO5JTLDtz|W
zyGl(vDiaU9_ZrSDBlCd|aJ`@_3_YNlfKjWWeK`hFyVU#h?EGJAe<;cSqf6U~rw!u0
z+py+J;y2rqe7&?i$i>RQG^&x1u79F}$x^a_POe6?ZQp2IXGp4VsMFLCSwc>{by!
z6#_WUBlx>phK35BME(NxsHlfU{|f|)Ud8|S`9l>nCqjk3kE7KzDPhcf)N&Z-w*>kS
zR9CArl3lGU#vCie-2`oyF|{AA`nUk||H9_^ne6#XjfZ@^i{t;9u3tU)Yj2<>PH_UW
z)6+)wK+8llWe?aqqz8mD!U?hm>=DEVs=uPQp^kv+_eH0}{e9s4-jLb-W8{GgeWT*$
z5$Nj~WZ*nH%e0g)*zjgm)u5b>{JqoBSalQh|B){SZr)U)x>09L^MC4lWU5mj9Uh9e
zKkRfw8
zr})F3y_r-efc%0Adc@Ev@ESh(TSJX0*gW+84yesbFMdE>=lEm4vb?x_@~8&D49U=LnAW<&*v&~6I2ffzD`KcGjf5Ky_TM=aWSZS9QK6#awk^k`Y7xBmgM?4>h|dKd$-ZLW8_mct#y&XXQ3N(aOba|{v_rQ
zsZ=jI-hTwgE*_{0@ihGKc6Jz@Nn8kqsv{aYw
zbdf#Kz6|5_U=JW)(CTsh=}z>giOwkDqc$Om@c{H>3j0Ri9;Uu}M=Q;Ny=~>roun&R
zh=8!d{{w*m(zzXXjE_@aeO>IZMDuv;wGr1Y@WkSv&FVe!H+hA|%#7cSd%n_i3~$f&T8%V8BRt?$dV})*#Zm
z7`(L}I>3|{Xdm@9AulkP+DGS{6L`M+Ej9nAmf|uMhbj(v;BQhKoci?r1qJ?!Bh9{M
zm5|sm5(=o_s4Ttihi+1l>K2js9|7*x{)0W)Y{_h|CBFC^Ww#>p+H*}=sy!W5=uQF#bJ68|3}{Hd^A=fFR{R|EpK^uxj`+7r1|#;0
z_4-`l*L%z&%>gQhp@^sf_+EUMq9tN*6#5eAH}xZ=ARqKo9SHTmAR}PkiT{rXfg>#6
zsfN7}q`3=0e;@i$Pi*lc0Tjl0W1NBT)WM!Cv(*tjfH;B1=tq_b%2AjH_J|29&ym2{xZ=f$(M__e&lzO+8@u(}AFL*nW^4r1N
z9*bj4>Nr~cz%pwLn)0Yu7r`&R&YW3A=m4UAU%$v;0KX0F
z9Vo7A($=&Nc(ug0VyhMU1)fsNc&zTr;ZLf=MIh`DBGb_Ap=_?UFcGXcg3L7%uf!X`
z+fmB@R>h>C9RJ6^>a>IZD9hiNr~uv%#54bj@_-)V6$lHrQXW|F#GEuo&m9{!QbTI@HkIKhy_&1xQXhLSEpwug}m)c9HM>{@v;8dsDEh$rL0z;5+bWGcsxZ
z57_~iYX0vV_`cTGZ+t`H|4oNBL4_Fe6RN5jP@h@g7om?sc@A39$%%D@-X9m?pF)=p
z@%N?ec#pNA9(@BgF#`-=-v4*}gI@EjdC@xiX-{9n{pQvUl=@;}9Gi2q490dWWW
z0oWa&eB7e9w)`9u~
zJ>mmV#ZN~4zMJ%fTaS+)L!DfyGne86f4UQXI{FMU@@x|l)(7hj#$;_LNS`d3m!g7b$x3~>OZI7FZ5HX*=LG$_uQa_&^y5
z=k(vZkoVzdaNWTlW!6KOtNfc4b~n{YKCq1R?9W`Gucmx{`udv{qXtw8puVElYv_3n
zb?m`lvGI+Kdh~}n8i}Xs9CdYwk6#l0$5n=Zy}0`zcpCI?T)K^Pi|zKVrWdn)KBJMo
zPYfO0M1Hcvh58ccDcZ)P0@)v;&3e)EhY5qGzhEWce1fJAhpV9<=trCZ^^i*Zhvq~J
ztHRJN6x_Ae``-Lnw!6-1u0+1UjNjWlqF$ZUyL{@PQHcx8gzuCL&(}
zLxB2fR3Lt`v;4tk|Np6R`H%a0csJf%-_a3u
zc+oG7zIef@E${)_xK1Z^rx4A=FEiVgOr!
zaIrZ)s_5qi`gAI?D|U?_)86#8rmD7%+^>YXnpAfq!wvphE83hCXE56;LwfWnIL142
zDIabgcL}5$jC6y$ZL}u~GQi?L%kDM<1OR0CYveCe-g(oeO(&`DPz-nrsgF+dQvcp>
zRuH~x(Ek8BQ0$Ok!cX>k|X8LvTL5AN2Ll=DLHfC+(!!{J)v@eJg(O#zsTEeXvve
z0r*2~k%i25ic6ep-Iw~keZm{`{}Ph2`ir!#%=WIP@K|%p8?fIRYh#GF9JREzPMlQc
z3m}g}eIKIOkCk{+O1+=HCO@b72=wz)*I1IrMcMs4@;^r8e@NePEF28h)xW%=;1_rF
zp}(%WDz>QTgDp6(%EK=jpl=-O@#G$bu9Fi64*Ab?T(`^-WjiQ2?F|7SD^3JP5r0-U|EHx<}eCnGcw7JD-QT~D1C#S
zh5AdeKW5rDAIIm+|L40;7RK*gZTown{ypU9cX$pv>cH<2I|c*X5C2URO(*Vu467`B
zx`Ni$$@S05=k)%;Qn6AN{(S#eOK3eotJo6pSiV|PY#Na0cv@X1baU#O`tm!^(9Kce
z4E?A>!1vo?(H_Fj79^|{yTRNVHPlBft^28O@i!|h@Gq&Z;Fo)Tx%T!WYxFt@)X4HZ
z^^wToRyFDkHyt{3km3%-h(DA5LBJ~+=s3aVL{S~tA#xw=4?}&TuTV?h>+hS2^UsI-
zPIkcSI4>l@C)cixuQ$o))1dQpVSpT+Cz9Zb{Xr{zF7@w@(K>;j)9R)9D5?0=8yh>D
ziuwlddzu>P3%OI*^^X)MXpKpow95OWe7auY-BJ(DgGBiq>?Qo%gLndToXk>BC)K~3
zC!($cmIq5JWhp{)mu&d|&}Yg+AE}^4-@d=FO`!Qw{#`Vu1^%$HXwe5aA74RW;26HY
z41}5dep^&ubJSvlZPf8nmzI64HENnv-ZMFb#y|Pt~Bl
z)QC$b!=0auW6u74JV1Ra{isK=Iw|kbla*;K?xpLgHF));&)HR&dDX=MnEx+!-&|e)
zKaDfI&M!ayeDB9}-mjYC{l)f%S4&YQt$Ly1w)F`^kMu%A`TAgwG~?QjpNsjDw7ubX
z_t!?yd)ClVD%vV)DgIyVZwYoa9k8f$nf}yyjm>m^#9uZCc#L$7oY5%pMacH>L8V`y
zHX8X2botP3KGs>1t|eljFz>)Qc0H9m*d`$*iEn_S-)
zlIw0-@$(q12P~xHK=)JJ?-uIo4K@F7qb)-AmCY<0$j)dU?L&SCb(GpRrEd~ntJpK0
z1F}qdd)2Xl4`0XeDtBX!5bkr_AUG+0vH#a{%X6p?k)*z%4`2_9<6C-(NB?Kc1-rpx
zX&KM;998-wPT2SOslTrXx=|;#ppMV+;qbfJuCWOl#UmVLLDTI=)~S>Ad-rZ@#rY1S
zFVSqSu)j0>iM*oX(Vz_fAO8Ae|0+mi7SYV+pG^k36~zV!Zqw#9nSIqyj-6vP~?_X{Ed!hV2lz$gGBJlSyH^4q@+kHRyx>+o+gSY*t
z!`t3qZlJpO?F}2&3u>2rd&7O}$z7Ux#qV_p!R-w{ZRpAG$^R+Y0fR1KL&L68?v3vJ(@FUG;=O*&29CcF9QSiGJdV-|?L;Yjv
zRjD^n;{CrUH6ox}kN+1O8ZD;yw{Mr%vrz8qT>qU^zvzYcO=}0dY5M*lRB6t19`zKz
zs5EyIKf0n8+uevec%+!pcM2Z2DtRM8TR?W-BIJ3zxQ}g}Ug+|mKcd14U8#&bI|L-2
ze**eQ-6C{}p&KwE1~3x3Coc8T9@UA!AyCMU7dz}*h`ou{xh&isFM
z^Z9J;;45_>FVyoU-gk9)?CCgv1Mz-k(3tl3w>R9@pjYL(i1#~VJ&y8*L&aL;1y)q%
zED@wuF}cRECQMY1KKXwANmH&A0RLM=@Oz)~{~@rxz2OAn0WR1PuaX^rIR&r-b_`W2
z^#t06-xU#;miSx@TO$VWfM|}(R40J0!|>!vpEt*4(q|DzgGJ;|
z26Q^rG4Rsc4mrF~@Ao|UyIWz;)k{*$LcEVWyqR>N!26CU^8F;t_aN#Keq|L!(uG2w
zJ?1Y{r(%YNc;6Tlg9hXkayxpeH8s#Pf}qcvn2&5W`;AoZH#$(LrTV^)uHQ@I_D;Cc2FRlGD+x^48|MBDrCgc2wPe$xc^Fzt}{$!kA@%K>=MZE3tMCp1-=L&Y)}SPu
zvL+-q{hbB64%ESQHAP}G`=PuK=VBkW+Q<(key4hXT5AjZWYW=d*HV3-%Wb#zq91_z
zH{q(E@}l_*)Tc@MQG!aVr#=XGBvN&JV_TLvhFXI{A7LH>)?4Z`l)Wfg+e%5
zsUD8^#nkm844JFz(TRFRDK@@e(Z_|KUI+i(UPgT)P~-#QAAkxlXw=+;x_#=`CyYDW
zD;FOk{12Ue>a#EKAFak5LL86urc8dy-#65QXEW(=imwzoF+WR-=eUvRxX&{qh%BRgexe0N&}{U?8qKGXkr
zdgqfgUqhqI&>aK+XF~r{x$cR?=v-a@%l$pf{};O7uFn5=x%V3%|AKHF^SLR`??#-T
z{C#WaOn)D|pZ51VJc#q}gTH_H6y8T!_8ETu>3l!a`*b{D1M&ud(*W54`Px1uFVLn^
zX}33gy23t~t`D%-mHL1kLn%Apqw)e5bUo&b{}$?gRrHY5stD!lDX(9Gdj7GIiPodl
zP+kJ>qkB|{Y%(i4J)6x_y1c~QAN3;jeIx7uvKJ0DkG4Gu-R8wXQGDv)OW6pwBW@2}
zsEexO`~A~ZF0vn>H;nvL#gXc)qQ245%_Fa@h+q!%z1v>Owt@He$2*mJSXusXSc4Om
z<)!VE2YBir?2<93?N2N6)VE>a66Lq9$Kc1oF0iZ_-
zL4gf#wq-@3Ge!Esl)rcY)e4x42>!pRM5oc{DE?n??X?ATe-g5sm>2iy66_b|f98LB
zX4B8n)v~Xz^uI&l{SNf+r{esl@_r%e`Ip1rPuBB;_wDzse`if+e&ipO{Qd>R`Dfz$
znLaTDKDVaDR}|Z2NWSLuwi{N9`I+SPH-|WK>Y$cC=UobAj6oRukw+30os#S
z`hC38&Y%4Lo{qLvN}S(n3mvUKob8G<+Izu=6(DfJiVJyRnuLI|zsx=Uo~)wcU~uz@
zzQkVjV%I(Oxv&e&YtzSs+B4<_c04)AQ9R9yN{fWE}+FUNFv^r~exZ>%`k%oGoPop7SAFIVa1~q7k4@}wt`-bz>I-|c^
z(f3#EfRD!MuuOA_T~)Uq$x|agW{w9)7tmKY9ADb*TcpDrfLnX%=lkRDX1k-~Hkv;f
zoiQg(pSFEBuP0j*Y5w7mg#fKneY)i-Dy4Iv%?{Q%WueZY)5LcH%T&%QhDy2h#g
za%7<1LG}Gs`xyEtW^xkcl
z8yqPwdu2tg@R^?kgJBtZj~Ru~^?%<|j)YNGJN$I3wKjb$n)|aD2cr4DT0PYTH2acu
ze5c|y&Hbgk#O+54^fVv%zBi#CI2tJ089!E?jPqkofRfjLDVy^8i1sV_i{yC*6VM^X
zJVC#a<{20>)B@=$k0#^+%J<_iTI&1rb;cB(#`$2Mop!%2+8$y4KXpGX6rP{y@4VFe
zi;wrwxSg!)gTJrT^*PP=Oy>7rQ|gnpH(b|nO}?N``qR&kQ=DJh6Kz!D{0>_S@iY4P
zyl3+C+57q~{`bKDc&!}BS#B)$V{TvIQ9&Tx{^4iI&mR~$X*Am`(fcZkmuPi;$Oqh4
zX(;sdPW20*PVkg?0Okqp2!>CM2TX8%z-5mIpsrt%>W*zGso!1rS|jEAwNk5@bQYqr
zS)}-Xq(2;_etnyBQ>&(?cNy-R>p|E7D66YY&I=OZb0=SQ;8oDI>DJynwcn=`*7~GU
zl{@Mn-ba`na}F_I2YNbhQNN#KEOOocm$K0gD2Ac;Ogj6U(f^0C{lR;;fsgS8>EphJ
z=%;<^$cX6kPbERKI$8*6Y@SC@jm7)sK^dFIzDmH{5s$9kNKbZ
zpPsd}Juu(*>s4}oXTe659cpo1hmw6e^~9M25~2*588f4x!#H
z)yI#yH-EZQ5PHl?pT3~=>uX-EmJAYfa4^TAC5|~zy(=71_piwgXtmobP&E(U?=})E
zlfV6!rwgE`6LrwMM)>2wcFc_q20x5YU%n2yJWJahg?!5p#xnvNL?6;`2|SP9O6CNPWPZ
z=u=U=!RQZ~KODvcAiGkY<}AnjlWsXa@oZs+ZkH?%90|7>
zFhWLI(NaG!g2H_9GOYNXX~&HZjKp1rAnLS6GEuNKxv%5HJ0pXb%l@rHi%*_BIWg5Y
zcwc3HC)oo^zkqkDZ*W>(pt~j6FOXq0rLHsE0T*cp(EPxmmcS1(+x0bDsw>Ro*RO33
zH6N|Uq+R&Q)bH+=Lj|9&$rWUAKvh`tNY+45ME<`gTV*H;DEfVaV>X)C=Z3%iI{N<2
z-6rF$z0o_38LFP=pLjQ$gaAGdJ->43=^TZB4VuN=p&RooV-eS%Fz3Ozci55DUXX`2
z|KhCnXAw^rj6j7)n5d{Q*I_>N7IAYA>G&2QE^z&k$D8aYVw)RKA80MFFk||pK=A`j
z&5PNj6HU6o!9FeK8F?%pNcs8nxpmBqc}DBhVuv)cb=wIIa8Ce!st&_|c}p^9|!M=>Y&t&MqV
zA=ZlHVvZAzLvwSt7;3`8p4-BTZV>7LgUVcLl}b-K(L?cP0;CT;
zB)_ksd_`-EJcc=h)gMZ371b|_Vsj7a_dY503)_?Ng2*-=dsLtvJ)CEu-7U>Kkzl`%vugULM?11oSXoJ!>SU|eMqN=k{(GhZC
zE+Od&PU#3a?KH2pc(k(ljg20Qpw$#m9kx6%e&T%bZQ=c%lGl$>d|xuWXr~pr_TXny
z=5sDnd*;`iXo{JA
zT>F&ypZTBp|I$ByZ(#1KAzxKZ_3iM6q0diqdAf7#4b$TM;7#Iv>fbL{^!g_K{aNeu
z&YgXb!#fd#ROYAmr8t;F!y^+)r3bx!=dD5i)L2;1m0L)oebcMBe
zrR{)Z-=Ncud9kG?;Quki16*C1>3G0`&kOvv33Hn~*0Sd|Cg(T3ky^F&Crv6z6ty)c
zmAOu;W$zfZUQs-`<`ep$*X61_GP1F^Fr)4IBkT1pchvcr-aFOc-{9^h@Okt5ZQIwc
z%QE^+y3fWB6}SCR6uun
zBJbbY+M2nkzG*=6I-c7&eJ&5h`8!GjD3GFge46~Wl)o=2dVPk@)LfplzpwbsAI+a>
zzQ28W&JwY?Wk^|vDy5Uq=WA|mmT4VosXSx7eI~7m@KDVgm?h*0^{QgE-&z(zSoI5zP&lWd>~<5
zyS5DW;`29xP#d570^O&$>J4R;g`6c_`2q$z7BBf4t-*(CP8z$ri}Dqf9ORka+L()e
zxS&6)eVy8$slpt+oRz|0t$oi|a+Z(|Ue1yqeHO>HpIr0CYC#w`o?KJ+1tHgFKWTgk
z9=R+A9{>GkrC1`vu_sR`vpT92|GdyQO8Pm7GX%f84RHqK?QiXU-GX`m7u5+OOl19b
z$;IgjQJ=mMuLE_4npWA0d4whPT|ax|XN+I7!!PE4=6~XS=Kt9}H>cywv5j{(?KVht
zN#3`H`pDmJ4w|Ow`KR>xlm7lY#XX(TbbcQ^jQsuu#Q7(70`Eut=)>RqkeKkQWLi=0
zB*%B0bq$Yfwu<-1TtkoJ|Cy~7XXF3<f??hk0Xt#;-`Qj)h!q0TP_>PC^`|$nW
z5?f=g;pB14&&B(v|2%023{{dHpvB-8Wxjwe84u{xY7N^PewVBdNX{8TeZXU-1w+l1
zZ)|)Od4bH{*U1i$Pc9fcU=jE~=enHhHmu26vi1*azjv)AQDFRm&qw*~%1DR14*E)!
z$H$|nztf{$-}M7@>Y0$p|I5>PYFBKt_!j(bD|GOeVs5TcCkXd$%W9WD9QeC?w0ZqR$X_GfI5B~^l@|5xcpwnZ5PS5V9Dwm+D
zz;r$8-y=01q=$^6?{!O|wylop^FjM&R2zQeoFKxYk9vI-b_3cCPzRWihq^<|g+x9-
zI9g2gA%8wPwqWl6>G*S@@0tIZ|LJ*S{=YE(KenZ-DJ}Eiq=_a=;XJ-CzY?#KZ2h#2aqFaZPyPxFL;B^LpyI)@jE}9iRIDrEdDYRaL91
zZ+IqWc{yIE^ZWU}Puc;<3rvp(D0zWozrY6A0Td5N)(JWrY3{Ib@6gb(jZsU7cWY`s
z>!r`bBkH00_`{Oh
zMfG`(Xw*%8aKY|_6(bv~vvdfcFKvhNPDj3eY5R2zF4y3yePmA@Dr-4bg8ScF@Pn-O
zHG1&6KzezmkhPrDbG4Z3xMSp=`ijO#+X(9aLS>d(S+34PS%6=bUs*x(AO82#;D6Ky
zeyS#y>ip0L2;LSqMgTRldXc?=xYJ^aCj|X^rC(o<`~!4)(62v$zCBHiv9Bwi{%)QV
zIs1Lj{LlPP4g5#x#p3TujDKzUN2sW`h2NHF1`zW0WG395HG$f$>+{jrt$xbJUz+(
z@txsUU;jU^THi{T{s>-2-+@srj}E1ek2-*r#VI>s_3G-?7t8-?JAvj480Ay)0+og?
zFZuFt!+KMIHJQm`=B;PIs-IiZIuxiz+LAp*44?k>8^8eOdT{N#(
zk^*(;6WE)G4^e%*Wh^>Kb^oN}=K+se?NRrqY6Ky(z;DiKhfa=41v}u-n!!j_741s{
zUiZ`=GH%6dr0bX8!|@z%Hwa4|b&}9uoSWS{Dhd1J-&?CQ7R!g;T(b;vJ}zZ`4-A3L
zBLI`O_Y+i4P>%Tl9i{8kCS#Gd19}1W##(nuH)vAlcP3-tH>g%j>+n;ZAf3Nnt4j9k
zLzvIIQD1LFKOgbFJIeKZ7iwoR|1$D=y58l6kIDeWKPhZdE|AaB^*8{gD%HNAEavXhnD@_m#
zfd791{J-^e@V_zb*Y{03f2spCnTnM-0qB4A1o8&oki&SQ(!KPQY$${ybK^cN7Rh?lmuT
z<9mam*uVbp7oGNKM34CVs2DmKwY-=;8ptf9dO$tuTs1Y{N58+@Me%#22ck3az7pRT
zNso737TN;Q-+#ao=##WczkVP9eZG=CE50K3n`1UgW0@!%;gI-_7>tGxLAC4llVT`JdwX
z7r_5r{{sI%XGxO(Pd)Aw|L+VX`TyeL|1hMUB3LHN%7cyDtFkADsJpJlSKTF!x}RG?j+0!Q|9~C@0d&(ZfR+I
z=9foNC$O~rq5H)SK`0mXU()@p)seI0GuK0p_Zrjy_Wh;$J7?zq7r_78%g_INQTK%x
z<=-=|$sE~>jQ@Z3;|3n@E~Mi=6RJW10O}DhD*u08{O{F!ng7q7uNuHZ{_QQtYwD!kvFDl+
zMstO|F=xp?8(00kOTDH#+bHG#Y!~U|IieBQK4WfHLBY*M>G;2HqoZK!u3fu6y=`eb
z;ri+8()RZ)RfDd`Z@+{(lJakUbIh70W_!&2<_8i{p4zd`6u)G#QPY(qoU_D1VP?Q^}OXrd&}kL{~Lahv%J7RDuVAHQmOi|ZbqG-G;O7NKzg5E
zi_2V*n0fd~;C4!<$9)?ABc2?h`aq0f590qltkU_W{r~iF(%+MMAK(12%RMgQxXa6x
zfpW^?z44o4HU)cWt?Dpw%O^1rB8k6~bkH;fDXaT?D1%9?TVv^^p
zCHsu13#m@?|L2>YGH%_q^%1HM>`-^)rTKqpyBGevt7>U`uHZ&J|2w8U^`cCTE@#Pq
zD?mPCRb^Pc`tV_gt)sLpYtK*o1qSHtcImtFX}(axXEc(|zIoG$T&mj>McYZT3z|c5
z9sOKv9%%DIHv?s}$-MrrcE`^3{PE9cw+~LgUYCmhcai^(_|h410FM82{2#`}>HF?#
zc|XPfkDZqP|LJ;zOWpAl^8bJQ>C=CtJodxZO~|j#ju)>-e?R3psg6%<9x@F*O7Yx8
z;RN_w6lH;UJhd*L<(mF~=UUI}xHupBz1(T%GyS-(9S_lY+UyixhzEng^S=(sd;|F3
zMDhO=|LbU;plfh&FqQvbfbsv?;l7vnzp4uUKV46c1lFhezDFppZgWmVwKW#}d~lHN
zi=j}zYoF=eTYf$E$HuI7n(Rk?0*|7C-;KV$Tp?0n4qo^2I@IIu(w_KP>sQCdWjSZb
zlh+Rpu3B}^KRl9ERbCc6VCl&+7U@(a(Bnm&e&I3jzOSoCnXiN46f)`W+9hcpt^Otb
z?~`8NnA{R3T;RO^+~MV=;{P*vKb;R?{%8Kb`uX2)Kpz_QVN<_0OL4iy`{`OpX6us$<`^a0Cpece^e
z|B4+DPubH_YCWD>cYB-u=>dfIRz0`zq{&`UhN~Gu9iOY}M-Ti>$$l_L!W@o7q7sSUeXCNZGW>Z3$nr5%_IN2-KcX#
zu7^St~aeMOnx89Nuzh7Sy^k;5)9enU1?1a>L@d`T!u=ufG
z2jc(n{_%0*Z#tjzSk>^AkTE&L-yGl`B
z72MG9Z}-D*GH!49>H5wdDgRfPe>*%L>v2>jj8;d)m9ztfH=WLZC*dEN#XsW
z0C@i$@V?Zu0rh^K{t+4WRD%#bQMIAr^-}1_Ie!Peg|*PBThe|2{eM36zs(O^z5M5K
z!*X}6-TvJN(BBys#SfaW;(Gs(O(TaKWC
zyk;CP9MAc>Ef#U@RPqeAa^eB>D|*xCcdiwE0xLxbzLE~%s8@yfMAGkX4HbXAJ8Uf{
zoj}OWWYTJHj40=AE-O>c8+O2Se}7GHq15vN{C)I)NiTr+^Lu)#?F}&t>BpvdpLCak
zqsB#~|GE{03=4&4yiG%w=cZI_vhSX9utJupaUeLp&)0;w*M{&`Ql0A
zwby{}TmR3}L->5av#aEW8~iBDKepwu($T~~5zQMa?s9wH$8&KA8|?Js^ZQH7-xqs5
zng5ypng1`G|I^PO*#Sj&P+s#@i>2{J^esdGw>4y^`89|Kh}#?f3_HL8I{Ab*6;#)y2Nds}{`Y3h%&bJO%HCErSx47)dJ=rqmp;Ez4k>i3Z*DcGHW#x9eo$QND
z`n%#Q_u{;(Hsd_#yibkuCwboo-X|R;!Ch4a-Y0)w(N|nsMst8X7T6h?G-pZUS~$F)
z-fz>_0bFE?+qOu@l{xk;A#O(|H!yA*|VgtW5vMUbbVmd
zvQF)YcwG9LwydCk5p?)ISweFk$S(Umd6OU>&}XzP{(W{&V?r=KnPA
z@k(~UY;a;O_vw{#UT>g|sR#f{^Jz9!4Wh5s79{jq5EC(KUxgrkh!1d@4utD$T
z^!Y$%KOX&F3=aIjk(|3Seg1A)UO9lia2(f))$PRheBEAdu^~TDX3W&1PjQFS9f>q<
zF8gQG$zz+Wl;8JF`ulzG_sbik9;wdW@V>(PKcqN6c>g)fQw#=*Q7>Ln|AU@rzrr`r
zyS-BO$CYxPbX~3c4ZEpM-{u^PqHnJhbDul(=*#y>yS2poK~rWM#rNMm6dt-#{w_Yx
zQ{xZJ|IGXB|6h80{dM5yq5&Ki`OpdswAVl%aL61^+X14T;sFBX1zuRM^(5l~V^No|
zp)zNQ6Z$B_Po6YU9f2GVJW2D`!z0C3JL<8VZ&g~Ms~)uuAg}(RCvqy@CF2j0p=-B@_!oqJB$?cn{BYmD9=CBGjXANX*4!*%fYBatcI?`M{uN$tGB5cbegvji
zkdC!PKIU|O;`f*LdR#6XS;)s77(hG~eyb(wc2C6vI;cJX@qkZP2&xPv9-zIY(?jt9
z#~8%}a+Z@FFmU9gDKjuicEIC;N(X$Yy-QzY9I{sp>SBg;|-vIR86@NcBf_naBoS)_3loi-ZTGSew@7nH=XhV7{8*_2T)$XF=)>kk!YqE7q;==KD_=PxwewjTBT
z@b{B-eGUKcV5$9Jc&M)aG2(sbz8h+cU8)Y=kC%Tx5(e>gUYOUJ`JefJdVYm*VD4~$
z;sHrJfabGPeZa%1`hZcy1JE}pWaueA9`ky=sXD>Q`T(U)Fg!fjH#o<(_3!(TFDBmidHW^B-*-hC)BZli`76+$Uf)E#?^EWz=ymyAhkAwQl^I9o4o5D=
zeq;V;{%8LGc>SNLya3e)zzzsmC+&dk4a+9$0}MU+s1LA+<0sO6gSC;FbcAN&=ga(g
zs(+t!dr;5+LkaN<==DL*9sT>{?^maJzu|uP`wwG2eJakc`1^(V%Dk70!87KaD}#6V
zKFyEQe|v&;0-K@_(A|?!Z5&PLS&VPK^gpeZUtg5DzfIk8X&0cfGIJ0ZP9>!eq5X
z22*wb^aEz<&$~RIr~Q4Ue_zq-OZM??fZow$J--lbOvm}ZL%iP-9!mN9I?|o%)#uNu
zKRtcDc%2{nmhZ!rdmrWt|I>M(-^l+Q>i)5x1e*7ZH9~u9IzRFI%X>Z8F8}!L@>B8x
zsD~Sx)DIYiju7bwB>M%Vj?PIAL!XfhrUdiaki9U<5O{~39KExrv6{p&~e
zkNqlLACS}&96Nlu;sGgtfA3TGP+ec~A|=0HC?PMgVLi=nSMvM9ze4vgRo6%U{$E4k
zDc;xC8?~I@=jUwxJZFS~3-x}?n*ZUahr_lo_2Zn^9H2Ai|I{}L9WM0wf$yVsho_L)
z9+2!8u#ldhp!5qsK;RPB2c+}+M)><{eEKP!-gG^G+TVW&af|Yhn9lDj_540vzIr}i
zXL`o?{Fs*)(mt4b{x7L_MIu!t(2*Q_+Zoo>JfMdiVE@euK^U`|&7ad_YTBqMwqx2f
z&9kC=!Tits&$#SuO4bQZj|W&cCF23qFF<;N85)WQ3>>F;0O|xIWCzfE0mK6^XJ{xq
zJnOu`nfZOx^H1vZdXx41m`nK6$^QLhoFBUJrNM5ahU)r!y3Sm_f6S{3iC3?b{hs3g
z5%TBh{+x5YX#d|(5Bjgt)Eupj{_BZj2P{3=7z<)wr4|I5<4IgU{YB?Q?|Ge@>u{y)
z+l73dee|48<^_`T1#WBTC@nILCg%+bIz7!BM14SyVh2|#!pW_J&`8g%dny-I9@jm2rW9Q`i
z)9r!_;{VE)uBJ{!&zJK1RguO<;{RjE`X?SNU8g4gpU(Ny|INHVH@u&|&hvG@@_C)<
zKc?#ht&OB3)KOX)n$i#0-tcc!C%B9H1tjkazI49;@&ZPyGn%vm!q%jo&``6a*afsw
zoSLA{(Z%th=rp9CGh(`V%S$~1~fBwWb_<5b5&+A9smpcF`lktH2AA^q2
z@TTi19#D{q2dFYmi3f~DJ+AHR|NA|ivLs|TJSB>f+>(6XlYTF6Z}^hfACT0<`@X(D
zZ)zSN`uEdwc#+>Xi@~}kit`s|dQr#Ab$#>K-}|WjGavYf&u?yV=i}smyM3&d{FTV+
zzjr@YDhN);rt;}N|MY*;-lX@u&dqh;=WuSH!%KO+r{@Lqumi-FgPX2f?@{ssDLp~W
zcJ$@t=6C9-USI0zM7{n`*Bg2S%pp#%8`gVnapUv!&&l7HP-l?l{ptR`66dGv$K;|Huclgj;4+|9`swAB_xB{@>!TkL^BS$yM8HBhh!W1wj`Z`~({l>?gJG-dJ*SG|Gq)X{rk-O%=?#-r!N<7&OQI9`~EaFwGOBCX!V07
zf@`pf{QszZc=+vuJz2p(p?1f}v1$=<$loS
z*B^N)TcgwITIJ#RM2kGc{QvRVJB+i8vy8Ks4rlp!;^%2TK2IMD|2Nj6@Be_M&QV)M
z>b@0tZ64X(q|ekFhvDx}wElI1`JefJK0YsuC-JtWG
z|C8+hGt}2cA`zPRQx$c)(Dw)3pYpN(gLkSmdSkJS{J-S&>QnsR%K86~#|~h;V!WD<
zc*XmY_a*PkOXn9{4F7}vTW8Pznwm&@-k-at_NXNz&pu{%E^QZtV(5lHb+9^1=o7_?
zBR|U)q@cKYv>|Ht^x_|N!%>F}SQr-l7I%`yL*>*_T%cI#U7{XekG
zH5jRS?@s9cTFcDD?bBa*m;+>jJpgM!D8$PAKezS|U1Mq4&3TZCTlL?myeVng8dO|M`0J^`_^L_W|z%-Us{~
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
zFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&dFb*&d
TFb*&dFb*&dFb>RL9QgkMJ!A(+
literal 0
HcmV?d00001
From 2a778ded2fc3503f44364526cdabc142eda37691 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 12:29:20 +0000
Subject: [PATCH 056/107] Updated translations
---
translations/translation_de.xml | 25 +++++++++++++++++++++----
translations/translation_en.xml | 2 +-
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 93770f193..33aa49ecf 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -830,15 +830,32 @@ Als erstes muss auf der Helferkarte der Lade-Marker gesetzt werden.
Dieses erkennt vorhandende Haufen oder Silos und markiert den ausgewählten.
Anschließend kann der Helfer gestartet werden.
"/>
-
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index b1bf7ddca..3728c719f 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -830,7 +830,7 @@ To start the loading-marker on the AI menu needs to be set.
The marker detects heaps or silos and highlights them on the map.
Now it's possible to start the helper.
"/>
-
+
From 58bce751bee00e0d12579f11d2b79fae48533de4 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 14:37:54 +0200
Subject: [PATCH 057/107] TPS extension
---
config/HelpMenu.xml | 3 +++
config/MasterTranslations.xml | 11 +++++++++++
2 files changed, 14 insertions(+)
diff --git a/config/HelpMenu.xml b/config/HelpMenu.xml
index f6667d36b..42b8e24ca 100644
--- a/config/HelpMenu.xml
+++ b/config/HelpMenu.xml
@@ -234,6 +234,9 @@
+
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index 6068736c8..d63fbdc8f 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2543,6 +2543,17 @@ Das Kreuz sollte jetzt wie im Bild dar gestellt gelb sein.
WIP
]]>
+
+
From 7c14f92337aa15772d4548f42fc5fb400cfeedf5 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 24 Aug 2023 14:40:27 +0200
Subject: [PATCH 058/107] ups
---
config/HelpMenu.xml | 3 +--
config/MasterTranslations.xml | 1 -
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/config/HelpMenu.xml b/config/HelpMenu.xml
index 42b8e24ca..0be47f0d8 100644
--- a/config/HelpMenu.xml
+++ b/config/HelpMenu.xml
@@ -237,7 +237,6 @@
-
-
+
\ No newline at end of file
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index d63fbdc8f..f7cee8016 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2543,7 +2543,6 @@ Das Kreuz sollte jetzt wie im Bild dar gestellt gelb sein.
WIP
]]>
-
+
+ toolOffsetX
+ noReverse
+ turnRadius
+ workingWidth
+ balerUnloadDistance
+ directionNodeOffsetZ
+ implementWheelAlwaysOnGround
+ ignoreCollisionBoxesWhenFolded
+ baleCollectorOffset
+ disableUnfolding
+ raiseLate
+ lowerEarly
+ useVehicleSizeForMarkers
+ armMovingToolIx
+ movingToolIx
+ shovelMovingToolIx
+ ignoreBaleCollisionForward
+ fixWheelLoaderDirectionNodeByMovingToolIx
+
@@ -343,6 +367,9 @@ You can define the following custom settings:
+
.
---
---@class VehicleConfigurations : CpObject
VehicleConfigurations = CpObject()
-VehicleConfigurations.XML_KEY = "VehicleConfigurations.Vehicle"
+VehicleConfigurations.BASE_KEY = "VehicleConfigurations"
+VehicleConfigurations.XML_KEY = VehicleConfigurations.BASE_KEY .. ".Vehicle"
+VehicleConfigurations.XML_CONFIGURATION_KEY = VehicleConfigurations.BASE_KEY .. ".Configurations.Configuration"
VehicleConfigurations.MOD_NAME = g_currentModName
---- All attributes and the data type.
-VehicleConfigurations.attributes = {
- toolOffsetX = XMLValueType.FLOAT,
- noReverse = XMLValueType.BOOL,
- turnRadius = XMLValueType.FLOAT,
- workingWidth = XMLValueType.FLOAT,
- balerUnloadDistance = XMLValueType.FLOAT,
- directionNodeOffsetZ = XMLValueType.FLOAT,
- implementWheelAlwaysOnGround = XMLValueType.BOOL,
- ignoreCollisionBoxesWhenFolded = XMLValueType.BOOL,
- baleCollectorOffset = XMLValueType.FLOAT,
- disableUnfolding = XMLValueType.BOOL,
- raiseLate = XMLValueType.BOOL,
- lowerEarly = XMLValueType.BOOL,
- useVehicleSizeForMarkers = XMLValueType.BOOL,
- armMovingToolIx = XMLValueType.INT,
- movingToolIx = XMLValueType.INT,
- shovelMovingToolIx = XMLValueType.INT,
- ignoreBaleCollisionForward = XMLValueType.BOOL,
-}
-
function VehicleConfigurations:init()
self.vehicleConfigurations = {}
self.modVehicleConfigurations = {}
+ self.attributes = {}
if g_currentMission then
self:loadFromXml()
end
@@ -64,17 +46,15 @@ function VehicleConfigurations:registerXmlSchema()
self.xmlSchema = XMLSchema.new("vehicleConfigurations")
self.xmlSchema:register(XMLValueType.STRING,self.XML_KEY.."(?)#name","Configuration name")
self.xmlSchema:register(XMLValueType.STRING,self.XML_KEY.."(?)#modName","Mod name") --- Optional to avoid conflict for xml files with the same name.
- for name,xmlType in pairs(VehicleConfigurations.attributes) do
- self.xmlSchema:register(xmlType,self.XML_KEY.."(?)#"..name,"Configuration value")
- end
+ self.xmlSchema:register(XMLValueType.STRING,self.XML_CONFIGURATION_KEY.."(?)#type","Configuration value type")
+ self.xmlSchema:register(XMLValueType.STRING,self.XML_CONFIGURATION_KEY.."(?)","Configuration name")
end
function VehicleConfigurations:loadFromXml()
- self:registerXmlSchema()
self.xmlFileName = Utils.getFilename('config/VehicleConfigurations.xml', Courseplay.BASE_DIRECTORY)
- self.xmlFile = self:loadXmlFile(self.xmlFileName)
+ self:registerXmlSchema()
+ self.xmlFile = self:loadXmlFile(self.xmlFileName, true)
self.userXmlFileName = getUserProfileAppPath() .. 'modSettings/'..VehicleConfigurations.MOD_NAME..'/vehicleConfigurations.xml'
-
self.userXmlFile = self:loadXmlFile(self.userXmlFileName)
end
@@ -113,19 +93,39 @@ function VehicleConfigurations:readVehicle(xmlFile, vehicleElement)
end
end
-function VehicleConfigurations:loadXmlFile(fileName)
+
+function VehicleConfigurations:loadXmlFile(fileName, loadConfig)
CpUtil.info('Loading vehicle configuration from %s ...', fileName)
local xmlFile = XMLFile.loadIfExists("vehicleConfigurationsXmlFile",fileName, self.xmlSchema)
if xmlFile then
- xmlFile:iterate(self.XML_KEY, function (ix, key)
- self:readVehicle(xmlFile, key)
- end)
+ if not loadConfig or self:loadConfigurations(xmlFile) then
+ xmlFile:iterate(self.XML_KEY, function (ix, key)
+ self:readVehicle(xmlFile, key)
+ end)
+ end
xmlFile:delete()
else
CpUtil.info('Vehicle configuration file %s does not exist.', fileName)
end
end
+function VehicleConfigurations:loadConfigurations(xmlFile)
+ self.attributes = {}
+ xmlFile:iterate(self.XML_CONFIGURATION_KEY, function(ix, key)
+ local type = xmlFile:getValue(key .. "#type"):upper()
+ local name = xmlFile:getValue(key)
+ self.attributes[name] = XMLValueType[type]
+ if self.attributes[name] == nil then
+ CpUtil.info("Vehicle configuration %s has no valid type for %s!", name, type)
+ end
+ end)
+ for name, xmlType in pairs(self.attributes) do
+ CpUtil.info("Registered %s", name)
+ self.xmlSchema:register(xmlType, self.XML_KEY.."(?)#"..name, "Configuration value")
+ end
+ return true
+end
+
--- Get a custom configuration value for a single vehicle/implement
--- @param object table vehicle or implement object. This function uses the object's configFileName to uniquely
--- identify the vehicle/implement.
diff --git a/scripts/dev/DevHelper.lua b/scripts/dev/DevHelper.lua
index 00c8fcc7a..b78cee93f 100644
--- a/scripts/dev/DevHelper.lua
+++ b/scripts/dev/DevHelper.lua
@@ -262,10 +262,22 @@ function DevHelper:showAIMarkers()
CpUtil.drawDebugNode(frontMarker, false, 3)
CpUtil.drawDebugNode(backMarker, false, 3)
- if self.vehicle:getAIDirectionNode() then
+ local directionNode = self.vehicle:getAIDirectionNode()
+ if directionNode then
CpUtil.drawDebugNode(self.vehicle:getAIDirectionNode(), false , 3, "AiDirectionNode")
end
-
+ local reverseNode = self.vehicle:getAIReverserNode()
+ if reverseNode and reverseNode ~= directionNode then
+ CpUtil.drawDebugNode(reverseNode, false , 3, "AiReverseNode")
+ end
+ local steeringNode = self.vehicle:getAISteeringNode()
+ if steeringNode and steeringNode ~= directionNode then
+ CpUtil.drawDebugNode(steeringNode, false , 3, "AiSteeringNode")
+ end
+ local articulatedAxisReverseNode = self.spec_articulatedAxis and self.spec_articulatedAxis.aiRevereserNode
+ if articulatedAxisReverseNode and articulatedAxisReverseNode ~= directionNode and articulatedAxisReverseNode ~= reverseNode then
+ CpUtil.drawDebugNode(articulatedAxisReverseNode, false , 3, "AiArticulatedAxisReverseNode")
+ end
end
function DevHelper:togglePpcControlledNode()
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index c470e7af9..dbbd3b5c0 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -54,6 +54,7 @@ function CpAISiloLoaderWorker.registerOverwrittenFunctions(vehicleType)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'getCpStartText', CpAISiloLoaderWorker.getCpStartText)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'startCpAtFirstWp', CpAISiloLoaderWorker.startCpAtFirstWp)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'startCpAtLastWp', CpAISiloLoaderWorker.startCpAtLastWp)
+ SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIDirectionNode", CpAISiloLoaderWorker.getAIDirectionNode)
end
------------------------------------------------------------------------------------------------------------------------
--- Event listeners
@@ -191,4 +192,17 @@ end
function CpAISiloLoaderWorker:stopCpSiloLoaderWorker()
self:stopCpDriver()
+end
+
+--- Fixes the Direction for the platinum wheel loader, as
+--- their direction is not updated base on the rotation.
+--- So we use the parent node of the arm tool node.
+---@param superFunc any
+function CpAISiloLoaderWorker:getAIDirectionNode(superFunc)
+ if not self:getIsCpActive() then return superFunc(self) end
+ local movingToolIx = g_vehicleConfigurations:get(self, "fixWheelLoaderDirectionNodeByMovingToolIx")
+ if movingToolIx ~= nil then
+ return getParent(self.spec_cylindered.movingTools[movingToolIx].node)
+ end
+ return superFunc(self)
end
\ No newline at end of file
From e66e3e59586de1cd6e024549041cd6c8d55d8dd9 Mon Sep 17 00:00:00 2001
From: Peter Vaiko
Date: Sat, 2 Sep 2023 08:17:32 -0400
Subject: [PATCH 061/107] fix: workaround for Platinum reversing
---
scripts/specializations/CpAISiloLoaderWorker.lua | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index dbbd3b5c0..d2661bba7 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -201,7 +201,15 @@ end
function CpAISiloLoaderWorker:getAIDirectionNode(superFunc)
if not self:getIsCpActive() then return superFunc(self) end
local movingToolIx = g_vehicleConfigurations:get(self, "fixWheelLoaderDirectionNodeByMovingToolIx")
- if movingToolIx ~= nil then
+ if movingToolIx ~= nil then
+ -- Fix the Platinum wheel loader's "revereser" node, which is pointing backwards instead forwards
+ -- like on every other articulated axis vehicle
+ -- TODO: this should probably be in an appended function to ArticulatedAxis
+ -- TODO: maybe even add a new node and use that, instead of rotating the original node
+ -- TODO: add a separate vehicle config entry just for this, in case not all the Platinum vehicles are screwed up the same way?
+ if self.spec_articulatedAxis and self.spec_articulatedAxis.aiRevereserNode then
+ setRotation(self.spec_articulatedAxis.aiRevereserNode, 0, 0, 0)
+ end
return getParent(self.spec_cylindered.movingTools[movingToolIx].node)
end
return superFunc(self)
From 87782a65901ea7e9e3c4eb708de43688bfb80cfe Mon Sep 17 00:00:00 2001
From: Peter Vaiko
Date: Sat, 2 Sep 2023 08:20:12 -0400
Subject: [PATCH 062/107] refactor: use reverser node for articulate axis
---
scripts/ai/AIReverseDriver.lua | 136 ++++++++++++++++-----------------
1 file changed, 65 insertions(+), 71 deletions(-)
diff --git a/scripts/ai/AIReverseDriver.lua b/scripts/ai/AIReverseDriver.lua
index a8c4eb3da..8db253599 100644
--- a/scripts/ai/AIReverseDriver.lua
+++ b/scripts/ai/AIReverseDriver.lua
@@ -63,90 +63,84 @@ function AIReverseDriver:debug(...)
end
function AIReverseDriver:getDriveData()
- if self.reversingImplement == nil then
- -- no wheeled implement, simple reversing the PPC can handle by itself
- return nil
- end
+ if self.reversingImplement == nil then
+ -- no wheeled implement, simple reversing the PPC can handle by itself
+ return nil
+ end
- -- if there's a reverser node on the tool, use that, otherwise the steering node
- -- the reverser direction node, if exists, works better for tools with offset or for
- -- rotating plows where it remains oriented and placed correctly
- local trailerNode = AIVehicleUtil.getAIToolReverserDirectionNode(self.vehicle) or self.reversingImplement.steeringAxleNode
- local trailerFrontNode = self.reversingImplement.reversingProperties.frontNode
-
- local tx, ty, tz = self.ppc:getGoalPointPosition()
- local lxTrailer, lzTrailer = AIVehicleUtil.getDriveDirection(trailerNode, tx, ty, tz)
- self:showDirection(trailerNode, lxTrailer, lzTrailer, 1, 0, 0)
-
- local maxTractorAngle = math.rad(75)
-
- -- for articulated vehicles use the articulated axis' rotation node as it is a better indicator or the
- -- vehicle's orientation than the direction node which often turns/moves with an articulated vehicle part
- -- TODO: consolidate this with AITurn:getTurnNode() and if getAIDirectionNode() considers this already
- local tractorNode
- local useArticulatedAxisRotationNode = SpecializationUtil.hasSpecialization(ArticulatedAxis, self.vehicle.specializations) and self.vehicle.spec_articulatedAxis.rotationNode
- if useArticulatedAxisRotationNode then
- tractorNode = self.vehicle.spec_articulatedAxis.rotationNode
- else
- tractorNode = self.vehicle:getAIDirectionNode()
- end
+ local trailerNode = self.reversingImplement.steeringAxleNode
+ local xTipper, yTipper, zTipper = getWorldTranslation(trailerNode);
- local lx, lz, angleDiff
+ local trailerFrontNode = self.reversingImplement.reversingProperties.frontNode
+ local xFrontNode,yFrontNode,zFrontNode = getWorldTranslation(trailerFrontNode)
- if self.reversingImplement.reversingProperties.isPivot then
- -- The trailer/implement has a front axle (or dolly) with a draw bar.
- -- The current Courseplay dev team has no idea how this works :), this is magic
- -- from the old code, written by Satissis (Claus).
- -- TODO: adapt a documented algorithm for these trailers
- local xTrailer, yTrailer, zTrailer = getWorldTranslation(trailerNode);
- local xFrontNode, yFrontNode, zFrontNode = getWorldTranslation(trailerFrontNode)
- local lxFrontNode, lzFrontNode = AIVehicleUtil.getDriveDirection(trailerFrontNode, xTrailer, yTrailer, zTrailer)
- self:showDirection(trailerFrontNode, lxFrontNode, lzFrontNode, 0, 1, 0)
+ local tx, ty, tz = self.ppc:getGoalPointPosition()
- local lxTractor, lzTractor = AIVehicleUtil.getDriveDirection(tractorNode, xFrontNode, yFrontNode, zFrontNode)
- self:showDirection(tractorNode, lxTractor, lzTractor, 0, 0.7, 0)
+ local lxTipper, lzTipper = AIVehicleUtil.getDriveDirection(trailerNode, tx, ty, tz)
- local rotDelta = (self.reversingImplement.reversingProperties.nodeDistance *
- (0.5 - (0.023 * self.reversingImplement.reversingProperties.nodeDistance - 0.073)))
- local trailerToWaypointAngle = self:getLocalYRotationToPoint(trailerNode, tx, ty, tz, -1) * rotDelta
- trailerToWaypointAngle = MathUtil.clamp(trailerToWaypointAngle, -math.rad(90), math.rad(90))
+ self:showDirection(trailerNode, lxTipper, lzTipper, 1, 0, 0)
- local dollyToTrailerAngle = self:getLocalYRotationToPoint(trailerFrontNode, xTrailer, yTrailer, zTrailer, -1)
+ local lxFrontNode, lzFrontNode = AIVehicleUtil.getDriveDirection(trailerFrontNode, xTipper, yTipper, zTipper)
- local tractorToDollyAngle = self:getLocalYRotationToPoint(tractorNode, xFrontNode, yFrontNode, zFrontNode, -1)
+ local lxTractor, lzTractor = 0, 0
- local rearAngleDiff = (dollyToTrailerAngle - trailerToWaypointAngle)
- rearAngleDiff = MathUtil.clamp(rearAngleDiff, -math.rad(45), math.rad(45))
+ local maxTractorAngle = math.rad(75)
- local frontAngleDiff = (tractorToDollyAngle - dollyToTrailerAngle)
- frontAngleDiff = MathUtil.clamp(frontAngleDiff, -math.rad(45), math.rad(45))
+ -- for articulated vehicles use the articulated axis' rotation node as it is a better indicator or the
+ -- vehicle's orientation than the direction node which often turns/moves with an articulated vehicle part
+ -- TODO: consolidate this with AITurn:getTurnNode() and if getAIDirectionNode() considers this already
+ local tractorNode
+ if self.vehicle.spec_articulatedAxis then
+ tractorNode = AIUtil.getArticulatedAxisVehicleReverserNode(self.vehicle)
+ else
+ tractorNode = self.vehicle:getAIDirectionNode()
+ end
- angleDiff = (frontAngleDiff - rearAngleDiff) *
- (1.5 - (self.reversingImplement.reversingProperties.nodeDistance * 0.4 - 0.9) + rotDelta)
- angleDiff = MathUtil.clamp(angleDiff, -math.rad(45), math.rad(45))
+ local lx, lz, angleDiff
+
+ if self.reversingImplement.reversingProperties.isPivot then
+ self:showDirection(trailerFrontNode, lxFrontNode, lzFrontNode, 0, 1, 0)
- lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
- else
- -- the trailer/implement is like a semi-trailer, has a rear axle only, the front of the implement
- -- is supported by the tractor
- local crossTrackError, orientationError, curvatureError, currentHitchAngle = self:calculateErrors(tractorNode, trailerNode)
- angleDiff = self:calculateHitchCorrectionAngle(crossTrackError, orientationError, curvatureError, currentHitchAngle)
- angleDiff = MathUtil.clamp(angleDiff, -maxTractorAngle, maxTractorAngle)
+ lxTractor, lzTractor = AIVehicleUtil.getDriveDirection(tractorNode, xFrontNode, yFrontNode, zFrontNode)
+ self:showDirection(tractorNode,lxTractor, lzTractor, 0, 0.7, 0)
- lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
- end
+ local rotDelta = (self.reversingImplement.reversingProperties.nodeDistance *
+ (0.5 - (0.023 * self.reversingImplement.reversingProperties.nodeDistance - 0.073)))
+ local trailerToWaypointAngle = self:getLocalYRotationToPoint(trailerNode, tx, ty, tz, -1) * rotDelta
+ trailerToWaypointAngle = MathUtil.clamp(trailerToWaypointAngle, -math.rad(90), math.rad(90))
- self:showDirection(tractorNode, lx, lz, 0.7, 0, 1)
- -- do a little bit of damping if using the articulated axis as lx tends to oscillate around 0 which results in the
- -- speed adjustment kicking in and slowing down the vehicle.
- if useArticulatedAxisRotationNode and math.abs(lx) < 0.04 then
- lx = 0
- end
- -- construct an artificial goal point to drive to
- lx, lz = -lx * self.ppc:getLookaheadDistance(), -lz * self.ppc:getLookaheadDistance()
- -- AIDriveStrategy wants a global position to drive to (which it later converts to local, but whatever...)
- local gx, _, gz = localToWorld(self.vehicle:getAIDirectionNode(), lx, 0, lz)
- return gx, gz, false, self.settings.reverseSpeed:getValue()
+ local dollyToTrailerAngle = self:getLocalYRotationToPoint(trailerFrontNode, xTipper, yTipper, zTipper, -1)
+
+ local tractorToDollyAngle = self:getLocalYRotationToPoint(tractorNode, xFrontNode, yFrontNode, zFrontNode, -1)
+
+ local rearAngleDiff = (dollyToTrailerAngle - trailerToWaypointAngle)
+ rearAngleDiff = MathUtil.clamp(rearAngleDiff, -math.rad(45), math.rad(45))
+
+ local frontAngleDiff = (tractorToDollyAngle - dollyToTrailerAngle)
+ frontAngleDiff = MathUtil.clamp(frontAngleDiff, -math.rad(45), math.rad(45))
+
+ angleDiff = (frontAngleDiff - rearAngleDiff) *
+ (1.5 - (self.reversingImplement.reversingProperties.nodeDistance * 0.4 - 0.9) + rotDelta)
+ angleDiff = MathUtil.clamp(angleDiff, -math.rad(45), math.rad(45))
+
+ lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
+ else
+ local crossTrackError, orientationError, curvatureError, currentHitchAngle = self:calculateErrors(tractorNode, trailerNode)
+ angleDiff = self:calculateHitchCorrectionAngle(crossTrackError, orientationError, curvatureError, currentHitchAngle)
+ angleDiff = MathUtil.clamp(angleDiff, -maxTractorAngle, maxTractorAngle)
+
+ lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
+ end
+
+ self:showDirection(tractorNode, lx, lz, 0.7, 0, 1)
+ -- do a little bit of damping if using the articulated axis as lx tends to oscillate around 0 which results in the
+ -- speed adjustment kicking in and slowing down the vehicle.
+ if useArticulatedAxisRotationNode and math.abs(lx) < 0.04 then lx = 0 end
+ -- construct an artificial goal point to drive to
+ lx, lz = -lx * self.ppc:getLookaheadDistance(), -lz * self.ppc:getLookaheadDistance()
+ -- AIDriveStrategy wants a global position to drive to (which it later converts to local, but whatever...)
+ local gx, _, gz = localToWorld(self.vehicle:getAIDirectionNode(), lx, 0, lz)
+ return gx, gz, false, self.settings.reverseSpeed:getValue()
end
function AIReverseDriver:getLocalYRotationToPoint(node, x, y, z, direction)
From 46fa1f6f2decbcf8df41bac369a651a8a865b3ba Mon Sep 17 00:00:00 2001
From: Peter Vaiko
Date: Sat, 2 Sep 2023 08:39:13 -0400
Subject: [PATCH 063/107] doc: reverser node comment updated
---
scripts/ai/AIReverseDriver.lua | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/ai/AIReverseDriver.lua b/scripts/ai/AIReverseDriver.lua
index 8db253599..ab3f9f3ff 100644
--- a/scripts/ai/AIReverseDriver.lua
+++ b/scripts/ai/AIReverseDriver.lua
@@ -86,7 +86,7 @@ function AIReverseDriver:getDriveData()
local maxTractorAngle = math.rad(75)
- -- for articulated vehicles use the articulated axis' rotation node as it is a better indicator or the
+ -- for articulated vehicles use the articulated axis' reverser node as it is a better indicator or the
-- vehicle's orientation than the direction node which often turns/moves with an articulated vehicle part
-- TODO: consolidate this with AITurn:getTurnNode() and if getAIDirectionNode() considers this already
local tractorNode
From 6032bb2302232a904a01a618922251c3ca42d92a Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Sat, 2 Sep 2023 14:54:23 +0200
Subject: [PATCH 064/107] Add config for l120H and add turn radius for both
wheelloader
---
config/VehicleConfigurations.xml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index b3c537c92..1ab06411b 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -369,6 +369,14 @@ You can define the following custom settings:
/>
+
+
From 9933b5ce96a329d3e63b868ec85c5bcb6d3453be Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sat, 2 Sep 2023 18:51:24 +0200
Subject: [PATCH 065/107] Callstack and code adjustments fix and code
adjustments
---
config/VehicleConfigurations.xml | 6 +
.../ai/AIDriveStrategyShovelSiloLoader.lua | 10 +-
scripts/ai/ImplementUtil.lua | 3 +-
scripts/ai/Markers.lua | 37 ++++-
scripts/ai/controllers/ShovelController.lua | 2 +-
scripts/config/VehicleConfigurations.lua | 2 +-
scripts/dev/DevHelper.lua | 31 ++--
.../specializations/CpAISiloLoaderWorker.lua | 22 ---
scripts/specializations/CpAIWorker.lua | 35 ++++
scripts/specializations/CpShovelPositions.lua | 151 +++++++++++-------
10 files changed, 198 insertions(+), 101 deletions(-)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index 1ab06411b..8b6dc6c0e 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -116,6 +116,9 @@ You can define the following custom settings:
Fixes the ai direction node for the platinum wheel loaders, as their direction is not changed based on the rotation.
As a fix the parent node of the arm moving tool ix is used.
+- articulatedAxisReverseNodeInverted
+ Is the reverse node for articulated axis vehicles rotated by 180 degree?
+
-->
@@ -137,6 +140,7 @@ You can define the following custom settings:
shovelMovingToolIx
ignoreBaleCollisionForward
fixWheelLoaderDirectionNodeByMovingToolIx
+ articulatedAxisReverseNodeInverted
@@ -369,6 +373,7 @@ You can define the following custom settings:
/>
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 023c622ef..302de4f70 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -130,8 +130,8 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
local dirX, dirZ = self.silo:getLengthDirection()
local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ)
self.siloFrontNode = CpUtil.createNode("siloFrontNode", cx, cz, yRot)
- self.siloAreaToAvoid = PathfinderUtil.NodeArea(self.siloFrontNode, -self.silo:getWidth()/2 - 1,
- -1, self.silo:getWidth() + 2, self.silo:getLength() + 2)
+ self.siloAreaToAvoid = PathfinderUtil.NodeArea(self.siloFrontNode, -self.silo:getWidth()/2 - 3,
+ -3, self.silo:getWidth() + 6, self.silo:getLength() + 6)
self.siloController = CpBunkerSiloLoaderController(self.silo, self.vehicle, self)
end
@@ -159,7 +159,9 @@ function AIDriveStrategyShovelSiloLoader:setAllStaticParameters()
self.reverser = AIReverseDriver(self.vehicle, self.ppc)
self.proximityController = ProximityController(self.vehicle, self:getWorkWidth())
self.proximityController:registerIgnoreObjectCallback(self, self.ignoreProximityObject)
- self:setFrontAndBackMarkers()
+ Markers.setMarkerNodes(self.vehicle)
+ self.frontMarkerNode, self.backMarkerNode, self.frontMarkerDistance, self.backMarkerDistance =
+ Markers.getMarkerNodes(self.vehicle)
self.siloEndProximitySensor = SingleForwardLookingProximitySensorPack(self.vehicle, self.shovelController:getShovelNode(), 5, 1)
self.heapNode = CpUtil.createNode("heapNode", 0, 0, 0, nil)
self.lastTrailerSearch = 0
@@ -635,7 +637,7 @@ end
function AIDriveStrategyShovelSiloLoader:startReversingAwayFromUnloading()
local _, _, spaceToTrailer = localToLocal(self.shovelController:getShovelNode(), self.vehicle:getAIDirectionNode(), 0, 0, 0)
local course = Course.createStraightReverseCourse(self.vehicle, 2*spaceToTrailer,
- 0, self.vehicle.rootNode )
+ 0, self.vehicle:getAIDirectionNode() )
self:startCourse(course, 1)
self:setNewState(self.states.REVERSING_AWAY_FROM_UNLOAD)
end
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index 236e24ddc..dd1b62ac8 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -366,9 +366,10 @@ end
---@param tool table moving tool
---@param dt number
---@param rotTarget number target rotation in radiant
+---@return boolean
function ImplementUtil.moveMovingToolToRotation(implement, tool, dt, rotTarget)
if tool.rotSpeed == nil then
- return
+ return false
end
local spec = implement.spec_cylindered
tool.curRot[1], tool.curRot[2], tool.curRot[3] = getRotation(tool.node)
diff --git a/scripts/ai/Markers.lua b/scripts/ai/Markers.lua
index 2aeb6d8b2..217a04583 100644
--- a/scripts/ai/Markers.lua
+++ b/scripts/ai/Markers.lua
@@ -15,6 +15,13 @@
Markers = {}
+function Markers.registerConsoleCommands()
+ g_devHelper.consoleCommands:registerConsoleCommand("cpFrontAndBackerMarkerCalculate",
+ "Calculates the front and back markers", "consoleCommandReload", Markers)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpFrontAndBackerMarkerPrintDebug",
+ "Print Marker data", "consoleCommandPrintDebug", Markers)
+end
+Markers.registerConsoleCommands()
-- a global table with the vehicle as the key to persist the marker nodes we don't want to leak through jobs
-- and also don't want to deal with keeping track when to delete them
g_vehicleMarkers = {}
@@ -119,4 +126,32 @@ function Markers.getMarkerNodes(vehicle)
local frontMarker = Markers.getFrontMarkerNode(vehicle)
local backMarker = Markers.getBackMarkerNode(vehicle)
return frontMarker, backMarker, g_vehicleMarkers[vehicle].frontMarkerOffset, g_vehicleMarkers[vehicle].backMarkerOffset
-end
\ No newline at end of file
+end
+
+--------------------------------------------
+--- Console Commands
+--------------------------------------------
+
+function Markers:consoleCommandReload(backDistance)
+ local vehicle = g_currentMission.controlledVehicle
+ if not vehicle then
+ CpUtil.info("No valid vehicle entered!")
+ return
+ end
+ if backDistance then
+ backDistance = tonumber(backDistance)
+ end
+ Markers.setMarkerNodes(vehicle, backDistance)
+ Markers:consoleCommandPrintDebug()
+end
+
+function Markers:consoleCommandPrintDebug()
+ local vehicle = g_currentMission.controlledVehicle
+ if not vehicle then
+ CpUtil.info("No valid vehicle entered!")
+ return
+ end
+ local _, frontMarkerDistance = Markers.getFrontMarkerNode(vehicle)
+ local _, backMarkerDistance = Markers.getBackMarkerNode(vehicle)
+ CpUtil.infoVehicle(vehicle, "Front distance: %.2f, back distance: %.2f", frontMarkerDistance, backMarkerDistance)
+end
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 9abeb7c45..7d5034bd3 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -116,7 +116,7 @@ function ShovelController:calculateMinimalUnloadingHeight(triggerNode)
self.TRIGGER_HEIGHT_RAYCAST_COLLISION_MASK)
if not self.objectWasHit then
self:debug("Finished raycast with minimal height: %.2f", i)
- self.implement:setCpShovelMinimalUnloadHeight(i + 0.25)
+ self.implement:setCpShovelMinimalUnloadHeight(i + 1)
return true
end
end
diff --git a/scripts/config/VehicleConfigurations.lua b/scripts/config/VehicleConfigurations.lua
index f5b917c3a..f56edeee1 100644
--- a/scripts/config/VehicleConfigurations.lua
+++ b/scripts/config/VehicleConfigurations.lua
@@ -133,7 +133,7 @@ end
--- @return any|nil the value of the configuration attribute or nil if there's no custom config for it
function VehicleConfigurations:get(object, attribute)
if not self:isValidAttribute(attribute) then
- CpUtil.infoImplement(object, "The given attribute name: %s is not valid!", attribute)
+ CpUtil.infoImplement(object, "The given vehicle config attribute name: %s is not valid!", attribute)
return
end
if object and object.configFileNameClean then
diff --git a/scripts/dev/DevHelper.lua b/scripts/dev/DevHelper.lua
index b78cee93f..e21336e55 100644
--- a/scripts/dev/DevHelper.lua
+++ b/scripts/dev/DevHelper.lua
@@ -39,15 +39,26 @@ function DevHelper:debug(...)
CpUtil.info(string.format(...))
end
+--- Makes sure deleting of the selected vehicle can be detected
+function DevHelper:removedSelectedVehicle()
+ self.vehicle = nil
+end
+
function DevHelper:update()
if not self.isEnabled then return end
local lx, lz, hasCollision, vehicle
-- make sure not calling this for something which does not have courseplay installed (only ones with spec_aiVehicle)
- if g_currentMission.controlledVehicle and g_currentMission.controlledVehicle.spec_aiVehicle then
-
+ if g_currentMission.controlledVehicle and g_currentMission.controlledVehicle.spec_cpAIWorker then
+ if self.vehicle ~= g_currentMission.controlledVehicle then
+ if self.vehicle then
+ self.vehicle:removeDeleteListener(self, "removedSelectedVehicle")
+ end
+ --self.vehicleData = PathfinderUtil.VehicleData(g_currentMission.controlledVehicle, true)
+ end
self.vehicle = g_currentMission.controlledVehicle
+ self.vehicle:addDeleteListener(self, "removedSelectedVehicle")
self.node = g_currentMission.controlledVehicle:getAIDirectionNode()
lx, _, lz = localDirectionToWorld(self.node, 0, 0, 1)
@@ -264,19 +275,19 @@ function DevHelper:showAIMarkers()
local directionNode = self.vehicle:getAIDirectionNode()
if directionNode then
- CpUtil.drawDebugNode(self.vehicle:getAIDirectionNode(), false , 3, "AiDirectionNode")
+ CpUtil.drawDebugNode(self.vehicle:getAIDirectionNode(), false , 4, "AiDirectionNode")
end
local reverseNode = self.vehicle:getAIReverserNode()
- if reverseNode and reverseNode ~= directionNode then
- CpUtil.drawDebugNode(reverseNode, false , 3, "AiReverseNode")
+ if reverseNode then
+ CpUtil.drawDebugNode(reverseNode, false , 4.5, "AiReverseNode")
end
local steeringNode = self.vehicle:getAISteeringNode()
- if steeringNode and steeringNode ~= directionNode then
- CpUtil.drawDebugNode(steeringNode, false , 3, "AiSteeringNode")
+ if steeringNode then
+ CpUtil.drawDebugNode(steeringNode, false , 5, "AiSteeringNode")
end
- local articulatedAxisReverseNode = self.spec_articulatedAxis and self.spec_articulatedAxis.aiRevereserNode
- if articulatedAxisReverseNode and articulatedAxisReverseNode ~= directionNode and articulatedAxisReverseNode ~= reverseNode then
- CpUtil.drawDebugNode(articulatedAxisReverseNode, false , 3, "AiArticulatedAxisReverseNode")
+ local articulatedAxisReverseNode = AIUtil.getArticulatedAxisVehicleReverserNode(self.vehicle)
+ if articulatedAxisReverseNode then
+ CpUtil.drawDebugNode(articulatedAxisReverseNode, false , 5.5, "AiArticulatedAxisReverseNode")
end
end
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index d2661bba7..da718578f 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -54,7 +54,6 @@ function CpAISiloLoaderWorker.registerOverwrittenFunctions(vehicleType)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'getCpStartText', CpAISiloLoaderWorker.getCpStartText)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'startCpAtFirstWp', CpAISiloLoaderWorker.startCpAtFirstWp)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'startCpAtLastWp', CpAISiloLoaderWorker.startCpAtLastWp)
- SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIDirectionNode", CpAISiloLoaderWorker.getAIDirectionNode)
end
------------------------------------------------------------------------------------------------------------------------
--- Event listeners
@@ -193,24 +192,3 @@ end
function CpAISiloLoaderWorker:stopCpSiloLoaderWorker()
self:stopCpDriver()
end
-
---- Fixes the Direction for the platinum wheel loader, as
---- their direction is not updated base on the rotation.
---- So we use the parent node of the arm tool node.
----@param superFunc any
-function CpAISiloLoaderWorker:getAIDirectionNode(superFunc)
- if not self:getIsCpActive() then return superFunc(self) end
- local movingToolIx = g_vehicleConfigurations:get(self, "fixWheelLoaderDirectionNodeByMovingToolIx")
- if movingToolIx ~= nil then
- -- Fix the Platinum wheel loader's "revereser" node, which is pointing backwards instead forwards
- -- like on every other articulated axis vehicle
- -- TODO: this should probably be in an appended function to ArticulatedAxis
- -- TODO: maybe even add a new node and use that, instead of rotating the original node
- -- TODO: add a separate vehicle config entry just for this, in case not all the Platinum vehicles are screwed up the same way?
- if self.spec_articulatedAxis and self.spec_articulatedAxis.aiRevereserNode then
- setRotation(self.spec_articulatedAxis.aiRevereserNode, 0, 0, 0)
- end
- return getParent(self.spec_cylindered.movingTools[movingToolIx].node)
- end
- return superFunc(self)
-end
\ No newline at end of file
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 95a27b95c..934824cb6 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -79,6 +79,8 @@ function CpAIWorker.registerOverwrittenFunctions(vehicleType)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'stopCurrentAIJob', CpAIWorker.stopCurrentAIJob)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'getCanMotorRun', CpAIWorker.getCanMotorRun)
SpecializationUtil.registerOverwrittenFunction(vehicleType, 'stopFieldWorker', CpAIWorker.stopFieldWorker)
+ SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIReverserNode", CpAIWorker.getAIReverserNode)
+ SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIDirectionNode", CpAIWorker.getAIDirectionNode)
end
---------------------------------------------------
@@ -511,6 +513,39 @@ function CpAIWorker:getCpReverseDrivingDirectionNode()
return spec.reverseDrivingDirectionNode
end
+--- Fixes the ai reverse node rotation for articulated axis vehicles,
+--- if the node is pointing backwards and not forwards.
+function CpAIWorker:getAIReverserNode(superFunc)
+ local spec = self.spec_cpAIWorker
+ -- if not self:getIsCpActive() then return superFunc(self) end
+ if self.spec_articulatedAxis and self.spec_articulatedAxis.aiRevereserNode then
+ if g_vehicleConfigurations:get(self, "articulatedAxisReverseNodeInverted") then
+ if not spec.articulatedAxisReverseNode then
+ spec.articulatedAxisReverseNode = CpUtil.createNode(
+ "cpAiRevereserNode", 0, 0, 0,
+ getParent(self.spec_articulatedAxis.aiRevereserNode))
+ end
+ return spec.articulatedAxisReverseNode
+ end
+ end
+ return superFunc(self)
+end
+
+--- Fixes the Direction for the platinum wheel loader, as
+--- their direction is not updated base on the rotation.
+--- So we use the parent node of the arm tool node.
+---@param superFunc any
+function CpAIWorker:getAIDirectionNode(superFunc)
+ -- if not self:getIsCpActive() then return superFunc(self) end
+ local movingToolIx = g_vehicleConfigurations:get(self, "fixWheelLoaderDirectionNodeByMovingToolIx")
+ if movingToolIx ~= nil then
+ return getParent(self.spec_cylindered.movingTools[movingToolIx].node)
+ end
+ return superFunc(self)
+end
+
+
+
--- TODO: Do we really need the AIDriveStrategyCollision from giants, as this one is only active for fieldwork?
function CpAIWorker:isCollisionDetectionEnabled()
local spec = self.spec_cpAIWorker
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 605929aec..1348fd804 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -211,6 +211,8 @@ function CpShovelPositions:onLoad(savegame)
spec.state = CpShovelPositions.DEACTIVATED
spec.isDirty = false
spec.minimalShovelUnloadHeight = 4
+ spec.highDumpMovingToolIx = g_vehicleConfigurations:get(self, "shovelMovingToolIx")
+ spec.isHighDumpShovel = spec.highDumpMovingToolIx ~= nil
end
function CpShovelPositions:onPostAttach()
@@ -234,13 +236,13 @@ function CpShovelPositions:onUpdateTick(dt)
return
end
if spec.state == CpShovelPositions.LOADING then
- CpShovelPositions.updateLoadingPosition(self, dt)
+ CpUtil.try(CpShovelPositions.updateLoadingPosition, self, dt)
elseif spec.state == CpShovelPositions.TRANSPORT then
- CpShovelPositions.updateTransportPosition(self, dt)
+ CpUtil.try(CpShovelPositions.updateTransportPosition, self, dt)
elseif spec.state == CpShovelPositions.PRE_UNLOAD then
- CpShovelPositions.updatePreUnloadPosition(self, dt)
+ CpUtil.try(CpShovelPositions.updatePreUnloadPosition, self, dt)
elseif spec.state == CpShovelPositions.UNLOADING then
- CpShovelPositions.updateUnloadingPosition(self, dt)
+ CpUtil.try(CpShovelPositions.updateUnloadingPosition, self, dt)
end
end
@@ -307,6 +309,54 @@ function CpShovelPositions:cpSetupShovelPositions()
end
end
+function CpShovelPositions:controlShovelPosition(dt, targetAngle)
+ local spec = self.spec_cpShovelPositions
+ local shovelData = ImplementUtil.getShovelNode(self)
+ local isDirty = false
+ if shovelData.movingToolActivation and not spec.isHighDumpShovel then
+ --- The shovel has a moving tool for grabbing.
+ for i, tool in pairs(self.spec_cylindered.movingTools) do
+ if tool.axis and tool.rotMax ~= nil and tool.rotMin ~= nil then
+ if spec.state ~= CpShovelPositions.TRANSPORT then
+ --- Opens the shovel for loading and unloading
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMin or tool.rotMax)
+ else
+ --- Closes the shovel after loading or unloading
+ isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
+ tool.invertAxis and tool.rotMax or tool.rotMin)
+ end
+ break
+ end
+ end
+ end
+ local curRot = {}
+ curRot[1], curRot[2], curRot[3] = getRotation(spec.shovelTool.node)
+ local oldShovelRot = curRot[spec.shovelTool.rotationAxis]
+ local goalAngle = MathUtil.clamp(oldShovelRot + targetAngle, spec.shovelTool.rotMin, spec.shovelTool.rotMax)
+ return ImplementUtil.moveMovingToolToRotation(spec.shovelVehicle,
+ spec.shovelTool, dt, goalAngle) or isDirty
+end
+
+function CpShovelPositions:unfoldHighDumpShovel(dt)
+ local highDumpShovelTool = self.spec_cylindered.movingTools[self.spec_cpShovelPositions.highDumpMovingToolIx]
+ local _, dy, _ = localDirectionToWorld(getParent(highDumpShovelTool.node), 0, 0, 1)
+ local angle = math.acos(dy) or 0
+ local targetAngle = math.pi/2 - math.pi/6
+ if CpShovelPositions.controlShovelPosition(self, dt, targetAngle - angle) then
+ return true, angle, targetAngle
+ end
+ local isDirty = ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
+ highDumpShovelTool.invertAxis and highDumpShovelTool.rotMin or highDumpShovelTool.rotMax)
+ return isDirty, angle, targetAngle
+end
+
+function CpShovelPositions:foldHighDumpShovel(dt)
+ local highDumpShovelTool = self.spec_cylindered.movingTools[self.spec_cpShovelPositions.highDumpMovingToolIx]
+ return ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
+ highDumpShovelTool.invertAxis and highDumpShovelTool.rotMax or highDumpShovelTool.rotMin)
+end
+
--- Sets the current shovel position values, like the arm and shovel rotations.
---@param dt number
---@param shovelLimits table
@@ -318,6 +368,7 @@ end
function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
isLoading, heightOffset, isUnloading)
heightOffset = heightOffset or 0
+ local spec = self.spec_cpShovelPositions
local min, max = unpack(shovelLimits)
--- Target angle of the shovel node, which is at the end of the shovel.
local targetAngle = math.rad(min) + math.rad(max - min)/2
@@ -325,11 +376,11 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
--- Target height of the arm.
--- This is relative to the attacher joint of the shovel.
local targetHeight = min + (max - min)/2
- local shovelTool = self.spec_cpShovelPositions.shovelTool
- local armTool = self.spec_cpShovelPositions.armTool
- local shovelVehicle = self.spec_cpShovelPositions.shovelVehicle
- local armVehicle = self.spec_cpShovelPositions.armVehicle
- local minimalTargetHeight = self.spec_cpShovelPositions.minimalShovelUnloadHeight
+ local shovelTool = spec.shovelTool
+ local armTool = spec.armTool
+ local shovelVehicle = spec.shovelVehicle
+ local armVehicle = spec.armVehicle
+ local minimalTargetHeight = spec.minimalShovelUnloadHeight
local curRot = {}
curRot[1], curRot[2], curRot[3] = getRotation(shovelTool.node)
local oldShovelRot = curRot[shovelTool.rotationAxis]
@@ -338,8 +389,8 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
curRot[1], curRot[2], curRot[3] = getRotation(armTool.node)
local oldArmRot = curRot[armTool.rotationAxis]
- local armProjectionNode = self.spec_cpShovelPositions.armProjectionNode
- local armToolRefNode = self.spec_cpShovelPositions.armToolRefNode
+ local armProjectionNode = spec.armProjectionNode
+ local armToolRefNode = spec.armToolRefNode
local radiusArmToolToShovelTool = calcDistanceFrom(shovelTool.node, armTool.node)
@@ -354,7 +405,8 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
local ax, ay, az = localToLocal(armTool.node, armVehicle.rootNode, 0, 0, 0)
local wx, _, wz = getWorldTranslation(armVehicle.rootNode)
local deltaY = 0
- if isUnloading then
+
+ if spec.state == CpShovelPositions.PRE_UNLOAD or spec.state == CpShovelPositions.UNLOADING then
deltaY = minimalTargetHeight - ay
end
local by = shovelY
@@ -406,8 +458,21 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
local hasIntersection, i1z, i1y, i2z, i2y = MathUtil.getCircleLineIntersection(
az, ay, radiusArmToolToShovelTool,
sz, sy, ez, ey)
-
- local isDirty, alpha, oldRotRelativeArmRot
+
+ local isDirty, skipArm
+ if spec.state == CpShovelPositions.UNLOADING or spec.state == CpShovelPositions.PRE_UNLOAD then
+ if spec.isHighDumpShovel then
+ if spec.state == CpShovelPositions.UNLOADING then
+ isDirty, angle, targetAngle = CpShovelPositions.unfoldHighDumpShovel(self, dt)
+ end
+ else
+ isDirty = CpShovelPositions.controlShovelPosition(self, dt, targetAngle - angle)
+ end
+ if spec.state == CpShovelPositions.UNLOADING and isDirty then
+ skipArm = true
+ end
+ end
+ local alpha, oldRotRelativeArmRot = 0, 0
if hasIntersection then
--- Controls the arm height
setTranslation(armProjectionNode, 0, i1y, i1z)
@@ -418,57 +483,21 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
alpha = math.atan2(i1y - ay, i1z - az)
local beta = -math.atan2(i2y - ay, i2z - az)
- local angle = MathUtil.clamp(oldArmRot - MathUtil.getAngleDifference(
+ local a = MathUtil.clamp(oldArmRot - MathUtil.getAngleDifference(
alpha, oldRotRelativeArmRot), armTool.rotMin, armTool.rotMax)
- isDirty = ImplementUtil.moveMovingToolToRotation(
- armVehicle, armTool, dt, angle)
+ if not skipArm then
+ isDirty = ImplementUtil.moveMovingToolToRotation(
+ armVehicle, armTool, dt, a) or isDirty
+ end
end
- --- Controls the arm extension
-
-
- local highDumpShovelTool
- local highDumpShovelIx = g_vehicleConfigurations:get(self, "shovelMovingToolIx")
- if highDumpShovelIx ~= nil then
- highDumpShovelTool = self.spec_cylindered.movingTools[highDumpShovelIx]
- if isUnloading then
- --- Makes sure the shovel is almost vertical for the high dump functionality
- local _, dy, _ = localDirectionToWorld(getParent(highDumpShovelTool.node), 0, 0, 1)
- angle = math.acos(dy)
- targetAngle = math.pi/2 - math.pi/6
- else
- isDirty = ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
- highDumpShovelTool.invertAxis and highDumpShovelTool.rotMax or highDumpShovelTool.rotMin) or isDirty
+ if spec.state ~= CpShovelPositions.UNLOADING then
+ if spec.isHighDumpShovel then
+ isDirty = CpShovelPositions.foldHighDumpShovel(self, dt) or isDirty
end
- else
- local shovelData = ImplementUtil.getShovelNode(self)
- if shovelData.movingToolActivation then
- --- The shovel has a moving tool for grabbing.
- for i, tool in pairs(self.spec_cylindered.movingTools) do
- if tool.axis then
- if isLoading or isUnloading then
- --- Opens the shovel for loading and unloading
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMin or tool.rotMax) or isDirty
- else
- --- Closes the shovel after loading
- isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
- tool.invertAxis and tool.rotMax or tool.rotMin) or isDirty
- end
- break
- end
- end
- end
- end
- local deltaAngle = targetAngle - angle
- local goalAngle = MathUtil.clamp(oldShovelRot + deltaAngle, shovelTool.rotMin, shovelTool.rotMax)
- isDirty = ImplementUtil.moveMovingToolToRotation(shovelVehicle,
- shovelTool, dt, goalAngle) or isDirty
- if isUnloading and highDumpShovelTool then
- --- Uses the high dump shovel functionality.
- isDirty = isDirty or ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
- highDumpShovelTool.invertAxis and highDumpShovelTool.rotMin or highDumpShovelTool.rotMax)
+ isDirty = isDirty or CpShovelPositions.controlShovelPosition(self, dt, targetAngle - angle)
end
+
--- Debug information
if g_currentMission.controlledVehicle == shovelVehicle.rootVehicle and
CpDebug:isChannelActive(CpDebug.DBG_SILO, shovelVehicle.rootVehicle) then
@@ -517,7 +546,7 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
table.insert(debugData, {
name = "angle", value = math.deg(angle) })
table.insert(debugData, {
- name = "deltaAngle", value = math.deg(deltaAngle) })
+ name = "deltaAngle", value = math.deg(targetAngle - angle) })
table.insert(debugData, {
name = "targetAngle", value = math.deg(targetAngle) })
table.insert(debugData, {
From 0e727c09f85a41b79bd112b4a5aba155622a9480 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 3 Sep 2023 10:16:37 +0200
Subject: [PATCH 066/107] Some more adjustments and fixes
---
.../ai/AIDriveStrategyShovelSiloLoader.lua | 61 +++-
scripts/ai/ImplementUtil.lua | 11 +-
scripts/ai/controllers/ShovelController.lua | 177 ++++++++++-
scripts/ai/controllers/TrailerController.lua | 6 +-
scripts/ai/jobs/CpAIJobSiloLoader.lua | 6 +-
scripts/ai/tasks/CpAITaskSiloLoader.lua | 4 +-
.../specializations/CpAISiloLoaderWorker.lua | 4 +-
scripts/specializations/CpAIWorker.lua | 2 +-
scripts/specializations/CpShovelPositions.lua | 284 +++++++++---------
scripts/trigger/TriggerWrapper.lua | 8 +-
10 files changed, 389 insertions(+), 174 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 302de4f70..5653b0c6e 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -36,12 +36,10 @@ local AIDriveStrategyShovelSiloLoader_mt = Class(AIDriveStrategyShovelSiloLoader
AIDriveStrategyShovelSiloLoader.myStates = {
DRIVING_ALIGNMENT_COURSE = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
-
DRIVING_INTO_SILO = {shovelPosition = ShovelController.POSITIONS.LOADING, shovelMovingSpeed = 0},
DRIVING_OUT_OF_SILO = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
-
+ DRIVING_TEMPORARY_OUT_OF_SILO = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
WAITING_FOR_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
-
DRIVING_TO_UNLOAD_POSITION = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
DRIVING_TO_UNLOAD_TRAILER = {shovelPosition = ShovelController.POSITIONS.TRANSPORT},
DRIVING_TO_UNLOAD = {shovelPosition = ShovelController.POSITIONS.PRE_UNLOADING, shovelMovingSpeed = 0},
@@ -53,7 +51,7 @@ AIDriveStrategyShovelSiloLoader.maxValidTrailerDistanceToSiloFront = 30
AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 30
AIDriveStrategyShovelSiloLoader.distShovelTrailerPreUnload = 7
AIDriveStrategyShovelSiloLoader.distShovelUnloadStationPreUnload = 8
-
+AIDriveStrategyShovelSiloLoader.isStuckMs = 1000 * 15
function AIDriveStrategyShovelSiloLoader.new(customMt)
if customMt == nil then
customMt = AIDriveStrategyShovelSiloLoader_mt
@@ -74,6 +72,7 @@ function AIDriveStrategyShovelSiloLoader:delete()
CpUtil.destroyNode(self.heapNode)
CpUtil.destroyNode(self.unloadPositionNode)
CpUtil.destroyNode(self.siloFrontNode)
+ self.isStuckTimer:delete()
end
function AIDriveStrategyShovelSiloLoader:getGeneratedCourse(jobParameters)
@@ -88,8 +87,10 @@ function AIDriveStrategyShovelSiloLoader:setSiloAndHeap(bunkerSilo, heapSilo)
end
---@param unloadTrigger CpTrigger
-function AIDriveStrategyShovelSiloLoader:setUnloadTrigger(unloadTrigger)
+---@param unloadStation table
+function AIDriveStrategyShovelSiloLoader:setUnloadTriggerAndStation(unloadTrigger, unloadStation)
self.unloadTrigger = unloadTrigger
+ self.unloadStation = unloadStation
end
function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
@@ -108,12 +109,13 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
--- Uses the exactFillRootNode from the trigger
--- and the direction of the unload position marker
--- to place the unload position node slightly in front.
- local x, y, z = getWorldTranslation(self.unloadTrigger:getFillUnitExactFillRootNode())
+ local x, y, z = getWorldTranslation(self.unloadTrigger:getFillUnitExactFillRootNode(1))
setTranslation(self.unloadPositionNode, x, y, z)
local position = jobParameters.unloadPosition
local dirX, dirZ = position:getDirection()
setDirection(self.unloadPositionNode, dirX, 0, dirZ, 0, 0, 1)
- local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -math.max(self.distShovelUnloadStationPreUnload, self.turningRadius))
+ local dx, dy, dz = localToWorld(self.unloadPositionNode, 0, 0, -math.max(
+ self.distShovelUnloadStationPreUnload, self.turningRadius, 1.5 * AIUtil.getLength(self.vehicle)))
setTranslation(self.unloadPositionNode, dx, dy, dz)
else
self:debug("Starting shovel silo to unload into trailer.")
@@ -165,6 +167,17 @@ function AIDriveStrategyShovelSiloLoader:setAllStaticParameters()
self.siloEndProximitySensor = SingleForwardLookingProximitySensorPack(self.vehicle, self.shovelController:getShovelNode(), 5, 1)
self.heapNode = CpUtil.createNode("heapNode", 0, 0, 0, nil)
self.lastTrailerSearch = 0
+ self.isStuckTimer = Timer.new(self.isStuckMs)
+ self.isStuckTimer:setFinishCallback(function ()
+ if self.frozen then
+ return
+ end
+ if self.state == self.states.DRIVING_INTO_SILO then
+ self:debug("Was stuck trying to drive into the bunker silo.")
+ self:startDrivingOutOfSilo()
+ self:setNewState(self.states.DRIVING_TEMPORARY_OUT_OF_SILO)
+ end
+ end)
end
-----------------------------------------------------------------------------------------------------------------------
@@ -184,6 +197,8 @@ function AIDriveStrategyShovelSiloLoader:onWaypointPassed(ix, course)
else
self:startPathfindingToUnloadPosition()
end
+ elseif self.state == self.states.DRIVING_TEMPORARY_OUT_OF_SILO then
+ self:startDrivingToSilo({self.siloController:getLastTarget()})
elseif self.state == self.states.DRIVING_TO_UNLOAD_TRAILER then
self:approachTrailerForUnloading()
elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
@@ -235,7 +250,9 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:setMaxSpeed(0)
elseif self.state == self.states.DRIVING_INTO_SILO then
self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
-
+ if AIUtil.isStopped(self.vehicle) and not self.proximityController:isStopped() then
+ self.isStuckTimer:startIfNotRunning()
+ end
local _, _, closestObject = self.siloEndProximitySensor:getClosestObjectDistanceAndRootVehicle()
local isEndReached, maxSpeed = self.siloController:isEndReached(self.shovelController:getShovelNode(), 0)
if self.silo:isTheSameSilo(closestObject) or isEndReached then
@@ -248,6 +265,8 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
end
elseif self.state == self.states.DRIVING_OUT_OF_SILO then
self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
+ elseif self.state == self.states.DRIVING_TEMPORARY_OUT_OF_SILO then
+ self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
elseif self.state == self.states.DRIVING_TO_UNLOAD_POSITION then
self:setMaxSpeed(self.settings.fieldSpeed:getValue())
elseif self.state == self.states.DRIVING_TO_UNLOAD_TRAILER then
@@ -268,7 +287,7 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
if self.isUnloadingAtTrailerActive then
refNode = self.targetTrailer.exactFillRootNode
else
- refNode = self.unloadTrigger:getFillUnitExactFillRootNode()
+ refNode = self.unloadTrigger:getFillUnitExactFillRootNode(1)
end
if self.shovelController:isShovelOverTrailer(refNode) then
self:setNewState(self.states.UNLOADING)
@@ -296,6 +315,7 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
end
end
self:limitSpeed()
+ self:checkProximitySensors(moveForwards)
return gx, gz, moveForwards, self.maxSpeed, 100
end
@@ -323,7 +343,7 @@ function AIDriveStrategyShovelSiloLoader:update(dt)
end
end
---- Ignores the bunker silo for the proximity sensors.
+--- Ignores the bunker silo and the unload target for the proximity sensors.
function AIDriveStrategyShovelSiloLoader:ignoreProximityObject(object, vehicle)
if self.silo:isTheSameSilo(object) then
return true
@@ -332,6 +352,18 @@ function AIDriveStrategyShovelSiloLoader:ignoreProximityObject(object, vehicle)
if object == nil then
return true
end
+ if object == self.unloadStation then
+ return true
+ end
+ if self.unloadTrigger:isTheSameObject(object) then
+ return true
+ end
+ if self.targetTrailer then
+ if object == self.targetTrailer.trailer then
+ return true
+ end
+ end
+ return false
end
function AIDriveStrategyShovelSiloLoader:getProximitySensorWidth()
@@ -551,9 +583,14 @@ end
----------------------------------------------------------------
--- Starts driving into the silo lane
-function AIDriveStrategyShovelSiloLoader:startDrivingToSilo()
+function AIDriveStrategyShovelSiloLoader:startDrivingToSilo(target)
--- Creates a straight course in the silo.
- local startPos, endPos = self.siloController:getTarget(self:getWorkWidth())
+ local startPos, endPos
+ if target then
+ startPos, endPos = unpack(target)
+ else
+ startPos, endPos = self.siloController:getTarget(self:getWorkWidth())
+ end
local x, z = unpack(startPos)
local dx, dz = unpack(endPos)
local siloCourse = Course.createFromTwoWorldPositions(self.vehicle, x, z, dx, dz,
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index dd1b62ac8..f7ccef7b1 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -375,10 +375,13 @@ function ImplementUtil.moveMovingToolToRotation(implement, tool, dt, rotTarget)
tool.curRot[1], tool.curRot[2], tool.curRot[3] = getRotation(tool.node)
local oldRot = tool.curRot[tool.rotationAxis]
local diff = rotTarget - oldRot
- local rotSpeed = MathUtil.clamp(diff * tool.rotSpeed, tool.rotSpeed/3, 0.5)
- if diff < 0 then
- rotSpeed=rotSpeed*(-1)
- end
+ local dir = MathUtil.sign(diff)
+ local rotSpeed = MathUtil.clamp( math.abs(diff) * math.abs(tool.rotSpeed), math.abs(tool.rotSpeed)/3, 0.5 )
+ rotSpeed = dir * rotSpeed
+ --local rotSpeed = MathUtil.clamp(diff * tool.rotSpeed, tool.rotSpeed/3, 0.5)
+ -- if diff < 0 then
+ -- rotSpeed=rotSpeed*(-1)
+ -- end
if math.abs(diff) < 0.03 or rotSpeed == 0 then
ImplementUtil.stopMovingTool(implement, tool)
return false
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 7d5034bd3..6ed36a59d 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -9,7 +9,7 @@ ShovelController.POSITIONS = {
UNLOADING = 4,
}
ShovelController.MAX_TRIGGER_HEIGHT = 8
-ShovelController.MIN_TRIGGER_HEIGHT = 2
+ShovelController.MIN_TRIGGER_HEIGHT = 1
ShovelController.TRIGGER_HEIGHT_RAYCAST_COLLISION_MASK = CollisionFlag.STATIC_WORLD + CollisionFlag.STATIC_OBJECTS +
CollisionFlag.STATIC_OBJECT + CollisionFlag.VEHICLE
@@ -19,10 +19,74 @@ function ShovelController:init(vehicle, implement, isConsoleCommand)
self.shovelNode = ImplementUtil.getShovelNode(implement)
self.turnOnSpec = self.implement.spec_turnOnVehicle
self.isConsoleCommand = isConsoleCommand
+ self.isSugarCaneTrailer = self.implement.spec_trailer ~= nil
+ self.sugarCaneTrailer = {
+ isDischargeActive = false,
+ isDischargingTimer = CpTemporaryObject(false),
+ movingTool = nil,
+ isMovingToolDirty = false,
+ isDischargingToGround = false
+ }
+ if self.isSugarCaneTrailer then
+ --- Find the moving tool for the sugar cane trailer
+ for i, tool in pairs(implement.cylindered.movingTools) do
+ if tool.axis then
+ self.sugarCaneTrailer.movingTool = tool
+ end
+ end
+ end
+end
+
+function ShovelController:getDriveData()
+ local maxSpeed
+ if self.isSugarCaneTrailer then
+ if self.sugarCaneTrailer.isDischargeActive then
+ if self.sugarCaneTrailer.isDischargingTimer:get() then
+ --- Waiting until the discharging stopped or
+ --- the trailer is empty
+ maxSpeed = 0
+ self:debugSparse("Waiting for unloading!")
+ end
+
+ -- if self.trailerSpec.tipState == Trailer.TIPSTATE_OPENING then
+ -- --- Trailer not yet ready to unload.
+ -- maxSpeed = 0
+ -- self:debugSparse("Waiting for trailer animation opening!")
+ -- end
+ if self:isEmpty() then
+ --- Waiting for the trailer animation to finish.
+ maxSpeed = 0
+ self:debugSparse("Waiting for trailer animation closing!")
+ end
+ else
+ -- ImplementUtil.moveMovingToolToRotation(self.implement,
+ -- self.sugarCaneTrailerMovingTool, dt , )
+ end
+ end
+ return nil, nil, nil, maxSpeed
end
-function ShovelController:update()
-
+function ShovelController:update(dt)
+ --- Sugar cane trailer discharge
+ if self.isSugarCaneTrailer then
+ if self.sugarCaneTrailer.isDischargeActive then
+ if self:isEmpty() then
+ self:finishedSugarCaneTrailerDischarge()
+ end
+ if self.implement:getCanDischargeToGround(self.dischargeData.dischargeNode) then
+ --- Update discharge timer
+ self.sugarCaneTrailer.isDischargingTimer:set(true, 500)
+ if not self:isDischarging() then
+ -- self.implement:setDischargeState(Dischargeable.DISCHARGE_STATE_GROUND)
+ end
+ end
+ -- ImplementUtil.moveMovingToolToRotation(self.implement,
+ -- self.sugarCaneTrailerMovingTool, dt , )
+ else
+ -- ImplementUtil.moveMovingToolToRotation(self.implement,
+ -- self.sugarCaneTrailerMovingTool, dt , )
+ end
+ end
end
function ShovelController:getShovelNode()
@@ -104,22 +168,33 @@ end
---@return boolean
function ShovelController:calculateMinimalUnloadingHeight(triggerNode)
local sx, sy, sz = getWorldTranslation(self.vehicle:getAIDirectionNode())
- local tx, ty, tz = getWorldTranslation(triggerNode)
+ local tx, ty, tz
+ if triggerNode then
+ tx, ty, tz = getWorldTranslation(triggerNode)
+ else
+ local dirX, _, dirZ = localDirectionToWorld(self.vehicle:getAIDirectionNode(), 0, 0, 1)
+ local _, frontMarkerDistance = Markers.getFrontMarkerNode(self.vehicle)
+ tx, ty, tz = sx + dirX * (frontMarkerDistance + 4), sy, sz + dirZ * (frontMarkerDistance + 4)
+ end
local length = MathUtil.vector2Length(tx - sx, tz - sz) + 0.25
local dx, dy, dz = tx - sx, ty - sy, tz -sz
- local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx, 0, sz)
- for i=self.MIN_TRIGGER_HEIGHT, self.MAX_TRIGGER_HEIGHT, 0.25 do
+ local _, terrainHeight, _ = getWorldTranslation(self.vehicle.rootNode)
+ local maxHeightObjectHit = 0
+ for i=self.MIN_TRIGGER_HEIGHT, self.MAX_TRIGGER_HEIGHT, 0.1 do
self.objectWasHit = false
raycastAll(sx, terrainHeight + i, sz, dx, 0, dz,
"calculateMinimalUnloadingHeightRaycastCallback",
length, self,
self.TRIGGER_HEIGHT_RAYCAST_COLLISION_MASK)
- if not self.objectWasHit then
- self:debug("Finished raycast with minimal height: %.2f", i)
- self.implement:setCpShovelMinimalUnloadHeight(i + 1)
- return true
+ if self.objectWasHit then
+ maxHeightObjectHit = i
end
end
+ if maxHeightObjectHit > 0 then
+ self:debug("Finished raycast with minimal height: %.2f", maxHeightObjectHit)
+ self.implement:setCpShovelMinimalUnloadHeight(maxHeightObjectHit + 0.5)
+ return true
+ end
self:debug("Could not find a valid minimal height, so we use the maximum: %.2f", self.MAX_TRIGGER_HEIGHT)
self.implement:setCpShovelMinimalUnloadHeight(self.MAX_TRIGGER_HEIGHT)
return false
@@ -129,8 +204,8 @@ function ShovelController:calculateMinimalUnloadingHeightRaycastCallback(hitObje
if hitObjectId then
local object = g_currentMission.nodeToObject[hitObjectId]
if object then
- self:debug("Object: %s was hit!", CpUtil.getName(object))
if object ~= self.vehicle and object ~= self.implement then
+ self:debug("Object: %s was hit!", CpUtil.getName(object))
self.objectWasHit = true
return true
end
@@ -177,6 +252,86 @@ function ShovelController:moveShovelToPosition(pos)
return self.implement:areCpShovelPositionsDirty()
end
+--------------------------------------------
+--- Sugar cane trailer functions
+--------------------------------------------
+
+--- Gets the dischargeNode and offset from a selected tip side.
+---@param tipSideID number
+---@param isTippingToGroundNeeded boolean
+---@return table|nil dischargeNodeIndex
+---@return table|nil dischargeNode
+---@return number|nil xOffset
+function ShovelController:getDischargeNodeAndOffsetForTipSide(tipSideID, isTippingToGroundNeeded)
+ local dischargeNode = self:getDischargeNode()
+ return dischargeNode.index, dischargeNode, self:getDischargeXOffset(dischargeNode)
+end
+
+--- Gets the x offset of the discharge node relative to the implement root.
+function ShovelController:getDischargeXOffset(dischargeNode)
+ local node = dischargeNode.node
+ local xOffset, _ ,_ = localToLocal(node, self.implement.rootNode, 0, 0, 0)
+ return xOffset
+end
+
+--- Starts AI Discharge to an object/trailer.
+---@param dischargeNode table discharge node to use.
+---@return boolean success
+function ShovelController:startDischarge(dischargeNode)
+ self.sugarCaneTrailer.isDischargeActive = true
+ return true
+end
+
+--- Starts discharging to the ground if possible.
+function ShovelController:startDischargeToGround(dischargeNode)
+ self.sugarCaneTrailer.isDischargeActive = true
+ self.sugarCaneTrailer.isDischargingToGround = true
+ -- self.isDischargingToGround = true
+ -- self.dischargeData = {
+ -- dischargeNode = dischargeNode,
+ -- }
+ -- local tipSide = self.trailerSpec.dischargeNodeIndexToTipSide[dischargeNode.index]
+ -- if tipSide ~= nil then
+ -- self.implement:setPreferedTipSide(tipSide.index)
+ -- end
+ return true
+end
+
+--- Callback for the drive strategy, when the unloading finished.
+function ShovelController:setFinishDischargeCallback(finishDischargeCallback)
+ self.sugarCaneTrailer.finishDischargeCallback = finishDischargeCallback
+end
+
+--- Callback for ai discharge.
+function ShovelController:finishedSugarCaneTrailerDischarge()
+ self:debug("Finished unloading.")
+ if self.sugarCaneTrailer.finishDischargeCallback then
+ self.sugarCaneTrailer.finishDischargeCallback(self.driveStrategy, self)
+ end
+ self.sugarCaneTrailer.isDischargeActive = false
+ self.sugarCaneTrailer.isDischargingToGround = false
+end
+
+function ShovelController:prepareForUnload()
+ return true
+end
+
+function ShovelController:isDischarging()
+ return self.implement:getDischargeState() ~= Dischargeable.DISCHARGE_STATE_OFF
+end
+
+--- Gets the discharge node z offset relative to the root vehicle direction node.
+function ShovelController:getUnloadOffsetZ(dischargeNode)
+ local node = dischargeNode.node
+ local dist = ImplementUtil.getDistanceToImplementNode(self.vehicle:getAIDirectionNode(),
+ self.implement, node)
+ return dist
+end
+
+--------------------------------------------
+--- Debug functions
+--------------------------------------------
+
function ShovelController:printShovelDebug()
self:debug("--Shovel Debug--")
if self.shovelNode then
diff --git a/scripts/ai/controllers/TrailerController.lua b/scripts/ai/controllers/TrailerController.lua
index d667e53a1..88e5c70a7 100644
--- a/scripts/ai/controllers/TrailerController.lua
+++ b/scripts/ai/controllers/TrailerController.lua
@@ -59,9 +59,9 @@ end
--- Gets the dischargeNode and offset from a selected tip side.
---@param tipSideID number
---@param isTippingToGroundNeeded boolean
----@return table dischargeNodeIndex
----@return table dischargeNode
----@return number xOffset
+---@return table|nil dischargeNodeIndex
+---@return table|nil dischargeNode
+---@return number|nil xOffset
function TrailerController:getDischargeNodeAndOffsetForTipSide(tipSideID, isTippingToGroundNeeded)
local tipSide = self.trailerSpec.tipSides[tipSideID]
if not tipSide then
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 9a9d5b74f..881e5e883 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -184,9 +184,9 @@ end
--- Gets the unload trigger at the unload position.
---@param unloadPosition CpAIParameterPositionAngle
----@return boolean
----@return table|nil
----@return table|nil
+---@return boolean found?
+---@return table|nil Trigger
+---@return table|nil unloadStation
function CpAIJobSiloLoader:getUnloadTriggerAt(unloadPosition)
local x, z = unloadPosition:getPosition()
local dirX, dirZ = unloadPosition:getDirection()
diff --git a/scripts/ai/tasks/CpAITaskSiloLoader.lua b/scripts/ai/tasks/CpAITaskSiloLoader.lua
index 31f856bbe..ddfc5333a 100644
--- a/scripts/ai/tasks/CpAITaskSiloLoader.lua
+++ b/scripts/ai/tasks/CpAITaskSiloLoader.lua
@@ -33,8 +33,8 @@ end
function CpAITaskSiloLoader:start()
if self.isServer then
- local _, unloadTrigger, _ = self.job:getUnloadTriggerAt(self.job:getCpJobParameters().unloadPosition)
- self.vehicle:startCpSiloLoaderWorker(self.job:getCpJobParameters(), self.silo, self.heap, unloadTrigger)
+ local _, unloadTrigger, unloadStation = self.job:getUnloadTriggerAt(self.job:getCpJobParameters().unloadPosition)
+ self.vehicle:startCpSiloLoaderWorker(self.job:getCpJobParameters(), self.silo, self.heap, unloadTrigger, unloadStation)
end
CpAITaskSiloLoader:superClass().start(self)
diff --git a/scripts/specializations/CpAISiloLoaderWorker.lua b/scripts/specializations/CpAISiloLoaderWorker.lua
index da718578f..4ec9f4486 100644
--- a/scripts/specializations/CpAISiloLoaderWorker.lua
+++ b/scripts/specializations/CpAISiloLoaderWorker.lua
@@ -172,7 +172,7 @@ function CpAISiloLoaderWorker:startCpAtLastWp(superFunc, ...)
end
end
-function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap, unloadTrigger)
+function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo, heap, unloadTrigger, unloadStation)
if self.isServer then
local strategy
if SpecializationUtil.hasSpecialization(ConveyorBelt, self.specializations) then
@@ -181,7 +181,7 @@ function CpAISiloLoaderWorker:startCpSiloLoaderWorker(jobParameters, bunkerSilo,
else
CpUtil.debugVehicle(CpDebug.DBG_SILO, self, "Starting a shovel silo loader strategy.")
strategy = AIDriveStrategyShovelSiloLoader.new()
- strategy:setUnloadTrigger(unloadTrigger)
+ strategy:setUnloadTriggerAndStation(unloadTrigger, unloadStation)
end
strategy:setSiloAndHeap(bunkerSilo, heap)
strategy:setAIVehicle(self, jobParameters)
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 934824cb6..250c3c44f 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -563,7 +563,7 @@ function CpAIWorker:disableCollisionDetection()
end
function CpAIWorker:getCollisionCheckActive(superFunc,...)
- local spec = self.spec_cpAIWorker
+ local spec = self.vehicle.spec_cpAIWorker
if spec.collisionDetectionEnabled then
return superFunc(self,...)
else
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 1348fd804..726c64caf 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -58,18 +58,7 @@ CpShovelPositions.KEY = "." .. CpShovelPositions.SPEC_NAME
function CpShovelPositions.initSpecialization()
local schema = Vehicle.xmlSchemaSavegame
- g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsPrintShovelDebug",
- "Prints debug information for the shovel",
- "consoleCommandPrintShovelDebug", CpShovelPositions)
- g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsSetState",
- "Set's the current shovel state",
- "consoleCommandSetShovelState", CpShovelPositions)
- g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsSetArmLimit",
- "Set's the arm max limit",
- "consoleCommandSetPreUnloadArmLimit", CpShovelPositions)
- g_devHelper.consoleCommands:registerConsoleCommand('cpShovelPositionsSetMinimalUnloadHeight',
- 'cpSetShovelSetMinimalUnloadHeight',
- 'consoleCommandSetMinimalUnloadHeight', CpShovelPositions)
+ CpShovelPositions.initConsoleCommands()
end
function CpShovelPositions.prerequisitesPresent(specializations)
@@ -99,106 +88,6 @@ function CpShovelPositions.registerFunctions(vehicleType)
SpecializationUtil.registerFunction(vehicleType, "setCpShovelMinimalUnloadHeight", CpShovelPositions.setCpShovelMinimalUnloadHeight)
end
---------------------------------------------
---- Console Commands
---------------------------------------------
-
-local function executeConsoleCommand(func, ...)
- local vehicle = g_currentMission.controlledVehicle
- if not vehicle then
- CpUtil.info("Not entered a valid vehicle!")
- return false
- end
- -- if vehicle:getIsAIActive() then
- -- CpUtil.infoVehicle(vehicle, "Error, AI is active!")
- -- return false
- -- end
- local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(vehicle, Shovel)
- if not found then
- CpUtil.infoVehicle(vehicle, "No shovel implement found!")
- return false
- end
- return func(shovels[1], ...)
-end
-
-function CpShovelPositions:consoleCommandSetShovelState(state)
- return executeConsoleCommand(function(shovelImplement, state)
- state = tonumber(state)
- if state == nil or state < 0 or state > CpShovelPositions.NUM_STATES then
- CpUtil.infoVehicle(shovelImplement, "No valid state(0 - %d) was given!", CpShovelPositions.NUM_STATES)
- return false
- end
- shovelImplement:cpSetShovelState(state)
- end, state)
-end
-
-function CpShovelPositions:consoleCommandSetPreUnloadArmLimit(min, max)
- return executeConsoleCommand(function(shovelImplement, min, max)
- min = tonumber(min)
- max = tonumber(max)
- if min == nil or max == nil then
- CpUtil.infoVehicle(shovelImplement, "No valid limits given! min: %s, max: %s", tostring(min), tostring(max))
- return false
- end
- CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS = { min, max }
- end, min, max)
-end
-
-function CpShovelPositions:consoleCommandPrintShovelDebug(cylinderedDepth)
- return executeConsoleCommand(function(shovelImplement)
- --- Position debug
- CpUtil.infoImplement(shovelImplement, "-- Position debug --")
- local spec = shovelImplement.spec_cpShovelPositions
- if spec then
- CpUtil.infoImplement(shovelImplement, " arm tool %s -> %s",
- CpUtil.getName(spec.armVehicle), tostring(spec.armToolIx))
- CpUtil.infoImplement(shovelImplement, " shovel tool %s -> %s",
- CpUtil.getName(spec.shovelVehicle), tostring(spec.shovelToolIx))
- local highDumpShovelIx = g_vehicleConfigurations:get(shovelImplement, "shovelMovingToolIx")
- CpUtil.infoImplement(shovelImplement, " shovel high dump %s -> %s",
- CpUtil.getName(shovelImplement), tostring(highDumpShovelIx))
- end
-
- CpUtil.infoImplement(shovelImplement, "-- Position debug --")
- --- Shovel debug
- local controller = ShovelController(shovelImplement.rootVehicle, shovelImplement, true)
- controller:printShovelDebug()
- controller:delete()
- --- Cylindered debug here
- CpUtil.infoImplement(shovelImplement, "-- Cylindered debug --")
- cylinderedDepth = cylinderedDepth and tonumber(cylinderedDepth) or 0
-
- local childVehicles = shovelImplement.rootVehicle:getChildVehicles()
- for _, vehicle in ipairs(childVehicles) do
- if vehicle.spec_cylindered then
- for ix, tool in pairs(vehicle.spec_cylindered.movingTools) do
- CpUtil.infoImplement(shovelImplement, " %s => ix: %d ",
- CpUtil.getName(vehicle), ix)
- if cylinderedDepth > 0 then
- CpUtil.infoImplement(shovelImplement, " %s",
- DebugUtil.debugTableToString(tool, " ", 0, cylinderedDepth))
- end
- CpUtil.infoImplement(shovelImplement, " %s => ix: %d finished",
- CpUtil.getName(vehicle), ix)
- end
- end
- end
- CpUtil.infoImplement(shovelImplement, "-- Cylindered debug finished --")
- end)
-end
-
-function CpShovelPositions:consoleCommandSetMinimalUnloadHeight(height)
- return executeConsoleCommand(function(shovelImplement, height)
- height = tonumber(height)
- if height == nil then
- CpUtil.infoVehicle(shovelImplement, "No valid height given! height: %s", tostring(height))
- return false
- end
- local spec = shovelImplement.spec_cpShovelPositions
- spec.minimalShovelUnloadHeight = height
- end, height)
-end
-
--------------------------------------------
--- Event Listener
--------------------------------------------
@@ -361,12 +250,9 @@ end
---@param dt number
---@param shovelLimits table
---@param armLimits table
----@param isLoading boolean|nil
---@param heightOffset number|nil
----@param isUnloading boolean|nil
---@return boolean|nil
-function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
- isLoading, heightOffset, isUnloading)
+function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, heightOffset)
heightOffset = heightOffset or 0
local spec = self.spec_cpShovelPositions
local min, max = unpack(shovelLimits)
@@ -404,11 +290,7 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
local _, ty, tz = localToLocal(getChildAt(armTool.node, 0), armVehicle.rootNode, 0, 0, 0)
local ax, ay, az = localToLocal(armTool.node, armVehicle.rootNode, 0, 0, 0)
local wx, _, wz = getWorldTranslation(armVehicle.rootNode)
- local deltaY = 0
- if spec.state == CpShovelPositions.PRE_UNLOAD or spec.state == CpShovelPositions.UNLOADING then
- deltaY = minimalTargetHeight - ay
- end
local by = shovelY
if self.spec_foliageBending and self.spec_foliageBending.bendingNodes[1] then
local bending = self.spec_foliageBending.bendingNodes[1]
@@ -436,12 +318,15 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
_, by, _ = worldToLocal(shovelTool.node, sx, by2, sz)
end
end
-
- local sx, sy, sz = 0, -by + targetHeight + heightOffset + deltaY, 0
- local ex, ey, ez = 0, -by + targetHeight + heightOffset + deltaY, 20
+ local deltaY = 0
+ if spec.state == CpShovelPositions.PRE_UNLOAD or spec.state == CpShovelPositions.UNLOADING then
+ targetHeight = minimalTargetHeight
+ end
+ local sx, sy, sz = 0, -by + targetHeight + heightOffset, 0
+ local ex, ey, ez = 0, sy, 20
local wsx, wsy, wsz = localToWorld(armVehicle.rootNode, sx, sy, sz)
local wex, wey, wez = localToWorld(armVehicle.rootNode, ex, ey, ez)
- local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wsx, 0, wsz)
+ local _, terrainHeight, _ = getWorldTranslation(self.rootVehicle.rootNode, 0, 0, 0)
local yMax = ay + radiusArmToolToShovelTool
local yMin = ay - radiusArmToolToShovelTool
@@ -472,6 +357,15 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
skipArm = true
end
end
+ if spec.state ~= CpShovelPositions.UNLOADING then
+ if spec.isHighDumpShovel then
+ isDirty = CpShovelPositions.foldHighDumpShovel(self, dt) or isDirty
+ if isDirty then
+ skipArm = true
+ end
+ end
+ end
+
local alpha, oldRotRelativeArmRot = 0, 0
if hasIntersection then
--- Controls the arm height
@@ -492,9 +386,6 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits,
end
if spec.state ~= CpShovelPositions.UNLOADING then
- if spec.isHighDumpShovel then
- isDirty = CpShovelPositions.foldHighDumpShovel(self, dt) or isDirty
- end
isDirty = isDirty or CpShovelPositions.controlShovelPosition(self, dt, targetAngle - angle)
end
@@ -583,8 +474,7 @@ function CpShovelPositions:updateLoadingPosition(dt)
if angle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.LOADING_POSITION.SHOVEL_LIMITS,
- CpShovelPositions.LOADING_POSITION.ARM_LIMITS,
- true, heightOffset)
+ CpShovelPositions.LOADING_POSITION.ARM_LIMITS, heightOffset)
end
spec.isDirty = isDirty
end
@@ -597,8 +487,7 @@ function CpShovelPositions:updateTransportPosition(dt)
if angle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.TRANSPORT_POSITION.SHOVEL_LIMITS,
- CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS,
- false, heightOffset)
+ CpShovelPositions.TRANSPORT_POSITION.ARM_LIMITS, heightOffset)
end
spec.isDirty = isDirty
end
@@ -610,8 +499,7 @@ function CpShovelPositions:updatePreUnloadPosition(dt)
if angle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
CpShovelPositions.PRE_UNLOAD_POSITION.SHOVEL_LIMITS,
- CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS,
- false, nil)
+ CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, nil)
end
spec.isDirty = isDirty
end
@@ -623,8 +511,7 @@ function CpShovelPositions:updateUnloadingPosition(dt)
if angle and maxAngle then
isDirty = CpShovelPositions.setShovelPosition(self, dt,
{math.deg(maxAngle), math.deg(maxAngle) + 2},
- CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, false,
- nil, true)
+ CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS, nil)
end
spec.isDirty = isDirty
end
@@ -660,4 +547,131 @@ function CpShovelPositions.debug(implement, ...)
if CpShovelPositions.DEBUG then
CpUtil.infoImplement(implement, ...)
end
+end
+
+
+--------------------------------------------
+--- Console Commands
+--------------------------------------------
+
+function CpShovelPositions.initConsoleCommands()
+ g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsPrintShovelDebug",
+ "Prints debug information for the shovel",
+ "consoleCommandPrintShovelDebug", CpShovelPositions)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsSetState",
+ "Set's the current shovel state",
+ "consoleCommandSetShovelState", CpShovelPositions)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpShovelPositionsSetArmLimit",
+ "Set's the arm max limit",
+ "consoleCommandSetPreUnloadArmLimit", CpShovelPositions)
+ g_devHelper.consoleCommands:registerConsoleCommand('cpShovelPositionsSetMinimalUnloadHeight',
+ 'Sets the minimal unload height to a fixed value',
+ 'consoleCommandSetMinimalUnloadHeight', CpShovelPositions)
+ g_devHelper.consoleCommands:registerConsoleCommand('cpShovelPositionsMeasureAndSetMinUnloadHeight',
+ 'Measures and sets the minimal unload height',
+ 'consoleCommandMeasureAndSetMinimalUnloadHeight', CpShovelPositions)
+end
+
+local function executeConsoleCommand(func, ...)
+ local vehicle = g_currentMission.controlledVehicle
+ if not vehicle then
+ CpUtil.info("Not entered a valid vehicle!")
+ return false
+ end
+ -- if vehicle:getIsAIActive() then
+ -- CpUtil.infoVehicle(vehicle, "Error, AI is active!")
+ -- return false
+ -- end
+ local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(vehicle, Shovel)
+ if not found then
+ CpUtil.infoVehicle(vehicle, "No shovel implement found!")
+ return false
+ end
+ return func(shovels[1], ...)
+end
+
+function CpShovelPositions:consoleCommandSetShovelState(state)
+ return executeConsoleCommand(function(shovelImplement, state)
+ state = tonumber(state)
+ if state == nil or state < 0 or state > CpShovelPositions.NUM_STATES then
+ CpUtil.infoVehicle(shovelImplement, "No valid state(0 - %d) was given!", CpShovelPositions.NUM_STATES)
+ return false
+ end
+ shovelImplement:cpSetShovelState(state)
+ end, state)
+end
+
+function CpShovelPositions:consoleCommandSetPreUnloadArmLimit(min, max)
+ return executeConsoleCommand(function(shovelImplement, min, max)
+ min = tonumber(min)
+ max = tonumber(max)
+ if min == nil or max == nil then
+ CpUtil.infoVehicle(shovelImplement, "No valid limits given! min: %s, max: %s", tostring(min), tostring(max))
+ return false
+ end
+ CpShovelPositions.PRE_UNLOAD_POSITION.ARM_LIMITS = { min, max }
+ end, min, max)
+end
+
+function CpShovelPositions:consoleCommandPrintShovelDebug(cylinderedDepth)
+ return executeConsoleCommand(function(shovelImplement)
+ --- Position debug
+ CpUtil.infoImplement(shovelImplement, "-- Position debug --")
+ local spec = shovelImplement.spec_cpShovelPositions
+ if spec then
+ CpUtil.infoImplement(shovelImplement, " arm tool %s -> %s",
+ CpUtil.getName(spec.armVehicle), tostring(spec.armToolIx))
+ CpUtil.infoImplement(shovelImplement, " shovel tool %s -> %s",
+ CpUtil.getName(spec.shovelVehicle), tostring(spec.shovelToolIx))
+ local highDumpShovelIx = g_vehicleConfigurations:get(shovelImplement, "shovelMovingToolIx")
+ CpUtil.infoImplement(shovelImplement, " shovel high dump %s -> %s",
+ CpUtil.getName(shovelImplement), tostring(highDumpShovelIx))
+ end
+
+ CpUtil.infoImplement(shovelImplement, "-- Position debug --")
+ --- Shovel debug
+ local controller = ShovelController(shovelImplement.rootVehicle, shovelImplement, true)
+ controller:printShovelDebug()
+ controller:delete()
+ --- Cylindered debug here
+ CpUtil.infoImplement(shovelImplement, "-- Cylindered debug --")
+ cylinderedDepth = cylinderedDepth and tonumber(cylinderedDepth) or 0
+
+ local childVehicles = shovelImplement.rootVehicle:getChildVehicles()
+ for _, vehicle in ipairs(childVehicles) do
+ if vehicle.spec_cylindered then
+ for ix, tool in pairs(vehicle.spec_cylindered.movingTools) do
+ CpUtil.infoImplement(shovelImplement, " %s => ix: %d ",
+ CpUtil.getName(vehicle), ix)
+ if cylinderedDepth > 0 then
+ CpUtil.infoImplement(shovelImplement, " %s",
+ DebugUtil.debugTableToString(tool, " ", 0, cylinderedDepth))
+ end
+ CpUtil.infoImplement(shovelImplement, " %s => ix: %d finished",
+ CpUtil.getName(vehicle), ix)
+ end
+ end
+ end
+ CpUtil.infoImplement(shovelImplement, "-- Cylindered debug finished --")
+ end)
+end
+
+function CpShovelPositions:consoleCommandSetMinimalUnloadHeight(height)
+ return executeConsoleCommand(function(shovelImplement, height)
+ height = tonumber(height)
+ if height == nil then
+ CpUtil.infoVehicle(shovelImplement, "No valid height given! height: %s", tostring(height))
+ return false
+ end
+ local spec = shovelImplement.spec_cpShovelPositions
+ spec.minimalShovelUnloadHeight = height
+ end, height)
+end
+
+function CpShovelPositions:consoleCommandMeasureAndSetMinimalUnloadHeight()
+ return executeConsoleCommand(function(shovelImplement)
+ local controller = ShovelController(shovelImplement.rootVehicle, shovelImplement, true)
+ controller:calculateMinimalUnloadingHeight()
+ controller:delete()
+ end)
end
\ No newline at end of file
diff --git a/scripts/trigger/TriggerWrapper.lua b/scripts/trigger/TriggerWrapper.lua
index bc4548712..369cab4de 100644
--- a/scripts/trigger/TriggerWrapper.lua
+++ b/scripts/trigger/TriggerWrapper.lua
@@ -59,4 +59,10 @@ function CpTrigger:drawPlot(map, selectedTrigger, fillTypes)
end
self.plot:setHighlighted(self == selectedTrigger)
self.plot:draw(map)
-end
\ No newline at end of file
+end
+
+function CpTrigger:isTheSameObject(otherObject)
+ if self.trigger:getTarget().owningPlaceable == otherObject then
+ return true
+ end
+end
From 8fbc32de85653194f6e2084dd5cca9c1f3d258bf Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 3 Sep 2023 10:23:13 +0200
Subject: [PATCH 067/107] small fix
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 5653b0c6e..a55143956 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -355,7 +355,7 @@ function AIDriveStrategyShovelSiloLoader:ignoreProximityObject(object, vehicle)
if object == self.unloadStation then
return true
end
- if self.unloadTrigger:isTheSameObject(object) then
+ if self.unloadTrigger and self.unloadTrigger:isTheSameObject(object) then
return true
end
if self.targetTrailer then
From b6cc4194e73aa566ec9b468c6356afef6dbb45bf Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 3 Sep 2023 10:50:42 +0200
Subject: [PATCH 068/107] Applies the shovel loading state, when hud value was
changed
---
config/VehicleSettingsSetup.xml | 2 +-
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 9 +++++++--
scripts/specializations/CpShovelPositions.lua | 17 +++++++++++++++++
scripts/specializations/CpVehicleSettings.lua | 10 ++++++++++
4 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/config/VehicleSettingsSetup.xml b/config/VehicleSettingsSetup.xml
index 9ac6b2868..3456b6eed 100644
--- a/config/VehicleSettingsSetup.xml
+++ b/config/VehicleSettingsSetup.xml
@@ -77,7 +77,7 @@
+ isVisible="isLoadingShovelOffsetSettingVisible" isDisabled="isLoadingShovelOffsetSettingDisabled" onChangeCallback="onCpLoadingShovelOffsetSettingChanged"/>
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index a55143956..75e61908c 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -440,6 +440,7 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
local trailerData, dist = self:getClosestTrailerAndDistance({})
if not trailerData then
self:debug("No valid trailer found anywhere!")
+ self:setInfoText(InfoTextManager.WAITING_FOR_UNLOADER)
return
end
local trailer = trailerData.trailer
@@ -447,8 +448,10 @@ function AIDriveStrategyShovelSiloLoader:searchForTrailerToUnloadInto()
self:debug("Closest Trailer %s attached to %s with the distance %.2fm/%.2fm found is to far away!",
CpUtil.getName(trailer), trailer.rootVehicle and CpUtil.getName(trailer.rootVehicle) or "no root vehicle",
dist, self.maxValidTrailerDistanceToSiloFront)
+ self:setInfoText(InfoTextManager.WAITING_FOR_UNLOADER)
return
end
+ self:clearInfoText(InfoTextManager.WAITING_FOR_UNLOADER)
--- Sets the unload position node in front of the closest side of the trailer.
self:debug("Found a valid trailer %s within distance %.2f", CpUtil.getName(trailer), dist)
self.targetTrailer = trailerData
@@ -541,7 +544,7 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToUnloadPosition(path,
self:setNewState(self.states.DRIVING_TO_UNLOAD_POSITION)
else
self:debug("Failed to drive close to unload position.")
- -- self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
+ self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
end
end
@@ -575,7 +578,9 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToTrailer(path, goalNo
self:setNewState(self.states.DRIVING_TO_UNLOAD_TRAILER)
else
self:debug("Failed to find path to trailer!")
- self:setNewState(self.states.WAITING_FOR_TRAILER)
+ ---self:setNewState(self.states.WAITING_FOR_TRAILER)
+ --- Later on we might try another approach?
+ self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
end
end
----------------------------------------------------------------
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 726c64caf..c1bd435db 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -82,6 +82,8 @@ end
function CpShovelPositions.registerFunctions(vehicleType)
SpecializationUtil.registerFunction(vehicleType, "cpSetShovelState", CpShovelPositions.cpSetShovelState)
+ SpecializationUtil.registerFunction(vehicleType, "cpSetTemporaryShovelState", CpShovelPositions.cpSetTemporaryShovelState)
+ SpecializationUtil.registerFunction(vehicleType, "cpSetTemporaryLoadingShovelState", CpShovelPositions.cpSetTemporaryLoadingShovelState)
SpecializationUtil.registerFunction(vehicleType, "cpResetShovelState", CpShovelPositions.cpResetShovelState)
SpecializationUtil.registerFunction(vehicleType, "cpSetupShovelPositions", CpShovelPositions.cpSetupShovelPositions)
SpecializationUtil.registerFunction(vehicleType, "areCpShovelPositionsDirty", CpShovelPositions.areCpShovelPositionsDirty)
@@ -133,11 +135,16 @@ function CpShovelPositions:onUpdateTick(dt)
elseif spec.state == CpShovelPositions.UNLOADING then
CpUtil.try(CpShovelPositions.updateUnloadingPosition, self, dt)
end
+ if spec.resetStateWhenReached and not self:areCpShovelPositionsDirty() then
+ self:cpSetShovelState(CpShovelPositions.DEACTIVATED)
+ spec.resetStateWhenReached = false
+ end
end
--- Changes the current shovel state position.
function CpShovelPositions:cpSetShovelState(state)
local spec = self.spec_cpShovelPositions
+ spec.resetWhenReached = false
if spec.state ~= state then
spec.state = state
if state == CpShovelPositions.DEACTIVATED then
@@ -147,6 +154,16 @@ function CpShovelPositions:cpSetShovelState(state)
end
end
+function CpShovelPositions:cpSetTemporaryShovelState(state)
+ local spec = self.spec_cpShovelPositions
+ self:cpSetShovelState(state)
+ spec.resetStateWhenReached = true
+end
+
+function CpShovelPositions:cpSetTemporaryLoadingShovelState()
+ self:cpSetTemporaryShovelState(CpShovelPositions.LOADING)
+end
+
--- Deactivates the shovel position control.
function CpShovelPositions:cpResetShovelState()
CpShovelPositions.debug(self, "Reset shovelPositionState.")
diff --git a/scripts/specializations/CpVehicleSettings.lua b/scripts/specializations/CpVehicleSettings.lua
index 7e3c60375..7d2e397c8 100644
--- a/scripts/specializations/CpVehicleSettings.lua
+++ b/scripts/specializations/CpVehicleSettings.lua
@@ -45,6 +45,7 @@ end
function CpVehicleSettings.registerEvents(vehicleType)
SpecializationUtil.registerEvent(vehicleType, 'onCpUserSettingChanged')
+ SpecializationUtil.registerEvent(vehicleType, 'onCpLoadingShovelOffsetSettingChanged')
end
@@ -57,6 +58,7 @@ function CpVehicleSettings.registerEventListeners(vehicleType)
SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onStateChange", CpVehicleSettings)
SpecializationUtil.registerEventListener(vehicleType, "onCpUserSettingChanged", CpVehicleSettings)
+ SpecializationUtil.registerEventListener(vehicleType, 'onCpLoadingShovelOffsetSettingChanged', CpVehicleSettings)
end
function CpVehicleSettings.registerFunctions(vehicleType)
@@ -398,6 +400,14 @@ function CpVehicleSettings:isLoadingShovelOffsetSettingDisabled()
return not AIUtil.isStopped(self)
end
+function CpVehicleSettings:onCpLoadingShovelOffsetSettingChanged()
+ local shovels, found = AIUtil.getAllChildVehiclesWithSpecialization(self, Shovel)
+ if not found then
+ return false
+ end
+ shovels[1]:cpSetTemporaryLoadingShovelState()
+end
+
--- Saves the user value changed on the server.
function CpVehicleSettings:onCpUserSettingChanged(setting)
if not self.isServer then
From 51e408d9f0adc1e577465f13404a72b7c01476b5 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 3 Sep 2023 12:57:16 +0200
Subject: [PATCH 069/107] Updated comments
---
Courseplay.lua | 2 +-
.../ai/AIDriveStrategyShovelSiloLoader.lua | 14 ++++++++++-
scripts/ai/controllers/ShovelController.lua | 11 ++++++---
scripts/ai/jobs/CpAIJobSiloLoader.lua | 18 ++++++++++-----
scripts/gui/CpAIFrameExtended.lua | 7 ++++--
scripts/gui/UnloadingTriggerPlot.lua | 2 +-
scripts/specializations/CpAIWorker.lua | 1 +
scripts/specializations/CpShovelPositions.lua | 23 ++++++++++++++++++-
scripts/trigger/TriggerWrapper.lua | 1 +
9 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/Courseplay.lua b/Courseplay.lua
index d9c7192bc..2dcb6efa0 100644
--- a/Courseplay.lua
+++ b/Courseplay.lua
@@ -196,7 +196,7 @@ function Courseplay:update(dt)
g_bunkerSiloManager:update(dt)
g_triggerManager:update(dt)
if not self.postInit then
- -- Doubles the map zoom. Mainly to make it easier to set targets for unload triggers.
+ -- Doubles the map zoom for 4x Maps. Mainly to make it easier to set targets for unload triggers.
self.postInit = true
local function setIngameMapFix(mapElement)
local factor = 2*mapElement.terrainSize/2048
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 75e61908c..7d036fe83 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -1,6 +1,6 @@
--[[
This file is part of Courseplay (https://github.com/Courseplay/courseplay)
-Copyright (C) 2022
+Copyright (C) 2023 Courseplay Dev Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,17 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
]]
+--[[
+
+This drive strategy implements:
+ - Loading from an bunker silo or a heap on a field with a wheel loader.
+ - Dumping the picked up fill level to an unload trigger oder a trailer.
+ - Automatically setting the shovel/arm Positions of the wheel loader.
+
+]]
+
+
+
---@class AIDriveStrategyShovelSiloLoader : AIDriveStrategyCourse
---@field shovelController ShovelController
AIDriveStrategyShovelSiloLoader = {}
@@ -251,6 +262,7 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
elseif self.state == self.states.DRIVING_INTO_SILO then
self:setMaxSpeed(self.settings.bunkerSiloSpeed:getValue())
if AIUtil.isStopped(self.vehicle) and not self.proximityController:isStopped() then
+ --- Updates the is stuck timer
self.isStuckTimer:startIfNotRunning()
end
local _, _, closestObject = self.siloEndProximitySensor:getClosestObjectDistanceAndRootVehicle()
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 6ed36a59d..3a46b13c1 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -19,6 +19,7 @@ function ShovelController:init(vehicle, implement, isConsoleCommand)
self.shovelNode = ImplementUtil.getShovelNode(implement)
self.turnOnSpec = self.implement.spec_turnOnVehicle
self.isConsoleCommand = isConsoleCommand
+ --- Sugar can unlading is still WIP
self.isSugarCaneTrailer = self.implement.spec_trailer ~= nil
self.sugarCaneTrailer = {
isDischargeActive = false,
@@ -40,6 +41,7 @@ end
function ShovelController:getDriveData()
local maxSpeed
if self.isSugarCaneTrailer then
+ --- Sugar cane trailer discharge
if self.sugarCaneTrailer.isDischargeActive then
if self.sugarCaneTrailer.isDischargingTimer:get() then
--- Waiting until the discharging stopped or
@@ -67,8 +69,8 @@ function ShovelController:getDriveData()
end
function ShovelController:update(dt)
- --- Sugar cane trailer discharge
if self.isSugarCaneTrailer then
+ --- Sugar cane trailer discharge
if self.sugarCaneTrailer.isDischargeActive then
if self:isEmpty() then
self:finishedSugarCaneTrailerDischarge()
@@ -164,7 +166,7 @@ function ShovelController:isHighDumpShovel()
end
--- Calculates the minimal unloading height for the trigger.
----@param triggerNode any
+---@param triggerNode number|nil
---@return boolean
function ShovelController:calculateMinimalUnloadingHeight(triggerNode)
local sx, sy, sz = getWorldTranslation(self.vehicle:getAIDirectionNode())
@@ -200,6 +202,7 @@ function ShovelController:calculateMinimalUnloadingHeight(triggerNode)
return false
end
+--- Callback checks if an object was hit.
function ShovelController:calculateMinimalUnloadingHeightRaycastCallback(hitObjectId, x, y, z, distance, nx, ny, nz, subShapeIndex, shapeId, isLast)
if hitObjectId then
local object = g_currentMission.nodeToObject[hitObjectId]
@@ -225,6 +228,8 @@ function ShovelController:onFinished()
end
end
+--- Applies the given shovel position and
+--- enables shovels that need an activation for unloading.
---@param pos number shovel position 1-4
---@return boolean reached?
function ShovelController:moveShovelToPosition(pos)
@@ -253,7 +258,7 @@ function ShovelController:moveShovelToPosition(pos)
end
--------------------------------------------
---- Sugar cane trailer functions
+--- WIP! Sugar cane trailer functions
--------------------------------------------
--- Gets the dischargeNode and offset from a selected tip side.
diff --git a/scripts/ai/jobs/CpAIJobSiloLoader.lua b/scripts/ai/jobs/CpAIJobSiloLoader.lua
index 881e5e883..dc3fdc8ca 100644
--- a/scripts/ai/jobs/CpAIJobSiloLoader.lua
+++ b/scripts/ai/jobs/CpAIJobSiloLoader.lua
@@ -1,5 +1,5 @@
---- Job for stationary loader.
----@class CpAIJobSiloLoader : CpAIJobFieldWork
+--- AI Job for silo loader like the ropa maus or wheel loaders.
+---@class CpAIJobSiloLoader : CpAIJob
---@field heapPlot HeapPlot
---@field heapNode number
CpAIJobSiloLoader = {
@@ -79,7 +79,6 @@ function CpAIJobSiloLoader:applyCurrentState(vehicle, mission, farmId, isDirectS
end
end
-
function CpAIJobSiloLoader:setValues()
CpAIJob.setValues(self)
local vehicle = self.vehicleParameter:getVehicle()
@@ -134,7 +133,7 @@ function CpAIJobSiloLoader:validate(farmId)
end
if not AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) then
if self.cpJobParameters.unloadAt:getValue() == CpSiloLoaderJobParameters.UNLOAD_TRIGGER then
- --- Validate the trigger setup
+ --- Validates the unload trigger setup
local found, unloadTrigger, unloadStation = self:getUnloadTriggerAt(self.cpJobParameters.unloadPosition)
if found then
self.unloadStation = unloadStation
@@ -144,6 +143,9 @@ function CpAIJobSiloLoader:validate(farmId)
end
local id = NetworkUtil.getObjectId(unloadStation)
if id ~= nil then
+ CpUtil.debugVehicle(CpDebug.DBG_SILO, vehicle,
+ "Found a valid unload trigger: %s for %s",
+ CpUtil.getName(unloadTrigger), CpUtil.getName(unloadStation))
self:getCpJobParameters().unloadStation:setValue(id)
self:getCpJobParameters().unloadStation:validateUnloadingStation()
end
@@ -199,7 +201,9 @@ function CpAIJobSiloLoader:getUnloadTriggerAt(unloadPosition)
fillType = silo:getFillType()
end
local found, trigger, station = g_triggerManager:getDischargeableUnloadTriggerAt( x, z, dirX, dirZ, 5, 25)
- if found and fillType~=nil then
+ if found and fillType ~= nil then
+ --- Additional check if the fill type of the silo
+ --- matches with the fill type of the unload target.
if not trigger:getIsFillTypeAllowed(fillType) then
--- Fill type is not supported by the trigger.
found = false
@@ -230,10 +234,12 @@ function CpAIJobSiloLoader:drawSilos(map)
end
---- Gets the unload station.
+--- Gets all the unloading stations.
function CpAIJobSiloLoader:getUnloadingStations()
local unloadingStations = {}
for _, unloadingStation in pairs(g_currentMission.storageSystem:getUnloadingStations()) do
+ --- TODO: Maybe a few stations need to be ignored?
+ --- For example stations that have no possible correct fill type
table.insert(unloadingStations, unloadingStation)
end
return unloadingStations
diff --git a/scripts/gui/CpAIFrameExtended.lua b/scripts/gui/CpAIFrameExtended.lua
index 3038501f9..c3d48e1e1 100644
--- a/scripts/gui/CpAIFrameExtended.lua
+++ b/scripts/gui/CpAIFrameExtended.lua
@@ -14,8 +14,8 @@ CpInGameMenuAIFrameExtended.curDrawPositions={}
CpInGameMenuAIFrameExtended.drawDelay = g_updateLoopIndex
CpInGameMenuAIFrameExtended.DELAY = 1
CpInGameMenuAIFrameExtended.hotspotFilterState = {}
+--- Hotspots visible, while drawing a custom field border.
CpInGameMenuAIFrameExtended.validCustomFieldCreationHotspots = {
- --- Hotspots visible, while drawing a custom field border.
[MapHotspot.CATEGORY_FIELD] = true,
-- [MapHotspot.CATEGORY_UNLOADING] = true,
-- [MapHotspot.CATEGORY_LOADING] = true,
@@ -29,8 +29,8 @@ CpInGameMenuAIFrameExtended.validCustomFieldCreationHotspots = {
[CustomFieldHotspot.CATEGORY] = true
}
+--- Hotspots visible, while picking a loading position.
CpInGameMenuAIFrameExtended.validPickingLoadingPositionHotspots = {
- --- Hotspots visible, while picking a loading position.
[MapHotspot.CATEGORY_FIELD] = true,
-- [MapHotspot.CATEGORY_UNLOADING] = true,
-- [MapHotspot.CATEGORY_LOADING] = true,
@@ -155,6 +155,7 @@ end
InGameMenuAIFrame.onLoadMapFinished = Utils.appendedFunction(InGameMenuAIFrame.onLoadMapFinished,
CpInGameMenuAIFrameExtended.onAIFrameLoadMapFinished)
+--- Creates alternative buttons, which are put into the button layout.
function CpInGameMenuAIFrameExtended:setupButtons()
local function createBtn(prefab, text, callback)
local btn = prefab:clone(prefab.parent)
@@ -221,6 +222,7 @@ InGameMenuAIFrame.updateContextInputBarVisibility = Utils.appendedFunction(InGam
function CpInGameMenuAIFrameExtended:setJobMenuVisible(visible)
if not visible then
+ --- Removes the map hotspot, if the job menu of the vehicle is closed.
g_currentMission:removeMapHotspot(self.driveToAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.fieldSiloAiTargetMapHotspot)
g_currentMission:removeMapHotspot(self.unloadAiTargetMapHotspot)
@@ -289,6 +291,7 @@ function InGameMenuAIFrame:onClickOpenCloseCourseGenerator()
end
end
+--- Generates the correct course generator layout and binds the settings to the gui elements.
function CpInGameMenuAIFrameExtended:bindCourseGeneratorSettings()
local vehicle = InGameMenuMapUtil.getHotspotVehicle(self.currentHotspot)
if vehicle ~=nil and vehicle.getCourseGeneratorSettings then
diff --git a/scripts/gui/UnloadingTriggerPlot.lua b/scripts/gui/UnloadingTriggerPlot.lua
index c2913504b..18e69421d 100644
--- a/scripts/gui/UnloadingTriggerPlot.lua
+++ b/scripts/gui/UnloadingTriggerPlot.lua
@@ -1,4 +1,4 @@
---- Draws the bunker silo dimensions on the in game map.
+--- Draws an unloading triggers as a X Symbol on the in game menu map.
---@class UnloadingTriggerPlot
UnloadingTriggerPlot = CpObject()
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 250c3c44f..92ddfbf56 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -547,6 +547,7 @@ end
--- TODO: Do we really need the AIDriveStrategyCollision from giants, as this one is only active for fieldwork?
+--- Maybe there is already a unique cp logic implemented, that catches the use cases.
function CpAIWorker:isCollisionDetectionEnabled()
local spec = self.spec_cpAIWorker
return spec.collisionDetectionEnabled
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index c1bd435db..44bec80ff 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -205,6 +205,7 @@ function CpShovelPositions:cpSetupShovelPositions()
spec.shovelTool = tool
spec.shovelVehicle = vehicle
elseif tool.axis == "AXIS_FRONTLOADER_ARM2" then
+ --- WIP for telescope loaders
spec.armExtendToolIx = i
spec.armExtendTool = tool
spec.armExtendVehicle = vehicle
@@ -215,12 +216,18 @@ function CpShovelPositions:cpSetupShovelPositions()
end
end
+--- Controls the shovel rotation.
+--- Also opens/closes the shovel if needed.
+---@param dt number
+---@param targetAngle number
+---@return boolean isDirty
function CpShovelPositions:controlShovelPosition(dt, targetAngle)
local spec = self.spec_cpShovelPositions
local shovelData = ImplementUtil.getShovelNode(self)
local isDirty = false
if shovelData.movingToolActivation and not spec.isHighDumpShovel then
--- The shovel has a moving tool for grabbing.
+ --- So it needs to be opened for loading and unloading.
for i, tool in pairs(self.spec_cylindered.movingTools) do
if tool.axis and tool.rotMax ~= nil and tool.rotMin ~= nil then
if spec.state ~= CpShovelPositions.TRANSPORT then
@@ -244,6 +251,12 @@ function CpShovelPositions:controlShovelPosition(dt, targetAngle)
spec.shovelTool, dt, goalAngle) or isDirty
end
+--- Performs the unloading with a high dump shovel.
+--- This kind of a shovel has a moving tool for unloading.
+---@param dt number
+---@return boolean isDirty
+---@return number angle
+---@return number targetAngle
function CpShovelPositions:unfoldHighDumpShovel(dt)
local highDumpShovelTool = self.spec_cylindered.movingTools[self.spec_cpShovelPositions.highDumpMovingToolIx]
local _, dy, _ = localDirectionToWorld(getParent(highDumpShovelTool.node), 0, 0, 1)
@@ -257,6 +270,9 @@ function CpShovelPositions:unfoldHighDumpShovel(dt)
return isDirty, angle, targetAngle
end
+--- Folds the high dump shovel back to the normal position.
+---@param dt number
+---@return boolean isDirty
function CpShovelPositions:foldHighDumpShovel(dt)
local highDumpShovelTool = self.spec_cylindered.movingTools[self.spec_cpShovelPositions.highDumpMovingToolIx]
return ImplementUtil.moveMovingToolToRotation(self, highDumpShovelTool, dt,
@@ -268,7 +284,7 @@ end
---@param shovelLimits table
---@param armLimits table
---@param heightOffset number|nil
----@return boolean|nil
+---@return boolean
function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, heightOffset)
heightOffset = heightOffset or 0
local spec = self.spec_cpShovelPositions
@@ -310,8 +326,11 @@ function CpShovelPositions:setShovelPosition(dt, shovelLimits, armLimits, height
local by = shovelY
if self.spec_foliageBending and self.spec_foliageBending.bendingNodes[1] then
+ --- The foliage bending area can be used to get relatively exact dimensions of the shovel.
local bending = self.spec_foliageBending.bendingNodes[1]
if bending.id ~= nil and bending.node ~= nil then
+ --- Trying to find the lowest point of shovel.
+ --- This might be front tip or near the attacher.
local sx, _, sz = localToWorld(shovelTool.node, 0, 0, 0)
local bx1, by1, bz1 = localToWorld(bending.node, 0, 0, bending.minZ)
local bx2, by2, bz2 = localToWorld(bending.node, 0, 0, bending.maxZ)
@@ -533,6 +552,8 @@ function CpShovelPositions:updateUnloadingPosition(dt)
spec.isDirty = isDirty
end
+--- Sets the unload height target of the lowest part of the shovel.
+---@param height number
function CpShovelPositions:setCpShovelMinimalUnloadHeight(height)
local spec = self.spec_cpShovelPositions
spec.minimalShovelUnloadHeight = height
diff --git a/scripts/trigger/TriggerWrapper.lua b/scripts/trigger/TriggerWrapper.lua
index 369cab4de..549db2ab9 100644
--- a/scripts/trigger/TriggerWrapper.lua
+++ b/scripts/trigger/TriggerWrapper.lua
@@ -61,6 +61,7 @@ function CpTrigger:drawPlot(map, selectedTrigger, fillTypes)
self.plot:draw(map)
end
+--- Is the trigger part of the given object?
function CpTrigger:isTheSameObject(otherObject)
if self.trigger:getTarget().owningPlaceable == otherObject then
return true
From 2d07785b9a045c2a7dd3e9d269203776b00bebda Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 4 Sep 2023 20:01:24 +0200
Subject: [PATCH 070/107] Small callstack fixes
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 4 ++--
scripts/ai/AIReverseDriver.lua | 7 +++++--
scripts/ai/ProximityController.lua | 9 ++++-----
3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 7d036fe83..98b7a8805 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -332,8 +332,6 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
end
function AIDriveStrategyShovelSiloLoader:update(dt)
- AIDriveStrategyCourse.update(self)
- self:updateImplementControllers(dt)
if CpDebug:isChannelActive(CpDebug.DBG_SILO, self.vehicle) then
if self.course:isTemporary() then
self.course:draw()
@@ -353,6 +351,8 @@ function AIDriveStrategyShovelSiloLoader:update(dt)
end
CpUtil.drawDebugNode(self.unloadPositionNode, false, 3)
end
+ self:updateImplementControllers(dt)
+ AIDriveStrategyCourse.update(self)
end
--- Ignores the bunker silo and the unload target for the proximity sensors.
diff --git a/scripts/ai/AIReverseDriver.lua b/scripts/ai/AIReverseDriver.lua
index ab3f9f3ff..fedb55bd2 100644
--- a/scripts/ai/AIReverseDriver.lua
+++ b/scripts/ai/AIReverseDriver.lua
@@ -91,8 +91,11 @@ function AIReverseDriver:getDriveData()
-- TODO: consolidate this with AITurn:getTurnNode() and if getAIDirectionNode() considers this already
local tractorNode
if self.vehicle.spec_articulatedAxis then
- tractorNode = AIUtil.getArticulatedAxisVehicleReverserNode(self.vehicle)
- else
+ --- TODO consolidate this with AIUtil.getReverserNode() maybe ??
+ local node = self.vehicle.getAIReverserNode and self.vehicle:getAIReverserNode()
+ tractorNode = node or AIUtil.getArticulatedAxisVehicleReverserNode(self.vehicle)
+ end
+ if not tractorNode then
tractorNode = self.vehicle:getAIDirectionNode()
end
diff --git a/scripts/ai/ProximityController.lua b/scripts/ai/ProximityController.lua
index 4045723dc..3cad859df 100644
--- a/scripts/ai/ProximityController.lua
+++ b/scripts/ai/ProximityController.lua
@@ -161,10 +161,6 @@ end
---@return boolean|nil direction is forwards if true or nil
---@return number maximum speed adjusted to slow down (or 0 to stop) when obstacles are ahead, otherwise maxSpeed
function ProximityController:getDriveData(maxSpeed, moveForwards)
-
- --- Resets the traffic info text.
- self.vehicle:resetCpActiveInfoText(InfoTextManager.BLOCKED_BY_OBJECT)
-
local d, vehicle, object, range, deg, dAvg, hitTerrain = math.huge, nil, nil, 10, 0, 0, false
local pack = moveForwards and self.forwardLookingProximitySensorPack or self.backwardLookingProximitySensorPack
if pack then
@@ -173,12 +169,14 @@ function ProximityController:getDriveData(maxSpeed, moveForwards)
end
if self:ignoreObject(object, vehicle, moveForwards, hitTerrain) then
self:setState(self.states.NO_OBSTACLE, 'No obstacle')
+ self.vehicle:resetCpActiveInfoText(InfoTextManager.BLOCKED_BY_OBJECT)
return nil, nil, nil, maxSpeed
end
if object then
--- Makes sure the detected object is not an implement or the root vehicle.
for _, childVehicle in pairs(self.vehicle:getChildVehicles()) do
if object == childVehicle then
+ self.vehicle:resetCpActiveInfoText(InfoTextManager.BLOCKED_BY_OBJECT)
return nil, nil, nil, maxSpeed
end
end
@@ -228,8 +226,9 @@ function ProximityController:getDriveData(maxSpeed, moveForwards)
end
if self.showBlockedByObjectMessageTimer:get() then
self.vehicle:setCpInfoTextActive(InfoTextManager.BLOCKED_BY_OBJECT)
+ else
+ self.vehicle:resetCpActiveInfoText(InfoTextManager.BLOCKED_BY_OBJECT)
end
-
return nil, nil, nil, maxSpeed
end
From c59fbd638bfaa9f5c906f3de1c5fcc4bceef8217 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 5 Sep 2023 21:14:21 +0200
Subject: [PATCH 071/107] Added missing unfolding at the start
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 2 ++
1 file changed, 2 insertions(+)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 98b7a8805..45dc073bf 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -147,6 +147,8 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
-3, self.silo:getWidth() + 6, self.silo:getLength() + 6)
self.siloController = CpBunkerSiloLoaderController(self.silo, self.vehicle, self)
+
+ self.vehicle:raiseAIEvent("onAIFieldWorkerStart", "onAIImplementStart")
end
-----------------------------------------------------------------------------------------------------------------------
From b7c754072be922aea146bb62fb74ad6b3da8d9b1 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Wed, 6 Sep 2023 19:31:57 +0200
Subject: [PATCH 072/107] DE Update
---
config/MasterTranslations.xml | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index f7cee8016..acf86bc9f 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2508,9 +2508,16 @@ Mit einem Radlader oder Tranktor mit Frontlader und Schaufel, lassen sich Bunker
Die Schaufelpositionen werden dabei automatisch auf die richtige Position gesetzt.
Ist der Modus im HUD nicht direkt zu sehen, sollte er durch das durchschalten der "Startposition" gewählt werden können.
-Schaufeln mit gebiss öffnen dieses sogar beim laden und abladen und schließen dieses zum Transport.
+Im HUD erscheint dann das gewohnte Ziel Icon um direkt mit dem richtigen Modus auf der Helfer Karte zu landen.
+Außerdem gibt es eine Anzeige des Fortschritts, die anzeigt, wie viel % des erkannten Haufens bereits abgearbeitet wurde.
+Die Arbeitsbreite muss eventuell auch angepasst werden, wenn ihr ein Bunker Silo leeren möchtet.
-Die Schaufel zum zerkleinern von Zuckerrüben wird auch unterstützt.
+Der Versatz Schaufelhöhe dient dazu, die höhe über dem Boden anzupassen. Diese Höhe sollte relativ genau sein, damit auch alles eingesammelt wird,
+oder damit der Radlader nicht an Kanten fest hängt. Wird der Wert verändert, fährt die Schaufel automatisch auf die Position und die eingestellte Höhe.
+Zum zurück setzen einfach auf den Text klicken. Der Wert geht von +1 bis -1 in 0,1er Schritten.
+
+Schaufeln mit gebiss öffnen dieses sogar beim laden und abladen und schließen dieses zum Transport,
+sogar die Schaufel zum zerkleinern von Zuckerrüben wird mit allen Funktionen unterstützt.
]]>
Date: Wed, 6 Sep 2023 17:32:22 +0000
Subject: [PATCH 073/107] Updated translations
---
translations/translation_de.xml | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 33aa49ecf..021438955 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -836,9 +836,16 @@ Mit einem Radlader oder Tranktor mit Frontlader und Schaufel, lassen sich Bunker
Die Schaufelpositionen werden dabei automatisch auf die richtige Position gesetzt.
Ist der Modus im HUD nicht direkt zu sehen, sollte er durch das durchschalten der "Startposition" gewählt werden können.
-Schaufeln mit gebiss öffnen dieses sogar beim laden und abladen und schließen dieses zum Transport.
+Im HUD erscheint dann das gewohnte Ziel Icon um direkt mit dem richtigen Modus auf der Helfer Karte zu landen.
+Außerdem gibt es eine Anzeige des Fortschritts, die anzeigt, wie viel % des erkannten Haufens bereits abgearbeitet wurde.
+Die Arbeitsbreite muss eventuell auch angepasst werden, wenn ihr ein Bunker Silo leeren möchtet.
-Die Schaufel zum zerkleinern von Zuckerrüben wird auch unterstützt.
+Der Versatz Schaufelhöhe dient dazu, die höhe über dem Boden anzupassen. Diese Höhe sollte relativ genau sein, damit auch alles eingesammelt wird,
+oder damit der Radlader nicht an Kanten fest hängt. Wird der Wert verändert, fährt die Schaufel automatisch auf die Position und die eingestellte Höhe.
+Zum zurück setzen einfach auf den Text klicken. Der Wert geht von +1 bis -1 in 0,1er Schritten.
+
+Schaufeln mit gebiss öffnen dieses sogar beim laden und abladen und schließen dieses zum Transport,
+sogar die Schaufel zum zerkleinern von Zuckerrüben wird mit allen Funktionen unterstützt.
"/>
+
+
+
From 5efffee42923de5541b87f8adbddda86629c43b9 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 7 Sep 2023 16:30:26 +0200
Subject: [PATCH 075/107] Vehicle config reload fix
---
scripts/config/VehicleConfigurations.lua | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/scripts/config/VehicleConfigurations.lua b/scripts/config/VehicleConfigurations.lua
index f56edeee1..f6162b72d 100644
--- a/scripts/config/VehicleConfigurations.lua
+++ b/scripts/config/VehicleConfigurations.lua
@@ -51,6 +51,9 @@ function VehicleConfigurations:registerXmlSchema()
end
function VehicleConfigurations:loadFromXml()
+ self.vehicleConfigurations = {}
+ self.modVehicleConfigurations = {}
+ self.attributes = {}
self.xmlFileName = Utils.getFilename('config/VehicleConfigurations.xml', Courseplay.BASE_DIRECTORY)
self:registerXmlSchema()
self.xmlFile = self:loadXmlFile(self.xmlFileName, true)
@@ -254,7 +257,10 @@ function VehicleConfigurations:consoleCommandPrintSingleAttributeValuesForVehicl
local values = self:queryAttributeValues(vehicle, attribute)
for _, data in pairs(values) do
if data.found then
- CpUtil.infoVehicle(data.implement, "%s", tostring(data.value))
+ CpUtil.infoVehicle(data.implement, "(%s => Mod: %s) %s",
+ tostring(data.implement.configFileNameClean),
+ tostring(data.implement.customEnvironment ~= nil and data.implement.customEnvironment or false),
+ tostring(data.value))
else
CpUtil.infoVehicle(data.implement, "not found")
end
@@ -273,7 +279,10 @@ function VehicleConfigurations:consoleCommandPrintAllAttributeValuesForVehicleAn
CpUtil.info("Found the following for %s: ....", attribute)
for _, data in pairs(values) do
if data.found then
- CpUtil.infoVehicle(data.implement, "%s", tostring(data.value))
+ CpUtil.infoVehicle(data.implement, "(%s => Mod: %s) %s",
+ tostring(data.implement.configFileNameClean),
+ tostring(data.implement.customEnvironment ~= nil and data.implement.customEnvironment or false),
+ tostring(data.value))
end
end
end
@@ -282,7 +291,8 @@ end
function VehicleConfigurations:consoleCommandPrintAttributeNames()
for attribute, xmlValueType in pairs(self.attributes) do
- CpUtil.info("Attribute: %s => %s", attribute, XMLValueType.TYPES[xmlValueType].name)
+ CpUtil.info("Attribute: %s => %s",
+ attribute, XMLValueType.TYPES[xmlValueType].name)
end
end
From 5f52acd8e0fdc5181dc03f3f2cf11a57792c162b Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 7 Sep 2023 18:45:21 +0200
Subject: [PATCH 076/107] Fixed vehicle config typo
---
scripts/config/VehicleConfigurations.lua | 45 +++++++++++++++++++-----
1 file changed, 37 insertions(+), 8 deletions(-)
diff --git a/scripts/config/VehicleConfigurations.lua b/scripts/config/VehicleConfigurations.lua
index f6162b72d..cef9e48fe 100644
--- a/scripts/config/VehicleConfigurations.lua
+++ b/scripts/config/VehicleConfigurations.lua
@@ -139,17 +139,20 @@ function VehicleConfigurations:get(object, attribute)
CpUtil.infoImplement(object, "The given vehicle config attribute name: %s is not valid!", attribute)
return
end
+ local function getConfigName(data)
+ if data[object.configFileNameClean] then
+ return data[object.configFileNameClean][attribute]
+ elseif data[object.configFileNameClean..".xml"] then
+ return data[object.configFileNameClean..".xml"][attribute]
+ end
+ end
if object and object.configFileNameClean then
local modName = object.customEnvironment
- if self.modVehicleConfigurations[modName] then
+ if modName and self.modVehicleConfigurations[modName] then
--- If a mod name was given, then also check the xml filename.
- if self.modVehicleConfigurations[modName][object.configFileNameClean] then
- return self.modVehicleConfigurations[modName][object.configFileNameClean][attribute]
- end
- elseif self.vehicleConfigurations[object.configFileNameClean] then
- return self.vehicleConfigurations[object.configFileNameClean][attribute]
- elseif self.vehicleConfigurations[object.configFileNameClean..".xml"] then
- return self.vehicleConfigurations[object.configFileNameClean..".xml"][attribute]
+ return getConfigName(self.modVehicleConfigurations[modName])
+ else
+ return getConfigName(self.vehicleConfigurations)
end
end
end
@@ -225,6 +228,12 @@ function VehicleConfigurations:registerConsoleCommands()
g_devHelper.consoleCommands:registerConsoleCommand("cpVehicleConfigurationsListAttributes",
"Prints all valid attribute names",
"consoleCommandPrintAttributeNames", self)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpVehicleConfigurationsPrintAttributes",
+ "Prints all normal attributes",
+ "consoleCommandPrintAllNormalVehicleConfigurations", self)
+ g_devHelper.consoleCommands:registerConsoleCommand("cpVehicleConfigurationsPrintModAttributes",
+ "Prints all mod name attributes",
+ "consoleCommandPrintAllModNameVehicleConfigurations", self)
end
function VehicleConfigurations:consoleCommandReload()
@@ -289,6 +298,26 @@ function VehicleConfigurations:consoleCommandPrintAllAttributeValuesForVehicleAn
end
end
+function VehicleConfigurations:consoleCommandPrintAllModNameVehicleConfigurations()
+ for modName, configurations in pairs(self.modVehicleConfigurations) do
+ for name, configs in pairs(configurations) do
+ for n, v in pairs(configs) do
+ CpUtil.info("(%s => Mod: %s) %s => %s",
+ name, modName, n, v)
+ end
+ end
+ end
+end
+
+function VehicleConfigurations:consoleCommandPrintAllNormalVehicleConfigurations()
+ for name, configs in pairs(self.vehicleConfigurations) do
+ for n, v in pairs(configs) do
+ CpUtil.info("(%s) %s => %s",
+ name, n, v)
+ end
+ end
+end
+
function VehicleConfigurations:consoleCommandPrintAttributeNames()
for attribute, xmlValueType in pairs(self.attributes) do
CpUtil.info("Attribute: %s => %s",
From 98681f741ac10781200a662da03ef2df89a304d7 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 7 Sep 2023 18:50:24 +0200
Subject: [PATCH 077/107] Added missing heap filllevel percentage
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 45dc073bf..d5ed15f45 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -138,6 +138,8 @@ function AIDriveStrategyShovelSiloLoader:startWithoutCourse(jobParameters)
self:debug("Heap was found.")
self.silo = self.heapSilo
end
+ --- fill level, when the driver is started
+ self.fillLevelLeftOverSinceStart = self.silo:getTotalFillLevel()
local cx, cz = self.silo:getFrontCenter()
local dirX, dirZ = self.silo:getLengthDirection()
@@ -357,6 +359,10 @@ function AIDriveStrategyShovelSiloLoader:update(dt)
AIDriveStrategyCourse.update(self)
end
+function AIDriveStrategyShovelSiloLoader:updateCpStatus(status)
+ status:setSiloLoaderStatus(self.silo:getTotalFillLevel(), self.fillLevelLeftOverSinceStart)
+end
+
--- Ignores the bunker silo and the unload target for the proximity sensors.
function AIDriveStrategyShovelSiloLoader:ignoreProximityObject(object, vehicle)
if self.silo:isTheSameSilo(object) then
From cf91cda1009a2563f8948b7c1ad480f398cbbb54 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 7 Sep 2023 18:58:01 +0200
Subject: [PATCH 078/107] EN Translation WIP
---
config/MasterTranslations.xml | 42 +++++++++++++++++++++++++++--------
1 file changed, 33 insertions(+), 9 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index acf86bc9f..b3857447d 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2505,22 +2505,35 @@ Now it's possible to start the helper.
@@ -2528,13 +2541,19 @@ WIP
Um einen Radlader Fahrer zu starten, müssen zunächst über das Ziel Icon im HUD die Lade- und Entladeposition gewählt werden.
Die Ladeposition wird wie auch bereits beim Lader mit der Ladeposition gewählt. Ein blauer Ramen entsteht um den Haufen.
-Die Abladeposition hängt davon ab, ob du in einen Anhänger oder in einen Trigger entladen möchtest.
+Die Abladeposition hängt davon ab, ob du in einen Anhänger oder in einen Lager entladen möchtest.
In einen Anhänger funktioniert automatisch und braucht keine Position. Es wird der naheste, stehende Anhänger gewählt und seitlich angefahren.
Möchtest du in ein Lager entladen, muss zunächst das Ziel umgestellt werden und anschließend den Marker auf den Trigger gesetzt werden.
]]>
@@ -2547,7 +2566,12 @@ Anschließend musst du noch die richtung wählen, in die der Fahrer den Trigger
Das Kreuz sollte jetzt wie im Bild dar gestellt gelb sein.
]]>
From 66e4f825a426589f9331fe28ffcee7a993512860 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Fri, 8 Sep 2023 18:19:10 +0200
Subject: [PATCH 080/107] Some Translation adjustments
---
config/MasterTranslations.xml | 42 +++++++++++++++++------------------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index b3857447d..a6c7bccea 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2504,54 +2504,54 @@ Now it's possible to start the helper.
@@ -2563,7 +2563,7 @@ Da Gebäude mehrere Trigger haben können, muss dieser selber gewählt werden.
Die verfügbaren Trigger werden als orangene Kreuze da gestellt.
Um einen Trigger zu wählen, setzt du den Punkt in der mitte des Runden Icons einfach mittig auf das Kreuz.
Anschließend musst du noch die richtung wählen, in die der Fahrer den Trigger anfahren soll, da es keine klare Richtung eines Triggers gibt.
-Das Kreuz sollte jetzt wie im Bild dar gestellt gelb sein.
+Das Kreuz sollte jetzt, wie im Bild da gestellt, gelb sein.
]]>
Date: Fri, 8 Sep 2023 16:19:34 +0000
Subject: [PATCH 081/107] Updated translations
---
translations/translation_de.xml | 20 ++++++++++----------
translations/translation_en.xml | 22 +++++++++++-----------
2 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 10996c965..30e3413bf 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -832,29 +832,29 @@ Anschließend kann der Helfer gestartet werden.
"/>
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 0ab4c7d95..48851b82f 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -832,27 +832,27 @@ Now it's possible to start the helper.
"/>
From eed839320cb98aa2601663aa0cadb2c743074f0e Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 8 Sep 2023 18:33:12 +0200
Subject: [PATCH 082/107] Changed silo loader status to liter and shovel
grabber adjustment
---
scripts/gui/CpGuiUtil.lua | 20 +++++++++++++++++++
scripts/gui/CpStatus.lua | 15 +++++++++-----
scripts/specializations/CpShovelPositions.lua | 2 +-
3 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/scripts/gui/CpGuiUtil.lua b/scripts/gui/CpGuiUtil.lua
index 7d920a159..489cadcd7 100644
--- a/scripts/gui/CpGuiUtil.lua
+++ b/scripts/gui/CpGuiUtil.lua
@@ -512,3 +512,23 @@ function CpGuiUtil.openGlobalSettingsGui(vehicle)
local inGameMenu = CpGuiUtil.preOpeningInGameMenu(vehicle)
inGameMenu:goToPage(inGameMenu.pageCpGlobalSettings)
end
+
+CpGuiUtil.UNIT_EXTENSIONS = {
+ "k",
+ "M",
+ "G",
+ "T"
+}
+--- Converts the number into kilo, mega, giga or tera units with the correct symbol.
+---@param num number
+---@return number
+---@return string
+function CpGuiUtil.getFixedUnitValueWithUnitSymbol(num)
+ for i=4, 1, -1 do
+ local delta = math.pow(10, 3 * i)
+ if num >= delta then
+ return num / delta, CpGuiUtil.UNIT_EXTENSIONS[i]
+ end
+ end
+ return num, ""
+end
\ No newline at end of file
diff --git a/scripts/gui/CpStatus.lua b/scripts/gui/CpStatus.lua
index e756d37e6..528779123 100644
--- a/scripts/gui/CpStatus.lua
+++ b/scripts/gui/CpStatus.lua
@@ -132,11 +132,16 @@ function CpStatus:getCompactionText(withoutPercentageSymbol)
end
function CpStatus:getSiloFillLevelPercentageLeftOver(withoutPercentageSymbol)
- if self.isActive and self.fillLevelPercentageLeftOver ~=nil then
- if withoutPercentageSymbol then
- return tostring(self.fillLevelPercentageLeftOver)
- end
- return string.format('%d%%', self.fillLevelPercentageLeftOver)
+ -- if self.isActive and self.fillLevelPercentageLeftOver ~=nil then
+ -- if withoutPercentageSymbol then
+ -- return tostring(self.fillLevelPercentageLeftOver)
+ -- end
+ -- return string.format('%d%%', self.fillLevelPercentageLeftOver)
+ -- end
+ -- return '--'
+ if self.isActive and self.fillLevelLeftOver ~= nil then
+ local value, unitExtension = CpGuiUtil.getFixedUnitValueWithUnitSymbol(self.fillLevelLeftOver)
+ return string.format("%.1f %s%s", value, unitExtension, g_i18n:getText("unit_literShort"))
end
return '--'
end
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 44bec80ff..360dd1d66 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -230,7 +230,7 @@ function CpShovelPositions:controlShovelPosition(dt, targetAngle)
--- So it needs to be opened for loading and unloading.
for i, tool in pairs(self.spec_cylindered.movingTools) do
if tool.axis and tool.rotMax ~= nil and tool.rotMin ~= nil then
- if spec.state ~= CpShovelPositions.TRANSPORT then
+ if spec.state == CpShovelPositions.LOADING or spec.state == CpShovelPositions.UNLOADING then
--- Opens the shovel for loading and unloading
isDirty = ImplementUtil.moveMovingToolToRotation(self, tool, dt,
tool.invertAxis and tool.rotMin or tool.rotMax)
From fc7dab8910fadfa750f21d23f3235c58b9931563 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Fri, 8 Sep 2023 18:51:35 +0200
Subject: [PATCH 083/107] Translation adjustment and recheck time reduced
Info for Translator: Line 96 "Progress" -> "Liters left"
---
config/MasterTranslations.xml | 4 ++--
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index a6c7bccea..364deb16b 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -302,8 +302,8 @@
-
-
+
+
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index d5ed15f45..43ec9c93d 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -59,7 +59,7 @@ AIDriveStrategyShovelSiloLoader.myStates = {
}
AIDriveStrategyShovelSiloLoader.maxValidTrailerDistanceToSiloFront = 30
-AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 30
+AIDriveStrategyShovelSiloLoader.searchForTrailerDelaySec = 10
AIDriveStrategyShovelSiloLoader.distShovelTrailerPreUnload = 7
AIDriveStrategyShovelSiloLoader.distShovelUnloadStationPreUnload = 8
AIDriveStrategyShovelSiloLoader.isStuckMs = 1000 * 15
From dccce59851ebb4459719eac78c463a90e325d69c Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Fri, 8 Sep 2023 16:51:54 +0000
Subject: [PATCH 084/107] Updated translations
---
translations/translation_de.xml | 2 +-
translations/translation_en.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index 30e3413bf..9de92e8c7 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -93,7 +93,7 @@
-
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 48851b82f..8741c813d 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -93,7 +93,7 @@
-
+
From f4e197152242785c87f9af566075060fee862aa3 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 8 Sep 2023 18:51:59 +0200
Subject: [PATCH 085/107] Updated comments
---
scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
index 91ebc0aa3..89567521d 100644
--- a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
+++ b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
@@ -35,11 +35,11 @@ function CpSiloLoaderWorkerHudPageElement:setupElements(baseHud, vehicle, lines,
end)
- --- Progress of fill level removed since the start of the driver.
+ --- Displays the fill level of current worked on heap.
local x, y = unpack(lines[4].left)
self.fillLevelProgressLabel = CpTextHudElement.new(self , x , y, CpBaseHud.defaultFontSize)
self.fillLevelProgressLabel:setTextDetails(g_i18n:getText("CP_siloLoader_fillLevelProgress"))
- --- Progress of fill level removed since the start of the driver.
+ --- Displays the fill level of current worked on heap.
local x, y = unpack(lines[4].right)
self.fillLevelProgressText = CpTextHudElement.new(self, x, y, CpBaseHud.defaultFontSize, RenderText.ALIGN_RIGHT)
From 98fc18c6812a702838884f6cd1e1185a7fc3f4ae Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 8 Sep 2023 19:42:00 +0200
Subject: [PATCH 086/107] Timing callstack fix
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 43ec9c93d..61eefd69a 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -293,10 +293,6 @@ function AIDriveStrategyShovelSiloLoader:getDriveData(dt, vX, vY, vZ)
self:searchForTrailerToUnloadInto()
self.lastTrailerSearch = g_time
end
- if CpDebug:isChannelActive(CpDebug.DBG_SILO, self.vehicle) then
- DebugUtil.drawDebugCircleAtNode(self.siloFrontNode, self.maxValidTrailerDistanceToSiloFront,
- math.ceil(self.maxValidTrailerDistanceToSiloFront), nil, false, {0, 3, 0})
- end
elseif self.state == self.states.DRIVING_TO_UNLOAD then
self:setMaxSpeed(self.settings.reverseSpeed:getValue())
local refNode
@@ -337,6 +333,10 @@ end
function AIDriveStrategyShovelSiloLoader:update(dt)
if CpDebug:isChannelActive(CpDebug.DBG_SILO, self.vehicle) then
+ if self.siloFrontNode and self.state == self.states.WAITING_FOR_TRAILER then
+ DebugUtil.drawDebugCircleAtNode(self.siloFrontNode, self.maxValidTrailerDistanceToSiloFront,
+ math.ceil(self.maxValidTrailerDistanceToSiloFront), nil, false, {0, 3, 0})
+ end
if self.course:isTemporary() then
self.course:draw()
elseif self.ppc:getCourse():isTemporary() then
From 6a46f82862460e8758bd7ba2528d52ee808d6d0d Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Fri, 8 Sep 2023 20:41:12 +0200
Subject: [PATCH 087/107] minior debug adjustment
---
scripts/specializations/CpShovelPositions.lua | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 360dd1d66..0cae82b68 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -583,7 +583,7 @@ end
function CpShovelPositions.debug(implement, ...)
if CpShovelPositions.DEBUG then
- CpUtil.infoImplement(implement, ...)
+ CpUtil.debugImplement(implement, ...)
end
end
From cbb38b4213a2f5f866e597b1c580869fd28cd224 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 09:59:11 +0200
Subject: [PATCH 088/107] PR Adjustments
---
config/VehicleConfigurations.xml | 8 +++++---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 2 +-
scripts/ai/ImplementUtil.lua | 4 ----
scripts/gui/CoursePlot.lua | 6 ------
scripts/gui/CpStatus.lua | 7 -------
scripts/pathfinder/PathfinderUtil.lua | 4 ++--
scripts/specializations/CpAIWorker.lua | 16 +++-------------
7 files changed, 11 insertions(+), 36 deletions(-)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index 3e69c4bee..261a3d082 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -98,11 +98,12 @@ You can define the following custom settings:
Used to control the target tilt.
- loadingShovelOffset: number -1 : 1
- Offset relative to the calculated loading shovel position, needs to be set for a shovel implement.
+ Offset to the loading and transport shovel position in meter for the height of the shovel.
- shovelMovingToolIx: number
- If the shovel is a high dump shovel then this moving tool ix is needed.
-
+ If the shovel is a high dump shovel then the moving tool index of the correct one is needed.
+ Usually this index is 1 for the first moving tool.
+
- modName: Name of the .zip file (without '.zip')
In case a Mod has the same .xml filename for the vehicle/implement, as a default giants vehicle/implement,
add the name of the .zip file to prevent conflicts. For example: "FS22_exampleMod".
@@ -138,6 +139,7 @@ You can define the following custom settings:
armMovingToolIx
movingToolIx
shovelMovingToolIx
+ loadingShovelOffset
ignoreBaleCollisionForward
fixWheelLoaderDirectionNodeByMovingToolIx
articulatedAxisReverseNodeInverted
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 61eefd69a..3c117e4c8 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -1,5 +1,5 @@
--[[
-This file is part of Courseplay (https://github.com/Courseplay/courseplay)
+This file is part of Courseplay (https://github.com/Courseplay/Courseplay_FS22)
Copyright (C) 2023 Courseplay Dev Team
This program is free software: you can redistribute it and/or modify
diff --git a/scripts/ai/ImplementUtil.lua b/scripts/ai/ImplementUtil.lua
index f7ccef7b1..82defb206 100644
--- a/scripts/ai/ImplementUtil.lua
+++ b/scripts/ai/ImplementUtil.lua
@@ -378,10 +378,6 @@ function ImplementUtil.moveMovingToolToRotation(implement, tool, dt, rotTarget)
local dir = MathUtil.sign(diff)
local rotSpeed = MathUtil.clamp( math.abs(diff) * math.abs(tool.rotSpeed), math.abs(tool.rotSpeed)/3, 0.5 )
rotSpeed = dir * rotSpeed
- --local rotSpeed = MathUtil.clamp(diff * tool.rotSpeed, tool.rotSpeed/3, 0.5)
- -- if diff < 0 then
- -- rotSpeed=rotSpeed*(-1)
- -- end
if math.abs(diff) < 0.03 or rotSpeed == 0 then
ImplementUtil.stopMovingTool(implement, tool)
return false
diff --git a/scripts/gui/CoursePlot.lua b/scripts/gui/CoursePlot.lua
index aa60429ba..6069f97f0 100644
--- a/scripts/gui/CoursePlot.lua
+++ b/scripts/gui/CoursePlot.lua
@@ -79,12 +79,6 @@ function CoursePlot:setStopPosition( x, z )
self.stopPosition.x, self.stopPosition.z = x, z
end
--- function CoursePlot:screenToWorld( x, y )
--- local worldX = ((x - self.x) / self.scaleX) - self.worldOffsetX
--- local worldZ = ((y - self.y - self.height) / -self.scaleZ) - self.worldOffsetZ
--- return worldX, worldZ
--- end
-
-- Draw the waypoints in the screen area defined in new(), the bottom left corner
-- is at worldX/worldZ coordinates, the size shown is worldWidth wide (and high)
function CoursePlot:drawPoints(map, points, isHudMap)
diff --git a/scripts/gui/CpStatus.lua b/scripts/gui/CpStatus.lua
index 528779123..ce261d9a8 100644
--- a/scripts/gui/CpStatus.lua
+++ b/scripts/gui/CpStatus.lua
@@ -132,13 +132,6 @@ function CpStatus:getCompactionText(withoutPercentageSymbol)
end
function CpStatus:getSiloFillLevelPercentageLeftOver(withoutPercentageSymbol)
- -- if self.isActive and self.fillLevelPercentageLeftOver ~=nil then
- -- if withoutPercentageSymbol then
- -- return tostring(self.fillLevelPercentageLeftOver)
- -- end
- -- return string.format('%d%%', self.fillLevelPercentageLeftOver)
- -- end
- -- return '--'
if self.isActive and self.fillLevelLeftOver ~= nil then
local value, unitExtension = CpGuiUtil.getFixedUnitValueWithUnitSymbol(self.fillLevelLeftOver)
return string.format("%.1f %s%s", value, unitExtension, g_i18n:getText("unit_literShort"))
diff --git a/scripts/pathfinder/PathfinderUtil.lua b/scripts/pathfinder/PathfinderUtil.lua
index a2423dfae..32b19e645 100644
--- a/scripts/pathfinder/PathfinderUtil.lua
+++ b/scripts/pathfinder/PathfinderUtil.lua
@@ -890,8 +890,8 @@ function PathfinderUtil.getNodePositionAndDirection(node, xOffset, zOffset)
end
---@param vehicle table
----@param xOffset|nil
----@param zOffset|nil
+---@param xOffset number|nil
+---@param zOffset number|nil
---@return State3D position/heading of vehicle
function PathfinderUtil.getVehiclePositionAsState3D(vehicle, xOffset, zOffset)
local x, z, yRot = PathfinderUtil.getNodePositionAndDirection( AIUtil.getDirectionNode(vehicle), xOffset, zOffset)
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 92ddfbf56..5532b9210 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -72,7 +72,6 @@ function CpAIWorker.registerFunctions(vehicleType)
SpecializationUtil.registerFunction(vehicleType, "cpHold", CpAIWorker.cpHold)
SpecializationUtil.registerFunction(vehicleType, "cpBrakeToStop", CpAIWorker.cpBrakeToStop)
SpecializationUtil.registerFunction(vehicleType, "getCpDriveStrategy", CpAIWorker.getCpDriveStrategy)
- SpecializationUtil.registerFunction(vehicleType, 'getCpReverseDrivingDirectionNode', CpAIWorker.getCpReverseDrivingDirectionNode)
end
function CpAIWorker.registerOverwrittenFunctions(vehicleType)
@@ -503,21 +502,12 @@ function CpAIWorker:getCpDriveStrategy()
return spec.driveStrategy
end
-function CpAIWorker:getCpReverseDrivingDirectionNode()
- local spec = self.spec_cpAIWorker
- if not spec.reverseDrivingDirectionNode and SpecializationUtil.hasSpecialization(ReverseDriving, self.specializations) then
- spec.reverseDrivingDirectionNode =
- CpUtil.createNewLinkedNode(self, "realReverseDrivingDirectionNode", self:getAIDirectionNode())
- setRotation(spec.reverseDrivingDirectionNode, 0, math.pi, 0)
- end
- return spec.reverseDrivingDirectionNode
-end
-
--- Fixes the ai reverse node rotation for articulated axis vehicles,
--- if the node is pointing backwards and not forwards.
+--- TODO: Consider consolidation with AIUtil.getArticulatedAxisVehicleReverserNode
function CpAIWorker:getAIReverserNode(superFunc)
local spec = self.spec_cpAIWorker
- -- if not self:getIsCpActive() then return superFunc(self) end
+ if not self:getIsCpActive() then return superFunc(self) end
if self.spec_articulatedAxis and self.spec_articulatedAxis.aiRevereserNode then
if g_vehicleConfigurations:get(self, "articulatedAxisReverseNodeInverted") then
if not spec.articulatedAxisReverseNode then
@@ -536,7 +526,7 @@ end
--- So we use the parent node of the arm tool node.
---@param superFunc any
function CpAIWorker:getAIDirectionNode(superFunc)
- -- if not self:getIsCpActive() then return superFunc(self) end
+ if not self:getIsCpActive() then return superFunc(self) end
local movingToolIx = g_vehicleConfigurations:get(self, "fixWheelLoaderDirectionNodeByMovingToolIx")
if movingToolIx ~= nil then
return getParent(self.spec_cylindered.movingTools[movingToolIx].node)
From 5bd671d0bd0b76d3baf0517590275784e1568bc9 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 10:42:15 +0200
Subject: [PATCH 089/107] Small adjustment for vehicle config
---
config/VehicleSettingsSetup.xml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/config/VehicleSettingsSetup.xml b/config/VehicleSettingsSetup.xml
index 3456b6eed..adbfe7500 100644
--- a/config/VehicleSettingsSetup.xml
+++ b/config/VehicleSettingsSetup.xml
@@ -77,7 +77,8 @@
+ isVisible="isLoadingShovelOffsetSettingVisible" isDisabled="isLoadingShovelOffsetSettingDisabled"
+ onChangeCallback="onCpLoadingShovelOffsetSettingChanged" vehicleConfiguration="loadingShovelOffset"/>
From 1dc8ef47e98c190ac67e857eef487fee46ffd559 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 10:57:53 +0200
Subject: [PATCH 090/107] debug fix
---
scripts/trigger/TriggerManager.lua | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/trigger/TriggerManager.lua b/scripts/trigger/TriggerManager.lua
index d841002da..20386277f 100644
--- a/scripts/trigger/TriggerManager.lua
+++ b/scripts/trigger/TriggerManager.lua
@@ -2,7 +2,7 @@
--- For now only unload triggers are supported.
---@class TriggerManager
TriggerManager = CpObject()
-TriggerManager.DEBUG = true
+TriggerManager.DEBUG = false
function TriggerManager:init()
---@type table
self.unloadTriggers = {}
From 2ea4cfdb9ff83c56f8952dca3eea9f5a73529223 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 11:37:19 +0200
Subject: [PATCH 091/107] Fixes shovel controller mp for now
---
scripts/ai/controllers/ShovelController.lua | 2 +-
scripts/specializations/CpAIWorker.lua | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/scripts/ai/controllers/ShovelController.lua b/scripts/ai/controllers/ShovelController.lua
index 3a46b13c1..22d4ca547 100644
--- a/scripts/ai/controllers/ShovelController.lua
+++ b/scripts/ai/controllers/ShovelController.lua
@@ -222,7 +222,7 @@ function ShovelController:calculateMinimalUnloadingHeightRaycastCallback(hitObje
return false
end
-function ShovelController:onFinished()
+function ShovelController:delete()
if self.implement.cpResetShovelState then
self.implement:cpResetShovelState()
end
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 5532b9210..1fcdcbedb 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -297,6 +297,8 @@ end
--- Used to enable/disable release of the helper
--- and handles post release functionality with for example auto drive.
+--- TODO: this might by only called on the client, so
+--- server depended code has to be moved to stopJob or similar code.
function CpAIWorker:stopCurrentAIJob(superFunc, message, ...)
if message then
CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, self, "stop message: %s", message:getMessage())
From 33c1d9634a8481122f066787ad852d9f81ba0bbd Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 12:08:58 +0200
Subject: [PATCH 092/107] Bug fix ...
---
scripts/CpUtil.lua | 5 ++---
scripts/editor/CourseEditor.lua | 4 +++-
scripts/specializations/CpAIWorker.lua | 1 +
scripts/specializations/CpShovelPositions.lua | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/scripts/CpUtil.lua b/scripts/CpUtil.lua
index 65f2436ad..aa7de4cdf 100644
--- a/scripts/CpUtil.lua
+++ b/scripts/CpUtil.lua
@@ -169,11 +169,10 @@ end
--- Debug function for implements, that calls CpUtil.debugVehicle, with the root vehicle.
---@param channel number
---@param implement table
----@param ... unknown
-function CpUtil.debugImplement(channel, implement, ...)
+function CpUtil.debugImplement(channel, implement, str, ...)
local rootVehicle = implement and implement.rootVehicle or implement
CpUtil.debugVehicle(channel, rootVehicle,
- CpUtil.getName(implement) .. ': ' .. string.format(...))
+ CpUtil.getName(implement) .. ": " .. str, ...)
end
function CpUtil.isVehicleDebugActive(vehicle)
diff --git a/scripts/editor/CourseEditor.lua b/scripts/editor/CourseEditor.lua
index e11782857..a2e34485e 100644
--- a/scripts/editor/CourseEditor.lua
+++ b/scripts/editor/CourseEditor.lua
@@ -114,7 +114,9 @@ function CourseEditor:showYesNoDialog(title, callbackFunc)
end
function CourseEditor:delete()
- self.courseDisplay:delete()
+ if self.courseDisplay then
+ self.courseDisplay:delete()
+ end
end
--- Updates the course display, when a waypoint change happened.
diff --git a/scripts/specializations/CpAIWorker.lua b/scripts/specializations/CpAIWorker.lua
index 1fcdcbedb..5e39040fc 100644
--- a/scripts/specializations/CpAIWorker.lua
+++ b/scripts/specializations/CpAIWorker.lua
@@ -468,6 +468,7 @@ function CpAIWorker:cpHold(ms)
end
end
+---@param strategy AIDriveStrategyCourse
function CpAIWorker:startCpWithStrategy(strategy)
local spec = self.spec_cpAIWorker
spec.driveStrategy = strategy
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 0cae82b68..d8e73eb00 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -583,7 +583,7 @@ end
function CpShovelPositions.debug(implement, ...)
if CpShovelPositions.DEBUG then
- CpUtil.debugImplement(implement, ...)
+ CpUtil.debugImplement(CpDebug.DBG_SILO, implement, ...)
end
end
From ec2e6b5091ac92db70f1b28ef0e501bcfe0fb3c5 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 12:33:18 +0200
Subject: [PATCH 093/107] Added additional mp safety check for shovel positions
---
scripts/specializations/CpShovelPositions.lua | 3 +++
1 file changed, 3 insertions(+)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index d8e73eb00..82ef7e1ea 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -143,6 +143,7 @@ end
--- Changes the current shovel state position.
function CpShovelPositions:cpSetShovelState(state)
+ if not self.isServer then return end
local spec = self.spec_cpShovelPositions
spec.resetWhenReached = false
if spec.state ~= state then
@@ -155,6 +156,7 @@ function CpShovelPositions:cpSetShovelState(state)
end
function CpShovelPositions:cpSetTemporaryShovelState(state)
+ if not self.isServer then return end
local spec = self.spec_cpShovelPositions
self:cpSetShovelState(state)
spec.resetStateWhenReached = true
@@ -166,6 +168,7 @@ end
--- Deactivates the shovel position control.
function CpShovelPositions:cpResetShovelState()
+ if not self.isServer then return end
CpShovelPositions.debug(self, "Reset shovelPositionState.")
local spec = self.spec_cpShovelPositions
spec.state = CpShovelPositions.DEACTIVATED
From 330314aeb00f9a45ee09b026f62923c937c51132 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 14:34:26 +0200
Subject: [PATCH 094/107] Update modDesc.xml
---
modDesc.xml | 82 ++++++++++++++++++++++++++---------------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/modDesc.xml b/modDesc.xml
index 3122d9935..d03191a74 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -222,11 +222,24 @@ Changelog 7.1.0.0:
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -238,21 +251,20 @@ Changelog 7.1.0.0:
-
-
-
-
-
+
+
+
+
@@ -261,17 +273,30 @@ Changelog 7.1.0.0:
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -283,16 +308,8 @@ Changelog 7.1.0.0:
-
-
-
-
-
-
-
-
-
-
+
+
@@ -327,35 +344,14 @@ Changelog 7.1.0.0:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -363,6 +359,7 @@ Changelog 7.1.0.0:
+
@@ -370,9 +367,7 @@ Changelog 7.1.0.0:
-
-
-
+
@@ -387,6 +382,7 @@ Changelog 7.1.0.0:
+
@@ -395,6 +391,7 @@ Changelog 7.1.0.0:
+
@@ -407,6 +404,7 @@ Changelog 7.1.0.0:
+
From 4ac14e786b68208d9848ea6d5b6a434f363e53e3 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 14:38:21 +0200
Subject: [PATCH 095/107] Rebase fix
---
modDesc.xml | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/modDesc.xml b/modDesc.xml
index d03191a74..56bea87ef 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -297,19 +297,6 @@ Changelog 7.1.0.0:
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -345,6 +332,19 @@ Changelog 7.1.0.0:
+
+
+
+
+
+
+
+
+
+
+
+
+
From e8544649d712038ef89a72df9a10783d2e83d37a Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sun, 10 Sep 2023 20:32:55 +0200
Subject: [PATCH 096/107] Added vehicle config for premos
---
config/VehicleConfigurations.xml | 16 +++++++++++++++-
scripts/ai/controllers/PipeController.lua | 16 ++++++++++++----
2 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/config/VehicleConfigurations.xml b/config/VehicleConfigurations.xml
index 261a3d082..d50e7001c 100644
--- a/config/VehicleConfigurations.xml
+++ b/config/VehicleConfigurations.xml
@@ -117,9 +117,16 @@ You can define the following custom settings:
Fixes the ai direction node for the platinum wheel loaders, as their direction is not changed based on the rotation.
As a fix the parent node of the arm moving tool ix is used.
-- articulatedAxisReverseNodeInverted
+- articulatedAxisReverseNodeInverted: boolean
Is the reverse node for articulated axis vehicles rotated by 180 degree?
+- unloadXOffset: number
+ Offset of the discharge node or a given pipe for unloading into a trailer.
+ For pipes this overwrites the measured pipe offset.
+
+- disablePipeMovingToolCorrection: boolean
+ Disables the pipe height adjustment for trailers of a few pipe implements/vehicles.
+
-->
@@ -143,6 +150,8 @@ You can define the following custom settings:
ignoreBaleCollisionForward
fixWheelLoaderDirectionNodeByMovingToolIx
articulatedAxisReverseNodeInverted
+ disablePipeMovingToolCorrection
+ unloadOffsetX
@@ -535,4 +544,9 @@ You can define the following custom settings:
turnRadius = "10"
/>
+
+
diff --git a/scripts/ai/controllers/PipeController.lua b/scripts/ai/controllers/PipeController.lua
index 2ed47da1e..2040c0574 100644
--- a/scripts/ai/controllers/PipeController.lua
+++ b/scripts/ai/controllers/PipeController.lua
@@ -293,7 +293,11 @@ function PipeController:measurePipeProperties()
currentPipeState, targetPipeState, pipeAnimTime)
self:printFoldableDebug()
self:printPipeDebug()
-
+ local configOffsetX = g_vehicleConfigurations:get(self.implement, "unloadOffsetX" )
+ if configOffsetX ~= nil then
+ self:debug("Setting pipe x offset to configured %.2f x offset", configOffsetX)
+ self.pipeOffsetX = configOffsetX
+ end
end
--- Unfolds the pipe completely to measure the pipe properties.
@@ -403,6 +407,13 @@ end
function PipeController:setupMoveablePipe()
self.validMovingTools = {}
+ self.hasPipeMovingTools = false
+ self.tempBaseNode = CpUtil.createNode("tempBaseNode", 0, 0, 0)
+ self.tempDependedNode = CpUtil.createNode("tempDependedNode", 0, 0, 0)
+ if g_vehicleConfigurations:get(self.implement, "disablePipeMovingToolCorrection") then
+ --- Moveable pipe will not be adjusted based on a nearby trailer.
+ return
+ end
if self.cylinderedSpec and self.pipeSpec.numAutoAimingStates <= 0 then
for i, m in ipairs(self.cylinderedSpec.movingTools) do
-- Gets only the pipe moving tools.
@@ -437,9 +448,6 @@ function PipeController:setupMoveablePipe()
end
end
- self.tempBaseNode = CpUtil.createNode("tempBaseNode", 0, 0, 0)
- self.tempDependedNode = CpUtil.createNode("tempDependedNode", 0, 0, 0)
-
self:debug("Number of moveable pipe elements found: %d", #self.validMovingTools)
end
From 43c026edddf6e904cee404ac189e637a7d1bd63e Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Mon, 11 Sep 2023 09:17:14 +0200
Subject: [PATCH 097/107] Translation adjustments
---
config/MasterTranslations.xml | 72 ++++++++++++++++++-----------------
1 file changed, 38 insertions(+), 34 deletions(-)
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index 364deb16b..d86e4a427 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -2505,55 +2505,59 @@ Now it's possible to start the helper.
@@ -2561,17 +2565,17 @@ If you want to unload into a storage, you need to switch the target and then mar
Die Auswahl eines Triggers wirkt zunächst kompliziert, ist aber im Prinzip recht einfach.
Da Gebäude mehrere Trigger haben können, muss dieser selber gewählt werden.
Die verfügbaren Trigger werden als orangene Kreuze da gestellt.
-Um einen Trigger zu wählen, setzt du den Punkt in der mitte des Runden Icons einfach mittig auf das Kreuz.
-Anschließend musst du noch die richtung wählen, in die der Fahrer den Trigger anfahren soll, da es keine klare Richtung eines Triggers gibt.
+Um einen Trigger zu wählen, setzt du den Punkt in der Mitte des runden Icons einfach mittig auf das Kreuz.
+Die Richtung des Pfeils entspricht hierbei die Anfahrtsrichtung vom Helfer.
Das Kreuz sollte jetzt, wie im Bild da gestellt, gelb sein.
]]>
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 8741c813d..b84ef98c0 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -832,37 +832,40 @@ Now it's possible to start the helper.
"/>
From c24c1b6f6a7bc15592466997b85c0051c6f6a070 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 12 Sep 2023 19:19:42 +0200
Subject: [PATCH 099/107] Fixes hud bug
---
scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
index 89567521d..4d5068109 100644
--- a/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
+++ b/scripts/gui/hud/CpSiloLoaderWorkerHudPage.lua
@@ -156,7 +156,7 @@ function CpSiloLoaderWorkerHudPageElement:arePositionEqual(parameters, otherPara
end
function CpSiloLoaderWorkerHudPageElement:isStartingPointBtnDisabled(vehicle)
- return AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt)
+ return AIUtil.hasChildVehicleWithSpecialization(vehicle, ConveyorBelt) or vehicle:getIsCpActive()
end
function CpSiloLoaderWorkerHudPageElement:getStartingPointBtnText(vehicle)
From 867576f41d3fff896efc8d31422ed5e720478326 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Sat, 16 Sep 2023 17:39:18 +0200
Subject: [PATCH 100/107] Rebase fix
---
scripts/ai/AIReverseDriver.lua | 141 +++++++++++++++++----------------
1 file changed, 72 insertions(+), 69 deletions(-)
diff --git a/scripts/ai/AIReverseDriver.lua b/scripts/ai/AIReverseDriver.lua
index fedb55bd2..249767095 100644
--- a/scripts/ai/AIReverseDriver.lua
+++ b/scripts/ai/AIReverseDriver.lua
@@ -63,87 +63,90 @@ function AIReverseDriver:debug(...)
end
function AIReverseDriver:getDriveData()
- if self.reversingImplement == nil then
- -- no wheeled implement, simple reversing the PPC can handle by itself
- return nil
- end
-
- local trailerNode = self.reversingImplement.steeringAxleNode
- local xTipper, yTipper, zTipper = getWorldTranslation(trailerNode);
-
- local trailerFrontNode = self.reversingImplement.reversingProperties.frontNode
- local xFrontNode,yFrontNode,zFrontNode = getWorldTranslation(trailerFrontNode)
-
- local tx, ty, tz = self.ppc:getGoalPointPosition()
-
- local lxTipper, lzTipper = AIVehicleUtil.getDriveDirection(trailerNode, tx, ty, tz)
-
- self:showDirection(trailerNode, lxTipper, lzTipper, 1, 0, 0)
-
- local lxFrontNode, lzFrontNode = AIVehicleUtil.getDriveDirection(trailerFrontNode, xTipper, yTipper, zTipper)
-
- local lxTractor, lzTractor = 0, 0
+ if self.reversingImplement == nil then
+ -- no wheeled implement, simple reversing the PPC can handle by itself
+ return nil
+ end
- local maxTractorAngle = math.rad(75)
+ -- if there's a reverser node on the tool, use that, otherwise the steering node
+ -- the reverser direction node, if exists, works better for tools with offset or for
+ -- rotating plows where it remains oriented and placed correctly
+ local trailerNode = AIVehicleUtil.getAIToolReverserDirectionNode(self.vehicle) or self.reversingImplement.steeringAxleNode
+ local trailerFrontNode = self.reversingImplement.reversingProperties.frontNode
+
+ local tx, ty, tz = self.ppc:getGoalPointPosition()
+ local lxTrailer, lzTrailer = AIVehicleUtil.getDriveDirection(trailerNode, tx, ty, tz)
+ self:showDirection(trailerNode, lxTrailer, lzTrailer, 1, 0, 0)
+
+ local maxTractorAngle = math.rad(75)
+
+ -- for articulated vehicles use the articulated axis' rotation node as it is a better indicator or the
+ -- vehicle's orientation than the direction node which often turns/moves with an articulated vehicle part
+ -- TODO: consolidate this with AITurn:getTurnNode() and if getAIDirectionNode() considers this already
+ local tractorNode
+ local useArticulatedAxisRotationNode = SpecializationUtil.hasSpecialization(ArticulatedAxis, self.vehicle.specializations) and self.vehicle.spec_articulatedAxis.rotationNode
+ if useArticulatedAxisRotationNode then
+ tractorNode = self.vehicle.spec_articulatedAxis.rotationNode
+ else
+ tractorNode = self.vehicle:getAIDirectionNode()
+ end
- -- for articulated vehicles use the articulated axis' reverser node as it is a better indicator or the
- -- vehicle's orientation than the direction node which often turns/moves with an articulated vehicle part
- -- TODO: consolidate this with AITurn:getTurnNode() and if getAIDirectionNode() considers this already
- local tractorNode
- if self.vehicle.spec_articulatedAxis then
- --- TODO consolidate this with AIUtil.getReverserNode() maybe ??
- local node = self.vehicle.getAIReverserNode and self.vehicle:getAIReverserNode()
- tractorNode = node or AIUtil.getArticulatedAxisVehicleReverserNode(self.vehicle)
- end
- if not tractorNode then
- tractorNode = self.vehicle:getAIDirectionNode()
- end
+ local lx, lz, angleDiff
- local lx, lz, angleDiff
-
- if self.reversingImplement.reversingProperties.isPivot then
- self:showDirection(trailerFrontNode, lxFrontNode, lzFrontNode, 0, 1, 0)
+ if self.reversingImplement.reversingProperties.isPivot then
+ -- The trailer/implement has a front axle (or dolly) with a draw bar.
+ -- The current Courseplay dev team has no idea how this works :), this is magic
+ -- from the old code, written by Satissis (Claus).
+ -- TODO: adapt a documented algorithm for these trailers
+ local xTrailer, yTrailer, zTrailer = getWorldTranslation(trailerNode);
+ local xFrontNode, yFrontNode, zFrontNode = getWorldTranslation(trailerFrontNode)
+ local lxFrontNode, lzFrontNode = AIVehicleUtil.getDriveDirection(trailerFrontNode, xTrailer, yTrailer, zTrailer)
+ self:showDirection(trailerFrontNode, lxFrontNode, lzFrontNode, 0, 1, 0)
- lxTractor, lzTractor = AIVehicleUtil.getDriveDirection(tractorNode, xFrontNode, yFrontNode, zFrontNode)
- self:showDirection(tractorNode,lxTractor, lzTractor, 0, 0.7, 0)
+ local lxTractor, lzTractor = AIVehicleUtil.getDriveDirection(tractorNode, xFrontNode, yFrontNode, zFrontNode)
+ self:showDirection(tractorNode, lxTractor, lzTractor, 0, 0.7, 0)
- local rotDelta = (self.reversingImplement.reversingProperties.nodeDistance *
- (0.5 - (0.023 * self.reversingImplement.reversingProperties.nodeDistance - 0.073)))
- local trailerToWaypointAngle = self:getLocalYRotationToPoint(trailerNode, tx, ty, tz, -1) * rotDelta
- trailerToWaypointAngle = MathUtil.clamp(trailerToWaypointAngle, -math.rad(90), math.rad(90))
+ local rotDelta = (self.reversingImplement.reversingProperties.nodeDistance *
+ (0.5 - (0.023 * self.reversingImplement.reversingProperties.nodeDistance - 0.073)))
+ local trailerToWaypointAngle = self:getLocalYRotationToPoint(trailerNode, tx, ty, tz, -1) * rotDelta
+ trailerToWaypointAngle = MathUtil.clamp(trailerToWaypointAngle, -math.rad(90), math.rad(90))
- local dollyToTrailerAngle = self:getLocalYRotationToPoint(trailerFrontNode, xTipper, yTipper, zTipper, -1)
+ local dollyToTrailerAngle = self:getLocalYRotationToPoint(trailerFrontNode, xTrailer, yTrailer, zTrailer, -1)
- local tractorToDollyAngle = self:getLocalYRotationToPoint(tractorNode, xFrontNode, yFrontNode, zFrontNode, -1)
+ local tractorToDollyAngle = self:getLocalYRotationToPoint(tractorNode, xFrontNode, yFrontNode, zFrontNode, -1)
- local rearAngleDiff = (dollyToTrailerAngle - trailerToWaypointAngle)
- rearAngleDiff = MathUtil.clamp(rearAngleDiff, -math.rad(45), math.rad(45))
+ local rearAngleDiff = (dollyToTrailerAngle - trailerToWaypointAngle)
+ rearAngleDiff = MathUtil.clamp(rearAngleDiff, -math.rad(45), math.rad(45))
- local frontAngleDiff = (tractorToDollyAngle - dollyToTrailerAngle)
- frontAngleDiff = MathUtil.clamp(frontAngleDiff, -math.rad(45), math.rad(45))
+ local frontAngleDiff = (tractorToDollyAngle - dollyToTrailerAngle)
+ frontAngleDiff = MathUtil.clamp(frontAngleDiff, -math.rad(45), math.rad(45))
- angleDiff = (frontAngleDiff - rearAngleDiff) *
- (1.5 - (self.reversingImplement.reversingProperties.nodeDistance * 0.4 - 0.9) + rotDelta)
- angleDiff = MathUtil.clamp(angleDiff, -math.rad(45), math.rad(45))
+ angleDiff = (frontAngleDiff - rearAngleDiff) *
+ (1.5 - (self.reversingImplement.reversingProperties.nodeDistance * 0.4 - 0.9) + rotDelta)
+ angleDiff = MathUtil.clamp(angleDiff, -math.rad(45), math.rad(45))
- lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
- else
- local crossTrackError, orientationError, curvatureError, currentHitchAngle = self:calculateErrors(tractorNode, trailerNode)
- angleDiff = self:calculateHitchCorrectionAngle(crossTrackError, orientationError, curvatureError, currentHitchAngle)
- angleDiff = MathUtil.clamp(angleDiff, -maxTractorAngle, maxTractorAngle)
+ lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
+ else
+ -- the trailer/implement is like a semi-trailer, has a rear axle only, the front of the implement
+ -- is supported by the tractor
+ local crossTrackError, orientationError, curvatureError, currentHitchAngle = self:calculateErrors(tractorNode, trailerNode)
+ angleDiff = self:calculateHitchCorrectionAngle(crossTrackError, orientationError, curvatureError, currentHitchAngle)
+ angleDiff = MathUtil.clamp(angleDiff, -maxTractorAngle, maxTractorAngle)
- lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
- end
+ lx, lz = MathUtil.getDirectionFromYRotation(angleDiff)
+ end
- self:showDirection(tractorNode, lx, lz, 0.7, 0, 1)
- -- do a little bit of damping if using the articulated axis as lx tends to oscillate around 0 which results in the
- -- speed adjustment kicking in and slowing down the vehicle.
- if useArticulatedAxisRotationNode and math.abs(lx) < 0.04 then lx = 0 end
- -- construct an artificial goal point to drive to
- lx, lz = -lx * self.ppc:getLookaheadDistance(), -lz * self.ppc:getLookaheadDistance()
- -- AIDriveStrategy wants a global position to drive to (which it later converts to local, but whatever...)
- local gx, _, gz = localToWorld(self.vehicle:getAIDirectionNode(), lx, 0, lz)
- return gx, gz, false, self.settings.reverseSpeed:getValue()
+ self:showDirection(tractorNode, lx, lz, 0.7, 0, 1)
+ -- do a little bit of damping if using the articulated axis as lx tends to oscillate around 0 which results in the
+ -- speed adjustment kicking in and slowing down the vehicle.
+ if useArticulatedAxisRotationNode and math.abs(lx) < 0.04 then
+ lx = 0
+ end
+ -- construct an artificial goal point to drive to
+ lx, lz = -lx * self.ppc:getLookaheadDistance(), -lz * self.ppc:getLookaheadDistance()
+ -- AIDriveStrategy wants a global position to drive to (which it later converts to local, but whatever...)
+ local gx, _, gz = localToWorld(self.vehicle:getAIDirectionNode(), lx, 0, lz)
+ return gx, gz, false, self.settings.reverseSpeed:getValue()
end
function AIReverseDriver:getLocalYRotationToPoint(node, x, y, z, direction)
@@ -273,4 +276,4 @@ function AIReverseDriver:calculateHitchCorrectionAngle(crossTrackError, orientat
end
return correctionAngle
-end
+end
\ No newline at end of file
From d9b40823ff4114a2cd4e148cb08c17078a099ec0 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 19 Sep 2023 19:44:48 +0200
Subject: [PATCH 101/107] Removed leftover debug
---
scripts/specializations/CpShovelPositions.lua | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/scripts/specializations/CpShovelPositions.lua b/scripts/specializations/CpShovelPositions.lua
index 82ef7e1ea..0ac058084 100644
--- a/scripts/specializations/CpShovelPositions.lua
+++ b/scripts/specializations/CpShovelPositions.lua
@@ -113,12 +113,7 @@ function CpShovelPositions:onPostAttach()
end
function CpShovelPositions:onDraw()
- if CpShovelPositions.DEBUG and self:getRootVehicle() then
- local angle, shovelNode, maxAngle, minAngle, factor = CpShovelPositions.getShovelData(self)
- if shovelNode then
- DebugUtil.drawDebugNode(shovelNode, "shovelNode")
- end
- end
+
end
function CpShovelPositions:onUpdateTick(dt)
From 1e682d87674ac3e4cb9507f040aeaeb429f00e8d Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Tue, 19 Sep 2023 19:58:20 +0200
Subject: [PATCH 102/107] Stops the driver if no path to the silo is found.
---
scripts/ai/AIDriveStrategyShovelSiloLoader.lua | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
index 3c117e4c8..1f28a76aa 100644
--- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
+++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua
@@ -526,10 +526,9 @@ function AIDriveStrategyShovelSiloLoader:onPathfindingDoneToStart(path)
self:startCourse(alignmentCourse, 1)
self:setNewState(self.states.DRIVING_ALIGNMENT_COURSE)
else
- local course = self:getRememberedCourseAndIx()
- self:debug("No alignment path found, so driving directly to the course!")
- self:startCourse(course, 1)
- self:setNewState(self.states.DRIVING_INTO_SILO)
+ self:debug("No path to the silo found!")
+ self.vehicle:stopCurrentAIJob(AIMessageCpErrorNoPathFound.new())
+ --- TODO: Might need to consider a retry to another silo lane
end
end
From ad8afd60b3b7e6e94696ccef4a5b873cc59cfc5e Mon Sep 17 00:00:00 2001
From: schwiti6190
Date: Tue, 19 Sep 2023 18:23:29 +0000
Subject: [PATCH 103/107] Updated translations
---
translations/translation_hu.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index f1e87e787..13002836c 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -25,7 +25,7 @@
-
+
From d4656428b429d4bffe4ad0d76af26190d8dddbfd Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Wed, 20 Sep 2023 20:57:17 +0200
Subject: [PATCH 104/107] Push Release 7.3.1.0
- fix for #2768
- fix for #2777
- fix for #2761 and other plow improvements.
- Improvement for reverse driving with offset tools (e.g. plows or potato harvester)
- Plows default noReverse configuration was removed, User who want them to not drive in reverse turn off "turn on field" or can also turn on "use pathfinder in turns".
- Added shovel mode back in. #2254
Please check the in-game help menu for how to set up the new mode.
We can't support all kinds of shovel vehicles (like bobcats) as they were built inconsistently (like the tool arms are sometimes flipped, and so on).
If it turns out to be a lot of non-working shovel vehicles, we'll consider implementing some kind of Tool Position Saver (like our separate mod) or find some another solution, until then, we would prefer keeping the automatic control.
We were not able to test all different kinds of combinations. If you have a vehicle that does weird things, pls post a screenshot (with debug on) in our Issue: #2783
---
modDesc.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modDesc.xml b/modDesc.xml
index 56bea87ef..859e12116 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -1,6 +1,6 @@
- 7.3.0.3
+ 7.3.1.0
CoursePlay
From d6695e7aafe985371ffe9041963b66cad549a73b Mon Sep 17 00:00:00 2001
From: Roby1164
Date: Wed, 20 Sep 2023 22:28:28 +0200
Subject: [PATCH 105/107] Update translation_it.xml
---
translations/translation_it.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/translations/translation_it.xml b/translations/translation_it.xml
index 6e23a5e16..f05e3034a 100644
--- a/translations/translation_it.xml
+++ b/translations/translation_it.xml
@@ -819,7 +819,7 @@ Per avviare l'indicatore di caricamento nel menu AI è necessario impostare.
Il marcatore rileva cumuli o silos e li evidenzia sulla mappa.
Ora è possibile avviare l'helper.
"/>
-
+
From 7533e757448d63d39958424c4807dc6cc32b8758 Mon Sep 17 00:00:00 2001
From: schwiti6190 <58079399+schwiti6190@users.noreply.github.com>
Date: Thu, 21 Sep 2023 17:21:47 +0200
Subject: [PATCH 106/107] Updated ReadMe what works text
---
README.md | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index a717a1158..056fe0ef0 100644
--- a/README.md
+++ b/README.md
@@ -12,17 +12,32 @@
## What Works
* **Multiplayer support**
-* Fieldwork and vine work with courses from the course generator.
-* Course manager for saving/loading/renaming/moving and deleting of courses.
-* Wrapping and collecting of bales with or without a course.
-* Unloading of combines with unloaders.
-* Creating heaps of sugar beets or other fruits on the field with the combine unloader.
-* Unloading silo loaders, like the ``ROPA Maus`` and letting AD or Giants unload the trailer after that.
-* Compacting of a bunker silo or pushing the chaff into the back of a silo.
-* Let the combine unload into nearby trailers (combine self unload).
-* Field work with up to 5 vehicles on the same course (multi tool course).
-* Creating custom fields by recording a course or drawing on the AI Map.
-* Course editor to edit fieldwork courses or custom field borders.
+* Fieldwork mode:
+ * Course generator for complex fields with many option like headlands or beets with combines and so on ..
+ * Up to 5 workers with the same tools can work together on a field with the same course (multi tools)
+ * Generate courses for vine work
+ * Save/load/rename/move courses
+ * Load courses for baling, straw or grass collection and so on
+ * Combines can automatically unload into nearby trailers (combine self unload)
+* Bale collector mode:
+ * Wrapping bales on a field without a course
+ * Collecting bales on the field without a course and unloading them with [AutoDrive](https://github.com/Stephan-S/FS22_AutoDrive)
+* Combine unloader mode:
+ * Unload combines on the field
+ * Sending the giants helper or [AutoDrive](https://github.com/Stephan-S/FS22_AutoDrive) to unload at an unload station
+ * Creating heaps of sugar beets or other fruits on the field
+ * Unloading a loader vehicle, like the ``ROPA Maus`` and letting [AutoDrive](https://github.com/Stephan-S/FS22_AutoDrive) or Giants unload the trailer after that
+* Silo load mode:
+ * Loading from a heap or bunker silo with loader, like the ``ROPA Maus``
+ * Using a wheel loader or a front loader to load from a heap or a bunker silo and unload to:
+ * Unloading to nearby trailers
+ * Unloading to an unloading station, which needs to be selected on the AI menu
+* Bunker silo mode:
+ * Compacting the silo with or without tools like this one [Silo distributor](https://www.farming-simulator.com/mod.php?lang=de&country=de&mod_id=242708&title=fs2022)
+ * Using a shield in a silo with a back wall to push the chaff to the back of silo
+* Misc:
+ * Creating custom fields by recording the boarder with a vehicle or drawing on the AI Map.
+ * Course editor in the buy menu to edit courses or custom fields.
* Mod support with [AutoDrive](https://github.com/Stephan-S/FS22_AutoDrive):
* Sending the fieldwork driver to refill seeds/fertilizers and so on.
* Sending the fieldworker/ bale collector to unload collected straw and so on.
From ede02e169f5965621f6273d131f67801b060e897 Mon Sep 17 00:00:00 2001
From: Tensuko
Date: Thu, 21 Sep 2023 17:26:54 +0200
Subject: [PATCH 107/107] increse skip row for vine generator to 4 #2787
---
config/VineCourseGeneratorSettingsSetup.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/VineCourseGeneratorSettingsSetup.xml b/config/VineCourseGeneratorSettingsSetup.xml
index fe7f220c9..f191e4802 100644
--- a/config/VineCourseGeneratorSettingsSetup.xml
+++ b/config/VineCourseGeneratorSettingsSetup.xml
@@ -21,6 +21,6 @@
-
+