LUADOC - Farming Simulator 19

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
644function WildlifeSpawner:addAreaOfInterest(liveTime, posX, posZ, radius)
645 if #self.areasOfInterest <= self.maxAreaOfInterest then
646 local info = {}
647 info.liveTime = liveTime
648 info.positionX = posX
649 info.positionZ = posZ
650 info.radius = radius
651 info.timeToLive = self.areaOfInterestliveTime
652 table.insert(self.areasOfInterest, info)
653 end
654end

animalExists

Description
Definition
animalExists()
Return Values
bool
Code
707function WildlifeSpawner:animalExists(spawnId, animalId)
708 for _, area in pairs(self.areas) do
709 for _, species in pairs(area.species) do
710 if species.classType == "companionAnimal" then
711 for _, spawn in pairs(species.spawned) do
712 if spawn.spawnId == spawnId and animalId < spawn.count then
713 return true
714 end
715 end
716 end
717 end
718 end
719 return false
720end

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
446function WildlifeSpawner:checkArea(x, y, z, rules, radius)
447 local nbTrees = self:countTrees(x, y, z, radius)
448 local isOnField = self:getIsOnField(x, y, z)
449 local isInWater = self:getIsInWater(x, y, z)
450 local hoursTest = self:checkHours(rules)
451 local onFieldTest = (rules.onField and isOnField) or (not rules.onField and not isOnField)
452 local hasTreesTest = (rules.hasTrees and nbTrees > 0) or (not rules.hasTrees and nbTrees == 0)
453 local inWaterTest = (rules.inWater and isInWater) or (not rules.inWater and not isInWater)
454 if self.bypassRules or (hoursTest and onFieldTest and hasTreesTest and inWaterTest) then
455 return true
456 end
457 return false
458end

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
411function WildlifeSpawner:checkAreas(x, y, z)
412 local testX = x
413 local testZ = z
414 local testY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, testX, 0, testZ) + 0.5
415
416 for _, area in pairs(self.areas) do
417 local hasSpawned = false
418 for _, interestArea in pairs(self.areasOfInterest) do
419 local distSq = (testX - interestArea.positionX) * (testX - interestArea.positionX) + (testZ - interestArea.positionZ) * (testZ - interestArea.positionZ)
420 if (distSq < (area.areaSpawnRadius * area.areaSpawnRadius)) then
421 hasSpawned = self:trySpawnAtArea(area.species, interestArea.radius, testX, testY, testZ)
422 if hasSpawned then
423 break
424 end
425 end
426 end
427 if not hasSpawned then
428 local angle = math.rad(math.random(0, 360))
429 testX = x + area.areaSpawnRadius * math.cos(angle) - area.areaSpawnRadius * math.sin(angle)
430 testZ = z + area.areaSpawnRadius * math.cos(angle) + area.areaSpawnRadius * math.sin(angle)
431 testY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, testX, 0, testZ) + 0.5
432
433 self:trySpawnAtArea(area.species, area.spawnCircleRadius, testX, testY, testZ)
434 end
435 end
436end

checkHours

Description
Check daytime hour is in one of the valid hour ranges
Definition
checkHours()
Return Values
boolreturnstrue if current time in hours range
Code
514function WildlifeSpawner:checkHours(rules)
515 local currentHour = math.floor(g_currentMission.environment.dayTime / (60 * 60 * 1000))
516
517 for _, hours in pairs(rules.hours) do
518 if (currentHour >= hours.from and currentHour <= hours.to) then
519 return true
520 end
521 end
522 return false
523end

consoleCommandAddWildlifeAnimalToDebug

Description
Definition
consoleCommandAddWildlifeAnimalToDebug()
Return Values
stringthatwill be displayed on console
Code
737function WildlifeSpawner:consoleCommandAddWildlifeAnimalToDebug(spawnId, animalId)
738 local argsTest = true
739 spawnId = tonumber(spawnId)
740 if spawnId == nil then
741 argsTest = false
742 end
743 animalId = tonumber(animalId)
744 if animalId == nil then
745 argsTest = false
746 end
747
748 if argsTest and self:animalExists(spawnId, animalId) then
749 table.insert(self.debugAnimalList, {spawnId = spawnId, animalId = animalId})
750 return string.format("-- added [spawn(%d)][animal(%d)] to debug list.", spawnId, animalId)
751 else
752 return string.format("-- gsAddWildlifeAnimalToDebug [spawnId][animalId]")
753 end
754end

