LUADOC - Farming Simulator 19

AnimalFoodManager

Description
This class handles animal food [Food groups] Each animal has a list of food group. A single food group contains a list of fillType. The consumption of each food group is defined as 'serial' or 'parallel'. In case of 'serial' each fillType is reduced one after the other and the production value returned is that of the current food group. In case of 'parallel' all food groups are reduced together. Production value returned is that of the sum of all available fillTypes contained in food group. [Mixtures] A mixture is fillType containing a group of fillTypes. A percentage of each ingredient is needed to create a unit of that mixture. Note: g_animalFoodManager:loadMapData requires g_fillTypeManager:loadMapData
Parent
AbstractManager
XML Configuration Parameters
animalFood.animals.animalfor each animal type we define food groups and mixtures
animalFood.animals.animal#typethe type of animal. It is defined in $dataS\character\xxxAnimals.xml (animalHusbandry.animals#type)
animalFood.animals.animal#consumptionTypeis how the food is consumed by the animals
animalFood.animals.animal.foodGroups.foodGroupis a list of fillType. It must be defined in $data\maps\mapXXX.xml
animalFood.animals.animal.foodGroups.foodGroup#titlelocalized string for the group
animalFood.animals.animal.foodGroups.foodGroup#productionWeighthow much production is impacted when this group of food is processed. Total of weight must be equal to 1.0.
animalFood.foodMixtureslist of mixtures possible
animalFood.foodMixtures.foodMixture#fillTypename of fillType for the mixture. It must be defined in $data\maps\mapXXX.xml
animalFood.foodMixtures.foodMixture.ingredientlist of ingredients for the mixture.
animalFood.foodMixtures.foodMixture.ingredient#fillTypeslist of filltypes for this ingredient
animalFood.foodMixtures.foodMixture.ingredient#weightpercentage of a filltype that is contained in the mixture. Total of weights must be equal to 1.0.

Functions

changeFillLevels

Description
Definition
changeFillLevels()
Code
408function AnimalFoodManager:changeFillLevels(fillDelta, fillLevels, fillTypeIndex)
409 local old = fillLevels[fillTypeIndex]
410 fillLevels[fillTypeIndex] = math.max(0, old + fillDelta)
411 local new = fillLevels[fillTypeIndex]
412 return new - old
413end

consumeFood

Description
Consumes food(fillType) in fillLevels and returns the production weight associated to it
Definition
consumeFood(string animalType, float amountToConsume., table fillLevels)
Arguments
stringanimalType
floatamountToConsume.Is modified, is zero all food is consumed. If not enough food, amount is > 0.
tablefillLevelsarray of floats indexed to fillTypeIndices. Is modified depending on how much food is conumed.
Return Values
floatreturnsa production weight between 0 and 1
Code
316function AnimalFoodManager:consumeFood(animalType, amountToConsume, fillLevels, consumedFood)
317 local production = 0.0
318 local animalFoodGroups = self.foodGroups[animalType]
319
320 -- print(string.format("-- [AnimalFoodManager:consumeFood] animalType(%s) animalFoodGroups(%s)", tostring(animalType), tostring(animalFoodGroups)))
321 if animalFoodGroups ~= nil then
322 -- print(string.format("-- [AnimalFoodManager:consumeFood] consumptionType(%d)", animalFoodGroups.consumptionType))
323 if animalFoodGroups.consumptionType == AnimalFoodManager.FOOD_CONSUME_TYPE_SERIAL then
324 production = self:consumeFoodSerially(amountToConsume, animalFoodGroups.content, fillLevels, consumedFood)
325 elseif animalFoodGroups.consumptionType == AnimalFoodManager.FOOD_CONSUME_TYPE_PARALLEL then
326 production = self:consumeFoodParallelly(amountToConsume, animalFoodGroups.content, fillLevels, consumedFood)
327 end
328 end
329 return production
330end

consumeFoodGroup

