LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

IngameMapElement

Description
In-game map element. Controls input on the map in the in-game menu with objectives, vehicles, etc. The actual map rendering is deferred to the map component of the current mission. The map reference and terrain size must be set during mission initialization via the setIngameMap() and setTerrainSize() methods.
Parent
GuiElement
XML Configuration Parameters
GuiElement#cursorIdstring ID of element to use as a cursor on the map.
GuiElement#mapAlphafloat Transparency value of the map display, defaults to 1. Range is [0=invisible, 1=opaque].
GuiElement#onDrawPreIngameMapcallback [optional] onDrawPreIngameMap(element) Called before the map is drawn. Receives this element.
GuiElement#onDrawPostIngameMapcallback [optional] onDrawPostIngameMap(element) Called after the map is drawn. Receives this element.
GuiElement#onDrawPostIngameMapHotspotscallback [optional] onDrawPostIngameMapHotspots(element) Called after map markers are drawn. Receives this element.
GuiElement#onClickHotspotcallback [optional] onClickHotspot(element, hotspot) Called when a marker is clicked / activated. Receives this element and the clicked hotspot (as defined in missions).
GuiElement#onClickMapcallback [optional] onClickMap(element, worldX, worldY) Called when the map itself is clicked / activated. Receives this element and the world space X and Z coordinates of the clicked point.

Functions

addCursorDeadzone

Description
Add a dead zone wherein the map will not react to cursor inputs. Used this to designate areas where other controls should receive cursor input which would otherwise be used up by the map (e.g. in full-screen mode in the map overview screen in-game). The deadzones will also restrict cursor movement.
Definition
addCursorDeadzone()
Code
145function IngameMapElement:addCursorDeadzone(screenX, screenY, width, height)
146 table.insert(self.cursorDeadzones, {screenX, screenY, width, height})
147end

checkAndResetMouse

Description
Check if mouse input was active before a bound input was triggered and queue a reset of the mouse state for the next frame. Mouse input continuously sets the mouse input flag (self.useMouse) but does not receive any events when the mouse is inert. Therefore we need to set and reset the state each frame to make sure we can seamlessly switch between mouse and gamepad input on the map element while at the same time preventing any player bindings from interfering with the custom mouse input logic of this class.
Definition
checkAndResetMouse()
Code
584function IngameMapElement:checkAndResetMouse()
585 local useMouse = self.useMouse
586 if useMouse then
587 self.resetMouseNextFrame = true
588 end
589
590 return useMouse
591end

clearCursorDeadzones

Description
Clear cursor dead zones.
Definition
clearCursorDeadzones()
Code
151function IngameMapElement:clearCursorDeadzones()
152 self.cursorDeadzones = {}
153end

copyAttributes

Description
Definition
copyAttributes()
Code
113function IngameMapElement:copyAttributes(src)
114 IngameMapElement:superClass().copyAttributes(self, src)
115
116 self.mapZoom = src.mapZoom
117 self.mapAlpha = src.mapAlpha
118 self.cursorId = src.cursorId
119 self.onDrawPreIngameMapCallback = src.onDrawPreIngameMapCallback
120 self.onDrawPostIngameMapCallback = src.onDrawPostIngameMapCallback
121 self.onDrawPostIngameMapHotspotsCallback = src.onDrawPostIngameMapHotspotsCallback
122 self.onClickHotspotCallback = src.onClickHotspotCallback
123 self.onClickMapCallback = src.onClickMapCallback
124end

delete

Description
Definition
delete()
Code
81function IngameMapElement:delete()
82 GuiOverlay.deleteOverlay(self.overlay)
83 self.ingameMap = nil
84
85 IngameMapElement:superClass().delete(self)
86end

draw