consoleCommandRemoveWildlifeAnimalToDebug

Description
Definition
consoleCommandRemoveWildlifeAnimalToDebug()
Return Values
stringthatwill be displayed on console
Code
759function WildlifeSpawner:consoleCommandRemoveWildlifeAnimalToDebug(spawnId, animalId)
760 local argsTest = true
761 spawnId = tonumber(spawnId)
762 if spawnId == nil then
763 argsTest = false
764 end
765 animalId = tonumber(animalId)
766 if animalId == nil then
767 argsTest = false
768 end
769 if argsTest then
770 for key, entry in pairs(self.debugAnimalList) do
771 if entry.spawnId == spawnId and entry.animalId == animalId then
772 table.remove(self.debugAnimalList, key)
773 return string.format("-- removed [spawn(%d)][animal(%d)] from debug list.", spawnId, animalId)
774 end
775 end
776 end
777 return string.format("-- gsRemoveWildlifeAnimalToDebug [spawnId][animalId]")
778end

consoleCommandToggleShowWildlife

Description
Definition
consoleCommandToggleShowWildlife()
Return Values
stringthatwill be displayed on console
Code
659function WildlifeSpawner:consoleCommandToggleShowWildlife()
660 self.debugShow = not self.debugShow
661
662 return string.format("-- show Wildlife debug = %s", tostring(self.debugShow))
663end

consoleCommandToggleShowWildlifeAnimation

Description
Definition
consoleCommandToggleShowWildlifeAnimation()
Return Values
stringthatwill be displayed on console
Code
698function WildlifeSpawner:consoleCommandToggleShowWildlifeAnimation()
699 self.debugShowAnimation = not self.debugShowAnimation
700
701 return string.format("-- show Wildlife Animation = %s", tostring(self.debugShowAnimation))
702end

consoleCommandToggleShowWildlifeId

Description
Definition
consoleCommandToggleShowWildlifeId()
Return Values
stringthatwill be displayed on console
Code
668function WildlifeSpawner:consoleCommandToggleShowWildlifeId()
669 self.debugShowId = self.debugShowId + 1
670
671 if self.debugShowId > WildlifeSpawner.DEBUGSHOWIDSTATES.MAX then
672 self.debugShowId = WildlifeSpawner.DEBUGSHOWIDSTATES.NONE
673 end
674
675 local state = ""
676 if (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.NONE) then
677 state = "NONE"
678 elseif (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.SINGLE) then
679 state = "SINGLE"
680 elseif (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.ALL) then
681 state = "ALL"
682 end
683 return string.format("-- show Wildlife Id = %s", state)
684end

consoleCommandToggleShowWildlifeSteering

Description
Definition
consoleCommandToggleShowWildlifeSteering()
Return Values
stringthatwill be displayed on console
Code
689function WildlifeSpawner:consoleCommandToggleShowWildlifeSteering()
690 self.debugShowSteering = not self.debugShowSteering
691
692 return string.format("-- show Wildlife Steering = %s", tostring(self.debugShowSteering))
693end

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
529function WildlifeSpawner:countAnimalsTobeSpawned(species)
530 local remainingAnimal = math.floor((self.maxCost - self.totalCost) / species.cost)
531
532 if species.minCount > remainingAnimal then
533 return 0
534 end
535 local deltaNbAnimals = species.maxCount - species.minCount
536 local nbAnimals = species.minCount + math.random(1, deltaNbAnimals)
537 nbAnimals = math.min(remainingAnimal, nbAnimals)
538 return nbAnimals
539end

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
467function WildlifeSpawner:countTrees(x, y, z, radius)
468 self.treeCount = 0
469 overlapSphere(x, y, z, radius, "treeCountTestCallback", self, 2, false, true, false)
470 --overlapBox(x, y, z, 0, 1, 0, radius, radius, radius, "treeCountTestCallback", self, self.collisionDetectionMask, false, true, false)
471 return self.treeCount
472end

