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
WoodCrusher
DescriptionSpecialization for wood crusher allowing to cut and convert tree trunks into wood chipsFunctions
- crushSplitShape
- deleteWoodCrusher
- getCanBeTurnedOn
- getDirtMultiplier
- getWearMultiplier
- initSpecialization
- loadWoodCrusher
- onCrushedSplitShape
- onDelete
- onLoad
- onReadUpdateStream
- onTurnedOff
- onTurnedOn
- onUpdate
- onUpdateTick
- onWriteUpdateStream
- prerequisitesPresent
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- registerWoodCrusherXMLPaths
- turnOffWoodCrusher
- turnOnWoodCrusher
- updateTickWoodCrusher
- updateWoodCrusher
- woodCrusherDownForceTriggerCallback
- woodCrusherMoveTriggerCallback
- woodCrusherSplitShapeCallback
crushSplitShape
DescriptionCrush split shapeDefinition
crushSplitShape(integer shape)Arguments
integer | shape | id of shape |
628 | function WoodCrusher.crushSplitShape(self, woodCrusher, shape) |
629 | local splitType = g_splitTypeManager:getSplitTypeByIndex(getSplitType(shape)) |
630 | if splitType ~= nil and splitType.woodChipsPerLiter > 0 then |
631 | local volume = getVolume(shape) |
632 | delete(shape) |
633 | woodCrusher.crushingTime = 1000 |
634 | self:onCrushedSplitShape(splitType, volume) |
635 | end |
636 | end |
deleteWoodCrusher
DescriptionDelete wood crusherDefinition
deleteWoodCrusher()Code
428 | function WoodCrusher.deleteWoodCrusher(self, woodCrusher) |
429 | if woodCrusher.moveTriggers ~= nil then |
430 | for _,node in pairs(woodCrusher.moveTriggers) do |
431 | removeTrigger(node) |
432 | end |
433 | end |
434 | |
435 | if woodCrusher.downForceTriggers ~= nil then |
436 | for trigger, _ in pairs(woodCrusher.downForceTriggers) do |
437 | removeTrigger(trigger) |
438 | end |
439 | end |
440 | |
441 | g_effectManager:deleteEffects(woodCrusher.crushEffects) |
442 | g_soundManager:deleteSamples(woodCrusher.samples) |
443 | g_animationManager:deleteAnimations(woodCrusher.animationNodes) |
444 | end |
getCanBeTurnedOn
DescriptionReturns if user is allowed to turn on the vehicleDefinition
getCanBeTurnedOn()Return Values
boolean | allow | allow turn on |
236 | function WoodCrusher:getCanBeTurnedOn(superFunc) |
237 | local spec = self.spec_woodCrusher |
238 | if spec.turnOnAutomatically then |
239 | return false |
240 | end |
241 | |
242 | return superFunc(self) |
243 | end |
getDirtMultiplier
DescriptionReturns current dirt multiplierDefinition
getDirtMultiplier()Return Values
float | dirtMultiplier | current dirt multiplier |
248 | function WoodCrusher:getDirtMultiplier(superFunc) |
249 | local multiplier = superFunc(self) |
250 | |
251 | local spec = self.spec_woodCrusher |
252 | if spec.crushingTime > 0 then |
253 | multiplier = multiplier + self:getWorkDirtMultiplier() |
254 | end |
255 | |
256 | return multiplier |
257 | end |
getWearMultiplier
DescriptionReturns current wear multiplierDefinition
getWearMultiplier()Return Values
float | dirtMultiplier | current wear multiplier |
262 | function WoodCrusher:getWearMultiplier(superFunc) |
263 | local multiplier = superFunc(self) |
264 | |
265 | local spec = self.spec_woodCrusher |
266 | if spec.crushingTime > 0 then |
267 | multiplier = multiplier + self:getWorkWearMultiplier() |
268 | end |
269 | |
270 | return multiplier |
271 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
25 | function WoodCrusher.initSpecialization() |
26 | local schema = Vehicle.xmlSchema |
27 | schema:setXMLSpecializationType("WoodCrusher") |
28 | |
29 | WoodCrusher.registerWoodCrusherXMLPaths(schema, "vehicle.woodCrusher") |
30 | |
31 | schema:register(XMLValueType.BOOL, "vehicle.woodCrusher#moveColDisableCollisionPairs", "Activate collision between move collisions and components", true) |
32 | schema:register(XMLValueType.INT, "vehicle.woodCrusher#fillUnitIndex", "Fill unit index", 1) |
33 | |
34 | schema:setXMLSpecializationType() |
35 | end |
loadWoodCrusher
DescriptionLoad wood crusher from xml fileDefinition
loadWoodCrusher(table woodCrusher, integer xmlFile, integer rootNode, table i3dMappings)Arguments
table | woodCrusher | target wood crusher table |
integer | xmlFile | id of xml object |
integer | rootNode | id of root node or list of components |
table | i3dMappings | i3d mappings |
294 | function WoodCrusher.loadWoodCrusher(self, woodCrusher, xmlFile, rootNode, i3dMappings) |
295 | woodCrusher.vehicle = self |
296 | |
297 | woodCrusher.woodCrusherSplitShapeCallback = WoodCrusher.woodCrusherSplitShapeCallback |
298 | woodCrusher.woodCrusherMoveTriggerCallback = WoodCrusher.woodCrusherMoveTriggerCallback |
299 | woodCrusher.woodCrusherDownForceTriggerCallback = WoodCrusher.woodCrusherDownForceTriggerCallback |
300 | |
301 | local xmlRoot = xmlFile:getRootName() |
302 | local baseKey = xmlRoot .. ".woodCrusher" |
303 | |
304 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusher.moveTrigger(0)#index", xmlRoot .. ".woodCrusher.moveTriggers.trigger#node") --FS17 to FS19 |
305 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusher.moveCollision(0)#index", xmlRoot .. ".woodCrusher.moveCollisions.collision#node") --FS17 to FS19 |
306 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusher.emitterShape(0)", xmlRoot .. ".woodCrusher.crushEffects with effectClass 'ParticleEffect'") --FS17 to FS19 |
307 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusherStartSound", xmlRoot .. ".woodCrusher.sounds.start") --FS17 to FS19 |
308 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusherIdleSound", xmlRoot .. ".woodCrusher.sounds.idle") --FS17 to FS19 |
309 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusherWorkSound", xmlRoot .. ".woodCrusher.sounds.work") --FS17 to FS19 |
310 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".woodCrusherStopSound", xmlRoot .. ".woodCrusher.sounds.stop") --FS17 to FS19 |
311 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".turnedOnRotationNodes.turnedOnRotationNode#type", xmlRoot .. ".woodCrusher.animationNodes.animationNode", "woodCrusher") --FS17 to FS19 |
312 | XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlRoot .. ".turnedOnScrollers.turnedOnScroller", xmlRoot .. ".woodCrusher.animationNodes.animationNode") --FS17 to FS19 |
313 | |
314 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. "#downForceNode", baseKey .. ".downForceNodes.downForceNode#node") --FS19 to FS22 |
315 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. "#downForce", baseKey .. ".downForceNodes.downForceNode#force") --FS19 to FS22 |
316 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. "#downForceSizeY", baseKey .. ".downForceNodes.downForceNode#sizeY") --FS19 to FS22 |
317 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. "#downForceSizeZ", baseKey .. ".downForceNodes.downForceNode#sizeZ") --FS19 to FS22 |
318 | |
319 | woodCrusher.cutNode = xmlFile:getValue(baseKey .. "#cutNode", nil, rootNode, i3dMappings) |
320 | woodCrusher.mainDrumRefNode = xmlFile:getValue(baseKey .. "#mainDrumRefNode", nil, rootNode, i3dMappings) |
321 | woodCrusher.mainDrumRefNodeMaxY = xmlFile:getValue(baseKey .. "#mainDrumRefNodeMaxY", math.huge) |
322 | |
323 | if woodCrusher.mainDrumRefNode ~= nil then |
324 | local mainDrumRefNodeParent = createTransformGroup("mainDrumRefNodeParent") |
325 | link(getParent(woodCrusher.mainDrumRefNode), mainDrumRefNodeParent, getChildIndex(woodCrusher.mainDrumRefNode)) |
326 | setTranslation(mainDrumRefNodeParent, getTranslation(woodCrusher.mainDrumRefNode)) |
327 | setRotation(mainDrumRefNodeParent, getRotation(woodCrusher.mainDrumRefNode)) |
328 | link(mainDrumRefNodeParent, woodCrusher.mainDrumRefNode) |
329 | setTranslation(woodCrusher.mainDrumRefNode, 0, 0, 0) |
330 | setRotation(woodCrusher.mainDrumRefNode, 0, 0, 0) |
331 | end |
332 | |
333 | woodCrusher.moveTriggers = {} |
334 | local i = 0 |
335 | while true do |
336 | local key = string.format("%s.moveTriggers.trigger(%d)", baseKey, i) |
337 | if not xmlFile:hasProperty(key) then |
338 | break |
339 | end |
340 | |
341 | local node = xmlFile:getValue(key .. "#node", nil, rootNode, i3dMappings) |
342 | if node ~= nil then |
343 | if not CollisionFlag.getHasFlagSet(node, CollisionFlag.TREE) then |
344 | Logging.xmlWarning(self.xmlFile, "Missing collision mask bit '%d'. Please add this bit to move trigger node '%s' in '%s'", CollisionFlag.getBit(CollisionFlag.TREE), getName(node), key) |
345 | break |
346 | end |
347 | table.insert(woodCrusher.moveTriggers, node) |
348 | end |
349 | i = i + 1 |
350 | end |
351 | |
352 | woodCrusher.moveColNodes = {} |
353 | i = 0 |
354 | while true do |
355 | local key = string.format("%s.moveCollisions.collision(%d)", baseKey, i) |
356 | if not xmlFile:hasProperty(key) then |
357 | break |
358 | end |
359 | |
360 | local moveColNode = {} |
361 | moveColNode.node = xmlFile:getValue(key .. "#node", nil, rootNode, i3dMappings) |
362 | if moveColNode.node ~= nil then |
363 | moveColNode.transX, moveColNode.transY, moveColNode.transZ = getTranslation(moveColNode.node) |
364 | table.insert(woodCrusher.moveColNodes, moveColNode) |
365 | end |
366 | i = i + 1 |
367 | end |
368 | |
369 | woodCrusher.moveVelocityZ = xmlFile:getValue(baseKey.."#moveVelocityZ", 0.8) -- m/s |
370 | woodCrusher.moveMaxForce = xmlFile:getValue(baseKey.."#moveMaxForce", 7) -- input is kN |
371 | woodCrusher.shapeSizeDetectionNode = xmlFile:getValue(baseKey.."#shapeSizeDetectionNode", nil, rootNode, i3dMappings) |
372 | woodCrusher.cutSizeY = xmlFile:getValue(baseKey.."#cutSizeY", 1) |
373 | woodCrusher.cutSizeZ = xmlFile:getValue(baseKey.."#cutSizeZ", 1) |
374 | |
375 | woodCrusher.downForceNodes = {} |
376 | woodCrusher.downForceTriggers = {} |
377 | xmlFile:iterate(baseKey .. ".downForceNodes.downForceNode", function(_, key) |
378 | local downForceNode = {} |
379 | downForceNode.node = xmlFile:getValue(key .. "#node", nil, rootNode, i3dMappings) |
380 | if downForceNode.node ~= nil then |
381 | downForceNode.force = xmlFile:getValue(key.."#force", 2) |
382 | downForceNode.trigger = xmlFile:getValue(key .. "#trigger", nil, rootNode, i3dMappings) |
383 | |
384 | downForceNode.sizeY = xmlFile:getValue(key.."#sizeY", woodCrusher.cutSizeY) |
385 | downForceNode.sizeZ = xmlFile:getValue(key.."#sizeZ", woodCrusher.cutSizeZ) |
386 | |
387 | downForceNode.woodCrusher = woodCrusher |
388 | downForceNode.triggerNodes = {} |
389 | |
390 | if downForceNode.trigger ~= nil and woodCrusher.downForceTriggers[downForceNode.trigger] == nil then |
391 | if self.isServer then |
392 | woodCrusher.downForceTriggers[downForceNode.trigger] = true |
393 | addTrigger(downForceNode.trigger, "woodCrusherDownForceTriggerCallback", woodCrusher) |
394 | end |
395 | end |
396 | |
397 | table.insert(woodCrusher.downForceNodes, downForceNode) |
398 | end |
399 | end) |
400 | |
401 | woodCrusher.moveTriggerNodes = {} |
402 | if self.isServer and woodCrusher.moveTriggers ~= nil then |
403 | for _,node in pairs(woodCrusher.moveTriggers) do |
404 | addTrigger(node, "woodCrusherMoveTriggerCallback", woodCrusher) |
405 | end |
406 | end |
407 | |
408 | woodCrusher.crushNodes = {} |
409 | woodCrusher.crushingTime = 0 |
410 | woodCrusher.turnOnAutomatically = xmlFile:getValue(baseKey .. "#automaticallyTurnOn", false) |
411 | |
412 | if self.isClient then |
413 | woodCrusher.crushEffects = g_effectManager:loadEffect(xmlFile, baseKey..".crushEffects", rootNode, self, i3dMappings) |
414 | |
415 | woodCrusher.animationNodes = g_animationManager:loadAnimations(xmlFile, baseKey..".animationNodes", rootNode, self, i3dMappings) |
416 | |
417 | woodCrusher.isWorkSamplePlaying = false |
418 | woodCrusher.samples = {} |
419 | woodCrusher.samples.start = g_soundManager:loadSampleFromXML(xmlFile, baseKey..".sounds", "start", self.baseDirectory, rootNode, 1, AudioGroup.VEHICLE, i3dMappings, self) |
420 | woodCrusher.samples.stop = g_soundManager:loadSampleFromXML(xmlFile, baseKey..".sounds", "stop", self.baseDirectory, rootNode, 1, AudioGroup.VEHICLE, i3dMappings, self) |
421 | woodCrusher.samples.work = g_soundManager:loadSampleFromXML(xmlFile, baseKey..".sounds", "work", self.baseDirectory, rootNode, 0, AudioGroup.VEHICLE, i3dMappings, self) |
422 | woodCrusher.samples.idle = g_soundManager:loadSampleFromXML(xmlFile, baseKey..".sounds", "idle", self.baseDirectory, rootNode, 0, AudioGroup.VEHICLE, i3dMappings, self) |
423 | end |
424 | end |
onCrushedSplitShape
DescriptionCalled on crush split shapeDefinition
onCrushedSplitShape(table splitType, float volume)Arguments
table | splitType | split type |
float | volume | volume |
277 | function WoodCrusher:onCrushedSplitShape(splitType, volume) |
278 | local spec = self.spec_woodCrusher |
279 | |
280 | local damage = self:getVehicleDamage() |
281 | if damage > 0 then |
282 | volume = volume * (1 - damage * WoodCrusher.DAMAGED_YIELD_DECREASE) |
283 | end |
284 | |
285 | self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.fillUnitIndex, volume * 1000 * splitType.woodChipsPerLiter, FillType.WOODCHIPS, ToolType.UNDEFINED) |
286 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
119 | function WoodCrusher:onDelete() |
120 | WoodCrusher.deleteWoodCrusher(self, self.spec_woodCrusher) |
121 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
100 | function WoodCrusher:onLoad(savegame) |
101 | local spec = self.spec_woodCrusher |
102 | |
103 | WoodCrusher.loadWoodCrusher(self, spec, self.xmlFile, self.components, self.i3dMappings) |
104 | |
105 | local moveColDisableCollisionPairs = self.xmlFile:getValue("vehicle.woodCrusher#moveColDisableCollisionPairs", true) |
106 | if moveColDisableCollisionPairs then |
107 | for _, component in pairs(self.components) do |
108 | for _, node in pairs(spec.moveColNodes) do |
109 | setPairCollision(component.node, node, false) |
110 | end |
111 | end |
112 | end |
113 | |
114 | spec.fillUnitIndex = self.xmlFile:getValue("vehicle.woodCrusher#fillUnitIndex", 1) |
115 | end |
onReadUpdateStream
DescriptionCalled on on updateDefinition
onReadUpdateStream(integer streamId, integer timestamp, table connection)Arguments
integer | streamId | stream ID |
integer | timestamp | timestamp |
table | connection | connection |
128 | function WoodCrusher:onReadUpdateStream(streamId, timestamp, connection) |
129 | if connection:getIsServer() then |
130 | local spec = self.spec_woodCrusher |
131 | if streamReadBool(streamId) then |
132 | spec.crushingTime = 1000 |
133 | else |
134 | spec.crushingTime = 0 |
135 | end |
136 | end |
137 | end |
onTurnedOff
DescriptionCalled on turn offDefinition
onTurnedOff(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
229 | function WoodCrusher:onTurnedOff() |
230 | WoodCrusher.turnOffWoodCrusher(self, self.spec_woodCrusher) |
231 | end |
onTurnedOn
DescriptionCalled on turn onDefinition
onTurnedOn(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
222 | function WoodCrusher:onTurnedOn() |
223 | WoodCrusher.turnOnWoodCrusher(self, self.spec_woodCrusher) |
224 | end |
onUpdate
DescriptionCalled on updateDefinition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
156 | function WoodCrusher:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
157 | WoodCrusher.updateWoodCrusher(self, self.spec_woodCrusher, dt, self:getIsTurnedOn()) |
158 | end |
onUpdateTick
DescriptionCalled on update tickDefinition
onUpdateTick(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
165 | function WoodCrusher:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
166 | WoodCrusher.updateTickWoodCrusher(self, self.spec_woodCrusher, dt, self:getIsTurnedOn()) |
167 | |
168 | local spec = self.spec_woodCrusher |
169 | -- turn on/off automatically if tree node is in trigger |
170 | if self.isServer then |
171 | if g_currentMission.missionInfo.automaticMotorStartEnabled then |
172 | if spec.turnOnAutomatically and self.setIsTurnedOn ~= nil then |
173 | if next(spec.moveTriggerNodes) ~= nil then |
174 | if self.getIsMotorStarted ~= nil then |
175 | if not self:getIsMotorStarted() then |
176 | self:startMotor() |
177 | end |
178 | else |
179 | if self.attacherVehicle ~= nil then |
180 | if self.attacherVehicle.getIsMotorStarted ~= nil then |
181 | if not self.attacherVehicle:getIsMotorStarted() then |
182 | self.attacherVehicle:startMotor() |
183 | end |
184 | end |
185 | end |
186 | end |
187 | |
188 | if not self.isControlled and not self:getIsTurnedOn() and self:getCanBeTurnedOn() then |
189 | self:setIsTurnedOn(true) |
190 | end |
191 | spec.turnOffTimer = 3000 |
192 | else |
193 | if self:getIsTurnedOn() then |
194 | if spec.turnOffTimer == nil then |
195 | spec.turnOffTimer = 3000 |
196 | end |
197 | spec.turnOffTimer = spec.turnOffTimer - dt |
198 | |
199 | if spec.turnOffTimer < 0 then |
200 | local rootAttacherVehicle = self:getRootVehicle() |
201 | |
202 | if not rootAttacherVehicle.isControlled then |
203 | if self.getIsMotorStarted ~= nil then |
204 | if self:getIsMotorStarted() then |
205 | self:stopMotor() |
206 | end |
207 | end |
208 | |
209 | self:setIsTurnedOn(false) |
210 | end |
211 | end |
212 | end |
213 | end |
214 | end |
215 | end |
216 | end |
217 | end |
onWriteUpdateStream
DescriptionCalled on on updateDefinition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)Arguments
integer | streamId | stream ID |
table | connection | connection |
integer | dirtyMask | dirty mask |
144 | function WoodCrusher:onWriteUpdateStream(streamId, connection, dirtyMask) |
145 | if not connection:getIsServer() then |
146 | local spec = self.spec_woodCrusher |
147 | streamWriteBool(streamId, spec.crushingTime > 0) |
148 | end |
149 | 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 |
19 | function WoodCrusher.prerequisitesPresent(specializations) |
20 | return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations) and SpecializationUtil.hasSpecialization(FillUnit, specializations) |
21 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
86 | function WoodCrusher.registerEventListeners(vehicleType) |
87 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", WoodCrusher) |
88 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", WoodCrusher) |
89 | SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", WoodCrusher) |
90 | SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", WoodCrusher) |
91 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", WoodCrusher) |
92 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", WoodCrusher) |
93 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", WoodCrusher) |
94 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", WoodCrusher) |
95 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
72 | function WoodCrusher.registerFunctions(vehicleType) |
73 | SpecializationUtil.registerFunction(vehicleType, "onCrushedSplitShape", WoodCrusher.onCrushedSplitShape) |
74 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
78 | function WoodCrusher.registerOverwrittenFunctions(vehicleType) |
79 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", WoodCrusher.getDirtMultiplier) |
80 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", WoodCrusher.getWearMultiplier) |
81 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", WoodCrusher.getCanBeTurnedOn) |
82 | end |
registerWoodCrusherXMLPaths
DescriptionDefinitionregisterWoodCrusherXMLPaths()Code
39 | function WoodCrusher.registerWoodCrusherXMLPaths(schema, key) |
40 | schema:register(XMLValueType.NODE_INDEX, key .. "#cutNode", "Cut node") |
41 | schema:register(XMLValueType.NODE_INDEX, key .. "#mainDrumRefNode", "Main drum reference node") |
42 | schema:register(XMLValueType.FLOAT, key .. "#mainDrumRefNodeMaxY", "Max tree size the main drum can handle") |
43 | |
44 | schema:register(XMLValueType.NODE_INDEX, key .. ".moveTriggers.trigger(?)#node", "Move trigger") |
45 | schema:register(XMLValueType.NODE_INDEX, key .. ".moveCollisions.collision(?)#node", "Move collision") |
46 | |
47 | schema:register(XMLValueType.FLOAT, key .. "#moveVelocityZ", "Move velocity Z (m/s)", 0.8) |
48 | schema:register(XMLValueType.FLOAT, key .. "#moveMaxForce", "Move max. force (kN)", 7) |
49 | schema:register(XMLValueType.NODE_INDEX, key .. "#shapeSizeDetectionNode", "At this node the tree shape size will be detected to set the #mainDrumRefNode") |
50 | schema:register(XMLValueType.FLOAT, key .. "#cutSizeY", "Cut size Y", 1) |
51 | schema:register(XMLValueType.FLOAT, key .. "#cutSizeZ", "Cut size Z", 1) |
52 | |
53 | schema:register(XMLValueType.NODE_INDEX, key .. ".downForceNodes.downForceNode(?)#node", "Down force node") |
54 | schema:register(XMLValueType.NODE_INDEX, key .. ".downForceNodes.downForceNode(?)#trigger", "Additional trigger (If defined the tree needs to be present in the mover trigger and inside this trigger)") |
55 | schema:register(XMLValueType.FLOAT, key .. ".downForceNodes.downForceNode(?)#force", "Down force (kN)", 2) |
56 | schema:register(XMLValueType.FLOAT, key .. ".downForceNodes.downForceNode(?)#sizeY", "Size Y in which the down force node detects trees", "Cut size Y") |
57 | schema:register(XMLValueType.FLOAT, key .. ".downForceNodes.downForceNode(?)#sizeZ", "Size Z in which the down force node detects trees", "Cut size Z") |
58 | |
59 | schema:register(XMLValueType.BOOL, key .. "#automaticallyTurnOn", "Automatically turned on", false) |
60 | |
61 | EffectManager.registerEffectXMLPaths(schema, key .. ".crushEffects") |
62 | AnimationManager.registerAnimationNodesXMLPaths(schema, key .. ".animationNodes") |
63 | |
64 | SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "start") |
65 | SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "stop") |
66 | SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "work") |
67 | SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "idle") |
68 | end |
turnOffWoodCrusher
DescriptionTurn off wood crusherDefinition
turnOffWoodCrusher()Code
600 | function WoodCrusher.turnOffWoodCrusher(self, woodCrusher) |
601 | if self.isServer then |
602 | for node in pairs(woodCrusher.crushNodes) do |
603 | WoodCrusher.crushSplitShape(self, woodCrusher, node) |
604 | woodCrusher.crushNodes[node] = nil |
605 | end |
606 | if woodCrusher.moveColNodes ~= nil then |
607 | for _, moveColNode in pairs(woodCrusher.moveColNodes) do |
608 | setFrictionVelocity(moveColNode.node, 0.0) |
609 | end |
610 | end |
611 | end |
612 | |
613 | if self.isClient then |
614 | g_effectManager:stopEffects(woodCrusher.crushEffects) |
615 | g_soundManager:stopSamples(woodCrusher.samples) |
616 | g_soundManager:playSample(woodCrusher.samples.stop) |
617 | woodCrusher.isWorkSamplePlaying = false |
618 | |
619 | if self.isClient then |
620 | g_animationManager:stopAnimations(woodCrusher.animationNodes) |
621 | end |
622 | end |
623 | end |
turnOnWoodCrusher
DescriptionTurn on wood crusherDefinition
turnOnWoodCrusher()Code
579 | function WoodCrusher.turnOnWoodCrusher(self, woodCrusher) |
580 | if self.isServer and woodCrusher.moveColNodes ~= nil then |
581 | for _, moveColNode in pairs(woodCrusher.moveColNodes) do |
582 | setFrictionVelocity(moveColNode.node, woodCrusher.moveVelocityZ) |
583 | end |
584 | end |
585 | |
586 | if self.isClient then |
587 | g_soundManager:stopSamples(woodCrusher.samples) |
588 | woodCrusher.isWorkSamplePlaying = false |
589 | g_soundManager:playSample(woodCrusher.samples.start) |
590 | g_soundManager:playSample(woodCrusher.samples.idle, 0, woodCrusher.samples.start) |
591 | |
592 | if self.isClient then |
593 | g_animationManager:startAnimations(woodCrusher.animationNodes) |
594 | end |
595 | end |
596 | end |
updateTickWoodCrusher
DescriptionUpdate tick wood crusherDefinition
updateTickWoodCrusher(float dt)Arguments
float | dt | time since last call in ms |
516 | function WoodCrusher.updateTickWoodCrusher(self, woodCrusher, dt, isTurnedOn) |
517 | if isTurnedOn then |
518 | if self.isServer then |
519 | if woodCrusher.cutNode ~= nil and next(woodCrusher.moveTriggerNodes) ~= nil then |
520 | local x,y,z = getWorldTranslation(woodCrusher.cutNode) |
521 | local nx,ny,nz = localDirectionToWorld(woodCrusher.cutNode, 1,0,0) |
522 | local yx,yy,yz = localDirectionToWorld(woodCrusher.cutNode, 0,1,0) |
523 | for id in pairs(woodCrusher.moveTriggerNodes) do |
524 | local lenBelow, lenAbove = getSplitShapePlaneExtents(id, x,y,z, nx,ny,nz) |
525 | if lenAbove ~= nil and lenBelow ~= nil then |
526 | if lenBelow <= 0.4 then |
527 | woodCrusher.moveTriggerNodes[id] = nil |
528 | WoodCrusher.crushSplitShape(self, woodCrusher, id) |
529 | elseif lenAbove >= 0.2 then |
530 | self.shapeBeingCut = id |
531 | local minY = splitShape(id, x,y,z, nx,ny,nz, yx,yy,yz, woodCrusher.cutSizeY, woodCrusher.cutSizeZ, "woodCrusherSplitShapeCallback", woodCrusher) |
532 | g_treePlantManager:removingSplitShape(id) |
533 | if minY ~= nil then |
534 | woodCrusher.moveTriggerNodes[id] = nil |
535 | end |
536 | end |
537 | end |
538 | end |
539 | end |
540 | |
541 | if self.isServer and woodCrusher.moveColNodes ~= nil then |
542 | for _, moveColNode in pairs(woodCrusher.moveColNodes) do |
543 | setTranslation(moveColNode.node, moveColNode.transX, moveColNode.transY + math.random() * 0.005, moveColNode.transZ) |
544 | end |
545 | end |
546 | end |
547 | end |
548 | |
549 | if woodCrusher.crushingTime > 0 then |
550 | woodCrusher.crushingTime = math.max(woodCrusher.crushingTime - dt, 0) |
551 | end |
552 | |
553 | local isCrushing = woodCrusher.crushingTime > 0 |
554 | |
555 | if self.isClient then |
556 | if isCrushing then |
557 | g_effectManager:setFillType(woodCrusher.crushEffects, FillType.WOODCHIPS) |
558 | g_effectManager:startEffects(woodCrusher.crushEffects) |
559 | else |
560 | g_effectManager:stopEffects(woodCrusher.crushEffects) |
561 | end |
562 | |
563 | if isTurnedOn and isCrushing then |
564 | if not woodCrusher.isWorkSamplePlaying then |
565 | g_soundManager:playSample(woodCrusher.samples.work) |
566 | woodCrusher.isWorkSamplePlaying = true |
567 | end |
568 | else |
569 | if woodCrusher.isWorkSamplePlaying then |
570 | g_soundManager:stopSample(woodCrusher.samples.work) |
571 | woodCrusher.isWorkSamplePlaying = false |
572 | end |
573 | end |
574 | end |
575 | end |
updateWoodCrusher
DescriptionUpdate wood crusherDefinition
updateWoodCrusher(float dt)Arguments
float | dt | time since last call in ms |
449 | function WoodCrusher.updateWoodCrusher(self, woodCrusher, dt, isTurnedOn) |
450 | if isTurnedOn then |
451 | if self.isServer then |
452 | for node in pairs(woodCrusher.crushNodes) do |
453 | WoodCrusher.crushSplitShape(self, woodCrusher, node) |
454 | woodCrusher.crushNodes[node] = nil |
455 | woodCrusher.moveTriggerNodes[node] = nil |
456 | end |
457 | |
458 | local maxTreeSizeY = 0 |
459 | for id in pairs(woodCrusher.moveTriggerNodes) do |
460 | if not entityExists(id) then |
461 | woodCrusher.moveTriggerNodes[id] = nil |
462 | else |
463 | for i=1, #woodCrusher.downForceNodes do |
464 | local downForceNode = woodCrusher.downForceNodes[i] |
465 | if downForceNode.triggerNodes[id] ~= nil or downForceNode.trigger == nil then |
466 | local x, y, z = getWorldTranslation(downForceNode.node) |
467 | local nx, ny, nz = localDirectionToWorld(downForceNode.node, 1,0,0) |
468 | local yx, yy, yz = localDirectionToWorld(downForceNode.node, 0,1,0) |
469 | |
470 | local minY,maxY, minZ,maxZ = testSplitShape(id, x,y,z, nx,ny,nz, yx,yy,yz, downForceNode.sizeY, downForceNode.sizeZ) |
471 | if minY ~= nil then |
472 | local cx,cy,cz = localToWorld(downForceNode.node, 0, (minY+maxY)*0.5, (minZ+maxZ)*0.5) |
473 | local downX,downY,downZ = localDirectionToWorld(downForceNode.node, 0, -downForceNode.force, 0) |
474 | addForce(id, downX, downY, downZ, cx,cy,cz, false) |
475 | --#debug drawDebugLine(cx, cy, cz, 1, 0, 0, cx+downX, cy+downY, cz+downZ, 0, 1, 0, true) |
476 | end |
477 | end |
478 | end |
479 | |
480 | if woodCrusher.shapeSizeDetectionNode ~= nil then |
481 | local x, y, z = getWorldTranslation(woodCrusher.shapeSizeDetectionNode) |
482 | local nx, ny, nz = localDirectionToWorld(woodCrusher.shapeSizeDetectionNode, 1,0,0) |
483 | local yx, yy, yz = localDirectionToWorld(woodCrusher.shapeSizeDetectionNode, 0,1,0) |
484 | |
485 | local minY, maxY, _, _ = testSplitShape(id, x, y, z, nx, ny, nz, yx, yy, yz, woodCrusher.cutSizeY, woodCrusher.cutSizeZ) |
486 | if minY ~= nil then |
487 | if woodCrusher.mainDrumRefNode ~= nil then |
488 | maxTreeSizeY = math.max(maxTreeSizeY, maxY) |
489 | end |
490 | end |
491 | end |
492 | end |
493 | end |
494 | if woodCrusher.mainDrumRefNode ~= nil then |
495 | local x, y, z = getTranslation(woodCrusher.mainDrumRefNode) |
496 | local ty = math.min(maxTreeSizeY, woodCrusher.mainDrumRefNodeMaxY) |
497 | if ty > y then |
498 | y = math.min(y + 0.0003*dt, ty) |
499 | else |
500 | y = math.max(y - 0.0003*dt, ty) |
501 | end |
502 | |
503 | setTranslation(woodCrusher.mainDrumRefNode, x, y, z) |
504 | end |
505 | |
506 | if next(woodCrusher.moveTriggerNodes) ~= nil or woodCrusher.crushingTime > 0 then |
507 | self:raiseActive() |
508 | end |
509 | end |
510 | end |
511 | end |
woodCrusherDownForceTriggerCallback
DescriptionTrigger callbackDefinition
woodCrusherDownForceTriggerCallback(integer triggerId, integer otherActorId, boolean onEnter, boolean onLeave, boolean onStay, integer otherShapeId)Arguments
integer | triggerId | id of trigger |
integer | otherActorId | id of other actor |
boolean | onEnter | on enter |
boolean | onLeave | on leave |
boolean | onStay | on stay |
integer | otherShapeId | id of other shape |
693 | function WoodCrusher.woodCrusherDownForceTriggerCallback(self, triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId) |
694 | local vehicle = g_currentMission.nodeToObject[otherActorId] |
695 | if vehicle == nil and getRigidBodyType(otherActorId) == RigidBodyType.DYNAMIC then |
696 | local splitType = g_splitTypeManager:getSplitTypeByIndex(getSplitType(otherActorId)) |
697 | if splitType ~= nil and splitType.woodChipsPerLiter > 0 then |
698 | for i=1, #self.downForceNodes do |
699 | local downForceNode = self.downForceNodes[i] |
700 | if downForceNode.trigger == triggerId then |
701 | if onEnter then |
702 | downForceNode.triggerNodes[otherActorId] = Utils.getNoNil(downForceNode.triggerNodes[otherActorId], 0) + 1 |
703 | self.vehicle:raiseActive() |
704 | elseif onLeave then |
705 | local c = downForceNode.triggerNodes[otherActorId] |
706 | if c ~= nil then |
707 | c = c-1 |
708 | if c == 0 then |
709 | downForceNode.triggerNodes[otherActorId] = nil |
710 | else |
711 | downForceNode.triggerNodes[otherActorId] = c |
712 | end |
713 | end |
714 | end |
715 | end |
716 | end |
717 | end |
718 | end |
719 | end |
woodCrusherMoveTriggerCallback
DescriptionTrigger callbackDefinition
woodCrusherMoveTriggerCallback(integer triggerId, integer otherActorId, boolean onEnter, boolean onLeave, boolean onStay, integer otherShapeId)Arguments
integer | triggerId | id of trigger |
integer | otherActorId | id of other actor |
boolean | onEnter | on enter |
boolean | onLeave | on leave |
boolean | onStay | on stay |
integer | otherShapeId | id of other shape |
662 | function WoodCrusher.woodCrusherMoveTriggerCallback(self, triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId) |
663 | local vehicle = g_currentMission.nodeToObject[otherActorId] |
664 | if vehicle == nil and getRigidBodyType(otherActorId) == RigidBodyType.DYNAMIC then |
665 | local splitType = g_splitTypeManager:getSplitTypeByIndex(getSplitType(otherActorId)) |
666 | if splitType ~= nil and splitType.woodChipsPerLiter > 0 then |
667 | if onEnter then |
668 | self.moveTriggerNodes[otherActorId] = Utils.getNoNil(self.moveTriggerNodes[otherActorId],0)+1 |
669 | self.vehicle:raiseActive() |
670 | elseif onLeave then |
671 | local c = self.moveTriggerNodes[otherActorId] |
672 | if c ~= nil then |
673 | c = c-1 |
674 | if c == 0 then |
675 | self.moveTriggerNodes[otherActorId] = nil |
676 | else |
677 | self.moveTriggerNodes[otherActorId] = c |
678 | end |
679 | end |
680 | end |
681 | end |
682 | end |
683 | end |
woodCrusherSplitShapeCallback
DescriptionSplit shape callbackDefinition
woodCrusherSplitShapeCallback(integer shape, boolean isBelow, boolean isAbove, float minY, float maxY, float minZ, float maxZ)Arguments
integer | shape | shape |
boolean | isBelow | is below |
boolean | isAbove | is above |
float | minY | min y split position |
float | maxY | max y split position |
float | minZ | min z split position |
float | maxZ | max z split position |
647 | function WoodCrusher.woodCrusherSplitShapeCallback(self, shape, isBelow, isAbove, minY, maxY, minZ, maxZ) |
648 | if not isBelow then |
649 | self.crushNodes[shape] = shape |
650 | g_treePlantManager:addingSplitShape(shape, self.shapeBeingCut) |
651 | end |
652 | end |