Description
Definition
draw()
Code
358function IngameMapElement:draw()
359 local leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached = self.ingameMap:updateMapHeightZoomFactor()
360
361 self:raiseCallback("onDrawPreIngameMapCallback", self, self.ingameMap)
362 self.ingameMap:drawMap(self.mapAlpha)
363 self:raiseCallback("onDrawPostIngameMapCallback", self, self.ingameMap)
364
365 local showNames = self.mapZoom >= IngameMapElement.MAP_ZOOM_SHOW_NAMES
366 local minimalHotspotSize = self.minimalHotspotSize / self.mapZoom
367
368 self.ingameMap:renderHotspots(leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached, false, showNames, minimalHotspotSize, true)
369 self.ingameMap:drawOtherPlayerArrows(showNames, leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached)
370
371 self.ingameMap:drawEnterableArrows(showNames, leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached)
372
373 -- render hotspots that appear on top of player arrows
374 self.ingameMap:renderHotspots(leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached, true, showNames, minimalHotspotSize, true)
375
376 if self.ingameMap.selectedHotspot ~= nil then
377 self.ingameMap:drawHotspot(self.ingameMap.selectedHotspot, leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached, showNames, true)
378 end
379
380 self.ingameMap:updatePlayerArrow(false, leftBorderReached, rightBorderReached, topBorderReached, bottomBorderReached)
381 self.ingameMap:drawPlayerArrow()
382
383 self:raiseCallback("onDrawPostIngameMapHotspots", self, self.ingameMap)
384
385 IngameMapElement:superClass().draw(self)
386end

getElementSize

Description
Definition
getElementSize()
Code
318function IngameMapElement:getElementSize()
319 local width = 1 * self.mapZoom
320
321 -- Always square so just use aspect ratio
322 return width, width * g_screenAspectRatio
323end

getLocalPosition

Description
Definition
getLocalPosition()
Code
460function IngameMapElement:getLocalPosition(posX, posY)
461 if posX == nil then printCallstack() end
462 return MathUtil.clamp((posX - self.absPosition[1]) / self.size[1], 0, 1),
463 MathUtil.clamp((posY - self.absPosition[2]) / self.size[2], 0, 1)
464end

getLocaPointerTarget

Description
Definition
getLocaPointerTarget()
Code
241function IngameMapElement:getLocaPointerTarget()
242 if self.useMouse then
243 return self:getLocalPosition(self.lastMousePosX, self.lastMousePosY)
244 elseif self.cursorElement then
245 local posX = self.cursorElement.absPosition[1] + self.cursorElement.size[1] * 0.5
246 local posY = self.cursorElement.absPosition[2] + self.cursorElement.size[2] * 0.5
247
248 return self:getLocalPosition(posX, posY)
249 end
250
251 return 0, 0
252end

isCursorInDeadzones

Description
Check if a cursor position is within one of the stored deadzones.
Definition
isCursorInDeadzones()
Code
157function IngameMapElement:isCursorInDeadzones(cursorScreenX, cursorScreenY)
158 for _, zone in pairs(self.cursorDeadzones) do
159 if GuiUtils.checkOverlayOverlap(cursorScreenX, cursorScreenY, zone[1], zone[2], zone[3], zone[4]) then
160 return true
161 end
162 end
163
164 return false
165end

isPointVisible

Description
Definition
isPointVisible()
Code
504function IngameMapElement:isPointVisible(x, z)
505end

loadFromXML

Description
Definition
loadFromXML()
Code
90function IngameMapElement:loadFromXML(xmlFile, key)
91 IngameMapElement:superClass().loadFromXML(self, xmlFile, key)
92
93 self.cursorId = getXMLString(xmlFile, key.."#cursorId")
94 self.mapAlpha = getXMLFloat(xmlFile, key .. "#mapAlpha") or self.mapAlpha
95
96 self:addCallback(xmlFile, key.."#onDrawPreIngameMap", "onDrawPreIngameMapCallback")
97 self:addCallback(xmlFile, key.."#onDrawPostIngameMap", "onDrawPostIngameMapCallback")
98 self:addCallback(xmlFile, key.."#onDrawPostIngameMapHotspots", "onDrawPostIngameMapHotspotsCallback")
99 self:addCallback(xmlFile, key.."#onClickHotspot", "onClickHotspotCallback")
100 self:addCallback(xmlFile, key.."#onClickMap", "onClickMapCallback")
101end

loadProfile

Description
Definition
loadProfile()
Code
105function IngameMapElement:loadProfile(profile, applyProfile)
106 IngameMapElement:superClass().loadProfile(self, profile, applyProfile)
107
108 self.mapAlpha = profile:getNumber("mapAlpha", self.mapAlpha)
109end

