LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

WildlifeSpawner

Description
Wildlife Spawner class
XML Configuration Parameters
wildlifeSpawner#maxCost/ max cost of all animals generated by the spawner
wildlifeSpawner#checkTimeInterval/ how often creation process is executed (in seconds)
wildlifeSpawner.area#areaSpawnRadius/ radius of the main spawn circle, testing circles are placed on this radius
wildlifeSpawner.area#areaMaxRadius/ radius where animals are removed
wildlifeSpawner.area#spawnCircleRadius/ radius of testing circles
wildlifeSpawner.area.species#name/ name of the animal to spawn
wildlifeSpawner.area.species#config/ configuration file of the animal to spawn
wildlifeSpawner.area.species.spawnRules#hours/ daytimes where we can spawn an animal
wildlifeSpawner.area.species.spawnRules#onField/ if true, will spawn on field ground
wildlifeSpawner.area.species.spawnRules#hasTrees/ if true, will spawn if trees in testing circle
wildlifeSpawner.area.species.cost/ cost of one animal
wildlifeSpawner.area.species.maxCount/ maximal amount of animal to spawn
wildlifeSpawner.area.species.spawnCount/ how many animals to spawn in one group
wildlifeSpawner.area.species.groupSpawnRadius/ radius within which the animals are spawned

Functions

addAreaOfInterest

Description
Adds an area of interest to check
Definition
addAreaOfInterest(float liveTime, float posX, float posZ, float radius)
Arguments
floatliveTimehow long the area is available
floatposXx world position
floatposZz world position
floatradiusradius of the area in m
Code
623function WildlifeSpawner:addAreaOfInterest(liveTime, posX, posZ, radius)
624 if #self.areasOfInterest <= self.maxAreaOfInterest then
625 local info = {}
626 info.liveTime = liveTime
627 info.positionX = posX
628 info.positionZ = posZ
629 info.radius = radius
630 info.timeToLive = self.areaOfInterestliveTime
631 table.insert(self.areasOfInterest, info)
632 end
633end

animalExists

Description
Definition
animalExists()
Return Values
bool
Code
638function WildlifeSpawner:animalExists(spawnId, animalId)
639 for _, area in pairs(self.areas) do
640 for _, species in pairs(area.species) do
641 if species.classType == "companionAnimal" then
642 for _, spawn in pairs(species.spawned) do
643 if spawn.spawnId == spawnId and animalId < spawn.count then
644 return true
645 end
646 end
647 end
648 end
649 end
650 return false
651end

checkArea

Description
Check area with to see if we should spawn animals (trees amount, is a field, is in water, hours of the day)
Definition
checkArea(float x, float y, float z, table rules, float radius)
Arguments
floatxx world position from which areas are checked
floatyy world position from which areas are checked
floatzz world position from which areas are checked
tablerulesrules to check against for the species
floatradiusradius of the test
Return Values
boolreturnstrue if all tests are validated
Code
425function WildlifeSpawner:checkArea(x, y, z, rules, radius, isInWater)
426 local validArea = false
427 local currentHour = math.floor(g_currentMission.environment.dayTime / (60 * 60 * 1000))
428 local isOnField
429 local hasTrees
430
431 for _, rule in pairs(rules) do
432 if (currentHour >= rule.hourFrom or currentHour <= rule.hourTo) then
433 local validRule = true
434 if rule.onField ~= WildlifeSpawner.RULE.DONT_CARE then
435 if isOnField == nil then
436 isOnField, _ = FSDensityMapUtil.getFieldDataAtWorldPosition(x, y, z)
437 end
438 validRule = (rule.onField == WildlifeSpawner.RULE.REQUIRED and isOnField) or
439 (rule.onField == WildlifeSpawner.RULE.NOT_ALLOWED and not isOnField)
440 end
441
442 if validRule and rule.hasTrees ~= WildlifeSpawner.RULE.DONT_CARE then
443 if hasTrees == nil then
444 hasTrees = self:countTrees(x, y, z, radius) > 3
445 end
446 validRule = (rule.hasTrees == WildlifeSpawner.RULE.REQUIRED and hasTrees) or
447 (rule.hasTrees == WildlifeSpawner.RULE.NOT_ALLOWED and not hasTrees)
448 end
449
450 if validRule and rule.inWater ~= WildlifeSpawner.RULE.DONT_CARE then
451 validRule = (rule.inWater == WildlifeSpawner.RULE.REQUIRED and isInWater) or
452 (rule.inWater == WildlifeSpawner.RULE.NOT_ALLOWED and not isInWater)
453 end
454
455 if validRule then
456 validArea = true
457 break
458 end
459 end
460 end
461
462 return validArea
463end

