LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

FieldManager

Description
This class handles all functionality for AI fields and the NPCs handling them.
Parent
AbstractManager
Functions

delete

Description
Deletes field manager
Definition
delete()
Code
312function FieldManager:delete()
313end

initDataStructures

Description
Initialize data structures
Definition
initDataStructures()
Code
49function FieldManager:initDataStructures()
50 self.fields = {}
51 self.farmlandIdFieldMapping = {}
52 self.fieldStatusParametersToSet = nil
53 self.currentFieldPartitionIndex = nil
54 self.nextCheckTime = 0
55 self.nextUpdateTime = 0
56 self.nextFieldCheckIndex = 0
57end

loadFromXMLFile

Description
Load field savegame data
Definition
loadFromXMLFile(string filename)
Arguments
stringfilenamexml filename
Code
318function FieldManager:loadFromXMLFile(xmlFilename)
319 local xmlFile = XMLFile.load("fields", xmlFilename)
320 if xmlFile == nil then
321 return
322 end
323
324 xmlFile:iterate("fields.field", function (_, key)
325 local fieldId = xmlFile:getInt(key .. "#id")
326 local fruitName = xmlFile:getString(key .. "#plannedFruit")
327 local fruitDesc = g_fruitTypeManager:getFruitTypeByName(fruitName)
328
329 if fieldId ~= nil then
330 local field = self:getFieldByIndex(fieldId)
331 if field ~= nil then
332 if fruitName == "FALLOW" then
333 field.plannedFruit = 0
334 elseif fruitDesc ~= nil then
335 field.plannedFruit = fruitDesc.index
336 end
337 end
338 end
339 end)
340
341 xmlFile:delete()
342end

loadMapData