debugDraw

Description
Display debug information
Definition
debugDraw()
Code
583function WildlifeSpawner:debugDraw()
584 renderText(0.02, 0.95, 0.02, string.format("Wildlife Info\nCost(%d / %d)", self.totalCost, self.maxCost))
585 local passedTest, originX, originY, originZ = self:getPlayerCenter()
586
587 if passedTest then
588 for _, area in pairs(self.areas) do
589 for _, species in pairs(area.species) do
590 for _, spawn in pairs(species.spawned) do
591 if spawn.spawnId ~= nil then
592 local distance = 0.0
593
594 if species.classType == "companionAnimal" then
595 distance, _ = getCompanionClosestDistance(spawn.spawnId, originX, originY, originZ)
596 elseif species.classType == "lightWildlife" then
597 distance = species.lightWildlife:getClosestDistance(originX, originY, originZ)
598 distance = math.sqrt(distance)
599 end
600 local text = string.format("[%s][%d]\n- nearest player distance (%.3f)", species.name, spawn.spawnId, distance)
601
602 Utils.renderTextAtWorldPosition(spawn.posX, spawn.posY + 0.12, spawn.posZ, text, getCorrectTextSize(0.012), 0)
603 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)
604 DebugUtil.drawDebugCircle(spawn.posX, spawn.posY, spawn.posZ, species.groupSpawnRadius, 10.0, {1.0, 1.0, 0.0})
605 end
606 end
607 end
608 end
609 end
610
611 for _, area in pairs(self.areas) do
612 for _, species in pairs(area.species) do
613 if species.classType == "companionAnimal" then
614 for _, spawn in pairs(species.spawned) do
615 for animalId=0, spawn.count - 1 do
616 local showAdditionalInfo = self:isInDebugList(spawn.spawnId, animalId)
617 local showId = (self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.SINGLE and showAdditionalInfo) or self.debugShowId == WildlifeSpawner.DEBUGSHOWIDSTATES.ALL
618 companionDebugDraw(spawn.spawnId, animalId, showId, showAdditionalInfo and self.debugShowSteering, showAdditionalInfo and self.debugShowAnimation)
619 end
620 end
621 end
622 end
623 end
624end

delete

Description
Delete instance
Definition
delete()
Code
76function WildlifeSpawner:delete()
77 self:removeAllAnimals()
78
79 removeConsoleCommand("gsToggleShowWildlife")
80 removeConsoleCommand("gsToggleShowWildlifeId")
81 removeConsoleCommand("gsToggleShowWildlifeSteering")
82 removeConsoleCommand("gsToggleShowWildlifeAnimation")
83 removeConsoleCommand("gsAddWildlifeAnimalToDebug")
84 removeConsoleCommand("gsRemoveWildlifeAnimalToDebug")
85end

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
505function WildlifeSpawner:getIsInWater(x, y, z)
506 local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z)
507 return g_currentMission.waterY >= terrainHeight
508end

getIsOnField