checkAreas

Description
For each areas, we try to spawn first in areas of interests that have been registered by workAreas. If there is no spawn then, we try to spawn at a random position around the player.
Definition
checkAreas(float x, float y, float z)
Arguments
floatxx world position from which areas are checked
floatyy world position from which areas are checked
floatzz world position from which areas are checked
Code
388function WildlifeSpawner:checkAreas(x, y, z)
389 local testX = x
390 local testZ = z
391 local testY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, testX, 0, testZ) + 0.5
392
393 local isInWater = self:getIsInWater(testX, testY, testZ)
394
395 for _, area in pairs(self.areas) do
396 local hasSpawned = false
397 for _, interestArea in pairs(self.areasOfInterest) do
398 local distSq = (testX - interestArea.positionX) * (testX - interestArea.positionX) + (testZ - interestArea.positionZ) * (testZ - interestArea.positionZ)
399 if (distSq < (area.areaSpawnRadius * area.areaSpawnRadius)) then
400 hasSpawned = self:trySpawnAtArea(area.species, interestArea.radius, testX, testY, testZ, isInWater)
401 if hasSpawned then
402 break
403 end
404 end
405 end
406 if not hasSpawned then
407 local angle = math.rad(math.random(0, 360))
408 testX = x + area.areaSpawnRadius * math.cos(angle) - area.areaSpawnRadius * math.sin(angle)
409 testZ = z + area.areaSpawnRadius * math.cos(angle) + area.areaSpawnRadius * math.sin(angle)
410 testY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, testX, 0, testZ) + 0.5
411
412 self:trySpawnAtArea(area.species, area.spawnCircleRadius, testX, testY, testZ, isInWater)
413 end
414 end
415end

consoleCommandAddWildlifeAnimalToDebug

Description
Definition
consoleCommandAddWildlifeAnimalToDebug()
Return Values
stringthatwill be displayed on console
Code
668function WildlifeSpawner:consoleCommandAddWildlifeAnimalToDebug(spawnId, animalId)
669 local argsTest = true
670 spawnId = tonumber(spawnId)
671 if spawnId == nil then
672 argsTest = false
673 end
674 animalId = tonumber(animalId)
675 if animalId == nil then
676 argsTest = false
677 end
678
679 if argsTest and self:animalExists(spawnId, animalId) then
680 table.insert(self.debugAnimalList, {spawnId = spawnId, animalId = animalId})
681 return string.format("-- added [spawn(%d)][animal(%d)] to debug list.", spawnId, animalId)
682 else
683 return string.format("-- gsWildlifeAddAnimalToDebug [spawnId][animalId]")
684 end
685end

consoleCommandRemoveWildlifeAnimalToDebug

Description
Definition
consoleCommandRemoveWildlifeAnimalToDebug()
Return Values
stringthatwill be displayed on console
Code
690function WildlifeSpawner:consoleCommandRemoveWildlifeAnimalToDebug(spawnId, animalId)
691 local argsTest = true
692 spawnId = tonumber(spawnId)
693 if spawnId == nil then
694 argsTest = false
695 end
696 animalId = tonumber(animalId)
697 if animalId == nil then
698 argsTest = false
699 end
700 if argsTest then
701 for key, entry in pairs(self.debugAnimalList) do
702 if entry.spawnId == spawnId and entry.animalId == animalId then
703 table.remove(self.debugAnimalList, key)
704 return string.format("-- removed [spawn(%d)][animal(%d)] from debug list.", spawnId, animalId)
705 end
706 end
707 end
708 return string.format("-- gsWildlifeRemoveAnimalToDebug [spawnId][animalId]")
709end

consoleCommandToggleEnabled