Description
Definition
consumeFoodGroup()
Code
379function AnimalFoodManager:consumeFoodGroup(foodGroup, amount, fillLevels, consumedFood)
380 for _, fillTypeIndex in pairs(foodGroup.fillTypes) do
381 if fillLevels[fillTypeIndex] ~= nil then
382 local currentFillLevel = fillLevels[fillTypeIndex]
383 local amountToConsume = -math.min(amount, currentFillLevel)
384 local deltaConsumed = self:changeFillLevels(amountToConsume, fillLevels, fillTypeIndex)
385
386 -- print(string.format("-- [AnimalFoodManager:consumeFoodGroup] foodGroup(%s) amount(%.3f) amountToConsume(%.3f) deltaConsumed(%.3f) fillTypeIndex(%s/%d) newAmount(%.3f)",
387 -- foodGroup.title,
388 -- amount,
389 -- amountToConsume,
390 -- deltaConsumed,
391 -- g_fillTypeManager:getFillTypeNameByIndex(fillTypeIndex), fillTypeIndex,
392 -- math.max(amount + deltaConsumed, 0.0)
393 -- ))
394 amount = math.max(amount + deltaConsumed, 0.0)
395 consumedFood[fillTypeIndex] = -deltaConsumed
396 if amount == 0.0 then
397 -- print(string.format("-- [AnimalFoodManager:consumeFoodGroup][A] EXIT"))
398 return amount
399 end
400 end
401 end
402 -- print(string.format("-- [AnimalFoodManager:consumeFoodGroup][B] EXIT restAmount(%.3f) ", amount))
403 return amount
404end

consumeFoodParallelly

Description
Definition
consumeFoodParallelly()
Code
359function AnimalFoodManager:consumeFoodParallelly(amount, foodGroups, fillLevels, consumedFood)
360 local productionWeight = 0.0
361
362 for _, foodGroup in pairs(foodGroups) do
363 local totalFillLevelInGroup = self:getTotalFillLevelInGroup(foodGroup, fillLevels)
364 local foodGroupConsume = amount * foodGroup.eatWeight
365 local consumeFood = math.min(totalFillLevelInGroup, foodGroupConsume)
366
367 local ret = self:consumeFoodGroup(foodGroup, consumeFood, fillLevels, consumedFood)
368 local foodFactor = (consumeFood-ret) / foodGroupConsume
369
370 productionWeight = productionWeight + foodFactor * foodGroup.productionWeight
371 end
372
373 return productionWeight
374end

consumeFoodSerially

Description
Definition
consumeFoodSerially()
Code
334function AnimalFoodManager:consumeFoodSerially(amount, foodGroups, fillLevels, consumedFood)
335 local productionWeight = 0.0
336 local totalAmountToConsume = amount
337
338 -- print(string.format("-- [AnimalFoodManager:consumeFoodSerially] ENTER"))
339 for _, foodGroup in ipairs(foodGroups) do
340 local oldAmount = amount
341 amount = self:consumeFoodGroup(foodGroup, amount, fillLevels, consumedFood)
342 local deltaProdWeight = ((oldAmount - amount) / totalAmountToConsume) * foodGroup.productionWeight
343 -- print(string.format("-- [AnimalFoodManager:consumeFoodSerially] deltaProdWeight(%.3f) amount(%.3f) oldAmount(%.3f) totalAmountToConsume(%.3f) foodGroup.productionWeight(%.3f)",
344 -- deltaProdWeight,
345 -- amount,
346 -- oldAmount,
347 -- totalAmountToConsume,
348 -- foodGroup.productionWeight
349 -- ))
350
351 productionWeight = productionWeight + deltaProdWeight
352 end
353 -- print(string.format("-- [AnimalFoodManager:consumeFoodSerially] EXIT: productionWeight(%.3f)", productionWeight))
354 return productionWeight
355end

getFoodConsumptionTypeByAnimalType