Description
Check if position is on a field
Definition
getIsOnField(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
boolreturntrue is on field
Code
494function WildlifeSpawner:getIsOnField(x, y, z)
495 local densityBits = getDensityAtWorldPos(g_currentMission.terrainDetailId, x, y, z)
496 return densityBits ~= 0
497end

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
364function WildlifeSpawner:getPlayerCenter()
365 if g_currentMission.controlPlayer and g_currentMission.player ~= nil then
366 local x, y, z = getWorldTranslation(g_currentMission.player.rootNode)
367 return true, x, y, z
368 elseif g_currentMission.controlledVehicle ~= nil then
369 local x,y,z = getWorldTranslation(g_currentMission.controlledVehicle.rootNode)
370 return true, x, y, z
371 end
372 return false, 0, 0, 0
373end

isInDebugList

Description
Definition
isInDebugList()
Return Values
bool
Code
725function WildlifeSpawner:isInDebugList(spawnId, animalId)
726 for key, entry in pairs(self.debugAnimalList) do
727 if entry.spawnId == spawnId and entry.animalId == animalId then
728 return true
729 end
730 end
731 return false
732end

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
119function WildlifeSpawner:loadMapData(xmlFile)
120 local filename = Utils.getFilename(getXMLString(xmlFile, "map.wildlife#filename"), g_currentMission.baseDirectory)
121 if filename == nil or filename == "" then
122 print("Error: Could not load wildlife config file '"..tostring(filename).."'!")
123 return false
124 end
125
126 local wildlifeXmlFile = loadXMLFile("wildlife", filename)
127
128 if wildlifeXmlFile ~= nil then
129 self.maxCost = Utils.getNoNil(getXMLInt(wildlifeXmlFile, "wildlifeSpawner#maxCost"), 0)
130 self.checkTimeInterval = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, "wildlifeSpawner#checkTimeInterval"), 1.0) * 1000.0
131 self.maxAreaOfInterest = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, "wildlifeSpawner#maxAreaOfInterest"), 1)
132 self.areaOfInterestliveTime = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, "wildlifeSpawner#areaOfInterestliveTime"), 1.0) * 1000.0
133 self.bypassRules = Utils.getNoNil(getXMLBool(wildlifeXmlFile, "wildlifeSpawner#bypassRules"), false)
134 local i = 0
135 while true do
136 local areaBaseString = string.format("wildlifeSpawner.area(%d)", i)
137 if not hasXMLProperty(wildlifeXmlFile, areaBaseString) then
138 break
139 end
140 local newArea = {}
141 newArea.areaSpawnRadius = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, areaBaseString .. "#areaSpawnRadius"), 1.0)
142 newArea.areaMaxRadius = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, areaBaseString .. "#areaMaxRadius"), 1.0)
143 newArea.spawnCircleRadius = Utils.getNoNil(getXMLFloat(wildlifeXmlFile, areaBaseString .. "#spawnCircleRadius"), 1.0)
144
145 newArea.species = {}
146 local j = 0
147 while true do
148 local speciesBaseString = string.format("%s.species(%d)", areaBaseString, j)
149 if not hasXMLProperty(wildlifeXmlFile, speciesBaseString) then
150 break
151 end
152 local classTypeString = getXMLString(wildlifeXmlFile, speciesBaseString .. "#classType")
153 local classType = nil
154
155 if classTypeString ~= nil then
156 if string.lower(classTypeString) == "companionanimal" then
157 classType = "companionAnimal"
158 elseif string.lower(classTypeString) == "lightwildlife" then
159 classType = "lightWildlife"
160 end
161 end
162 if classType ~= nil then
163 local newSpecies = {}
164 newSpecies.classType = classType
165 newSpecies.name = getXMLString(wildlifeXmlFile, speciesBaseString .. "#name")
166 newSpecies.configFilename = getXMLString(wildlifeXmlFile, speciesBaseString .. "#config")
167 newSpecies.spawnRule = {}
168 newSpecies.spawnRule.hours = self:parseHours(getXMLString(wildlifeXmlFile, speciesBaseString .. ".spawnRules#hours"))
169 newSpecies.spawnRule.onField = getXMLBool(wildlifeXmlFile, speciesBaseString .. ".spawnRules#onField")
170 newSpecies.spawnRule.hasTrees = getXMLBool(wildlifeXmlFile, speciesBaseString .. ".spawnRules#hasTrees")
171 newSpecies.spawnRule.inWater = getXMLBool(wildlifeXmlFile, speciesBaseString .. ".spawnRules#inWater")
172 newSpecies.cost = getXMLFloat(wildlifeXmlFile, speciesBaseString .. ".cost")
173 newSpecies.minCount = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".minCount")
174 newSpecies.maxCount = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".maxCount")
175 newSpecies.currentCount = 0
176 newSpecies.spawnCount = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".spawnCount")
177 newSpecies.groupSpawnRadius = getXMLInt(wildlifeXmlFile, speciesBaseString .. ".groupSpawnRadius")
178 newSpecies.spawned = {}
179 newSpecies.lightWildlife = nil
180 if classType == "lightWildlife" then
181 if newSpecies.name == "crow" then
182 newSpecies.lightWildlife = CrowsWildlife:new()
183 newSpecies.lightWildlife:load(Utils.getNoNil(getXMLString(wildlifeXmlFile, speciesBaseString .. "#config"), ""))
184 end
185 end
186 table.insert(newArea.species, newSpecies)
187 end
188 j = j + 1
189 end
190 table.insert(self.areas, newArea)
191 i = i + 1
192 end
193 delete(wildlifeXmlFile)
194 return true
195 end
196 return false
197end