Description
Definition
consoleCommandToggleEnabled()
Code
762function WildlifeSpawner:consoleCommandToggleEnabled(state)
763 if state ~= nil then
764 state = Utils.stringToBoolean(state)
765 end
766 self.isEnabled = Utils.getNoNil(state, not self.isEnabled)
767
768 if not self.isEnabled then
769 self:removeAllAnimals()
770 print("removed all wildlife animals")
771 end
772
773 return string.format("Wildlife isEnabled=%s", self.isEnabled)
774end

consoleCommandToggleShowWildlife

Description
Definition
consoleCommandToggleShowWildlife()
Return Values
stringthatwill be displayed on console
Code
715function WildlifeSpawner:consoleCommandToggleShowWildlife()
716 self.debugShow = not self.debugShow
717
718 return string.format("-- show Wildlife debug = %s", tostring(self.debugShow))
719end

consoleCommandToggleShowWildlifeAnimation

Description
Definition
consoleCommandToggleShowWildlifeAnimation()
Return Values
stringthatwill be displayed on console
Code
754function WildlifeSpawner:consoleCommandToggleShowWildlifeAnimation()
755 self.debugShowAnimation = not self.debugShowAnimation
756
757 return string.format("-- show Wildlife Animation = %s", tostring(self.debugShowAnimation))
758end

consoleCommandToggleShowWildlifeId

Description
Definition
consoleCommandToggleShowWildlifeId()
Return Values
stringthatwill be displayed on console
Code
724function WildlifeSpawner:consoleCommandToggleShowWildlifeId()
725 self.debugShowId = self.debugShowId + 1
726
727 if self.debugShowId > WildlifeSpawner.DEBUGSHOWIDSTATES.MAX then
728 self.debugShowId = WildlifeSpawner.DEBUGSHOWIDSTATES.NONE
729 end
730
731 local state = ""
732 if (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.NONE) then
733 state = "NONE"
734 elseif (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.SINGLE) then
735 state = "SINGLE"
736 elseif (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.ALL) then
737 state = "ALL"
738 end
739 return string.format("-- show Wildlife Id = %s", state)
740end

consoleCommandToggleShowWildlifeSteering

Description
Definition
consoleCommandToggleShowWildlifeSteering()
Return Values
stringthatwill be displayed on console
Code
745function WildlifeSpawner:consoleCommandToggleShowWildlifeSteering()
746 self.debugShowSteering = not self.debugShowSteering
747
748 return string.format("-- show Wildlife Steering = %s", tostring(self.debugShowSteering))
749end

countAnimalsTobeSpawned

Description
Calculate a random amount of animals that can be spawned for a species
Definition
countAnimalsTobeSpawned(table species)
Arguments
tablespecies
Return Values
integerreturnsthe number of animals to spawn
Code
508function WildlifeSpawner:countAnimalsTobeSpawned(species)
509 local remainingAnimal = math.floor((self.maxCost - self.totalCost) / species.cost)
510
511 if species.minCount > remainingAnimal then
512 return 0
513 end
514 local deltaNbAnimals = species.maxCount - species.minCount
515 local nbAnimals = species.minCount + math.random(1, deltaNbAnimals)
516 nbAnimals = math.min(remainingAnimal, nbAnimals)
517 return nbAnimals
518end

countTrees

Description
Count number of trees
Definition
countTrees(float x, float y, float z, radius radius)
Arguments
floatxx world position from which areas are checked
floatyy world position from which areas are checked
floatzz world position from which areas are checked
radiusradiusof the test in m
Return Values
integernumberof trees found
Code
472function WildlifeSpawner:countTrees(x, y, z, radius)
473 self.treeCount = 0
474 overlapSphere(x, y, z, radius, "treeCountTestCallback", self, CollisionFlag.TREE, false, true, false)
475 --overlapBox(x, y, z, 0, 1, 0, radius, radius, radius, "treeCountTestCallback", self, self.collisionDetectionMask, false, true, false)
476 return self.treeCount
477end

debugDraw