Description
Retrieve food consumption type by animal type.
Definition
getFoodConsumptionTypeByAnimalType(string animalType)
Arguments
stringanimalTypeAnimal type
Return Values
intFoodconsumption type, one of [AnimalFoodManager.FOOD_CONSUME_TYPE_SERIAL | AnimalFoodManager.FOOD_CONSUME_TYPE_PARALLEL]
Code
281function AnimalFoodManager:getFoodConsumptionTypeByAnimalType(animalType)
282 if animalType ~= nil then
283 return self.foodGroups[animalType].consumptionType
284 end
285
286 return nil
287end

getFoodGroupByAnimalIndex

Description
Retrieves food group by animal index
Definition
getFoodGroupByAnimalIndex(integer animalIndex)
Arguments
integeranimalIndex
Return Values
tablereturnsa food group or nil if nothing is found
Code
240function AnimalFoodManager:getFoodGroupByAnimalIndex(animalIndex)
241 if animalIndex ~= nil then
242 local animalType = g_animalManager:getAnimalType(animalIndex)
243 return self.foodGroups[animalType].content
244 end
245
246 return nil
247end

getFoodGroupByAnimalType

Description
Retrieves food group by animal type
Definition
getFoodGroupByAnimalType(string animalType)
Arguments
stringanimalType
Return Values
tablereturnsa food group or nil if nothing is found
Code
253function AnimalFoodManager:getFoodGroupByAnimalType(animalType)
254 if animalType ~= nil then
255 return self.foodGroups[animalType].content
256 end
257
258 return nil
259end

getFoodGroupByFillType

Description
Retrieves food group by fill type
Definition
getFoodGroupByFillType(string animalIndex, integer fillType)
Arguments
stringanimalIndex
integerfillType
Return Values
tablereturnsa food group or nil if not found
Code
294function AnimalFoodManager:getFoodGroupByFillType(animalType, fillTypeIndex)
295 local animalFoodGroups = self.foodGroups[animalType]
296
297 if animalFoodGroups ~= nil then
298 for _, foodGroup in pairs(animalFoodGroups.content) do
299 for _, foodGroupFillTypeIndex in pairs(foodGroup.fillTypes) do
300 if foodGroupFillTypeIndex == fillTypeIndex then
301 return foodGroup
302 end
303 end
304 end
305 end
306
307 return nil
308end

getFoodMixturesByAnimalType

Description
Retrieves food mixtures by animal type
Definition
getFoodMixturesByAnimalType(string animalType)
Arguments
stringanimalType
Return Values
tablereturnsa food mixture or nil if nothing is found
Code
265function AnimalFoodManager:getFoodMixturesByAnimalType(animalType)
266 if animalType ~= nil then
267 return self.animalFoodMixtures[animalType]
268 end
269
270 return nil
271end

getTotalFillLevelInGroup

Description
Definition
getTotalFillLevelInGroup()
Code
428function AnimalFoodManager:getTotalFillLevelInGroup(foodGroup, fillLevels)
429 local totalFillLevel = 0.0
430 for _, fillTypeIndex in pairs(foodGroup.fillTypes) do
431 if fillLevels[fillTypeIndex] ~= nil then
432 totalFillLevel = totalFillLevel + fillLevels[fillTypeIndex]
433 end
434 end
435 return totalFillLevel
436end

getTotalFillLevelInGroupByFillTypeIndex

Description
Definition
getTotalFillLevelInGroupByFillTypeIndex()
Code
417function AnimalFoodManager:getTotalFillLevelInGroupByFillTypeIndex(animalType, fillLevels, fillTypeIndex)
418 local foodGroup = self:getFoodGroupByFillType(animalType, fillTypeIndex)
419
420 if foodGroup ~= nil then
421 return self:getTotalFillLevelInGroup(foodGroup, fillLevels)
422 end
423 return 0.0
424end

initDataStructures

Description
Initialize data structures
Definition
initDataStructures()
Code
52function AnimalFoodManager:initDataStructures()
53 self.foodGroups = {}
54 self.foodMixtures = {}
55 self.animalFoodMixtures = {}
56end

loadFoodGroups