new

Description
Creating instance
Definition
new(table customMt)
Arguments
tablecustomMtcustom meta table
Return Values
tableinstanceInstance of object
Code
39function WildlifeSpawner:new(customMt)
40 local mt = customMt
41 if mt == nil then
42 mt = WildlifeSpawner_mt
43 end
44 local self = {}
45 setmetatable(self, mt)
46
47 self.collisionDetectionMask = 4096 -- dynamic_objects
48 self.maxCost = 0
49 self.checkTimeInterval = 0.0
50 self.nextCheckTime = 0.0
51 self.areas = {}
52 self.areasOfInterest = {}
53 self.totalCost = 0
54 self.treeCount = 0
55
56 -- Debug
57 -- if g_addCheatCommands then
58 self.debugAnimalList = {}
59 self.debugShow = false
60 self.debugShowId = WildlifeSpawner.DEBUGSHOWIDSTATES.NONE
61 self.debugShowSteering = false
62 self.debugShowAnimation = false
63 addConsoleCommand("gsToggleShowWildlife", "Toggle shows/hide all wildlife debug information.", "consoleCommandToggleShowWildlife", self)
64 addConsoleCommand("gsToggleShowWildlifeId", "Toggle shows/hide all wildlife animal id.", "consoleCommandToggleShowWildlifeId", self)
65 addConsoleCommand("gsToggleShowWildlifeSteering", "Toggle shows/hide animal steering information.", "consoleCommandToggleShowWildlifeSteering", self)
66 addConsoleCommand("gsToggleShowWildlifeAnimation", "Toggle shows/hide animal animation information.", "consoleCommandToggleShowWildlifeAnimation", self)
67 addConsoleCommand("gsAddWildlifeAnimalToDebug", "Adds an animal to a debug list.", "consoleCommandAddWildlifeAnimalToDebug", self)
68 addConsoleCommand("gsRemoveWildlifeAnimalToDebug", "Removes an animal to a debug list.", "consoleCommandRemoveWildlifeAnimalToDebug", self)
69 -- end
70
71 return self
72end

onConnectionClosed

Description
Definition
onConnectionClosed()
Code
89function WildlifeSpawner:onConnectionClosed()
90 self:removeAllAnimals()
91end

onGhostAdd

Description
On ghost add callback
Definition
onGhostAdd()
Code
267function WildlifeSpawner:onGhostAdd()
268 for _, area in pairs(self.areas) do
269 for _, species in pairs(area.species) do
270 if species.classType == "companionAnimal" then
271 for _, spawn in pairs(species.spawned) do
272 if spawn.spawnId ~= nil then
273 setCompanionsVisibility(spawn.spawnId, true)
274 setCompanionsPhysicsUpdate(spawn.spawnId, true)
275 end
276 end
277 end
278 end
279 end
280end

onGhostRemove

Description
On ghost remove callback
Definition
onGhostRemove()
Code
250function WildlifeSpawner:onGhostRemove()
251 for _, area in pairs(self.areas) do
252 for _, species in pairs(area.species) do
253 if species.classType == "companionAnimal" then
254 for _, spawn in pairs(species.spawned) do
255 if spawn.spawnId ~= nil then
256 setCompanionsVisibility(spawn.spawnId, false)
257 setCompanionsPhysicsUpdate(spawn.spawnId, false)
258 end
259 end
260 end
261 end
262 end
263end

parseHours