Description
Display debug information
Definition
debugDraw()
Code
562function WildlifeSpawner:debugDraw()
563 renderText(0.02, 0.95, 0.02, string.format("Wildlife Info\nCost(%d / %d)", self.totalCost, self.maxCost))
564 local passedTest, originX, originY, originZ = self:getPlayerCenter()
565
566 if passedTest then
567 for _, area in pairs(self.areas) do
568 for _, species in pairs(area.species) do
569 for _, spawn in pairs(species.spawned) do
570 if spawn.spawnId ~= nil then
571 local distance = 0.0
572
573 if species.classType == "companionAnimal" then
574 distance, _ = getCompanionClosestDistance(spawn.spawnId, originX, originY, originZ)
575 elseif species.classType == "lightWildlife" then
576 distance = species.lightWildlife:getClosestDistance(originX, originY, originZ)
577 distance = math.sqrt(distance)
578 end
579 local text = string.format("[%s][%d]\n- nearest player distance (%.3f)", species.name, spawn.spawnId, distance)
580
581 Utils.renderTextAtWorldPosition(spawn.posX, spawn.posY + 0.12, spawn.posZ, text, getCorrectTextSize(0.012), 0)
582 DebugUtil.drawDebugCubeAtWorldPos(spawn.posX, spawn.posY, spawn.posZ, 1, 0, 0, 0, 1, 0, 0.05, 0.05, 0.05, 1.0, 1.0, 0.0)
583 DebugUtil.drawDebugCircle(spawn.posX, spawn.posY, spawn.posZ, species.groupSpawnRadius, 10.0, {1.0, 1.0, 0.0})
584 end
585 end
586 end
587 end
588 end
589
590 for _, area in pairs(self.areas) do
591 for _, species in pairs(area.species) do
592 if species.classType == "companionAnimal" then
593 for _, spawn in pairs(species.spawned) do
594 for animalId=0, spawn.count - 1 do
595 local showAdditionalInfo = self:isInDebugList(spawn.spawnId, animalId)
596 local showId = (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.SINGLE and showAdditionalInfo) or self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.ALL
597 companionDebugDraw(spawn.spawnId, animalId, showId, showAdditionalInfo and self.debugShowSteering, showAdditionalInfo and self.debugShowAnimation)
598 end
599 end
600 end
601 end
602 end
603end

delete

Description
Delete instance
Definition
delete()
Code
81function WildlifeSpawner:delete()
82 self:removeAllAnimals()
83 for _, area in pairs(self.areas) do
84 for _, species in pairs(area.species) do
85 if species.lightWildlife ~= nil then
86 species.lightWildlife:delete()
87 end
88 end
89 end
90
91 self.areas = {}
92
93 removeConsoleCommand("gsWildlifeToggle")
94 removeConsoleCommand("gsWildlifeDebug")
95 removeConsoleCommand("gsWildlifeDebugId")
96 removeConsoleCommand("gsWildlifeDebugSteering")
97 removeConsoleCommand("gsWildlifeDebugAnimation")
98 removeConsoleCommand("gsWildlifeDebugAnimalAdd")
99 removeConsoleCommand("gsWildlifeDebugAnimalRemove")
100end

getIsInWater

Description
Check if position is in water
Definition
getIsInWater(float x, float y, float z)
Arguments
floatxx world position from which areas are checked
floatyy world position from which areas are checked
floatzz world position from which areas are checked
Return Values
boolreturnstrue if there is water
Code
499function WildlifeSpawner:getIsInWater(x, y, z)
500 local waterY = g_currentMission.environmentAreaSystem:getWaterYAtWorldPosition(x, y, z) or -2000
501 return waterY > y
502end

getPlayerCenter

Description
Get player location from which the tests should be done
Definition
getPlayerCenter()
Return Values
floatxworld position. default is 0
floatxworld position. default is 0
floatxworld position. default is 0
Code
344function WildlifeSpawner:getPlayerCenter()
345 if self.playerNode ~= nil and entityExists(self.playerNode) then
346 local x, y, z = getWorldTranslation(self.playerNode)
347 return true, x, y, z
348 end
349 return false, 0, 0, 0
350end

isInDebugList

Description
Definition
isInDebugList()
Return Values
bool
Code
656function WildlifeSpawner:isInDebugList(spawnId, animalId)
657 for _, entry in pairs(self.debugAnimalList) do
658 if entry.spawnId == spawnId and entry.animalId == animalId then
659 return true
660 end
661 end
662 return false
663end

loadMapData