localToWorldPos

Description
Definition
localToWorldPos()
Code
476function IngameMapElement:localToWorldPos(localPosX, localPosY)
477 local worldPosX = localPosX * self.terrainSize
478 local worldPosZ = -localPosY * self.terrainSize
479
480 -- move world positions to range -1024 to 1024 on a 2k map
481 worldPosX = worldPosX - self.terrainSize * 0.5
482 worldPosZ = worldPosZ + self.terrainSize * 0.5
483
484 return worldPosX, worldPosZ
485end

mouseEvent

Description
Custom mouse event handling for the in-game map. Directly handles zoom, click and drag events on the map. See input events and IngameMapElement:checkAndResetMouse() for the state checking code required to bypass player mouse input bindings.
Definition
mouseEvent()
Code
171function IngameMapElement:mouseEvent(posX, posY, isDown, isUp, button, eventUsed)
172 if self:getIsActive() then
173 eventUsed = IngameMapElement:superClass().mouseEvent(self, posX, posY, isDown, isUp, button, eventUsed)
174
175 if not GS_IS_CONSOLE_VERSION and (isDown or isUp or posX ~= self.lastMousePosX or posY ~= self.lastMousePosY) then
176 self.useMouse = true
177
178 if self.cursorElement then
179 self.cursorElement:setVisible(false)
180 end
181 end
182
183 if not eventUsed and GuiUtils.checkOverlayOverlap(posX, posY, self.absPosition[1], self.absPosition[2], self.size[1], self.size[2]) then
184 if isDown and button == Input.MOUSE_BUTTON_LEFT and not self:isCursorInDeadzones(posX, posY) then
185 eventUsed = true
186 if not self.mouseDown then
187 self.mouseDown = true
188 end
189 end
190 end
191
192 if self.mouseDown and self.lastMousePosX ~= nil then
193 local distX = self.lastMousePosX - posX
194 local distY = posY - self.lastMousePosY
195
196 if math.abs(distX) > self.minDragDistanceX or math.abs(distY) > self.minDragDistanceY then
197 local factorX = -distX
198 local factorY = distY
199
200 self:moveCenter(factorX, factorY)
201
202 self.hasDragged = true
203 end
204 end
205
206 if isUp and button == Input.MOUSE_BUTTON_LEFT then
207 if not eventUsed and self.mouseDown and not self.hasDragged then
208 local localX, localY = self:getLocalPosition(posX, posY)
209
210 self:onClickMap(localX, localY)
211
212 -- Trigger hot spot selection after map clicking because it's the more specific event
213 self:selectHotspotAt(posX, posY)
214
215 eventUsed = true
216 end
217
218 self.mouseDown = false
219 self.hasDragged = false
220 end
221
222 self.lastMousePosX = posX
223 self.lastMousePosY = posY
224 end
225
226 return eventUsed
227end

moveCenter

Description
Move center of the map
Definition
moveCenter()
Code
231function IngameMapElement:moveCenter(x, y)
232 local width, height = self:getElementSize()
233
234 -- If the center never moves further away than half the size, the borders will never pass the center
235 self.mapCenterX = MathUtil.clamp(self.mapCenterX + x, width * -0.5, width * 0.5)
236 self.mapCenterY = MathUtil.clamp(self.mapCenterY + y, height * -0.5, height * 0.5)
237end

new