Description
Loads food groups
Definition
loadFoodGroups(table xmlFile)
Arguments
tablexmlFile
Return Values
booltrueif successful
Code
90function AnimalFoodManager:loadFoodGroups(xmlFile)
91 local i = 0
92
93 while true do
94 local animalKey = string.format("animalFood.animals.animalFoodGroups(%d)", i)
95 if not hasXMLProperty(xmlFile, animalKey) then
96 break
97 end
98 local animalType = getXMLString(xmlFile, animalKey.."#type")
99 if animalType ~= nil then
100 animalType = animalType:upper()
101 self.foodGroups[animalType] = {}
102 self.foodGroups[animalType].content = {}
103 self.foodGroups[animalType].consumptionType = AnimalFoodManager.FOOD_CONSUME_TYPE_SERIAL
104
105 local foodProcessTypeString = getXMLString(xmlFile, animalKey .. "#consumptionType")
106 foodProcessTypeString = foodProcessTypeString:upper()
107 if foodProcessTypeString == "PARALLEL" then
108 self.foodGroups[animalType].consumptionType = AnimalFoodManager.FOOD_CONSUME_TYPE_PARALLEL
109 end
110
111 local j = 0
112 while true do
113 local groupKey = string.format("%s.foodGroup(%d)", animalKey, j)
114 if not hasXMLProperty(xmlFile, groupKey) then
115 break
116 end
117
118 local foodGroup = {}
119 foodGroup.title = g_i18n:convertText(Utils.getNoNil(getXMLString(xmlFile, groupKey.."#title"), ""))
120 foodGroup.productionWeight = Utils.getNoNil(getXMLFloat(xmlFile, groupKey.."#productionWeight"), 0.0)
121 foodGroup.eatWeight = Utils.getNoNil(getXMLFloat(xmlFile, groupKey.."#eatWeight"), 1.0)
122 foodGroup.fillTypes = {}
123 local fillTypesStr = Utils.getNoNil(getXMLString(xmlFile, groupKey.."#fillTypes"), "")
124 local warning = string.format("Warning: FillType '%s' undefined for foodGroups of '%s'. Ignoring it!", tostring(fillTypeName), tostring(animalType))
125 foodGroup.fillTypes = g_fillTypeManager:getFillTypesByNames(fillTypesStr, warning)
126 table.insert(self.foodGroups[animalType].content, foodGroup)
127 j = j + 1
128 end
129 end
130 i = i + 1
131 end
132 return true
133end

loadMapData

Description
Load data on map load
Definition
loadMapData()
Return Values
booleantrueif loading was successful else false
Code
61function AnimalFoodManager:loadMapData(xmlFile, missionInfo)
62 AnimalFoodManager:superClass().loadMapData(self)
63
64 local filename = Utils.getFilename(getXMLString(xmlFile, "map.husbandryFood#filename"), g_currentMission.baseDirectory)
65 if filename == nil or filename == "" then
66 print("Error: Could not load husbandry food configuration file '" .. tostring(filename) .. "'!")
67 return false
68 end
69 local foodGroupsLoaded = false
70 local mixturesLoaded = false
71 local foodGroupsNormalized = false
72 local mixturesNormalized = false
73 local animalFoodXmlFile = loadXMLFile("animalFood", filename)
74
75 if animalFoodXmlFile ~= nil then
76 foodGroupsLoaded = self:loadFoodGroups(animalFoodXmlFile)
77 mixturesLoaded = self:loadMixtures(animalFoodXmlFile)
78 foodGroupsNormalized = self:normalizeFoodGroupWeights()
79 mixturesNormalized = self:normalizeMixtureWeights()
80 delete(animalFoodXmlFile)
81 end
82
83 return foodGroupsLoaded and mixturesLoaded and foodGroupsNormalized and mixturesNormalized
84end

loadMixtures