Description
Loads xml file (areas and containing animals)
Definition
loadMapData(table xmlFile)
Arguments
tablexmlFileXML file handle
Return Values
boolreturnstrue if load is successful
Code
134function WildlifeSpawner:loadMapData(xmlFile)
135 local filename = getXMLString(xmlFile, "map.wildlife#filename")
136 if filename == nil or filename == "" then
137 Logging.xmlInfo(xmlFile, "No wildlife config file defined")
138 return false
139 end
140
141 filename = Utils.getFilename(filename, g_currentMission.baseDirectory)
142
143 local wildlifeXmlFile = loadXMLFile("wildlife", filename)
144 if wildlifeXmlFile == 0 or wildlifeXmlFile == nil then
145 Logging.xmlError(xmlFile, "Could not load wildlife config file '%s'", filename)
146 return false
147 end
148
149 self.maxCost = Utils.getNoNil(getXMLInt(wildlifeXmlFile, "wildlifeSpawner#maxCost"), 0)
150 self.checkTimeInterval = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, "wildlifeSpawner#checkTimeInterval"), 1.0) * 1000.0
151 self.maxAreaOfInterest = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, "wildlifeSpawner#maxAreaOfInterest"), 1)
152 self.areaOfInterestliveTime = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, "wildlifeSpawner#areaOfInterestliveTime"), 1.0) * 1000.0
153 local i = 0
154 while true do
155 local areaBaseString = string.format("wildlifeSpawner.area(%d)", i)
156 if not hasXMLProperty(wildlifeXmlFile, areaBaseString) then
157 break
158 end
159 local newArea = {}
160 newArea.areaSpawnRadius = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, areaBaseString .. "#areaSpawnRadius"), 1.0)
161 newArea.areaMaxRadius = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, areaBaseString .. "#areaMaxRadius"), 1.0)
162 newArea.spawnCircleRadius = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, areaBaseString .. "#spawnCircleRadius"), 1.0)
163
164 newArea.species = {}
165 local j = 0
166 while true do
167 local speciesBaseString = string.format("%s.species(%d)", areaBaseString, j)
168 if not hasXMLProperty(wildlifeXmlFile, speciesBaseString) then
169 break
170 end
171 local classTypeString = getXMLString(wildlifeXmlFile, speciesBaseString .. "#classType")
172 local classType = nil
173
174 if classTypeString ~= nil then
175 if string.lower(classTypeString) == "companionanimal" then
176 classType = "companionAnimal"
177 elseif string.lower(classTypeString) == "lightwildlife" then
178 classType = "lightWildlife"
179 end
180 end
181 if classType ~= nil then
182 local newSpecies = {}
183 newSpecies.classType = classType
184 newSpecies.name = getXMLString(wildlifeXmlFile, speciesBaseString .. "#name")
185 newSpecies.configFilename = getXMLString(wildlifeXmlFile, speciesBaseString .. "#config")
186 newSpecies.cost = getXMLFloat(wildlifeXmlFile, speciesBaseString .. ".cost")
187 newSpecies.minCount = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".minCount")
188 newSpecies.maxCount = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".maxCount")
189 newSpecies.currentCount = 0
190 newSpecies.spawnCount = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".spawnCount")
191 newSpecies.groupSpawnRadius = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".groupSpawnRadius")
192 newSpecies.spawned = {}
193 newSpecies.lightWildlife = nil
194 if classType == "lightWildlife" then
195 if newSpecies.name == "crow" then
196 newSpecies.lightWildlife = CrowsWildlife.new()
197 newSpecies.lightWildlife:load(Utils.getNoNil(getXMLString(wildlifeXmlFile, speciesBaseString .. "#config"), ""))
198 end
199 end
200
201 newSpecies.spawnRules = {}
202 local k = 0
203 while true do
204 local spawnRuleBaseString = string.format("%s.spawnRules.rule(%d)", speciesBaseString, k)
205 if not hasXMLProperty(wildlifeXmlFile, spawnRuleBaseString) then
206 break
207 end
208
209 local newRule = {}
210 newRule.hourFrom = getXMLInt(wildlifeXmlFile, spawnRuleBaseString .. "#hourFrom")
211 newRule.hourTo = getXMLInt(wildlifeXmlFile, spawnRuleBaseString .. "#hourTo")
212 newRule.onField = self:parseSpawnRule(getXMLString(wildlifeXmlFile, spawnRuleBaseString .. "#onField"))
213 newRule.hasTrees = self:parseSpawnRule(getXMLString(wildlifeXmlFile, spawnRuleBaseString .. "#hasTrees"))
214 newRule.inWater = self:parseSpawnRule(getXMLString(wildlifeXmlFile, spawnRuleBaseString .. "#inWater"))
215 table.insert(newSpecies.spawnRules, newRule)
216 k = k + 1
217 end
218
219 table.insert(newArea.species, newSpecies)
220 end
221 j = j + 1
222 end
223 table.insert(self.areas, newArea)
224 i = i + 1
225 end
226 delete(wildlifeXmlFile)
227
228 return true
229end