Description
Definition
new()
Code
35function IngameMapElement:new(target, custom_mt)
36 local self = GuiElement:new(target, custom_mt or IngameMapElement_mt)
37
38 self.ingameMap = nil
39
40 -- cursor
41 self.cursorId = nil
42
43 self.inputMode = GS_INPUT_HELP_MODE_GAMEPAD
44
45 -- map attributes
46 self.terrainSize = 0
47 self.mapAlpha = 1
48 self.zoomMin = 0.4
49 self.zoomMax = 2
50 self.zoomDefault = 1
51
52 self.mapCenterX = 0
53 self.mapCenterY = 0
54
55 self.mapZoom = self.zoomDefault
56
57 -- horizontal cursor input since last frame
58 self.accumHorizontalInput = 0
59 -- vertical cursor input since last frame
60 self.accumVerticalInput = 0
61 -- zoom input since last frame
62 self.accumZoomInput = 0
63 -- mouse input flag to override potential double binding on cursor movement
64 self.useMouse = false
65 -- reset flag for mouse input flag to avoid catching input in the current frame
66 self.resetMouseNextFrame = false
67 -- screen space rectangle definitions {x, y, w, h} where the cursor/mouse should not go and react to input
68 self.cursorDeadzones = {}
69
70 self.minDragDistanceX = IngameMapElement.DRAG_START_DISTANCE / g_screenWidth
71 self.minDragDistanceY = IngameMapElement.DRAG_START_DISTANCE / g_screenHeight
72 self.hasDragged = false -- drag state flag to avoid triggering a click event on a dragging mouse up
73
74 self.minimalHotspotSize = getNormalizedScreenValues(9, 1)
75
76 return self
77end

onAccept

Description
Event function for gamepad cursor accept input bound to InputAction.INGAMEMAP_ACCEPT.
Definition
onAccept()
Code
556function IngameMapElement:onAccept()
557 if self.cursorElement then
558 local posX, posY = self.cursorElement.absPosition[1], self.cursorElement.absPosition[2]
559 local localX, localY = self:getLocaPointerTarget()
560
561 self:onClickMap(localX, localY)
562 -- trigger hot spot selection after map clicking because it's the more specific event
563 self:selectHotspotAt(posX, posY)
564 end
565end

onClickMap

Description
Definition
onClickMap()
Code
468function IngameMapElement:onClickMap(localPosX, localPosY)
469 local worldPosX, worldPosZ = self:localToWorldPos(localPosX, localPosY)
470
471 self:raiseCallback("onClickMapCallback", self, worldPosX, worldPosZ)
472end

onClose

Description
Definition
onClose()
Code
406function IngameMapElement:onClose()
407 IngameMapElement:superClass().onClose(self)
408
409 self:removeActionEvents()
410
411 self.ingameMap:setFullscreen(false)
412 self.ingameMap:resetSettings()
413end

onGuiSetupFinished

Description
Definition
onGuiSetupFinished()
Code
128function IngameMapElement:onGuiSetupFinished()
129 IngameMapElement:superClass().onGuiSetupFinished(self)
130
131 if self.cursorId ~= nil then
132 if self.target[self.cursorId] ~= nil then
133 self.cursorElement = self.target[self.cursorId]
134 else
135 print("Warning: CursorId '"..self.cursorId.."' not found for '"..self.target.name.."'!")
136 end
137 end
138end

onHorizontalCursorInput

Description
Event function for horizontal cursor input bound to InputAction.AXIS_LOOK_LEFTRIGHT_VEHICLE.
Definition
onHorizontalCursorInput()
Code
540function IngameMapElement:onHorizontalCursorInput(_, inputValue)
541 if not self:checkAndResetMouse() then
542 self.accumHorizontalInput = self.accumHorizontalInput + inputValue
543 end
544end

onOpen

Description
Definition
onOpen()
Code
390function IngameMapElement:onOpen()
391 IngameMapElement:superClass().onOpen(self)
392
393 if self.cursorElement ~= nil then
394 self.cursorElement:setVisible(false)
395 end
396
397 if self.largestSize == nil then
398 self.largestSize = self.size
399 end
400
401 self.ingameMap:setFullscreen(true)
402end

onVerticalCursorInput

Description
Event function for vertical cursor input bound to InputAction.AXIS_LOOK_UPDOWN_VEHICLE.
Definition
onVerticalCursorInput()
Code
548function IngameMapElement:onVerticalCursorInput(_, inputValue)
549 if not self:checkAndResetMouse() then
550 self.accumVerticalInput = self.accumVerticalInput + inputValue
551 end
552end

onZoomInput

Description
Event function for map zoom input bound to InputAction.AXIS_ACCELERATE_VEHICLE and InputAction.AXIS_BRAKE_VEHICLE.
Definition
onZoomInput(inputValue Zoom, direction Zoom)
Arguments
inputValueZoominput value
directionZoominput sign value, 1 for zoom in, -1 for zoom out
Code
571function IngameMapElement:onZoomInput(_, inputValue, direction)
572 if not self:checkAndResetMouse() then
573 self.accumZoomInput = self.accumZoomInput + direction * inputValue
574 end
575end

