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
StumpCutter
DescriptionSpecialization for stump cutter allowing to cut/remove tree trunks/split shapesFunctions
- crushSplitShape
- getConsumingLoad
- getCultivatorLimitToField
- getDirtMultiplier
- getPlowForceLimitToField
- getPlowLimitToField
- getWearMultiplier
- initSpecialization
- onDeactivate
- onDelete
- onLoad
- onTurnedOff
- onTurnedOn
- onUpdateTick
- prerequisitesPresent
- processStumpCutterArea
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- stumpCutterSplitShapeCallback
crushSplitShape
DescriptionCrush slit shapeDefinition
crushSplitShape(integer shape)Arguments
integer | shape | shape |
352 | function StumpCutter:crushSplitShape(shape) |
353 | if self.isServer then |
354 | local x, _, z = getWorldTranslation(shape) |
355 | delete(shape) |
356 | |
357 | local range = 10 |
358 | g_densityMapHeightManager:setCollisionMapAreaDirty(x-range, z-range, x+range, z+range, true) |
359 | g_currentMission.aiSystem:setAreaDirty(x-range, x+range, z-range, z+range) |
360 | end |
361 | end |
getConsumingLoad
DescriptionDefinitiongetConsumingLoad()Code
473 | function StumpCutter:getConsumingLoad(superFunc) |
474 | local value, count = superFunc(self) |
475 | |
476 | local spec = self.spec_stumpCutter |
477 | local loadPercentage = 0 -- idle load |
478 | for i=1, #spec.cutNodes do |
479 | if spec.cutNodes[i].lastWorkTime + 500 > g_time then |
480 | loadPercentage = 1 |
481 | break |
482 | end |
483 | end |
484 | |
485 | return value+loadPercentage, count+1 |
486 | end |
getCultivatorLimitToField
DescriptionReturns if cultivator is limited to the fieldDefinition
getCultivatorLimitToField()Return Values
boolean | isLimited | is limited to field |
453 | function StumpCutter:getCultivatorLimitToField(superFunc) |
454 | return false |
455 | end |
getDirtMultiplier
DescriptionReturns current dirt multiplierDefinition
getDirtMultiplier()Return Values
float | dirtMultiplier | current dirt multiplier |
425 | function StumpCutter:getDirtMultiplier(superFunc) |
426 | local multiplier = superFunc(self) |
427 | |
428 | local spec = self.spec_stumpCutter |
429 | if spec.curSplitShape ~= nil then |
430 | multiplier = multiplier + self:getWorkDirtMultiplier() |
431 | end |
432 | |
433 | return multiplier |
434 | end |
getPlowForceLimitToField
DescriptionReturns if plow limit to field is forced and not changeableDefinition
getPlowForceLimitToField()Return Values
boolean | isForced | is forced |
467 | function StumpCutter:getPlowForceLimitToField() |
468 | return true |
469 | end |
getPlowLimitToField
DescriptionReturns if plow is limited to the fieldDefinition
getPlowLimitToField()Return Values
boolean | isLimited | is limited to field |
460 | function StumpCutter:getPlowLimitToField() |
461 | return false |
462 | end |
getWearMultiplier
DescriptionReturns current wear multiplierDefinition
getWearMultiplier()Return Values
float | wearMultiplier | current wear multiplier |
439 | function StumpCutter:getWearMultiplier(superFunc) |
440 | local multiplier = superFunc(self) |
441 | |
442 | local spec = self.spec_stumpCutter |
443 | if spec.curSplitShape ~= nil then |
444 | multiplier = multiplier + self:getWorkWearMultiplier() |
445 | end |
446 | |
447 | return multiplier |
448 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
23 | function StumpCutter.initSpecialization() |
24 | g_workAreaTypeManager:addWorkAreaType("stumpCutter", true) |
25 | |
26 | local schema = Vehicle.xmlSchema |
27 | schema:setXMLSpecializationType("StumpCutter") |
28 | |
29 | schema:register(XMLValueType.NODE_INDEX, "vehicle.stumpCutter.cutNode(?)#node", "Cut node") |
30 | |
31 | schema:register(XMLValueType.FLOAT, "vehicle.stumpCutter.cutNode(?)#cutSizeY", "Cut size Y", 1) |
32 | schema:register(XMLValueType.FLOAT, "vehicle.stumpCutter.cutNode(?)#cutSizeZ", "Cut size X", 1) |
33 | |
34 | schema:register(XMLValueType.TIME, "vehicle.stumpCutter.cutNode(?)#maxCutTime", "Time until cut", 4) |
35 | schema:register(XMLValueType.TIME, "vehicle.stumpCutter.cutNode(?)#maxResetCutTime", "Time between cuts", 4) |
36 | |
37 | schema:register(XMLValueType.FLOAT, "vehicle.stumpCutter.cutNode(?)#cutFullTreeThreshold", "Cut fill tree threshold", 0.4) |
38 | schema:register(XMLValueType.FLOAT, "vehicle.stumpCutter.cutNode(?)#cutPartThreshold", "Cut part threshold", 0.2) |
39 | |
40 | schema:register(XMLValueType.INT, "vehicle.stumpCutter.cutNode(?)#workAreaIndex", "Work area index") |
41 | schema:register(XMLValueType.TIME, "vehicle.stumpCutter.cutNode(?)#cutDuration", "Cut duration", 1) |
42 | |
43 | EffectManager.registerEffectXMLPaths(schema, "vehicle.stumpCutter.cutNode(?).effects") |
44 | |
45 | SoundManager.registerSampleXMLPaths(schema, "vehicle.stumpCutter.sounds", "start") |
46 | SoundManager.registerSampleXMLPaths(schema, "vehicle.stumpCutter.sounds", "stop") |
47 | SoundManager.registerSampleXMLPaths(schema, "vehicle.stumpCutter.sounds", "idle") |
48 | SoundManager.registerSampleXMLPaths(schema, "vehicle.stumpCutter.sounds", "work") |
49 | |
50 | EffectManager.registerEffectXMLPaths(schema, "vehicle.stumpCutter.effects") |
51 | AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.stumpCutter.animationNodes") |
52 | |
53 | schema:setXMLSpecializationType() |
54 | end |
onDeactivate
DescriptionCalled on deactivateDefinition
onDeactivate()Code
308 | function StumpCutter:onDeactivate() |
309 | if self.isClient then |
310 | local spec = self.spec_stumpCutter |
311 | g_effectManager:stopEffects(spec.effects) |
312 | for i=1, #spec.cutNodes do |
313 | g_effectManager:stopEffects(spec.cutNodes[i].effects) |
314 | end |
315 | end |
316 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
168 | function StumpCutter:onDelete() |
169 | local spec = self.spec_stumpCutter |
170 | g_soundManager:deleteSamples(spec.samples) |
171 | g_animationManager:deleteAnimations(spec.animationNodes) |
172 | g_effectManager:deleteEffects(spec.effects) |
173 | |
174 | if spec.cutNodes ~= nil then |
175 | for i=1, #spec.cutNodes do |
176 | g_effectManager:deleteEffects(spec.cutNodes[i].effects) |
177 | end |
178 | end |
179 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
89 | function StumpCutter:onLoad(savegame) |
90 | local spec = self.spec_stumpCutter |
91 | |
92 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "vehicle.stumpCutter.animationNodes.animationNode", "stumbCutter") --FS17 to FS19 |
93 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutterStartSound", "vehicle.stumpCutter.sounds.start") --FS17 to FS19 |
94 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutterIdleSound", "vehicle.stumpCutter.sounds.idle") --FS17 to FS19 |
95 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutterWorkSound", "vehicle.stumpCutter.sounds.work") --FS17 to FS19 |
96 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutterStopSound", "vehicle.stumpCutter.sounds.stop") --FS17 to FS19 |
97 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter.emitterShape(0)", "vehicle.stumpCutter.effects.effectNode") --FS17 to FS19 |
98 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter.particleSystem(0)", "vehicle.stumpCutter.effects.effectNode") --FS17 to FS19 |
99 | |
100 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter#cutNode", "vehicle.stumpCutter.cutNode#node") --FS19 to FS22 |
101 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter#cutSizeY", "vehicle.stumpCutter.cutNode#cutSizeY") --FS19 to FS22 |
102 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter#cutSizeZ", "vehicle.stumpCutter.cutNode#cutSizeZ") --FS19 to FS22 |
103 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter#cutFullTreeThreshold", "vehicle.stumpCutter.cutNode#cutFullTreeThreshold") --FS19 to FS22 |
104 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.stumpCutter#cutPartThreshold", "vehicle.stumpCutter.cutNode#cutPartThreshold") --FS19 to FS22 |
105 | |
106 | local baseKey = "vehicle.stumpCutter" |
107 | |
108 | spec.cutNodes = {} |
109 | spec.currentCutNodeIndex = 1 |
110 | |
111 | local i = 0 |
112 | while true do |
113 | local key = string.format("%s.cutNode(%d)", baseKey, i) |
114 | if not self.xmlFile:hasProperty(key) then |
115 | break |
116 | end |
117 | |
118 | local node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
119 | if node == nil then |
120 | Logging.xmlWarning(self.xmlFile, "Missing 'node' for '%s'!", key) |
121 | break |
122 | end |
123 | |
124 | local cutNode = {} |
125 | cutNode.node = node |
126 | cutNode.cutSizeY = self.xmlFile:getValue(key .. "#cutSizeY", 1) |
127 | cutNode.cutSizeZ = self.xmlFile:getValue(key .. "#cutSizeZ", 1) |
128 | cutNode.maxCutTime = self.xmlFile:getValue(key .. "#maxCutTime", 4) |
129 | cutNode.nextCutTime = cutNode.maxCutTime |
130 | cutNode.maxResetCutTime = self.xmlFile:getValue(key .. "#maxResetCutTime", 1) |
131 | cutNode.resetCutTime = cutNode.maxResetCutTime |
132 | cutNode.cutFullTreeThreshold = self.xmlFile:getValue(key .. "#cutFullTreeThreshold", 0.4) |
133 | cutNode.cutPartThreshold = self.xmlFile:getValue(key .. "#cutPartThreshold", 0.2) |
134 | cutNode.workAreaIndex = self.xmlFile:getValue(key.."#workAreaIndex") |
135 | cutNode.workTimer = 0 |
136 | cutNode.workDuration = self.xmlFile:getValue(key .. "#cutDuration", 1) |
137 | |
138 | cutNode.lastWorkTime = -1000 |
139 | |
140 | cutNode.workFadeTime = 0 |
141 | cutNode.maxWorkFadeTime = 1000 |
142 | |
143 | if self.isClient then |
144 | cutNode.effects = g_effectManager:loadEffect(self.xmlFile, key..".effects", self.components, self, self.i3dMappings) |
145 | end |
146 | |
147 | table.insert(spec.cutNodes, cutNode) |
148 | i = i + 1 |
149 | end |
150 | |
151 | if self.isClient then |
152 | spec.samples = {} |
153 | spec.samples.start = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey .. ".sounds", "start", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
154 | spec.samples.stop = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey .. ".sounds", "stop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
155 | spec.samples.idle = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey .. ".sounds", "idle", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
156 | spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey .. ".sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
157 | |
158 | spec.maxWorkFadeTime = 1000 |
159 | spec.workFadeTime = 0 |
160 | |
161 | spec.effects = g_effectManager:loadEffect(self.xmlFile, baseKey..".effects", self.components, self, self.i3dMappings) |
162 | spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, baseKey .. ".animationNodes", self.components, self, self.i3dMappings) |
163 | end |
164 | end |
onTurnedOff
DescriptionCalled on turn offDefinition
onTurnedOff(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
334 | function StumpCutter:onTurnedOff() |
335 | if self.isClient then |
336 | local spec = self.spec_stumpCutter |
337 | spec.workFadeTime = 0 |
338 | g_effectManager:stopEffects(spec.effects) |
339 | for i=1, #spec.cutNodes do |
340 | g_effectManager:stopEffects(spec.cutNodes[i].effects) |
341 | end |
342 | |
343 | g_soundManager:stopSamples(spec.samples) |
344 | g_soundManager:playSample(spec.samples.stop) |
345 | g_animationManager:stopAnimations(spec.animationNodes) |
346 | end |
347 | end |
onTurnedOn
DescriptionCalled on turn onDefinition
onTurnedOn(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
321 | function StumpCutter:onTurnedOn() |
322 | if self.isClient then |
323 | local spec = self.spec_stumpCutter |
324 | g_soundManager:stopSamples(spec.samples) |
325 | g_soundManager:playSample(spec.samples.start) |
326 | g_soundManager:playSample(spec.samples.idle, 0, spec.samples.start) |
327 | g_animationManager:startAnimations(spec.animationNodes) |
328 | end |
329 | 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 |
186 | function StumpCutter:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
187 | if self:getIsTurnedOn() then |
188 | local spec = self.spec_stumpCutter |
189 | |
190 | local numCutNodes = #spec.cutNodes |
191 | if numCutNodes > 0 then |
192 | local nextCutNodeIndex = spec.currentCutNodeIndex + 1 |
193 | if nextCutNodeIndex > numCutNodes then |
194 | nextCutNodeIndex = 1 |
195 | end |
196 | |
197 | spec.currentCutNodeIndex = nextCutNodeIndex |
198 | local cutNode = spec.cutNodes[nextCutNodeIndex] |
199 | |
200 | cutNode.curLenAbove = 0 |
201 | cutNode.curLenBelow = 0 |
202 | |
203 | local x,y,z = getWorldTranslation(cutNode.node) |
204 | local nx,ny,nz = localDirectionToWorld(cutNode.node, 1,0,0) |
205 | local yx,yy,yz = localDirectionToWorld(cutNode.node, 0,1,0) |
206 | if cutNode.curSplitShape ~= nil then |
207 | if testSplitShape(cutNode.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, cutNode.cutSizeY, cutNode.cutSizeZ) == nil then |
208 | cutNode.curSplitShape = nil |
209 | end |
210 | end |
211 | if cutNode.curSplitShape == nil then |
212 | local shape, _, _, _, _ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, cutNode.cutSizeY, cutNode.cutSizeZ) |
213 | if shape ~= 0 then |
214 | cutNode.curSplitShape = shape |
215 | end |
216 | end |
217 | |
218 | if VehicleDebug.state == VehicleDebug.DEBUG_ATTRIBUTES then |
219 | local x1, y1, z1 = localToWorld(cutNode.node, 0, 0, cutNode.cutSizeZ) |
220 | local x2, y2, z2 = localToWorld(cutNode.node, 0, cutNode.cutSizeY, 0) |
221 | DebugUtil.drawDebugAreaRectangle(x, y, z, x1, y1, z1, x2, y2, z2, false, 0.5924, 0.1871, 0.3723) |
222 | end |
223 | |
224 | if cutNode.curSplitShape ~= nil then |
225 | local lenBelow, lenAbove = getSplitShapePlaneExtents(cutNode.curSplitShape, x,y,z, nx,ny,nz) |
226 | |
227 | if lenAbove >= cutNode.cutPartThreshold then |
228 | cutNode.lastWorkTime = g_time |
229 | end |
230 | |
231 | cutNode.workFadeTime = math.min(cutNode.maxWorkFadeTime, cutNode.workFadeTime + dt * numCutNodes) |
232 | if self.isServer then |
233 | cutNode.resetCutTime = cutNode.maxResetCutTime |
234 | if cutNode.nextCutTime > 0 then |
235 | cutNode.nextCutTime = cutNode.nextCutTime - dt |
236 | if cutNode.nextCutTime <= 0 then |
237 | -- cut |
238 | local _,ly,_ = worldToLocal(cutNode.curSplitShape, x,y,z) |
239 | if (lenBelow <= cutNode.cutFullTreeThreshold or ly < cutNode.cutPartThreshold+0.01) and lenAbove < 1 then -- only delete tree if lenAbove < 1 to avoid full tree deletion |
240 | -- Delete full tree: Not much left below the cut or cutting near the ground |
241 | self:crushSplitShape(cutNode.curSplitShape) |
242 | cutNode.curSplitShape = nil |
243 | elseif lenAbove >= cutNode.cutPartThreshold then |
244 | -- Normal cut: Splitting 20cm below the top |
245 | cutNode.nextCutTime = cutNode.maxCutTime |
246 | local curSplitShape = cutNode.curSplitShape |
247 | cutNode.curSplitShape = nil |
248 | cutNode.curLenAbove = lenAbove |
249 | cutNode.curLenBelow = lenBelow |
250 | |
251 | self.shapeBeingCut = curSplitShape |
252 | splitShape(curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, cutNode.cutSizeY, cutNode.cutSizeZ, "stumpCutterSplitShapeCallback", self) |
253 | g_treePlantManager:removingSplitShape(curSplitShape) |
254 | else |
255 | cutNode.curSplitShape = nil |
256 | cutNode.nextCutTime = cutNode.maxCutTime |
257 | end |
258 | end |
259 | end |
260 | end |
261 | else |
262 | cutNode.workFadeTime = math.max(0, cutNode.workFadeTime - dt) |
263 | if self.isServer then |
264 | if cutNode.resetCutTime > 0 then |
265 | cutNode.resetCutTime = cutNode.resetCutTime - dt |
266 | if cutNode.resetCutTime <= 0 then |
267 | cutNode.nextCutTime = cutNode.maxCutTime |
268 | end |
269 | end |
270 | end |
271 | end |
272 | |
273 | if self.isClient then |
274 | if cutNode.lastWorkTime + 500 > g_time then |
275 | g_effectManager:setFillType(cutNode.effects, FillType.WOODCHIPS) |
276 | g_effectManager:startEffects(cutNode.effects) |
277 | else |
278 | g_effectManager:stopEffects(cutNode.effects) |
279 | end |
280 | |
281 | local anyCutNodeWorking = false |
282 | for i=1, #spec.cutNodes do |
283 | if spec.cutNodes[i].lastWorkTime + 500 > g_time then |
284 | anyCutNodeWorking = true |
285 | break |
286 | end |
287 | end |
288 | |
289 | if anyCutNodeWorking then |
290 | g_effectManager:setFillType(spec.effects, FillType.WOODCHIPS) |
291 | g_effectManager:startEffects(spec.effects) |
292 | if not g_soundManager:getIsSamplePlaying(spec.samples.work) then |
293 | g_soundManager:playSample(spec.samples.work) |
294 | end |
295 | else |
296 | g_effectManager:stopEffects(spec.effects) |
297 | if g_soundManager:getIsSamplePlaying(spec.samples.work) then |
298 | g_soundManager:stopSample(spec.samples.work) |
299 | end |
300 | end |
301 | end |
302 | end |
303 | end |
304 | 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 |
17 | function StumpCutter.prerequisitesPresent(specializations) |
18 | return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations) |
19 | end |
processStumpCutterArea
DescriptionDefinitionprocessStumpCutterArea()Code
399 | function StumpCutter:processStumpCutterArea(workArea, dt) |
400 | local spec = self.spec_stumpCutter |
401 | |
402 | local area, totalArea = 0, 0 |
403 | for _, cutNode in ipairs(spec.cutNodes) do |
404 | if cutNode.workAreaIndex == workArea.index then |
405 | local xs,_,zs = getWorldTranslation(workArea.start) |
406 | local xw,_,zw = getWorldTranslation(workArea.width) |
407 | local xh,_,zh = getWorldTranslation(workArea.height) |
408 | |
409 | local _area, _totalArea, nonMowableCut = FSDensityMapUtil.clearDecoArea(xs, zs, xw, zw, xh, zh) |
410 | if _area > 0 and nonMowableCut then |
411 | cutNode.lastWorkTime = g_time |
412 | end |
413 | |
414 | area = area + _area |
415 | totalArea = totalArea + _totalArea |
416 | end |
417 | end |
418 | |
419 | return area, totalArea |
420 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
77 | function StumpCutter.registerEventListeners(vehicleType) |
78 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", StumpCutter) |
79 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", StumpCutter) |
80 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", StumpCutter) |
81 | SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", StumpCutter) |
82 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", StumpCutter) |
83 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", StumpCutter) |
84 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
58 | function StumpCutter.registerFunctions(vehicleType) |
59 | SpecializationUtil.registerFunction(vehicleType, "crushSplitShape", StumpCutter.crushSplitShape) |
60 | SpecializationUtil.registerFunction(vehicleType, "stumpCutterSplitShapeCallback", StumpCutter.stumpCutterSplitShapeCallback) |
61 | SpecializationUtil.registerFunction(vehicleType, "processStumpCutterArea", StumpCutter.processStumpCutterArea) |
62 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
66 | function StumpCutter.registerOverwrittenFunctions(vehicleType) |
67 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", StumpCutter.getDirtMultiplier) |
68 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", StumpCutter.getWearMultiplier) |
69 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCultivatorLimitToField", StumpCutter.getCultivatorLimitToField) |
70 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getPlowLimitToField", StumpCutter.getPlowLimitToField) |
71 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getPlowForceLimitToField", StumpCutter.getPlowForceLimitToField) |
72 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getConsumingLoad", StumpCutter.getConsumingLoad) |
73 | end |
stumpCutterSplitShapeCallback
DescriptionSplit shape callbackDefinition
stumpCutterSplitShapeCallback(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 |
372 | function StumpCutter:stumpCutterSplitShapeCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ) |
373 | local spec = self.spec_stumpCutter |
374 | local cutNode = spec.cutNodes[spec.currentCutNodeIndex] |
375 | |
376 | if not isBelow then |
377 | if cutNode.curLenAbove < 1 then -- split tree if lenAbove > 1 to avoid fulltree deletion |
378 | self:crushSplitShape(shape) |
379 | else |
380 | g_treePlantManager:addingSplitShape(shape, self.shapeBeingCut) |
381 | end |
382 | else |
383 | local yPos = minY + (maxY-minY)/2 |
384 | local zPos = minZ + (maxZ-minZ)/2 |
385 | |
386 | local _,y,_ = localToWorld(cutNode.node, -0.05, yPos, zPos) |
387 | local height = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, getWorldTranslation(cutNode.node)) |
388 | if y < height then |
389 | self:crushSplitShape(shape) |
390 | else |
391 | spec.curSplitShape = shape |
392 | g_treePlantManager:addingSplitShape(shape, self.shapeBeingCut) |
393 | end |
394 | end |
395 | end |