new

Description
Creating instance
Definition
new(table customMt)
Arguments
tablecustomMtcustom meta table
Return Values
tableinstanceInstance of object
Code
45function WildlifeSpawner.new(customMt)
46 local self = setmetatable({}, customMt or WildlifeSpawner_mt)
47
48 self.isEnabled = true -- flag to disable all wildlife
49 self.collisionDetectionMask = 4096 -- dynamic_objects
50 self.maxCost = 0
51 self.checkTimeInterval = 0.0
52 self.nextCheckTime = 0.0
53 self.areas = {}
54 self.areasOfInterest = {}
55 self.totalCost = 0
56 self.treeCount = 0
57 self.playerNode = nil
58 self.avoidDistance = 20
59
60 -- Debug
61 -- if g_addCheatCommands then
62 self.debugAnimalList = {}
63 self.debugShow = false
64 self.debugShowId = WildlifeSpawner.DEBUGSHOWIDSTATES.NONE
65 self.debugShowSteering = false
66 self.debugShowAnimation = false
67 addConsoleCommand("gsWildlifeToggle", "Toggle wildlife on map", "consoleCommandToggleEnabled", self)
68 addConsoleCommand("gsWildlifeDebug", "Toggle shows/hide all wildlife debug information.", "consoleCommandToggleShowWildlife", self)
69 addConsoleCommand("gsWildlifeDebugId", "Toggle shows/hide all wildlife animal id.", "consoleCommandToggleShowWildlifeId", self)
70 addConsoleCommand("gsWildlifeDebugSteering", "Toggle shows/hide animal steering information.", "consoleCommandToggleShowWildlifeSteering", self)
71 addConsoleCommand("gsWildlifeDebugAnimation", "Toggle shows/hide animal animation information.", "consoleCommandToggleShowWildlifeAnimation", self)
72 addConsoleCommand("gsWildlifeDebugAnimalAdd", "Adds an animal to a debug list.", "consoleCommandAddWildlifeAnimalToDebug", self)
73 addConsoleCommand("gsWildlifeDebugAnimalRemove", "Removes an animal to a debug list.", "consoleCommandRemoveWildlifeAnimalToDebug", self)
74 -- end
75
76 return self
77end

onConnectionClosed

Description
Definition
onConnectionClosed()
Code
104function WildlifeSpawner:onConnectionClosed()
105 self:removeAllAnimals()
106end

parseSpawnRule

Description
Parse rule value string
Definition
parseSpawnRule(string input)
Arguments
stringinputstring to parse
Code
235function WildlifeSpawner:parseSpawnRule(ruleValue)
236 if string.lower(ruleValue) == "required" then
237 return WildlifeSpawner.RULE.REQUIRED
238 elseif string.lower(ruleValue) == "notallowed" then
239 return WildlifeSpawner.RULE.NOT_ALLOWED
240 elseif string.lower(ruleValue) == "dontcare" then
241 return WildlifeSpawner.RULE.DONT_CARE
242 else
243 return WildlifeSpawner.RULE.DONT_CARE
244 end
245end

removeAllAnimals

Description
Definition
removeAllAnimals()
Code
110function WildlifeSpawner:removeAllAnimals()
111 for _, area in pairs(self.areas) do
112 for _, species in pairs(area.species) do
113 for i=#species.spawned, 1, -1 do
114 if species.classType == "companionAnimal" then
115 local spawn = species.spawned[i]
116 if spawn.spawnId ~= nil then
117 delete(spawn.spawnId)
118 spawn.spawnId = nil
119 end
120 elseif species.classType == "lightWildlife" and species.lightWildlife ~= nil then
121 species.lightWildlife:removeAllAnimals()
122 end
123 table.remove(species.spawned, i)
124 end
125 end
126 end
127 self.totalCost = 0
128end

