325 | function IngameMap:addMapHotspot(mapHotspot) |
326 | table.insert(self.hotspots, mapHotspot) |
327 | |
328 | -- On mobile we sort spatially |
329 | if GS_IS_MOBILE_VERSION then |
330 | local mapSize = 1024 |
331 | table.sort(self.hotspots, function(v1, v2) |
332 | -- Split into 6 horizontal bands (must be an even number because map changes position based on the 0.5 split) |
333 | -- Sort horizontall within bands and vertically per band |
334 | |
335 | local band1 = math.ceil((v1.worldZ + mapSize * 0.5) / (mapSize * 0.16666)) |
336 | local band2 = math.ceil((v2.worldZ + mapSize * 0.5) / (mapSize * 0.16666)) |
337 | |
338 | if band1 == band2 then |
339 | return v1.worldX < v2.worldX or (v1.worldX == v2.worldX and v1.worldZ < v2.worldZ) |
340 | else |
341 | return (band1 - band2) < 0 |
342 | end |
343 | end) |
344 | else |
345 | table.sort(self.hotspots, function(v1, v2) return v1:getCategory() > v2:getCategory() end) |
346 | end |
347 | self.hotspotsSorted = nil |
348 | |
349 | return mapHotspot |
350 | end |
773 | function IngameMap:createToggleMapSizeGlyph(hudAtlasPath, baseX, baseY, baseWidth, baseHeight) |
774 | local width, height = getNormalizedScreenValues(unpack(IngameMap.SIZE.INPUT_ICON)) |
775 | local offX, offY = getNormalizedScreenValues(unpack(IngameMap.POSITION.INPUT_ICON)) |
776 | |
777 | local element = InputGlyphElement.new(self.inputDisplayManager, width, height) |
778 | local posX, posY = baseX + offX, baseY + offY |
779 | |
780 | element:setPosition(posX, posY) |
781 | element:setKeyboardGlyphColor(IngameMap.COLOR.INPUT_ICON) |
782 | element:setAction(InputAction.TOGGLE_MAP_SIZE) |
783 | |
784 | self.toggleMapSizeGlyph = element |
785 | self:addChild(element) |
786 | end |
302 | function IngameMap:determineVehiclePosition(enterable) |
303 | local posX, posY, posZ = getTranslation(enterable.rootNode) |
304 | |
305 | -- set arrow rotation |
306 | local dx, _, dz = localDirectionToWorld(enterable.rootNode, 0, 0, 1) |
307 | local yRot |
308 | if enterable.spec_drivable ~= nil and enterable.spec_drivable.reverserDirection == -1 then |
309 | yRot = MathUtil.getYRotationFromDirection(dx, dz) |
310 | else |
311 | yRot = MathUtil.getYRotationFromDirection(dx, dz) + math.pi |
312 | end |
313 | |
314 | local vel = enterable:getLastSpeed() |
315 | |
316 | return posX, posY, posZ, yRot, vel |
317 | end |
694 | function IngameMap:drawHotspot(hotspot, smallVersion) |
695 | if hotspot == nil then |
696 | return |
697 | end |
698 | |
699 | local worldX, worldZ = hotspot:getWorldPosition() |
700 | local rotation = hotspot:getWorldRotation() |
701 | |
702 | local objectX = (worldX + self.worldCenterOffsetX) / self.worldSizeX * self.mapExtensionScaleFactor + self.mapExtensionOffsetX |
703 | local objectZ = (worldZ + self.worldCenterOffsetZ) / self.worldSizeZ * self.mapExtensionScaleFactor + self.mapExtensionOffsetZ |
704 | |
705 | local zoom = self.layout:getIconZoom() |
706 | hotspot:setScale(self.uiScale * zoom) |
707 | |
708 | local x, y, yRot, visible = self.layout:getMapObjectPosition(objectX, objectZ, hotspot:getWidth(), hotspot:getHeight(), rotation, hotspot:getIsPersistent()) |
709 | if visible then |
710 | hotspot:setLastRenderInfo(x, y, yRot, self.layout) |
711 | -- drawFilledRect(x, y, hotspot:getWidth(), hotspot:getHeight(), 1, 0, 0, 0.2) |
712 | hotspot:render(x, y, yRot, smallVersion) |
713 | end |
714 | end |
639 | function IngameMap:drawLatencyToServer() |
640 | if g_client ~= nil and g_client.currentLatency ~= nil and g_currentMission.missionDynamicInfo.isMultiplayer and g_currentMission.missionDynamicInfo.isClient then |
641 | local color |
642 | if g_client.currentLatency <= 50 then |
643 | color = IngameMap.COLOR.LATENCY_GOOD |
644 | elseif g_client.currentLatency < 100 then |
645 | color = IngameMap.COLOR.LATENCY_MEDIUM |
646 | else |
647 | color = IngameMap.COLOR.LATENCY_BAD |
648 | end |
649 | |
650 | self.layout:drawLatency(string.format("%dms", math.max(g_client.currentLatency, 10)), color) |
651 | end |
652 | end |
246 | function IngameMap:loadMap(filename, worldSizeX, worldSizeZ, fieldColor, grassFieldColor) |
247 | self.mapElement:delete() -- will also delete the wrapped Overlay |
248 | |
249 | self:setWorldSize(worldSizeX, worldSizeZ) |
250 | |
251 | self.mapOverlay = Overlay.new(filename, 0, 0, 1, 1) |
252 | |
253 | self.mapElement = HUDElement.new(self.mapOverlay) |
254 | self:addChild(self.mapElement) |
255 | |
256 | self:setScale(self.uiScale) |
257 | |
258 | self.mapOverlayGenerator = MapOverlayGenerator.new(g_i18n, g_fruitTypeManager, g_fillTypeManager, g_farmlandManager, g_farmManager, g_currentMission.weedSystem) |
259 | self.mapOverlayGenerator:setColorBlindMode(false) |
260 | self.mapOverlayGenerator:setFieldColor(fieldColor, grassFieldColor) |
261 | self.fieldRefreshTimer = IngameMap.FIELD_REFRESH_INTERVAL |
262 | end |
40 | function IngameMap.new(hud, hudAtlasPath, inputDisplayManager, customMt) |
41 | local self = IngameMap:superClass().new(nil, nil, customMt or IngameMap_mt) |
42 | self.overlay = self:createBackground(hudAtlasPath) |
43 | |
44 | self.hud = hud |
45 | self.hudAtlasPath = hudAtlasPath |
46 | self.inputDisplayManager = inputDisplayManager |
47 | |
48 | self.uiScale = 1.0 |
49 | |
50 | self.isVisible = true |
51 | |
52 | self.layouts = { |
53 | IngameMapLayoutNone.new(), |
54 | IngameMapLayoutCircle.new(), |
55 | IngameMapLayoutSquare.new(), |
56 | IngameMapLayoutSquareLarge.new(), |
57 | IngameMapLayoutFullscreen.new(), |
58 | } |
59 | self.fullScreenLayout = self.layouts[#self.layouts] |
60 | self.state = 1 |
61 | self.layout = self.layouts[self.state] |
62 | |
63 | self.mapOverlay = Overlay.new(nil, 0, 0, 1, 1) -- null-object, obsoletes defensive checks |
64 | self.mapElement = HUDElement.new(self.mapOverlay) -- null-object |
65 | |
66 | self:createComponents(hudAtlasPath) |
67 | for _, layout in ipairs(self.layouts) do |
68 | layout:createComponents(self, hudAtlasPath) |
69 | end |
70 | |
71 | self.filter = {} |
72 | self.filter[MapHotspot.CATEGORY_FIELD] = true |
73 | self.filter[MapHotspot.CATEGORY_ANIMAL] = true |
74 | self.filter[MapHotspot.CATEGORY_MISSION] = true |
75 | self.filter[MapHotspot.CATEGORY_TOUR] = true |
76 | self.filter[MapHotspot.CATEGORY_STEERABLE] = true |
77 | self.filter[MapHotspot.CATEGORY_COMBINE] = true |
78 | self.filter[MapHotspot.CATEGORY_TRAILER] = true |
79 | self.filter[MapHotspot.CATEGORY_TOOL] = true |
80 | self.filter[MapHotspot.CATEGORY_UNLOADING] = true |
81 | self.filter[MapHotspot.CATEGORY_LOADING] = true |
82 | self.filter[MapHotspot.CATEGORY_PRODUCTION] = true |
83 | self.filter[MapHotspot.CATEGORY_SHOP] = true |
84 | self.filter[MapHotspot.CATEGORY_OTHER] = true |
85 | self.filter[MapHotspot.CATEGORY_AI] = true |
86 | self.filter[MapHotspot.CATEGORY_PLAYER] = true |
87 | |
88 | self:setWorldSize(2048, 2048) |
89 | |
90 | self.hotspots = {} |
91 | self.selectedHotspot = nil |
92 | |
93 | self.mapExtensionOffsetX = 0.25 |
94 | self.mapExtensionOffsetZ = 0.25 |
95 | self.mapExtensionScaleFactor = 0.5 |
96 | |
97 | self.allowToggle = true |
98 | |
99 | self.topDownCamera = nil -- set by screen views which use a top down view, used for map position update |
100 | |
101 | return self |
102 | end |
354 | function IngameMap:removeMapHotspot(mapHotspot) |
355 | if mapHotspot ~= nil then |
356 | for i=1, #self.hotspots do |
357 | if self.hotspots[i] == mapHotspot then |
358 | table.remove(self.hotspots, i) |
359 | break |
360 | end |
361 | end |
362 | |
363 | if self.selectedHotspot == mapHotspot then |
364 | self:setSelectedHotspot(nil) |
365 | end |
366 | |
367 | if g_currentMission ~= nil then |
368 | if g_currentMission.currentMapTargetHotspot == mapHotspot then |
369 | g_currentMission:setMapTargetHotspot(nil) |
370 | end |
371 | end |
372 | |
373 | self.hotspotsSorted = nil |
374 | end |
375 | end |
193 | function IngameMap:resetSettings() |
194 | if self.overlay == nil then |
195 | return -- instance has been deleted, ignore reset |
196 | end |
197 | |
198 | -- self:setScale(self.uiScale) -- resets scaled values |
199 | |
200 | -- local baseX, baseY = self:getBackgroundPosition() |
201 | -- self:setPosition(baseX + self.mapOffsetX, baseY + self.mapOffsetY) |
202 | -- self:setSize(self.mapWidth, self.mapHeight) |
203 | |
204 | self:setSelectedHotspot(nil) |
205 | end |
150 | function IngameMap:toggleSize(state, force) |
151 | --#profile g_remoteProfiler.ZoneBeginN("IngameMap_toggleSize") |
152 | self.layout:deactivate() |
153 | |
154 | if state ~= nil then |
155 | self.state = math.max(math.min(state, #self.layouts - 1), 1) |
156 | else |
157 | self.state = (self.state % (#self.layouts - 1)) + 1 |
158 | end |
159 | |
160 | self.layout = self.layouts[self.state] |
161 | self.layout:activate() |
162 | |
163 | g_inputBinding:setActionEventTextVisibility(self.toggleMapSizeEventId, self.layout:getShowsToggleActionText()) |
164 | g_gameSettings:setValue("ingameMapState", self.state) |
165 | --#profile g_remoteProfiler.ZoneEnd() |
166 | end |