registerActionEvents

Description
Register non-GUI input action events.
Definition
registerActionEvents()
Code
524function IngameMapElement:registerActionEvents()
525 g_inputBinding:registerActionEvent(InputAction.AXIS_LOOK_LEFTRIGHT_VEHICLE, self, self.onHorizontalCursorInput, false, false, true, true)
526 g_inputBinding:registerActionEvent(InputAction.AXIS_LOOK_UPDOWN_VEHICLE, self, self.onVerticalCursorInput, false, false, true, true)
527 g_inputBinding:registerActionEvent(InputAction.INGAMEMAP_ACCEPT, self, self.onAccept, false, true, false, true)
528 g_inputBinding:registerActionEvent(InputAction.AXIS_ACCELERATE_VEHICLE, self, self.onZoomInput, false, false, true, true, -1) -- -1 == zoom in
529 g_inputBinding:registerActionEvent(InputAction.AXIS_BRAKE_VEHICLE, self, self.onZoomInput, false, false, true, true, 1) -- 1 == zoom out
530end

removeActionEvents

Description
Remove non-GUI input action events.
Definition
removeActionEvents()
Code
534function IngameMapElement:removeActionEvents()
535 g_inputBinding:removeActionEventsByTarget(self)
536end

reset

Description
Definition
reset()
Code
417function IngameMapElement:reset()
418 IngameMapElement:superClass().reset(self)
419
420 self.mapCenterX = 0
421 self.mapCenterY = 0
422 self.mapZoom = 1
423
424 self.ingameMap:resetSettings()
425end

resetFrameInputState

Description
Definition
resetFrameInputState()
Code
346function IngameMapElement:resetFrameInputState()
347 self.accumZoomInput = 0
348 self.accumHorizontalInput = 0
349 self.accumVerticalInput = 0
350 if self.resetMouseNextFrame then
351 self.useMouse = false
352 self.resetMouseNextFrame = false
353 end
354end

selectHotspotAt

Description
Definition
selectHotspotAt()
Code
447function IngameMapElement:selectHotspotAt(posX, posY)
448 for _, hotspot in pairs(self.ingameMap.hotspots) do
449 if self.ingameMap.filter[hotspot.category] and hotspot.visible and hotspot.category ~= MapHotspot.CATEGORY_FIELD_DEFINITION and hotspot.category ~= MapHotspot.CATEGORY_COLLECTABLE and hotspot:getIsActive() then
450 if GuiUtils.checkOverlayOverlap(posX, posY, hotspot.x, hotspot.y, hotspot:getWidth(), hotspot:getHeight(), nil) then
451 self:raiseCallback("onClickHotspotCallback", self, hotspot)
452 break
453 end
454 end
455 end
456end

setIngameMap

Description
Set the IngameMap reference to use for display.
Definition
setIngameMap()
Code
509function IngameMapElement:setIngameMap(ingameMap)
510 self.ingameMap = ingameMap
511end

setMapFocusToHotspot

Description
Definition
setMapFocusToHotspot()
Code
489function IngameMapElement:setMapFocusToHotspot(hotspot)
490 if hotspot ~= nil then
491 local objectX = (hotspot.xMapPos + self.ingameMap.worldCenterOffsetX) / self.ingameMap.worldSizeX
492 local objectZ = (hotspot.zMapPos + self.ingameMap.worldCenterOffsetZ) / self.ingameMap.worldSizeZ
493
494 -- This function is only used to cycle for visible hotspots. So we only need to check the 'visible' does not overlap deadzones
495 if self:isCursorInDeadzones(objectX, objectZ) then
496 self.ingameMapCenterX = MathUtil.clamp(objectX, 0 + self.ingameMap.mapVisWidth * 0.5, 1 - self.ingameMap.mapVisWidth * 0.5)
497 self.ingameMapCenterY = MathUtil.clamp(objectZ, 0 + self.ingameMap.mapVisHeight * 0.5, 1 - self.ingameMap.mapVisHeight * 0.5)
498 end
499 end
500end

