234 | function AdditionalFieldBuyInfo:onFarmlandSelectionChanged(selectedFarmland) |
235 | if self.mapFrame ~= nil then |
236 | if selectedFarmland ~= nil then |
237 | if g_server ~= nil then |
238 | local fieldNumber, fieldArea = self:getFarmlandFieldInfo(selectedFarmland.id) |
239 | if fieldArea >= 0.01 then |
240 | self.selectedField = fieldNumber |
241 | self.selectedFieldSize = fieldArea |
242 | |
243 | self.mapFrame.fieldBuyInfoWindow:setVisible(true) |
244 | |
245 | if selectedFarmland.soilDistribution ~= nil then |
246 | for i=1, #self.soilDistributionTarget do |
247 | self.soilDistribution[i] = 0 |
248 | self.soilDistributionTarget[i] = selectedFarmland.soilDistribution[i] |
249 | end |
250 | |
251 | self.yieldPotentialTarget = selectedFarmland.yieldPotential |
252 | self.yieldPotential = 1 |
253 | self.doInterpolation = true |
254 | end |
255 | |
256 | self:updateUIValues() |
257 | else |
258 | self.mapFrame.fieldBuyInfoWindow:setVisible(false) |
259 | end |
260 | else |
261 | -- client doesn't know that the values have changed -> so just poll the latest data |
262 | if g_server == nil and g_client ~= nil then |
263 | g_client:getServerConnection():sendEvent(RequestFieldBuyInfoEvent.new(selectedFarmland.id)) |
264 | end |
265 | end |
266 | else |
267 | self.mapFrame.fieldBuyInfoWindow:setVisible(false) |
268 | end |
269 | end |
270 | end |
380 | function AdditionalFieldBuyInfo:overwriteGameFunctions(pfModule) |
381 | -- calculate the soil distribution for |
382 | pfModule:overwriteGameFunction(FarmlandManager, "loadFarmlandData", function(superFunc, farmlandManager, xmlFile) |
383 | if not superFunc(farmlandManager, xmlFile) then |
384 | return false |
385 | end |
386 | |
387 | if g_currentMission.missionInfo.isValid then |
388 | self:updateFieldSoilDistributionData() |
389 | else |
390 | -- delay the initialization on new savegames to make sure the terrain detail is painted |
391 | self.delayedFieldSoilDistributionUpdate = true |
392 | end |
393 | |
394 | return true |
395 | end) |
396 | |
397 | -- calculate the soil distribution for |
398 | pfModule:overwriteGameFunction(FieldManager, "setFieldPartitionStatus", function(superFunc, fieldManager, field, fieldPartitions, fieldPartitionIndex, fruitIndex, fieldState, growthState, sprayState, setSpray, plowState, weedState, limeState) |
399 | superFunc(fieldManager, field, fieldPartitions, fieldPartitionIndex, fruitIndex, fieldState, growthState, sprayState, setSpray, plowState, weedState, limeState) |
400 | |
401 | field.pa_fieldInitialized = true |
402 | |
403 | if self.delayedFieldSoilDistributionUpdate then |
404 | local readyForUpdate = true |
405 | for _, _field in pairs(fieldManager.fields) do |
406 | if _field:getIsAIActive() and _field.fieldMissionAllowed and not _field.farmland.isOwned then |
407 | if not _field.pa_fieldInitialized then |
408 | readyForUpdate = false |
409 | break |
410 | end |
411 | end |
412 | end |
413 | |
414 | if readyForUpdate then |
415 | self.delayedFieldSoilDistributionUpdate = false |
416 | self:updateFieldSoilDistributionData() |
417 | end |
418 | end |
419 | end) |
420 | |
421 | -- multiply the field price with the yield potential |
422 | pfModule:overwriteGameFunction(Farmland, "updatePrice", function(superFunc, farmland) |
423 | superFunc(farmland) |
424 | |
425 | if farmland.yieldPotential ~= nil then |
426 | farmland.price = farmland.price * farmland.yieldPotential |
427 | end |
428 | end) |
429 | end |
82 | function AdditionalFieldBuyInfo:readInfoFromStream(farmlandId, streamId, connection) |
83 | if streamReadBool(streamId) then |
84 | self.selectedField = streamReadUIntN(streamId, 9) |
85 | self.selectedFieldSize = streamReadFloat32(streamId) |
86 | |
87 | self.mapFrame.fieldBuyInfoWindow:setVisible(true) |
88 | |
89 | for i=1, #self.soilDistributionTarget do |
90 | self.soilDistribution[i] = 0 |
91 | self.soilDistributionTarget[i] = streamReadUIntN(streamId, 8) / 255 |
92 | end |
93 | |
94 | self.yieldPotentialTarget = streamReadUIntN(streamId, 8) / 255 * 1.25 |
95 | self.yieldPotential = 1 |
96 | |
97 | self.doInterpolation = true |
98 | |
99 | self:updateUIValues() |
100 | else |
101 | self.mapFrame.fieldBuyInfoWindow:setVisible(false) |
102 | end |
103 | end |
300 | function AdditionalFieldBuyInfo:updateFieldSoilDistributionData() |
301 | local pfModule = self.pfModule |
302 | local farmlandManager = g_farmlandManager |
303 | if pfModule.soilMap ~= nil then |
304 | local soilBitVectorMap = pfModule.soilMap.bitVectorMap |
305 | if soilBitVectorMap ~= nil then |
306 | local farmlandX, _ = getBitVectorMapSize(farmlandManager.localMap) |
307 | local soilX, soilY = getBitVectorMapSize(soilBitVectorMap) |
308 | |
309 | local farmlandScale = farmlandX / soilX |
310 | for x = 0, soilX - 1 do |
311 | for y = 0, soilY - 1 do |
312 | local worldX = x / (soilX - 1) * g_currentMission.terrainSize - g_currentMission.terrainSize * 0.5 |
313 | local worldZ = y / (soilY - 1) * g_currentMission.terrainSize - g_currentMission.terrainSize * 0.5 |
314 | local isOnField = getDensityAtWorldPos(g_currentMission.terrainDetailId, worldX, 0, worldZ) ~= 0 |
315 | if isOnField then |
316 | local valueFarmland = getBitVectorMapPoint(farmlandManager.localMap, x * farmlandScale, y * farmlandScale, 0, farmlandManager.numberOfBits) |
317 | local valueSoil = bitAND(getBitVectorMapPoint(soilBitVectorMap, x, y, 0, pfModule.soilMap.numChannels), 3) |
318 | |
319 | if valueFarmland > 0 then |
320 | local farmland = farmlandManager.farmlands[valueFarmland] |
321 | if farmland ~= nil then |
322 | if farmland.totalFieldArea == nil then |
323 | farmland.totalFieldArea = 0 |
324 | end |
325 | |
326 | farmland.totalFieldArea = farmland.totalFieldArea + 1 |
327 | |
328 | if farmland.soilDistribution == nil then |
329 | farmland.soilDistribution = {} |
330 | for i=1, #pfModule.soilMap.soilTypes do |
331 | farmland.soilDistribution[i] = 0 |
332 | end |
333 | end |
334 | |
335 | farmland.soilDistribution[valueSoil + 1] = farmland.soilDistribution[valueSoil + 1] + 1 |
336 | end |
337 | end |
338 | end |
339 | end |
340 | end |
341 | |
342 | local totalYieldPotentialPixels = 0 |
343 | local totalFarmlandPixels = 0 |
344 | for _, farmland in pairs(farmlandManager.farmlands) do |
345 | farmland:updatePrice() |
346 | |
347 | if farmland.soilDistribution ~= nil then |
348 | local soilSum = 0 |
349 | for i=1, #farmland.soilDistribution do |
350 | soilSum = soilSum + farmland.soilDistribution[i] |
351 | end |
352 | |
353 | if soilSum > 0 then |
354 | local yieldPotential = 0 |
355 | for i=1, #farmland.soilDistribution do |
356 | farmland.soilDistribution[i] = math.floor(farmland.soilDistribution[i] / soilSum * 100) / 100 |
357 | yieldPotential = yieldPotential + self.pfModule.soilMap:getYieldPotentialBySoilTypeIndex(i) * farmland.soilDistribution[i] |
358 | self.soilDistribution[i] = 0 |
359 | end |
360 | |
361 | farmland.yieldPotential = MathUtil.clamp(yieldPotential, 0, 1.25) |
362 | |
363 | totalYieldPotentialPixels = totalYieldPotentialPixels + farmland.yieldPotential * soilSum |
364 | totalFarmlandPixels = totalFarmlandPixels + soilSum |
365 | end |
366 | |
367 | local pixelToSqm = g_currentMission.terrainSize / soilX |
368 | farmland.totalFieldArea = (farmland.totalFieldArea * pixelToSqm * pixelToSqm) / 10000 |
369 | end |
370 | end |
371 | |
372 | Logging.devInfo("Map Overall Yield Potential: %.3f", totalYieldPotentialPixels / totalFarmlandPixels) |
373 | end |
374 | end |
375 | end |
184 | function AdditionalFieldBuyInfo:updateUIValues() |
185 | local mapFrame = self.mapFrame |
186 | |
187 | self:updateSoilBars() |
188 | |
189 | local text |
190 | if self.selectedField ~= 0 then |
191 | text = string.format(g_i18n:getText("ui_economicAnalysisHeaderField", AdditionalFieldBuyInfo.MOD_NAME), self.selectedField, self.selectedFieldSize) |
192 | else |
193 | text = string.format(g_i18n:getText("ui_economicAnalysisHeaderAdditionalField", AdditionalFieldBuyInfo.MOD_NAME), self.selectedFieldSize) |
194 | end |
195 | |
196 | mapFrame.fieldBuyHeader:setText(text) |
197 | |
198 | for i=1, 4 do |
199 | local offset = mapFrame.soilPercentageText[i].size[1] * 0.1 |
200 | local str = "~%d%%" |
201 | if self.soilDistribution[i] == 0 then |
202 | str = "%d%%" |
203 | offset = 0 |
204 | end |
205 | |
206 | mapFrame.soilPercentageText[i]:setText(string.format(str, self.soilDistribution[i] * 100)) |
207 | mapFrame.soilPercentageBar[i]:setSize(self.maxBarSize * self.soilDistribution[i]) |
208 | mapFrame.soilPercentageText[i]:setPosition(mapFrame.soilPercentageBar[i].position[1] + mapFrame.soilPercentageBar[i].size[1] + offset) |
209 | end |
210 | |
211 | if self.yieldPotential > 1 then |
212 | mapFrame.yieldPercentageBarPos:setPosition(mapFrame.yieldPercentageBarBase.position[1] + mapFrame.yieldPercentageBarBase.size[1]) |
213 | mapFrame.yieldPercentageBarPos:setSize(mapFrame.yieldPercentageBarBase.size[1] * (self.yieldPotential - 1)) |
214 | |
215 | mapFrame.yieldPercentageBarNeg:setSize(0) |
216 | elseif self.yieldPotential < 1 then |
217 | local barWidth = mapFrame.yieldPercentageBarBase.size[1] * math.abs(self.yieldPotential - 1) |
218 | mapFrame.yieldPercentageBarNeg:setPosition(mapFrame.yieldPercentageBarBase.position[1] + mapFrame.yieldPercentageBarBase.size[1] - barWidth) |
219 | mapFrame.yieldPercentageBarNeg:setSize(barWidth) |
220 | |
221 | mapFrame.yieldPercentageBarPos:setSize(0) |
222 | else |
223 | mapFrame.yieldPercentageBarNeg:setSize(0) |
224 | mapFrame.yieldPercentageBarPos:setSize(0) |
225 | end |
226 | |
227 | mapFrame.yieldPercentageText:setText(string.format("~%d%%", self.yieldPotential * 100)) |
228 | local maxWidth = mapFrame.yieldPercentageBarBase.position[1] + mapFrame.yieldPercentageBarBase.size[1] * 1.25 - mapFrame.yieldPercentageText.size[1] |
229 | mapFrame.yieldPercentageText:setPosition(math.min(mapFrame.yieldPercentageBarBase.position[1] + mapFrame.yieldPercentageBarBase.size[1] * self.yieldPotential - mapFrame.yieldPercentageText.size[1] * 0.5, maxWidth)) |
230 | end |
107 | function AdditionalFieldBuyInfo:writeInfoToStream(farmlandId, streamId, connection) |
108 | local farmland = g_farmlandManager.farmlands[farmlandId] |
109 | local fieldNumber, fieldArea = self:getFarmlandFieldInfo(farmlandId) |
110 | |
111 | local isValid = fieldArea > 0 and farmland.soilDistribution ~= nil |
112 | if streamWriteBool(streamId, isValid) then |
113 | streamWriteUIntN(streamId, fieldNumber, 9) |
114 | streamWriteFloat32(streamId, fieldArea) |
115 | |
116 | for i=1, #self.soilDistributionTarget do |
117 | streamWriteUIntN(streamId, farmland.soilDistribution[i] * 255, 8) |
118 | end |
119 | |
120 | streamWriteUIntN(streamId, farmland.yieldPotential / 1.25 * 255, 8) |
121 | end |
122 | end |