removeFarAwayAnimals

Description
Removing animals that are too far away
Definition
removeFarAwayAnimals()
Code
300function WildlifeSpawner:removeFarAwayAnimals()
301 local passedTest, originX, originY, originZ = self:getPlayerCenter()
302
303 if passedTest then
304 for _, area in pairs(self.areas) do
305 for _, species in pairs(area.species) do
306 if species.classType == "companionAnimal" then
307 for i=#species.spawned, 1, -1 do
308 local spawn = species.spawned[i]
309 if spawn.spawnId ~= nil then
310 local distance, _ = getCompanionClosestDistance(spawn.spawnId, originX, originY, originZ)
311
312 if distance > area.areaMaxRadius then
313 delete(spawn.spawnId)
314 spawn.spawnId = nil
315 species.currentCount = species.currentCount - spawn.count
316 self.totalCost = self.totalCost - species.cost * spawn.count
317 table.remove(species.spawned, i)
318 end
319 end
320 end
321 elseif species.classType == "lightWildlife" and species.lightWildlife ~= nil then
322 local removedAnimalsCount = species.lightWildlife:removeFarAwayAnimals(area.areaMaxRadius, originX, originY, originZ)
323 if removedAnimalsCount > 0 then
324 species.currentCount = species.currentCount - removedAnimalsCount
325 self.totalCost = self.totalCost - species.cost * removedAnimalsCount
326 for i=#species.spawned, 1, -1 do
327 --local spawn = species.spawned[i]
328 if species.lightWildlife:countSpawned() == 0 then
329 table.remove(species.spawned, i)
330 end
331 end
332 end
333 end
334 end
335 end
336 end
337end

spawnAnimals

Description
Spawn animals
Definition
spawnAnimals(table species, float spawnPosX, float spawnPosY, float spawnPosZ)
Arguments
tablespeciesspecies to spawn
floatspawnPosXx world position to spawn
floatspawnPosYy world position to spawn
floatspawnPosZz world position to spawn
Return Values
boolreturnstrue if animals are spawned
Code
527function WildlifeSpawner:spawnAnimals(species, spawnPosX, spawnPosY, spawnPosZ)
528 local xmlFilename = Utils.getFilename(species.configFilename, g_currentMission.loadingMapBaseDirectory)
529
530 if species.name == nil or
531 xmlFilename == nil or
532 g_currentMission.terrainRootNode == nil or
533 species.currentCount >= species.maxCount then
534 return false
535 end
536 local nbAnimals = self:countAnimalsTobeSpawned(species)
537 if nbAnimals == 0 then
538 return false
539 end
540 local id = nil
541 if species.classType == "companionAnimal" then
542 id = createAnimalCompanionManager(species.name, xmlFilename, "wildlifeAnimal", spawnPosX, spawnPosY, spawnPosZ, g_currentMission.terrainRootNode, g_currentMission:getIsServer(), g_currentMission:getIsClient(), nbAnimals, AudioGroup.ENVIRONMENT)
543 setCompanionAvoidPlayer(id, self.playerNode, self.avoidDistance)
544
545 local groundMask = CollisionFlag.TERRAIN + CollisionFlag.STATIC_WORLD
546 local obstacleMask = CollisionFlag.STATIC_OBJECTS + CollisionFlag.DYNAMIC_OBJECT + CollisionFlag.VEHICLE
547 setCompanionCollisionMask(id, groundMask, obstacleMask, CollisionFlag.WATER)
548 elseif species.classType == "lightWildlife" then
549 id = species.lightWildlife:createAnimals(species.name, spawnPosX, spawnPosY, spawnPosZ, nbAnimals)
550 end
551 if (id ~= nil) and (id ~= 0) then
552 table.insert(species.spawned, {spawnId = id, posX = spawnPosX, posY = spawnPosY, posZ = spawnPosZ, count = nbAnimals, avoidNode = self.playerNode})
553 species.currentCount = species.currentCount + nbAnimals
554 self.totalCost = self.totalCost + species.cost * nbAnimals
555 return true
556 end
557 return false
558end