setTerrainSize

Description
Set the current map's terrain size for map display.
Definition
setTerrainSize()
Code
515function IngameMapElement:setTerrainSize(terrainSize)
516 self.terrainSize = terrainSize
517end

update

Description
Definition
update()
Code
290function IngameMapElement:update(dt)
291 IngameMapElement:superClass().update(self, dt)
292
293 self.inputMode = g_inputBinding:getLastInputMode()
294
295 if not g_gui:getIsDialogVisible() then
296 if not self.alreadyClosed then
297 local zoomFactor = MathUtil.clamp(self.accumZoomInput, -1, 1)
298
299 if zoomFactor ~= 0 then
300 self:zoom(zoomFactor * -0.015 * dt)
301 end
302
303 if self.cursorElement ~= nil then
304 self.cursorElement:setVisible(self.inputMode == GS_INPUT_HELP_MODE_GAMEPAD)
305 self:updateCursor(self.accumHorizontalInput, -self.accumVerticalInput, dt)
306 self.useMouse = false
307 end
308
309 self:updateMap()
310 end
311 end
312
313 self:resetFrameInputState()
314end

updateCursor

Description
Definition
updateCursor()
Code
430function IngameMapElement:updateCursor(deltaX, deltaY, dt)
431 if self.cursorElement ~= nil and self.cursorElement:getIsVisible() then
432 local speed = IngameMapElement.CURSOR_SPEED_FACTOR
433
434 -- Notably assume the cursor lives in a parent that determines position limits
435 local parentWidth, parentHeight = self.cursorElement.parent.size[1], self.cursorElement.parent.size[2]
436 local cursorWidth, cursorHeight = self.cursorElement.size[1], self.cursorElement.size[2]
437
438 local diffX = deltaX * speed * dt / g_screenAspectRatio
439 local diffY = deltaY * speed * dt
440
441 self:moveCenter(-diffX, -diffY)
442 end
443end

updateMap

Description
Update our element to match the zoom level and map center
Definition
updateMap()
Code
327function IngameMapElement:updateMap()
328 -- Size depends on the zoom level
329 local width, height = self:getElementSize()
330 self:setSize(width, height)
331
332 -- Location depends on size and center
333 self:setPosition(self.mapCenterX, self.mapCenterY)
334
335 -- Update the ingame map. The ingame map draws the map background and hotspots
336 self.ingameMap:setPosition(self.absPosition[1], self.absPosition[2])
337 self.ingameMap:setSize(self.size[1], self.size[2])
338 self.ingameMap.iconZoom = 0.3 + (self.zoomMax - self.zoomMin) * self.mapZoom
339 self.ingameMap:setZoomScale(self.ingameMap.iconZoom)
340
341 self.ingameMap:updatePlayerPosition()
342end

zoom

Description
Definition
zoom()
Code
256function IngameMapElement:zoom(direction)
257 -- Find the location pointed at by the cursor so we can zoom towards it
258 local targetX, targetY = self:getLocaPointerTarget()
259
260 -- Zoom by a set factor
261 local oldZoom = self.mapZoom
262 local speed = IngameMapElement.ZOOM_SPEED_FACTOR * direction * self.size[1] -- multiply by size to mimic a constant scroll
263 self.mapZoom = MathUtil.clamp(self.mapZoom + speed, self.zoomMin, self.zoomMax)
264
265 -- Size depends on zoom, center bounds depend on size. So clamp the center
266 self:moveCenter(0, 0)
267
268 -- Update size so our targeting works
269 local width, height = self:getElementSize()
270 self:setSize(width, height)
271
272 -- Do not change focus position if we did not changg zoom
273 if oldZoom ~= self.mapZoom then
274 -- Find the location the mouseis pointing at now
275 local newTargetX, newTargetY = self:getLocaPointerTarget()
276
277 -- Above location is wrong. We want it to point at the same location as before, so find the different for moving
278 local diffX, diffY = newTargetX - targetX, newTargetY - targetY
279
280 -- The diff is in local coordinates. Transform it to screenspace.
281 diffX = diffX * width
282 diffY = diffY * height
283
284 self:moveCenter(diffX, diffY)
285 end
286end