Description
Load data on map load
Definition
loadMapData()
Return Values
booleantrueif loading was successful else false
Code
62function FieldManager:loadMapData(xmlFile)
63 FieldManager:superClass().loadMapData(self)
64
65 local mission = g_currentMission
66 self.mission = mission
67
68 mission:addUpdateable(self)
69
70 local terrainNode = mission.terrainRootNode
71 local fieldGroundSystem = mission.fieldGroundSystem
72 local sprayLevelMapId, sprayLevelFirstChannel, sprayLevelNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.SPRAY_LEVEL)
73 local sprayLevelMaxValue = fieldGroundSystem:getMaxValue(FieldDensityMap.SPRAY_LEVEL)
74 local plowLevelMapId, plowLevelFirstChannel, plowLevelNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.PLOW_LEVEL)
75 local plowLevelMaxValue = fieldGroundSystem:getMaxValue(FieldDensityMap.PLOW_LEVEL)
76
77 self.limeLevelMaxValue = 0
78 self.plowLevelMaxValue = plowLevelMaxValue
79 self.sprayLevelMaxValue = sprayLevelMaxValue
80 self.fruitModifiers = {}
81
82 self.sprayLevelModifier = DensityMapModifier.new(sprayLevelMapId, sprayLevelFirstChannel, sprayLevelNumChannels, terrainNode)
83 self.plowLevelModifier = DensityMapModifier.new(plowLevelMapId, plowLevelFirstChannel, plowLevelNumChannels, terrainNode)
84
85
86 if Platform.gameplay.useLimeCounter then
87 local limeLevelMapId, limeLevelFirstChannel, limeLevelNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.LIME_LEVEL)
88 self.limeLevelMaxValue = fieldGroundSystem:getMaxValue(FieldDensityMap.LIME_LEVEL)
89 self.limeLevelModifier = DensityMapModifier.new(limeLevelMapId, limeLevelFirstChannel, limeLevelNumChannels, terrainNode)
90 end
91
92 if Platform.gameplay.useStubbleShred then
93 local stubbleShredLevelMapId, stubbleShredLevelFirstChannel, stubbleShredLevelNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.STUBBLE_SHRED)
94 self.stubbleShredModifier = DensityMapModifier.new(stubbleShredLevelMapId, stubbleShredLevelFirstChannel, stubbleShredLevelNumChannels, terrainNode)
95 end
96
97 local groundTypeMapId, groundTypeFirstChannel, groundTypeNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.GROUND_TYPE)
98 self.groundTypeModifier = DensityMapModifier.new(groundTypeMapId, groundTypeFirstChannel, groundTypeNumChannels, terrainNode)
99
100 local groundAngleMapId, groundAngleFirstChannel, groundAngleNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.GROUND_ANGLE)
101 self.angleModifier = DensityMapModifier.new(groundAngleMapId, groundAngleFirstChannel, groundAngleNumChannels, terrainNode)
102
103 local sprayTypeMapId, sprayTypeFirstChannel, sprayTypeNumChannels = fieldGroundSystem:getDensityMapData(FieldDensityMap.SPRAY_TYPE)
104 self.sprayTypeModifier = DensityMapModifier.new(sprayTypeMapId, sprayTypeFirstChannel, sprayTypeNumChannels, terrainNode)
105
106 self.fieldFilter = DensityMapFilter.new(groundTypeMapId, groundTypeFirstChannel, groundTypeNumChannels)
107 self.fieldFilter:setValueCompareParams(DensityValueCompareType.GREATER, 0)
108
109 if mission.weedSystem:getMapHasWeed() then
110 local weedMapId, weedFirstChannel, weedNumChannels = mission.weedSystem:getDensityMapData()
111 self.weedModifier = DensityMapModifier.new(weedMapId, weedFirstChannel, weedNumChannels, terrainNode)
112 end
113
114 self.fieldGroundSystem = fieldGroundSystem
115
116 local terrainDetailHeightId = mission.terrainDetailHeightId
117 self.terrainHeightTypeModifier = DensityMapModifier.new(terrainDetailHeightId, g_densityMapHeightManager.heightTypeFirstChannel, g_densityMapHeightManager.heightTypeNumChannels)
118 self.terrainHeightModifier = DensityMapModifier.new(terrainDetailHeightId, getDensityMapHeightFirstChannel(terrainDetailHeightId), getDensityMapHeightNumChannels(terrainDetailHeightId))
119
120 self.groundTypeSown = fieldGroundSystem:getFieldGroundValue(FieldGroundType.SOWN)
121 self.sprayTypeFertilizer = fieldGroundSystem:getFieldSprayValue(FieldSprayType.FERTILIZER)
122 self.sprayTypeLime = fieldGroundSystem:getFieldSprayValue(FieldSprayType.LIME)
123
124 -- create list of valid/available fruit types
125 self.availableFruitTypeIndices = {}
126 for _, fruitType in ipairs(g_fruitTypeManager:getFruitTypes()) do
127 if fruitType.useForFieldJob and fruitType.allowsSeeding and fruitType.needsSeeding then
128 table.insert(self.availableFruitTypeIndices, fruitType.index)
129 end
130 end
131 self.fruitTypesCount = #self.availableFruitTypeIndices
132
133 self.fieldIndexToCheck = 1
134
135 -- Connect farmlands to fields first. We need the farmlands to skip overriding owned fields (in order to have working starter fields)
136 g_asyncTaskManager:addSubtask(function()
137 for i, field in ipairs(self.fields) do
138 local posX, posZ = field:getCenterOfFieldWorldPosition()
139 local farmland = g_farmlandManager:getFarmlandAtWorldPosition(posX, posZ)
140 if farmland ~= nil then
141 field:setFarmland(farmland)
142
143 if self.farmlandIdFieldMapping[farmland.id] == nil then
144 self.farmlandIdFieldMapping[farmland.id] = {}
145 end
146
147 table.insert(self.farmlandIdFieldMapping[farmland.id], field)
148 else
149 Logging.error("Failed to find farmland in center of field '%s'", i)
150 end
151 end
152 end)
153
154 -- New save game
155 if not mission.missionInfo.isValid and g_server ~= nil then
156 g_asyncTaskManager:addSubtask(function()
157 local index = 1
158
159 for _, field in pairs(self.fields) do
160 if field:getIsAIActive() and field.fieldMissionAllowed and field.farmland ~= nil and not field.farmland.isOwned then
161 -- Plan a random fruit for the NPC
162 local fruitIndex = self.availableFruitTypeIndices[math.random(1, #self.availableFruitTypeIndices)]
163
164 if field.fieldGrassMission then
165 fruitIndex = FruitType.GRASS
166 end
167 field.plannedFruit = fruitIndex
168
169 -- Assume the crop is growing
170 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitIndex)
171 local fieldState = FieldManager.FIELDSTATE_GROWING
172
173 local plowState
174 if not mission.missionInfo.plowingRequiredEnabled then
175 plowState = self.plowLevelMaxValue
176 else
177 plowState = math.random(0, self.plowLevelMaxValue)
178 end
179
180 local sprayLevel = math.random(0, self.sprayLevelMaxValue)
181 local limeState = math.random(0, self.limeLevelMaxValue)
182
183 local weedValue = 0
184
185 -- Growth state is defined by the growth system which gives us a random
186 -- state that is possible on a new save.
187 local growthState = g_currentMission.growthSystem:getRandomInitialState(fruitIndex)
188
189 if growthState == nil and fruitIndex == FruitType.GRASS then
190 -- Force grass
191 growthState = 2
192 end
193
194 -- growth state is nil when there is no initial state because it is not possible
195 if growthState ~= nil then
196 if fruitDesc.plantsWeed then
197 -- Add some randomness: older plants have higher chance of older weeds
198 if growthState > 4 then
199 weedValue = math.random(3, 9)
200 else
201 weedValue = math.random(1, 7)
202 end
203 end
204
205 if growthState == fruitDesc.cutState then
206 fieldState = FieldManager.FIELDSTATE_HARVESTED
207 end
208 else
209 fieldState = math.random() < 0.5 and FieldManager.FIELDSTATE_CULTIVATED or FieldManager.FIELDSTATE_PLOWED
210
211 if fieldState == FieldManager.FIELDSTATE_PLOWED then
212 plowState = self.plowLevelMaxValue
213 end
214
215 fruitIndex = 0
216 end
217
218 for i = 1, table.getn(field.maxFieldStatusPartitions) do
219 self:setFieldPartitionStatus(field, field.maxFieldStatusPartitions, i, fruitIndex, fieldState, growthState, sprayLevel, false, plowState, weedValue, limeState)
220 end
221
222 index = index + 1
223 end
224 end
225 end)
226 elseif g_server ~= nil then
227 -- get current state of fields
228 for _, field in pairs(self.fields) do
229 g_asyncTaskManager:addSubtask(function()
230 self:findFieldFruit(field)
231 end)
232 end
233 end
234
235 g_asyncTaskManager:addSubtask(function()
236 self:findFieldSizes()
237 end)
238
239 g_asyncTaskManager:addSubtask(function()
240 g_farmlandManager:addStateChangeListener(self)
241
242 if mission:getIsServer() then
243 if g_addCheatCommands then
244 addConsoleCommand("gsFieldSetFruit", "Sets a given fruit to field", "consoleCommandSetFieldFruit", self)
245 addConsoleCommand("gsFieldSetFruitAll", "Sets a given fruit to all fields", "consoleCommandSetFieldFruitAll", self)
246 addConsoleCommand("gsFieldSetGround", "Sets a given fruit to field", "consoleCommandSetFieldGround", self)
247 addConsoleCommand("gsFieldSetGroundAll", "Sets a given fruit to allfield", "consoleCommandSetFieldGroundAll", self)
248 end
249 end
250
251 if g_addCheatCommands then
252 addConsoleCommand("gsFieldToggleStatus", "Shows field status", "consoleCommandToggleDebugFieldStatus", self)
253 end
254 end)
255
256 -- On clients, force all fields to have some value so map at least shows them
257 g_asyncTaskManager:addSubtask(function()
258 if not mission:getIsServer() then
259 for _, field in pairs(self.fields) do
260 self:setFieldGround(field, FieldGroundType.CULTIVATED, field.fieldAngle, 0, 0, 0, 0, 0, 0, false, false)
261 end
262 end
263 end)
264
265 g_messageCenter:subscribe(MessageType.FARM_PROPERTY_CHANGED, self.onFarmPropertyChanged, self)
266 g_messageCenter:subscribe(MessageType.YEAR_CHANGED, self.onYearChanged, self)
267 g_messageCenter:subscribe(MessageType.PERIOD_CHANGED, self.onPeriodChanged, self)
268end

new

Description
Creating manager
Definition
new()
Return Values
tableinstanceinstance of object
Code
41function FieldManager.new(customMt)
42 local self = AbstractManager.new(customMt or FieldManager_mt)
43
44 return self
45end

saveToXMLFile

Description
Write field data
Definition
saveToXMLFile(string xmlFilename)
Arguments
stringxmlFilenamefile path
Return Values
booleantrueif loading was successful else false
Code
348function FieldManager:saveToXMLFile(xmlFilename)
349 local xmlFile = XMLFile.create("fields", xmlFilename, "fields")
350
351 for i = 1, #self.fields do
352 local field = self.fields[i]
353
354 local key = string.format("fields.field(%d)", i - 1)
355
356 xmlFile:setInt(key .. "#id", field.fieldId)
357
358 if field.plannedFruit == 0 then
359 xmlFile:setString(key .. "#plannedFruit", "FALLOW")
360 else
361 xmlFile:setString(key .. "#plannedFruit", g_fruitTypeManager:getFruitTypeByIndex(field.plannedFruit).name)
362 end
363 end
364
365 xmlFile:save()
366 xmlFile:delete()
367end

unloadMapData

Description
Unload data on mission delete
Definition
unloadMapData()
Code
272function FieldManager:unloadMapData()
273 if self.mission ~= nil then
274 self.mission:removeUpdateable(self)
275 end
276
277 g_farmlandManager:removeStateChangeListener(self)
278
279 for _, field in pairs(self.fields) do
280 field:delete()
281 end
282 self.fields = {}
283
284 self.fieldGroundSystem = nil
285 self.sprayLevelModifier = nil
286 self.plowLevelModifier = nil
287 self.limeLevelModifier = nil
288 self.stubbleShredModifier = nil
289 self.fruitModifiers = nil
290 self.sprayTypeModifier = nil
291 self.angleModifier = nil
292 self.groundTypeModifier = nil
293 self.fieldFilter = nil
294 self.weedModifier = nil
295 self.terrainHeightTypeModifier = nil
296 self.terrainHeightModifier = nil
297 self.mission = nil
298
299 g_messageCenter:unsubscribeAll(self)
300
301 removeConsoleCommand("gsFieldSetFruit")
302 removeConsoleCommand("gsFieldSetFruitAll")
303 removeConsoleCommand("gsFieldSetGround")
304 removeConsoleCommand("gsFieldSetGroundAll")
305 removeConsoleCommand("gsFieldToggleStatus")
306
307 FieldManager:superClass().unloadMapData(self)
308end