106 | function WorkArea:getIsAccessibleAtWorldPosition(farmId, x, z, workAreaType) |
107 | -- Disallow mission vehicles outside mission fields |
108 | if self.propertyState == Vehicle.PROPERTY_STATE_MISSION then |
109 | return g_missionManager:getIsMissionWorkAllowed(farmId, x, z, workAreaType) |
110 | end |
111 | |
112 | local farmlandId = g_farmlandManager:getFarmlandIdAtWorldPosition(x, z) |
113 | if farmlandId == nil then -- no valid farmland, or not buyable |
114 | return false |
115 | end |
116 | |
117 | local landOwner = g_farmlandManager:getFarmlandOwner(farmlandId) |
118 | local accessible = (landOwner ~= 0 and g_currentMission.accessHandler:canFarmAccessOtherId(farmId, landOwner)) |
119 | or g_missionManager:getIsMissionWorkAllowed(farmId, x, z, workAreaType) |
120 | |
121 | return accessible, landOwner |
122 | end |
399 | function WorkArea:getTypedNetworkAreas(areaType, needsFieldProperty) |
400 | local workAreasSend = {} |
401 | local area = 0 |
402 | local typedWorkAreas = self:getTypedWorkAreas(areaType) |
403 | local showFarmlandNotOwnedWarning = false |
404 | |
405 | for _, workArea in pairs(typedWorkAreas) do |
406 | if self:getIsWorkAreaActive(workArea) then |
407 | local x,_,z = getWorldTranslation(workArea.start) |
408 | |
409 | local isAccessible = not needsFieldProperty |
410 | if needsFieldProperty then |
411 | local farmId = g_currentMission:getFarmId() |
412 | isAccessible = g_currentMission.accessHandler:canFarmAccessLand(farmId, x, z) or g_missionManager:getIsMissionWorkAllowed(farmId, x, z, areaType) |
413 | end |
414 | |
415 | if isAccessible then |
416 | local x1,_,z1 = getWorldTranslation(workArea.width) |
417 | local x2,_,z2 = getWorldTranslation(workArea.height) |
418 | area = area + math.abs((z1-z)*(x2-x) - (x1-x)*(z2-z)) |
419 | table.insert(workAreasSend, {x,z,x1,z1,x2,z2}) |
420 | else |
421 | showFarmlandNotOwnedWarning = true |
422 | end |
423 | end |
424 | end |
425 | |
426 | return workAreasSend, showFarmlandNotOwnedWarning, area |
427 | end |
267 | function WorkArea:loadWorkAreaFromXML(workArea, xmlFile, key) |
268 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. ".area#startIndex", key .. ".area#startNode") --FS17 to FS19 |
269 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. ".area#widthIndex", key .. ".area#widthNode") --FS17 to FS19 |
270 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. ".area#heightIndex", key .. ".area#heightNode") --FS17 to FS19 |
271 | |
272 | local start = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. ".area#startNode"), self.i3dMappings) |
273 | local width = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. ".area#widthNode"), self.i3dMappings) |
274 | local height = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. ".area#heightNode"), self.i3dMappings) |
275 | |
276 | if start ~= nil and width ~= nil and height ~= nil then |
277 | local areaTypeStr = getXMLString(xmlFile, key .."#type") |
278 | workArea.type = g_workAreaTypeManager:getWorkAreaTypeIndexByName(areaTypeStr) or WorkAreaType.DEFAULT |
279 | |
280 | if workArea.type == nil then |
281 | g_logManager:xmlWarning(self.configFileName, "Invalid workArea type '%s' for workArea '%s'!", areaTypeStr, key) |
282 | return false |
283 | end |
284 | |
285 | workArea.isSynchronized = Utils.getNoNil(getXMLBool(xmlFile, key.."#isSynchronized"), true) |
286 | workArea.requiresGroundContact = Utils.getNoNil(getXMLBool(xmlFile, key .. "#requiresGroundContact"), true) |
287 | |
288 | if workArea.type ~= WorkAreaType.AUXILIARY then |
289 | |
290 | if workArea.requiresGroundContact then |
291 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. "#refNodeIndex", key .. ".groundReferenceNode#index") --FS17 to FS19 |
292 | local groundReferenceNodeIndex = getXMLInt(xmlFile, key ..".groundReferenceNode#index") |
293 | if groundReferenceNodeIndex == nil then |
294 | g_logManager:xmlWarning(self.configFileName, "Missing groundReference 'groundReferenceNode#index' for workArea '%s'. Add requiresGroundContact=\"false\" if groundContact is not required!", key) |
295 | return false |
296 | end |
297 | local groundReferenceNode = self:getGroundReferenceNodeFromIndex(groundReferenceNodeIndex) |
298 | if groundReferenceNode ~= nil then |
299 | workArea.groundReferenceNode = groundReferenceNode |
300 | else |
301 | g_logManager:xmlWarning(self.configFileName, "Invalid groundReferenceNode-index for workArea '%s'!", key) |
302 | return false |
303 | end |
304 | end |
305 | |
306 | workArea.disableBackwards = Utils.getNoNil(getXMLBool(xmlFile, key .. "#disableBackwards"), true) |
307 | |
308 | workArea.functionName = getXMLString(xmlFile, key .. "#functionName") |
309 | if workArea.functionName == nil then |
310 | g_logManager:xmlWarning(self.configFileName, "Missing 'functionName' for workArea '%s'!", key) |
311 | return false |
312 | else |
313 | if self[workArea.functionName] == nil then |
314 | g_logManager:xmlWarning(self.configFileName, "Given functionName '%s' not defined. Please add missing function or specialization!", tostring(workArea.functionName)) |
315 | return false |
316 | end |
317 | workArea.processingFunction = self[workArea.functionName] |
318 | end |
319 | |
320 | workArea.preprocessFunctionName = getXMLString(xmlFile, key .. "#preprocessFunctionName") |
321 | if workArea.preprocessFunctionName ~= nil then |
322 | if self[workArea.preprocessFunctionName] == nil then |
323 | g_logManager:xmlWarning(self.configFileName, "Given preprocessFunctionName '%s' not defined. Please add missing function or specialization!", tostring(workArea.preprocessFunctionName)) |
324 | return false |
325 | end |
326 | workArea.preprocessingFunction = self[workArea.preprocessFunctionName] |
327 | end |
328 | |
329 | workArea.postprocessFunctionName = getXMLString(xmlFile, key .. "#postprocessFunctionName") |
330 | if workArea.postprocessFunctionName ~= nil then |
331 | if self[workArea.postprocessFunctionName] == nil then |
332 | g_logManager:xmlWarning(self.configFileName, "Given postprocessFunctionName '%s' not defined. Please add missing function or specialization!", tostring(workArea.postprocessFunctionName)) |
333 | return false |
334 | end |
335 | workArea.postprocessingFunction = self[workArea.postprocessFunctionName] |
336 | end |
337 | |
338 | workArea.requiresOwnedFarmland = Utils.getNoNil(getXMLBool(xmlFile, key .. "#requiresOwnedFarmland"), true) |
339 | end |
340 | |
341 | workArea.lastProcessingTime = 0 |
342 | workArea.start = start |
343 | workArea.width = width |
344 | workArea.height = height |
345 | |
346 | return true |
347 | end |
348 | |
349 | return false |
350 | end |
67 | function WorkArea:onLoad(savegame) |
68 | local spec = self.spec_workArea |
69 | |
70 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.workAreas.workArea(0)#startIndex", "vehicle.workAreas.workArea(0).area#startIndex") --FS17 to FS19 |
71 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.workAreas.workArea(0)#widthIndex", "vehicle.workAreas.workArea(0).area#widthIndex") --FS17 to FS19 |
72 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.workAreas.workArea(0)#heightIndex", "vehicle.workAreas.workArea(0).area#heightIndex") --FS17 to FS19 |
73 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.workAreas.workArea(0)#foldMinLimit", "vehicle.workAreas.workArea(0).folding#minLimit") --FS17 to FS19 |
74 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.workAreas.workArea(0)#foldMaxLimit", "vehicle.workAreas.workArea(0).folding#maxLimit") --FS17 to FS19 |
75 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.workAreas.workArea(0)#refNodeIndex", "vehicle.workAreas.workArea(0).groundReferenceNode#index") --FS17 to FS19 |
76 | |
77 | spec.workAreas = {} |
78 | local i = 0 |
79 | while true do |
80 | local key = string.format("vehicle.workAreas.workArea(%d)", i) |
81 | if not hasXMLProperty(self.xmlFile, key) then |
82 | break |
83 | end |
84 | local workArea = {} |
85 | if self:loadWorkAreaFromXML(workArea, self.xmlFile, key) then |
86 | table.insert(spec.workAreas, workArea) |
87 | workArea.index = #spec.workAreas |
88 | end |
89 | i = i + 1 |
90 | end |
91 | |
92 | spec.workAreaByType = {} |
93 | for _, area in pairs(spec.workAreas) do |
94 | if spec.workAreaByType[area.type] == nil then |
95 | spec.workAreaByType[area.type] = {} |
96 | end |
97 | table.insert(spec.workAreaByType[area.type], area) |
98 | end |
99 | |
100 | spec.lastAccessedFarmlandOwner = 0 |
101 | spec.showFarmlandNotOwnedWarning = false |
102 | end |
141 | function WorkArea:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
142 | local spec = self.spec_workArea |
143 | SpecializationUtil.raiseEvent(self, "onStartWorkAreaProcessing", dt, spec.workAreas) |
144 | |
145 | spec.showFarmlandNotOwnedWarning = false |
146 | -- do not reset last accessed farmland owner |
147 | -- spec.lastAccessedFarmlandOwner = 0 |
148 | local hasProcessed = false |
149 | |
150 | local isOwned = false |
151 | local allowWarning = false |
152 | for _,workArea in ipairs(spec.workAreas) do |
153 | if workArea.type ~= WorkAreaType.AUXILIARY then |
154 | workArea.lastWorkedHectares = 0 |
155 | |
156 | local isAreaActive = self:getIsWorkAreaActive(workArea) |
157 | if isAreaActive and workArea.requiresOwnedFarmland then |
158 | local farmId = self:getActiveFarm() |
159 | if farmId == nil then -- Shop |
160 | farmId = AccessHandler.EVERYONE |
161 | end |
162 | |
163 | local xs,_,zs = getWorldTranslation(workArea.start) |
164 | local isAccessible, farmlandOwner = self:getIsAccessibleAtWorldPosition(farmId, xs, zs, workArea.type) |
165 | if isAccessible then |
166 | if farmlandOwner ~= nil then |
167 | spec.lastAccessedFarmlandOwner = farmlandOwner |
168 | end |
169 | isOwned = true |
170 | else |
171 | local xw,_,zw = getWorldTranslation(workArea.width) |
172 | if self:getIsAccessibleAtWorldPosition(farmId, xw, zw, workArea.type) then |
173 | isOwned = true |
174 | else |
175 | local xh,_,zh = getWorldTranslation(workArea.height) |
176 | if self:getIsAccessibleAtWorldPosition(farmId, xh, zh, workArea.type) then |
177 | isOwned = true |
178 | else |
179 | local x = xw + (xh - xs) |
180 | local z = zw + (zh - zs) |
181 | if self:getIsAccessibleAtWorldPosition(farmId, x, z, workArea.type) then |
182 | isOwned = true |
183 | end |
184 | end |
185 | end |
186 | end |
187 | |
188 | if not isOwned then |
189 | isAreaActive = false |
190 | end |
191 | |
192 | allowWarning = true |
193 | end |
194 | |
195 | if isAreaActive then |
196 | if workArea.preprocessingFunction ~= nil then |
197 | workArea.preprocessingFunction(self, workArea, dt) |
198 | end |
199 | |
200 | if workArea.processingFunction ~= nil then |
201 | local realArea, _ = workArea.processingFunction(self, workArea, dt) |
202 | |
203 | workArea.lastWorkedHectares = MathUtil.areaToHa(realArea, g_currentMission:getFruitPixelsToSqm()) -- 4096px are mapped to 2048m |
204 | |
205 | if workArea.lastWorkedHectares > 0 then |
206 | self:setWorkAreaProcessingTime(workArea, g_currentMission.time) |
207 | end |
208 | |
209 | -- Adding an area of interest for the wildlife spawners / keep (xw,zw) and (xh,zh) |
210 | if g_wildlifeSpawnerManager ~= nil and realArea > 0 then |
211 | local workAreaType = g_workAreaTypeManager:getWorkAreaTypeByIndex(workArea.type) |
212 | if workAreaType.attractWildlife then |
213 | local xw,_,zw = getWorldTranslation(workArea.width) |
214 | local xh,_,zh = getWorldTranslation(workArea.height) |
215 | |
216 | local radius = 3.0 |
217 | local posX = 0.5 * xw + 0.5 * xh |
218 | local posZ = 0.5 * zw + 0.5 * zh |
219 | local lifeTime = 0 |
220 | g_wildlifeSpawnerManager:addAreaOfInterest(lifeTime, posX, posZ, radius) |
221 | end |
222 | end |
223 | end |
224 | |
225 | if workArea.postprocessingFunction ~= nil then |
226 | workArea.postprocessingFunction(self, workArea, dt) |
227 | end |
228 | |
229 | hasProcessed = true |
230 | end |
231 | end |
232 | end |
233 | |
234 | -- display warning if none of the work areas got valid owned ground |
235 | if allowWarning and not isOwned then |
236 | spec.showFarmlandNotOwnedWarning = true |
237 | end |
238 | |
239 | SpecializationUtil.raiseEvent(self, "onEndWorkAreaProcessing", dt, hasProcessed) |
240 | end |
35 | function WorkArea.registerFunctions(vehicleType) |
36 | SpecializationUtil.registerFunction(vehicleType, "loadWorkAreaFromXML", WorkArea.loadWorkAreaFromXML) |
37 | SpecializationUtil.registerFunction(vehicleType, "getWorkAreaByIndex", WorkArea.getWorkAreaByIndex) |
38 | SpecializationUtil.registerFunction(vehicleType, "getIsWorkAreaActive", WorkArea.getIsWorkAreaActive) |
39 | SpecializationUtil.registerFunction(vehicleType, "setWorkAreaProcessingTime", WorkArea.setWorkAreaProcessingTime) |
40 | SpecializationUtil.registerFunction(vehicleType, "getIsWorkAreaProcessing", WorkArea.getIsWorkAreaProcessing) |
41 | SpecializationUtil.registerFunction(vehicleType, "getTypedNetworkAreas", WorkArea.getTypedNetworkAreas) |
42 | SpecializationUtil.registerFunction(vehicleType, "getTypedWorkAreas", WorkArea.getTypedWorkAreas) |
43 | SpecializationUtil.registerFunction(vehicleType, "getIsTypedWorkAreaActive", WorkArea.getIsTypedWorkAreaActive) |
44 | SpecializationUtil.registerFunction(vehicleType, "getIsFarmlandNotOwnedWarningShown", WorkArea.getIsFarmlandNotOwnedWarningShown) |
45 | SpecializationUtil.registerFunction(vehicleType, "getLastTouchedFarmlandFarmId", WorkArea.getLastTouchedFarmlandFarmId) |
46 | SpecializationUtil.registerFunction(vehicleType, "getIsAccessibleAtWorldPosition", WorkArea.getIsAccessibleAtWorldPosition) |
47 | end |