Description
Parse hours string
Definition
parseHours(string input)
Arguments
stringinputstring to parse
Code
218function WildlifeSpawner:parseHours(input)
219 local hoursResult = {}
220 if input ~= nil then
221 input = input:gsub('[^-,0-9]','') -- remove all but numbers, '-' and ','
222 local hourRangesStrings = StringUtil.splitString(",", input) -- split by ','
223 local num = table.getn(hourRangesStrings)
224
225 for i = 1, num do
226 local hourFromStartString = StringUtil.splitString("-", hourRangesStrings[i]) -- split string by '-'
227 local num2 = table.getn(hourFromStartString)
228 local fromVal = 0
229 local toVal = 0
230
231 if num2 == 1 then
232 fromVal = tonumber(hourFromStartString[1])
233 toVal = tonumber(hourFromStartString[1])
234 elseif num2 == 2 then
235 fromVal = tonumber(hourFromStartString[1])
236 toVal = tonumber(hourFromStartString[2])
237 end
238
239 -- sanity checks
240 if (num2 == 1 or num2 == 2) and (fromVal <= toVal) and (fromVal >= 0 and fromVal <= 24) and (toVal >= 0 and toVal <= 24) then
241 table.insert(hoursResult, {from = fromVal, to = toVal})
242 end
243 end
244 end
245 return hoursResult
246end

removeAllAnimals

Description
Definition
removeAllAnimals()
Code
95function WildlifeSpawner:removeAllAnimals()
96 for _, area in pairs(self.areas) do
97 for _, species in pairs(area.species) do
98 for i=#species.spawned, 1, -1 do
99 if species.classType == "companionAnimal" then
100 local spawn = species.spawned[i]
101 if spawn.spawnId ~= nil then
102 delete(spawn.spawnId)
103 spawn.spawnId = nil
104 end
105 elseif species.classType == "lightWildlife" and species.lightWildlife ~= nil then
106 species.lightWildlife:removeAllAnimals()
107 end
108 table.remove(species.spawned, i)
109 end
110 end
111 end
112 self.totalCost = 0
113end

removeFarAwayAnimals

Description
Removing animals that are too far away
Definition
removeFarAwayAnimals()
Code
320function WildlifeSpawner:removeFarAwayAnimals()
321 local passedTest, originX, originY, originZ = self:getPlayerCenter()
322
323 if passedTest then
324 for _, area in pairs(self.areas) do
325 for _, species in pairs(area.species) do
326 if species.classType == "companionAnimal" then
327 for i=#species.spawned, 1, -1 do
328 local spawn = species.spawned[i]
329 if spawn.spawnId ~= nil then
330 local distance, _ = getCompanionClosestDistance(spawn.spawnId, originX, originY, originZ)
331
332 if distance > area.areaMaxRadius then
333 delete(spawn.spawnId)
334 spawn.spawnId = nil
335 species.currentCount = species.currentCount - spawn.count
336 self.totalCost = self.totalCost - species.cost * spawn.count
337 table.remove(species.spawned, i)
338 end
339 end
340 end
341 elseif species.classType == "lightWildlife" and species.lightWildlife ~= nil then
342 local removedAnimalsCount = species.lightWildlife:removeFarAwayAnimals(area.areaMaxRadius, originX, originY, originZ)
343 if removedAnimalsCount > 0 then
344 species.currentCount = species.currentCount - removedAnimalsCount
345 self.totalCost = self.totalCost - species.cost * removedAnimalsCount
346 for i=#species.spawned, 1, -1 do
347 --local spawn = species.spawned[i]
348 if species.lightWildlife:countSpawned() == 0 then
349 table.remove(species.spawned, i)
350 end
351 end
352 end
353 end
354 end
355 end
356 end
357end

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
548function WildlifeSpawner:spawnAnimals(species, spawnPosX, spawnPosY, spawnPosZ)
549 local xmlFilename = Utils.getFilename(species.configFilename, g_currentMission.loadingMapBaseDirectory)
550
551 if species.name == nil or
552 xmlFilename == nil or
553 g_currentMission.terrainRootNode == nil or
554 species.currentCount >= species.maxCount then
555 return false
556 end
557 local nbAnimals = self:countAnimalsTobeSpawned(species)
558 if nbAnimals == 0 then
559 return false
560 end
561 local id = nil
562 if species.classType == "companionAnimal" then
563 id = createAnimalCompanionManager(species.name, xmlFilename, "wildlifeAnimal", spawnPosX, spawnPosY, spawnPosZ, g_currentMission.terrainRootNode, g_currentMission:getIsServer(), g_currentMission:getIsClient(), nbAnimals)
564 setCompanionWaterLevel(id, g_currentMission.waterY)
565 for animalId=0, nbAnimals - 1 do
566 setCompanionCommonSteeringParameters(id, animalId, 0.5, 3.0, MathUtil.degToRad(20.0), 0.2)
567 setCompanionWanderSteeringParameters(id, animalId, spawnPosX, spawnPosY, spawnPosZ, 10.0, 12.0, 0.01)
568 end
569 elseif species.classType == "lightWildlife" then
570 id = species.lightWildlife:createAnimals(species.name, spawnPosX, spawnPosY, spawnPosZ, nbAnimals)
571 end
572 if (id ~= nil) and (id ~= 0) then
573 table.insert(species.spawned, {spawnId = id, posX = spawnPosX, posY = spawnPosY, posZ = spawnPosZ, count=nbAnimals})
574 species.currentCount = species.currentCount + nbAnimals
575 self.totalCost = self.totalCost + species.cost * nbAnimals
576 return true
577 end
578 return false
579end

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
478function WildlifeSpawner:treeCountTestCallback(transformId)
479 if transformId ~= 0 and getHasClassId(transformId, ClassIds.SHAPE) then
480 local object = getParent(transformId)
481 if object ~= nil and getSplitType(transformId) ~= 0 then
482 self.treeCount = self.treeCount + 1
483 end
484 end
485 return true
486end

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
392function WildlifeSpawner:trySpawnAtArea(species, spawnCircleRadius, testX, testY, testZ)
393 for _, animalType in pairs(species) do
394 if self:checkArea(testX, testY, testZ, animalType.spawnRule, spawnCircleRadius) then
395 local spawnPosX = testX + math.random() * spawnCircleRadius
396 local spawnPosZ = testZ + math.random() * spawnCircleRadius
397 local spawnPosY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, spawnPosX, 0, spawnPosZ) + 0.5
398 if self:spawnAnimals(animalType, spawnPosX, spawnPosY, spawnPosZ) then
399 return true
400 end
401 end
402 end
403 return false
404end