Description
Loads food groups
Definition
loadMixtures(table xmlFile)
Arguments
tablexmlFile
Return Values
booltrueif successful
Code
139function AnimalFoodManager:loadMixtures(xmlFile)
140 local i = 0
141
142 while true do
143 local mixtureKey = string.format("animalFood.foodMixtures.foodMixture(%d)", i)
144 if not hasXMLProperty(xmlFile, mixtureKey) then
145 break
146 end
147
148 local mixtureFillTypeName = Utils.getNoNil(getXMLString(xmlFile, mixtureKey.."#fillType"), "")
149 local animalType = Utils.getNoNil(getXMLString(xmlFile, mixtureKey.."#type"), "")
150 if animalType ~= nil then
151 animalType = animalType:upper()
152 if self.animalFoodMixtures[animalType] == nil then
153 self.animalFoodMixtures[animalType] = {}
154 end
155
156 local mixtureFillType = g_fillTypeManager:getFillTypeByName(mixtureFillTypeName)
157 if mixtureFillType ~= nil then
158 local fillType = mixtureFillType.index
159 table.insert(self.animalFoodMixtures[animalType], fillType)
160 self.foodMixtures[fillType] = {}
161 self.foodMixtures[fillType].ingredients = {}
162
163 local j = 0
164 while true do
165 local ingredientKey = string.format("%s.ingredient(%d)", mixtureKey, j)
166 if not hasXMLProperty(xmlFile, ingredientKey) then
167 break
168 end
169
170 local ingredient = {}
171 local warning = string.format("Warning: FillType '%s' undefined for mixture of '%s'. Ignoring it!", tostring(fillTypeName), tostring(mixtureFillTypeName))
172 local fillTypesStr = Utils.getNoNil(getXMLString(xmlFile, ingredientKey.."#fillTypes"), "")
173
174 ingredient.fillTypes = g_fillTypeManager:getFillTypesByNames(fillTypesStr, warning)
175 ingredient.weight = Utils.getNoNil(getXMLFloat(xmlFile, ingredientKey.."#weight"), 0.0)
176 table.insert(self.foodMixtures[fillType].ingredients, ingredient)
177 j = j + 1
178 end
179 else
180 print("Warning: FillType '"..tostring(fillTypeName).."' undefined for mixtures. Ignoring it!")
181 return false
182 end
183 end
184 i = i + 1
185 end
186 return true
187end

new

Description
Creating manager
Definition
new()
Return Values
tableinstanceinstance of object
Code
44function AnimalFoodManager:new(customMt)
45 local self = AbstractManager:new(customMt or AnimalFoodManager_mt)
46
47 return self
48end

normalizeFoodGroupWeights

Description
Normalize food groups weight if parallel consumption type
Definition
normalizeFoodGroupWeights()
Return Values
booltrueif normalized
Code
192function AnimalFoodManager:normalizeFoodGroupWeights()
193 for _, animalFoodGroup in pairs(self.foodGroups) do
194 if animalFoodGroup.consumptionType == AnimalFoodManager.FOOD_CONSUME_TYPE_PARALLEL then
195 local sumWeigths = 0
196 local eatWeights = 0
197 for _, foodGroup in pairs(animalFoodGroup.content) do
198 sumWeigths = sumWeigths + foodGroup.productionWeight
199 eatWeights = eatWeights + foodGroup.eatWeight
200 end
201
202 for _, foodGroup in pairs(animalFoodGroup.content) do
203 if sumWeigths > 0 then
204 foodGroup.productionWeight = foodGroup.productionWeight / sumWeigths
205 end
206 if eatWeights > 0 then
207 foodGroup.eatWeight = foodGroup.eatWeight / eatWeights
208 end
209 end
210 end
211 end
212
213 return true
214end

normalizeMixtureWeights

Description
Normalize mixture's ingredient weight
Definition
normalizeMixtureWeights()
Return Values
booltrueif normalized
Code
219function AnimalFoodManager:normalizeMixtureWeights()
220 for _, mixture in pairs(self.foodMixtures) do
221 local sumWeigths = 0
222 for _, ingredient in pairs(mixture.ingredients) do
223 sumWeigths = sumWeigths + ingredient.weight
224 end
225
226 if sumWeigths > 0 then
227 for _, ingredient in pairs(mixture.ingredients) do
228 ingredient.weight = ingredient.weight / sumWeigths
229 end
230 end
231 end
232
233 return true
234end