274 | function MapOverlayGenerator:buildFarmlandsMapOverlay(selectedFarmland) |
275 | local map = self.farmlandManager:getLocalMap() |
276 | local farmlands = self.farmlandManager:getFarmlands() |
277 | |
278 | setOverlayColor(self.farmlandStateOverlay, 1, 1, 1, MapOverlayGenerator.FARMLANDS_ALPHA) |
279 | |
280 | for k, farmland in pairs(farmlands) do |
281 | local ownerFarmId = self.farmlandManager:getFarmlandOwner(farmland.id) |
282 | |
283 | if ownerFarmId ~= FarmlandManager.NOT_BUYABLE_FARM_ID then |
284 | if selectedFarmland ~= nil and farmland.id == selectedFarmland.id then |
285 | setDensityMapVisualizationOverlayStateColor(self.farmlandStateOverlay, map, 0, 0, getBitVectorMapNumChannels(map), k, unpack(MapOverlayGenerator.COLOR.FIELD_SELECTED)) |
286 | else |
287 | local color = MapOverlayGenerator.COLOR.FIELD_UNOWNED |
288 | if farmland.isOwned then -- assign farm color |
289 | local ownerFarm = self.farmManager:getFarmById(ownerFarmId) |
290 | color = ownerFarm:getColor() |
291 | end |
292 | |
293 | setDensityMapVisualizationOverlayStateColor(self.farmlandStateOverlay, map, 0, 0, getBitVectorMapNumChannels(map), k, unpack(color)) |
294 | end |
295 | end |
296 | end |
297 | |
298 | -- No borders on small maps |
299 | local profileClass = Utils.getPerformanceClassId() |
300 | if profileClass >= GS_PROFILE_HIGH and not GS_IS_CONSOLE_VERSION then |
301 | setDensityMapVisualizationOverlayStateBorderColor(self.farmlandStateOverlay, map, 0, getBitVectorMapNumChannels(map), MapOverlayGenerator.FARMLANDS_BORDER_THICKNESS, unpack(MapOverlayGenerator.COLOR.FIELD_BORDER)) |
302 | end |
303 | end |
158 | function MapOverlayGenerator:buildGrowthStateMapOverlay(growthStateFilter, fruitTypeFilter) |
159 | for _, displayCropType in ipairs(self.displayCropTypes) do |
160 | if fruitTypeFilter[displayCropType.fruitTypeIndex] then |
161 | local foliageId = displayCropType.foliageId |
162 | local desc = self.fruitTypeManager:getFruitTypeByIndex(displayCropType.fruitTypeIndex) |
163 | if desc.maxHarvestingGrowthState >= 0 then |
164 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.WITHERED] then |
165 | local witheredState = desc.maxHarvestingGrowthState + 1 |
166 | if desc.maxPreparingGrowthState >= 0 then |
167 | witheredState = desc.maxPreparingGrowthState + 1 |
168 | end |
169 | |
170 | if witheredState ~= desc.cutState and witheredState ~= desc.preparedGrowthState and witheredState ~= desc.minPreparingGrowthState then |
171 | local color = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.WITHERED].colors[self.isColorBlindMode][1] |
172 | setDensityMapVisualizationOverlayGrowthStateColor(self.foliageStateOverlay, foliageId, witheredState+1, color[1], color[2], color[3]) |
173 | end |
174 | end |
175 | |
176 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.HARVESTED] then |
177 | local color = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.HARVESTED].colors[self.isColorBlindMode][1] |
178 | setDensityMapVisualizationOverlayGrowthStateColor(self.foliageStateOverlay, foliageId, desc.cutState + 1, color[1], color[2], color[3]) |
179 | end |
180 | |
181 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.GROWING] then |
182 | local maxGrowingState = desc.minHarvestingGrowthState - 1 |
183 | if desc.minPreparingGrowthState >= 0 then |
184 | maxGrowingState = math.min(maxGrowingState, desc.minPreparingGrowthState-1) |
185 | end |
186 | |
187 | local colors = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.GROWING].colors[self.isColorBlindMode] |
188 | for i = 0, maxGrowingState do |
189 | local index = math.min(i + 1, #colors) |
190 | setDensityMapVisualizationOverlayGrowthStateColor(self.foliageStateOverlay, foliageId, i + 1, colors[index][1], colors[index][2], colors[index][3]) |
191 | end |
192 | end |
193 | |
194 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.TOPPING] then |
195 | if desc.minPreparingGrowthState >= 0 then |
196 | local color = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.TOPPING].colors[self.isColorBlindMode][1] |
197 | for i = desc.minPreparingGrowthState, desc.maxPreparingGrowthState do |
198 | setDensityMapVisualizationOverlayGrowthStateColor(self.foliageStateOverlay, foliageId, i + 1, color[1], color[2], color[3]) |
199 | end |
200 | end |
201 | end |
202 | |
203 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.HARVEST] then |
204 | local colors = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.HARVEST].colors[self.isColorBlindMode] |
205 | for i = desc.minHarvestingGrowthState,desc.maxHarvestingGrowthState do |
206 | local index = math.min(i - desc.minHarvestingGrowthState + 1, #colors) |
207 | setDensityMapVisualizationOverlayGrowthStateColor(self.foliageStateOverlay, foliageId, i + 1, colors[index][1], colors[index][2], colors[index][3]) |
208 | end |
209 | end |
210 | end |
211 | end |
212 | end |
213 | |
214 | -- TODO: un-global this: |
215 | if g_currentMission.terrainDetailId ~= 0 then |
216 | local fieldMask = bitShiftLeft(bitShiftLeft(1, g_currentMission.terrainDetailTypeNumChannels)-1, g_currentMission.terrainDetailTypeFirstChannel) |
217 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.CULTIVATED] then |
218 | local color = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.CULTIVATED].colors[self.isColorBlindMode][1] |
219 | setDensityMapVisualizationOverlayStateColor(self.foliageStateOverlay, g_currentMission.terrainDetailId, fieldMask, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels, g_currentMission.cultivatorValue, color[1], color[2], color[3]) |
220 | end |
221 | |
222 | if growthStateFilter[MapOverlayGenerator.GROWTH_STATE_INDEX.PLOWED] then |
223 | local color = self.displayGrowthStates[MapOverlayGenerator.GROWTH_STATE_INDEX.PLOWED].colors[self.isColorBlindMode][1] |
224 | setDensityMapVisualizationOverlayStateColor(self.foliageStateOverlay, g_currentMission.terrainDetailId, fieldMask, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels, g_currentMission.plowValue, color[1], color[2], color[3]) |
225 | end |
226 | end |
227 | end |
231 | function MapOverlayGenerator:buildSoilStateMapOverlay(soilStateFilter) |
232 | -- TODO: un-global this: |
233 | if g_currentMission.terrainDetailId ~= 0 then |
234 | local fieldMask = bitShiftLeft(bitShiftLeft(1, g_currentMission.terrainDetailTypeNumChannels)-1, g_currentMission.terrainDetailTypeFirstChannel) |
235 | |
236 | if soilStateFilter[MapOverlayGenerator.SOIL_STATE_INDEX.WEEDS] then |
237 | for _, missionFruitType in ipairs(self.missionFruitTypes) do |
238 | if missionFruitType.fruitTypeIndex == FruitType.WEED then |
239 | local weedType = self.fruitTypeManager:getWeedFruitType() |
240 | -- only show on overlay if at least one growth stage has passed so it's visible in the world -> minValue + 1 |
241 | local minDisplayState = weedType.weed.minValue + 1 |
242 | local maxDisplayState = weedType.weed.maxValue |
243 | local colors = self.displaySoilStates[MapOverlayGenerator.SOIL_STATE_INDEX.WEEDS].colors[self.isColorBlindMode] |
244 | for i = minDisplayState, maxDisplayState do |
245 | setDensityMapVisualizationOverlayGrowthStateColor(self.foliageStateOverlay, missionFruitType.foliageId, i, unpack(colors[1])) |
246 | end |
247 | end |
248 | end |
249 | end |
250 | |
251 | if soilStateFilter[MapOverlayGenerator.SOIL_STATE_INDEX.NEEDS_PLOWING] then |
252 | local color = self.displaySoilStates[MapOverlayGenerator.SOIL_STATE_INDEX.NEEDS_PLOWING].colors[self.isColorBlindMode][1] |
253 | setDensityMapVisualizationOverlayStateColor(self.foliageStateOverlay, g_currentMission.terrainDetailId, fieldMask, g_currentMission.plowCounterFirstChannel, g_currentMission.plowCounterNumChannels, 0, color[1], color[2], color[3]) |
254 | end |
255 | |
256 | if soilStateFilter[MapOverlayGenerator.SOIL_STATE_INDEX.NEEDS_LIME] then |
257 | local color = self.displaySoilStates[MapOverlayGenerator.SOIL_STATE_INDEX.NEEDS_LIME].colors[self.isColorBlindMode][1] |
258 | setDensityMapVisualizationOverlayStateColor(self.foliageStateOverlay, g_currentMission.terrainDetailId, fieldMask, g_currentMission.limeCounterFirstChannel, g_currentMission.limeCounterNumChannels, 0, color[1], color[2], color[3]) |
259 | end |
260 | |
261 | if soilStateFilter[MapOverlayGenerator.SOIL_STATE_INDEX.FERTILIZED] then |
262 | local colors = self.displaySoilStates[MapOverlayGenerator.SOIL_STATE_INDEX.FERTILIZED].colors[self.isColorBlindMode] |
263 | local maxSprayLevel = bitShiftLeft(1, g_currentMission.sprayLevelNumChannels) - 1 |
264 | for level = 1, maxSprayLevel do |
265 | local color = colors[math.min(level, #colors)] |
266 | setDensityMapVisualizationOverlayStateColor(self.foliageStateOverlay, g_currentMission.terrainDetailId, fieldMask, g_currentMission.sprayLevelFirstChannel, g_currentMission.sprayLevelNumChannels, level, color[1], color[2], color[3]) |
267 | end |
268 | end |
269 | end |
270 | end |
315 | function MapOverlayGenerator:generateOverlay(mapOverlayType, finishedCallback, overlayState, overlayState2) |
316 | local success = true |
317 | if self.overlayTypeCheckHash[mapOverlayType] == nil then |
318 | g_logManager:warning("Tried generating a map overlay with an invalid overlay type: [%s]", tostring(mapOverlayType)) |
319 | success = false |
320 | else |
321 | local overlayHandle = self.overlayHandles[mapOverlayType] |
322 | self.overlayFinishedCallback = finishedCallback or NO_CALLBACK |
323 | resetDensityMapVisualizationOverlay(overlayHandle) -- clear any previous overlay state |
324 | |
325 | self.currentOverlayHandle = overlayHandle |
326 | |
327 | local builderFunction = self.typeBuilderFunctionMap[mapOverlayType] |
328 | |
329 | builderFunction(self, overlayState, overlayState2) |
330 | |
331 | -- generate the map overlay based on the settings made in the build methods |
332 | generateDensityMapVisualizationOverlay(overlayHandle) |
333 | self:checkOverlayFinished() -- check now, might already be done |
334 | end |
335 | |
336 | return success |
337 | end |
416 | function MapOverlayGenerator:getDisplayCropTypes() |
417 | local cropTypes = {} |
418 | -- load crop type icon definitions in order of map configuration |
419 | for i, fruitType in ipairs(self.missionFruitTypes) do |
420 | if fruitType.shownOnMap and fruitType.fruitTypeIndex ~= FruitType.WEED then -- weed is known as a fruit type, but is handled as a soil state |
421 | local fillableIndex = self.fruitTypeManager:getFillTypeIndexByFruitTypeIndex(fruitType.fruitTypeIndex) |
422 | local fillable = self.fillTypeManager:getFillTypeByIndex(fillableIndex) |
423 | |
424 | local iconFilename = fillable.hudOverlayFilenameSmall |
425 | local iconUVs = Overlay.DEFAULT_UVS -- default crop type icons are separate files, use full texture |
426 | local description = fillable.title |
427 | |
428 | table.insert(cropTypes, { |
429 | colors = {[false] = fruitType.defaultColor, [true] = fruitType.colorBlindColor}, |
430 | iconFilename = iconFilename, |
431 | iconUVs = iconUVs, |
432 | description = description, |
433 | fruitTypeIndex = fruitType.fruitTypeIndex, |
434 | foliageId = fruitType.foliageId |
435 | }) |
436 | end |
437 | end |
438 | |
439 | return cropTypes |
440 | end |
448 | function MapOverlayGenerator:getDisplayGrowthStates() |
449 | return { |
450 | -- indices are contiguous, so this definition is a valid array: |
451 | [MapOverlayGenerator.GROWTH_STATE_INDEX.CULTIVATED] = { |
452 | colors = { |
453 | [true] = {MapOverlayGenerator.FRUIT_COLOR_CULTIVATED[true]}, |
454 | [false] = {MapOverlayGenerator.FRUIT_COLOR_CULTIVATED[false]} |
455 | }, |
456 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_CULTIVATED) |
457 | }, |
458 | [MapOverlayGenerator.GROWTH_STATE_INDEX.GROWING] = { |
459 | colors = MapOverlayGenerator.FRUIT_COLORS_GROWING, |
460 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_GROWING) |
461 | }, |
462 | [MapOverlayGenerator.GROWTH_STATE_INDEX.HARVEST] = { |
463 | colors = MapOverlayGenerator.FRUIT_COLORS_HARVEST, |
464 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_HARVEST) |
465 | }, |
466 | [MapOverlayGenerator.GROWTH_STATE_INDEX.HARVESTED] = { |
467 | colors = { |
468 | [true] = {MapOverlayGenerator.FRUIT_COLOR_CUT}, |
469 | [false] = {MapOverlayGenerator.FRUIT_COLOR_CUT} |
470 | }, |
471 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_HARVESTED) |
472 | }, |
473 | [MapOverlayGenerator.GROWTH_STATE_INDEX.PLOWED] = { |
474 | colors = { |
475 | [true] = {MapOverlayGenerator.FRUIT_COLOR_PLOWED[true]}, |
476 | [false] = {MapOverlayGenerator.FRUIT_COLOR_PLOWED[false]} |
477 | }, |
478 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_PLOWED) |
479 | }, |
480 | [MapOverlayGenerator.GROWTH_STATE_INDEX.TOPPING] = { |
481 | colors = { |
482 | [true] = {MapOverlayGenerator.FRUIT_COLOR_REMOVE_TOPS[true]}, |
483 | [false] = {MapOverlayGenerator.FRUIT_COLOR_REMOVE_TOPS[false]} |
484 | }, |
485 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_TOPPING) |
486 | }, |
487 | [MapOverlayGenerator.GROWTH_STATE_INDEX.WITHERED] = { |
488 | colors = { |
489 | [true] = {MapOverlayGenerator.FRUIT_COLOR_WITHERED[true]}, |
490 | [false] = {MapOverlayGenerator.FRUIT_COLOR_WITHERED[false]} |
491 | }, |
492 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.GROWTH_MAP_WITHERED) |
493 | } |
494 | } |
495 | end |
503 | function MapOverlayGenerator:getDisplaySoilStates() |
504 | local weedType = self.fruitTypeManager:getWeedFruitType() |
505 | local fillableIndex = self.fruitTypeManager:getFillTypeIndexByFruitTypeIndex(FruitType.WEED) |
506 | local weedFillable = self.fillTypeManager:getFillTypeByIndex(fillableIndex) |
507 | |
508 | return { |
509 | [MapOverlayGenerator.SOIL_STATE_INDEX.WEEDS] = { |
510 | colors = { |
511 | [true] = {weedType.colorBlindMapColor}, |
512 | [false] = {weedType.defaultMapColor} |
513 | }, |
514 | description = weedFillable.title |
515 | }, |
516 | [MapOverlayGenerator.SOIL_STATE_INDEX.FERTILIZED] = { |
517 | colors = MapOverlayGenerator.FRUIT_COLORS_FERTILIZED, |
518 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.SOIL_MAP_FERTILIZED) |
519 | }, |
520 | [MapOverlayGenerator.SOIL_STATE_INDEX.NEEDS_PLOWING] = { |
521 | colors = { |
522 | [true] = {MapOverlayGenerator.FRUIT_COLOR_NEEDS_PLOWING[true]}, |
523 | [false] = {MapOverlayGenerator.FRUIT_COLOR_NEEDS_PLOWING[false]} |
524 | }, |
525 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.SOIL_MAP_NEED_PLOWING) |
526 | }, |
527 | [MapOverlayGenerator.SOIL_STATE_INDEX.NEEDS_LIME] = { |
528 | colors = { |
529 | [true] = {MapOverlayGenerator.FRUIT_COLOR_NEEDS_LIME[true]}, |
530 | [false] = {MapOverlayGenerator.FRUIT_COLOR_NEEDS_LIME[false]} |
531 | }, |
532 | description = self.l10n:getText(MapOverlayGenerator.L10N_SYMBOL.SOIL_MAP_NEED_LIME) |
533 | } |
534 | } |
535 | end |
40 | function MapOverlayGenerator:new(l10n, fruitTypeManager, fillTypeManager, farmlandManager, farmManager) |
41 | local self = setmetatable({}, MapOverlayGenerator_mt) |
42 | |
43 | self.l10n = l10n |
44 | self.fruitTypeManager = fruitTypeManager |
45 | self.fillTypeManager = fillTypeManager |
46 | self.farmlandManager = farmlandManager |
47 | self.farmManager = farmManager |
48 | |
49 | self.missionFruitTypes = {} |
50 | self.isColorBlindMode = nil |
51 | |
52 | self.foliageStateOverlay = createDensityMapVisualizationOverlay("foliageState", unpack(self:adjustedOverlayResolution(MapOverlayGenerator.OVERLAY_RESOLUTION.FOLIAGE_STATE))) |
53 | self.farmlandStateOverlay = createDensityMapVisualizationOverlay("farmlandState", unpack(self:adjustedOverlayResolution(MapOverlayGenerator.OVERLAY_RESOLUTION.FARMLANDS, true))) |
54 | |
55 | self.typeBuilderFunctionMap = { |
56 | [MapOverlayGenerator.OVERLAY_TYPE.CROPS] = self.buildFruitTypeMapOverlay, |
57 | [MapOverlayGenerator.OVERLAY_TYPE.GROWTH] = self.buildGrowthStateMapOverlay, |
58 | [MapOverlayGenerator.OVERLAY_TYPE.SOIL] = self.buildSoilStateMapOverlay, |
59 | [MapOverlayGenerator.OVERLAY_TYPE.FARMLANDS] = self.buildFarmlandsMapOverlay |
60 | } |
61 | |
62 | self.overlayHandles = { |
63 | [MapOverlayGenerator.OVERLAY_TYPE.CROPS] = self.foliageStateOverlay, -- re-use this handle, these types are mutually exclusive |
64 | [MapOverlayGenerator.OVERLAY_TYPE.GROWTH] = self.foliageStateOverlay, |
65 | [MapOverlayGenerator.OVERLAY_TYPE.SOIL] = self.foliageStateOverlay, |
66 | [MapOverlayGenerator.OVERLAY_TYPE.FARMLANDS] = self.farmlandStateOverlay, -- farmlands are separate |
67 | } |
68 | |
69 | self.currentOverlayHandle = nil -- handle of overlay which is currently being generated or nil if none is processing |
70 | self.overlayFinishedCallback = NO_CALLBACK |
71 | |
72 | self.overlayTypeCheckHash = {} |
73 | for k, v in pairs(MapOverlayGenerator.OVERLAY_TYPE) do |
74 | self.overlayTypeCheckHash[v] = k |
75 | end |
76 | |
77 | -- Set overlay refresh time limit... block less long in console single- and console/PC MP server mode |
78 | if GS_IS_CONSOLE_VERSION or (g_currentMission.missionDynamicInfo.isMultiplayer and g_currentMission:getIsServer()) then |
79 | setDensityMapVisualizationOverlayUpdateTimeLimit(self.foliageStateOverlay, 10) |
80 | setDensityMapVisualizationOverlayUpdateTimeLimit(self.farmlandStateOverlay, 10) |
81 | else |
82 | setDensityMapVisualizationOverlayUpdateTimeLimit(self.foliageStateOverlay, 20) |
83 | setDensityMapVisualizationOverlayUpdateTimeLimit(self.farmlandStateOverlay, 20) |
84 | end |
85 | |
86 | return self |
87 | end |
115 | function MapOverlayGenerator:setMissionFruitTypes(missionFruitTypes) |
116 | self.missionFruitTypes = {} |
117 | for i, missionFruitType in ipairs(missionFruitTypes) do |
118 | local fruitType = self.fruitTypeManager:getFruitTypeByIndex(missionFruitType.fruitTypeIndex) |
119 | |
120 | -- transfer to new data structure used to display filters: |
121 | table.insert(self.missionFruitTypes, { |
122 | foliageId = missionFruitType.id, |
123 | fruitTypeIndex = missionFruitType.fruitTypeIndex, |
124 | shownOnMap = fruitType.shownOnMap, |
125 | defaultColor = fruitType.defaultMapColor, |
126 | colorBlindColor = fruitType.colorBlindMapColor |
127 | }) |
128 | end |
129 | |
130 | self.displayCropTypes = self:getDisplayCropTypes() |
131 | self.displayGrowthStates = self:getDisplayGrowthStates() |
132 | self.displaySoilStates = self:getDisplaySoilStates() |
133 | end |