treeCountTestCallback

Description
Tree count callback
Definition
treeCountTestCallback(integer transformId)
Arguments
integertransformId- transformId of the element detected in the overlap test
Return Values
booltrueto continue counting trees
Code
483function WildlifeSpawner:treeCountTestCallback(transformId)
484 if transformId ~= 0 and getHasClassId(transformId, ClassIds.SHAPE) then
485 local object = getParent(transformId)
486 if object ~= nil and getSplitType(transformId) ~= 0 then
487 self.treeCount = self.treeCount + 1
488 end
489 end
490 return true
491end

trySpawnAtArea

Description
We try to spawn one animal type if the rules are valid
Definition
trySpawnAtArea(table species, float spawnCircleRadius, float testX, float testY, float testZ)
Arguments
tablespeciesspecies information
floatspawnCircleRadiusspawn circle radius in m
floattestXx world position to test
floattestYy world position to test
floattestZz world position to test
Return Values
boolreturnstrue if animals are spawned
Code
369function WildlifeSpawner:trySpawnAtArea(species, spawnCircleRadius, testX, testY, testZ, isInWater)
370 for _, animalType in pairs(species) do
371 if self:checkArea(testX, testY, testZ, animalType.spawnRules, spawnCircleRadius, isInWater) then
372 local spawnPosX = testX + math.random() * spawnCircleRadius
373 local spawnPosZ = testZ + math.random() * spawnCircleRadius
374 local spawnPosY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, spawnPosX, 0, spawnPosZ) + 0.5
375 if self:spawnAnimals(animalType, spawnPosX, spawnPosY, spawnPosZ) then
376 return true
377 end
378 end
379 end
380 return false
381end

update

Description
Update function. Regulate animal population.
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
251function WildlifeSpawner:update(dt)
252 -- remove outdated areas of interest
253 self:updateAreaOfInterest(dt)
254
255 if self.isEnabled then
256 -- add animals
257 self.nextCheckTime = self.nextCheckTime - dt
258 if (self.nextCheckTime < 0.0) then
259 self.nextCheckTime = self.checkTimeInterval
260 self:updateSpawner()
261 end
262 -- remove animals too far away
263 self:removeFarAwayAnimals()
264
265 self.playerNode = nil
266 if g_currentMission.controlPlayer and g_currentMission.player ~= nil then
267 self.playerNode = g_currentMission.player.rootNode
268 elseif g_currentMission.controlledVehicle ~= nil then
269 self.playerNode = g_currentMission.controlledVehicle.rootNode
270 end
271
272 -- update animal context
273 for _, area in pairs(self.areas) do
274 for _, species in pairs(area.species) do
275 if species.classType == "companionAnimal" then
276 for _, spawn in pairs(species.spawned) do
277 if spawn.spawnId ~= nil then
278 setCompanionDaytime(spawn.spawnId, g_currentMission.environment.dayTime)
279 if spawn.avoidNode ~= self.playerNode then
280 setCompanionAvoidPlayer(spawn.spawnId, self.playerNode, self.avoidDistance)
281 spawn.avoidNode = self.playerNode
282 end
283 end
284 end
285 elseif species.classType == "lightWildlife" then
286 species.lightWildlife:update(dt)
287 end
288 end
289 end
290
291 if self.debugShow then
292 -- debug
293 self:debugDraw()
294 end
295 end
296end

updateAreaOfInterest

Description
Removes an area of interest if the time to live expires
Definition
updateAreaOfInterest(float dt)
Arguments
floatdtdelta time in ms
Code
608function WildlifeSpawner:updateAreaOfInterest(dt)
609 for key, area in pairs(self.areasOfInterest) do
610 area.timeToLive = area.timeToLive - dt
611 if area.timeToLive <= 0.0 then
612 table.remove(self.areasOfInterest, key)
613 end
614 end
615end

updateSpawner

Description
Update spawner logic
Definition
updateSpawner()
Code
354function WildlifeSpawner:updateSpawner()
355 local passedTest, x, y, z = self:getPlayerCenter()
356 if passedTest then
357 self:checkAreas(x, y, z)
358 end
359end