diff --git a/README.md b/README.md index 9db02ebe..d066aa1c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # FS22_AutoDrive FS22 version of the AutoDrive mod -### Latest Release: 2.0.1.4 +### Latest Release: 2.0.1.6 ![GitHub all releases](https://img.shields.io/github/downloads/Stephan-S/FS22_AutoDrive/total?label=Downloads&style=plastic) Direct Download: https://github.com/Stephan-S/FS22_AutoDrive/releases/latest/download/FS22_AutoDrive.zip @@ -18,13 +18,12 @@ And to all who do donate: Thank you very much :-) #### Stephan (Founder): https://www.paypal.me/StephanSchlosser -#### Axel (Modder) - #### Iwan1803 (Community Manager, Supporter & Tester): -https://www.tipeeestream.com/iwan1803/tip +https://iwan1803.de/urls/tip -#### Willi (Supporter & Tester) +#### Axel & Tommo (Modder) +#### Willi (Supporter & Tester) ## Course Editor The course editor is now maintained by @KillBait and can be found here: diff --git a/gui/settingsPage.xml b/gui/settingsPage.xml index deacf582..9a8122fe 100644 --- a/gui/settingsPage.xml +++ b/gui/settingsPage.xml @@ -100,6 +100,14 @@ + + + + + + + + diff --git a/gui/vehicleSettingsPage.xml b/gui/vehicleSettingsPage.xml index 75bf7088..64f1bb08 100644 --- a/gui/vehicleSettingsPage.xml +++ b/gui/vehicleSettingsPage.xml @@ -163,6 +163,14 @@ + + + + + + + + diff --git a/modDesc.xml b/modDesc.xml index 61d08954..968ce961 100644 --- a/modDesc.xml +++ b/modDesc.xml @@ -1,5 +1,5 @@ - + AutoDrive Team <en>AutoDrive</en> @@ -32,7 +32,7 @@ Différents modes d'utilisation ont été ajoutés depuis les premières version <![CDATA[Этот мод может быть использован для создания сети маршрутов для транспортных средств для автономного вождения. После настройки вы можете указать трактору, стоящему где-угодно рядом с сетью, проехать в любую точку, например, в магазин, поле №1 или в точку продажи.]]> </ru> </description> - <version>2.0.1.4</version> + <version>2.0.1.6</version> <multiplayer supported="true" /> <iconFilename>icon.dds</iconFilename> <extraSourceFiles> diff --git a/register.lua b/register.lua index 1c3162f8..02e6797d 100644 --- a/register.lua +++ b/register.lua @@ -22,6 +22,7 @@ source(Utils.getFilename("scripts/TelemetryExport.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Hud/GenericHudElement.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Hud/HudButton.lua", g_currentModDirectory)) +source(Utils.getFilename("scripts/Hud/HudCounterButton.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Hud/HudSettingsButton.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Hud/HudIcon.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Hud/HudSpeedmeter.lua", g_currentModDirectory)) @@ -79,6 +80,7 @@ source(Utils.getFilename("scripts/Manager/UserDataManager.lua", g_currentModDire source(Utils.getFilename("scripts/Manager/MultipleTargetsManager.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Manager/ThirdPartyModsManager.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Manager/Scheduler.lua", g_currentModDirectory)) +source(Utils.getFilename("scripts/Manager/BunkerSiloManager.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Tasks/AbstractTask.lua", g_currentModDirectory)) source(Utils.getFilename("scripts/Tasks/DriveToDestinationTask.lua", g_currentModDirectory)) diff --git a/scripts/AutoDrive.lua b/scripts/AutoDrive.lua index bd0b10a4..76cfe98d 100644 --- a/scripts/AutoDrive.lua +++ b/scripts/AutoDrive.lua @@ -1,5 +1,5 @@ AutoDrive = {} -AutoDrive.version = "2.0.1.4" +AutoDrive.version = "2.0.1.6" AutoDrive.directory = g_currentModDirectory @@ -92,6 +92,11 @@ AutoDrive.FLAG_TRAFFIC_SYSTEM_CONNECTION = 4 -- add this to measured size of vehicles AutoDrive.DIMENSION_ADDITION = 0.2 +-- AD invoked by which type of user +AutoDrive.USER_PLAYER = 1 +AutoDrive.USER_GIANTS = 2 +AutoDrive.USER_CP = 3 + AutoDrive.colors = { ad_color_singleConnection = {0, 1, 0, 1}, ad_color_dualConnection = {0, 0, 1, 1}, @@ -107,8 +112,13 @@ AutoDrive.colors = { ad_color_currentConnection = {1, 1, 1, 1}, ad_color_closestLine = {1, 0, 0, 1}, ad_color_editorHeightLine = {1, 1, 1, 1}, + ad_color_previewSingleConnection = {0.3, 0.9, 0, 1}, + ad_color_previewDualConnection = {0, 0, 0.9, 1}, + ad_color_previewSubPrioSingleConnection = {0.9, 0.4, 0.1, 1}, + ad_color_previewSubPrioDualConnection = {0.3, 0.15, 0, 1}, ad_color_previewOk = {0.3, 0.9, 0, 1}, - ad_color_previewNotOk = {1, 0.1, 0, 1} + ad_color_previewNotOk = {1, 0.1, 0, 1}, + ad_color_textInputBackground = {0.0227, 0.5346, 0.8519, 1} -- Giants original } AutoDrive.currentColors = {} -- this will hold the current colors, derived from default colors above, overwritten by local settings @@ -146,7 +156,7 @@ end function AutoDrive:restartMySavegame() if g_server then - restartApplication(" -autoStartSavegameId 1", true) + restartApplication(true, " -autoStartSavegameId 1") end end @@ -252,6 +262,7 @@ function AutoDrive:loadMap(name) ADMultipleTargetsManager:load() -- AutoDrive.initTelemetry() + ADBunkerSiloManager:load() InGameMenuAIFrame.onFrameOpen = Utils.appendedFunction(InGameMenuAIFrame.onFrameOpen, AutoDrive.onAIFrameOpen) InGameMenuAIFrame.onFrameClose = Utils.appendedFunction(InGameMenuAIFrame.onFrameClose, AutoDrive.onAIFrameClose) @@ -651,6 +662,7 @@ function AutoDrive:update(dt) if g_server ~= nil then ADHarvestManager:update(dt) ADScheduler:update(dt) + ADBunkerSiloManager:update(dt) end ADMessagesManager:update(dt) diff --git a/scripts/Events/Graph/CreateSplineConnectionEvent.lua b/scripts/Events/Graph/CreateSplineConnectionEvent.lua index b2d2297a..bc095350 100644 --- a/scripts/Events/Graph/CreateSplineConnectionEvent.lua +++ b/scripts/Events/Graph/CreateSplineConnectionEvent.lua @@ -8,15 +8,16 @@ function CreateSplineConnectionEvent.emptyNew() return self end -function CreateSplineConnectionEvent.new(start, waypoints, target) +function CreateSplineConnectionEvent.new(start, waypoints, target, dualConnection) local self = CreateSplineConnectionEvent.emptyNew() self.start = start self.waypoints = waypoints self.target = target + self.dualConnection = dualConnection return self end -function CreateSplineConnectionEvent:writeStream(streamId, connection) +function CreateSplineConnectionEvent:writeStream(streamId, connection) local paramsXZ = g_currentMission.vehicleXZPosCompressionParams local paramsY = g_currentMission.vehicleYPosCompressionParams @@ -30,6 +31,7 @@ function CreateSplineConnectionEvent:writeStream(streamId, connection) end streamWriteInt32(streamId, self.target) + streamWriteBool(streamId, self.dualConnection) end function CreateSplineConnectionEvent:readStream(streamId, connection) @@ -47,21 +49,22 @@ function CreateSplineConnectionEvent:readStream(streamId, connection) end self.target = streamReadInt32(streamId) + self.dualConnection = streamReadBool(streamId) self:run(connection) end function CreateSplineConnectionEvent:run(connection) if g_server ~= nil and connection:getIsServer() == false then -- If the event is coming from a client, server have only to broadcast - CreateSplineConnectionEvent.sendEvent(self.start, self.waypoints, self.target) + CreateSplineConnectionEvent.sendEvent(self.start, self.waypoints, self.target, self.dualConnection) else -- If the event is coming from the server, both clients and server have to create the way point - ADGraphManager:createSplineConnection(self.start, self.waypoints, self.target, false) + ADGraphManager:createSplineConnection(self.start, self.waypoints, self.target, self.dualConnection, false) end end -function CreateSplineConnectionEvent.sendEvent(start, waypoints, target) - local event = CreateSplineConnectionEvent.new(start, waypoints, target) +function CreateSplineConnectionEvent.sendEvent(start, waypoints, target, dualConnection) + local event = CreateSplineConnectionEvent.new(start, waypoints, target, dualConnection) if g_server ~= nil then -- Server have to broadcast to all clients and himself g_server:broadcastEvent(event, true) diff --git a/scripts/Events/Graph/ToggleConnectionEvent.lua b/scripts/Events/Graph/ToggleConnectionEvent.lua index 323d51e7..7193beb1 100644 --- a/scripts/Events/Graph/ToggleConnectionEvent.lua +++ b/scripts/Events/Graph/ToggleConnectionEvent.lua @@ -8,11 +8,12 @@ function AutoDriveToggleConnectionEvent.emptyNew() return self end -function AutoDriveToggleConnectionEvent.new(startNode, endNode, reverseDirection) +function AutoDriveToggleConnectionEvent.new(startNode, endNode, reverseDirection, dualConnection) local self = AutoDriveToggleConnectionEvent.emptyNew() self.startNode = startNode self.endNode = endNode self.reverseDirection = reverseDirection + self.dualConnection = dualConnection return self end @@ -20,26 +21,28 @@ function AutoDriveToggleConnectionEvent:writeStream(streamId, connection) streamWriteUIntN(streamId, self.startNode.id, 20) streamWriteUIntN(streamId, self.endNode.id, 20) streamWriteBool(streamId, self.reverseDirection) + streamWriteBool(streamId, self.dualConnection) end function AutoDriveToggleConnectionEvent:readStream(streamId, connection) self.startNode = ADGraphManager:getWayPointById(streamReadUIntN(streamId, 20)) self.endNode = ADGraphManager:getWayPointById(streamReadUIntN(streamId, 20)) self.reverseDirection = streamReadBool(streamId) + self.dualConnection = streamReadBool(streamId) self:run(connection) end function AutoDriveToggleConnectionEvent:run(connection) if g_server ~= nil and connection:getIsServer() == false then -- If the event is coming from a client, server have only to broadcast - AutoDriveToggleConnectionEvent.sendEvent(self.startNode, self.endNode, self.reverseDirection) + AutoDriveToggleConnectionEvent.sendEvent(self.startNode, self.endNode, self.reverseDirection, self.dualConnection) else - ADGraphManager:toggleConnectionBetween(self.startNode, self.endNode, self.reverseDirection, false) + ADGraphManager:toggleConnectionBetween(self.startNode, self.endNode, self.reverseDirection, self.dualConnection, false) end end -function AutoDriveToggleConnectionEvent.sendEvent(startNode, endNode, reverseDirection) - local event = AutoDriveToggleConnectionEvent.new(startNode, endNode, reverseDirection) +function AutoDriveToggleConnectionEvent.sendEvent(startNode, endNode, reverseDirection, dualConnection) + local event = AutoDriveToggleConnectionEvent.new(startNode, endNode, reverseDirection, dualConnection) if g_server ~= nil then -- Server have to broadcast to all clients and himself g_server:broadcastEvent(event, true) diff --git a/scripts/Events/HudInputEvent.lua b/scripts/Events/HudInputEvent.lua index 6e93ec1d..5f204d03 100644 --- a/scripts/Events/HudInputEvent.lua +++ b/scripts/Events/HudInputEvent.lua @@ -4,6 +4,10 @@ AutoDriveHudInputEventEvent.TYPE_SECOND_MARKER = 2 AutoDriveHudInputEventEvent.TYPE_FILLTYPE = 3 AutoDriveHudInputEventEvent.TYPE_TOGGLE_FILLTYPE_SELECTION = 4 AutoDriveHudInputEventEvent.TYPE_TOGGLE_ALL_FILLTYPE_SELECTIONS = 5 +AutoDriveHudInputEventEvent.CHANGE_LOOP_COUNTER = 6 + + + AutoDriveHudInputEventEvent_mt = Class(AutoDriveHudInputEventEvent, Event) @@ -40,7 +44,7 @@ function AutoDriveHudInputEventEvent:run(connection) if self.eventType == self.TYPE_FIRST_MARKER then local currentFirstMarker = self.vehicle.ad.stateModule:getFirstMarkerId() if currentFirstMarker > 0 and currentFirstMarker ~= self.value then - if not (self.vehicle.spec_combine or AutoDrive.getIsBufferCombine(self.vehicle) or self.vehicle.ad.isCombine ~= nil) then + if not self.vehicle.ad.hasCombine then -- not stop / change CP for harvesters AutoDrive:StopCP(self.vehicle) end @@ -63,6 +67,11 @@ function AutoDriveHudInputEventEvent:run(connection) if self.eventType == self.TYPE_TOGGLE_ALL_FILLTYPE_SELECTIONS then self.vehicle.ad.stateModule:toggleAllFillTypeSelections(self.value) end + + if self.eventType == self.CHANGE_LOOP_COUNTER then + local increment, fast, wheel = ADHudCounterButton.int_to_flags(self.value) + self.vehicle.ad.stateModule:changeLoopCounter(increment, fast, wheel) + end end end @@ -100,3 +109,11 @@ function AutoDriveHudInputEventEvent:sendToggleAllFillTypeSelectionsEvent(vehicl g_client:getServerConnection():sendEvent(AutoDriveHudInputEventEvent.new(vehicle, self.TYPE_TOGGLE_ALL_FILLTYPE_SELECTIONS, fillTypeId)) end end + +function AutoDriveHudInputEventEvent:sendChangeLoopCounterEvent(vehicle, increment, fast, wheel) + if g_client ~= nil then + -- Client have to send to server + local value = ADHudCounterButton.flags_to_int(increment, fast, wheel) + g_client:getServerConnection():sendEvent(AutoDriveHudInputEventEvent.new(vehicle, self.CHANGE_LOOP_COUNTER, value)) + end +end diff --git a/scripts/Gui/EnterDestinationFilterGUI.lua b/scripts/Gui/EnterDestinationFilterGUI.lua index eabb27b8..aa4f187a 100644 --- a/scripts/Gui/EnterDestinationFilterGUI.lua +++ b/scripts/Gui/EnterDestinationFilterGUI.lua @@ -22,6 +22,11 @@ function ADEnterDestinationFilterGui:onOpen() ADEnterDestinationFilterGui:superClass().onOpen(self) self.textInputElement.blockTime = 0 self.textInputElement:onFocusActivate() + if self.textInputElement.overlay and self.textInputElement.overlay.colorFocused then + if AutoDrive.currentColors and AutoDrive.currentColors.ad_color_textInputBackground then + self.textInputElement.overlay.colorFocused = AutoDrive.currentColors.ad_color_textInputBackground + end + end if g_currentMission.controlledVehicle ~= nil and g_currentMission.controlledVehicle.ad ~= nil then self.textInputElement:setText(g_currentMission.controlledVehicle.ad.destinationFilterText) end diff --git a/scripts/Gui/EnterDriverNameGUI.lua b/scripts/Gui/EnterDriverNameGUI.lua index 0b50b154..5144981a 100644 --- a/scripts/Gui/EnterDriverNameGUI.lua +++ b/scripts/Gui/EnterDriverNameGUI.lua @@ -22,6 +22,11 @@ function ADEnterDriverNameGui:onOpen() ADEnterDriverNameGui:superClass().onOpen(self) self.textInputElement.blockTime = 0 self.textInputElement:onFocusActivate() + if self.textInputElement.overlay and self.textInputElement.overlay.colorFocused then + if AutoDrive.currentColors and AutoDrive.currentColors.ad_color_textInputBackground then + self.textInputElement.overlay.colorFocused = AutoDrive.currentColors.ad_color_textInputBackground + end + end if g_currentMission.controlledVehicle ~= nil and g_currentMission.controlledVehicle.ad ~= nil then self.textInputElement:setText(g_currentMission.controlledVehicle.ad.stateModule:getName()) end diff --git a/scripts/Gui/EnterGroupNameGUI.lua b/scripts/Gui/EnterGroupNameGUI.lua index b6eca8d3..bdc4c926 100644 --- a/scripts/Gui/EnterGroupNameGUI.lua +++ b/scripts/Gui/EnterGroupNameGUI.lua @@ -22,6 +22,11 @@ function ADEnterGroupNameGui:onOpen() ADEnterGroupNameGui:superClass().onOpen(self) self.textInputElement.blockTime = 0 self.textInputElement:onFocusActivate() + if self.textInputElement.overlay and self.textInputElement.overlay.colorFocused then + if AutoDrive.currentColors and AutoDrive.currentColors.ad_color_textInputBackground then + self.textInputElement.overlay.colorFocused = AutoDrive.currentColors.ad_color_textInputBackground + end + end self.textInputElement:setText("") end diff --git a/scripts/Gui/EnterTargetNameGUI.lua b/scripts/Gui/EnterTargetNameGUI.lua index 44b0e5a8..c115da1b 100644 --- a/scripts/Gui/EnterTargetNameGUI.lua +++ b/scripts/Gui/EnterTargetNameGUI.lua @@ -24,6 +24,11 @@ function ADEnterTargetNameGui:onOpen() ADEnterTargetNameGui:superClass().onOpen(self) self.textInputElement.blockTime = 0 self.textInputElement:onFocusActivate() + if self.textInputElement.overlay and self.textInputElement.overlay.colorFocused then + if AutoDrive.currentColors and AutoDrive.currentColors.ad_color_textInputBackground then + self.textInputElement.overlay.colorFocused = AutoDrive.currentColors.ad_color_textInputBackground + end + end self.editName = nil self.editId = nil self.edit = false diff --git a/scripts/Gui/RoutesManagerGUI.lua b/scripts/Gui/RoutesManagerGUI.lua index bfda3289..7bd6b6ef 100644 --- a/scripts/Gui/RoutesManagerGUI.lua +++ b/scripts/Gui/RoutesManagerGUI.lua @@ -17,6 +17,11 @@ function ADRoutesManagerGui:onCreate() end function ADRoutesManagerGui:onOpen() + if self.textInputElement.overlay and self.textInputElement.overlay.colorFocused then + if AutoDrive.currentColors and AutoDrive.currentColors.ad_color_textInputBackground then + self.textInputElement.overlay.colorFocused = AutoDrive.currentColors.ad_color_textInputBackground + end + end self:refreshItems() ADRoutesManagerGui:superClass().onOpen(self) end diff --git a/scripts/Gui/Settings.lua b/scripts/Gui/Settings.lua index f9116e15..baaaea69 100644 --- a/scripts/Gui/Settings.lua +++ b/scripts/Gui/Settings.lua @@ -87,7 +87,7 @@ function ADSettings:setupPages() end local combineEnabled = function() - if vehicleEnabled() and g_currentMission.controlledVehicle.ad.isCombine then + if vehicleEnabled() and (g_currentMission.controlledVehicle.ad and g_currentMission.controlledVehicle.ad.hasCombine) then return true end return false diff --git a/scripts/Hud.lua b/scripts/Hud.lua index 5dd8620e..c1d03d95 100644 --- a/scripts/Hud.lua +++ b/scripts/Hud.lua @@ -216,7 +216,10 @@ function AutoDriveHud:createHudAt(hudX, hudY) self:AddButton("input_continue", nil, nil, nil, "input_AD_continue", 1, true) self:AddButton("input_parkVehicle", "input_setParkDestination", nil, nil, "input_ADParkVehicle", 1, true) if vehicle == nil or vehicle.ad.stateModule:getMode() ~= AutoDrive.MODE_BGA then - self:AddButton("input_incLoopCounter", "input_decLoopCounter", nil, nil, "input_ADIncLoopCounter", 1, true) + local loopX = self.posX + (self.cols - 2 + self.buttonCollOffset) * self.borderX + (self.cols - 3 + self.buttonCollOffset) * self.buttonWidth + local loopY = self.posY + (1) * self.borderY + (0) * self.buttonHeight + table.insert(self.hudElements, ADHudCounterButton:new(loopX, loopY, self.buttonWidth, self.buttonHeight, "loop_counter")) + self.buttonCounter = self.buttonCounter + 1 else self:AddButton("input_bunkerUnloadType", nil, nil, nil, "input_ADbunkerUnloadType", 1, true) end @@ -500,15 +503,15 @@ function AutoDriveHud:mouseEvent(vehicle, posX, posY, isDown, isUp, button) end -- waypoint at mouse position - if button == 1 and isUp - and not AutoDrive.leftLSHIFTmodifierKeyPressed - and not AutoDrive.leftCTRLmodifierKeyPressed - and not AutoDrive.leftALTmodifierKeyPressed - --and AutoDrive.rightSHIFTmodifierKeyPressed -- see below !!! + local connectOneWay = not AutoDrive.leftLSHIFTmodifierKeyPressed and not AutoDrive.leftCTRLmodifierKeyPressed and not AutoDrive.leftALTmodifierKeyPressed + local connectDual = not AutoDrive.leftLSHIFTmodifierKeyPressed and AutoDrive.leftCTRLmodifierKeyPressed and AutoDrive.leftALTmodifierKeyPressed + if button == 1 and isUp and (connectOneWay or connectDual) then -- left mouse button to select point / connect to already selected point if vehicle.ad.selectedNodeId ~= nil then if vehicle.ad.selectedNodeId ~= vehicle.ad.hoveredNodeId then + local reverseDirection = AutoDrive.rightSHIFTmodifierKeyPressed + if not table.contains(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId).out, vehicle.ad.hoveredNodeId) then -- connect selected point with hovered point @@ -525,20 +528,16 @@ function AutoDriveHud:mouseEvent(vehicle, posX, posY, isDown, isUp, button) end end - ADGraphManager:createSplineConnection(vehicle.ad.selectedNodeId, waypoints, vehicle.ad.hoveredNodeId) + ADGraphManager:createSplineConnection(vehicle.ad.selectedNodeId, waypoints, vehicle.ad.hoveredNodeId, connectDual) else AutoDriveHud.debugMsg(vehicle, "AutoDriveHud:mouseEvent toggleConnectionBetween 1 vehicle.ad.selectedNodeId %d vehicle.ad.hoveredNodeId %d", vehicle.ad.selectedNodeId, vehicle.ad.hoveredNodeId) - ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId), ADGraphManager:getWayPointById(vehicle.ad.hoveredNodeId), AutoDrive.rightSHIFTmodifierKeyPressed) - if AutoDrive.leftLSHIFTmodifierKeyPressed then - AutoDriveHud.debugMsg(vehicle, "AutoDriveHud:mouseEvent toggleWayPointAsSubPrio 1 selectedNodeId %d", vehicle.ad.selectedNodeId) - ADGraphManager:toggleWayPointAsSubPrio(vehicle.ad.selectedNodeId) - end + ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId), ADGraphManager:getWayPointById(vehicle.ad.hoveredNodeId), reverseDirection, connectDual) end AutoDrive.splineInterpolationUserCurvature = nil else AutoDriveHud.debugMsg(vehicle, "AutoDriveHud:mouseEvent toggleConnectionBetween 1 vehicle.ad.selectedNodeId %d vehicle.ad.hoveredNodeId %d", vehicle.ad.selectedNodeId, vehicle.ad.hoveredNodeId) - ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId), ADGraphManager:getWayPointById(vehicle.ad.hoveredNodeId), AutoDrive.rightSHIFTmodifierKeyPressed) + ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId), ADGraphManager:getWayPointById(vehicle.ad.hoveredNodeId), reverseDirection, connectDual) end end @@ -609,7 +608,8 @@ function AutoDriveHud:mouseEvent(vehicle, posX, posY, isDown, isUp, button) AutoDriveHud.debugMsg(vehicle, "AutoDriveHud:mouseEvent auto connection 1 selectedNodeId %d", vehicle.ad.selectedNodeId) end - if button == 1 and isUp + -- if LSHIFT is pressed, selecting a waypoint will toggle its priority + if button == 1 and isUp and AutoDrive.leftLSHIFTmodifierKeyPressed and not AutoDrive.leftCTRLmodifierKeyPressed and not AutoDrive.leftALTmodifierKeyPressed @@ -625,11 +625,16 @@ function AutoDriveHud:mouseEvent(vehicle, posX, posY, isDown, isUp, button) --If no node is hovered / moved - create new node if vehicle.ad.nodeToMoveId == nil and vehicle.ad.hoveredNodeId == nil then if button == 1 and isUp - -- and not AutoDrive.leftLSHIFTmodifierKeyPressed -- see below !!! + -- and not AutoDrive.leftLSHIFTmodifierKeyPressed -- sub-priority and AutoDrive.leftCTRLmodifierKeyPressed - and not AutoDrive.leftALTmodifierKeyPressed - -- and not AutoDrive.rightSHIFTmodifierKeyPressed -- see below !!! + -- and not AutoDrive.leftALTmodifierKeyPressed -- dual connection + -- and not AutoDrive.rightSHIFTmodifierKeyPressed -- reverse then + local reverseDirection = AutoDrive.rightSHIFTmodifierKeyPressed + local subPrio = AutoDrive.leftLSHIFTmodifierKeyPressed and not reverseDirection + local dualConnection = AutoDrive.leftALTmodifierKeyPressed and not reverseDirection + + --For rough depth assertion, we use the closest nodes location as this is roughly in the screen's center local closest = vehicle:getClosestWayPoint() closest = ADGraphManager:getWayPointById(closest) @@ -678,7 +683,7 @@ function AutoDriveHud:mouseEvent(vehicle, posX, posY, isDown, isUp, button) -- auto connect only working in single player properly ! local createdId = ADGraphManager:getWayPointsCount() - if AutoDrive.leftLSHIFTmodifierKeyPressed and not AutoDrive.rightSHIFTmodifierKeyPressed then + if subPrio then ADGraphManager:toggleWayPointAsSubPrio(createdId) AutoDriveHud.debugMsg(vehicle, "AutoDriveHud:mouseEvent toggleWayPointAsSubPrio 3 createdId %d", createdId) end @@ -686,7 +691,7 @@ function AutoDriveHud:mouseEvent(vehicle, posX, posY, isDown, isUp, button) if vehicle.ad.newcreated ~= nil and vehicle.ad.selectedNodeId == vehicle.ad.newcreated then -- connect only if previous created point is selected and newcreated ~= nil AutoDriveHud.debugMsg(vehicle, "AutoDriveHud:mouseEvent toggleConnectionBetween 2 vehicle.ad.selectedNodeId %d to %d", vehicle.ad.selectedNodeId, createdId) - ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId), ADGraphManager:getWayPointById(createdId), AutoDrive.rightSHIFTmodifierKeyPressed) + ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.selectedNodeId), ADGraphManager:getWayPointById(createdId), reverseDirection, dualConnection) end vehicle.ad.newcreated = createdId vehicle.ad.selectedNodeId = vehicle.ad.newcreated diff --git a/scripts/Hud/HudButton.lua b/scripts/Hud/HudButton.lua index 43560a8d..c305e120 100644 --- a/scripts/Hud/HudButton.lua +++ b/scripts/Hud/HudButton.lua @@ -29,7 +29,7 @@ function ADHudButton:readImages() path = "input_toggleAutomaticUnloadTarget" end - while counter <= 19 do + while counter <= 6 do images[counter] = AutoDrive.directory .. "textures/" .. path .. "_" .. counter .. ".dds" counter = counter + 1 end @@ -141,15 +141,6 @@ function ADHudButton:getNewState(vehicle) self.isVisible = AutoDrive.isEditorModeEnabled() end - if self.primaryAction == "input_incLoopCounter" then - newState = math.max(0, vehicle.ad.stateModule:getLoopCounter() - vehicle.ad.stateModule:getLoopsDone()) + 1 - if vehicle.ad.stateModule:isActive() and vehicle.ad.stateModule:getMode() == AutoDrive.MODE_PICKUPANDDELIVER then - if newState > 1 then - newState = newState + 9 - end - end - end - if self.primaryAction == "input_parkVehicle" then local actualParkDestination = vehicle.ad.stateModule:getParkDestinationAtJobFinished() diff --git a/scripts/Hud/HudCounterButton.lua b/scripts/Hud/HudCounterButton.lua new file mode 100644 index 00000000..4dd35177 --- /dev/null +++ b/scripts/Hud/HudCounterButton.lua @@ -0,0 +1,108 @@ +ADHudCounterButton = ADInheritsFrom(ADGenericHudElement) + +ADHudCounterButton.STATE_INFINITE = 1 +ADHudCounterButton.STATE_ACTIVE = 2 +ADHudCounterButton.STATE_INACTIVE = 3 + +function ADHudCounterButton:new(posX, posY, width, height, mode) + local o = ADHudCounterButton:create() + o:init(posX, posY, width, height) + o.state = 1 + o.counter = 1 + o.mode = mode + + o.images = { + [ADHudCounterButton.STATE_INFINITE] = AutoDrive.directory .. "textures/" .. mode .. "_inf.dds", + [ADHudCounterButton.STATE_ACTIVE] = AutoDrive.directory .. "textures/" .. mode .. "_active.dds", + [ADHudCounterButton.STATE_INACTIVE] = AutoDrive.directory .. "textures/" .. mode .. "_inactive.dds", + } + + o.layer = 5 + o.ov = Overlay.new(o.images[o.state], o.position.x, o.position.y, o.size.width, o.size.height) + return o +end + +function ADHudCounterButton:updateState(vehicle) + local newState, newCounter = self:getNewState(vehicle) + self.ov:setImage(self.images[newState]) + self.state = newState + self.counter = newCounter +end + +function ADHudCounterButton:getNewState(vehicle) + local newState = self.state + local newCounter = self.counter + if self.mode == "loop_counter" then + if vehicle.ad.stateModule:getLoopCounter() == 0 then + newState = ADHudCounterButton.STATE_INFINITE + newCounter = -1 + else + newCounter = math.max(0, vehicle.ad.stateModule:getLoopCounter() - vehicle.ad.stateModule:getLoopsDone()) + if vehicle.ad.stateModule:isActive() and vehicle.ad.stateModule:getMode() == AutoDrive.MODE_PICKUPANDDELIVER then + newState = ADHudCounterButton.STATE_ACTIVE + else + newState = ADHudCounterButton.STATE_INACTIVE + end + end + end + return newState, newCounter + +end + +function ADHudCounterButton:onDraw(vehicle, uiScale) + self:updateState(vehicle) + self.ov:render() + + if self.state ~= ADHudCounterButton.STATE_INFINITE then + local adFontSize = AutoDrive.FONT_SCALE * uiScale + if self.state == ADHudCounterButton.STATE_ACTIVE then + setTextColor(0.16, 0.76, 0.93, 1) + else + setTextColor(1, 1, 1, 1) + end + setTextAlignment(RenderText.ALIGN_CENTER) + local text = string.format("%d", self.counter) + local posX = self.position.x + (self.size.width / 2) + local posY = self.position.y + AutoDrive.Hud.gapHeight + renderText(posX, posY, adFontSize, text) + end +end + + +-- Helper functions to wrap the 3 boolean flags into an int and back. +ADHudCounterButton.FLAG_INCREMENT = 1 +ADHudCounterButton.FLAG_FAST = 2 +ADHudCounterButton.FLAG_WHEEL = 4 + + +function ADHudCounterButton.flags_to_int(increment, fast, wheel) + return (increment and ADHudCounterButton.FLAG_INCREMENT or 0) + + (fast and ADHudCounterButton.FLAG_FAST or 0) + + (wheel and ADHudCounterButton.FLAG_WHEEL or 0) +end + +function ADHudCounterButton.int_to_flags(value) + return bitAND(value, ADHudCounterButton.FLAG_INCREMENT) > 0, bitAND(value, ADHudCounterButton.FLAG_FAST) > 0, bitAND(value, ADHudCounterButton.FLAG_WHEEL) > 0 +end + + +function ADHudCounterButton:act(vehicle, posX, posY, isDown, isUp, button) + if not isUp or button < 1 or button > 5 then + return false + end + + local increment = (button == 1) or (button == 4) + local wheel = (button == 4) or (button == 5) + local fast = AutoDrive.leftLSHIFTmodifierKeyPressed + + if wheel then + AutoDrive.mouseWheelActive = true + end + + if self.mode == "loop_counter" then + AutoDriveHudInputEventEvent:sendChangeLoopCounterEvent(vehicle, increment, fast, wheel) + return true + end + + return false +end diff --git a/scripts/Hud/HudHarvesterInfo.lua b/scripts/Hud/HudHarvesterInfo.lua index b78bdf8e..776cba6d 100644 --- a/scripts/Hud/HudHarvesterInfo.lua +++ b/scripts/Hud/HudHarvesterInfo.lua @@ -10,14 +10,14 @@ function HudHarvesterInfo:new(posX, posY, width, height) end function HudHarvesterInfo:onDraw(vehicle, uiScale) - if (vehicle.ad.isCombine and (vehicle.ad.stateModule:getMode() == AutoDrive.MODE_DELIVERTO or vehicle.ad.stateModule:getMode() == AutoDrive.MODE_DRIVETO)) or vehicle.ad.stateModule:getMode() == AutoDrive.MODE_UNLOAD then + if ((vehicle.ad.hasCombine) and (vehicle.ad.stateModule:getMode() == AutoDrive.MODE_DELIVERTO or vehicle.ad.stateModule:getMode() == AutoDrive.MODE_DRIVETO)) or vehicle.ad.stateModule:getMode() == AutoDrive.MODE_UNLOAD then if AutoDrive.pullDownListExpanded == 0 or AutoDrive.Hud.targetPullDownList.direction == ADPullDownList.EXPANDED_UP then local text = "" setTextColor(1, 1, 1, 1) local harvesterPairingOk = vehicle.ad.stateModule:getHarvesterPairingOk() - if vehicle.ad.isCombine then + if vehicle.ad.isRegisterdHarvester then if not harvesterPairingOk then setTextColor(1, 0, 0, 1) text = g_i18n:getText("gui_ad_noUnloaderAvailable") diff --git a/scripts/Hud/PullDownList.lua b/scripts/Hud/PullDownList.lua index f987a493..7bcbbb7a 100644 --- a/scripts/Hud/PullDownList.lua +++ b/scripts/Hud/PullDownList.lua @@ -229,27 +229,29 @@ function ADPullDownList:onDraw(vehicle, uiScale) end end end - local isSelectedFillType = false + + local makeBold = listEntry.isFolder + local makeBlue = listEntry.isFolder + if self.type == ADPullDownList.TYPE_FILLTYPE then - isSelectedFillType = table.contains(vehicle.ad.stateModule:getSelectedFillTypes(), listEntry.returnValue) + makeBold = table.contains(vehicle.ad.stateModule:getSelectedFillTypes(), listEntry.returnValue) + makeBlue = makeBold or vehicle.ad.stateModule:getFillType() == listEntry.returnValue end + setTextBold(makeBold) + if self.hovered == self.selected + (i - 1) then -- mouse hovering over selected item - if listEntry.isFolder or isSelectedFillType then - setTextBold(true) + if makeBlue then setTextColor(0.296, 0.823, 1, 1) else - setTextBold(false) setTextColor(0, 0.871, 1, 1) end else -- other element - if listEntry.isFolder or isSelectedFillType then - setTextBold(true) + if makeBlue then setTextColor(0.0, 0.569, 0.835, 1) else - setTextBold(false) setTextColor(1, 1, 1, 1) end end diff --git a/scripts/Manager/BunkerSiloManager.lua b/scripts/Manager/BunkerSiloManager.lua new file mode 100644 index 00000000..12bfc0d7 --- /dev/null +++ b/scripts/Manager/BunkerSiloManager.lua @@ -0,0 +1,86 @@ +ADBunkerSiloManager = {} + +ADBunkerSiloManager.UPDATE_TIME = 1000 + +function ADBunkerSiloManager:load() + self.bunkerSilos = {} + self.lastUpdateTime = 0 +end + +function ADBunkerSiloManager:update(dt) + + if g_time < self.lastUpdateTime + ADBunkerSiloManager.UPDATE_TIME then + return + end + self.lastUpdateTime = g_time + local bsmRange = AutoDrive.getSetting("BSMRange") or 0 + if bsmRange == 0 then + return + end + + self.bunkerSilos = {} + for _, bunkerSilo in pairs(ADTriggerManager.getUnloadTriggers()) do + if bunkerSilo and bunkerSilo.bunkerSiloArea then + bunkerSilo.adVehicles = {} + table.insert(self.bunkerSilos, bunkerSilo) + end + end + + for _, bunkerSilo in pairs(self.bunkerSilos) do + local minDistance = math.huge + bunkerSilo.adClosestVehicle = nil + for _, vehicle in pairs(g_currentMission.vehicles) do + if vehicle and vehicle.ad and vehicle.ad.stateModule and vehicle.ad.stateModule:isActive() then + if self:isDestinationInBunkerSilo(vehicle, bunkerSilo) then + table.insert(bunkerSilo.adVehicles, vehicle) + local vehicleX, _, vehicleZ = getWorldTranslation(vehicle.components[1].node) + local triggerX, _, triggerZ = ADTriggerManager.getTriggerPos(bunkerSilo) + if triggerX ~= nil then + local distance = MathUtil.vector2Length(triggerX - vehicleX, triggerZ - vehicleZ) + if minDistance > distance then + minDistance = distance + bunkerSilo.adClosestVehicle = vehicle + end + end + end + end + end + end + + for _, bunkerSilo in pairs(self.bunkerSilos) do + for _, vehicle in pairs(bunkerSilo.adVehicles) do + local vehicleX, _, vehicleZ = getWorldTranslation(vehicle.components[1].node) + local triggerX, _, triggerZ = ADTriggerManager.getTriggerPos(bunkerSilo) + if triggerX ~= nil then + local distance = MathUtil.vector2Length(triggerX - vehicleX, triggerZ - vehicleZ) + if distance < bsmRange then + if AutoDrive.isVehicleInBunkerSiloArea(vehicle) or bunkerSilo.adClosestVehicle == vehicle then + -- IMPORTANT: DO NOT SET setUnPaused to avoid crash with CP silo compacter !!! + -- vehicle.ad.drivePathModule:setUnPaused() + else + vehicle.ad.drivePathModule:setPaused() + end + end + end + end + end +end + +function ADBunkerSiloManager:isDestinationInBunkerSilo(vehicle, bunkerSilo) + local network = ADGraphManager:getWayPoints() + local destination = nil + local destinationInBunkerSilo = false + if vehicle.ad.stateModule:getMode() == AutoDrive.MODE_PICKUPANDDELIVER or vehicle.ad.stateModule:getMode() == AutoDrive.MODE_UNLOAD then + destination = vehicle.ad.stateModule:getSecondWayPoint() + elseif vehicle.ad.stateModule:getMode() == AutoDrive.MODE_DELIVERTO then + destination = vehicle.ad.stateModule:getFirstWayPoint() + end + if destination and destination > 0 then + local wp = network[destination] + if wp then + destinationInBunkerSilo = MathUtil.isPointInParallelogram(wp.x, wp.z, bunkerSilo.bunkerSiloArea.sx, bunkerSilo.bunkerSiloArea.sz, + bunkerSilo.bunkerSiloArea.dwx, bunkerSilo.bunkerSiloArea.dwz, bunkerSilo.bunkerSiloArea.dhx, bunkerSilo.bunkerSiloArea.dhz) + end + end + return destinationInBunkerSilo +end diff --git a/scripts/Manager/GraphManager.lua b/scripts/Manager/GraphManager.lua index d2768cc8..7f761fb2 100644 --- a/scripts/Manager/GraphManager.lua +++ b/scripts/Manager/GraphManager.lua @@ -6,522 +6,547 @@ ADGraphManager.MIN_START_DISTANCE = 8 ADGraphManager.MAX_POINTS_IN_SECTION = 100000 function ADGraphManager:load() - self.wayPoints = {} - self.mapMarkers = {} - self.groups = {} - self.groups["All"] = 1 - self.changes = false - self.preparedWayPoints = false + self.wayPoints = {} + self.mapMarkers = {} + self.groups = {} + self.groups["All"] = 1 + self.changes = false + self.preparedWayPoints = false end function ADGraphManager:markChanges() - self.changes = true - self.preparedWayPoints = false + self.changes = true + self.preparedWayPoints = false end function ADGraphManager:resetChanges() - self.changes = false + self.changes = false end function ADGraphManager:hasChanges() - return self.changes + return self.changes end function ADGraphManager:areWayPointsPrepared() - return self.preparedWayPoints + return self.preparedWayPoints end -- Calling functions expect a linear, continuous array function ADGraphManager:getWayPoints() - return self.wayPoints + return self.wayPoints end function ADGraphManager:getWayPointById(wayPointId) - return self.wayPoints[wayPointId] + return self.wayPoints[wayPointId] end function ADGraphManager:resetWayPoints() - self.wayPoints = {} - self:markChanges() + self.wayPoints = {} + self:markChanges() end function ADGraphManager:setWayPoints(wayPoints) - self.wayPoints = wayPoints - self:markChanges() + self.wayPoints = wayPoints + self:markChanges() end function ADGraphManager:getWayPointsCount() - return #self.wayPoints + return #self.wayPoints end function ADGraphManager:setWayPoint(newPoint) - self.wayPoints[newPoint.id] = newPoint - self:markChanges() + self.wayPoints[newPoint.id] = newPoint + self:markChanges() end function ADGraphManager:getMapMarkers() - return self.mapMarkers + return self.mapMarkers end function ADGraphManager:getMapMarkerById(mapMarkerId) - return self.mapMarkers[mapMarkerId] + return self.mapMarkers[mapMarkerId] end function ADGraphManager:getMapMarkerByWayPointId(wayPointId) - for _, mapMarker in pairs(self.mapMarkers) do - if mapMarker.id == wayPointId then - return mapMarker - end - end - return nil + for _, mapMarker in pairs(self.mapMarkers) do + if mapMarker.id == wayPointId then + return mapMarker + end + end + return nil end function ADGraphManager:getMapMarkerByName(mapMarkerName) - for _, mapMarker in pairs(self.mapMarkers) do - if mapMarker.name == mapMarkerName then - return mapMarker - end - end - return nil + for _, mapMarker in pairs(self.mapMarkers) do + if mapMarker.name == mapMarkerName then + return mapMarker + end + end + return nil end function ADGraphManager:getMapMarkersInGroup(groupName) - local markersInGroup = {} + local markersInGroup = {} - for _, mapMarker in pairs(self.mapMarkers) do - if mapMarker.group == groupName then - table.insert(markersInGroup, mapMarker) - end - end + for _, mapMarker in pairs(self.mapMarkers) do + if mapMarker.group == groupName then + table.insert(markersInGroup, mapMarker) + end + end - local sort_func = function(a, b) - a = tostring(a.name):lower() - b = tostring(b.name):lower() - local patt = "^(.-)%s*(%d+)$" - local _, _, col1, num1 = a:find(patt) - local _, _, col2, num2 = b:find(patt) - if (col1 and col2) and col1 == col2 then - return tonumber(num1) < tonumber(num2) - end - return a < b - end + local sort_func = function(a, b) + a = tostring(a.name):lower() + b = tostring(b.name):lower() + local patt = "^(.-)%s*(%d+)$" + local _, _, col1, num1 = a:find(patt) + local _, _, col2, num2 = b:find(patt) + if (col1 and col2) and col1 == col2 then + return tonumber(num1) < tonumber(num2) + end + return a < b + end - table.sort(markersInGroup, sort_func) + table.sort(markersInGroup, sort_func) - return markersInGroup + return markersInGroup end function ADGraphManager:resetMapMarkers() - self.mapMarkers = {} + self.mapMarkers = {} end function ADGraphManager:setMapMarkers(mapMarkers) - self.mapMarkers = mapMarkers + self.mapMarkers = mapMarkers -- create debug markers, debug markers are not saved, so no need to delete them or update map hotspots required -- notifyDestinationListeners is called from caller function -> argument is false self:createDebugMarkers(false) end function ADGraphManager:setMapMarker(mapMarker) - self.mapMarkers[mapMarker.markerIndex] = mapMarker + self.mapMarkers[mapMarker.markerIndex] = mapMarker end function ADGraphManager:getPathTo(vehicle, waypointId, startPoint) - local wp = {} + local wp = {} - local x, _, z = getWorldTranslation(vehicle.components[1].node) + local x, _, z = getWorldTranslation(vehicle.components[1].node) local wp_target = self.wayPoints[waypointId] if wp_target ~= nil then local distanceToTarget = MathUtil.vector2Length(x - wp_target.x, z - wp_target.z) - if distanceToTarget < ADGraphManager.MIN_START_DISTANCE then - table.insert(wp, wp_target) - return wp - end - end - - local closestWaypoint = self:findMatchingWayPointForVehicle(vehicle) - if startPoint ~= nil and startPoint.id ~= nil then + if distanceToTarget < ADGraphManager.MIN_START_DISTANCE then + table.insert(wp, wp_target) + return wp + end + end + + local closestWaypoint = self:findMatchingWayPointForVehicle(vehicle) + if startPoint ~= nil and startPoint.id ~= nil then -- consider id to avoid using Pathfinder wayPoints - local distanceToStartPoint = MathUtil.vector2Length(x - startPoint.x, z - startPoint.z) - if distanceToStartPoint < 5 then - closestWaypoint = startPoint.id - end - end - if closestWaypoint ~= nil then - local outCandidates = self:getBestOutPoints(vehicle, closestWaypoint) - wp = self:pathFromTo(closestWaypoint, waypointId, outCandidates) - end + local distanceToStartPoint = MathUtil.vector2Length(x - startPoint.x, z - startPoint.z) + if distanceToStartPoint < 5 then + closestWaypoint = startPoint.id + end + end + if closestWaypoint ~= nil then + local outCandidates = self:getBestOutPoints(vehicle, closestWaypoint) + wp = self:pathFromTo(closestWaypoint, waypointId, outCandidates) + end - return wp + return wp end function ADGraphManager:pathFromTo(startWaypointId, targetWaypointId, preferredNeighbors) - local wp = {} - if startWaypointId ~= nil and self.wayPoints[startWaypointId] ~= nil and targetWaypointId ~= nil and self.wayPoints[targetWaypointId] ~= nil then - if startWaypointId == targetWaypointId then - table.insert(wp, self.wayPoints[targetWaypointId]) - else - if preferredNeighbors == nil then - preferredNeighbors = {} - end - wp = ADPathCalculator:GetPath(startWaypointId, targetWaypointId, preferredNeighbors) - end - end - return wp + local wp = {} + + if + startWaypointId ~= nil and self.wayPoints[startWaypointId] ~= nil and targetWaypointId ~= nil and + self.wayPoints[targetWaypointId] ~= nil + then + if startWaypointId == targetWaypointId then + table.insert(wp, self.wayPoints[targetWaypointId]) + else + if preferredNeighbors == nil then + preferredNeighbors = {} + end + wp = ADPathCalculator:GetPath(startWaypointId, targetWaypointId, preferredNeighbors) + end + end + return wp end function ADGraphManager:pathFromToMarker(startWaypointId, markerId) - local wp = {} - if startWaypointId ~= nil and self.wayPoints[startWaypointId] ~= nil and self.mapMarkers[markerId] ~= nil and self.mapMarkers[markerId].id ~= nil then - local targetId = self.mapMarkers[markerId].id - if targetId == startWaypointId then - table.insert(wp, 1, self.wayPoints[targetId]) - return wp - else - wp = ADPathCalculator:GetPath(startWaypointId, targetId, {}) - end - end - return wp + local wp = {} + + if + startWaypointId ~= nil and self.wayPoints[startWaypointId] ~= nil and self.mapMarkers[markerId] ~= nil and + self.mapMarkers[markerId].id ~= nil + then + local targetId = self.mapMarkers[markerId].id + if targetId == startWaypointId then + table.insert(wp, 1, self.wayPoints[targetId]) + return wp + else + wp = ADPathCalculator:GetPath(startWaypointId, targetId, {}) + end + end + return wp end function ADGraphManager:FastShortestPath(start, markerName, markerId) - local wp = {} - local start_id = start - local target_id = 0 + local wp = {} + local start_id = start + local target_id = 0 - if start_id == nil or start_id == 0 then - return wp - end + if start_id == nil or start_id == 0 then + return wp + end - for i in pairs(self.mapMarkers) do - if self.mapMarkers[i].name == markerName then - target_id = self.mapMarkers[i].id - break - end - end + for i in pairs(self.mapMarkers) do + if self.mapMarkers[i].name == markerName then + target_id = self.mapMarkers[i].id + break + end + end - if target_id == 0 then - return wp - end + if target_id == 0 then + return wp + end - if target_id == start_id then - table.insert(wp, 1, self.wayPoints[target_id]) - return wp - end + if target_id == start_id then + table.insert(wp, 1, self.wayPoints[target_id]) + return wp + end - wp = ADPathCalculator:GetPath(start_id, target_id, {}) - return wp + wp = ADPathCalculator:GetPath(start_id, target_id, {}) + return wp end function ADGraphManager:getDistanceFromNetwork(vehicle) - local _, distance = vehicle:getClosestWayPoint() - return distance + local _, distance = vehicle:getClosestWayPoint() + return distance end function ADGraphManager:checkYPositionIntegrity() - for _, wp in pairs(self.wayPoints) do - if wp.y == -1 then - wp.y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wp.x, 1, wp.z) - end - end + for _, wp in pairs(self.wayPoints) do + if wp.y == -1 then + wp.y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wp.x, 1, wp.z) + end + end end function ADGraphManager:removeWayPoint(wayPointId, sendEvent) - if wayPointId ~= nil and wayPointId >= 0 and self.wayPoints[wayPointId] ~= nil then - if sendEvent == nil or sendEvent == true then - -- Propagating way point deletion all over the network - AutoDriveDeleteWayPointEvent.sendEvent(wayPointId) - else - -- Deleting map marker if there is one on this waypoint, 'sendEvent' must be false because the event propagation has already happened - self:removeMapMarkerByWayPoint(wayPointId, false) - - local wayPoint = self.wayPoints[wayPointId] - - -- Removing incoming node reference on all out nodes - for _, id in pairs(wayPoint.out) do + if wayPointId ~= nil and wayPointId >= 0 and self.wayPoints[wayPointId] ~= nil then + if sendEvent == nil or sendEvent == true then + -- Propagating way point deletion all over the network + AutoDriveDeleteWayPointEvent.sendEvent(wayPointId) + else + -- Deleting map marker if there is one on this waypoint, 'sendEvent' must be false because the event propagation has already happened + self:removeMapMarkerByWayPoint(wayPointId, false) + + local wayPoint = self.wayPoints[wayPointId] + + -- Removing incoming node reference on all out nodes + for _, id in pairs(wayPoint.out) do if self.wayPoints[id] ~= nil and self.wayPoints[id].incoming ~= nil and wayPoint.id ~= nil then local incomingId = table.indexOf(self.wayPoints[id].incoming, wayPoint.id) if incomingId ~= nil then table.remove(self.wayPoints[id].incoming, incomingId) end end - end + end - -- Removing out node reference on all incoming nodes - for _, id in pairs(wayPoint.incoming) do + -- Removing out node reference on all incoming nodes + for _, id in pairs(wayPoint.incoming) do if self.wayPoints[id] ~= nil and self.wayPoints[id].out ~= nil and wayPoint.id ~= nil then local outId = table.indexOf(self.wayPoints[id].out, wayPoint.id) if outId ~= nil then table.remove(self.wayPoints[id].out, outId) end end - end + end - if #wayPoint.incoming == 0 then - -- This is a reverse node, so we can't rely on the incoming table - for _, wp in pairs(self.wayPoints) do + if #wayPoint.incoming == 0 then + -- This is a reverse node, so we can't rely on the incoming table + for _, wp in pairs(self.wayPoints) do if wp.out ~= nil and wayPoint.id ~= nil then if table.contains(wp.out, wayPoint.id) then table.removeValue(wp.out, wayPoint.id) end end - end - end - - -- Removing waypoint from waypoints array and invalidate it by setting id to -1 - local wp = table.remove(self.wayPoints, wayPoint.id) - if wp ~= nil then - wp.id = -1 - end - - -- Adjusting ids for all succesive nodes :( - for _, wp in pairs(self.wayPoints) do - if wp.id > wayPointId then - wp.id = wp.id - 1 - end - for i, outId in pairs(wp.out) do - if outId > wayPointId then - wp.out[i] = outId - 1 - end - end - for i, incomingId in pairs(wp.incoming) do - if incomingId > wayPointId then - wp.incoming[i] = incomingId - 1 - end - end - end - - -- Adjusting way point id in markers - for _, marker in pairs(self.mapMarkers) do - if marker.id > wayPointId then - marker.id = marker.id - 1 - end - end - - -- Resetting HUD - AutoDrive.Hud.lastUIScale = 0 - - self:markChanges() - end - end + end + end + + -- Removing waypoint from waypoints array and invalidate it by setting id to -1 + local wp = table.remove(self.wayPoints, wayPoint.id) + if wp ~= nil then + wp.id = -1 + end + + -- Adjusting ids for all succesive nodes :( + for _, wp in pairs(self.wayPoints) do + if wp.id > wayPointId then + wp.id = wp.id - 1 + end + for i, outId in pairs(wp.out) do + if outId > wayPointId then + wp.out[i] = outId - 1 + end + end + for i, incomingId in pairs(wp.incoming) do + if incomingId > wayPointId then + wp.incoming[i] = incomingId - 1 + end + end + end + + -- Adjusting way point id in markers + for _, marker in pairs(self.mapMarkers) do + if marker.id > wayPointId then + marker.id = marker.id - 1 + end + end + + -- Resetting HUD + AutoDrive.Hud.lastUIScale = 0 + + self:markChanges() + end + end end function ADGraphManager:renameMapMarker(newName, markerId, sendEvent) - if newName:len() >= 1 and markerId >= 0 then + if newName:len() >= 1 and markerId >= 0 then local mapMarker = self:getMapMarkerById(markerId) if mapMarker == nil or mapMarker.isADDebug == true then -- do not allow rename debug marker return end - if sendEvent == nil or sendEvent == true then - -- Propagating marker rename all over the network - AutoDriveRenameMapMarkerEvent.sendEvent(newName, markerId) - else - -- Saving old map marker name - local oldName = self.mapMarkers[markerId].name - -- Renaming map marker - self.mapMarkers[markerId].name = newName + if sendEvent == nil or sendEvent == true then + -- Propagating marker rename all over the network + AutoDriveRenameMapMarkerEvent.sendEvent(newName, markerId) + else + -- Saving old map marker name + local oldName = self.mapMarkers[markerId].name + -- Renaming map marker + self.mapMarkers[markerId].name = newName - -- Calling external interop listeners - AutoDrive:notifyDestinationListeners() + -- Calling external interop listeners + AutoDrive:notifyDestinationListeners() - -- Resetting HUD - AutoDrive.Hud.lastUIScale = 0 + -- Resetting HUD + AutoDrive.Hud.lastUIScale = 0 - self:markChanges() - end - end + self:markChanges() + end + end end function ADGraphManager:createMapMarkerOnClosest(vehicle, markerName, sendEvent) - if vehicle ~= nil and markerName:len() >= 1 then - -- Finding closest waypoint - local closest, _ = vehicle:getClosestWayPoint() - if closest ~= nil and closest ~= -1 and self.wayPoints[closest] ~= nil then - self:createMapMarker(closest, markerName, sendEvent) - end - end + if vehicle ~= nil and markerName:len() >= 1 then + -- Finding closest waypoint + local closest, _ = vehicle:getClosestWayPoint() + if closest ~= nil and closest ~= -1 and self.wayPoints[closest] ~= nil then + self:createMapMarker(closest, markerName, sendEvent) + end + end end function ADGraphManager:createMapMarker(markerId, markerName, sendEvent) - if markerId ~= nil and markerId >= 0 and markerName:len() >= 1 then - if sendEvent == nil or sendEvent == true then - -- Propagating marker creation all over the network - AutoDriveCreateMapMarkerEvent.sendEvent(markerId, markerName) - else - -- Creating the new map marker - self.mapMarkers[#self.mapMarkers + 1] = {id = markerId, markerIndex = (#self.mapMarkers + 1), name = markerName, group = "All"} + if markerId ~= nil and markerId >= 0 and markerName:len() >= 1 then + if sendEvent == nil or sendEvent == true then + -- Propagating marker creation all over the network + AutoDriveCreateMapMarkerEvent.sendEvent(markerId, markerName) + else + -- Creating the new map marker + self.mapMarkers[#self.mapMarkers + 1] = { + id = markerId, + markerIndex = (#self.mapMarkers + 1), + name = markerName, + group = "All" + } - -- Calling external interop listeners - AutoDrive:notifyDestinationListeners() + -- Calling external interop listeners + AutoDrive:notifyDestinationListeners() - -- Resetting HUD - AutoDrive.Hud.lastUIScale = 0 + -- Resetting HUD + AutoDrive.Hud.lastUIScale = 0 - self:markChanges() - end - end + self:markChanges() + end + end end function ADGraphManager:addGroup(groupName, sendEvent) - if groupName:len() >= 1 and self.groups[groupName] == nil then - if sendEvent == nil or sendEvent == true then - -- Propagating group creation all over the network - AutoDriveGroupsEvent.sendEvent(groupName, AutoDriveGroupsEvent.TYPE_ADD) - else - self.groups[groupName] = table.count(self.groups) + 1 - for _, vehicle in pairs(g_currentMission.vehicles) do - if (vehicle.ad ~= nil and vehicle.ad.groups ~= nil) then - if vehicle.ad.groups[groupName] == nil then - vehicle.ad.groups[groupName] = false - end - end - end - -- Resetting HUD - if AutoDrive.Hud ~= nil then - AutoDrive.Hud.lastUIScale = 0 - end - self:markChanges() - end - end + if groupName:len() >= 1 and self.groups[groupName] == nil then + if sendEvent == nil or sendEvent == true then + -- Propagating group creation all over the network + AutoDriveGroupsEvent.sendEvent(groupName, AutoDriveGroupsEvent.TYPE_ADD) + else + self.groups[groupName] = table.count(self.groups) + 1 + for _, vehicle in pairs(g_currentMission.vehicles) do + if (vehicle.ad ~= nil and vehicle.ad.groups ~= nil) then + if vehicle.ad.groups[groupName] == nil then + vehicle.ad.groups[groupName] = false + end + end + end + -- Resetting HUD + if AutoDrive.Hud ~= nil then + AutoDrive.Hud.lastUIScale = 0 + end + self:markChanges() + end + end end function ADGraphManager:removeGroup(groupName, sendEvent) - if self.groups[groupName] ~= nil then - if sendEvent == nil or sendEvent == true then - -- Propagating group creation all over the network - AutoDriveGroupsEvent.sendEvent(groupName, AutoDriveGroupsEvent.TYPE_REMOVE) - else - local groupId = self.groups[groupName] - -- Removing group from the groups list - self.groups[groupName] = nil - -- Removing group from the vehicles groups list - for _, vehicle in pairs(g_currentMission.vehicles) do - if (vehicle.ad ~= nil and vehicle.ad.groups ~= nil) then - if vehicle.ad.groups[groupName] ~= nil then - vehicle.ad.groups[groupName] = nil - end - end - end - -- Moving all markers in the deleted group to default group - for markerID, mapMarker in pairs(self:getMapMarkers()) do - if mapMarker.group == groupName then - mapMarker.group = "All" - end - end - -- Resetting other goups id - for gName, gId in pairs(self.groups) do - if groupId <= gId then - self.groups[gName] = gId - 1 - end - end - -- Resetting HUD - AutoDrive.Hud.lastUIScale = 0 - self:markChanges() - end - end + if self.groups[groupName] ~= nil then + if sendEvent == nil or sendEvent == true then + -- Propagating group creation all over the network + AutoDriveGroupsEvent.sendEvent(groupName, AutoDriveGroupsEvent.TYPE_REMOVE) + else + local groupId = self.groups[groupName] + -- Removing group from the groups list + self.groups[groupName] = nil + -- Removing group from the vehicles groups list + for _, vehicle in pairs(g_currentMission.vehicles) do + if (vehicle.ad ~= nil and vehicle.ad.groups ~= nil) then + if vehicle.ad.groups[groupName] ~= nil then + vehicle.ad.groups[groupName] = nil + end + end + end + -- Moving all markers in the deleted group to default group + for markerID, mapMarker in pairs(self:getMapMarkers()) do + if mapMarker.group == groupName then + mapMarker.group = "All" + end + end + -- Resetting other goups id + for gName, gId in pairs(self.groups) do + if groupId <= gId then + self.groups[gName] = gId - 1 + end + end + -- Resetting HUD + AutoDrive.Hud.lastUIScale = 0 + self:markChanges() + end + end end function ADGraphManager:changeMapMarkerGroup(groupName, markerId, sendEvent) - if groupName:len() >= 1 and self.groups[groupName] ~= nil and markerId >= 0 and groupName ~= ADGraphManager.debugGroupName then - if sendEvent == nil or sendEvent == true then - -- Propagating marker group change all over the network - AutoDriveChangeMapMarkerGroupEvent.sendEvent(groupName, markerId) - else - -- Changing the group name of the marker - self.mapMarkers[markerId].group = groupName - self:markChanges() - end - end + if + groupName:len() >= 1 and self.groups[groupName] ~= nil and markerId >= 0 and + groupName ~= ADGraphManager.debugGroupName + then + if sendEvent == nil or sendEvent == true then + -- Propagating marker group change all over the network + AutoDriveChangeMapMarkerGroupEvent.sendEvent(groupName, markerId) + else + -- Changing the group name of the marker + self.mapMarkers[markerId].group = groupName + self:markChanges() + end + end end function ADGraphManager:getGroups() - return self.groups + return self.groups end function ADGraphManager:setGroups(groups, updateVehicles) - self.groups = groups - if updateVehicles then - for _, vehicle in pairs(g_currentMission.vehicles) do - if vehicle.ad ~= nil then - if vehicle.ad.groups == nil then - vehicle.ad.groups = {} - end - local newGroups = {} - for groupName, _ in pairs(ADGraphManager:getGroups()) do - newGroups[groupName] = vehicle.ad.groups[groupName] or false - end - vehicle.ad.groups = newGroups - end - end - end + self.groups = groups + if updateVehicles then + for _, vehicle in pairs(g_currentMission.vehicles) do + if vehicle.ad ~= nil then + if vehicle.ad.groups == nil then + vehicle.ad.groups = {} + end + local newGroups = {} + for groupName, _ in pairs(ADGraphManager:getGroups()) do + newGroups[groupName] = vehicle.ad.groups[groupName] or false + end + vehicle.ad.groups = newGroups + end + end + end end function ADGraphManager:getGroupByName(groupName) - return self.groups[groupName] + return self.groups[groupName] end function ADGraphManager:removeMapMarker(markerId, sendEvent) - if markerId ~= nil and markerId >= 0 then - if sendEvent == nil or sendEvent == true then - -- Propagating marker deletion all over the network - AutoDriveDeleteMapMarkerEvent.sendEvent(markerId) - else - if self.mapMarkers[markerId] ~= nil then - table.remove(self.mapMarkers, markerId) - --Readjust stored markerIndex values to point to corrected ID - for markerID, marker in pairs(self.mapMarkers) do - marker.markerIndex = markerID - end - - if g_server ~= nil then - -- Removing references to it on all vehicles - for _, vehicle in pairs(g_currentMission.vehicles) do - if vehicle.ad ~= nil and vehicle.ad.stateModule ~= nil and vehicle.ad.stateModule.getParkDestinationAtJobFinished ~= nil then - local parkDestinationAtJobFinished = vehicle.ad.stateModule:getParkDestinationAtJobFinished() - if parkDestinationAtJobFinished ~= nil and parkDestinationAtJobFinished >= markerId then - if parkDestinationAtJobFinished == markerId then - vehicle.ad.stateModule:setParkDestinationAtJobFinished(-1) - else - vehicle.ad.stateModule:setParkDestinationAtJobFinished(math.max(parkDestinationAtJobFinished - 1, 1)) - end - end - end - end - -- handle all vehicles and tools park destination - for _, vehicle in pairs(g_currentMission.vehicles) do - if vehicle.advd ~= nil and vehicle.advd.getParkDestination ~= nil and vehicle.advd.setParkDestination ~= nil then - local parkDestination = vehicle.advd:getParkDestination(vehicle) - if parkDestination ~= nil and parkDestination >= markerId then - if parkDestination == markerId then + if markerId ~= nil and markerId >= 0 then + if sendEvent == nil or sendEvent == true then + -- Propagating marker deletion all over the network + AutoDriveDeleteMapMarkerEvent.sendEvent(markerId) + else + if self.mapMarkers[markerId] ~= nil then + table.remove(self.mapMarkers, markerId) + --Readjust stored markerIndex values to point to corrected ID + for markerID, marker in pairs(self.mapMarkers) do + marker.markerIndex = markerID + end + + if g_server ~= nil then + -- Removing references to it on all vehicles + for _, vehicle in pairs(g_currentMission.vehicles) do + if + vehicle.ad ~= nil and vehicle.ad.stateModule ~= nil and + vehicle.ad.stateModule.getParkDestinationAtJobFinished ~= nil + then + local parkDestinationAtJobFinished = + vehicle.ad.stateModule:getParkDestinationAtJobFinished() + if parkDestinationAtJobFinished ~= nil and parkDestinationAtJobFinished >= markerId then + if parkDestinationAtJobFinished == markerId then + vehicle.ad.stateModule:setParkDestinationAtJobFinished(-1) + else + vehicle.ad.stateModule:setParkDestinationAtJobFinished( + math.max(parkDestinationAtJobFinished - 1, 1) + ) + end + end + end + end + -- handle all vehicles and tools park destination + for _, vehicle in pairs(g_currentMission.vehicles) do + if + vehicle.advd ~= nil and vehicle.advd.getParkDestination ~= nil and + vehicle.advd.setParkDestination ~= nil + then + local parkDestination = vehicle.advd:getParkDestination(vehicle) + if parkDestination ~= nil and parkDestination >= markerId then + if parkDestination == markerId then vehicle.advd:setParkDestination(vehicle, -1) - else + else vehicle.advd:setParkDestination(vehicle, math.max(parkDestination - 1, 1)) - end - end - end - end - end + end + end + end + end + end -- remove deleted marker from vehicle destinations ADGraphManager:checkResetVehicleDestinations(markerId) - end + end - -- Calling external interop listeners - AutoDrive:notifyDestinationListeners() + -- Calling external interop listeners + AutoDrive:notifyDestinationListeners() - -- Resetting HUD - AutoDrive.Hud.lastUIScale = 0 + -- Resetting HUD + AutoDrive.Hud.lastUIScale = 0 - self:markChanges() - end - end + self:markChanges() + end + end end function ADGraphManager:removeMapMarkerByWayPoint(wayPointId, sendEvent) - if wayPointId ~= nil and wayPointId >= 0 then - -- Finding the map waypoint where the marker should be - local wayPoint = self.wayPoints[wayPointId] + if wayPointId ~= nil and wayPointId >= 0 then + -- Finding the map waypoint where the marker should be + local wayPoint = self.wayPoints[wayPointId] if wayPoint ~= nil then for markerId, marker in pairs(self.mapMarkers) do -- Checking if the waypoint id matches the marker id @@ -531,57 +556,61 @@ function ADGraphManager:removeMapMarkerByWayPoint(wayPointId, sendEvent) end end end - end + end end -function ADGraphManager:toggleConnectionBetween(startNode, endNode, reverseDirection, sendEvent) - if startNode == nil or endNode == nil then - return - end - if sendEvent == nil or sendEvent == true then - -- Propagating connection toggling all over the network - AutoDriveToggleConnectionEvent.sendEvent(startNode, endNode, reverseDirection) - else - if table.contains(startNode.out, endNode.id) or table.contains(endNode.incoming, startNode.id) then - table.removeValue(startNode.out, endNode.id) - table.removeValue(endNode.incoming, startNode.id) - else - table.insert(startNode.out, endNode.id) - if not reverseDirection then - table.insert(endNode.incoming, startNode.id) - end - end +function ADGraphManager:toggleConnectionBetween(startNode, endNode, reverseDirection, dualConnection, sendEvent) + if startNode == nil or endNode == nil then + return + end + if sendEvent == nil or sendEvent == true then + -- Propagating connection toggling all over the network + AutoDriveToggleConnectionEvent.sendEvent(startNode, endNode, reverseDirection, dualConnection) + else + if table.contains(startNode.out, endNode.id) or table.contains(endNode.incoming, startNode.id) then + table.removeValue(startNode.out, endNode.id) + table.removeValue(endNode.incoming, startNode.id) + else + table.insert(startNode.out, endNode.id) + if not reverseDirection then + table.insert(endNode.incoming, startNode.id) + if dualConnection then + table.insert(endNode.out, startNode.id) + table.insert(startNode.incoming, endNode.id) + end + end + end - self:markChanges() - end + self:markChanges() + end end --[[ -single connection ahead 1 -single connection backward (not reverse) 2 -dual connection 3 -reverse connection 4 +single connection ahead 1 +single connection backward (not reverse) 2 +dual connection 3 +reverse connection 4 ]] function ADGraphManager:setConnectionBetween(startNode, endNode, direction, sendEvent) - if startNode == nil or endNode == nil or direction < 1 or direction > 4 then - return - end - if sendEvent == nil or sendEvent == true then - -- Propagating connection toggling all over the network - AutoDriveSetConnectionEvent.sendEvent(startNode, endNode, direction) - else + if startNode == nil or endNode == nil or direction < 1 or direction > 4 then + return + end + if sendEvent == nil or sendEvent == true then + -- Propagating connection toggling all over the network + AutoDriveSetConnectionEvent.sendEvent(startNode, endNode, direction) + else -- remove all connections between the 2 nodes - if table.contains(startNode.out, endNode.id) then - table.removeValue(startNode.out, endNode.id) + if table.contains(startNode.out, endNode.id) then + table.removeValue(startNode.out, endNode.id) end - if table.contains(startNode.incoming, endNode.id) then - table.removeValue(startNode.incoming, endNode.id) + if table.contains(startNode.incoming, endNode.id) then + table.removeValue(startNode.incoming, endNode.id) end - if table.contains(endNode.out, startNode.id) then - table.removeValue(endNode.out, startNode.id) + if table.contains(endNode.out, startNode.id) then + table.removeValue(endNode.out, startNode.id) end - if table.contains(endNode.incoming, startNode.id) then - table.removeValue(endNode.incoming, startNode.id) + if table.contains(endNode.incoming, startNode.id) then + table.removeValue(endNode.incoming, startNode.id) end if direction == 1 then -- forward @@ -601,23 +630,23 @@ function ADGraphManager:setConnectionBetween(startNode, endNode, direction, send -- reverse table.insert(startNode.out, endNode.id) end - self:markChanges() - end + self:markChanges() + end end function ADGraphManager:createWayPoint(x, y, z, sendEvent) - if sendEvent == nil or sendEvent == true then - -- Propagating waypoint creation all over the network - AutoDriveCreateWayPointEvent.sendEvent(x, y, z) - else - local prevId = self:getWayPointsCount() - local newId = prevId + 1 - local newWp = self:createNode(newId, x, y, z, {}, {}, 0) - self:setWayPoint(newWp) - self:markChanges() + if sendEvent == nil or sendEvent == true then + -- Propagating waypoint creation all over the network + AutoDriveCreateWayPointEvent.sendEvent(x, y, z) + else + local prevId = self:getWayPointsCount() + local newId = prevId + 1 + local newWp = self:createNode(newId, x, y, z, {}, {}, 0) + self:setWayPoint(newWp) + self:markChanges() - return newWp - end + return newWp + end end function ADGraphManager:createWayPointColored(x, y, z, colors) @@ -631,48 +660,48 @@ function ADGraphManager:createWayPointColored(x, y, z, colors) end function ADGraphManager:changeWayPointPosition(wayPointId) - local wayPoint = self:getWayPointById(wayPointId) - if wayPoint ~= nil then - self:moveWayPoint(wayPointId, wayPoint.x, wayPoint.y, wayPoint.z, wayPoint.flags) - end + local wayPoint = self:getWayPointById(wayPointId) + if wayPoint ~= nil then + self:moveWayPoint(wayPointId, wayPoint.x, wayPoint.y, wayPoint.z, wayPoint.flags) + end end function ADGraphManager:moveWayPoint(wayPointId, x, y, z, flags, sendEvent) - local wayPoint = self:getWayPointById(wayPointId) - if wayPoint ~= nil then - if sendEvent == nil or sendEvent == true then - -- Propagating waypoint moving all over the network - AutoDriveMoveWayPointEvent.sendEvent(wayPointId, x, y, z, flags) - else - wayPoint.x = x - wayPoint.y = y - wayPoint.z = z - wayPoint.flags = flags - self:markChanges() - end - end + local wayPoint = self:getWayPointById(wayPointId) + if wayPoint ~= nil then + if sendEvent == nil or sendEvent == true then + -- Propagating waypoint moving all over the network + AutoDriveMoveWayPointEvent.sendEvent(wayPointId, x, y, z, flags) + else + wayPoint.x = x + wayPoint.y = y + wayPoint.z = z + wayPoint.flags = flags + self:markChanges() + end + end end function ADGraphManager:recordWayPoint(x, y, z, connectPrevious, dual, isReverse, previousId, flags, sendEvent) - previousId = previousId or 0 - local previous - if connectPrevious then - if previousId == nil or previousId == 0 then - previousId = self:getWayPointsCount() - end - previous = self:getWayPointById(previousId) - end - if g_server ~= nil then - if sendEvent ~= false then - -- Propagating waypoint recording to clients - AutoDriveRecordWayPointEvent.sendEvent(x, y, z, connectPrevious, dual, isReverse, previousId, flags) - end - else - if sendEvent ~= false then - Logging.warning("ADGraphManager:recordWayPoint() must be called only on the server.") - return - end - end + previousId = previousId or 0 + local previous + if connectPrevious then + if previousId == nil or previousId == 0 then + previousId = self:getWayPointsCount() + end + previous = self:getWayPointById(previousId) + end + if g_server ~= nil then + if sendEvent ~= false then + -- Propagating waypoint recording to clients + AutoDriveRecordWayPointEvent.sendEvent(x, y, z, connectPrevious, dual, isReverse, previousId, flags) + end + else + if sendEvent ~= false then + Logging.warning("ADGraphManager:recordWayPoint() must be called only on the server.") + return + end + end -- play sound only on client with enabled editor mode or RecordWhileNotInVehicle if g_client ~= nil then @@ -683,28 +712,28 @@ function ADGraphManager:recordWayPoint(x, y, z, connectPrevious, dual, isReverse end end - local newId = self:getWayPointsCount() + 1 - local newWp = self:createNode(newId, x, y, z, {}, {}, flags) - self:setWayPoint(newWp) - if connectPrevious then - self:toggleConnectionBetween(previous, newWp, isReverse, false) - if dual then - self:toggleConnectionBetween(newWp, previous, isReverse, false) - end - end + local newId = self:getWayPointsCount() + 1 + local newWp = self:createNode(newId, x, y, z, {}, {}, flags) + self:setWayPoint(newWp) + if connectPrevious then + self:toggleConnectionBetween(previous, newWp, isReverse, dual, false) + end - self:markChanges() - return newWp + self:markChanges() + return newWp end function ADGraphManager:isDualRoad(start, target) - if start == nil or target == nil or start.incoming == nil or target.incoming == nil or start.id == nil or target.id == nil then - return false - end + if + start == nil or target == nil or start.incoming == nil or target.incoming == nil or start.id == nil or + target.id == nil + then + return false + end if table.contains(start.incoming, target.id) and table.contains(target.incoming, start.id) then return true end - return false + return false end function ADGraphManager:isReverseRoad(start, target) @@ -715,246 +744,294 @@ function ADGraphManager:isReverseRoad(start, target) end function ADGraphManager:getDistanceBetweenNodes(start, target) - local euclidianDistance = MathUtil.vector2Length(self.wayPoints[start].x - self.wayPoints[target].x, self.wayPoints[start].z - self.wayPoints[target].z) - - local distance = euclidianDistance - - if AutoDrive.getSetting("mapMarkerDetour") > 0 then - for _, mapMarker in pairs(self.mapMarkers) do - if mapMarker.id == start then - distance = distance + AutoDrive.getSetting("mapMarkerDetour") - break - end - end - end + local euclidianDistance = + MathUtil.vector2Length( + self.wayPoints[start].x - self.wayPoints[target].x, + self.wayPoints[start].z - self.wayPoints[target].z + ) + + local distance = euclidianDistance + + if AutoDrive.getSetting("mapMarkerDetour") > 0 then + for _, mapMarker in pairs(self.mapMarkers) do + if mapMarker.id == start then + distance = distance + AutoDrive.getSetting("mapMarkerDetour") + break + end + end + end - if self:getIsPointSubPrio(self.wayPoints[target].id) then - distance = distance * ADGraphManager.SUB_PRIO_FACTOR - end + if self:getIsPointSubPrio(self.wayPoints[target].id) then + distance = distance * ADGraphManager.SUB_PRIO_FACTOR + end - return distance + return distance end function ADGraphManager:getDriveTimeBetweenNodes(start, target, past, maxDrivingSpeed, arrivalTime) - --changed setToUse to defined 3 point for angle calculation - local wp_ahead = self.wayPoints[target] - local wp_current = self.wayPoints[start] - - if wp_ahead == nil or wp_current == nil then - return 0 - end - - local angle = 0 - - if past ~= nil then - local wp_ref = self.wayPoints[past] - if wp_ref ~= nil then - angle = math.abs(AutoDrive.angleBetween({x = wp_ahead.x - wp_current.x, z = wp_ahead.z - wp_current.z}, {x = wp_current.x - wp_ref.x, z = wp_current.z - wp_ref.z})) - end - end - - local driveTime = 0 - local drivingSpeed = 50 - - if angle < 3 then - drivingSpeed = 50 - elseif angle < 5 then - drivingSpeed = 38 - elseif angle < 8 then - drivingSpeed = 27 - elseif angle < 12 then - drivingSpeed = 20 - elseif angle < 15 then - drivingSpeed = 13 - elseif angle < 20 then - drivingSpeed = 10 - elseif angle < 30 then - drivingSpeed = 7 - else - drivingSpeed = 4 - end - - if maxDrivingSpeed ~= nil then - drivingSpeed = math.min(drivingSpeed, maxDrivingSpeed) - end - - local drivingDistance = MathUtil.vector2Length(wp_ahead.x - wp_current.x, wp_ahead.z - wp_current.z) - - driveTime = (drivingDistance) / (drivingSpeed * (1000 / 3600)) - - --avoid map marker - - if not arrivalTime == true then --only for djikstra, for live travel timer we ignore it - if AutoDrive.getSetting("mapMarkerDetour") > 0 then - for _, mapMarker in pairs(self.mapMarkers) do - if mapMarker.id == start then - driveTime = driveTime + (AutoDrive.getSetting("mapMarkerDetour") / (20 / 3.6)) - break - end - end - end - end - - return driveTime, angle + --changed setToUse to defined 3 point for angle calculation + local wp_ahead = self.wayPoints[target] + local wp_current = self.wayPoints[start] + + if wp_ahead == nil or wp_current == nil then + return 0 + end + + local angle = 0 + + if past ~= nil then + local wp_ref = self.wayPoints[past] + if wp_ref ~= nil then + angle = + math.abs( + AutoDrive.angleBetween( + {x = wp_ahead.x - wp_current.x, z = wp_ahead.z - wp_current.z}, + {x = wp_current.x - wp_ref.x, z = wp_current.z - wp_ref.z} + ) + ) + end + end + + local driveTime = 0 + local drivingSpeed = 50 + + if angle < 3 then + drivingSpeed = 50 + elseif angle < 5 then + drivingSpeed = 38 + elseif angle < 8 then + drivingSpeed = 27 + elseif angle < 12 then + drivingSpeed = 20 + elseif angle < 15 then + drivingSpeed = 13 + elseif angle < 20 then + drivingSpeed = 10 + elseif angle < 30 then + drivingSpeed = 7 + else + drivingSpeed = 4 + end + + if maxDrivingSpeed ~= nil then + drivingSpeed = math.min(drivingSpeed, maxDrivingSpeed) + end + + local drivingDistance = MathUtil.vector2Length(wp_ahead.x - wp_current.x, wp_ahead.z - wp_current.z) + + driveTime = (drivingDistance) / (drivingSpeed * (1000 / 3600)) + + --avoid map marker + + if not arrivalTime == true then --only for djikstra, for live travel timer we ignore it + if AutoDrive.getSetting("mapMarkerDetour") > 0 then + for _, mapMarker in pairs(self.mapMarkers) do + if mapMarker.id == start then + driveTime = driveTime + (AutoDrive.getSetting("mapMarkerDetour") / (20 / 3.6)) + break + end + end + end + end + + return driveTime, angle end function ADGraphManager:getDriveTimeForWaypoints(wps, currentWaypoint, maxDrivingSpeed) - local totalTime = 0 - - if wps ~= nil and currentWaypoint ~= nil and wps[currentWaypoint + 1] ~= nil and wps[currentWaypoint] ~= nil and wps[currentWaypoint - 1] == nil then - totalTime = totalTime + self:getDriveTimeBetweenNodes(wps[currentWaypoint].id, wps[currentWaypoint + 1].id, nil, maxDrivingSpeed, true) --first segment, only 2 points, no angle - currentWaypoint = currentWaypoint + 1 - end - while wps ~= nil and wps[currentWaypoint - 1] ~= nil and currentWaypoint ~= nil and wps[currentWaypoint + 1] ~= nil do - if wps[currentWaypoint] ~= nil then - totalTime = totalTime + self:getDriveTimeBetweenNodes(wps[currentWaypoint].id, wps[currentWaypoint + 1].id, wps[currentWaypoint - 1].id, maxDrivingSpeed, true) --continuous segments, 3 points for angle - end - currentWaypoint = currentWaypoint + 1 - end - return totalTime * 1.15 + local totalTime = 0 + + if + wps ~= nil and currentWaypoint ~= nil and wps[currentWaypoint + 1] ~= nil and wps[currentWaypoint] ~= nil and + wps[currentWaypoint - 1] == nil + then + totalTime = + totalTime + + self:getDriveTimeBetweenNodes( + wps[currentWaypoint].id, + wps[currentWaypoint + 1].id, + nil, + maxDrivingSpeed, + true + ) --first segment, only 2 points, no angle + + currentWaypoint = currentWaypoint + 1 + end + while wps ~= nil and wps[currentWaypoint - 1] ~= nil and currentWaypoint ~= nil and wps[currentWaypoint + 1] ~= nil do + if wps[currentWaypoint] ~= nil then + totalTime = + totalTime + + self:getDriveTimeBetweenNodes( + wps[currentWaypoint].id, + wps[currentWaypoint + 1].id, + wps[currentWaypoint - 1].id, + maxDrivingSpeed, + true + ) --continuous segments, 3 points for angle + end + currentWaypoint = currentWaypoint + 1 + end + return totalTime * 1.15 end function ADGraphManager:getHighestConsecutiveIndex() - local toCheckFor = 0 - local consecutive = true - while consecutive == true do - toCheckFor = toCheckFor + 1 - consecutive = false - if self.wayPoints[toCheckFor] ~= nil then - if self.wayPoints[toCheckFor].id == toCheckFor then - consecutive = true - end - end - end + local toCheckFor = 0 + local consecutive = true + while consecutive == true do + toCheckFor = toCheckFor + 1 + consecutive = false + if self.wayPoints[toCheckFor] ~= nil then + if self.wayPoints[toCheckFor].id == toCheckFor then + consecutive = true + end + end + end - return (toCheckFor - 1) + return (toCheckFor - 1) end function ADGraphManager:findMatchingWayPointForVehicle(vehicle) - local startNode = vehicle.ad.frontNode - --returns waypoint closest to vehicle position and with the most suited heading - local x1, _, z1 = getWorldTranslation(startNode) - local rx, _, rz = localDirectionToWorld(startNode, 0, 0, 1) - local vehicleVector = {x = rx, z = rz} - local point = {x = x1, z = z1} + local startNode = vehicle.ad.frontNode + --returns waypoint closest to vehicle position and with the most suited heading + local x1, _, z1 = getWorldTranslation(startNode) + local rx, _, rz = localDirectionToWorld(startNode, 0, 0, 1) + local vehicleVector = {x = rx, z = rz} + local point = {x = x1, z = z1} - local bestPoint, distance = self:findMatchingWayPoint(point, vehicleVector, vehicle:getWayPointIdsInRange(1, 20)) + local bestPoint, distance = self:findMatchingWayPoint(point, vehicleVector, vehicle:getWayPointIdsInRange(1, 20)) - if bestPoint == -1 then - return vehicle:getClosestNotReversedWayPoint() - end + if bestPoint == -1 then + return vehicle:getClosestNotReversedWayPoint() + end - return bestPoint, distance + return bestPoint, distance end function ADGraphManager:findMatchingWayPoint(point, direction, candidates) - candidates = candidates or {} - - local closest = -1 - local distance = -1 - local lastAngleToPoint = -1 - local lastAngleToVehicle = -1 - for _, id in pairs(candidates) do - local toCheck = self.wayPoints[id] - local nextP = nil - local outIndex = 1 - if toCheck.out ~= nil then - if toCheck.out[outIndex] ~= nil then - nextP = self.wayPoints[toCheck.out[outIndex]] - end - - while nextP ~= nil do - local vecToNextPoint = {x = nextP.x - toCheck.x, z = nextP.z - toCheck.z} - local vecToVehicle = {x = toCheck.x - point.x, z = toCheck.z - point.z} - local angleToNextPoint = AutoDrive.angleBetween(direction, vecToNextPoint) - local angleToVehicle = AutoDrive.angleBetween(direction, vecToVehicle) - local dis = MathUtil.vector2Length(toCheck.x - point.x, toCheck.z - point.z) - if closest == -1 and (math.abs(angleToNextPoint) < 60 and math.abs(angleToVehicle) < 30) and #toCheck.incoming > 0 then - closest = toCheck.id - distance = dis - lastAngleToPoint = angleToNextPoint - lastAngleToVehicle = angleToVehicle - else - if #toCheck.incoming > 0 and (math.abs(angleToNextPoint) + math.abs(angleToVehicle)) < (math.abs(lastAngleToPoint) + math.abs(lastAngleToVehicle)) and (math.abs(angleToNextPoint) < 60 and math.abs(angleToVehicle) < 30) then - closest = toCheck.id - distance = dis - lastAngleToPoint = angleToNextPoint - lastAngleToVehicle = angleToVehicle - end - end - - outIndex = outIndex + 1 - if toCheck.out[outIndex] ~= nil then - nextP = self.wayPoints[toCheck.out[outIndex]] - else - nextP = nil - end - end - end - end - - return closest, distance + candidates = candidates or {} + + local closest = -1 + local distance = -1 + local lastAngleToPoint = -1 + local lastAngleToVehicle = -1 + for _, id in pairs(candidates) do + local toCheck = self.wayPoints[id] + local nextP = nil + local outIndex = 1 + if toCheck.out ~= nil then + if toCheck.out[outIndex] ~= nil then + nextP = self.wayPoints[toCheck.out[outIndex]] + end + + while nextP ~= nil do + local vecToNextPoint = {x = nextP.x - toCheck.x, z = nextP.z - toCheck.z} + local vecToVehicle = {x = toCheck.x - point.x, z = toCheck.z - point.z} + local angleToNextPoint = AutoDrive.angleBetween(direction, vecToNextPoint) + local angleToVehicle = AutoDrive.angleBetween(direction, vecToVehicle) + local dis = MathUtil.vector2Length(toCheck.x - point.x, toCheck.z - point.z) + + if + closest == -1 and (math.abs(angleToNextPoint) < 60 and math.abs(angleToVehicle) < 30) and + #toCheck.incoming > 0 + then + closest = toCheck.id + distance = dis + lastAngleToPoint = angleToNextPoint + lastAngleToVehicle = angleToVehicle + else + if + #toCheck.incoming > 0 and + (math.abs(angleToNextPoint) + math.abs(angleToVehicle)) < + (math.abs(lastAngleToPoint) + math.abs(lastAngleToVehicle)) and + (math.abs(angleToNextPoint) < 60 and math.abs(angleToVehicle) < 30) + then + closest = toCheck.id + distance = dis + lastAngleToPoint = angleToNextPoint + lastAngleToVehicle = angleToVehicle + end + end + + outIndex = outIndex + 1 + if toCheck.out[outIndex] ~= nil then + nextP = self.wayPoints[toCheck.out[outIndex]] + else + nextP = nil + end + end + end + end + + return closest, distance end function ADGraphManager:getWayPointsInRange(point, rangeMin, rangeMax) - local inRange = {} + local inRange = {} - for _, wp in pairs(self.wayPoints) do - local dis = MathUtil.vector2Length(wp.x - point.x, wp.z - point.z) - if dis < rangeMax and dis > rangeMin then - table.insert(inRange, wp.id) - end - end + for _, wp in pairs(self.wayPoints) do + local dis = MathUtil.vector2Length(wp.x - point.x, wp.z - point.z) + if dis < rangeMax and dis > rangeMin then + table.insert(inRange, wp.id) + end + end - return inRange + return inRange end function ADGraphManager:createNode(id, x, y, z, out, incoming, flags, colors) - return { - id = id, - x = x, - y = y, - z = z, - out = out, - incoming = incoming, - flags = flags, + return { + id = id, + x = x, + y = y, + z = z, + out = out, + incoming = incoming, + flags = flags, colors = colors - } + } end function ADGraphManager:prepareWayPoints() - local network = self:getWayPoints() - for id, wp in ipairs(network) do - wp.transitMapping = {} - wp.inverseTransitMapping = {} - if #wp.incoming > 0 then --and #wp.out > 0 - for outIndex, outId in ipairs(wp.out) do - wp.inverseTransitMapping[outId] = {} - end - - for inIndex, inId in ipairs(wp.incoming) do - local inPoint = network[inId] - wp.transitMapping[inId] = {} - for outIndex, outId in ipairs(wp.out) do - local outPoint = network[outId] - local angle = math.abs(AutoDrive.angleBetween({x = outPoint.x - wp.x, z = outPoint.z - wp.z}, {x = wp.x - inPoint.x, z = wp.z - inPoint.z})) - --print("prep4: " .. outId .. " angle: " .. angle) - - if angle <= 90 then - table.insert(wp.transitMapping[inId], outId) - table.insert(wp.inverseTransitMapping[outId], inId) - else - --Also for reverse routes - but only checked on demand, if angle check fails - local isReverseStart = not table.contains(outPoint.incoming, wp.id) - local isReverseEnd = table.contains(outPoint.incoming, wp.id) and not table.contains(wp.incoming, inPoint.id) - if isReverseStart or isReverseEnd then - table.insert(wp.transitMapping[inId], outId) - table.insert(wp.inverseTransitMapping[outId], inId) - end - end - end - end - end + local network = self:getWayPoints() + for id, wp in ipairs(network) do + wp.transitMapping = {} + wp.inverseTransitMapping = {} + if #wp.incoming > 0 then --and #wp.out > 0 + for outIndex, outId in ipairs(wp.out) do + wp.inverseTransitMapping[outId] = {} + end + + for inIndex, inId in ipairs(wp.incoming) do + local inPoint = network[inId] + wp.transitMapping[inId] = {} + for outIndex, outId in ipairs(wp.out) do + local outPoint = network[outId] + local angle = + math.abs( + AutoDrive.angleBetween( + {x = outPoint.x - wp.x, z = outPoint.z - wp.z}, + {x = wp.x - inPoint.x, z = wp.z - inPoint.z} + ) + ) + + --print("prep4: " .. outId .. " angle: " .. angle) + + if angle <= 80 then + table.insert(wp.transitMapping[inId], outId) + table.insert(wp.inverseTransitMapping[outId], inId) + else + --Also for reverse routes - but only checked on demand, if angle check fails + local isReverseStart = not table.contains(outPoint.incoming, wp.id) + + local isReverseEnd = + table.contains(outPoint.incoming, wp.id) and not table.contains(wp.incoming, inPoint.id) + if isReverseStart or isReverseEnd then + table.insert(wp.transitMapping[inId], outId) + table.insert(wp.inverseTransitMapping[outId], inId) + end + end + end + end + end end self.preparedWayPoints = true end @@ -962,35 +1039,49 @@ end -- this looks simlar to prepareWayPoints, but is separated to not disturb this calculation -- here also additional checks may be implemented function ADGraphManager:getNetworkErrors() - local network = self:getWayPoints() - for id, wp in ipairs(network) do - wp.errorMapping = {} - - if #wp.incoming > 0 then - for outIndex, outId in ipairs(wp.out) do - wp.errorMapping[outId] = true -- assume no path - end - - for inIndex, inId in ipairs(wp.incoming) do - local inPoint = network[inId] - for outIndex, outId in ipairs(wp.out) do + local network = self:getWayPoints() + for _, wp in ipairs(network) do + wp.errorMapping = {} + + if #wp.incoming > 0 then + for _, inId in ipairs(wp.incoming) do + local inPoint = network[inId] + local hasGoodAngle = false + for _, outId in ipairs(wp.out) do if inId ~= outId then local outPoint = network[outId] - local angle = math.abs(AutoDrive.angleBetween({x = outPoint.x - wp.x, z = outPoint.z - wp.z}, {x = wp.x - inPoint.x, z = wp.z - inPoint.z})) - if angle <= 90 then - wp.errorMapping[outId] = false - else + local angle = + math.abs( + AutoDrive.angleBetween( + {x = outPoint.x - wp.x, z = outPoint.z - wp.z}, + {x = wp.x - inPoint.x, z = wp.z - inPoint.z} + ) + ) + if angle > 80 then + local isBadAngle = true local isReverseStart = not table.contains(outPoint.incoming, wp.id) - local isReverseEnd = table.contains(outPoint.incoming, wp.id) and not table.contains(wp.incoming, inPoint.id) + + local isReverseEnd = + table.contains(outPoint.incoming, wp.id) and not table.contains(wp.incoming, inPoint.id) if isReverseStart or isReverseEnd then - wp.errorMapping[outId] = false + isBadAngle = false + end + if ADGraphManager:isDualRoad(wp, outPoint) then + isBadAngle = false + end + if ADGraphManager:isDualRoad(wp, inPoint) then + isBadAngle = false + end + if isBadAngle then + wp.errorMapping[inId] = outId end + else + hasGoodAngle = true end end - if inId == outId and #wp.incoming == 1 then - -- only 1 dual connection - wp.errorMapping[outId] = false - end + end + if hasGoodAngle then + wp.errorMapping[inId] = nil end end end @@ -1050,12 +1141,12 @@ end -- create debug markers for waypoints issues function ADGraphManager:createDebugMarkers(updateMap) - local overallnumberWP = self:getWayPointsCount() - if overallnumberWP < 3 then - return - end + local overallnumberWP = self:getWayPointsCount() + if overallnumberWP < 3 then + return + end ADGraphManager:getNetworkErrors() - local network = self:getWayPoints() + local network = self:getWayPoints() local shouldUpdateMap = updateMap if shouldUpdateMap == nil then @@ -1066,39 +1157,41 @@ function ADGraphManager:createDebugMarkers(updateMap) self:removeDebugMarkers() end - if AutoDrive.getDebugChannelIsSet(AutoDrive.DC_ROADNETWORKINFO) then - -- create markers for open ends + if AutoDrive.getDebugChannelIsSet(AutoDrive.DC_ROADNETWORKINFO) then + -- create markers for open ends if self:getGroupByName(ADGraphManager.debugGroupName) == nil then -- sendEvent should be false as function is initiated on server and all clients via debug setting self:addGroup(ADGraphManager.debugGroupName, false) end - local count1 = 1 - local count2 = 1 - local count3 = 1 - local count4 = 1 - local count9 = 1 - local mapMarkerCounter = #self:getMapMarkers() + 1 - for i, wp in pairs(network) do + local count1 = 1 + local count2 = 1 + local count3 = 1 + local count4 = 1 + local count9 = 1 + local mapMarkerCounter = #self:getMapMarkers() + 1 + for i, wp in pairs(network) do wp.foundError = false -- mark wayPoint without outgoing connection - if #wp.out == 0 then - if wp ~= nil then - local debugMapMarkerName = "1_" .. tostring(count1) + if #wp.out == 0 then + if wp ~= nil then + if not ADGraphManager:getMapMarkerByWayPointId(wp.id) then + local debugMapMarkerName = "1_" .. tostring(count1) - -- create the mapMarker - local mapMarker = {} - mapMarker.name = debugMapMarkerName - mapMarker.group = ADGraphManager.debugGroupName - mapMarker.markerIndex = mapMarkerCounter - mapMarker.id = wp.id - mapMarker.isADDebug = true - self:setMapMarker(mapMarker) + -- create the mapMarker + local mapMarker = {} + mapMarker.name = debugMapMarkerName + mapMarker.group = ADGraphManager.debugGroupName + mapMarker.markerIndex = mapMarkerCounter + mapMarker.id = wp.id + mapMarker.isADDebug = true + self:setMapMarker(mapMarker) - wp.foundError = true - count1 = count1 + 1 - mapMarkerCounter = mapMarkerCounter + 1 - end - end + wp.foundError = true + count1 = count1 + 1 + mapMarkerCounter = mapMarkerCounter + 1 + end + end + end -- mark reverse wayPoint with less angle to be reverse -> wrong connection in network if not wp.foundError and wp.incoming ~= nil then @@ -1106,7 +1199,12 @@ function ADGraphManager:createDebugMarkers(updateMap) if wp.out ~= nil then for _, wp_out in pairs(wp.out) do -- if self:isReverseStart(wp,self:getWayPointById(wp_1)) then - local isWrongReverseStart = self:checkForWrongReverseStart(self:getWayPointById(wp_in),wp,self:getWayPointById(wp_out)) + local isWrongReverseStart = + self:checkForWrongReverseStart( + self:getWayPointById(wp_in), + wp, + self:getWayPointById(wp_out) + ) if isWrongReverseStart then local debugMapMarkerName = "2_" .. tostring(count2) @@ -1195,8 +1293,8 @@ function ADGraphManager:createDebugMarkers(updateMap) mapMarkerCounter = mapMarkerCounter + 1 end end - end - end + end + end if shouldUpdateMap == true then AutoDrive:notifyDestinationListeners() end @@ -1210,9 +1308,15 @@ function ADGraphManager:checkForWrongReverseStart(wp_ref, wp_current, wp_ahead) end local isReverseStart = wp_ahead.incoming ~= nil and (not table.contains(wp_ahead.incoming, wp_current.id)) - isReverseStart = isReverseStart and not(wp_current.incoming ~= nil and (not table.contains(wp_current.incoming, wp_ref.id))) - local angle = AutoDrive.angleBetween({x = wp_ahead.x - wp_current.x, z = wp_ahead.z - wp_current.z}, {x = wp_current.x - wp_ref.x, z = wp_current.z - wp_ref.z}) + isReverseStart = + isReverseStart and not (wp_current.incoming ~= nil and (not table.contains(wp_current.incoming, wp_ref.id))) + + local angle = + AutoDrive.angleBetween( + {x = wp_ahead.x - wp_current.x, z = wp_ahead.z - wp_current.z}, + {x = wp_current.x - wp_ref.x, z = wp_current.z - wp_ref.z} + ) angle = math.abs(angle) if angle <= 90 and isReverseStart then @@ -1230,7 +1334,6 @@ function ADGraphManager:checkForMissingIncoming(wp_current) end local reverseFound = false if wp_current.incoming ~= nil and #wp_current.incoming == 0 then - -- search for a possible reverse connection for _, wp in pairs(self.wayPoints) do if wp.out ~= nil and wp_current.id ~= nil then @@ -1257,7 +1360,6 @@ function ADGraphManager:checkForMissingDualConnection(wp_current) if wp_current.incoming ~= nil and wp_current.out ~= nil and #wp_current.incoming == 1 and #wp_current.out == 1 then if wp_current.incoming[1] ~= nil and wp_current.out[1] ~= nil and wp_current.incoming[1] == wp_current.out[1] then - local mapMarker = ADGraphManager:getMapMarkerByWayPointId(wp_current.id) -- only dual waypoint without Marker is an error if mapMarker == nil then @@ -1278,82 +1380,80 @@ function ADGraphManager:checkForMissingDualConnection(wp_current) return ret end - function ADGraphManager:checkForOtherErrors(wp) local ret = false - if wp == nil then return true end --- TODO + -- TODO - local network = self:getWayPoints() + -- local network = self:getWayPoints() - for outIndex, outId in ipairs(wp.out) do - ret = ret or wp.errorMapping[outId] + for _, inId in ipairs(wp.incoming) do + ret = ret or (wp.errorMapping[inId] ~= nil) end return ret end function ADGraphManager:toggleWayPointAsSubPrio(wayPointId) - local wayPoint = self:getWayPointById(wayPointId) - if wayPoint ~= nil then - if self:getIsPointSubPrio(wayPointId) then - wayPoint.flags = wayPoint.flags - AutoDrive.FLAG_SUBPRIO - else - wayPoint.flags = wayPoint.flags + AutoDrive.FLAG_SUBPRIO - end - end + local wayPoint = self:getWayPointById(wayPointId) + if wayPoint ~= nil then + if self:getIsPointSubPrio(wayPointId) then + wayPoint.flags = wayPoint.flags - AutoDrive.FLAG_SUBPRIO + else + wayPoint.flags = wayPoint.flags + AutoDrive.FLAG_SUBPRIO + end + end - self:moveWayPoint(wayPointId, wayPoint.x, wayPoint.y, wayPoint.z, wayPoint.flags) + self:moveWayPoint(wayPointId, wayPoint.x, wayPoint.y, wayPoint.z, wayPoint.flags) - self:markChanges() + self:markChanges() end function ADGraphManager:getIsPointSubPrio(wayPointId) - local wayPoint = self:getWayPointById(wayPointId) + local wayPoint = self:getWayPointById(wayPointId) - return wayPoint ~= nil and bitAND(wayPoint.flags, AutoDrive.FLAG_SUBPRIO) > 0 + return wayPoint ~= nil and bitAND(wayPoint.flags, AutoDrive.FLAG_SUBPRIO) > 0 end function ADGraphManager:setWayPointFlags(wayPointId, flags) - local wayPoint = self:getWayPointById(wayPointId) - if wayPoint ~= nil and flags ~= nil then + local wayPoint = self:getWayPointById(wayPointId) + if wayPoint ~= nil and flags ~= nil then self:moveWayPoint(wayPointId, wayPoint.x, wayPoint.y, wayPoint.z, flags) self:markChanges() - end + end end function ADGraphManager:getBestOutPoints(vehicle, nodeId) - local neighbors = {} - - local x, y, z = getWorldTranslation(vehicle.components[1].node) - local toCheck = self.wayPoints[nodeId] - local baseDistance = MathUtil.vector2Length(toCheck.x - x, toCheck.z - z) - - if toCheck.out ~= nil then - for _, outId in pairs(toCheck.out) do - local out = self.wayPoints[outId] - local _, _, offsetZ = worldToLocal(vehicle.components[1].node, out.x, y, out.z) - if out ~= nil and baseDistance < MathUtil.vector2Length(out.x - x, out.z - z) and offsetZ > 0 then - table.insert(neighbors, out.id) - end - end - end + local neighbors = {} + + local x, y, z = getWorldTranslation(vehicle.components[1].node) + local toCheck = self.wayPoints[nodeId] + local baseDistance = MathUtil.vector2Length(toCheck.x - x, toCheck.z - z) + + if toCheck.out ~= nil then + for _, outId in pairs(toCheck.out) do + local out = self.wayPoints[outId] + local _, _, offsetZ = worldToLocal(vehicle.components[1].node, out.x, y, out.z) + if out ~= nil and baseDistance < MathUtil.vector2Length(out.x - x, out.z - z) and offsetZ > 0 then + table.insert(neighbors, out.id) + end + end + end - return neighbors + return neighbors end --[[ TODO: at the moment only supported for directions: -single connection ahead 1 -single connection backward (not reverse) 2 -dual connection 3 -reverse connection not tested !!! +single connection ahead 1 +single connection backward (not reverse) 2 +dual connection 3 +reverse connection not tested !!! ]] function ADGraphManager:getIsWayPointInSection(wayPointId, direction) - local wayPoint = self:getWayPointById(wayPointId) + local wayPoint = self:getWayPointById(wayPointId) if wayPoint == nil then return false end @@ -1375,7 +1475,7 @@ function ADGraphManager:getIsWayPointInSection(wayPointId, direction) -- this is used to treat this wayPoint as last in a section local foundReverse = false for _, connectedId in pairs(connectedIds) do - connectedWayPoint = self:getWayPointById(connectedId) + local connectedWayPoint = self:getWayPointById(connectedId) foundReverse = foundReverse or ADGraphManager:isReverseRoad(wayPoint, connectedWayPoint) end return not foundReverse @@ -1388,20 +1488,20 @@ function ADGraphManager:getIsWayPointInSection(wayPointId, direction) end --[[ -no junction return 0 -single connection ahead return 1 -single connection backward (not reverse) return 2 -dual connection return 3 -reverse connection return 4 +no junction return 0 +single connection ahead return 1 +single connection backward (not reverse) return 2 +dual connection return 3 +reverse connection return 4 ]] function ADGraphManager:getIsWayPointJunction(startId, targetId) - if startId <= 0 or targetId <=0 then + if startId <= 0 or targetId <= 0 then return 0 end - local wayPointStart = self:getWayPointById(startId) - local wayPointTarget = self:getWayPointById(targetId) - if wayPointTarget == nil or wayPointStart == nil then + local wayPointStart = self:getWayPointById(startId) + local wayPointTarget = self:getWayPointById(targetId) + if wayPointTarget == nil or wayPointStart == nil then return 0 end @@ -1432,31 +1532,36 @@ function ADGraphManager:getIsWayPointJunction(startId, targetId) addConnections(wayPointTarget.incoming, targetConnectedIdsIncoming) addConnections(wayPointTarget.out, targetConnectedIdsOut) - if + if not (table.contains(startConnectedIdsIncoming, targetId) and table.contains(targetConnectedIdsOut, startId)) and - table.contains(startConnectedIdsOut, targetId) and table.contains(targetConnectedIdsIncoming, startId) and - (#startConnectedIds >= 3) and (#targetConnectedIds == 2) - then + table.contains(startConnectedIdsOut, targetId) and + table.contains(targetConnectedIdsIncoming, startId) and + (#startConnectedIds >= 3) and + (#targetConnectedIds == 2) + then -- one way ahead return 1 - elseif + elseif table.contains(startConnectedIdsIncoming, targetId) and table.contains(targetConnectedIdsOut, startId) and - not (table.contains(startConnectedIdsOut, targetId) and table.contains(targetConnectedIdsIncoming, startId)) and - (#startConnectedIds >= 3) and (#targetConnectedIds == 2) - then + not (table.contains(startConnectedIdsOut, targetId) and table.contains(targetConnectedIdsIncoming, startId)) and + (#startConnectedIds >= 3) and + (#targetConnectedIds == 2) + then -- one way backward return 2 - elseif + elseif table.contains(startConnectedIdsIncoming, targetId) and table.contains(targetConnectedIdsOut, startId) and - table.contains(startConnectedIdsOut, targetId) and table.contains(targetConnectedIdsIncoming, startId) and - (#startConnectedIds >= 3) and (#targetConnectedIds == 2) - then + table.contains(startConnectedIdsOut, targetId) and + table.contains(targetConnectedIdsIncoming, startId) and + (#startConnectedIds >= 3) and + (#targetConnectedIds == 2) + then -- two way return 3 - elseif - table.contains(startConnectedIdsOut, targetId) and not table.contains(targetConnectedIdsIncoming, startId) and - (#startConnectedIds >= 3) - then + elseif + table.contains(startConnectedIdsOut, targetId) and not table.contains(targetConnectedIdsIncoming, startId) and + (#startConnectedIds >= 3) + then -- reverse return 4 else @@ -1466,13 +1571,13 @@ end --[[ at the moment only supported for directions: -single connection ahead 1 -single connection backward (not reverse) 2 -dual connection 3 +single connection ahead 1 +single connection backward (not reverse) 2 +dual connection 3 ]] function ADGraphManager:getWayPointsInSection(startId, targetId, direction) - local previousId = startId - local nextId = targetId + local previousId = startId + local nextId = targetId local sectionWayPoints = {} if direction < 1 or direction > 3 then @@ -1489,16 +1594,16 @@ function ADGraphManager:getWayPointsInSection(startId, targetId, direction) table.insert(sectionWayPoints, nextId) local nextwayPoint = self:getWayPointById(nextId) - if nextwayPoint.incoming[1] ~= nil and nextwayPoint.incoming[1] ~= previousId then + if nextwayPoint.incoming[1] ~= nil and nextwayPoint.incoming[1] ~= previousId then previousId = nextId nextId = nextwayPoint.incoming[1] - elseif nextwayPoint.incoming[2] ~= nil and nextwayPoint.incoming[2] ~= previousId then + elseif nextwayPoint.incoming[2] ~= nil and nextwayPoint.incoming[2] ~= previousId then previousId = nextId nextId = nextwayPoint.incoming[2] - elseif nextwayPoint.out[1] ~= nil and nextwayPoint.out[1] ~= previousId then + elseif nextwayPoint.out[1] ~= nil and nextwayPoint.out[1] ~= previousId then previousId = nextId nextId = nextwayPoint.out[1] - elseif nextwayPoint.out[2] ~= nil and nextwayPoint.out[2] ~= previousId then + elseif nextwayPoint.out[2] ~= nil and nextwayPoint.out[2] ~= previousId then previousId = nextId nextId = nextwayPoint.out[2] else @@ -1515,7 +1620,11 @@ end function ADGraphManager:setConnectionBetweenWayPointsInSection(vehicle, direction) if vehicle.ad.sectionWayPoints ~= nil and #vehicle.ad.sectionWayPoints > 2 then for i = 1, #vehicle.ad.sectionWayPoints - 1 do - ADGraphManager:setConnectionBetween(ADGraphManager:getWayPointById(vehicle.ad.sectionWayPoints[i]), ADGraphManager:getWayPointById(vehicle.ad.sectionWayPoints[i+1]), direction) + ADGraphManager:setConnectionBetween( + ADGraphManager:getWayPointById(vehicle.ad.sectionWayPoints[i]), + ADGraphManager:getWayPointById(vehicle.ad.sectionWayPoints[i + 1]), + direction + ) end end end @@ -1574,7 +1683,7 @@ function ADGraphManager:deleteColorSelectionWayPoints() local wp = ADGraphManager:getWayPointById(actualID) if wp.colors ~= nil then ADGraphManager:removeWayPoint(actualID, false) - actualID = self:getWayPointsCount() -- removed a wayPoint so check from highest again + actualID = self:getWayPointsCount() -- removed a wayPoint so check from highest again else actualID = actualID - 1 end @@ -1582,88 +1691,100 @@ function ADGraphManager:deleteColorSelectionWayPoints() end function ADGraphManager:removeNodesWithFlag(flagToRemove) - local network = self:getWayPoints() - local pointsToDelete = {} - for i, wp in pairs(network) do - if bitAND(wp.flags, flagToRemove) > 0 then - table.insert(pointsToDelete, wp.id) - end - end - - -- sort the wayPoints to delete in descant order to ensure correct linkage deletion - local sort_func = function(a, b) - return a > b - end - table.sort(pointsToDelete, sort_func) - - for i = 1, #pointsToDelete do - ADGraphManager:removeWayPoint(pointsToDelete[i]) - end -end - -function ADGraphManager:createSplineConnection(start, waypoints, target, sendEvent) - if sendEvent == nil or sendEvent == true then - -- Propagating connection toggling all over the network - CreateSplineConnectionEvent.sendEvent(start, waypoints, target) - else - local lastId = start - local lastHeight = ADGraphManager:getWayPointById(start).y - for wpId, wp in pairs(waypoints) do - if math.abs(wp.y - lastHeight) > 1 then -- prevent point dropping into the ground in case of bridges etc - wp.y = lastHeight - end - self:createWayPoint(wp.x, wp.y, wp.z, sendEvent) - local createdId = self:getWayPointsCount() - self:toggleConnectionBetween(ADGraphManager:getWayPointById(lastId), ADGraphManager:getWayPointById(createdId), false, false) - lastId = createdId - lastHeight = wp.y - end - - local wp = self:getWayPointById(lastId) - self:toggleConnectionBetween(wp, self:getWayPointById(target), false, false) - end + local network = self:getWayPoints() + local pointsToDelete = {} + for i, wp in pairs(network) do + if bitAND(wp.flags, flagToRemove) > 0 then + table.insert(pointsToDelete, wp.id) + end + end + + -- sort the wayPoints to delete in descant order to ensure correct linkage deletion + local sort_func = function(a, b) + return a > b + end + table.sort(pointsToDelete, sort_func) + + for i = 1, #pointsToDelete do + ADGraphManager:removeWayPoint(pointsToDelete[i]) + end +end + +function ADGraphManager:createSplineConnection(start, waypoints, target, dualConnection, sendEvent) + if sendEvent == nil or sendEvent == true then + -- Propagating connection toggling all over the network + CreateSplineConnectionEvent.sendEvent(start, waypoints, target, dualConnection) + else + local lastId = start + local lastHeight = ADGraphManager:getWayPointById(start).y + local subPrio = self:getIsPointSubPrio(start) or self:getIsPointSubPrio(target) + + for _, wp in pairs(waypoints) do + if math.abs(wp.y - lastHeight) > 1 then -- prevent point dropping into the ground in case of bridges etc + wp.y = lastHeight + end + self:createWayPoint(wp.x, wp.y, wp.z, sendEvent) + local createdId = self:getWayPointsCount() + if subPrio then + ADGraphManager:toggleWayPointAsSubPrio(createdId) + end + + self:toggleConnectionBetween( + ADGraphManager:getWayPointById(lastId), + ADGraphManager:getWayPointById(createdId), + false, + dualConnection, + false + ) + lastId = createdId + lastHeight = wp.y + end + + local wp = self:getWayPointById(lastId) + self:toggleConnectionBetween(wp, self:getWayPointById(target), false, dualConnection, false) + end end function ADGraphManager:getNextTargetAlphabetically(markerId) - local sortedMarkers = self:getSortedMarkers() - for i, markerIdIter in ipairs(sortedMarkers) do - if markerIdIter == markerId then - if i < #sortedMarkers then - return sortedMarkers[i+1] - else - return sortedMarkers[1] - end - end - end - return markerId + local sortedMarkers = self:getSortedMarkers() + for i, markerIdIter in ipairs(sortedMarkers) do + if markerIdIter == markerId then + if i < #sortedMarkers then + return sortedMarkers[i + 1] + else + return sortedMarkers[1] + end + end + end + return markerId end function ADGraphManager:getPreviousTargetAlphabetically(markerId) - local sortedMarkers = self:getSortedMarkers() - for i, markerIdIter in ipairs(sortedMarkers) do - if markerIdIter == markerId then - if i > 1 then - return sortedMarkers[i-1] - else - return sortedMarkers[#sortedMarkers] - end - end - end - return markerId + local sortedMarkers = self:getSortedMarkers() + for i, markerIdIter in ipairs(sortedMarkers) do + if markerIdIter == markerId then + if i > 1 then + return sortedMarkers[i - 1] + else + return sortedMarkers[#sortedMarkers] + end + end + end + return markerId end function ADGraphManager:getSortedMarkers() - local useFolders = AutoDrive.getSetting("useFolders") + local useFolders = AutoDrive.getSetting("useFolders") local groups = {} - local groupsToSortedIndex = {} + local groupsToSortedIndex = {} if useFolders then groups, groupsToSortedIndex = self:sortGroups(groups) end if #groups == 0 then groups[1] = {} - groupsToSortedIndex[1] = "All" + groupsToSortedIndex[1] = "All" end for markerID, marker in pairs(self:getMapMarkers()) do @@ -1674,7 +1795,7 @@ function ADGraphManager:getSortedMarkers() end end - local sort_func = function(a, b) + local sort_func = function(a, b) a = tostring(a.displayName):lower() b = tostring(b.displayName):lower() local patt = "^(.-)%s*(%d+)$" @@ -1686,24 +1807,23 @@ function ADGraphManager:getSortedMarkers() return a < b end - for groupId, _ in pairs(groups) do - table.sort(groups[groupId], sort_func) - end - - local allInOneTable = {} - for groupId, entries in pairs(groups) do - for _, marker in pairs(entries) do - allInOneTable[#allInOneTable+1] = marker.returnValue - end - end + for groupId, _ in pairs(groups) do + table.sort(groups[groupId], sort_func) + end + local allInOneTable = {} + for groupId, entries in pairs(groups) do + for _, marker in pairs(entries) do + allInOneTable[#allInOneTable + 1] = marker.returnValue + end + end - return allInOneTable + return allInOneTable end function ADGraphManager:sortGroups(groups) groups = {} - groups[1] = {} + groups[1] = {} local sort_func = function(a, b) a = tostring(a):lower() @@ -1723,12 +1843,12 @@ function ADGraphManager:sortGroups(groups) end table.sort(groupTable, sort_func) - local groupsToSortedIndex = {} - groupsToSortedIndex[1] = "All" - for i=1,#groupTable do - groups[#groups + 1] = {} - groupsToSortedIndex[groupTable[i]] = i + 1 - end - - return groups, groupsToSortedIndex -end \ No newline at end of file + local groupsToSortedIndex = {} + groupsToSortedIndex[1] = "All" + for i = 1, #groupTable do + groups[#groups + 1] = {} + groupsToSortedIndex[groupTable[i]] = i + 1 + end + + return groups, groupsToSortedIndex +end diff --git a/scripts/Manager/HarvestManager.lua b/scripts/Manager/HarvestManager.lua index c9dc9fa3..f5249885 100644 --- a/scripts/Manager/HarvestManager.lua +++ b/scripts/Manager/HarvestManager.lua @@ -16,7 +16,8 @@ function ADHarvestManager:registerHarvester(harvester) if not table.contains(self.idleHarvesters, harvester) and not table.contains(self.harvesters, harvester) then AutoDrive.debugPrint(harvester, AutoDrive.DC_COMBINEINFO, "ADHarvestManager:registerHarvester - inserted") if harvester ~= nil and harvester.ad ~= nil then - harvester.ad.isCombine = true + local rootVehicle = harvester:getRootVehicle() + rootVehicle.ad.isRegisterdHarvester = true end if g_server ~= nil then table.insert(self.idleHarvesters, harvester) @@ -27,7 +28,8 @@ end function ADHarvestManager:unregisterHarvester(harvester) AutoDrive.debugPrint(harvester, AutoDrive.DC_COMBINEINFO, "ADHarvestManager:unregisterHarvester") if harvester ~= nil and harvester.ad ~= nil then - harvester.ad.isCombine = false + local rootVehicle = harvester:getRootVehicle() + rootVehicle.ad.isRegisterdHarvester = false end if g_server ~= nil then if table.contains(self.idleHarvesters, harvester) then @@ -97,7 +99,7 @@ function ADHarvestManager:update(dt) if vehicle.isTrailedHarvester then vehicle = vehicle.trailingVehicle end - if (vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive()) or (AutoDrive:getIsEntered(vehicle) and AutoDrive.isPipeOut(vehicle)) then + if (vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive()) or (AutoDrive:getIsEntered(vehicle:getRootVehicle()) and AutoDrive.isPipeOut(vehicle)) then table.insert(self.harvesters, idleHarvester) table.removeValue(self.idleHarvesters, idleHarvester) end @@ -107,7 +109,7 @@ function ADHarvestManager:update(dt) if vehicle.isTrailedHarvester then vehicle = vehicle.trailingVehicle end - if not ((vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive()) or (AutoDrive:getIsEntered(vehicle) and AutoDrive.isPipeOut(vehicle))) then + if not ((vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive()) or (AutoDrive:getIsEntered(vehicle:getRootVehicle()) and AutoDrive.isPipeOut(vehicle))) then table.insert(self.idleHarvesters, harvester) table.removeValue(self.harvesters, harvester) @@ -229,7 +231,7 @@ function ADHarvestManager.doesHarvesterNeedUnloading(harvester, ignorePipe) end function ADHarvestManager.isHarvesterActive(harvester) - if AutoDrive.getIsBufferCombine(harvester) then + if harvester.ad.isChopper then return true else local fillLevel, fillCapacity, _, fillFreeCapacity = AutoDrive.getObjectFillLevels(harvester) @@ -240,7 +242,7 @@ function ADHarvestManager.isHarvesterActive(harvester) -- Only chase the rear on low fill levels of the combine. This should prevent getting into unneccessarily tight spots for the final approach to the pipe. -- Also for small fields, there is often no purpose in chasing so far behind the combine as it will already start a turn soon local allowedToChase = true - if not AutoDrive.isSugarcaneHarvester(harvester) then + if not harvester.ad.isSugarcaneHarvester then local chasingRear = false local pipeSide = AutoDrive.getPipeSide(harvester) if pipeSide == AutoDrive.CHASEPOS_LEFT then @@ -258,7 +260,7 @@ function ADHarvestManager.isHarvesterActive(harvester) end end - local manuallyControlled = AutoDrive:getIsEntered(harvester) and (not (harvester.getIsAIActive ~= nil and harvester:getIsAIActive())) + local manuallyControlled = AutoDrive:getIsEntered(harvester:getRootVehicle()) and (not (harvester.getIsAIActive ~= nil and harvester:getIsAIActive())) if manuallyControlled then return AutoDrive.isPipeOut(harvester) diff --git a/scripts/Manager/InputManager.lua b/scripts/Manager/InputManager.lua index 8abec1a9..ff762d8a 100644 --- a/scripts/Manager/InputManager.lua +++ b/scripts/Manager/InputManager.lua @@ -191,7 +191,7 @@ function ADInputManager:input_toggleConnection(vehicle) local closestWayPoint, _ = vehicle:getClosestWayPoint() if ADGraphManager:getWayPointById(closestWayPoint) ~= nil then if vehicle.ad.stateModule:getSelectedNeighbourPoint() ~= nil then - ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(closestWayPoint), vehicle.ad.stateModule:getSelectedNeighbourPoint(), false) + ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(closestWayPoint), vehicle.ad.stateModule:getSelectedNeighbourPoint(), false, false) end end end @@ -202,7 +202,7 @@ function ADInputManager:input_toggleConnectionInverted(vehicle) local closestWayPoint, _ = vehicle:getClosestWayPoint() if ADGraphManager:getWayPointById(closestWayPoint) ~= nil then if vehicle.ad.stateModule:getSelectedNeighbourPoint() ~= nil then - ADGraphManager:toggleConnectionBetween(vehicle.ad.stateModule:getSelectedNeighbourPoint(), ADGraphManager:getWayPointById(closestWayPoint), false) + ADGraphManager:toggleConnectionBetween(vehicle.ad.stateModule:getSelectedNeighbourPoint(), ADGraphManager:getWayPointById(closestWayPoint), false, false) end end end @@ -269,7 +269,7 @@ function ADInputManager:input_start_stop(vehicle, farmId) vehicle.ad.stateModule:setActualFarmId(farmId) -- input_start_stop end - vehicle.ad.stateModule:getCurrentMode():start() + vehicle.ad.stateModule:getCurrentMode():start(AutoDrive.USER_PLAYER) if AutoDrive.rightSHIFTmodifierKeyPressed then for _, otherVehicle in pairs(g_currentMission.vehicles) do @@ -278,7 +278,7 @@ function ADInputManager:input_start_stop(vehicle, farmId) if otherVehicle.ad.stateModule.activeBeforeSave then -- g_currentMission:requestToEnterVehicle(otherVehicle) - otherVehicle.ad.stateModule:getCurrentMode():start() + otherVehicle.ad.stateModule:getCurrentMode():start(AutoDrive.USER_PLAYER) end if otherVehicle.ad.stateModule.AIVEActiveBeforeSave and otherVehicle.acParameters ~= nil then -- g_currentMission:requestToEnterVehicle(otherVehicle) @@ -296,11 +296,11 @@ function ADInputManager:input_start_stop(vehicle, farmId) end function ADInputManager:input_incLoopCounter(vehicle) - vehicle.ad.stateModule:increaseLoopCounter() + vehicle.ad.stateModule:changeLoopCounter(true) end function ADInputManager:input_decLoopCounter(vehicle) - vehicle.ad.stateModule:decreaseLoopCounter() + vehicle.ad.stateModule:changeLoopCounter(false) end function ADInputManager:input_setParkDestination(vehicle) @@ -388,7 +388,7 @@ function ADInputManager:input_nextTarget(vehicle) local currentTarget = vehicle.ad.stateModule:getFirstMarkerId() local nextTarget = ADGraphManager:getNextTargetAlphabetically(currentTarget) vehicle.ad.stateModule:setFirstMarker(nextTarget) - if not (vehicle.spec_combine or AutoDrive.getIsBufferCombine(vehicle) or vehicle.ad.isCombine ~= nil) then + if not vehicle.ad.hasCombine then -- not stop / change CP for harvesters AutoDrive:StopCP(vehicle) end @@ -400,7 +400,7 @@ function ADInputManager:input_previousTarget(vehicle) local currentTarget = vehicle.ad.stateModule:getFirstMarkerId() local previousTarget = ADGraphManager:getPreviousTargetAlphabetically(currentTarget) vehicle.ad.stateModule:setFirstMarker(previousTarget) - if not (vehicle.spec_combine or AutoDrive.getIsBufferCombine(vehicle) or vehicle.ad.isCombine ~= nil) then + if not vehicle.ad.hasCombine then -- not stop / change CP for harvesters AutoDrive:StopCP(vehicle) end @@ -436,9 +436,9 @@ function ADInputManager:input_continue(vehicle) end function ADInputManager:input_callDriver(vehicle) - if vehicle.spec_pipe ~= nil and vehicle.spec_enterable ~= nil then + if vehicle.spec_combine ~= nil and vehicle.spec_pipe ~= nil and vehicle.spec_enterable ~= nil then ADHarvestManager:assignUnloaderToHarvester(vehicle) - elseif vehicle.ad.isCombine and vehicle.ad.attachableCombine ~= nil then + elseif vehicle.ad.attachableCombine ~= nil then ADHarvestManager:assignUnloaderToHarvester(vehicle.ad.attachableCombine) end end @@ -464,7 +464,7 @@ function ADInputManager:input_swapTargets(vehicle) local currentFirstMarker = vehicle.ad.stateModule:getFirstMarkerId() vehicle.ad.stateModule:setFirstMarker(vehicle.ad.stateModule:getSecondMarkerId()) vehicle.ad.stateModule:setSecondMarker(currentFirstMarker) - if not (vehicle.spec_combine or AutoDrive.getIsBufferCombine(vehicle) or vehicle.ad.isCombine ~= nil) then + if not vehicle.ad.hasCombine then -- not stop / change CP for harvesters AutoDrive:StopCP(vehicle) end diff --git a/scripts/Modes/CombineUnloaderMode.lua b/scripts/Modes/CombineUnloaderMode.lua index fca772bd..e90529bb 100644 --- a/scripts/Modes/CombineUnloaderMode.lua +++ b/scripts/Modes/CombineUnloaderMode.lua @@ -1,17 +1,17 @@ CombineUnloaderMode = ADInheritsFrom(AbstractMode) -CombineUnloaderMode.STATE_INIT = 1 -CombineUnloaderMode.STATE_WAIT_TO_BE_CALLED = 2 -CombineUnloaderMode.STATE_DRIVE_TO_COMBINE = 3 -CombineUnloaderMode.STATE_DRIVE_TO_PIPE = 4 -CombineUnloaderMode.STATE_LEAVE_CROP = 5 -CombineUnloaderMode.STATE_DRIVE_TO_START = 6 -CombineUnloaderMode.STATE_DRIVE_TO_UNLOAD = 7 -CombineUnloaderMode.STATE_FOLLOW_COMBINE = 8 -CombineUnloaderMode.STATE_ACTIVE_UNLOAD_COMBINE = 9 -CombineUnloaderMode.STATE_FOLLOW_CURRENT_UNLOADER = 10 -CombineUnloaderMode.STATE_EXIT_FIELD = 11 -CombineUnloaderMode.STATE_REVERSE_FROM_BAD_LOCATION = 12 +CombineUnloaderMode.STATE_INIT = {} +CombineUnloaderMode.STATE_WAIT_TO_BE_CALLED = {} +CombineUnloaderMode.STATE_DRIVE_TO_COMBINE = {} +CombineUnloaderMode.STATE_DRIVE_TO_PIPE = {} +CombineUnloaderMode.STATE_LEAVE_CROP = {} +CombineUnloaderMode.STATE_DRIVE_TO_START = {} +CombineUnloaderMode.STATE_DRIVE_TO_UNLOAD = {} +CombineUnloaderMode.STATE_FOLLOW_COMBINE = {} +CombineUnloaderMode.STATE_ACTIVE_UNLOAD_COMBINE = {} +CombineUnloaderMode.STATE_FOLLOW_CURRENT_UNLOADER = {} +CombineUnloaderMode.STATE_EXIT_FIELD = {} +CombineUnloaderMode.STATE_REVERSE_FROM_BAD_LOCATION = {} CombineUnloaderMode.MAX_COMBINE_FILLLEVEL_CHASING = 101 CombineUnloaderMode.STATIC_X_OFFSET_FROM_HEADER = 0 @@ -23,6 +23,7 @@ function CombineUnloaderMode:new(vehicle) o.trailerCount = 0 o.tractorTrainLength = 0 CombineUnloaderMode.reset(o) + CombineUnloaderMode.setStateNames(o) return o end @@ -41,8 +42,8 @@ function CombineUnloaderMode:reset() AutoDrive.getAllDischargeableUnits(self.vehicle, true) -- force initialisation end -function CombineUnloaderMode:start() - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:start start self.state %s", tostring(self.state)) +function CombineUnloaderMode:start(user) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:start start self.state %s", tostring(self:getStateName())) if not self.vehicle.ad.stateModule:isActive() then self.vehicle:startAutoDrive() end @@ -57,7 +58,7 @@ function CombineUnloaderMode:start() if self.activeTask ~= nil then self.vehicle.ad.taskModule:addTask(self.activeTask) end - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:start end self.state %s", tostring(self.state)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:start end self.state %s", tostring(self:getStateName())) end function CombineUnloaderMode:monitorTasks(dt) @@ -140,7 +141,7 @@ function CombineUnloaderMode:handleFinishedTask() if self.activeTask ~= nil then self.vehicle.ad.taskModule:addTask(self.activeTask) end - AutoDrive.debugPrint(vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:handleFinishedTask self.state %s", tostring(self.state)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:handleFinishedTask self.state %s", tostring(self:getStateName())) end function CombineUnloaderMode:stop() @@ -165,7 +166,7 @@ function CombineUnloaderMode:continue() AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:continue self.STATE_DRIVE_TO_UNLOAD") self.activeTask:continue() else - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:continue self.state" .. tostring(self.state)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:continue self.state" .. tostring(self:getStateName())) self.vehicle.ad.taskModule:abortCurrentTask() if AutoDrive.checkIsOnField(x, y, z) and distanceToStart > 30 then @@ -193,7 +194,7 @@ function CombineUnloaderMode:continue() end function CombineUnloaderMode:getNextTask() - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask start self.state %s", tostring(self.state)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask start self.state %s", tostring(self:getStateName())) local nextTask local x, y, z = getWorldTranslation(self.vehicle.components[1].node) @@ -223,7 +224,7 @@ function CombineUnloaderMode:getNextTask() self:setToWaitForCall() end end - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask - STATE_INIT end self.state %s", tostring(self.state)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask - STATE_INIT end self.state %s", tostring(self:getStateName())) elseif self.state == self.STATE_DRIVE_TO_COMBINE then AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask - STATE_DRIVE_TO_COMBINE") -- we finished the precall to combine route @@ -278,7 +279,7 @@ function CombineUnloaderMode:getNextTask() self.state = self.STATE_DRIVE_TO_UNLOAD end - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask end self.state %s", tostring(self.state)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getNextTask end self.state %s", tostring(self:getStateName())) return nextTask end @@ -290,7 +291,7 @@ function CombineUnloaderMode:setToWaitForCall(keepCombine) if self.combine ~= nil and self.combine.ad ~= nil and (keepCombine == nil or keepCombine ~= true) then self.combine = nil end - AutoDrive.debugPrint(vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:setToWaitForCall end self.state %s self.combine %s", tostring(self.state), tostring(self.combine)) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:setToWaitForCall end self.state %s self.combine %s", tostring(self:getStateName()), tostring(self.combine)) end function CombineUnloaderMode:assignToHarvester(harvester) @@ -303,10 +304,11 @@ function CombineUnloaderMode:assignToHarvester(harvester) local cfillLevel, cfillCapacity, _, cleftCapacity = AutoDrive.getObjectFillLevels(self.combine) local cFillRatio = cfillCapacity > 0 and cfillLevel / cfillCapacity or 0 - local cpIsCalling = AutoDrive:getIsCPWaitingForUnload(harvester) - if (self.combine.spec_combine == nil or not AutoDrive.getIsBufferCombine(self.combine)) and (self.combine.ad.noMovementTimer.elapsedTime > 500 or cleftCapacity < 0.1 or cpIsCalling or cFillRatio > 0.945) then + if (self.combine.ad.isHarvester) + and (self.combine.ad.noMovementTimer.elapsedTime > 500 or cleftCapacity < 0.1 or cpIsCalling or cFillRatio > 0.945) + then -- default unloading - no movement self.state = self.STATE_DRIVE_TO_PIPE self.vehicle.ad.taskModule:addTask(EmptyHarvesterTask:new(self.vehicle, self.combine)) @@ -366,7 +368,7 @@ function CombineUnloaderMode:getTaskAfterUnload(filledToUnload) end else -- Should we park in the field? - if AutoDrive.getIsBufferCombine(self.combine) or (AutoDrive.getSetting("parkInField", self.vehicle) or (self.lastTask ~= nil and self.lastTask.stayOnField)) then + if (self.combine and self.combine.ad.isChopper) or (AutoDrive.getSetting("parkInField", self.vehicle) or (self.lastTask ~= nil and self.lastTask.stayOnField)) then -- If we are in fruit, we should clear it if AutoDrive.isVehicleOrTrailerInCrop(self.vehicle, true) then AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getTaskAfterUnload ClearCropTask...") @@ -497,10 +499,10 @@ function CombineUnloaderMode:getSideChaseOffsetX() -- So, choose the max between the two to avoid a collison local sideChaseTermX = math.max(sideChaseTermPipeIn, sideChaseTermPipeOut) - if AutoDrive.isSugarcaneHarvester(self.combine) then + if self.combine.ad.isSugarcaneHarvester then -- check for SugarcaneHarvester has to be first, as it also is IsBufferCombine! sideChaseTermX = AutoDrive.getPipeLength(self.combine) - elseif AutoDrive.getIsBufferCombine(self.combine) then + elseif self.combine.ad.isAutoAimingChopper then sideChaseTermX = sideChaseTermPipeIn + CombineUnloaderMode.STATIC_X_OFFSET_FROM_HEADER elseif (self.combine.ad ~= nil and self.combine.ad.storedPipeLength ~= nil) or AutoDrive.isPipeOut(self.combine) then -- If the pipe is extended, though, target it regardless @@ -524,10 +526,10 @@ function CombineUnloaderMode:getSideChaseOffsetX_new() -- So, choose the max between the two to avoid a collison local sideChaseTermX = 0 - if AutoDrive.isSugarcaneHarvester(self.combine) then + if self.combine.ad.isSugarcaneHarvester then -- check for SugarcaneHarvester has to be first, as it also is IsBufferCombine! sideChaseTermX = AutoDrive.getPipeLength(self.combine) - elseif AutoDrive.getIsBufferCombine(self.combine) then + elseif self.combine.ad.isAutoAimingChopper then sideChaseTermX = sideChaseTermPipeIn + CombineUnloaderMode.STATIC_X_OFFSET_FROM_HEADER elseif (self.combine.ad ~= nil and self.combine.ad.storedPipeLength ~= nil) or AutoDrive.isPipeOut(self.combine) then -- If the pipe is extended, though, target it regardless @@ -645,7 +647,7 @@ end function CombineUnloaderMode:getRearChaseOffsetX(leftBlocked, rightBlocked) local rearChaseOffset = (self.combine.size.width / 2 + self.vehicle.size.width / 2) + 1 - if AutoDrive.getIsBufferCombine(self.combine) and not AutoDrive.isSugarcaneHarvester(self.combine) then + if self.combine.ad.isAutoAimingChopper and not self.combine.ad.isSugarcaneHarvester then return 0 elseif rightBlocked and leftBlocked then return 0 @@ -659,14 +661,14 @@ end function CombineUnloaderMode:getRearChaseOffsetZ() local followDistance = AutoDrive.getSetting("followDistance", self.vehicle) local rearChaseOffset = -followDistance - (self.combine.size.length / 2) - if AutoDrive.getIsBufferCombine(self.combine) and not AutoDrive.isSugarcaneHarvester(self.combine) then + if self.combine.ad.isAutoAimingChopper and not self.combine.ad.isSugarcaneHarvester then rearChaseOffset = -followDistance - (self.combine.size.length / 2) else -- math.sqrt(2) ensures the trailer could straighten if it was turned 90 degrees, and it makes this point further -- back than the pathfinder (straightening) target in PathFinderModule:startPathPlanningToPipe -- math.sqrt(2) gives the hypotenuse of an isosceles right trangle with side length equal to the length -- of the trailer - if AutoDrive.isSugarcaneHarvester(self.combine) then + if self.combine.ad.isSugarcaneHarvester then rearChaseOffset = -self.combine.size.length / 2 - self.tractorTrainLength * math.sqrt(2) else if self.combine.lastSpeedReal > 0.002 and self.combine.ad.sensors.frontSensorFruit:pollInfo() then @@ -710,11 +712,11 @@ function CombineUnloaderMode:getPipeChasePosition(planningPhase) self.targetFillUnit, self.targetFillNode = AutoDrive.getNextFreeDischargeableUnit(self.vehicle) local sideChaseTermX = self:getSideChaseOffsetX() - local sideChaseTermZ = self:getSideChaseOffsetZ(AutoDrive.dynamicChaseDistance or not AutoDrive.getIsBufferCombine(self.combine)) + local sideChaseTermZ = self:getSideChaseOffsetZ(AutoDrive.dynamicChaseDistance or self.combine.ad.isHarvester) local rearChaseTermZ = self:getRearChaseOffsetZ() - if AutoDrive.getIsBufferCombine(self.combine) then - -- chopper + if self.combine.ad.isChopper then + -- any chopper --AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getPipeChasePosition=IsBufferCombine") local leftChasePos = AutoDrive.createWayPointRelativeToVehicle(self.combine, sideChaseTermX + self:getPipeSlopeCorrection(), sideChaseTermZ - 2) local rightChasePos = AutoDrive.createWayPointRelativeToVehicle(self.combine, -(sideChaseTermX + self:getPipeSlopeCorrection()), sideChaseTermZ - 2) @@ -731,7 +733,13 @@ function CombineUnloaderMode:getPipeChasePosition(planningPhase) chaseNode = rightChasePos sideIndex = AutoDrive.CHASEPOS_RIGHT end - if AutoDrive:getIsCPActive(self.combine) and AutoDrive.combineIsTurning(self.combine) then + -- following order is important! + if self.combine.ad.isFixedPipeChopper then + -- chopper with fixed unloading + local sideOffsetZ = self:getDynamicSideChaseOffsetZ_fromDischargeNode(planningPhase) + chaseNode = self:getPipeChaseWayPoint(0, sideOffsetZ) + sideIndex = self.pipeSide + elseif AutoDrive:getIsCPActive(self.combine) and AutoDrive.combineIsTurning(self.combine) then chaseNode = rearChasePos sideIndex = AutoDrive.CHASEPOS_REAR elseif (not leftBlocked) and ((self:isUnloaderOnCorrectSide(AutoDrive.CHASEPOS_LEFT) and angleToLeftChaseSide < angleToRearChaseSide) or planningPhase) then @@ -740,11 +748,12 @@ function CombineUnloaderMode:getPipeChasePosition(planningPhase) elseif (not rightBlocked) and (self:isUnloaderOnCorrectSide(AutoDrive.CHASEPOS_RIGHT) or planningPhase) then chaseNode = rightChasePos sideIndex = AutoDrive.CHASEPOS_RIGHT - elseif not AutoDrive.isSugarcaneHarvester(self.combine) then + elseif not self.combine.ad.isSugarcaneHarvester then chaseNode = rearChasePos sideIndex = AutoDrive.CHASEPOS_REAR end else + -- harveser with bunker --AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CombineUnloaderMode:getPipeChasePosition:IsNormalCombine") local rearChaseTermX = self:getRearChaseOffsetX(leftBlocked, rightBlocked) @@ -839,6 +848,28 @@ function CombineUnloaderMode:unregisterFollowingUnloader() self.followingUnloader = nil end +function CombineUnloaderMode:setStateNames() + if self.statesToNames == nil then + self.statesToNames = {} + for name, id in pairs(CombineUnloaderMode) do + if string.sub(name, 1, 6) == "STATE_" then + self.statesToNames[id] = name + end + end + end +end + +function CombineUnloaderMode:getStateName(state) + local requestedState = state + if requestedState == nil then + requestedState = self.state + end + if requestedState == nil then + Logging.error("[AD] CombineUnloaderMode: Could not find name for state ->%s<- !", tostring(requestedState)) + end + return self.statesToNames[requestedState] or "" +end + function CombineUnloaderMode.debugMsg(vehicle, debugText, ...) if CombineUnloaderMode.debug == true then AutoDrive.debugMsg(vehicle, debugText, ...) diff --git a/scripts/Modes/DriveToMode.lua b/scripts/Modes/DriveToMode.lua index 22928cd7..7d8ddb21 100644 --- a/scripts/Modes/DriveToMode.lua +++ b/scripts/Modes/DriveToMode.lua @@ -13,7 +13,7 @@ function DriveToMode:reset() self.vehicle.ad.trailerModule:reset() end -function DriveToMode:start() +function DriveToMode:start(user) AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_VEHICLEINFO, "DriveToMode:start self.vehicle.ad.onRouteToRefuel %s", tostring(self.vehicle.ad.onRouteToRefuel)) if not self.vehicle.ad.stateModule:isActive() then self.vehicle:startAutoDrive() diff --git a/scripts/Modes/LoadMode.lua b/scripts/Modes/LoadMode.lua index 763dc6fe..e9f39a8b 100644 --- a/scripts/Modes/LoadMode.lua +++ b/scripts/Modes/LoadMode.lua @@ -21,7 +21,7 @@ function LoadMode:reset() self.vehicle.ad.trailerModule:reset() end -function LoadMode:start() +function LoadMode:start(user) AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_PATHINFO, "LoadMode:start start self.state %s", tostring(self.state)) if not self.vehicle.ad.stateModule:isActive() then self.vehicle:startAutoDrive() diff --git a/scripts/Modes/PickupAndDeliverMode.lua b/scripts/Modes/PickupAndDeliverMode.lua index 5ad2ce87..89632306 100644 --- a/scripts/Modes/PickupAndDeliverMode.lua +++ b/scripts/Modes/PickupAndDeliverMode.lua @@ -27,7 +27,7 @@ function PickupAndDeliverMode:reset() self.vehicle.ad.trailerModule:reset() end -function PickupAndDeliverMode:start() +function PickupAndDeliverMode:start(user) AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_PATHINFO, "PickupAndDeliverMode:start start self.state %s", tostring(self.state)) if not self.vehicle.ad.stateModule:isActive() then @@ -39,7 +39,8 @@ function PickupAndDeliverMode:start() end self:reset() - self.activeTask = self:getNextTask() + local forced = not (user == AutoDrive.USER_PLAYER) -- force target delivery change if not started by player, i.e. CP + self.activeTask = self:getNextTask(forced) if self.activeTask ~= nil then self.vehicle.ad.taskModule:addTask(self.activeTask) end diff --git a/scripts/Modes/UnloadAtMode.lua b/scripts/Modes/UnloadAtMode.lua index e4972ff5..c70547f3 100644 --- a/scripts/Modes/UnloadAtMode.lua +++ b/scripts/Modes/UnloadAtMode.lua @@ -18,7 +18,7 @@ function UnloadAtMode:reset() self.vehicle.ad.trailerModule:reset() end -function UnloadAtMode:start() +function UnloadAtMode:start(user) if not self.vehicle.ad.stateModule:isActive() then self.vehicle:startAutoDrive() end diff --git a/scripts/Modules/CollisionDetectionModule.lua b/scripts/Modules/CollisionDetectionModule.lua index dda4dd1d..7439dfeb 100644 --- a/scripts/Modules/CollisionDetectionModule.lua +++ b/scripts/Modules/CollisionDetectionModule.lua @@ -24,12 +24,10 @@ function ADCollisionDetectionModule:update(dt) end function ADCollisionDetectionModule:detectObstacle() - local box = self.vehicle.ad.sensors.frontSensorDynamic:getBoxShape() - if AutoDrive.getSetting("enableTrafficDetection") >= 1 then - if self.vehicle.ad.sensors.frontSensorDynamic:pollInfo() then + if self.vehicle.ad.sensors.frontSensorDynamicShort:pollInfo() then local frontSensorDynamicInBunkerArea = false - local sensorLocation = self.vehicle.ad.sensors.frontSensorDynamic:getLocationByPosition() + local sensorLocation = self.vehicle.ad.sensors.frontSensorDynamicShort:getLocationByPosition() local vehX, vehY, vehZ = getWorldTranslation(self.vehicle.components[1].node) local worldOffsetX, worldOffsetY, worldOffsetZ = localDirectionToWorld(self.vehicle.components[1].node, sensorLocation.x, 0, sensorLocation.z) for _, trigger in pairs(ADTriggerManager.getUnloadTriggers()) do @@ -52,6 +50,7 @@ function ADCollisionDetectionModule:detectObstacle() if ((g_updateLoopIndex + self.vehicle.id) % AutoDrive.PERF_FRAMES == 0) then local excludedList = self.vehicle.ad.taskModule:getActiveTask():getExcludedVehiclesForCollisionCheck() + local box = self.vehicle.ad.sensors.frontSensorDynamicLong:getBoxShape() local boundingBox = {} boundingBox[1] = box.topLeft boundingBox[2] = box.topRight @@ -70,28 +69,36 @@ function ADCollisionDetectionModule:detectAdTrafficOnRoute() self.trafficVehicle = nil local idToCheck = 3 local alreadyOnDualRoute = false + local lastDualId = nil if wayPoints[currentWayPoint - 1] ~= nil and wayPoints[currentWayPoint] ~= nil then alreadyOnDualRoute = ADGraphManager:isDualRoad(wayPoints[currentWayPoint - 1], wayPoints[currentWayPoint]) end if wayPoints[currentWayPoint + idToCheck] ~= nil and wayPoints[currentWayPoint + idToCheck + 1] ~= nil and not alreadyOnDualRoute then - local dualRoute = ADGraphManager:isDualRoad(wayPoints[currentWayPoint + idToCheck], wayPoints[currentWayPoint + idToCheck + 1]) local dualRoutePoints = {} idToCheck = 0 - while (dualRoute == true) or (idToCheck < 8) do + local foundDualRoute = false + local continueSearch = true + while (continueSearch == true) do local startNode = wayPoints[currentWayPoint + idToCheck] local targetNode = wayPoints[currentWayPoint + idToCheck + 1] if (startNode ~= nil) and (targetNode ~= nil) then local testDual = ADGraphManager:isDualRoad(startNode, targetNode) if testDual == true then table.insert(dualRoutePoints, startNode.id) - dualRoute = true + lastDualId = targetNode.id + continueSearch = true + foundDualRoute = true + elseif foundDualRoute == true then + -- dual section ended - exit + continueSearch = false else - dualRoute = false + -- check min 7 WP ahead even if not dual + continueSearch = idToCheck < 8 end else - dualRoute = false + continueSearch = false end idToCheck = idToCheck + 1 end @@ -110,6 +117,13 @@ function ADCollisionDetectionModule:detectAdTrafficOnRoute() if point == otherWayPoints[otherCurrentWayPoint + i].id then onSameRoute = true --check if going in same direction + if #dualRoutePoints == 1 then + if lastDualId ~= nil and otherWayPoints[otherCurrentWayPoint + i + 1] ~= nil then + if lastDualId == otherWayPoints[otherCurrentWayPoint + i + 1].id then + sameDirection = true + end + end + end if dualRoutePoints[_ + 1] ~= nil and otherWayPoints[otherCurrentWayPoint + i + 1] ~= nil then if dualRoutePoints[_ + 1] == otherWayPoints[otherCurrentWayPoint + i + 1].id then sameDirection = true diff --git a/scripts/Modules/DrivePathModule.lua b/scripts/Modules/DrivePathModule.lua index ef47a3a3..de5cd0b2 100644 --- a/scripts/Modules/DrivePathModule.lua +++ b/scripts/Modules/DrivePathModule.lua @@ -269,12 +269,12 @@ function ADDrivePathModule:followWaypoints(dt) self.speedLimit = math.min(self.vehicle.ad.trailerModule:getBunkerSiloSpeed(), self.speedLimit) maxSpeedDiff = 1 else - if self.distanceToTarget < (AutoDrive.MAX_BUNKERSILO_LENGTH + AutoDrive.getSetting("maxTriggerDistance")) and AutoDrive.isVehicleInBunkerSiloArea(self.vehicle) then + if self.distanceToTarget < (AutoDrive.MAX_BUNKERSILO_LENGTH + AutoDrive.getMaxTriggerDistance(self.vehicle)) and AutoDrive.isVehicleInBunkerSiloArea(self.vehicle) then -- vehicle enters drive through bunker silo self.speedLimit = math.min(12, self.speedLimit) maxSpeedDiff = 3 else - local isInRangeToLoadUnloadTarget = AutoDrive.isInRangeToLoadUnloadTarget(self.vehicle) and self.distanceToTarget <= AutoDrive.getSetting("maxTriggerDistance") + local isInRangeToLoadUnloadTarget = AutoDrive.isInRangeToLoadUnloadTarget(self.vehicle) and self.distanceToTarget <= AutoDrive.getMaxTriggerDistance(self.vehicle) if isInRangeToLoadUnloadTarget == true then self.speedLimit = math.min(5, self.speedLimit) end diff --git a/scripts/Modules/PathFinderModule.lua b/scripts/Modules/PathFinderModule.lua index 56bab793..232fd50e 100644 --- a/scripts/Modules/PathFinderModule.lua +++ b/scripts/Modules/PathFinderModule.lua @@ -217,14 +217,26 @@ function PathFinderModule:startPathPlanningToPipe(combine, chasing) --else -- self:startPathPlanningTo(target, combineVector) --end - if combine.spec_combine ~= nil and AutoDrive.getIsBufferCombine(combine) then - local pathFinderTarget = {x = pipeChasePos.x - (self.PATHFINDER_TARGET_DISTANCE) * rx, y = worldY, z = pipeChasePos.z - (self.PATHFINDER_TARGET_DISTANCE) * rz} - --local appendTarget = {x = pipeChasePos.x - (lengthOffset/2) * rx, y = worldY, z = pipeChasePos.z - (lengthOffset/2) * rz} + if combine.ad.isAutoAimingChopper then + -- local pathFinderTarget = {x = pipeChasePos.x - (self.PATHFINDER_TARGET_DISTANCE) * rx, y = worldY, z = pipeChasePos.z - (self.PATHFINDER_TARGET_DISTANCE) * rz} + local pathFinderTarget = {x = pipeChasePos.x, y = worldY, z = pipeChasePos.z} + self:startPathPlanningTo(pathFinderTarget, combineVector) + + elseif combine.ad.isFixedPipeChopper then + local pathFinderTarget = {x = pipeChasePos.x, y = worldY, z = pipeChasePos.z} + -- only append target points / try to straighten the driver/trailer combination if we are driving up to the pipe not the rear end + if pipeChaseSide ~= AutoDrive.CHASEPOS_REAR then + pathFinderTarget = {x = pipeChasePos.x - (combine.size.length) * rx, y = worldY, z = pipeChasePos.z - (combine.size.length) * rz} + end + local appendedNode = {x = pipeChasePos.x - (combine.size.length / 2 * rx), y = worldY, z = pipeChasePos.z - (combine.size.length / 2 * rz)} self:startPathPlanningTo(pathFinderTarget, combineVector) - --table.insert(self.appendWayPoints, appendTarget) + if pipeChaseSide ~= AutoDrive.CHASEPOS_REAR then + table.insert(self.appendWayPoints, appendedNode) + end else + -- combine.ad.isHarvester local pathFinderTarget = {x = pipeChasePos.x, y = worldY, z = pipeChasePos.z} -- only append target points / try to straighten the driver/trailer combination if we are driving up to the pipe not the rear end if pipeChaseSide ~= AutoDrive.CHASEPOS_REAR then @@ -240,10 +252,10 @@ function PathFinderModule:startPathPlanningToPipe(combine, chasing) end end - if combine.spec_combine ~= nil then + if combine.spec_combine ~= nil and combine.ad.isHarvester then if combine.spec_combine.fillUnitIndex ~= nil and combine.spec_combine.fillUnitIndex ~= 0 then local fillType = g_fruitTypeManager:getFruitTypeIndexByFillTypeIndex(combine:getFillUnitFillType(combine.spec_combine.fillUnitIndex)) - if fillType ~= nil and (not AutoDrive.getIsBufferCombine(combine)) then + if fillType ~= nil then self.fruitToCheck = fillType local fruitType = g_fruitTypeManager:getFruitTypeByIndex(fillType) @@ -1176,11 +1188,9 @@ function PathFinderModule:drawDebugForPF() pointTarget.y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, pointTarget.x, 1, pointTarget.z) + 3 pointTargetUp.y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, pointTargetUp.x, 1, pointTargetUp.z) + 20 AutoDriveDM:addLineTask(pointTarget.x, pointTarget.y, pointTarget.z, pointTargetUp.x, pointTargetUp.y, pointTargetUp.z, 1, 0, 0, 1) - local pointStart = self:gridLocationToWorldLocation(self.startCell) - local pointStartUp = self:gridLocationToWorldLocation(self.startCell) + local pointStart = {x = self.startX, z = self.startZ} pointStart.y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, pointStart.x, 1, pointStart.z) + 3 - pointStartUp.y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, pointStartUp.x, 1, pointStartUp.z) + 6 - AutoDriveDM:addLineTask(pointTarget.x, pointTarget.y, pointTarget.z, pointTargetUp.x, pointTargetUp.y, pointTargetUp.z, 1, 0, 0, 1) + AutoDriveDM:addLineTask(pointStart.x, pointStart.y, pointStart.z, pointStart.x, pointStart.y + 20, pointStart.z, 1, 0, 1, 0) local color_red = 0.1 local color_green = 0.1 diff --git a/scripts/Modules/RecordingModule.lua b/scripts/Modules/RecordingModule.lua index 8a9f97dc..674f23a4 100644 --- a/scripts/Modules/RecordingModule.lua +++ b/scripts/Modules/RecordingModule.lua @@ -46,10 +46,7 @@ function ADRecordingModule:start(dual, subPrio) if AutoDrive.getSetting("autoConnectStart") then if startNode ~= nil then if ADGraphManager:getDistanceBetweenNodes(startNodeId, self.lastWp.id) < 12 then - ADGraphManager:toggleConnectionBetween(startNode, self.lastWp, self.drivingReverse) - if self.isDual then - ADGraphManager:toggleConnectionBetween(self.lastWp, startNode, self.drivingReverse) - end + ADGraphManager:toggleConnectionBetween(startNode, self.lastWp, self.drivingReverse, self.isDual) end end end @@ -63,10 +60,7 @@ function ADRecordingModule:stop() local targetId = ADGraphManager:findMatchingWayPointForVehicle(self.vehicle) local targetNode = ADGraphManager:getWayPointById(targetId) if targetNode ~= nil then - ADGraphManager:toggleConnectionBetween(self.lastWp, targetNode, false) - if self.isDual then - ADGraphManager:toggleConnectionBetween(targetNode, self.lastWp, false) - end + ADGraphManager:toggleConnectionBetween(self.lastWp, targetNode, false, self.isDual) end end end diff --git a/scripts/Modules/StateModule.lua b/scripts/Modules/StateModule.lua index 2e6e66d9..6808c67b 100644 --- a/scripts/Modules/StateModule.lua +++ b/scripts/Modules/StateModule.lua @@ -201,8 +201,8 @@ function ADStateModule:writeStream(streamId) streamWriteUIntN(streamId, self.fillType, 10) AutoDrive.streamWriteUIntNList(streamId, self.selectedFillTypes, 10) streamWriteBool(streamId, self.loadByFillLevel) - streamWriteUIntN(streamId, self.loopCounter, 4) - streamWriteUIntN(streamId, self.loopsDone, 4) + streamWriteUIntN(streamId, self.loopCounter, 7) + streamWriteUIntN(streamId, self.loopsDone, 7) streamWriteUIntN(streamId, self.speedLimit, 8) streamWriteUIntN(streamId, self.fieldSpeedLimit, 8) streamWriteUIntN(streamId, self.parkDestination + 1, 17) @@ -233,8 +233,8 @@ function ADStateModule:readStream(streamId) self.fillType = streamReadUIntN(streamId, 10) self.selectedFillTypes = AutoDrive.streamReadUIntNList(streamId, 10) self.loadByFillLevel = streamReadBool(streamId) - self.loopCounter = streamReadUIntN(streamId, 4) - self.loopsDone = streamReadUIntN(streamId, 4) + self.loopCounter = streamReadUIntN(streamId, 7) + self.loopsDone = streamReadUIntN(streamId, 7) self.speedLimit = streamReadUIntN(streamId, 8) self.fieldSpeedLimit = streamReadUIntN(streamId, 8) self.parkDestination = streamReadUIntN(streamId, 17) - 1 @@ -267,8 +267,8 @@ function ADStateModule:writeUpdateStream(streamId) streamWriteUIntN(streamId, self.fillType, 10) AutoDrive.streamWriteUIntNList(streamId, self.selectedFillTypes, 10) streamWriteBool(streamId, self.loadByFillLevel) - streamWriteUIntN(streamId, self.loopCounter, 4) - streamWriteUIntN(streamId, self.loopsDone, 4) + streamWriteUIntN(streamId, self.loopCounter, 7) + streamWriteUIntN(streamId, self.loopsDone, 7) streamWriteUIntN(streamId, self.speedLimit, 8) streamWriteUIntN(streamId, self.fieldSpeedLimit, 8) streamWriteUIntN(streamId, self.parkDestination + 1, 17) @@ -299,8 +299,8 @@ function ADStateModule:readUpdateStream(streamId) self.fillType = streamReadUIntN(streamId, 10) self.selectedFillTypes = AutoDrive.streamReadUIntNList(streamId, 10) self.loadByFillLevel = streamReadBool(streamId) - self.loopCounter = streamReadUIntN(streamId, 4) - self.loopsDone = streamReadUIntN(streamId, 4) + self.loopCounter = streamReadUIntN(streamId, 7) + self.loopsDone = streamReadUIntN(streamId, 7) self.speedLimit = streamReadUIntN(streamId, 8) self.fieldSpeedLimit = streamReadUIntN(streamId, 8) self.parkDestination = streamReadUIntN(streamId, 17) - 1 @@ -350,8 +350,8 @@ function ADStateModule:update(dt) end if g_server ~= nil then - if self.vehicle.ad.isCombine or (self:getMode() == AutoDrive.MODE_UNLOAD and self.active) then - if self.vehicle.ad.isCombine then + if self.vehicle.ad.isRegisterdHarvester or (self:getMode() == AutoDrive.MODE_UNLOAD and self.active) then + if self.vehicle.ad.isRegisterdHarvester then if ADHarvestManager:hasHarvesterPotentialUnloaders(self.vehicle) ~= self.harversterPairingOk then self:setHarvesterPairingOk(not self.harversterPairingOk) end @@ -697,17 +697,29 @@ function ADStateModule:getLoopCounter() return self.loopCounter end -function ADStateModule:increaseLoopCounter() - self.loopCounter = (self.loopCounter + 1) % 10 - self:raiseDirtyFlag() -end - -function ADStateModule:decreaseLoopCounter() - if self.loopCounter > 0 then - self.loopCounter = self.loopCounter - 1 +function ADStateModule:changeLoopCounter(increment, fast, wheel) + local newCounter = self.loopCounter + local delta = fast and 10 or 1 + if increment then + newCounter = newCounter + delta + if newCounter >= 100 then + if fast or wheel then + newCounter = 99 + else + newCounter = newCounter % 100 + end + end else - self.loopCounter = 9 + newCounter = newCounter - delta + if newCounter < 0 then + if fast or wheel then + newCounter = 0 + else + newCounter = (newCounter + 100) % 100 + end + end end + self.loopCounter = newCounter self:raiseDirtyFlag() end @@ -858,6 +870,10 @@ function ADStateModule:toggleFillTypeSelection(fillType) end else table.insert(self.selectedFillTypes, fillType) + if not table.contains(self.selectedFillTypes, self.fillType) then + -- selectedFillTypes was empty, select the new fillType + self.fillType = fillType + end end self:raiseDirtyFlag() end @@ -910,7 +926,7 @@ function ADStateModule:selectPreferredFillTypeFromFillLevels(fillLevels) end table.sort(fillLevelList) -- sort it local requiredFillLevel = fillLevelList[#fillLevelList] - local idx = table.indexOf(self.selectedFillTypes, self.fillType) -- starting point + local idx = table.indexOf(self.selectedFillTypes, self.fillType) or 0 -- starting point local loopsLeft = #self.selectedFillTypes local pickNextNonEmpty = requiredFillLevel == -1 or not self.loadByFillLevel if idx == nil or requiredFillLevel == nil then diff --git a/scripts/Modules/TrailerModule.lua b/scripts/Modules/TrailerModule.lua index a1c2f9a1..88512eec 100644 --- a/scripts/Modules/TrailerModule.lua +++ b/scripts/Modules/TrailerModule.lua @@ -448,7 +448,7 @@ end function ADTrailerModule:updateUnload(dt) AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_TRAILERINFO, "ADTrailerModule:updateUnload ") - AutoDrive.setAugerPipeOpen(self.trailers, AutoDrive.getDistanceToUnloadPosition(self.vehicle) <= AutoDrive.getSetting("maxTriggerDistance")) + AutoDrive.setAugerPipeOpen(self.trailers, AutoDrive.getDistanceToUnloadPosition(self.vehicle) <= AutoDrive.getMaxTriggerDistance(self.vehicle)) if not self.isUnloading and not (self.lastUnloadRotateTrigger) then AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_TRAILERINFO, "ADTrailerModule:updateUnload not self.isUnloading") @@ -604,7 +604,7 @@ function ADTrailerModule:lookForPossibleUnloadTrigger(trailer) -- local distanceToTarget = AutoDrive.getDistanceToUnloadPosition(self.vehicle) local distanceToTarget = AutoDrive.getDistanceToUnloadPosition(trailer) - if distanceToTarget < AutoDrive.getSetting("maxTriggerDistance") then + if distanceToTarget < AutoDrive.getMaxTriggerDistance(self.vehicle) then -- silo trigger - found by CanDischargeToObject, no need to loop through all triggers if trailer.getCanDischargeToObject and trailer.getCurrentDischargeNode and trailer.getDischargeState then if trailer:getCanDischargeToObject(trailer:getCurrentDischargeNode()) then diff --git a/scripts/Sensors/CollSensor.lua b/scripts/Sensors/CollSensor.lua index dff2403e..bee46f1b 100644 --- a/scripts/Sensors/CollSensor.lua +++ b/scripts/Sensors/CollSensor.lua @@ -226,7 +226,7 @@ function ADCollSensor:onUpdate(dt) self:setTriggered(self.hit) self.newHit = false - local offsetCompensation = -math.tan(box.rx) * box.size[3] + local offsetCompensation = math.max(-math.tan(box.rx) * box.size[3], 0) box.y = math.max(getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, box.x, 300, box.z), box.y) + offsetCompensation self.collisionHits = overlapBox(box.x, box.y, box.z, box.rx, box.ry, 0, box.size[1], box.size[2], box.size[3], "collisionTestCallback", self, self.mask, true, true, true) --AIVehicleUtil.COLLISION_MASK --16783599 diff --git a/scripts/Sensors/VirtualSensors.lua b/scripts/Sensors/VirtualSensors.lua index 1f2cddef..a689b4c6 100644 --- a/scripts/Sensors/VirtualSensors.lua +++ b/scripts/Sensors/VirtualSensors.lua @@ -44,12 +44,17 @@ function ADSensor:addSensorsToVehicle(vehicle) vehicle.ad.sensors = {} local sensorParameters = {} sensorParameters.dynamicLength = true + sensorParameters.minDynamicLength = 0.2 sensorParameters.position = ADSensor.POS_FRONT sensorParameters.width = vehicle.size.width * 0.75 - local frontSensorDynamic = ADCollSensor:new(vehicle, sensorParameters) - --frontSensorDynamic.drawDebug = true --test - --frontSensorDynamic.enabled = true --test - vehicle.ad.sensors["frontSensorDynamic"] = frontSensorDynamic + local frontSensorDynamicShort = ADCollSensor:new(vehicle, sensorParameters) + --frontSensorDynamicShort.drawDebug = true --test + --frontSensorDynamicShort.enabled = true --test + vehicle.ad.sensors["frontSensorDynamicShort"] = frontSensorDynamicShort + + sensorParameters.minDynamicLength = 2 + local frontSensorDynamicLong = ADCollSensor:new(vehicle, sensorParameters) + vehicle.ad.sensors["frontSensorDynamicLong"] = frontSensorDynamicLong sensorParameters.dynamicLength = false sensorParameters.width = vehicle.size.width * 0.65 @@ -83,6 +88,7 @@ function ADSensor:addSensorsToVehicle(vehicle) sensorParameters = {} sensorParameters.dynamicLength = true + sensorParameters.minDynamicLength = 0.3 sensorParameters.width = vehicle.size.width * 0.75 sensorParameters.position = ADSensor.POS_REAR local rearSensor = ADCollSensor:new(vehicle, sensorParameters) @@ -168,6 +174,7 @@ function ADSensor:loadBaseParameters() local vehicle = self.vehicle if vehicle ~= nil and vehicle.size.length ~= nil and vehicle.size.width ~= nil then self.dynamicLength = true + self.minDynamicLength = 2 self.dynamicRotation = true self.length = vehicle.size.length self.width = vehicle.size.width * ADSensor.WIDTH_FACTOR @@ -188,6 +195,9 @@ function ADSensor:loadDynamicParameters(sensorParameters) if sensorParameters.dynamicLength ~= nil then self.dynamicLength = sensorParameters.dynamicLength == true end + if sensorParameters.minDynamicLength ~= nil then + self.minDynamicLength = sensorParameters.minDynamicLength + end if sensorParameters.dynamicRotation ~= nil then self.dynamicRotation = sensorParameters.dynamicRotation == true end @@ -270,10 +280,7 @@ function ADSensor:getBoxShape() self.location = self:getLocationByPosition() local lookAheadDistance = self.length if self.dynamicLength then - lookAheadDistance = MathUtil.clamp(vehicle.lastSpeedReal * 3600 / 40, 0.13, 1) * 15.5 - if self.position == ADSensor.POS_REAR then - lookAheadDistance = MathUtil.clamp(vehicle.lastSpeedReal * 3600 / 40, 0.02, 1) * 15.5 - end + lookAheadDistance = MathUtil.clamp(vehicle.lastSpeedReal * 3600 * 15.5 / 40, self.minDynamicLength, 16) end local vecZ = {x = 0, z = 1} @@ -287,6 +294,8 @@ function ADSensor:getBoxShape() end local boxYPos = 2 + local boxHeight = 0.75 + if self.position == ADSensor.POS_FRONT_LEFT or self.position == ADSensor.POS_FRONT_RIGHT then boxYPos = 2.25 end @@ -299,33 +308,33 @@ function ADSensor:getBoxShape() box.size = {} box.center = {} box.size[1] = self.width * 0.5 - box.size[2] = 0.75 -- fixed height for now + box.size[2] = boxHeight * 0.5 box.size[3] = lookAheadDistance * 0.5 box.offset[1] = self.location.x - box.offset[2] = boxYPos -- fixed y pos for now + box.offset[2] = boxYPos box.offset[3] = self.location.z - box.center[1] = box.offset[1] + vecZ.x * box.size[3] -- + vecX.x * box.size[1] - box.center[2] = boxYPos -- fixed y pos for now - box.center[3] = box.offset[3] + vecZ.z * box.size[3] -- + vecX.z * box.size[1] + box.center[1] = box.offset[1] + vecZ.x * box.size[3] + box.center[2] = box.offset[2] + box.size[2] + box.center[3] = box.offset[3] + vecZ.z * box.size[3] box.topLeft = {} box.topLeft[1] = box.center[1] - vecX.x * box.size[1] + vecZ.x * box.size[3] - box.topLeft[2] = boxYPos + box.topLeft[2] = box.center[2] box.topLeft[3] = box.center[3] - vecX.z * box.size[1] + vecZ.z * box.size[3] box.topRight = {} box.topRight[1] = box.center[1] + vecX.x * box.size[1] + vecZ.x * box.size[3] - box.topRight[2] = boxYPos + box.topRight[2] = box.center[2] box.topRight[3] = box.center[3] + vecX.z * box.size[1] + vecZ.z * box.size[3] box.downRight = {} box.downRight[1] = box.center[1] + vecX.x * box.size[1] - vecZ.x * box.size[3] - box.downRight[2] = boxYPos + box.downRight[2] = box.center[2] box.downRight[3] = box.center[3] + vecX.z * box.size[1] - vecZ.z * box.size[3] box.downLeft = {} box.downLeft[1] = box.center[1] - vecX.x * box.size[1] - vecZ.x * box.size[3] - box.downLeft[2] = boxYPos + box.downLeft[2] = box.center[2] box.downLeft[3] = box.center[3] - vecX.z * box.size[1] - vecZ.z * box.size[3] if self.sideFactor == -1 then diff --git a/scripts/Settings.lua b/scripts/Settings.lua index 1fcab523..8321816a 100644 --- a/scripts/Settings.lua +++ b/scripts/Settings.lua @@ -740,6 +740,18 @@ AutoDrive.settings.maxTriggerDistance = { isVehicleSpecific = false } +AutoDrive.settings.maxTriggerDistanceVehicle = { + values = {0, 10, 25, 50, 100, 200}, + texts = {"gui_ad_useGlobalSetting", "10 m", "25 m", "50 m", "100 m", "200 m"}, + default = 0, + current = 0, + text = "gui_ad_maxTriggerDistance", + tooltip = "gui_ad_maxTriggerDistance_tooltip", + translate = true, + isVehicleSpecific = true, +} + + AutoDrive.settings.useBeaconLights = { values = {false, true}, texts = {"gui_ad_no", "gui_ad_yes"}, @@ -1024,8 +1036,8 @@ AutoDrive.settings.useHazardLightReverse = { } AutoDrive.settings.scaleLines = { - values = {0.5, 1, 2, 3, 4, 5, 6, 10}, - texts = {"50%", "100%", "200%", "300%", "400%", "500%", "600%", "1000%"}, + values = {0.5, 1, 2, 3, 4, 5, 6, 10, 20, 30, 50, 100}, + texts = {"50%", "100%", "200%", "300%", "400%", "500%", "600%", "1000%", "2000%", "3000%", "5000%", "10000%"}, default = 2, current = 2, text = "gui_ad_scaleLines", @@ -1047,6 +1059,17 @@ AutoDrive.settings.remainingDriveTimeInterval = { isUserSpecific = false } +AutoDrive.settings.BSMRange = { + values = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 400, 500}, + texts = { "gui_ad_off", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100", "120", "140", "160", "180", "200", "250", "300", "400", "500"}, + default = 6, + current = 6, + text = "gui_ad_BSMRange", + tooltip = "gui_ad_BSMRange_tooltip", + translate = true, + isVehicleSpecific = false +} + function AutoDrive.getSetting(settingName, vehicle) if AutoDrive.settings[settingName] ~= nil then local setting = AutoDrive.settings[settingName] @@ -1162,3 +1185,14 @@ function AutoDrive.readVehicleSettingsFromXML(vehicle, xmlFile, key) end end end + +function AutoDrive.getMaxTriggerDistance(vehicle) + -- the max-trigger-distance can be set globally and per-vehicle. + -- a per-vehicle setting of 0 means "use global value" + -- NB: this might not be the best place for this function + local distance = AutoDrive.getSetting("maxTriggerDistanceVehicle", vehicle) + if distance == 0 then + distance = AutoDrive.getSetting("maxTriggerDistance") + end + return distance +end diff --git a/scripts/Specialization.lua b/scripts/Specialization.lua index 936445f8..53ce4e91 100644 --- a/scripts/Specialization.lua +++ b/scripts/Specialization.lua @@ -98,10 +98,9 @@ function AutoDrive:onRegisterActionEvents(_, isOnActiveVehicle) if registerEvents then -- attach our actions local _, eventName - local toggleButton = false local showF1Help = AutoDrive.getSetting("showHelp") for _, action in pairs(ADInputManager.actionsToInputs) do - _, eventName = InputBinding.registerActionEvent(g_inputBinding, action[1], self, ADInputManager.onActionCall, toggleButton, true, false, true) + _, eventName = InputBinding.registerActionEvent(g_inputBinding, action[1], self, ADInputManager.onActionCall, false, true, false, true) if action[5] then g_inputBinding:setActionEventTextVisibility(eventName, action[5] and showF1Help) if showF1Help then @@ -110,6 +109,8 @@ function AutoDrive:onRegisterActionEvents(_, isOnActiveVehicle) g_inputBinding:setActionEventTextPriority(eventName, action[6]) end end + else + g_inputBinding:setActionEventTextVisibility(eventName, false) end end end @@ -262,6 +263,7 @@ function AutoDrive:onPostLoad(savegame) end end + -- sugarcane harvester need special consideration if self.spec_pipe ~= nil and self.spec_enterable ~= nil and self.spec_combine ~= nil then if self.typeName == "combineCutterFruitPreparer" then local _, vehicleFillCapacity, _, _ = AutoDrive.getObjectFillLevels(self) @@ -269,7 +271,9 @@ function AutoDrive:onPostLoad(savegame) end end - if self.spec_pipe ~= nil and self.spec_enterable ~= nil and self.spec_combine ~= nil then + -- harvester types + local isValidHarvester = AutoDrive.setCombineType(self) + if isValidHarvester then ADHarvestManager:registerHarvester(self) end @@ -637,54 +641,62 @@ function AutoDrive.drawTripod(node, offset) end function AutoDrive:onDrawPreviews() - --if AutoDrive:checkForCollisionOnSpline() then local lastHeight = AutoDrive.splineInterpolation.startNode.y local lastWp = AutoDrive.splineInterpolation.startNode + local targetWp = AutoDrive.splineInterpolation.endNode local arrowPosition = ADDrawingManager.arrows.position.middle local collisionFree = AutoDrive:checkForCollisionOnSpline() + local color + local isSubPrio = ADGraphManager:getIsPointSubPrio(lastWp.id) or ADGraphManager:getIsPointSubPrio(targetWp.id) + local isDual = AutoDrive.leftCTRLmodifierKeyPressed and AutoDrive.leftALTmodifierKeyPressed + if not collisionFree then + color = AutoDrive.currentColors.ad_color_previewNotOk + elseif isDual and isSubPrio then + color = AutoDrive.currentColors.ad_color_previewSubPrioDualConnection + elseif isDual then + color = AutoDrive.currentColors.ad_color_previewDualConnection + elseif isSubPrio then + color = AutoDrive.currentColors.ad_color_previewSubPrioSingleConnection + else + color = AutoDrive.currentColors.ad_color_previewSingleConnection + end + for wpId, wp in pairs(AutoDrive.splineInterpolation.waypoints) do if wpId ~= 1 and wpId < (#AutoDrive.splineInterpolation.waypoints - 1) then if math.abs(wp.y - lastHeight) > 1 then -- prevent point dropping into the ground in case of bridges etc wp.y = lastHeight end - if collisionFree then - ADDrawingManager:addLineTask(lastWp.x, lastWp.y, lastWp.z, wp.x, wp.y, wp.z, 1, unpack(AutoDrive.currentColors.ad_color_previewOk)) - ADDrawingManager:addArrowTask(lastWp.x, lastWp.y, lastWp.z, wp.x, wp.y, wp.z, 1, arrowPosition, unpack(AutoDrive.currentColors.ad_color_previewOk)) - else - ADDrawingManager:addLineTask(lastWp.x, lastWp.y, lastWp.z, wp.x, wp.y, wp.z, 1, unpack(AutoDrive.currentColors.ad_color_previewNotOk)) - ADDrawingManager:addArrowTask(lastWp.x, lastWp.y, lastWp.z, wp.x, wp.y, wp.z, 1, arrowPosition, unpack(AutoDrive.currentColors.ad_color_previewNotOk)) + ADDrawingManager:addLineTask(lastWp.x, lastWp.y, lastWp.z, wp.x, wp.y, wp.z, 1, unpack(color)) + if not isDual then + ADDrawingManager:addArrowTask(lastWp.x, lastWp.y, lastWp.z, wp.x, wp.y, wp.z, 1, arrowPosition, unpack(color)) end - lastWp = {x = wp.x, y = wp.y, z = wp.z} lastHeight = wp.y end end - local targetWp = AutoDrive.splineInterpolation.endNode - if collisionFree then - ADDrawingManager:addLineTask(lastWp.x, lastWp.y, lastWp.z, targetWp.x, targetWp.y, targetWp.z, 1, unpack(AutoDrive.currentColors.ad_color_previewOk)) - ADDrawingManager:addArrowTask(lastWp.x, lastWp.y, lastWp.z, targetWp.x, targetWp.y, targetWp.z, 1, arrowPosition, unpack(AutoDrive.currentColors.ad_color_previewOk)) - else - ADDrawingManager:addLineTask(lastWp.x, lastWp.y, lastWp.z, targetWp.x, targetWp.y, targetWp.z, 1, unpack(AutoDrive.currentColors.ad_color_previewNotOk)) - ADDrawingManager:addArrowTask(lastWp.x, lastWp.y, lastWp.z, targetWp.x, targetWp.y, targetWp.z, 1, arrowPosition, unpack(AutoDrive.currentColors.ad_color_previewNotOk)) + + ADDrawingManager:addLineTask(lastWp.x, lastWp.y, lastWp.z, targetWp.x, targetWp.y, targetWp.z, 1, unpack(color)) + if not isDual then + ADDrawingManager:addArrowTask(lastWp.x, lastWp.y, lastWp.z, targetWp.x, targetWp.y, targetWp.z, 1, arrowPosition, unpack(color)) end end function AutoDrive:onPostAttachImplement(attachable, inputJointDescIndex, jointDescIndex) if attachable["spec_FS19_addon_strawHarvest.strawHarvestPelletizer"] ~= nil then attachable.isPremos = true - -- attachable.getIsBufferCombine = function() - -- return false - -- end end if (attachable.spec_pipe ~= nil and attachable.spec_combine ~= nil) or attachable.isPremos then + attachable.ad = self.ad -- takeover i.e. sensors from trailing vehicle attachable.isTrailedHarvester = true attachable.trailingVehicle = self - ADHarvestManager:registerHarvester(attachable) - self.ad.isCombine = true + -- harvester types self.ad.attachableCombine = attachable - attachable.ad = self.ad + local isValidHarvester = AutoDrive.setCombineType(attachable) + if isValidHarvester then + ADHarvestManager:registerHarvester(attachable) + end end AutoDrive.setValidSupportedFillType(self) @@ -698,14 +710,11 @@ function AutoDrive:onPreDetachImplement(implement) local attachable = implement.object if attachable.isTrailedHarvester and attachable.trailingVehicle == self then attachable.ad = nil - self.ad.isCombine = false self.ad.attachableCombine = nil ADHarvestManager:unregisterHarvester(attachable) attachable.isTrailedHarvester = false attachable.trailingVehicle = nil - if attachable.isPremos then - -- attachable.getIsBufferCombine = nil - end + self.ad.isRegisterdHarvester = nil end if self.ad ~= nil then self.ad.frontToolWidth = nil diff --git a/scripts/Tasks/CatchCombinePipeTask.lua b/scripts/Tasks/CatchCombinePipeTask.lua index 6b3a0689..e25d9fae 100644 --- a/scripts/Tasks/CatchCombinePipeTask.lua +++ b/scripts/Tasks/CatchCombinePipeTask.lua @@ -37,7 +37,8 @@ function CatchCombinePipeTask:setUp() local angleToCombineHeading = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getAngleToCombineHeading() local angleToCombine = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getAngleToCombine() - if angleToCombineHeading < 35 and angleToCombine < 90 and AutoDrive.getDistanceBetween(self.vehicle, self.combine) < 60 then + if angleToCombineHeading < 35 and angleToCombine < 90 and AutoDrive.getDistanceBetween(self.vehicle, self.combine) < 60 + and not self.combine.ad.isFixedPipeChopper then self:finished() end self.trailers, _ = AutoDrive.getAllUnits(self.vehicle) @@ -73,6 +74,7 @@ function CatchCombinePipeTask:update(dt) self.vehicle.ad.specialDrivingModule:update(dt) end elseif self.state == CatchCombinePipeTask.STATE_DELAY_PATHPLANNING then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:update - STATE_DELAY_PATHPLANNING") if self.waitForCheckTimer:timer(true, 1000, dt) then if self:startNewPathFinding() then self.vehicle.ad.pathFinderModule:addDelayTimer(6000) @@ -97,6 +99,7 @@ function CatchCombinePipeTask:update(dt) -- or AutoDrive.getDistanceBetween(self.vehicle, self.combine) < self.MIN_COMBINE_DISTANCE then -- got stuck or to close to combine -> reverse + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:update - STATE_DRIVING stuck") self.stuckTimer:timer(false) local x, y, z = getWorldTranslation(self.vehicle.components[1].node) self.reverseStartLocation = {x = x, y = y, z = z} @@ -112,10 +115,12 @@ function CatchCombinePipeTask:update(dt) if self.vehicle.ad.drivePathModule:isTargetReached() then -- check if we have actually reached the target or not -- accept current location if we are in a good position to start chasing: distance and angle are important here + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:update - STATE_DRIVING TargetReached") local angleToCombine = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getAngleToCombineHeading() local isCorrectSide = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:isUnloaderOnCorrectSide() if angleToCombine < 35 and AutoDrive.getDistanceBetween(self.vehicle, self.combine) < 80 and isCorrectSide then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:update - STATE_DRIVING -> STATE_FINISHED") self.state = CatchCombinePipeTask.STATE_FINISHED return else @@ -137,6 +142,7 @@ function CatchCombinePipeTask:update(dt) self.vehicle.ad.specialDrivingModule:driveReverse(dt, 15, 1, self.vehicle.ad.trailerModule:canBeHandledInReverse()) end elseif self.state == CatchCombinePipeTask.STATE_WAIT_BEFORE_FINISH then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:update - STATE_WAIT_BEFORE_FINISH") self.waitTimer:timer(true, self.MAX_REVERSE_TIME, dt) if self.waitTimer:done() then self.waitTimer:timer(false) @@ -147,6 +153,7 @@ function CatchCombinePipeTask:update(dt) self.vehicle.ad.specialDrivingModule:update(dt) end elseif self.state == CatchCombinePipeTask.STATE_FINISHED then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:update - STATE_FINISHED") self:finished() return end @@ -161,6 +168,7 @@ function CatchCombinePipeTask:finished(propagate) end function CatchCombinePipeTask:startNewPathFinding() + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:startNewPathFinding()") local pipeChasePos, pipeChaseSide = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getPipeChasePosition(true) local x, _, z = getWorldTranslation(self.combine.components[1].node) local targetFieldId = g_farmlandManager:getFarmlandIdAtWorldPosition(pipeChasePos.x, pipeChasePos.z) @@ -181,7 +189,7 @@ function CatchCombinePipeTask:startNewPathFinding() self.newPathFindingCounter = self.newPathFindingCounter + 1 -- used to prevent deadlock - if AutoDrive.getIsBufferCombine(self.combine) or (pipeChaseSide ~= AutoDrive.CHASEPOS_REAR or (targetFieldId == combineFieldId and cFillRatio <= 0.85)) then + if self.combine.ad.isChopper or (pipeChaseSide ~= AutoDrive.CHASEPOS_REAR or (targetFieldId == combineFieldId and cFillRatio <= 0.85)) then -- if self.combine:getIsBufferCombine() or (pipeChaseSide ~= AutoDrive.CHASEPOS_REAR and targetFieldId == combineFieldId and cFillRatio <= 0.85) then -- is chopper or chase not rear and harvester on correct field and filled < 85% - i.e. combine pipe not in fruit AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "CatchCombinePipeTask:startNewPathFinding() - chase pos looks good - calculate path to it...") @@ -197,6 +205,14 @@ function CatchCombinePipeTask:startNewPathFinding() return false end +function CatchCombinePipeTask:getExcludedVehiclesForCollisionCheck() + local excludedVehicles = {} + if self.state == CatchCombinePipeTask.STATE_DRIVING then + table.insert(excludedVehicles, self.combine:getRootVehicle()) + end + return excludedVehicles +end + function CatchCombinePipeTask:getI18nInfo() local text = "$l10n_AD_task_catch_up_with_combine;" if self.state == CatchCombinePipeTask.STATE_PATHPLANNING then diff --git a/scripts/Tasks/EmptyHarvesterTask.lua b/scripts/Tasks/EmptyHarvesterTask.lua index cb0089c7..9dcd7531 100644 --- a/scripts/Tasks/EmptyHarvesterTask.lua +++ b/scripts/Tasks/EmptyHarvesterTask.lua @@ -183,7 +183,7 @@ end function EmptyHarvesterTask:getExcludedVehiclesForCollisionCheck() local excludedVehicles = {} if self.state == EmptyHarvesterTask.STATE_DRIVING then - table.insert(excludedVehicles, self.combine) + table.insert(excludedVehicles, self.combine:getRootVehicle()) end return excludedVehicles end diff --git a/scripts/Tasks/FollowCombineTask.lua b/scripts/Tasks/FollowCombineTask.lua index 09fa22ab..f21799a7 100644 --- a/scripts/Tasks/FollowCombineTask.lua +++ b/scripts/Tasks/FollowCombineTask.lua @@ -4,6 +4,7 @@ FollowCombineTask.debug = false FollowCombineTask.STATE_CHASING = 1 FollowCombineTask.STATE_WAIT_FOR_TURN = 2 FollowCombineTask.STATE_REVERSING = 3 +FollowCombineTask.STATE_REVERSING_FROM_CHOPPER = 12 FollowCombineTask.STATE_WAIT_FOR_PASS_BY = 4 FollowCombineTask.STATE_CIRCLING_PATHPLANNING = 5 FollowCombineTask.STATE_CIRCLING = 6 @@ -29,6 +30,8 @@ function FollowCombineTask:new(vehicle, combine) o.angleWrongTimer = AutoDriveTON:new() o.waitForTurnTimer = AutoDriveTON:new() o.stuckTimer = AutoDriveTON:new() + o.dischargeTimer = AutoDriveTON:new() + o.fillingTimer = AutoDriveTON:new() o.lastChaseSide = -10 o.waitForPassByTimer = AutoDriveTON:new() o.chaseTimer = AutoDriveTON:new() @@ -44,7 +47,7 @@ function FollowCombineTask:new(vehicle, combine) end function FollowCombineTask:setUp() - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "Setting up FollowCombineTask") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask setUp") self.lastChaseSide = self.chaseSide self.trailers, _ = AutoDrive.getAllUnits(self.vehicle) self.activeUnloading = AutoDrive.getSetting("activeUnloading", self.combine) @@ -63,20 +66,21 @@ function FollowCombineTask:update(dt) self.chaseTimer:timer(true, 4000, dt) self.stuckTimer:timer(self.vehicle.lastSpeedReal <= 0.0002, self.MAX_STUCK_TIME, dt) - if AutoDrive.getIsBufferCombine(self.combine) then + if self.combine.ad.isChopper then if self.filled and self.chaseSide ~= nil and self.chaseSide ~= AutoDrive.CHASEPOS_REAR then --skip reversing - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "I am filled and driving on the side - skip reversing and finish now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - filled chopper") self.state = FollowCombineTask.STATE_FINISHED -- finish immediate return elseif self.filledToUnload and self.chaseSide ~= nil and self.chaseSide == AutoDrive.CHASEPOS_REAR then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - filledToUnload chopper") local x, y, z = getWorldTranslation(self.vehicle.components[1].node) self.reverseStartLocation = {x = x, y = y, z = z} self.state = FollowCombineTask.STATE_REVERSING -- reverse to get room from harvester return end - elseif self.filled or ( not AutoDrive.getIsBufferCombine(self.combine) and self.combineFillPercent <= 0.1 and (not self.activeUnloading)) then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "I am filled - reversing now") + elseif self.filled or (self.combine.ad.isHarvester and self.combineFillPercent <= 0.1 and (not self.activeUnloading)) then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - filled harvester") self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH -- unload after some time to let harvester drive away return end @@ -88,10 +92,11 @@ function FollowCombineTask:update(dt) FollowCombineTask.debugMsg(self.vehicle, "FollowCombineTask:update STATE_CHASING stuckTimer:done -> STATE_REVERSING") end self.stuckTimer:timer(false) - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "got stuck - reversing now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - stuck -> stuckTimer:%s angleWrongTimer:%s" + , tostring(self.stuckTimer:done()), tostring(self.angleWrongTimer.elapsedTime > 15000)) local x, y, z = getWorldTranslation(self.vehicle.components[1].node) self.reverseStartLocation = {x = x, y = y, z = z} - if AutoDrive.getIsBufferCombine(self.combine) then + if self.combine.ad.isChopper then self.state = FollowCombineTask.STATE_REVERSING_FROM_CHOPPER else self.state = FollowCombineTask.STATE_REVERSING -- reverse to get room from harvester @@ -100,15 +105,16 @@ function FollowCombineTask:update(dt) end if not self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:isUnloaderOnCorrectSide() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "I am not on the correct side - set finished now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - not UnloaderOnCorrectSide -> finished") self:finished() return end - if (not AutoDrive.getIsBufferCombine(self.combine)) and self.combineFillPercent > 90 + if self.combine.ad.isHarvester and self.combineFillPercent > 90 and AutoDrive.getDistanceBetween(self.vehicle, self.combine) < self.MIN_COMBINE_DISTANCE -- if to close -> reverse then -- Stop chasing and wait for a normal unload call while standing + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - to close to harvester -> reverse") local x, y, z = getWorldTranslation(self.vehicle.components[1].node) self.reverseStartLocation = {x = x, y = y, z = z} self.state = FollowCombineTask.STATE_REVERSING -- reverse to get room from harvester @@ -117,7 +123,7 @@ function FollowCombineTask:update(dt) if (not self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:isUnloaderOnCorrectSide(self.chaseSide)) and (not AutoDrive.combineIsTurning(self.combine)) then if self.lastChaseSide ~= CombineUnloaderMode.CHASEPOS_REAR then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "switching chase side from side to elsewhere - let's wait for passby next") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - switching chase side from side to elsewhere - let's wait for passby next") self.state = FollowCombineTask.STATE_WAIT_FOR_PASS_BY end end @@ -125,7 +131,7 @@ function FollowCombineTask:update(dt) if AutoDrive.combineIsTurning(self.combine) then -- harvester turns --print("Waiting for turn now - 1- t:" .. tostring(AutoDrive.combineIsTurning(self.combine)) .. " anglewrongtimer: " .. tostring(self.angleWrongTimer.elapsedTime > 10000)) - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "Detected combine turning: " .. tostring(AutoDrive.combineIsTurning(self.combine)) .. " - waiting for turn to be finished next") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_CHASING - combineIsTurning") self.state = FollowCombineTask.STATE_WAIT_FOR_TURN return elseif ((self.combine.lastSpeedReal * self.combine.movingDirection) <= -0.00005) then @@ -134,49 +140,74 @@ function FollowCombineTask:update(dt) self:followChasePoint(dt) end elseif self.state == FollowCombineTask.STATE_WAIT_FOR_TURN then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_WAIT_FOR_TURN") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN") self.waitForTurnTimer:timer(true, self.MAX_TURN_TIME, dt) if self.waitForTurnTimer:done() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "combine turn took to long - set finished now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - combine turn took to long - set finished now") self.waitForTurnTimer:timer(false) self.state = FollowCombineTask.STATE_FINISHED return end if AutoDrive.combineIsTurning(self.combine) then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update combineIsTurning -> ") - if not AutoDrive.getIsBufferCombine(self.combine) and (self.distanceToCombine < ((self.vehicle.size.length + self.combine.size.length) / 2 + 10)) then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - combineIsTurning") + if self.combine.ad.isHarvester and (self.distanceToCombine < ((self.vehicle.size.length + self.combine.size.length) / 2 + 10)) then -- harvester -- if combine drive reverse to turn -> reverse to keep distance self:reverse(dt) - elseif AutoDrive.getIsBufferCombine(self.combine) and AutoDrive:getIsCPActive(self.combine) then + elseif self.combine.ad.isChopper and AutoDrive:getIsCPActive(self.combine) then -- CP chopper turn - -- local isdrivingReverse = ((self.combine.lastSpeedReal * self.combine.movingDirection) <= -0.00005) - local isdrivingReverse = ((self.combine.lastSpeedReal * self.combine.movingDirection) <= -0.00051) - local combineIsDriving = (self.combine.lastSpeedReal > 0.001) - self.stuckTimer:timer(self.vehicle.lastSpeedReal <= 0.0002, 15000, dt) - - if isdrivingReverse then - self:reverse(dt) - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update -> self:reverse") - elseif self.stuckTimer:done() or (not combineIsDriving and (self:getAngleToCobine() > 45)) then - -- if stuck with harvester - try reverse - self.stuckTimer:timer(false) - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update stuck / getAngleToCobine() > 45 -> STATE_REVERSING_FROM_CHOPPER combineIsDriving %s", tostring(combineIsDriving)) - local x, y, z = getWorldTranslation(self.vehicle.components[1].node) - self.reverseStartLocation = {x = x, y = y, z = z} - self.state = FollowCombineTask.STATE_REVERSING_FROM_CHOPPER -- reverse to get room from harvester - return - elseif combineIsDriving then - self.vehicle.ad.specialDrivingModule:stopVehicle() - self.vehicle.ad.specialDrivingModule:update(dt) - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update combineIsDriving -> stopVehicle") + if self.combine.ad.isAutoAimingChopper then + local isdrivingReverse = ((self.combine.lastSpeedReal * self.combine.movingDirection) <= -0.00051) + local combineIsDriving = (self.combine.lastSpeedReal > 0.001) + self.stuckTimer:timer(self.vehicle.lastSpeedReal <= 0.0002, 15000, dt) + if isdrivingReverse then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN -> self:reverse") + self:reverse(dt) + elseif self.stuckTimer:done() or (not combineIsDriving and (self:getAngleToCobine() > 45)) then + -- if stuck with harvester - try reverse + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - stuck / getAngleToCobine() > 45 -> STATE_REVERSING_FROM_CHOPPER combineIsDriving %s", tostring(combineIsDriving)) + self.stuckTimer:timer(false) + local x, y, z = getWorldTranslation(self.vehicle.components[1].node) + self.reverseStartLocation = {x = x, y = y, z = z} + self.state = FollowCombineTask.STATE_REVERSING_FROM_CHOPPER -- reverse to get room from harvester + return + elseif combineIsDriving then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - combineIsDriving -> stopVehicle") + self.vehicle.ad.specialDrivingModule:stopVehicle() + self.vehicle.ad.specialDrivingModule:update(dt) + else + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN -> followChasePoint self.chaseSide %s", tostring(self.chaseSide)) + self:followChasePoint(dt) + end else - self:followChasePoint(dt) - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update -> followChasePoint self.chaseSide %s", tostring(self.chaseSide)) + -- isFixedPipeChopper + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - noMovementTimer %d", self.combine.ad.noMovementTimer.elapsedTime) + local dischargeState = self.combine:getDischargeState() + self.fillingTimer:timer(not self.combine.spec_combine.isFilling, 100, dt) + if self.fillingTimer:done() and self.combine.ad.noMovementTimer.elapsedTime < 5000 then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - fillingTimer:done") + -- harvested to end of row + AutoDrive:holdCPCombine(self.combine) + self.vehicle.ad.specialDrivingModule:stopVehicle() + self.vehicle.ad.specialDrivingModule:update(dt) + else + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN -> followChasePoint no AutoAimingChopper") + self:followChasePoint(dt) + end + self.dischargeTimer:timer(dischargeState ~= Dischargeable.DISCHARGE_STATE_OBJECT , 500, dt) + if self.dischargeTimer:done() and self.fillingTimer:done() and self.combine.ad.noMovementTimer.elapsedTime < 5000 then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - dischargeTimer:done") + self.fillingTimer:timer(false) + self.dischargeTimer:timer(false) + local x, y, z = getWorldTranslation(self.vehicle.components[1].node) + self.reverseStartLocation = {x = x, y = y, z = z} + self.state = FollowCombineTask.STATE_REVERSING_FROM_CHOPPER -- reverse to get room from harvester + return + end end else - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update -> stopVehicle") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN -> stopVehicle") -- stop while combine is turning self.vehicle.ad.specialDrivingModule:stopVehicle() self.vehicle.ad.specialDrivingModule:update(dt) @@ -189,34 +220,34 @@ function FollowCombineTask:update(dt) ( self.combine.ad.sensors.frontSensorFruit:pollInfo() and ( - AutoDrive.getIsBufferCombine(self.combine) -- chopper + self.combine.ad.isChopper -- chopper or self.combine.ad.driveForwardTimer.elapsedTime > 8000 -- Harvester moves ) ) or self.waitForTurnTimer.elapsedTime > 15000 -- turn longer than 15 sec ) then if (self.angleToCombineHeading + self.angleToCombine) < 180 and self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:isUnloaderOnCorrectSide(self.chaseSide) then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "combine turn finished - Heading looks good - start chasing again") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - combine turn finished - Heading looks good - start chasing again") self.waitForTurnTimer:timer(false) self.chaseTimer:timer(false) self.state = FollowCombineTask.STATE_CHASING return - elseif self.angleToCombineHeading > 150 and self.angleToCombineHeading < 210 and self.distanceToCombine < 80 and AutoDrive.experimentalFeatures.UTurn == true and not AutoDrive.getIsBufferCombine(self.combine) then + elseif self.angleToCombineHeading > 150 and self.angleToCombineHeading < 210 and self.distanceToCombine < 80 and AutoDrive.experimentalFeatures.UTurn == true and self.combine.ad.isHarvester then -- Instead of directly trying a long way around to get behind the harvester, let's wait for him to pass us by and then U-turn - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "combine turn finished - Heading inverted - wait for passby, then U-turn") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - combine turn finished - Heading inverted - wait for passby, then U-turn") self.state = FollowCombineTask.STATE_WAIT_FOR_COMBINE_TO_PASS_BY self.waitForTurnTimer:timer(false) self.chaseTimer:timer(false) self.waitForPassByTimer:timer(false) else - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "combine turn finished - Heading looks bad - stop to be able to start pathfinder") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_TURN - combine turn finished - Heading looks bad - stop to be able to start pathfinder") self.stayOnField = true self.state = FollowCombineTask.STATE_FINISHED return end end elseif self.state == FollowCombineTask.STATE_WAIT_FOR_PASS_BY then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_WAIT_FOR_PASS_BY") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_PASS_BY") self.waitForPassByTimer:timer(true, 2200, dt) self.vehicle.ad.specialDrivingModule:stopVehicle() self.vehicle.ad.specialDrivingModule:update(dt) @@ -224,24 +255,24 @@ function FollowCombineTask:update(dt) self.waitForPassByTimer:timer(false) self.chaseTimer:timer(false) if (self.angleToCombineHeading + self.angleToCombine) < 180 and self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:isUnloaderOnCorrectSide() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "passby timer elapsed - heading looks good - chasing again") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_PASS_BY - passby timer elapsed - heading looks good - chasing again") self.state = FollowCombineTask.STATE_CHASING return else - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "passby timer elapsed - heading looks bad - set finished now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_PASS_BY - passby timer elapsed - heading looks bad - set finished now") self.stayOnField = true self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH return end end elseif self.state == FollowCombineTask.STATE_REVERSING then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_REVERSING") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_REVERSING") local x, y, z = getWorldTranslation(self.vehicle.components[1].node) local distanceToReverseStart = MathUtil.vector2Length(x - self.reverseStartLocation.x, z - self.reverseStartLocation.z) self.reverseTimer:timer(true, self.MAX_REVERSE_TIME, dt) local doneReversing = distanceToReverseStart > self.MAX_REVERSE_DISTANCE or (not self.startedChasing) if doneReversing or self.reverseTimer:done() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "done reversing - set finished") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_REVERSING - done reversing - set finished") self.reverseTimer:timer(false) self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH return @@ -249,25 +280,41 @@ function FollowCombineTask:update(dt) self:reverse(dt) end elseif self.state == FollowCombineTask.STATE_REVERSING_FROM_CHOPPER then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_REVERSING_FROM_CHOPPER") - local x, y, z = getWorldTranslation(self.vehicle.components[1].node) - local distanceToReverseStart = MathUtil.vector2Length(x - self.reverseStartLocation.x, z - self.reverseStartLocation.z) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_REVERSING_FROM_CHOPPER") + local cx, _, cz = getWorldTranslation(self.combine.components[1].node) + local vx, _, vz = getWorldTranslation(self.vehicle.components[1].node) + local distanceToReverseStart = MathUtil.vector2Length(vx - self.reverseStartLocation.x, vz - self.reverseStartLocation.z) + local distanceToCombine = MathUtil.vector2Length(cx - vx, cz - vz) self.reverseTimer:timer(true, self.MAX_REVERSE_TIME, dt) - local doneReversing = distanceToReverseStart > self.MAX_REVERSE_DISTANCE + local doneReversing = distanceToReverseStart > self.MAX_REVERSE_DISTANCE or distanceToCombine > self.MAX_REVERSE_DISTANCE if doneReversing or self.reverseTimer:done() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "done reversing - set finished") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_REVERSING_FROM_CHOPPER - done reversing - set finished") self.reverseTimer:timer(false) - self.state = FollowCombineTask.STATE_FINISHED + if self.combine.ad.isFixedPipeChopper and AutoDrive:getIsCPActive(self.combine) then + -- wait for CP to finish a turn maneuver before invoke pathfinder + self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH + else + self.state = FollowCombineTask.STATE_FINISHED + end return else - if self:getAngleToCobine() > 30 then + if self.combine.ad.isFixedPipeChopper then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_REVERSING_FROM_CHOPPER - not AutoAimingChopper -> holdCPCombine") AutoDrive:holdCPCombine(self.combine) + else + if self:getAngleToCobine() > 30 then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_REVERSING_FROM_CHOPPER - AngleToCobine > 30 -> holdCPCombine") + AutoDrive:holdCPCombine(self.combine) + end end self:reverse(dt) end elseif self.state == FollowCombineTask.STATE_WAIT_BEFORE_FINISH then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_WAIT_BEFORE_FINISH") - self.waitTimer:timer(true, self.WAIT_BEFORE_FINISH_TIME, dt) + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_BEFORE_FINISH") + -- wait for CP to finish a turn maneuver before invoke pathfinder + -- TODO: check if following is useful! + local combineIsDriving = self.combine.ad.isFixedPipeChopper and AutoDrive:getIsCPActive(self.combine) and (self.combine.lastSpeedReal > 0.001) + self.waitTimer:timer(not combineIsDriving, self.WAIT_BEFORE_FINISH_TIME, dt) if self.waitTimer:done() then self.waitTimer:timer(false) self.state = FollowCombineTask.STATE_FINISHED @@ -277,12 +324,12 @@ function FollowCombineTask:update(dt) self.vehicle.ad.specialDrivingModule:update(dt) end elseif self.state == FollowCombineTask.STATE_WAIT_FOR_COMBINE_TO_PASS_BY then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_WAIT_FOR_COMBINE_TO_PASS_BY") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_COMBINE_TO_PASS_BY") self.waitForPassByTimer:timer(true, 15000, dt) self.vehicle.ad.specialDrivingModule:stopVehicle() self.vehicle.ad.specialDrivingModule:update(dt) if self.waitForPassByTimer:done() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "passby timer elapsed - heading looks bad - set finished now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_COMBINE_TO_PASS_BY - passby timer elapsed - heading looks bad - set finished now") self.stayOnField = true self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH return @@ -290,7 +337,7 @@ function FollowCombineTask:update(dt) local cx, cy, cz = getWorldTranslation(self.combine.components[1].node) local _, _, offsetZ = worldToLocal(self.vehicle.components[1].node, cx, cy, cz) if offsetZ <= -10 then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "combine passed us. Calculate U-turn now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_WAIT_FOR_COMBINE_TO_PASS_BY - combine passed us. Calculate U-turn now") self.state = FollowCombineTask.STATE_GENERATE_UTURN_PATH local cx, cy, cz = getWorldTranslation(self.combine.components[1].node) local offsetX, _, _ = worldToLocal(self.vehicle.components[1].node, cx, cy, cz) @@ -299,30 +346,30 @@ function FollowCombineTask:update(dt) end end elseif self.state == FollowCombineTask.STATE_GENERATE_UTURN_PATH then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_GENERATE_UTURN_PATH") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_GENERATE_UTURN_PATH") if self.vehicle.ad.uTurn ~= nil and self.vehicle.ad.uTurn.inProgress then self.vehicle:generateUTurn(true) elseif self.vehicle.ad.uTurn ~= nil and not self.vehicle.ad.uTurn.inProgress then if self.vehicle.ad.uTurn.colliFound or self.vehicle.ad.uTurn.points == nil or #self.vehicle.ad.uTurn.points < 5 then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "U-Turn generation failed due to collision - set finished now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_GENERATE_UTURN_PATH - U-Turn generation failed due to collision - set finished now") self.stayOnField = true self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH else - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "U-Turn generation finished - passing points to drivePathModule now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_GENERATE_UTURN_PATH - U-Turn generation finished - passing points to drivePathModule now") self.vehicle.ad.drivePathModule:setWayPoints(self.vehicle.ad.uTurn.points) self.state = FollowCombineTask.STATE_DRIVE_UTURN_PATH end end elseif self.state == FollowCombineTask.STATE_DRIVE_UTURN_PATH then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_DRIVE_UTURN_PATH") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_DRIVE_UTURN_PATH") if self.vehicle.ad.drivePathModule:isTargetReached() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "U-Turn finished") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_DRIVE_UTURN_PATH - U-Turn finished") if (self.angleToCombineHeading + self.angleToCombine) < 180 and self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:isUnloaderOnCorrectSide() then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "passby timer elapsed - heading looks good - chasing again") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_DRIVE_UTURN_PATH - passby timer elapsed - heading looks good - chasing again") self.state = FollowCombineTask.STATE_CHASING return else - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "passby timer elapsed - heading looks bad - set finished now") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_DRIVE_UTURN_PATH - passby timer elapsed - heading looks bad - set finished now") self.stayOnField = true self.state = FollowCombineTask.STATE_WAIT_BEFORE_FINISH return @@ -331,7 +378,7 @@ function FollowCombineTask:update(dt) self.vehicle.ad.drivePathModule:update(dt) end elseif self.state == FollowCombineTask.STATE_FINISHED then - AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update FollowCombineTask.STATE_FINISHED") + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:update STATE_FINISHED") self:finished() return end @@ -387,6 +434,7 @@ end function FollowCombineTask:followChasePoint(dt) if self:shouldWaitForChasePos(dt) then + AutoDrive.debugPrint(self.vehicle, AutoDrive.DC_COMBINEINFO, "FollowCombineTask:followChasePoint getAngleToChasePos %.0f -> stopVehicle", self:getAngleToChasePos()) self.vehicle.ad.specialDrivingModule:stopVehicle() self.vehicle.ad.specialDrivingModule:update(dt) else @@ -423,6 +471,18 @@ function FollowCombineTask:isCaughtCurrentChaseSide() return caught end + +function FollowCombineTask:getAngleToCombineHeading() + if self.vehicle == nil or self.combine == nil then + return math.huge + end + + local combineRx, _, combineRz = localDirectionToWorld(self.combine:getAIDirectionNode(), 0, 0, 1) + local rx, _, rz = localDirectionToWorld(self.vehicle.components[1].node, 0, 0, 1) + + return math.abs(AutoDrive.angleBetween({x = rx, z = rz}, {x = combineRx, z = combineRz})) +end + function FollowCombineTask:getAngleToChasePos() local worldX, _, worldZ = getWorldTranslation(self.vehicle.components[1].node) local rx, _, rz = localDirectionToWorld(self.vehicle.components[1].node, 0, 0, 1) @@ -453,8 +513,8 @@ end function FollowCombineTask:getExcludedVehiclesForCollisionCheck() local excludedVehicles = {} - if self.state == FollowCombineTask.STATE_CHASING then - table.insert(excludedVehicles, self.combine) + if self.state == FollowCombineTask.STATE_CHASING or self.state == FollowCombineTask.STATE_WAIT_FOR_TURN then + table.insert(excludedVehicles, self.combine:getRootVehicle()) end return excludedVehicles end @@ -474,7 +534,7 @@ function FollowCombineTask:getI18nInfo() elseif self.chaseSide == AutoDrive.CHASEPOS_RIGHT then text = text .. " - " .. "$l10n_AD_task_chase_side_right;" end - elseif self.state == FollowCombineTask.STATE_WAIT_FOR_TURN then + elseif self.state == FollowCombineTask.STATE_REVERSING_FROM_CHOPPER then text = text .. " - " .. "$l10n_AD_task_wait_for_combine_turn;" elseif self.state == FollowCombineTask.STATE_REVERSING then text = text .. " - " .. "$l10n_AD_task_reversing_from_combine;" diff --git a/scripts/Tasks/HandleHarvesterTurnTask.lua b/scripts/Tasks/HandleHarvesterTurnTask.lua index a96926e7..dab933e5 100644 --- a/scripts/Tasks/HandleHarvesterTurnTask.lua +++ b/scripts/Tasks/HandleHarvesterTurnTask.lua @@ -313,7 +313,7 @@ function HandleHarvesterTurnTask:generateReverseToCombineSection() local nodes = {} local sideChaseTermX = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getSideChaseOffsetX() - local sideChaseTermZ = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getSideChaseOffsetZ(AutoDrive.dynamicChaseDistance or not AutoDrive.getIsBufferCombine(self.combine)) + local sideChaseTermZ = self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getSideChaseOffsetZ(AutoDrive.dynamicChaseDistance or not self.combine.ad.isChopper) if not AutoDrive.combineIsTurning(self.combine) then local chasePos = AutoDrive.createWayPointRelativeToVehicle(self.combine, -(sideChaseTermX + self.vehicle.ad.modes[AutoDrive.MODE_UNLOAD]:getPipeSlopeCorrection()), sideChaseTermZ - 2) diff --git a/scripts/Tasks/UnloadAtDestinationTask.lua b/scripts/Tasks/UnloadAtDestinationTask.lua index 877e55b5..72695a4b 100644 --- a/scripts/Tasks/UnloadAtDestinationTask.lua +++ b/scripts/Tasks/UnloadAtDestinationTask.lua @@ -8,6 +8,7 @@ UnloadAtDestinationTask.BALE_UNLOAD_DISTANCE = 5 function UnloadAtDestinationTask:new(vehicle, destinationID) local o = UnloadAtDestinationTask:create() + o.taskType = "UnloadAtDestinationTask" o.vehicle = vehicle o.destinationID = destinationID o.isContinued = false diff --git a/scripts/Utils/AutoDriveUtilFuncs.lua b/scripts/Utils/AutoDriveUtilFuncs.lua index 1bfb47cb..3d6134f2 100644 --- a/scripts/Utils/AutoDriveUtilFuncs.lua +++ b/scripts/Utils/AutoDriveUtilFuncs.lua @@ -160,7 +160,7 @@ function AutoDrive.combineIsTurning(combine) local fieldLengthInFront = AutoDrive.getLengthOfFieldInFront(combine, true, 50, 5) local fieldLengthBehind = math.abs(AutoDrive.getLengthOfFieldInFront(combine, false, 50, -5)) - if (fieldLengthInFront <= 20 or fieldLengthBehind <= 20) and combine.ad.noMovementTimer.elapsedTime < 5000 and not AutoDrive.getIsBufferCombine(combine) then + if (fieldLengthInFront <= 20 or fieldLengthBehind <= 20) and combine.ad.noMovementTimer.elapsedTime < 5000 and not combine.ad.isChopper then combineIsTurning = true end diff --git a/scripts/Utils/CollisionDetectionUtils.lua b/scripts/Utils/CollisionDetectionUtils.lua index bfa4d1fe..6117d34c 100644 --- a/scripts/Utils/CollisionDetectionUtils.lua +++ b/scripts/Utils/CollisionDetectionUtils.lua @@ -16,8 +16,9 @@ function AutoDrive.checkForVehiclesInBox(boundingBox, excludedVehicles) end end end - if otherVehicle.spec_conveyorBelt and otherVehicle.spec_motorized and otherVehicle.getIsMotorStarted and otherVehicle:getIsMotorStarted() then - -- ignore operating conveyor belts + if (otherVehicle.spec_conveyorBelt and otherVehicle.spec_motorized and otherVehicle.getIsMotorStarted and otherVehicle:getIsMotorStarted()) -- ignore operating conveyor belts + or (otherVehicle.trainSystem ~= nil) -- ignore train vehicles + then isExcluded = true end if (not isExcluded) and otherVehicle ~= nil and otherVehicle.components ~= nil and otherVehicle.size.width ~= nil and otherVehicle.size.length ~= nil and otherVehicle.rootNode ~= nil then @@ -197,6 +198,10 @@ function ADDimensionSensor:getRealVehicleDimensions() local maxWidthLeft, maxWidthRight, maxLengthFront, maxLengthBack = 0,0,0,0 + if not entityExists(self.vehicle.components[1].node) then + -- if selling attachments, the vehicle chain is not updated complete in 1 frame, so need this + return 0, 0 + end local rx, ry, rz = getWorldRotation(self.vehicle.components[1].node) local function leftright(dimStart, dimEnd) diff --git a/scripts/Utils/CombineUtil.lua b/scripts/Utils/CombineUtil.lua index 98132549..30fbe521 100644 --- a/scripts/Utils/CombineUtil.lua +++ b/scripts/Utils/CombineUtil.lua @@ -4,10 +4,40 @@ AutoDrive.CHASEPOS_REAR = 3 AutoDrive.CHASEPOS_FRONT = 4 AutoDrive.CHASEPOS_UNKNOWN = 0 -function AutoDrive.getIsBufferCombine(vehicle) - return vehicle ~= nil and vehicle.spec_combine ~= nil and vehicle.spec_combine.isBufferCombine == true +-- harvester types +function AutoDrive.setCombineType(vehicle) + if vehicle == nil then + return false + end + if vehicle.ad == nil then + vehicle.ad = {} + end + local rootVehicle = vehicle:getRootVehicle() + local rootVehicleName = rootVehicle and rootVehicle:getName() or "no rootVehicle!!!" + vehicle.ad.hasCombine = false -- vehicle is any combine or has attached one + vehicle.ad.isAutoAimingChopper = false -- chopper with flexible self targeting pipe + vehicle.ad.isFixedPipeChopper = false -- chopper with fixed pipe + vehicle.ad.isChopper = false -- chopper, without bunker + vehicle.ad.isHarvester = false -- harvester with bunker + + if (vehicle.spec_combine ~= nil and vehicle.spec_pipe ~= nil and vehicle.spec_combine.isBufferCombine == true and vehicle.spec_pipe.numAutoAimingStates > 0) then + vehicle.ad.isAutoAimingChopper = true + end + if (vehicle.spec_combine ~= nil and vehicle.spec_pipe ~= nil and vehicle.spec_combine.isBufferCombine == true and vehicle.spec_pipe.numAutoAimingStates == 0) then + vehicle.ad.isFixedPipeChopper = true + end + if (vehicle.spec_combine ~= nil and vehicle.spec_pipe ~= nil and vehicle.spec_combine.isBufferCombine == true) then + vehicle.ad.isChopper = true + end + if (vehicle.spec_combine ~= nil and vehicle.spec_pipe ~= nil and not vehicle.spec_combine.isBufferCombine) then + vehicle.ad.isHarvester = true + end + + rootVehicle.ad.hasCombine = vehicle.ad.isAutoAimingChopper or vehicle.ad.isFixedPipeChopper or vehicle.ad.isChopper or vehicle.ad.isHarvester + return rootVehicle.ad.hasCombine end + function AutoDrive.getDischargeNode(combine) local dischargeNode = nil if combine.spec_dischargeable ~= nil then @@ -114,7 +144,7 @@ function AutoDrive.getPipeSide(combine) local dischargeNode = AutoDrive.getDischargeNode(combine) local dischargeX, dichargeY, dischargeZ = getWorldTranslation(dischargeNode) local diffX, _, _ = worldToLocal(combineNode, dischargeX, dichargeY, dischargeZ) - if combine.ad ~= nil and AutoDrive.isPipeOut(combine) and not AutoDrive.getIsBufferCombine(combine) then + if combine.ad ~= nil and (combine.ad.isFixedPipeChopper or combine.ad.isHarvester) and AutoDrive.isPipeOut(combine) then combine.ad.storedPipeSide = AutoDrive.sign(diffX) end return AutoDrive.sign(diffX) @@ -131,7 +161,7 @@ function AutoDrive.getPipeLength(combine) 0, pipeRootZ - dischargeZ) --AutoDrive.debugPrint(combine, AutoDrive.DC_COMBINEINFO, "AutoDrive.getPipeLength - " .. length) - if AutoDrive.isPipeOut(combine) and not AutoDrive.getIsBufferCombine(combine) then + if (combine.ad.isFixedPipeChopper or combine.ad.isHarvester) and AutoDrive.isPipeOut(combine) then local combineNode = AutoDrive.getPipeRoot(combine) local dischargeX, dichargeY, dischargeZ = getWorldTranslation(AutoDrive.getDischargeNode(combine)) diffX, _, _ = worldToLocal(combineNode, dischargeX, dichargeY, dischargeZ) @@ -178,21 +208,6 @@ function AutoDrive.isPipeOut(combine) return false end -function AutoDrive.isSugarcaneHarvester(combine) - -- see Specialisation - return combine and combine.ad and combine.ad.isSugarcaneHarvester -end - -function AutoDrive.isSugarcaneHarvester_old(combine) - local isSugarCaneHarvester = combine.typeName == "combineCutterFruitPreparer" - for _, implement in pairs(AutoDrive.getAllImplements(combine)) do - if implement ~= combine then - isSugarCaneHarvester = false - end - end - return isSugarCaneHarvester -end - function AutoDrive.getAIMarkerWidth(object) local retWidth = 0 if object ~= nil and object.getAIMarkers ~= nil then diff --git a/scripts/Utils/DevFuncs.lua b/scripts/Utils/DevFuncs.lua index d73313b9..2128524a 100644 --- a/scripts/Utils/DevFuncs.lua +++ b/scripts/Utils/DevFuncs.lua @@ -47,6 +47,16 @@ function AutoDrive.devAction(vehicle) else Logging.info("[AD] AutoDrive.devAction vehicle %s", tostring(vehicle)) end + + if vehicle ~= nil and g_currentMission.mapWidth and AutoDrive.getDebugChannelIsSet(AutoDrive.DC_ROADNETWORKINFO) and AutoDrive.isInExtendedEditorMode() then + local x, y, z = getWorldTranslation(vehicle.rootNode) + + for _, wp in pairs(ADGraphManager:getWayPoints()) do + if math.abs(wp.x) >= g_currentMission.mapWidth/2 or math.abs(wp.z) >= g_currentMission.mapHeight/2 then + ADGraphManager:moveWayPoint(wp.id, x, y, z, wp.flags) + end + end + end AutoDrive.devPrintDebugQueue(vehicle) end diff --git a/scripts/Utils/TrafficSplineUtils.lua b/scripts/Utils/TrafficSplineUtils.lua index 6a886fe9..aa6ca24d 100644 --- a/scripts/Utils/TrafficSplineUtils.lua +++ b/scripts/Utils/TrafficSplineUtils.lua @@ -169,10 +169,7 @@ function AutoDrive:createWaypointsForSpline(startNodes, endNodes, usedSplines, s if targetId >= 0 then local wpId = ADGraphManager:getWayPointsCount() local wp = ADGraphManager:getWayPointById(wpId) - ADGraphManager:toggleConnectionBetween(wp, ADGraphManager:getWayPointById(targetId)) - if isDualRoad then - ADGraphManager:toggleConnectionBetween(ADGraphManager:getWayPointById(targetId), wp) - end + ADGraphManager:toggleConnectionBetween(wp, ADGraphManager:getWayPointById(targetId), false, isDualRoad) else if posX < mapSize and posZ < mapSize then ADGraphManager:recordWayPoint(posX, posY, posZ, true, isDualRoad, false, 0, AutoDrive.FLAG_TRAFFIC_SYSTEM) @@ -289,13 +286,13 @@ function AutoDrive:createJunctions(startNodes, endNodes, maxAngle, maxDist) end local wp = ADGraphManager:getWayPointById(lastId) - ADGraphManager:toggleConnectionBetween(wp, startNode, false) + ADGraphManager:toggleConnectionBetween(wp, startNode, false, false) end else --print("AutoDrive:createJunctions - Fallback to toggle connections") - ADGraphManager:toggleConnectionBetween(endNode, startNode, false) + ADGraphManager:toggleConnectionBetween(endNode, startNode, false, false) end - --ADGraphManager:toggleConnectionBetween(endNode, startNode, false) + --ADGraphManager:toggleConnectionBetween(endNode, startNode, false, false) end end end @@ -312,7 +309,7 @@ function AutoDrive:checkForCollisionOnSpline() local mask = AutoDrive.collisionMaskSplines for wpId, wp in pairs(self.splineInterpolation.waypoints) do - if wpId > 1 and wpId < (#self.splineInterpolation.waypoints - 1) then + if wpId > 1 then local wpLast = self.splineInterpolation.waypoints[wpId - 1] local deltaX, deltaY, deltaZ = wp.x - wpLast.x, wp.y - wpLast.y, wp.z - wpLast.z local centerX, centerY, centerZ = wpLast.x + deltaX/2, wpLast.y + deltaY/2, wpLast.z + deltaZ/2 diff --git a/scripts/Utils/TrailerUtil.lua b/scripts/Utils/TrailerUtil.lua index 10909a94..21e0dbdb 100644 --- a/scripts/Utils/TrailerUtil.lua +++ b/scripts/Utils/TrailerUtil.lua @@ -620,17 +620,19 @@ function AutoDrive.findGrainBackDoorTipSideIndex(vehicle, trailer) local tipSide = spec.tipSides[i] trailer:setCurrentDischargeNodeIndex(tipSide.dischargeNodeIndex) local currentDischargeNode = trailer:getCurrentDischargeNode() - local tx, ty, tz = getWorldTranslation(currentDischargeNode.node) - local _, _, diffZ = worldToLocal(trailer.components[1].node, tx, ty, tz + 50) - -- get the 2 most back doors - if diffZ < backDistance1 and currentDischargeNode and currentDischargeNode.effects and table.count(currentDischargeNode.effects) > 0 then - backDistance1 = diffZ - dischargeSpeed1 = currentDischargeNode.emptySpeed - tipSideIndex1 = i - elseif diffZ < backDistance2 and currentDischargeNode and currentDischargeNode.effects and table.count(currentDischargeNode.effects) > 0 then - backDistance2 = diffZ - dischargeSpeed2 = currentDischargeNode.emptySpeed - tipSideIndex2 = i + if currentDischargeNode then + local tx, ty, tz = getWorldTranslation(currentDischargeNode.node) + local _, _, diffZ = worldToLocal(trailer.components[1].node, tx, ty, tz + 50) + -- get the 2 most back doors + if diffZ < backDistance1 and currentDischargeNode and currentDischargeNode.effects and table.count(currentDischargeNode.effects) > 0 then + backDistance1 = diffZ + dischargeSpeed1 = currentDischargeNode.emptySpeed + tipSideIndex1 = i + elseif diffZ < backDistance2 and currentDischargeNode and currentDischargeNode.effects and table.count(currentDischargeNode.effects) > 0 then + backDistance2 = diffZ + dischargeSpeed2 = currentDischargeNode.emptySpeed + tipSideIndex2 = i + end end end local foundTwoBackDoors = math.abs(backDistance2 - backDistance1) < 1 @@ -713,7 +715,7 @@ function AutoDrive.getTriggerAndTrailerPairs(vehicle, dt) local trailerTriggerPairs = {} -- local trailers, _ = AutoDrive.getTrailersOf(vehicle, false) local trailers, _ = AutoDrive.getAllUnits(vehicle) - local maxTriggerDistance = AutoDrive.getSetting("maxTriggerDistance") + local maxTriggerDistance = AutoDrive.getMaxTriggerDistance(vehicle) for _, trailer in ipairs(trailers) do if trailer.getFillUnits ~= nil then local fillUnits = trailer:getFillUnits() @@ -918,9 +920,9 @@ function AutoDrive.isInRangeToLoadUnloadTarget(vehicle) else ret = ( - ((rootVehicle.ad.stateModule:getCurrentMode():shouldLoadOnTrigger() == true) and AutoDrive.getDistanceToTargetPosition(vehicle) <= AutoDrive.getSetting("maxTriggerDistance")) + ((rootVehicle.ad.stateModule:getCurrentMode():shouldLoadOnTrigger() == true) and AutoDrive.getDistanceToTargetPosition(vehicle) <= AutoDrive.getMaxTriggerDistance(vehicle)) or - ((rootVehicle.ad.stateModule:getCurrentMode():shouldUnloadAtTrigger() == true) and AutoDrive.getDistanceToUnloadPosition(vehicle) <= AutoDrive.getSetting("maxTriggerDistance")) + ((rootVehicle.ad.stateModule:getCurrentMode():shouldUnloadAtTrigger() == true) and AutoDrive.getDistanceToUnloadPosition(vehicle) <= AutoDrive.getMaxTriggerDistance(vehicle)) ) end end diff --git a/scripts/Utils/UtilFuncs.lua b/scripts/Utils/UtilFuncs.lua index 7dec6be3..2868f412 100644 --- a/scripts/Utils/UtilFuncs.lua +++ b/scripts/Utils/UtilFuncs.lua @@ -504,24 +504,58 @@ function AutoDrive:createSplineInterpolationBetween(startNode, endNode) return end - -- TODO: if we have more then one inbound or outbound connections, get the avg. vector - if #startNode.incoming >= 1 and #endNode.out >= 1 and AutoDrive.splineInterpolationUserCurvature >= 0.5 then - local p0 = nil - for _, px in pairs(startNode.incoming) do - p0 = ADGraphManager:getWayPointById(px) - --self.splineInterpolation.p0 = p0 - break + if AutoDrive.splineInterpolationUserCurvature >= 0.5 then + local p0, p3 = AutoDrive:getSplineControlPoints(startNode, endNode) + if p0 ~= nil and p3 ~= nil then + return AutoDrive:createSplineWithControlPoints(startNode, p0, endNode, p3) end - local p3 = nil - for _, px in pairs(endNode.out) do - p3 = ADGraphManager:getWayPointById(px) - --self.splineInterpolation.p3 = p3 - break - end - return AutoDrive:createSplineWithControlPoints(startNode, p0, endNode, p3) - else -- fallback to straight line connection behaviour - return end + -- fallback to straight line connection behaviour +end + +function AutoDrive:getSplineControlPoints(startNode, endNode) + -- Returns control points for the given startNode and endNode + if #startNode.incoming + #startNode.out == 0 then + return nil, nil + end + if #endNode.incoming + #endNode.out == 0 then + return nil, nil + end + + local function getWaypointDirection(node, waypointId) + -- returns unit vector from start/end node to a waypoint + local wp = ADGraphManager:getWayPointById(waypointId) + local wpVec = ADVectorUtils.subtract2D(node, wp) + return ADVectorUtils.unitVector2D(wpVec) + end + + local function getControlPoint(node, otherNode) + -- returns the node that forms the straightest connection (closest to 180 degrees) + local bestAngle, bestDirection = nil, nil + local startEndVec = ADVectorUtils.subtract2D(node, otherNode) + + for _, px in pairs(node.incoming) do + local dir = getWaypointDirection(node, px) + local angle = math.abs(180 - math.abs(AutoDrive.angleBetween(startEndVec, dir))) + if bestAngle == nil or bestAngle > angle then + bestAngle = angle + bestDirection = dir + end + end + for _, px in pairs(node.out) do + local dir = getWaypointDirection(node, px) + local angle = math.abs(180 - math.abs(AutoDrive.angleBetween(startEndVec, dir))) + if bestAngle == nil or bestAngle > angle then + bestAngle = angle + bestDirection = dir + end + end + if bestDirection == nil then + return nil + end + return ADVectorUtils.add2D(node, bestDirection) + end + return getControlPoint(startNode, endNode), getControlPoint(endNode, startNode) end function AutoDrive:createSplineWithControlPoints(startNode, p0, endNode, p3) @@ -550,21 +584,19 @@ function AutoDrive:createSplineWithControlPoints(startNode, p0, endNode, p3) -- distance from start to end, divided by two to give it more roundness... local dStartEnd = ADVectorUtils.distance2D(startNode, endNode) / self.splineInterpolation.curvature - -- we need to normalize the length of p0-start and end-p3, otherwise their length will influence the curve - -- get vector from p0->start - local vp0Start = ADVectorUtils.subtract2D(p0, startNode) - -- calculate unit vector of vp0Start - vp0Start = ADVectorUtils.unitVector2D(vp0Start) + -- we need to normalize the length of start-p0 and end-p3, otherwise their length will influence the curve + -- get vector from start->p0 + local vStartp0 = ADVectorUtils.subtract2D(startNode, p0) + -- calculate unit vector of vStartp0 + vStartp0 = ADVectorUtils.unitVector2D(vStartp0) -- scale it like start->end - vp0Start = ADVectorUtils.scaleVector2D(vp0Start, dStartEnd) - -- invert it - vp0Start = ADVectorUtils.invert2D(vp0Start) + vStartp0 = ADVectorUtils.scaleVector2D(vStartp0, dStartEnd) -- add it to the start Vector so that we get new p0 - p0 = ADVectorUtils.add2D(startNode, vp0Start) + p0 = ADVectorUtils.add2D(startNode, vStartp0) -- make sure p0 has a y value p0.y = startNode.y - -- same for end->p3, except that we do not need to invert it, but just add it to the endNode + -- same for end->p3 local vEndp3 = ADVectorUtils.subtract2D(endNode, p3) vEndp3 = ADVectorUtils.unitVector2D(vEndp3) vEndp3 = ADVectorUtils.scaleVector2D(vEndp3, dStartEnd) @@ -573,12 +605,10 @@ function AutoDrive:createSplineWithControlPoints(startNode, p0, endNode, p3) local prevWP = startNode local secondLastWp = nil - local prevV = ADVectorUtils.subtract2D(p0, startNode) -- we're calculting a VERY smooth curve and whenever the new point on the curve has a good distance to the last one create a new waypoint -- but make sure that the last point also has a good distance to the endNode for i = 1, 200 do local px = AutoDrive:CatmullRomInterpolate(i, p0, startNode, endNode, p3, 200) - local newV = ADVectorUtils.subtract2D(prevWP, px) local distPrev = ADVectorUtils.distance2D(prevWP, px) local distEnd = ADVectorUtils.distance2D(px, endNode) @@ -604,7 +634,6 @@ function AutoDrive:createSplineWithControlPoints(startNode, p0, endNode, p3) secondLastWp = prevWP prevWP = px - prevV = newV end end table.insert(self.splineInterpolation.waypoints, endNode) @@ -693,9 +722,7 @@ end --- @return table Vector function ADVectorUtils.scaleVector2D(vector, scale) scale = scale or 1.0 - vector.x = ( vector.x * scale ) or 0 - vector.z = ( vector.z * scale ) or 0 - return vector + return { x = ( vector.x * scale ) or 0, z = ( vector.z * scale ) or 0 } end --- Returns the distance between zwo vectors using their x and z coordinates. @@ -718,9 +745,7 @@ end --- @param vector table with x and z property --- @return table Vector inverted function ADVectorUtils.invert2D(vector) - vector.x = vector.x * -1 - vector.z = vector.z * -1 - return vector + return {x = vector.x * -1, z = vector.z * -1} end --- Adds x and z values of two given vectors and returns a new vector with x and z properties. @@ -763,7 +788,7 @@ end function AutoDrive.debugMsg(vehicle, debugText, ...) local printText = "[AD] " .. tostring(g_updateLoopIndex) .. " " if vehicle ~= nil then - if vehicle.ad ~= nil and vehicle.ad.stateModule ~= nil then + if vehicle.ad ~= nil and vehicle.ad.stateModule ~= nil and vehicle == vehicle:getRootVehicle() then printText = printText .. vehicle.ad.stateModule:getName() .. ": " elseif vehicle.getName ~= nil then printText = printText .. vehicle:getName() .. ": " diff --git a/textures/input_incLoopCounter_10.dds b/textures/input_incLoopCounter_10.dds deleted file mode 100644 index 6005b465..00000000 Binary files a/textures/input_incLoopCounter_10.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_11.dds b/textures/input_incLoopCounter_11.dds deleted file mode 100644 index cc4e9a28..00000000 Binary files a/textures/input_incLoopCounter_11.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_12.dds b/textures/input_incLoopCounter_12.dds deleted file mode 100644 index d217ead9..00000000 Binary files a/textures/input_incLoopCounter_12.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_13.dds b/textures/input_incLoopCounter_13.dds deleted file mode 100644 index 249a135f..00000000 Binary files a/textures/input_incLoopCounter_13.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_14.dds b/textures/input_incLoopCounter_14.dds deleted file mode 100644 index 0e3ef69b..00000000 Binary files a/textures/input_incLoopCounter_14.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_15.dds b/textures/input_incLoopCounter_15.dds deleted file mode 100644 index 9a652d9e..00000000 Binary files a/textures/input_incLoopCounter_15.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_16.dds b/textures/input_incLoopCounter_16.dds deleted file mode 100644 index 11f43cac..00000000 Binary files a/textures/input_incLoopCounter_16.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_17.dds b/textures/input_incLoopCounter_17.dds deleted file mode 100644 index 2be38e4a..00000000 Binary files a/textures/input_incLoopCounter_17.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_18.dds b/textures/input_incLoopCounter_18.dds deleted file mode 100644 index be2a581d..00000000 Binary files a/textures/input_incLoopCounter_18.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_19.dds b/textures/input_incLoopCounter_19.dds deleted file mode 100644 index 179e5063..00000000 Binary files a/textures/input_incLoopCounter_19.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_2.dds b/textures/input_incLoopCounter_2.dds deleted file mode 100644 index 31556f76..00000000 Binary files a/textures/input_incLoopCounter_2.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_3.dds b/textures/input_incLoopCounter_3.dds deleted file mode 100644 index bb195148..00000000 Binary files a/textures/input_incLoopCounter_3.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_4.dds b/textures/input_incLoopCounter_4.dds deleted file mode 100644 index b504e94e..00000000 Binary files a/textures/input_incLoopCounter_4.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_5.dds b/textures/input_incLoopCounter_5.dds deleted file mode 100644 index 63ccfdc8..00000000 Binary files a/textures/input_incLoopCounter_5.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_6.dds b/textures/input_incLoopCounter_6.dds deleted file mode 100644 index dae46c14..00000000 Binary files a/textures/input_incLoopCounter_6.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_7.dds b/textures/input_incLoopCounter_7.dds deleted file mode 100644 index e9eaeb49..00000000 Binary files a/textures/input_incLoopCounter_7.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_8.dds b/textures/input_incLoopCounter_8.dds deleted file mode 100644 index d493cac1..00000000 Binary files a/textures/input_incLoopCounter_8.dds and /dev/null differ diff --git a/textures/input_incLoopCounter_9.dds b/textures/input_incLoopCounter_9.dds deleted file mode 100644 index 9215a421..00000000 Binary files a/textures/input_incLoopCounter_9.dds and /dev/null differ diff --git a/textures/loop_counter_active.dds b/textures/loop_counter_active.dds new file mode 100644 index 00000000..59fd8414 Binary files /dev/null and b/textures/loop_counter_active.dds differ diff --git a/textures/loop_counter_inactive.dds b/textures/loop_counter_inactive.dds new file mode 100644 index 00000000..862c73ee Binary files /dev/null and b/textures/loop_counter_inactive.dds differ diff --git a/textures/input_incLoopCounter_1.dds b/textures/loop_counter_inf.dds similarity index 100% rename from textures/input_incLoopCounter_1.dds rename to textures/loop_counter_inf.dds diff --git a/translations/translation_br.xml b/translations/translation_br.xml index a2d8b58b..e2984496 100644 --- a/translations/translation_br.xml +++ b/translations/translation_br.xml @@ -56,7 +56,7 @@ <text name="input_AD_devAction" text="AD: Ação Developer" /> <text name="input_ADToggleAutomaticPickupTarget" text="AD: Alternar para coleta automática" /> <text name="input_ADToggleAutomaticUnloadTarget" text="AD: Alternar para descarga automática" /> - <text name="input_ADToggleLoadByFillLevel" text="AD: Toggle loading by fill level" /> + <text name="input_ADToggleLoadByFillLevel" text="AD: alternar para nível de preenchimento" /> <text name="hud_avoidFruit" text="AD: Evitar plantações" /> <text name="hud_startCp" text="AD: Iniciar CP / AIVE no destino" /> <text name="AD_parkVehicle_noPosSet" text="Nenhum destino de estacionamento atribuído." /> @@ -110,6 +110,8 @@ <text name="gui_ad_no" text="Não" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Inicializando" /> <text name="ad_bga_waiting" text="Aguardando carreta/silo" /> <text name="ad_bga_active" text="Ativo" /> @@ -166,6 +168,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Modos: Sem alteração de destino / apenas destino de Coleta / apenas destino de Entrega / destino de Coleta e Entrega na pasta são ciclados (não com pasta padrão) (considerado apenas se as pastas de uso estiverem ativas)" /> <text name="gui_ad_maxTriggerDistance" text="Maximo disância do trigger" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Distância do destino em que os triggers são detectados e ativados." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Luzes piscantes" /> <text name="gui_ad_useBeaconLights_tooltip" text="Sim - Use luzes de sinalização automáticas fora dos campos / Não - as luzes de sinalização não serão ligadas ou desligadas automaticamente" /> <text name="gui_ad_worklightsWhenLoading" text="Luz de aviso ao carregar/descarregar" /> @@ -300,8 +303,13 @@ <text name="ad_color_currentConnection" text="12 linha próximo caminho" /> <text name="ad_color_closestLine" text="13 linha do veículo para o mais próximo waypoint" /> <text name="ad_color_editorHeightLine" text="14 linha do waypoint de superfície para o veículo acima" /> - <text name="ad_color_previewOk" text="15 Visualização da curva OK, nenhuma colisão" /> - <text name="ad_color_previewNotOk" text="16 Visualização da curva não OK, com colisão" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 Visualização da curva OK, nenhuma colisão" /> + <text name="ad_color_previewNotOk" text="20 Visualização da curva não OK, com colisão" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Deletar Todos" /> <text name="button_reset_selected" text="Redefinir selecionado" /> diff --git a/translations/translation_cs.xml b/translations/translation_cs.xml index 49aedfef..96ed7360 100644 --- a/translations/translation_cs.xml +++ b/translations/translation_cs.xml @@ -110,6 +110,8 @@ <text name="gui_ad_no" text="否" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="初始化" /> <text name="ad_bga_waiting" text="等待拖车/筒仓" /> <text name="ad_bga_active" text="活跃" /> @@ -166,6 +168,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4种模式:不更改目标/仅装载目标/仅卸载目标/文件夹中的装载和卸载目标循环(不使用默认文件夹)(仅在使用文件夹处于活动状态时才考虑)" /> <text name="gui_ad_maxTriggerDistance" text="最大触发距离" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="检测和激活目标触发器的距离。" /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="信标灯" /> <text name="gui_ad_useBeaconLights_tooltip" text="是 - 在田地外自动使用信标灯/否 - 信标灯不会自动打开或关闭" /> @@ -303,8 +306,13 @@ <text name="ad_color_closestLine" text="13 从车辆到最近航点的线" /> <text name="ad_color_editorHeightLine" text="14 从地面航删除所有点到上述车辆的线" /> - <text name="ad_color_previewOk" text="15 曲线预览没问题,没有碰撞" /> - <text name="ad_color_previewNotOk" text="16 曲线预览注意,有碰撞" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 曲线预览没问题,没有碰撞" /> + <text name="ad_color_previewNotOk" text="20 曲线预览注意,有碰撞" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="全部删除" /> <text name="button_reset_selected" text="重置选择" /> diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml index 1a0a6f82..76735ce1 100644 --- a/translations/translation_cz.xml +++ b/translations/translation_cz.xml @@ -108,6 +108,8 @@ <text name="gui_ad_no" text="Ne" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Inicializace" /> <text name="ad_bga_waiting" text="Čekám na odvozce/jámu" /> <text name="ad_bga_active" text="Aktivní" /> @@ -166,6 +168,7 @@ <text name="gui_ad_distributeToFolder_tooltip" text="Všechny cíle v jednom adresáři budou použity pro vykládku" /> <text name="gui_ad_maxTriggerDistance" text="Rozsah detekce triggerů" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Rozsah, ve kterém jsou detekovány aktivní triggery (např. osivo a hnojivo)." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Zapnout maják" /> <text name="gui_ad_useBeaconLights_tooltip" text="Použití majáku na silnici" /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -301,8 +304,13 @@ <text name="ad_color_currentConnection" text="12 linie další cesty" /> <text name="ad_color_closestLine" text="13 linie od vozidla k nejbližšímu trasovému bodu" /> <text name="ad_color_editorHeightLine" text="14 linie z povrchového traťového bodu k bodu nad vozidlem" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Smazat všechny" /> <text name="button_reset_selected" text="Resetovat vybrané" /> diff --git a/translations/translation_de.xml b/translations/translation_de.xml index e0e8fb46..6909a75b 100644 --- a/translations/translation_de.xml +++ b/translations/translation_de.xml @@ -116,6 +116,8 @@ <text name="gui_ad_no" text="Nein" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Reichweite" /> + <text name="gui_ad_BSMRange_tooltip" text="In diesem Abstand um das Ziel Bunker Silo wird Fahrzeugen der Reihe nach die Zufahrt gewährt" /> <text name="ad_bga_init" text="Initialisieren" /> <text name="ad_bga_waiting" text="Warten auf Abfahrer/Silo" /> <text name="ad_bga_active" text="Aktiv" /> @@ -172,6 +174,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Modi: kein Wechsel der Ziele / nur Beladeziele / nur Entladeziele / Be- und Entladeziele im Ordner rotierend wechseln (nicht für Standard-Ordner) (und nur wenn Ordner verwenden aktiv)" /> <text name="gui_ad_maxTriggerDistance" text="Maximaler Siloabstand" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Bis zu dieser Entfernung zum Zielpunkt wird beladen/entladen bei erkanntem Trigger." /> + <text name="gui_ad_useGlobalSetting" text="Globale Einstellung benutzen" /> <text name="gui_ad_useBeaconLights" text="Rundumleuchten" /> <text name="gui_ad_useBeaconLights_tooltip" text="Ja - Außerhalb des Felds automatisch eingeschaltet / Nein - Rundumleuchten werden nicht automatisch ein- oder ausgeschaltet" /> <text name="gui_ad_worklightsWhenLoading" text="Arbeitslicht beim Be- und Entladen" /> @@ -212,7 +215,7 @@ <text name="gui_ad_callSecondUnloader" text="Rufe 2. Ablader" /> <text name="gui_ad_callSecondUnloader_tooltip" text="Rufe 2. Ablader wenn der aktuelle Abfahrer das eingestellte Füll Level erreicht hat" /> <text name="gui_ad_followOnlyOnField" text="Abfahrer aufs Feld begrenzen" /> - <text name="gui_ad_followOnlyOnField_tooltip" text="Während dem aktiven Abladen / Häckseln, darf nicht über Feldgrenzen hinausgfahren werden" /> + <text name="gui_ad_followOnlyOnField_tooltip" text="Während dem aktiven Abladen / Häckseln, darf nicht über Feldgrenzen hinausgefahren werden" /> <text name="gui_ad_addSettingsToHUD" text="Mehr Einstellungen im HUD" /> <text name="gui_ad_addSettingsToHUD_tooltip" text="Blendet mehr Knöpfe im HUD ein um direkt Einstellungen vorzunehmen ohne dieses Menü aufzurufen" /> <text name="gui_ad_iconSetToUse" text="Logo Personalisierug" /> @@ -307,8 +310,13 @@ <text name="ad_color_currentConnection" text="12 Pfeil nächster Pfad" /> <text name="ad_color_closestLine" text="13 Linie Fahrzeug <-> naheliegendster Wegpunkt" /> <text name="ad_color_editorHeightLine" text="14 senkrechte Linie Wegpunkt am Boden <-> Wegpunkt über dem Fahrzeug" /> - <text name="ad_color_previewOk" text="15 Kurve Vorschauline OK, kollisionsfrei" /> - <text name="ad_color_previewNotOk" text="16 Kurve Vorschauline hat Kollision" /> + <text name="ad_color_previewSingleConnection" text="15 Kurve Vorschauline OK, Hauptstrecke eine Richtung" /> + <text name="ad_color_previewDualConnection" text="16 Kurve Vorschauline OK, Hauptstrecke zwei Richtungen" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 Kurve Vorschauline OK, Nebenstrecke eine Richtung" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 Kurve Vorschauline OK, Nebenstrecke zwei Richtungen" /> + <text name="ad_color_previewOk" text="19 Kurve Vorschauline OK, kollisionsfrei" /> + <text name="ad_color_previewNotOk" text="20 Kurve Vorschauline hat Kollision" /> + <text name="ad_color_textInputBackground" text="21 Hintergrund Eingabe von Texten, Zielen etc." /> <text name="button_delete_all" text="Alle löschen" /> <text name="button_reset_selected" text="Ausgewählten zurücksetzen" /> diff --git a/translations/translation_en.xml b/translations/translation_en.xml index 8a83806e..2f3a8a95 100644 --- a/translations/translation_en.xml +++ b/translations/translation_en.xml @@ -110,6 +110,8 @@ <text name="gui_ad_no" text="No" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Initializing" /> <text name="ad_bga_waiting" text="Waiting for trailer/silo" /> <text name="ad_bga_active" text="Active" /> @@ -166,6 +168,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Modes: No change of targets / only Pickup Targets / only Deliver Targets / Pickup and Deliver Targets in folder are cycled (not with default folder) (only considered if use folders is active)" /> <text name="gui_ad_maxTriggerDistance" text="Maximum trigger distance" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Distance to target at which triggers are detected and activated." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Beacon lights" /> <text name="gui_ad_useBeaconLights_tooltip" text="Yes - Use beacon lights automatic outside of fields / No - beacon lights will not be turned on or off automatically" /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -289,7 +292,7 @@ <text name="ad_color_singleConnection" text="01 line of single-way connection" /> <text name="ad_color_dualConnection" text="02 line of dual-way connection" /> <text name="ad_color_reverseConnection" text="03 line of reverse connection" /> - <text name="ad_color_default" text="04 waypoint on sinle and reverse connection" /> + <text name="ad_color_default" text="04 waypoint on single and reverse connection" /> <text name="ad_color_subPrioSingleConnection" text="05 line of secondary single-way connection" /> <text name="ad_color_subPrioDualConnection" text="06 line of secondary dual-way connection" /> <text name="ad_color_subPrioNode" text="07 secondary waypoint" /> @@ -300,8 +303,13 @@ <text name="ad_color_currentConnection" text="12 line next path" /> <text name="ad_color_closestLine" text="13 line from vehicle to closest waypoint" /> <text name="ad_color_editorHeightLine" text="14 line from surface waypoint to the one above vehicle" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Delete All" /> <text name="button_reset_selected" text="Reset selected" /> diff --git a/translations/translation_es.xml b/translations/translation_es.xml index be8910e0..43d1c42c 100644 --- a/translations/translation_es.xml +++ b/translations/translation_es.xml @@ -108,6 +108,8 @@ <text name="gui_ad_no" text="No" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Inicializando" /> <text name="ad_bga_waiting" text="Esperando por Remolque/Silo" /> <text name="ad_bga_active" text="Activo" /> @@ -164,6 +166,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 modos: Sin cambio de objetivos/Solo recoger de objetivos/Solo entregar a objetivos/Recoger y entregar a objetivos dentro de la carpeta en bucle (no funciona con la carpeta por defecto) (solo funciona si se activa la opción de usar carpetas)" /> <text name="gui_ad_maxTriggerDistance" text="Distancia máxima al desencadenante" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Distancia a la que se detectan y activan los desencadenantes (por ejemplo, al llegar a un punto de descarga)." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Luces rotativas" /> <text name="gui_ad_useBeaconLights_tooltip" text="Sí: Usa luces rotativas automáticas fuera de los campos/No: Las luces rotativas no se encenderán ni apagarán automáticamente" /> <text name="gui_ad_worklightsWhenLoading" text="Luz de trabajo al Cargar/Descargar" /> @@ -299,8 +302,13 @@ <text name="ad_color_currentConnection" text="12 líneas siguiente ruta" /> <text name="ad_color_closestLine" text="13 líneas desde el vehículo hasta el punto de referencia más cercano" /> <text name="ad_color_editorHeightLine" text="14 línea desde el punto de ruta de superficie hasta el vehículo cercano" /> - <text name="ad_color_previewOk" text="15 vista previa de la curva OK, sin colisión" /> - <text name="ad_color_previewNotOk" text="16 vista previa de la curva no OK, tiene colisión" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 vista previa de la curva OK, sin colisión" /> + <text name="ad_color_previewNotOk" text="20 vista previa de la curva no OK, tiene colisión" /> + <text name="ad_color_textInputBackground" text="21 Fondo para entradas de texto, objetivos, etc." /> <text name="button_delete_all" text="Eliminar todas" /> <text name="button_reset_selected" text="Resetear seleccionados" /> diff --git a/translations/translation_fr.xml b/translations/translation_fr.xml index cefdfe27..50669231 100644 --- a/translations/translation_fr.xml +++ b/translations/translation_fr.xml @@ -110,6 +110,8 @@ <text name="gui_ad_no" text="Non" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Initialisation" /> <text name="ad_bga_waiting" text="En attente de remorque/silo" /> <text name="ad_bga_active" text="Actif" /> @@ -166,6 +168,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Modes: Aucune destination / uniquement les points de collecte / uniquement les points de livraison / les points de collecte et livraison sont choisis alternativement depuis un dossier (désactivé dans le dossier par défaut). Possible uniquement si gestion par dossier activée)" /> <text name="gui_ad_maxTriggerDistance" text="Distance maximum du déclencheur" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Distance de détection du déclencheur au point de destination pour le chargement/déchargement." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Gyrophares" /> <text name="gui_ad_useBeaconLights_tooltip" text="Oui - ils seront allumés automatiquement en dehors des champs / Non - pas d'allumage ou extinction automatique" /> <text name="gui_ad_worklightsWhenLoading" text="Feux de travail pendant le chargement/déchargement" /> @@ -303,8 +306,13 @@ <text name="ad_color_closestLine" text="13 ligne du véhicule vers le point le plus proche" /> <text name="ad_color_editorHeightLine" text="14 ligne entre le point au-dessus du véhicule et celui en surface" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Effacer tout" /> <text name="button_reset_selected" text="Effacer la sélection" /> diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml index 252c5266..3ca72212 100644 --- a/translations/translation_hu.xml +++ b/translations/translation_hu.xml @@ -10,7 +10,7 @@ <text name="input_ADSilomode" text="AD: Módváltás" /> <text name="input_ADPreviousMode" text="AD: Previous mode" /> <text name="input_ADRecord" text="AD: felvétel" /> - <text name="input_ADRecord_Dual" text="AD: Record 2 way route" /> + <text name="input_ADRecord_Dual" text="AD: 2 irányú útvonal rögzítése" /> <text name="input_ADRecord_SubPrio" text="AD: Record secondary route" /> <text name="input_ADRecord_SubPrioDual" text="AD: Record 2 way secondary route route" /> <text name="input_ADSelectTarget" text="AD: Cél választás" /> @@ -40,15 +40,15 @@ <text name="input_ADGoToVehicle" text="AD: Váltás az érkezett járműre" /> <text name="input_ADNameDriver" text="AD: Sofőr elnevezése" /> <text name="input_ADSetDestinationFilter" text="AD: Destination filter" /> - <text name="input_AD_FieldSpeed_up" text="AD: Increase Field Speed" /> - <text name="input_AD_FieldSpeed_down" text="AD: Decrease Field Speed" /> + <text name="input_AD_FieldSpeed_up" text="AD: Szántóföldi sebesség növelése" /> + <text name="input_AD_FieldSpeed_down" text="AD: Szántóföldi sebesség csökkentése" /> <text name="input_ADIncLoopCounter" text="AD: Útvonal ismétlése" /> - <text name="input_ADDecLoopCounter" text="AD: Decrease loop counter" /> + <text name="input_ADDecLoopCounter" text="AD: Körszámláló csökkentése" /> <text name="input_ADParkVehicle" text="AD: Parkolja le a járművet" /> <text name="input_ADSetParkDestination" text="AD: assign 1st Destination for parking" /> - <text name="input_ADRefuelVehicle" text="AD: Refuel vehicle" /> - <text name="input_ADRepairVehicle" text="AD: Repair vehicle" /> - <text name="input_ADbunkerUnloadType" text="AD: Unload to Trailer or BGA" /> + <text name="input_ADRefuelVehicle" text="AD: Jármű tankolása" /> + <text name="input_ADRepairVehicle" text="AD: Jármű javítása" /> + <text name="input_ADbunkerUnloadType" text="AD: Pótkocsiba vagy BGA-ba ürítés" /> <text name="input_ADSwapTargets" text="AD: Cél csere" /> <text name="input_ADStartCP" text="AD: Pass to CP/AIVE" /> <text name="input_ADToggleCP_AIVE" text="AD: Toggle CP/AIVE" /> @@ -57,7 +57,7 @@ <text name="input_ADToggleAutomaticUnloadTarget" text="AD: Toggle automatic unload target" /> <text name="input_ADToggleLoadByFillLevel" text="AD: Toggle loading by fill level" /> <text name="hud_avoidFruit" text="AD: Termény kikerülése" /> - <text name="hud_startCp" text="AD: Start CP / AIVE at destination" /> + <text name="hud_startCp" text="AD: CP / AIVE indítása az úticélnál" /> <text name="AD_parkVehicle_noPosSet" text="Járműnek nincs parkolója. Jobb egérgombbal rendeljen hozzá parkolási helyet." /> <text name="AD_parkVehicle_selected" text="Kiválasztott parkolóhely: " /> <text name="AD_Driver_of" text="Sofőr ki" /> @@ -69,8 +69,8 @@ <text name="AD_No_Trailer" text="Nem találja a pótkocsit" /> <text name="AD_No_Bunker" text="Nem találja a Silót" /> <text name="AD_No_Shovel" text="Nem talál kanalat" /> - <text name="AD_No_Refuel_Station" text="could not find refuel station" /> - <text name="AD_No_Repair_Station" text="could not find repair station for:" /> + <text name="AD_No_Refuel_Station" text="Nem talált töltőállomást" /> + <text name="AD_No_Repair_Station" text="Javítóállomás nem található a következőhöz:" /> <text name="AD_Wrong_Mode_takeover_from_CP" text="Wrong AD Mode to work together with CP" /> <text name="AD_MODE_DRIVETO" text="Sofőr" /> <text name="AD_MODE_DELIVERTO" text="Szállító" /> @@ -89,6 +89,7 @@ <text name="gui_ad_blinkValue" text="Irányjelző bekapcsolása automatikus" /> <text name="gui_ad_blinkValue_tooltip" text="Kormányállás az irányjelző fények automatikus engedélyezéséhez. (0 = az irányjelző fény automatikusan kikapcsol)" /> <text name="gui_ad_pipe_offset" text="Cső eltolás" /> + <text name="gui_ad_pipe_offset_tooltip" text="Útvonal oldalirányú eltolása a kombájnhoz viszonyítva. Pozitív értékek: balra, negatív értékek: jobbra. Nulla érték a cső végénél található. <text name="gui_ad_followDistance" text="Távolság a kombájntól" /> <text name="gui_ad_followDistance_tooltip" text="Távolság ha a kombájnt hátul követi" /> <text name="gui_ad_lookahead_turning" text="Kanyarodási távolság" /> @@ -108,6 +109,8 @@ <text name="gui_ad_no" text="Nem" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Elindítás" /> <text name="ad_bga_waiting" text="Várakozás pótkocsira" /> <text name="ad_bga_active" text="Aktív" /> @@ -164,6 +167,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Modes: A célok nem változnak / csak a felvételi célok / csak a célok kézbesítése / az átvétel és a célok kézbesítése a mappában ciklusosak (nem az alapértelmezett mappával) (csak akkor vehető figyelembe, ha a mappák használata aktív)" /> <text name="gui_ad_maxTriggerDistance" text="Maximális kirakodási távolság" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="A célponttól e távolságig a kirakodás felismerése esetén be- és kirakodás történik" /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Jelző lámpa" /> <text name="gui_ad_useBeaconLights_tooltip" text="Használjon jelzőfényeket az úton." /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -188,8 +192,8 @@ <text name="gui_ad_enterGroupNameText" text="Írja be a mappa nevét:" /> <text name="gui_ad_autoRefuel" text="Automatikus tankolás" /> <text name="gui_ad_autoRefuel_tooltip" text="Ha alacsony az üzemanyagszint, menjen az üzemanyagtöltési célig (közel az üzemanyag kiadóhoz)." /> - <text name="gui_ad_autoRepair" text="Automatic Repairing" /> - <text name="gui_ad_autoRepair_tooltip" text="Drive to workshop destination (close to repair trigger) when wear level is too high." /> + <text name="gui_ad_autoRepair" text="Automatikus javítás" /> + <text name="gui_ad_autoRepair_tooltip" text="Ha a kopási szint túl magas, hajtson egy műhelyhez (javító zónához közel)." /> <text name="gui_ad_filter" text="Szűrő" /> <text name="gui_ad_enterDestinationFilterTitle" text="Célszűrés választás" /> <text name="gui_ad_enterDestinationFilterText" text="Szűrő szöveg bevitel:" /> @@ -214,33 +218,33 @@ <text name="gui_ad_wideHUD" text="Széles HUD" /> <text name="gui_ad_wideHUD_tooltip" text="Használjon széles HUD módot, amely lehetővé teszi még néhány beállítási gombot a HUD-ban" /> <text name="gui_ad_playSounds" text="Sound" /> - <text name="gui_ad_playSounds_tooltip" text="Enables the sound effects for mouse clicks and notifications" /> - <text name="gui_ad_scaleLines" text="Scale Lines" /> - <text name="gui_ad_scaleLines_tooltip" text="Scale Thickness of connection lines" /> + <text name="gui_ad_playSounds_tooltip" text="Engedélyezi a hanghatásokat egérkattintásokhoz és értesítésekhez." /> + <text name="gui_ad_scaleLines" text="Vonalvastagság" /> + <text name="gui_ad_scaleLines_tooltip" text="Összekötő vonalak vastagsága" /> <text name="gui_ad_syncMultiTargets" text="Több cél szinkronizálása" /> <text name="gui_ad_syncMultiTargets_tooltip" text="Több útvonal, amely ugyanazt a mappát használja több célhoz, szinkronizálja a következő célokat" /> <text name="gui_ad_enableParkAtJobFinished" text="Parkolás a végén" /> <text name="gui_ad_enableParkAtJobFinished_tooltip" text="Csak az Átvétel és kézbesítés, kézbesítés módokban érhető el: Ha a munka befejeződött, a jármű / tartozék tárolt parkolási pozíciójába kerül. A Dedi-Server-en csak a jármű parkolóhelye áll rendelkezésre!" /> - <text name="gui_ad_autoTipSide" text="Automatikus hegyoldal" /> - <text name="gui_ad_autoTipSide_tooltip" text="Igen - Az AutoDrive automatikusan kiválasztja a csúcsoldalt / Nem - a már kiválasztott csúcsoldalt fogja használni" /> + <text name="gui_ad_autoTipSide" text="Automatikus billentési oldal" /> + <text name="gui_ad_autoTipSide_tooltip" text="Igen - Az AutoDrive automatikusan kiválasztja a billentési oldalt / Nem - a már kiválasztott billentési oldalt fogja használni" /> <text name="gui_ad_autoTrailerCover" text="Automatikus pótkocsi fedél " /> <text name="gui_ad_autoTrailerCover_tooltip" text="Igen - az AutoDrive szükség esetén nyissa meg és zárja be a pótkocsi fedelét / Nem - az AutoDrive nem nyitja vagy zárja le a pótkocsi fedelét" /> <text name="gui_ad_useForwardTurningManoeuvre" text="Forwards turning manoeuvre" /> <text name="gui_ad_useForwardTurningManoeuvre_tooltip" text="Yes - AutoDrive unloaders try to plan a path forwards to adapt to 90° turns of the combine. / No - Unloaders will reverse before turn" /> - <text name="gui_ad_ALUnload" text="Autoload: Unload Position" /> + <text name="gui_ad_ALUnload" text="Autoload: Kirakodási pozíció" /> <text name="gui_ad_ALUnload_tooltip" text="Off-no automatic unload, center-unload on loading platform, left / right vehicle unload position (Position depend on vehicle setup, not AD!)" /> <text name="gui_ad_AL_off" text="Unload Off" /> - <text name="gui_ad_AL_center" text="Unload center" /> - <text name="gui_ad_AL_left" text="Unload left" /> - <text name="gui_ad_AL_behind" text="Unload behind" /> - <text name="gui_ad_AL_right" text="Unload right" /> - <text name="gui_ad_ALUnloadWaitTime" text="Autoload: wait time after unload" /> - <text name="gui_ad_ALUnloadWaitTime_tooltip" text="Wait time after unloading, before continue to drive - useful for unload center: 0-no wait, wait selected time" /> - <text name="gui_ad_scanConfirmationTextTitle" text="AutoDrive - Network Generation" /> + <text name="gui_ad_AL_center" text="Kirakodás középre" /> + <text name="gui_ad_AL_left" text="Kirakodás balra" /> + <text name="gui_ad_AL_behind" text="Kirakodás hátra" /> + <text name="gui_ad_AL_right" text="Kirakodás jobbra" /> + <text name="gui_ad_ALUnloadWaitTime" text="Autoload: várakozási idő kirakodás után" /> + <text name="gui_ad_ALUnloadWaitTime_tooltip" text="Várakozási idő kirakodás után, továbbhajtás előtt - hasznos a középső kirakodáshoz: 0 - nincs várakozás, várakozás a kiválasztott ideig" /> + <text name="gui_ad_scanConfirmationTextTitle" text="AutoDrive - Hálózat generálás" /> <text name="gui_ad_scanConfirmationText" text="Az AutoDrive generáljon útvonalhálózatot a térképen lévő forgalmi és segédadatokból?" /> - <text name="gui_ad_noHarvesterAvailable" text="No harvester with same target found" /> - <text name="gui_ad_noUnloaderAvailable" text="No driver with same target available" /> - <text name="gui_ad_remainingDriveTimeInterval" text="Remaining Drive time" /> + <text name="gui_ad_noHarvesterAvailable" text="Nem található kombájn azonos úticéllal" /> + <text name="gui_ad_noUnloaderAvailable" text="Sofőr azonos úticéllal nem elérhető" /> + <text name="gui_ad_remainingDriveTimeInterval" text="Maradék vezetési idő" /> <text name="gui_ad_remainingDriveTimeInterval_tooltip" text="For external mods: Interval to calculate the remaining drive time. In case of issues with performance increase or deactivate." /> <text name="gui_ad_settingsPage_title" text="Beállítás - AutoDrive" /> @@ -251,7 +255,7 @@ <text name="gui_ad_eFeaturesSettingsPage_title" text="Kísérleti szolgáltatások beállításai - AutoDrive" /> <text name="gui_ad_environmentSettingsPage_title" text="Non-functional Settings - AutoDrive" /> <text name="gui_ad_restoreButtonText" text="Visszaállítás" /> - <text name="gui_ad_setDefaultButtonText" text="Set as default" /> + <text name="gui_ad_setDefaultButtonText" text="Eredeti beállítás" /> <text name="gui_ad_settingsClosingDialog_title" text="Minden változás elveszik" /> <text name="gui_ad_settingsClosingDialog_text" text="Biztosan bezárja a beállításokat mentés nélkül?" /> <text name="gui_ad_routesManagerTitle" text="Útvonal szerkesztés" /> @@ -295,8 +299,13 @@ <text name="ad_color_currentConnection" text="12 line next path" /> <text name="ad_color_closestLine" text="13 line from vehicle to closest waypoint" /> <text name="ad_color_editorHeightLine" text="14 line from surface waypoint to the one above vehicle" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Összes törlése" /> <text name="button_reset_selected" text="Reset selected" /> @@ -313,7 +322,7 @@ <text name="AD_task_wait_for_combine_turn" text="Kombájnra várás" /> <text name="AD_task_drive_to_load_point" text="Hajtson a rakodási ponthoz" /> <text name="AD_task_drive_to_refuel_point" text="Hajtson az üzemanyagtöltési ponthoz" /> - <text name="AD_task_drive_to_repair_point" text="Drive to repair station" /> + <text name="AD_task_drive_to_repair_point" text="Hajtson egy javító állomáshoz" /> <text name="AD_task_stop_and_disable" text="Megállás" /> <text name="AD_task_drive_to_unload_point" text="Hajtson a kirakodási pontig" /> <text name="AD_task_wait_for_call" text="Hívásra vár" /> @@ -328,7 +337,7 @@ <text name="AD_task_exiting_field" text="Kilépés a fölről" /> <text name="AD_task_reversing_from_collision" text="Tiszta terület keresése" /> <text name="AD_task_drive_to_park" text="Parkolás a területen" /> - <text name="AD_task_unload_area_in_fruit" text="Unload area blocked" /> + <text name="AD_task_unload_area_in_fruit" text="Kirakodási terület blokkolva" /> <text name = "gui_CPAD_off" text = "off"/> <text name = "gui_CPAD_simple" text = "simple"/> diff --git a/translations/translation_it.xml b/translations/translation_it.xml index 33e4749c..6bd4202c 100644 --- a/translations/translation_it.xml +++ b/translations/translation_it.xml @@ -108,6 +108,8 @@ <text name="gui_ad_no" text="No" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Inizializzazione" /> <text name="ad_bga_waiting" text="In attesa del rimorchio/Silos" /> <text name="ad_bga_active" text="Attivo" /> @@ -166,6 +168,7 @@ <text name="gui_ad_distributeToFolder_tooltip" text="Tutte le destinazioni nella stessa cartella verranno ruotate come destinazioni di scarico." /> <text name="gui_ad_maxTriggerDistance" text="Distanza massima dal trigger" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Distanza dall'obiettivo in cui i trigger vengono rilevati e attivati." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Accendi Fari" /> <text name="gui_ad_useBeaconLights_tooltip" text="Usa i fari sulla strada." /> <text name="gui_ad_worklightsWhenLoading" text="Faro da lavoro durante carico/scarico" /> @@ -302,8 +305,13 @@ <text name="ad_color_currentConnection" text="12 Linea percorso successivo" /> <text name="ad_color_closestLine" text="13 Linea dal veicolo al nodo più vicino" /> <text name="ad_color_editorHeightLine" text="14 Linea dal nodo di superficie a quello sopra il veicolo" /> - <text name="ad_color_previewOk" text="15 Anteprima svolte Ok, nessuna collisione" /> - <text name="ad_color_previewNotOk" text="16 Anteprima svolte non ok, ce collisione" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 Anteprima svolte Ok, nessuna collisione" /> + <text name="ad_color_previewNotOk" text="20 Anteprima svolte non ok, ce collisione" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Cancella Tutto" /> <text name="button_reset_selected" text="Ripristina selezionato" /> diff --git a/translations/translation_nl.xml b/translations/translation_nl.xml index 92e28d27..b50a3eb4 100644 --- a/translations/translation_nl.xml +++ b/translations/translation_nl.xml @@ -110,6 +110,8 @@ <text name="gui_ad_no" text="Nee" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Initialiseren" /> <text name="ad_bga_waiting" text="Wachten op aanhanger/silo" /> <text name="ad_bga_active" text="Actief" /> @@ -168,6 +170,7 @@ <text name="gui_ad_distributeToFolder_tooltip" text="Alle bestemmingen in dezelfde map worden geroteerd als aflever bestemming." /> <text name="gui_ad_maxTriggerDistance" text="Maximale trigger afstand" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Afstand tot aflever/ophaal bestemming waar de trigger wordt gevonden en geactiveerd." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Zwaailichten" /> <text name="gui_ad_useBeaconLights_tooltip" text="Gebruik zwaailampen buiten de velden." /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -303,8 +306,13 @@ <text name="ad_color_currentConnection" text="12 lijn volgend pad" /> <text name="ad_color_closestLine" text="13 lijn van voertuig naar dichtstbijzijnde routepunt" /> <text name="ad_color_editorHeightLine" text="14 lijn van oppervlakte routepunt naar degene boven het voertuig" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Alles verwijderen" /> <text name="button_reset_selected" text="Geselecteerde terugzetten" /> diff --git a/translations/translation_pl.xml b/translations/translation_pl.xml index d1a2dcaf..e71d3ea4 100644 --- a/translations/translation_pl.xml +++ b/translations/translation_pl.xml @@ -111,6 +111,8 @@ <text name="gui_ad_no" text="Nie" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Inicjowanie" /> <text name="ad_bga_waiting" text="Oczekiwanie na przyczepę/silos" /> <text name="ad_bga_active" text="Aktywny" /> @@ -167,6 +169,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Tryby: Bez zmiany celów / tylko cele odbioru / tylko cele dostarczania / Cele odbioru i dostarczania w folderze są kolejno przełączane (nie w folderze domyślnym) (działa tylko przy wykorzystywaniu folderów)" /> <text name="gui_ad_maxTriggerDistance" text="Maksymalna odległość do triggerów" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Odległość do celów, przy której są wykrywane i aktywowane triggery." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Światła ostrzegawcze" /> <text name="gui_ad_useBeaconLights_tooltip" text="Używaj świateł ostrzegawczych na drodze." /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -302,8 +305,13 @@ <text name="ad_color_currentConnection" text="12 linia kierunku jazdy" /> <text name="ad_color_closestLine" text="13 linia od pojazdu do najbliższego punktu" /> <text name="ad_color_editorHeightLine" text="14 linia od punktu na ziemi do punktu nad pojazdem" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Usuń wszystkie" /> <text name="button_reset_selected" text="Zresetuj wybrane" /> diff --git a/translations/translation_pt.xml b/translations/translation_pt.xml index bafd3295..cde53af4 100644 --- a/translations/translation_pt.xml +++ b/translations/translation_pt.xml @@ -108,6 +108,8 @@ <text name="gui_ad_no" text="Não" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Inicializando" /> <text name="ad_bga_waiting" text="À espera de reboque / silo" /> <text name="ad_bga_active" text="Activo" /> @@ -166,6 +168,7 @@ <text name="gui_ad_distributeToFolder_tooltip" text="Todos os destinos na mesma pasta serão girados como destinos de descarregamento." /> <text name="gui_ad_maxTriggerDistance" text="Distância máxima de gatilho" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Distância ao alvo em que os gatilhos são detectados e ativados." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Pirilampos" /> <text name="gui_ad_useBeaconLights_tooltip" text="Use pirilampos na estrada." /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -301,8 +304,13 @@ <text name="ad_color_currentConnection" text="12 line next path" /> <text name="ad_color_closestLine" text="13 line from vehicle to closest waypoint" /> <text name="ad_color_editorHeightLine" text="14 line from surface waypoint to the one above vehicle" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Eliminar tudo" /> <text name="button_reset_selected" text="Reset selected" /> diff --git a/translations/translation_ru.xml b/translations/translation_ru.xml index c2bc7626..22fc164e 100644 --- a/translations/translation_ru.xml +++ b/translations/translation_ru.xml @@ -54,9 +54,9 @@ <text name="input_ADStartCP" text="AD: Передать управление CP/AIVE" /> <text name="input_ADToggleCP_AIVE" text="AD: Переключение CP/AIVE" /> <text name="input_AD_devAction" text="AD: Действия разработчика" /> - <text name="input_ADToggleAutomaticPickupTarget" text="AD: Переключать автоматически цели подбора" /> + <text name="input_ADToggleAutomaticPickupTarget" text="AD: Переключать автоматически цели загрузки" /> <text name="input_ADToggleAutomaticUnloadTarget" text="AD: Переключать автоматически цели разгрузки" /> - <text name="input_ADToggleLoadByFillLevel" text="AD: Toggle loading by fill level" /> + <text name="input_ADToggleLoadByFillLevel" text="AD: Переключение загрузки по уровню заполнения" /> <text name="hud_avoidFruit" text="AD: Избегать посевов" /> <text name="hud_startCp" text="AD: Запустить CP/AIVE в пункте назначения" /> <text name="AD_parkVehicle_noPosSet" text="Место для парковки не назначено. Чтобы назначить выбранную локацию, как место парковки, нажмите правой кнопкой мыши на этой же кнопке." /> @@ -110,6 +110,8 @@ <text name="gui_ad_no" text="Нет" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Инициализация" /> <text name="ad_bga_waiting" text="В ожидании прицепа/бункера" /> <text name="ad_bga_active" text="Активно" /> @@ -166,6 +168,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 режима: не менять локации/ только локации Загрузок/ только локации Доставок/ менять циклически в папке локации Загрузок и Доставок (не для стандартных папок) (учитывается при активации 'Использовать папки')." /> <text name="gui_ad_maxTriggerDistance" text="Макс. расстояние триггера" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Расстояние до локации, на котором обнаруживаются и активируются триггеры." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Маячок" /> <text name="gui_ad_useBeaconLights_tooltip" text="Да - использовать автоматические сигнальные огни за пределами полей / Нет - сигнальные огни не будут включаться или выключаться автоматически." /> <text name="gui_ad_worklightsWhenLoading" text="Рабочий свет при загрузке/разгрузке" /> @@ -300,8 +303,13 @@ <text name="ad_color_currentConnection" text="12 линия планируемого пути" /> <text name="ad_color_closestLine" text="13 линия от техники до ближайшей путевой точки" /> <text name="ad_color_editorHeightLine" text="14 линия от поверхности путевой точки к точке над техникой " /> - <text name="ad_color_previewOk" text="15 предпросмотр кривой OK, нет преград" /> - <text name="ad_color_previewNotOk" text="16 предпросмотр кривой не OK, есть преграды" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 предпросмотр кривой OK, нет преград" /> + <text name="ad_color_previewNotOk" text="20 предпросмотр кривой не OK, есть преграды" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Удалить все" /> <text name="button_reset_selected" text="Сбросить выбранное" /> diff --git a/translations/translation_tr.xml b/translations/translation_tr.xml index 4737e928..bbb2e135 100644 --- a/translations/translation_tr.xml +++ b/translations/translation_tr.xml @@ -108,6 +108,8 @@ <text name="gui_ad_no" text="Hayır" /> <text name="gui_ad_FS22" text="FS 22" /> <text name="gui_ad_FS19" text="FS 19" /> + <text name="gui_ad_BSMRange" text="Bunker Silo Manager Range" /> + <text name="gui_ad_BSMRange_tooltip" text="In this range vehicles to destination bunker silo one by one get driveway" /> <text name="ad_bga_init" text="Başlatılıyor" /> <text name="ad_bga_waiting" text="Treyler / silo bekleniyor" /> <text name="ad_bga_active" text="Aktif" /> @@ -164,6 +166,7 @@ <text name="gui_ad_rotateTargets_tooltip" text="4 Mod: Hedeflerde değişiklik yok / yalnızca Toplama Hedefleri / yalnızca Hedefleri Teslim Et / Klasördeki Alım ve Teslim Hedefleri döngü halinde (varsayılan klasörle değil) (yalnızca klasörleri kullan etkinse dikkate alınır)" /> <text name="gui_ad_maxTriggerDistance" text="Maksimum tetik mesafesi" /> <text name="gui_ad_maxTriggerDistance_tooltip" text="Tetikleyicilerin algılandığı ve etkinleştirildiği hedefe olan mesafe." /> + <text name="gui_ad_useGlobalSetting" text="Use global setting" /> <text name="gui_ad_useBeaconLights" text="Uyarı ışıkları" /> <text name="gui_ad_useBeaconLights_tooltip" text="Evet - Alanların dışında otomatik olarak uyarı ışıkları kullan / Hayır - uyarı ışıkları otomatik olarak açılmayacak veya kapanmayacak" /> <text name="gui_ad_worklightsWhenLoading" text="Worklight when Loading / Unloading" /> @@ -299,8 +302,13 @@ <text name="ad_color_currentConnection" text="12 line next path" /> <text name="ad_color_closestLine" text="13 line from vehicle to closest waypoint" /> <text name="ad_color_editorHeightLine" text="14 line from surface waypoint to the one above vehicle" /> - <text name="ad_color_previewOk" text="15 curve preview OK, no collision" /> - <text name="ad_color_previewNotOk" text="16 curve preview NotOK, has collision" /> + <text name="ad_color_previewSingleConnection" text="15 curve preview OK, single-way connection" /> + <text name="ad_color_previewDualConnection" text="16 curve preview OK, dual-way connection" /> + <text name="ad_color_previewSubPrioSingleConnection" text="17 curve preview OK, secondary single-way connection" /> + <text name="ad_color_previewSubPrioDualConnection" text="18 curve preview OK, secondary dual-way connection" /> + <text name="ad_color_previewOk" text="19 curve preview OK, no collision" /> + <text name="ad_color_previewNotOk" text="20 curve preview NotOK, has collision" /> + <text name="ad_color_textInputBackground" text="21 Background for inputs of text, targets etc." /> <text name="button_delete_all" text="Hepsini sil" /> <text name="button_reset_selected" text="Reset selected" />