unloadMapData

Description
Unload data on mission delete
Definition
unloadMapData()
Code
201function WildlifeSpawner:unloadMapData()
202 self:removeAllAnimals()
203 for _, area in pairs(self.areas) do
204 for _, species in pairs(area.species) do
205 if species.lightWildlife ~= nil then
206 species.lightWildlife:delete()
207 end
208 end
209 end
210
211 self.areas = {}
212end

update

Description
Update function. Regulate animal population.
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
285function WildlifeSpawner:update(dt)
286 -- remove outdated areas of interest
287 self:updateAreaOfInterest(dt)
288 -- add animals
289 self.nextCheckTime = self.nextCheckTime - dt
290 if (self.nextCheckTime < 0.0) then
291 self.nextCheckTime = self.checkTimeInterval
292 self:updateSpawner()
293 end
294 -- remove animals too far away
295 self:removeFarAwayAnimals()
296
297 -- update animal context
298 for _, area in pairs(self.areas) do
299 for _, species in pairs(area.species) do
300 if species.classType == "companionAnimal" then
301 for _, spawn in pairs(species.spawned) do
302 if spawn.spawnId ~= nil then
303 setCompanionDaytime(spawn.spawnId, g_currentMission.environment.dayTime)
304 end
305 end
306 elseif species.classType == "lightWildlife" then
307 species.lightWildlife:update(dt)
308 end
309 end
310 end
311
312 if self.debugShow then
313 -- debug
314 self:debugDraw()
315 end
316end

updateAreaOfInterest

Description
Removes an area of interest if the time to live expires
Definition
updateAreaOfInterest(float dt)
Arguments
floatdtdelta time in ms
Code
629function WildlifeSpawner:updateAreaOfInterest(dt)
630 for key, area in pairs(self.areasOfInterest) do
631 area.timeToLive = area.timeToLive - dt
632 if area.timeToLive <= 0.0 then
633 table.remove(self.areasOfInterest, key)
634 end
635 end
636end

updateSpawner

Description
Update spawner logic
Definition
updateSpawner()
Code
377function WildlifeSpawner:updateSpawner()
378 local passedTest, x, y, z = self:getPlayerCenter()
379 if passedTest then
380 self:checkAreas(x, y, z)
381 end
382end