Script v1_7_1_0
- AI
- Animals
- Collections
- Contracts
- Debug
- Economy
- Elements
- EnvironmentalScore
- Errors
- Events
- GUI
- Handtools
- Hud
- I3d
- Input
- Jobs
- Maps
- Materials
- Misc
- Objects
- Parameters
- Placeables
- Placement
- Player
- Shop
- Sounds
- Specialization
- Specializations
- AIConveyorBelt
- AIDrivable
- AIFieldWorker
- AIImplement
- AIJobVehicle
- AIVehicle
- AIVehicleObstacle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- AutoLoader
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BigBag
- BunkerSiloCompacter
- BunkerSiloInteractor
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- CropSensor
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- ExtendedAIVehicle
- ExtendedCombine
- ExtendedMotorized
- ExtendedMower
- ExtendedSowingMachine
- ExtendedSprayer
- ExtendedWearable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- HeadlandAnimation
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- InlineWrapper
- JigglingParts
- Leveler
- LicensePlates
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- ManureSensor
- MixerWagon
- Motorized
- Mountable
- Mower
- Mulcher
- MultipleItemPurchase
- Pallet
- Pickup
- Pipe
- PlaceableAI
- PlaceableAnimatedObjects
- PlaceableBeehive
- PlaceableBeehivePalletSpa...
- PlaceableBunkerSilo
- PlaceableBuyingStation
- PlaceableCartridgePlayer
- PlaceableChargingStation
- PlaceableClearAreas
- PlaceableColorable
- PlaceableDeletedNodes
- PlaceableDoghouse
- PlaceableDynamicallyLoade...
- PlaceableFarmhouse
- PlaceableFence
- PlaceableFoliageAreas
- PlaceableGreenhouse
- PlaceableHighPressureWash...
- PlaceableHotspots
- PlaceableHusbandry
- PlaceableHusbandryAnimals
- PlaceableHusbandryFeeding...
- PlaceableHusbandryFence
- PlaceableHusbandryFood
- PlaceableHusbandryLiquidM...
- PlaceableHusbandryMilk
- PlaceableHusbandryPallets
- PlaceableHusbandryStraw
- PlaceableHusbandryWater
- PlaceableIncomePerHour
- PlaceableIndoorAreas
- PlaceableInfoTrigger
- PlaceableLeveling
- PlaceableLights
- PlaceableManureHeap
- PlaceablePlacement
- PlaceableProductionPoint
- PlaceableSellingStation
- PlaceableSilo
- PlaceableSiloExtension
- PlaceableSolarPanels
- PlaceableTipOcclusionArea...
- PlaceableTrainSystem
- PlaceableTriggerMarkers
- PlaceableVine
- PlaceableWardrobe
- PlaceableWeatherStation
- PlaceableWeighingStation
- PlaceableWindTurbine
- PlaceableWorkshop
- Plow
- PlowPacker
- PowerConsumer
- PowerTakeOffs
- PrecisionFarmingStatistic
- PushHandTool
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- RTKStation
- SaltSpreader
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SoilSampler
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StonePicker
- StrawBlower
- StumpCutter
- SupportVehicle
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TestAreas
- TipOccluder
- Trailer
- TreePlanter
- TreeSaplingPallet
- TreeSaw
- TurnOnVehicle
- VariableWorkWidth
- VehicleSettings
- VineCutter
- VineDetector
- VinePrepruner
- Washable
- WaterTrailer
- Wearable
- Weeder
- WeedSpotSpray
- Wheels
- WindBending
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- StateMachine
- Statistics
- Tasks
- Triggers
- Utils
- Vehicles
Engine v1_7_1_0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- general
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- NoteNode
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- VoiceChat
- XML
Foundation Reference
PlaceableHusbandryFood
DescriptionSpecialization for placeablesFunctions
- addFood
- collectPickObjects
- getAnimalDescription
- getFoodCapacity
- getFoodInfos
- getFreeFoodCapacity
- getSpecValueAnimalFoodFillTypes
- getTotalFood
- initSpecialization
- loadFromXMLFile
- loadSpecValueAnimalFoodFillTypes
- onDelete
- onFinalizePlacement
- onHusbandryAnimalsCreated
- onHusbandryAnimalsUpdate
- onLoad
- onPostFinalizePlacement
- onPostLoad
- onReadStream
- onReadUpdateStream
- onWriteStream
- onWriteUpdateStream
- prerequisitesPresent
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- registerSavegameXMLPaths
- registerXMLPaths
- removeFood
- saveToXMLFile
- updateFeeding
- updateFillPlanes
- updateFoodPlaces
- updateInfo
addFood
DescriptionDefinitionaddFood()Code
518 | function PlaceableHusbandryFood:addFood(farmId, deltaFillLevel, fillTypeIndex, fillPositionData, toolType, extraAttributes) |
519 | local spec = self.spec_husbandryFood |
520 | if spec.supportedFillTypes[fillTypeIndex] == nil then |
521 | return 0 |
522 | end |
523 | |
524 | local mixture = g_currentMission.animalFoodSystem:getMixtureByFillType(fillTypeIndex) |
525 | if mixture ~= nil then |
526 | local filled = 0 |
527 | local maxDelta = math.min(deltaFillLevel, self:getFreeFoodCapacity(fillTypeIndex)) |
528 | for _, ingredient in ipairs(mixture.ingredients) do |
529 | local delta = maxDelta * ingredient.weight |
530 | local ingredientFillType = ingredient.fillTypes[1] |
531 | local filledDelta = self:addFood(farmId, delta, ingredientFillType, fillPositionData, toolType, extraAttributes) |
532 | filled = filled + filledDelta |
533 | end |
534 | |
535 | if filled > 0 then |
536 | self:updateFillPlanes(fillTypeIndex) |
537 | end |
538 | |
539 | return filled |
540 | end |
541 | |
542 | local freeCapacity = self:getFreeFoodCapacity(fillTypeIndex) |
543 | if freeCapacity == 0 then |
544 | return 0 |
545 | end |
546 | |
547 | deltaFillLevel = math.min(freeCapacity, deltaFillLevel) |
548 | |
549 | if spec.dynamicFoodPlane ~= nil then |
550 | if fillPositionData ~= nil then |
551 | local data = fillPositionData |
552 | |
553 | local x0, y0, z0 = getWorldTranslation(data.node) |
554 | local d1x, d1y, d1z = localDirectionToWorld(data.node, data.width, 0, 0) |
555 | local d2x, d2y, d2z = localDirectionToWorld(data.node, 0, 0, data.length) |
556 | |
557 | if VehicleDebug.state == VehicleDebug.DEBUG then |
558 | drawDebugLine( x0,y0,z0, 1,0,0, x0+d1x, y0+d1y, z0+d1z, 1,0,0 ) |
559 | drawDebugLine( x0,y0,z0, 0,0,1, x0+d2x, y0+d2y, z0+d2z, 0,0,1 ) |
560 | drawDebugPoint( x0,y0,z0, 1,1,1,1 ) |
561 | drawDebugPoint( x0+d1x, y0+d1y, z0+d1z, 1,0,0,1 ) |
562 | drawDebugPoint( x0+d2x, y0+d2y, z0+d2z, 0,0,1,1 ) |
563 | end |
564 | |
565 | x0 = x0 - (d1x + d2x) / 2 |
566 | y0 = y0 - (d1y + d2y) / 2 |
567 | z0 = z0 - (d1z + d2z) / 2 |
568 | fillPlaneAdd(spec.dynamicFoodPlane, deltaFillLevel, x0, y0, z0, d1x, d1y, d1z, d2x, d2y, d2z) |
569 | |
570 | if self.isServer and math.abs(x0-spec.lastPositionInfoSent[1]) > FillVolume.SEND_PRECISION or math.abs(z0-spec.lastPositionInfoSent[2]) > FillVolume.SEND_PRECISION then |
571 | spec.lastPositionInfoSent[1] = x0 |
572 | spec.lastPositionInfoSent[2] = z0 |
573 | |
574 | self:raiseDirtyFlags(spec.dirtyFlagPosition) |
575 | end |
576 | else |
577 | local x,y,z = localToWorld(spec.dynamicFoodPlane, 0,0,0) |
578 | local d1x,d1y,d1z = localDirectionToWorld(spec.dynamicFoodPlane, 0.1, 0, 0) |
579 | local d2x,d2y,d2z = localDirectionToWorld(spec.dynamicFoodPlane, 0, 0, 0.1) |
580 | |
581 | if not self.isServer then |
582 | if spec.lastPositionInfo[1] ~= 0 and spec.lastPositionInfo[2] ~= 0 then |
583 | x, y, z = localToWorld(spec.dynamicFoodPlane, spec.lastPositionInfo[1], 0, spec.lastPositionInfo[2]) |
584 | end |
585 | end |
586 | |
587 | local steps = MathUtil.clamp(math.floor(deltaFillLevel/400), 1, 25) |
588 | for _=1, steps do |
589 | fillPlaneAdd(spec.dynamicFoodPlane, deltaFillLevel/steps, x,y,z, d1x,d1y,d1z, d2x,d2y,d2z) |
590 | end |
591 | end |
592 | end |
593 | |
594 | if self.isServer then |
595 | self:raiseDirtyFlags(spec.dirtyFlagFillLevel) |
596 | end |
597 | |
598 | spec.fillLevels[fillTypeIndex] = spec.fillLevels[fillTypeIndex] + deltaFillLevel |
599 | |
600 | self:updateFillPlanes(fillTypeIndex) |
601 | self:updateFoodPlaces() |
602 | |
603 | return deltaFillLevel |
604 | end |
collectPickObjects
DescriptionDefinitioncollectPickObjects()Code
452 | function PlaceableHusbandryFood:collectPickObjects(superFunc, node) |
453 | local spec = self.spec_husbandryFood |
454 | if spec.feedingTrough ~= nil and node == spec.feedingTrough.exactFillRootNode then |
455 | return |
456 | end |
457 | |
458 | superFunc(self, node) |
459 | end |
getAnimalDescription
DescriptionDefinitiongetAnimalDescription()Code
667 | function PlaceableHusbandryFood:getAnimalDescription(superFunc, cluster) |
668 | local text = superFunc(self, cluster) |
669 | |
670 | return text .. " " .. g_i18n:getText("animal_descriptionPercentage") |
671 | end |
getFoodCapacity
DescriptionDefinitiongetFoodCapacity()Code
501 | function PlaceableHusbandryFood:getFoodCapacity() |
502 | return self.spec_husbandryFood.capacity |
503 | end |
getFoodInfos
DescriptionDefinitiongetFoodInfos()Code
395 | function PlaceableHusbandryFood:getFoodInfos(superFunc) |
396 | local foodInfos = superFunc(self) |
397 | local spec = self.spec_husbandryFood |
398 | |
399 | local animalFood = g_currentMission.animalFoodSystem:getAnimalFood(spec.animalTypeIndex) |
400 | |
401 | if animalFood ~= nil then |
402 | for _, foodGroup in pairs(animalFood.groups) do |
403 | local title = foodGroup.title |
404 | local fillLevel = 0 |
405 | local capacity = spec.capacity |
406 | |
407 | for _, fillTypeIndex in pairs(foodGroup.fillTypes) do |
408 | if spec.fillLevels[fillTypeIndex] ~= nil then |
409 | fillLevel = fillLevel + spec.fillLevels[fillTypeIndex] |
410 | end |
411 | end |
412 | |
413 | local info = {} |
414 | info.title = string.format("%s (%d%%)", title, MathUtil.round(foodGroup.productionWeight*100)) |
415 | info.value = fillLevel |
416 | info.capacity = capacity |
417 | info.ratio = 0 |
418 | if capacity > 0 then |
419 | info.ratio = fillLevel / capacity |
420 | end |
421 | |
422 | table.insert(foodInfos, info) |
423 | end |
424 | end |
425 | |
426 | return foodInfos |
427 | end |
getFreeFoodCapacity
DescriptionDefinitiongetFreeFoodCapacity()Code
507 | function PlaceableHusbandryFood:getFreeFoodCapacity(fillTypeIndex) |
508 | local spec = self.spec_husbandryFood |
509 | if spec.supportedFillTypes[fillTypeIndex] == nil then |
510 | return 0 |
511 | end |
512 | |
513 | return spec.capacity - self:getTotalFood() |
514 | end |
getSpecValueAnimalFoodFillTypes
DescriptionDefinitiongetSpecValueAnimalFoodFillTypes()Code
693 | function PlaceableHusbandryFood.getSpecValueAnimalFoodFillTypes(storeItem, realItem) |
694 | local data = storeItem.specs.animalFoodFillTypes |
695 | if data == nil then |
696 | return nil |
697 | end |
698 | |
699 | local fillTypes = {} |
700 | local animalType = g_currentMission.animalSystem:getTypeByName(data.animalTypeName) |
701 | if animalType == nil then |
702 | return nil |
703 | end |
704 | |
705 | local animalFood = g_currentMission.animalFoodSystem:getAnimalFood(animalType.typeIndex) |
706 | local mixtures = g_currentMission.animalFoodSystem:getMixturesByAnimalTypeIndex(animalType.typeIndex) |
707 | |
708 | if animalFood ~= nil then |
709 | for _, foodGroup in pairs(animalFood.groups) do |
710 | for _, fillTypeIndex in pairs(foodGroup.fillTypes) do |
711 | table.addElement(fillTypes, fillTypeIndex) |
712 | end |
713 | end |
714 | end |
715 | |
716 | if mixtures ~= nil then |
717 | for _, foodMixtureFillType in ipairs(mixtures) do |
718 | table.addElement(fillTypes, foodMixtureFillType) |
719 | end |
720 | end |
721 | |
722 | if data.needsWater then |
723 | table.addElement(fillTypes, FillType.WATER) |
724 | end |
725 | |
726 | return fillTypes |
727 | end |
getTotalFood
DescriptionDefinitiongetTotalFood()Code
489 | function PlaceableHusbandryFood:getTotalFood() |
490 | local spec = self.spec_husbandryFood |
491 | local fillLevel = 0 |
492 | for _, level in pairs(spec.fillLevels) do |
493 | fillLevel = fillLevel + level |
494 | end |
495 | |
496 | return fillLevel |
497 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
88 | function PlaceableHusbandryFood.initSpecialization() |
89 | g_storeManager:addSpecType("animalFoodFillTypes", "shopListAttributeIconFillTypes", PlaceableHusbandryFood.loadSpecValueAnimalFoodFillTypes, PlaceableHusbandryFood.getSpecValueAnimalFoodFillTypes, "placeable") |
90 | end |
loadFromXMLFile
DescriptionDefinitionloadFromXMLFile()Code
332 | function PlaceableHusbandryFood:loadFromXMLFile(xmlFile, key) |
333 | local spec = self.spec_husbandryFood |
334 | xmlFile:iterate(key .. ".fillLevel", function(_, fillLevelKey) |
335 | local fillTypeName = xmlFile:getValue(fillLevelKey .. "#fillType") |
336 | local fillLevel = xmlFile:getValue(fillLevelKey .. "#fillLevel") |
337 | if fillTypeName ~= nil and fillLevel ~= nil then |
338 | local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeName) |
339 | if fillTypeIndex ~= nil and spec.supportedFillTypes[fillTypeIndex] ~= nil then |
340 | self:addFood(self:getOwnerFarmId(), fillLevel, fillTypeIndex, nil, nil, nil) |
341 | end |
342 | end |
343 | end) |
344 | end |
loadSpecValueAnimalFoodFillTypes
DescriptionDefinitionloadSpecValueAnimalFoodFillTypes()Code
675 | function PlaceableHusbandryFood.loadSpecValueAnimalFoodFillTypes(xmlFile, customEnvironment, baseDir) |
676 | local data = nil |
677 | |
678 | if xmlFile:hasProperty("placeable.husbandry.animals") then |
679 | data = data or {} |
680 | data.animalTypeName = xmlFile:getString("placeable.husbandry.animals#type") |
681 | end |
682 | |
683 | if xmlFile:hasProperty("placeable.husbandry.water") then |
684 | data = data or {} |
685 | data.needsWater = not xmlFile:getValue("placeable.husbandry.water#automaticWaterSupply", false) |
686 | end |
687 | |
688 | return data |
689 | end |
onDelete
DescriptionDefinitiononDelete()Code
201 | function PlaceableHusbandryFood:onDelete() |
202 | local spec = self.spec_husbandryFood |
203 | |
204 | if spec.feedingTrough ~= nil then |
205 | spec.feedingTrough:delete() |
206 | spec.feedingTrough = nil |
207 | end |
208 | |
209 | if spec.dynamicFoodPlane ~= nil then |
210 | delete(spec.dynamicFoodPlane) |
211 | spec.dynamicFoodPlane = nil |
212 | end |
213 | |
214 | if spec.foodPlane ~= nil then |
215 | spec.foodPlane:delete() |
216 | spec.foodPlane = nil |
217 | end |
218 | end |
onFinalizePlacement
DescriptionDefinitiononFinalizePlacement()Code
222 | function PlaceableHusbandryFood:onFinalizePlacement() |
223 | local spec = self.spec_husbandryFood |
224 | if spec.feedingTrough ~= nil then |
225 | spec.feedingTrough:register(true) |
226 | end |
227 | end |
onHusbandryAnimalsCreated
DescriptionDefinitiononHusbandryAnimalsCreated()Code
463 | function PlaceableHusbandryFood:onHusbandryAnimalsCreated(husbandry) |
464 | if husbandry ~= nil then |
465 | local spec = self.spec_husbandryFood |
466 | spec.husbandry = husbandry |
467 | for _, foodPlace in ipairs(spec.foodPlaces) do |
468 | foodPlace.place = addFeedingPlace(husbandry, foodPlace.node, 0.0, AnimalHusbandryFeedingType.FOOD) |
469 | end |
470 | end |
471 | end |
onHusbandryAnimalsUpdate
DescriptionDefinitiononHusbandryAnimalsUpdate()Code
646 | function PlaceableHusbandryFood:onHusbandryAnimalsUpdate(clusters) |
647 | local spec = self.spec_husbandryFood |
648 | |
649 | spec.litersPerHour = 0 |
650 | for _, cluster in ipairs(clusters) do |
651 | local subType = g_currentMission.animalSystem:getSubTypeByIndex(cluster.subTypeIndex) |
652 | if subType ~= nil then |
653 | local food = subType.input.food |
654 | if food ~= nil then |
655 | local age = cluster:getAge() |
656 | local litersPerAnimal = food:get(age) |
657 | local litersPerDay = litersPerAnimal * cluster:getNumAnimals() |
658 | |
659 | spec.litersPerHour = spec.litersPerHour + (litersPerDay / 24) |
660 | end |
661 | end |
662 | end |
663 | end |
onLoad
DescriptionDefinitiononLoad()Code
94 | function PlaceableHusbandryFood:onLoad(savegame) |
95 | local spec = self.spec_husbandryFood |
96 | |
97 | spec.animalTypeIndex = nil |
98 | spec.litersPerHour = 0 |
99 | spec.fillLevels = {} |
100 | spec.supportedFillTypes = {} |
101 | spec.fillTypes = {} |
102 | spec.lastPositionInfoSent = {0, 0} |
103 | spec.lastPositionInfo = {0, 0} |
104 | spec.foodPlaces = {} |
105 | spec.info = {title=g_i18n:getText("ui_animalFood"), text=""} |
106 | |
107 | spec.dirtyFlagPosition = self:getNextDirtyFlag() |
108 | spec.dirtyFlagFillLevel = self:getNextDirtyFlag() |
109 | |
110 | spec.capacity = self.xmlFile:getValue("placeable.husbandry.food#capacity", 5000) |
111 | spec.FILLLEVEL_NUM_BITS = MathUtil.getNumRequiredBits(spec.capacity) |
112 | |
113 | local feedingTrough = UnloadTrigger.new(self.isServer, self.isClient) |
114 | |
115 | local target = { |
116 | getIsFillTypeAllowed = function(_, fillTypeIndex) |
117 | return spec.supportedFillTypes[fillTypeIndex] |
118 | end, |
119 | getIsToolTypeAllowed = function(_, fillTypeIndex) |
120 | return true |
121 | end, |
122 | addFillLevelFromTool = function(_, ...) |
123 | return self:addFood(...) |
124 | end, |
125 | getFreeCapacity = function(_, fillTypeIndex) |
126 | return self:getFreeFoodCapacity(fillTypeIndex) |
127 | end |
128 | } |
129 | if not feedingTrough:load(self.components, self.xmlFile, "placeable.husbandry.food.feedingTrough", target, nil, self.i3dMappings) then |
130 | feedingTrough:delete() |
131 | self:setLoadingState(Placeable.LOADING_STATE_ERROR) |
132 | return |
133 | end |
134 | |
135 | spec.feedingTrough = feedingTrough |
136 | |
137 | spec.baseNode = self.xmlFile:getValue("placeable.husbandry.food.dynamicFoodPlane#node", nil, self.components, self.i3dMappings) |
138 | if spec.baseNode ~= nil then |
139 | local fillPlane = FillPlaneUtil.createFromXML(self.xmlFile, "placeable.husbandry.food.dynamicFoodPlane", spec.baseNode, spec.capacity) |
140 | local defaultFillTypeName = self.xmlFile:getValue("placeable.husbandry.food.dynamicFoodPlane#defaultFillType") |
141 | local defaultFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(defaultFillTypeName) or FillType.FORAGE |
142 | |
143 | if fillPlane ~= nil then |
144 | FillPlaneUtil.assignDefaultMaterials(fillPlane) |
145 | FillPlaneUtil.setFillType(fillPlane, defaultFillTypeIndex) |
146 | |
147 | spec.dynamicFoodPlane = fillPlane |
148 | end |
149 | end |
150 | |
151 | spec.foodPlane = FillPlane.new() |
152 | if spec.foodPlane:load(self.components, self.xmlFile, "placeable.husbandry.food.foodPlane", self.i3dMappings) then |
153 | local defaultFillTypeName = self.xmlFile:getValue("placeable.husbandry.food.foodPlane#defaultFillType") |
154 | local defaultFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(defaultFillTypeName) or FillType.DRYGRASS_WINDROW |
155 | |
156 | FillPlaneUtil.assignDefaultMaterials(spec.foodPlane.node) |
157 | FillPlaneUtil.setFillType(spec.foodPlane.node, defaultFillTypeIndex) |
158 | setShaderParameter(spec.foodPlane.node, "isCustomShape", 1, 0, 0, 0, false) |
159 | spec.foodPlane:setState(0) |
160 | else |
161 | spec.foodPlane:delete() |
162 | spec.foodPlane = nil |
163 | end |
164 | |
165 | self.xmlFile:iterate("placeable.husbandry.food.foodPlaces.foodPlace", function(_, key) |
166 | local node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
167 | table.insert(spec.foodPlaces, {node=node, place=nil}) |
168 | end) |
169 | end |
onPostFinalizePlacement
DescriptionDefinitiononPostFinalizePlacement()Code
231 | function PlaceableHusbandryFood:onPostFinalizePlacement() |
232 | self:updateFillPlanes() |
233 | end |
onPostLoad
DescriptionDefinitiononPostLoad()Code
173 | function PlaceableHusbandryFood:onPostLoad() |
174 | local spec = self.spec_husbandryFood |
175 | spec.animalTypeIndex = self:getAnimalTypeIndex() |
176 | local animalFood = g_currentMission.animalFoodSystem:getAnimalFood(spec.animalTypeIndex) |
177 | local mixtures = g_currentMission.animalFoodSystem:getMixturesByAnimalTypeIndex(spec.animalTypeIndex) |
178 | |
179 | if animalFood ~= nil then |
180 | for _, foodGroup in pairs(animalFood.groups) do |
181 | for _, fillTypeIndex in pairs(foodGroup.fillTypes) do |
182 | if spec.fillLevels[fillTypeIndex] == nil then |
183 | spec.fillLevels[fillTypeIndex] = 0.0 |
184 | spec.supportedFillTypes[fillTypeIndex] = true |
185 | table.insert(spec.fillTypes, fillTypeIndex) |
186 | end |
187 | end |
188 | end |
189 | end |
190 | |
191 | if mixtures ~= nil then |
192 | for _, foodMixtureFillType in ipairs(mixtures) do |
193 | spec.supportedFillTypes[foodMixtureFillType] = true |
194 | table.insert(spec.fillTypes, foodMixtureFillType) |
195 | end |
196 | end |
197 | end |
onReadStream
DescriptionDefinitiononReadStream()Code
237 | function PlaceableHusbandryFood:onReadStream(streamId, connection) |
238 | local spec = self.spec_husbandryFood |
239 | for _, fillTypeIndex in ipairs(spec.fillTypes) do |
240 | if spec.fillLevels[fillTypeIndex] ~= nil then |
241 | spec.fillLevels[fillTypeIndex] = streamReadUIntN(streamId, spec.FILLLEVEL_NUM_BITS) |
242 | end |
243 | end |
244 | |
245 | -- local totalFillLevel = self:getTotalFood() |
246 | -- if spec.dynamicFoodPlane ~= nil then |
247 | -- readFillPlaneFromStream(spec.dynamicFoodPlane, streamId, totalFillLevel) |
248 | -- end |
249 | |
250 | if spec.feedingTrough ~= nil then |
251 | local feedingTroughId = NetworkUtil.readNodeObjectId(streamId) |
252 | spec.feedingTrough:readStream(streamId, connection) |
253 | g_client:finishRegisterObject(spec.feedingTrough, feedingTroughId) |
254 | end |
255 | end |
onReadUpdateStream
DescriptionDefinitiononReadUpdateStream()Code
280 | function PlaceableHusbandryFood:onReadUpdateStream(streamId, timestamp, connection) |
281 | if connection:getIsServer() then |
282 | local spec = self.spec_husbandryFood |
283 | if streamReadBool(streamId) then |
284 | local x = (streamReadUIntN(streamId, FillVolume.SEND_NUM_BITS) / (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) * FillVolume.SEND_MAX_SIZE) - FillVolume.SEND_MAX_SIZE * 0.5 |
285 | local z = (streamReadUIntN(streamId, FillVolume.SEND_NUM_BITS) / (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) * FillVolume.SEND_MAX_SIZE) - FillVolume.SEND_MAX_SIZE * 0.5 |
286 | |
287 | spec.lastPositionInfo[1] = x |
288 | spec.lastPositionInfo[2] = z |
289 | end |
290 | |
291 | if streamReadBool(streamId) then |
292 | for _, fillTypeIndex in ipairs(spec.fillTypes) do |
293 | if spec.fillLevels[fillTypeIndex] ~= nil then |
294 | local newFillLevel = streamReadUIntN(streamId, spec.FILLLEVEL_NUM_BITS) |
295 | local delta = newFillLevel - spec.fillLevels[fillTypeIndex] |
296 | if delta > 0 then |
297 | self:addFood(self:getOwnerFarmId(), delta, fillTypeIndex, nil, nil, nil) |
298 | else |
299 | self:removeFood(math.abs(delta), fillTypeIndex) |
300 | end |
301 | end |
302 | end |
303 | end |
304 | end |
305 | end |
onWriteStream
DescriptionDefinitiononWriteStream()Code
259 | function PlaceableHusbandryFood:onWriteStream(streamId, connection) |
260 | local spec = self.spec_husbandryFood |
261 | for _, fillTypeIndex in ipairs(spec.fillTypes) do |
262 | if spec.fillLevels[fillTypeIndex] ~= nil then |
263 | streamWriteUIntN(streamId, spec.fillLevels[fillTypeIndex], spec.FILLLEVEL_NUM_BITS) |
264 | end |
265 | end |
266 | |
267 | -- if spec.dynamicFoodPlane ~= nil then |
268 | -- writeFillPlaneToStream(spec.dynamicFoodPlane, streamId) |
269 | -- end |
270 | |
271 | if spec.feedingTrough ~= nil then |
272 | NetworkUtil.writeNodeObjectId(streamId, NetworkUtil.getObjectId(spec.feedingTrough)) |
273 | spec.feedingTrough:writeStream(streamId, connection) |
274 | g_server:registerObjectInStream(connection, spec.feedingTrough) |
275 | end |
276 | end |
onWriteUpdateStream
DescriptionDefinitiononWriteUpdateStream()Code
309 | function PlaceableHusbandryFood:onWriteUpdateStream(streamId, connection, dirtyMask) |
310 | if not connection:getIsServer() then |
311 | local spec = self.spec_husbandryFood |
312 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlagPosition) ~= 0) then |
313 | local x = (spec.lastPositionInfoSent[1] + FillVolume.SEND_MAX_SIZE * 0.5) / FillVolume.SEND_MAX_SIZE * (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) |
314 | streamWriteUIntN(streamId, x, FillVolume.SEND_NUM_BITS) |
315 | |
316 | local z = (spec.lastPositionInfoSent[2] + FillVolume.SEND_MAX_SIZE * 0.5) / FillVolume.SEND_MAX_SIZE * (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) |
317 | streamWriteUIntN(streamId, z, FillVolume.SEND_NUM_BITS) |
318 | end |
319 | |
320 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlagFillLevel) ~= 0) then |
321 | for _, fillTypeIndex in ipairs(spec.fillTypes) do |
322 | if spec.fillLevels[fillTypeIndex] ~= nil then |
323 | streamWriteUIntN(streamId, spec.fillLevels[fillTypeIndex], spec.FILLLEVEL_NUM_BITS) |
324 | end |
325 | end |
326 | end |
327 | end |
328 | end |
prerequisitesPresent
DescriptionChecks if all prerequisite specializations are loadedDefinition
prerequisitesPresent(table specializations)Arguments
table | specializations | specializations |
boolean | hasPrerequisite | true if all prerequisite specializations are loaded |
18 | function PlaceableHusbandryFood.prerequisitesPresent(specializations) |
19 | return true |
20 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
46 | function PlaceableHusbandryFood.registerEventListeners(placeableType) |
47 | SpecializationUtil.registerEventListener(placeableType, "onLoad", PlaceableHusbandryFood) |
48 | SpecializationUtil.registerEventListener(placeableType, "onPostLoad", PlaceableHusbandryFood) |
49 | SpecializationUtil.registerEventListener(placeableType, "onDelete", PlaceableHusbandryFood) |
50 | SpecializationUtil.registerEventListener(placeableType, "onFinalizePlacement", PlaceableHusbandryFood) |
51 | SpecializationUtil.registerEventListener(placeableType, "onPostFinalizePlacement", PlaceableHusbandryFood) |
52 | SpecializationUtil.registerEventListener(placeableType, "onReadStream", PlaceableHusbandryFood) |
53 | SpecializationUtil.registerEventListener(placeableType, "onWriteStream", PlaceableHusbandryFood) |
54 | SpecializationUtil.registerEventListener(placeableType, "onReadUpdateStream", PlaceableHusbandryFood) |
55 | SpecializationUtil.registerEventListener(placeableType, "onWriteUpdateStream", PlaceableHusbandryFood) |
56 | SpecializationUtil.registerEventListener(placeableType, "onHusbandryAnimalsUpdate", PlaceableHusbandryFood) |
57 | SpecializationUtil.registerEventListener(placeableType, "onHusbandryAnimalsCreated", PlaceableHusbandryFood) |
58 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
24 | function PlaceableHusbandryFood.registerFunctions(placeableType) |
25 | SpecializationUtil.registerFunction(placeableType, "updateFillPlanes", PlaceableHusbandryFood.updateFillPlanes) |
26 | SpecializationUtil.registerFunction(placeableType, "updateFoodPlaces", PlaceableHusbandryFood.updateFoodPlaces) |
27 | SpecializationUtil.registerFunction(placeableType, "addFood", PlaceableHusbandryFood.addFood) |
28 | SpecializationUtil.registerFunction(placeableType, "removeFood", PlaceableHusbandryFood.removeFood) |
29 | SpecializationUtil.registerFunction(placeableType, "getTotalFood", PlaceableHusbandryFood.getTotalFood) |
30 | SpecializationUtil.registerFunction(placeableType, "getFoodCapacity", PlaceableHusbandryFood.getFoodCapacity) |
31 | SpecializationUtil.registerFunction(placeableType, "getFreeFoodCapacity", PlaceableHusbandryFood.getFreeFoodCapacity) |
32 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
36 | function PlaceableHusbandryFood.registerOverwrittenFunctions(placeableType) |
37 | SpecializationUtil.registerOverwrittenFunction(placeableType, "updateInfo", PlaceableHusbandryFood.updateInfo) |
38 | SpecializationUtil.registerOverwrittenFunction(placeableType, "updateFeeding", PlaceableHusbandryFood.updateFeeding) |
39 | SpecializationUtil.registerOverwrittenFunction(placeableType, "getFoodInfos", PlaceableHusbandryFood.getFoodInfos) |
40 | SpecializationUtil.registerOverwrittenFunction(placeableType, "collectPickObjects", PlaceableHusbandryFood.collectPickObjects) |
41 | SpecializationUtil.registerOverwrittenFunction(placeableType, "getAnimalDescription", PlaceableHusbandryFood.getAnimalDescription) |
42 | end |
registerSavegameXMLPaths
DescriptionDefinitionregisterSavegameXMLPaths()Code
79 | function PlaceableHusbandryFood.registerSavegameXMLPaths(schema, basePath) |
80 | schema:setXMLSpecializationType("Husbandry") |
81 | schema:register(XMLValueType.STRING, basePath .. ".fillLevel(?)#fillType", "Fill type") |
82 | schema:register(XMLValueType.FLOAT, basePath .. ".fillLevel(?)#fillLevel", "Fill level") |
83 | schema:setXMLSpecializationType() |
84 | end |
registerXMLPaths
DescriptionDefinitionregisterXMLPaths()Code
62 | function PlaceableHusbandryFood.registerXMLPaths(schema, basePath) |
63 | schema:setXMLSpecializationType("Husbandry") |
64 | basePath = basePath .. ".husbandry.food" |
65 | schema:register(XMLValueType.INT, basePath .. "#capacity", "Trough capacity", 5000) |
66 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".foodPlaces.foodPlace(?)#node", "Foodplace") |
67 | |
68 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".dynamicFoodPlane#node", "Node") |
69 | schema:register(XMLValueType.STRING, basePath .. ".dynamicFoodPlane#defaultFillType", "Fillplane default filltype") |
70 | FillPlaneUtil.registerFillPlaneXMLPaths(schema, basePath .. ".dynamicFoodPlane") |
71 | FillPlane.registerXMLPaths(schema, basePath .. ".foodPlane", "Fillplane") |
72 | schema:register(XMLValueType.STRING, basePath .. ".foodPlane#defaultFillType", "Fillplane default filltype") |
73 | UnloadTrigger.registerXMLPaths(schema, basePath .. ".feedingTrough") |
74 | schema:setXMLSpecializationType() |
75 | end |
removeFood
DescriptionDefinitionremoveFood()Code
608 | function PlaceableHusbandryFood:removeFood(absDeltaFillLevel, fillTypeIndex) |
609 | local spec = self.spec_husbandryFood |
610 | if spec.supportedFillTypes[fillTypeIndex] == nil then |
611 | return 0 |
612 | end |
613 | |
614 | if absDeltaFillLevel <= 0 then |
615 | return 0 |
616 | end |
617 | |
618 | absDeltaFillLevel = math.min(math.abs(absDeltaFillLevel), spec.fillLevels[fillTypeIndex]) |
619 | |
620 | if spec.dynamicFoodPlane ~= nil then |
621 | local x,y,z = localToWorld(spec.dynamicFoodPlane, 0,0,0) |
622 | local d1x,d1y,d1z = localDirectionToWorld(spec.dynamicFoodPlane, 0.1, 0, 0) |
623 | local d2x,d2y,d2z = localDirectionToWorld(spec.dynamicFoodPlane, 0, 0, 0.1) |
624 | |
625 | local steps = MathUtil.clamp(math.floor(absDeltaFillLevel/400), 1, 25) |
626 | local delta = absDeltaFillLevel/steps |
627 | for _=1, steps do |
628 | fillPlaneAdd(spec.dynamicFoodPlane, -delta, x,y,z, d1x,d1y,d1z, d2x,d2y,d2z) |
629 | end |
630 | end |
631 | |
632 | spec.fillLevels[fillTypeIndex] = spec.fillLevels[fillTypeIndex] - absDeltaFillLevel |
633 | |
634 | if self.isServer then |
635 | self:raiseDirtyFlags(spec.dirtyFlagFillLevel) |
636 | end |
637 | |
638 | self:updateFillPlanes() |
639 | self:updateFoodPlaces() |
640 | |
641 | return absDeltaFillLevel |
642 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
348 | function PlaceableHusbandryFood:saveToXMLFile(xmlFile, key, usedModNames) |
349 | local spec = self.spec_husbandryFood |
350 | local index = 0 |
351 | for fillTypeIndex, fillLevel in pairs(spec.fillLevels) do |
352 | if fillLevel > 0 then |
353 | local fillTypeName = g_fillTypeManager:getFillTypeNameByIndex(fillTypeIndex) |
354 | if fillTypeName ~= nil then |
355 | local fillLevelKey = string.format("%s.fillLevel(%d)", key, index) |
356 | xmlFile:setValue(fillLevelKey.."#fillType", fillTypeName) |
357 | xmlFile:setValue(fillLevelKey.."#fillLevel", fillLevel) |
358 | index = index + 1 |
359 | end |
360 | end |
361 | end |
362 | end |
updateFeeding
DescriptionDefinitionupdateFeeding()Code
366 | function PlaceableHusbandryFood:updateFeeding(superFunc) |
367 | local factor = superFunc(self) |
368 | local spec = self.spec_husbandryFood |
369 | |
370 | if self.isServer and spec.animalTypeIndex ~= nil then |
371 | local consumedFood = {} |
372 | factor = factor * g_currentMission.animalFoodSystem:consumeFood(spec.animalTypeIndex, spec.litersPerHour * g_currentMission.environment.timeAdjustment, spec.fillLevels, consumedFood) |
373 | |
374 | for fillTypeIndex, delta in pairs(consumedFood) do |
375 | self:removeFood(delta, fillTypeIndex) |
376 | end |
377 | end |
378 | |
379 | return factor |
380 | end |
updateFillPlanes
DescriptionDefinitionupdateFillPlanes()Code
431 | function PlaceableHusbandryFood:updateFillPlanes(fillTypeIndex) |
432 | local spec = self.spec_husbandryFood |
433 | if spec.foodPlane ~= nil then |
434 | local fillLevel = self:getTotalFood() |
435 | local capacity = self:getFoodCapacity() |
436 | local state = 0 |
437 | if capacity > 0 then |
438 | state = fillLevel / capacity |
439 | end |
440 | spec.foodPlane:setState(state) |
441 | |
442 | if state > 0 and fillTypeIndex ~= nil then |
443 | FillPlaneUtil.assignDefaultMaterials(spec.foodPlane.node) |
444 | FillPlaneUtil.setFillType(spec.foodPlane.node, fillTypeIndex) |
445 | setShaderParameter(spec.foodPlane.node, "isCustomShape", 1, 0, 0, 0, false) |
446 | end |
447 | end |
448 | end |
updateFoodPlaces
DescriptionDefinitionupdateFoodPlaces()Code
475 | function PlaceableHusbandryFood:updateFoodPlaces() |
476 | local spec = self.spec_husbandryFood |
477 | if spec.husbandry ~= nil then |
478 | local fillLevel = self:getTotalFood() |
479 | for _, foodPlace in pairs(spec.foodPlaces) do |
480 | if foodPlace.place ~= nil then |
481 | updateFeedingPlace(spec.husbandry, foodPlace.place, fillLevel) |
482 | end |
483 | end |
484 | end |
485 | end |
updateInfo
DescriptionDefinitionupdateInfo()Code
384 | function PlaceableHusbandryFood:updateInfo(superFunc, infoTable) |
385 | superFunc(self, infoTable) |
386 | local spec = self.spec_husbandryFood |
387 | |
388 | local fillLevel = self:getTotalFood() |
389 | spec.info.text = string.format("%d l", fillLevel) |
390 | table.insert(infoTable, spec.info) |
391 | end |