Script v1.4.4.0
- Handtools
- Events
- Objects
- Placeables
- Triggers
- Utils
- Vehicles
- Specializations
- AIVehicle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BuiltInCutterTrailer
- BunkerSiloCompacter
- Combine
- ConveyorBelt
- Cover
- CrabSteering
- Crawler
- Cultivator
- Cutter
- Cylindered
- Drivable
- DynamicMountAttacher
- Fillable
- FillActivatable
- FillVolume
- Foldable
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- FuelTrailer
- Honk
- HookLiftContainer
- HookLiftTrailer
- Leveler
- Lights
- LivestockTrailer
- ManureBarrel
- ManureSpreader
- MixerWagon
- Motorized
- Mountable
- Mower
- NonTabbable
- Overloading
- Pickup
- Pipe
- Plough
- PowerConsumer
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- RidgeMarker
- Roller
- Ropes
- RotorSpreader
- SemiTrailerFront
- Shovel
- SowingMachine
- SpeedRotatingParts
- Sprayer
- Steerable
- StrawBlower
- StumpCutter
- Tedder
- TensionBelts
- Trailer
- TreePlanter
- TreePlanterActivatable
- TreeSaw
- TurnOnVehicle
- Washable
- WaterTrailer
- Weeder
- WheelRotations
- Windrower
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkParticles
Engine v7.0.0.2
- General
- Entity
- Node
- Scenegraph
- Lighting
- Camera
- Shape
- Particle System
- Physics
- Spline
- Animation
- Overlays
- Sound
- Input
- XML
- Network
- Callbacks
- Text Rendering
- Terrain Detail
- Tire Track
- Editor
- Rendering
- String
- Math
- I3D
- Fillplanes
Foundation Reference
StumpCutter
DescriptionThis is the specialization for stump cuttersFunctions
- prerequisitesPresent
- load
- delete
- update
- updateTick
- onDeactivate
- onDeactivateSounds
- onTurnedOn
- onTurnedOff
- crushSplitShape
- stumpCutterSplitShapeCallback
- getDirtMultiplier
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 |
load
DescriptionCalled on loadingDefinition
load(table savegame)Arguments
table | savegame | savegame |
24 | function StumpCutter:load(savegame) |
25 | self.getDirtMultiplier = Utils.overwrittenFunction(self.getDirtMultiplier, StumpCutter.getDirtMultiplier); |
26 | self.stumpCutterSplitShapeCallback = StumpCutter.stumpCutterSplitShapeCallback; |
27 | self.crushSplitShape = StumpCutter.crushSplitShape; |
28 | |
29 | self.stumpCutterCutNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.stumpCutter#cutNode")); |
30 | self.stumpCutterCutSizeY = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.stumpCutter#cutSizeY"), 1); |
31 | self.stumpCutterCutSizeZ = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.stumpCutter#cutSizeZ"), 1); |
32 | |
33 | |
34 | if self.isClient then |
35 | self.sampleStumpCutterStart = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.stumpCutterStartSound", nil, self.baseDirectory); |
36 | self.sampleStumpCutterStop = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.stumpCutterStopSound", nil, self.baseDirectory); |
37 | self.sampleStumpCutterIdle = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.stumpCutterIdleSound", nil, self.baseDirectory); |
38 | self.sampleStumpCutterWork = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.stumpCutterWorkSound", nil, self.baseDirectory); |
39 | self.maxWorkFadeTime = 300; |
40 | self.workFadeTime = 0; |
41 | |
42 | self.stumpCutterParticleSystems = {} |
43 | |
44 | local i = 0 |
45 | while true do |
46 | local key = string.format("vehicle.stumpCutter.emitterShape(%d)", i); |
47 | if not hasXMLProperty(self.xmlFile, key) then |
48 | break |
49 | end |
50 | |
51 | local emitterShape = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node")); |
52 | local particleType = getXMLString(self.xmlFile, key.."#particleType") |
53 | if emitterShape ~= nil then |
54 | local fillType = FillUtil.FILLTYPE_WOODCHIPS; |
55 | local particleSystem = MaterialUtil.getParticleSystem(fillType, particleType) |
56 | if particleSystem ~= nil then |
57 | table.insert(self.stumpCutterParticleSystems, ParticleUtil.copyParticleSystem(self.xmlFile, key, particleSystem, emitterShape)) |
58 | end |
59 | end |
60 | i = i + 1 |
61 | end |
62 | |
63 | local i = 0; |
64 | while true do |
65 | local keyPS = string.format("vehicle.stumpCutter.particleSystem(%d)", i) |
66 | if not hasXMLProperty(self.xmlFile, keyPS) then |
67 | break; |
68 | end; |
69 | local currentPS = {} |
70 | ParticleUtil.loadParticleSystem(self.xmlFile, currentPS, keyPS, self.components, false, nil, self.baseDirectory) |
71 | table.insert(self.stumpCutterParticleSystems, currentPS) |
72 | i = i + 1 |
73 | end |
74 | if #self.stumpCutterParticleSystems == 0 then |
75 | self.stumpCutterParticleSystems = nil |
76 | end |
77 | |
78 | self.stumpCutterTurnedOnRotationNodes = Utils.loadRotationNodes(self.xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "stumpCutter", self.components); |
79 | end; |
80 | |
81 | self.maxCutTime = 4000; |
82 | self.nextCutTime = self.maxCutTime; |
83 | self.maxResetCutTime = 1000; |
84 | self.resetCutTime = self.maxResetCutTime; |
85 | end |
delete
DescriptionCalled on deletingDefinition
delete()Code
89 | function StumpCutter:delete() |
90 | if self.isClient then |
91 | ParticleUtil.deleteParticleSystems(self.stumpCutterParticleSystems) |
92 | SoundUtil.deleteSample(self.sampleStumpCutterStart); |
93 | SoundUtil.deleteSample(self.sampleStumpCutterStop); |
94 | SoundUtil.deleteSample(self.sampleStumpCutterIdle); |
95 | SoundUtil.deleteSample(self.sampleStumpCutterWork); |
96 | end; |
97 | end |
update
DescriptionCalled on updateDefinition
update(float dt)Arguments
float | dt | time since last call in ms |
126 | function StumpCutter:update(dt) |
127 | if self.isClient then |
128 | Utils.updateRotationNodes(self, self.stumpCutterTurnedOnRotationNodes, dt, self:getIsActive() and self:getIsTurnedOn()); |
129 | end; |
130 | end |
updateTick
DescriptionCalled on update tickDefinition
updateTick(float dt)Arguments
float | dt | time since last call in ms |
135 | function StumpCutter:updateTick(dt) |
136 | if self:getIsActive() then |
137 | if self:getIsTurnedOn() then |
138 | if self.stumpCutterCutNode ~= nil then |
139 | self.curLenAbove = 0; |
140 | local x,y,z = getWorldTranslation(self.stumpCutterCutNode); |
141 | local nx,ny,nz = localDirectionToWorld(self.stumpCutterCutNode, 1,0,0); |
142 | local yx,yy,yz = localDirectionToWorld(self.stumpCutterCutNode, 0,1,0); |
143 | if self.curSplitShape ~= nil then |
144 | if testSplitShape(self.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.stumpCutterCutSizeY, self.stumpCutterCutSizeZ) == nil then |
145 | self.curSplitShape = nil; |
146 | end |
147 | end |
148 | if self.curSplitShape == nil then |
149 | local shape, _, _, _, _ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, self.stumpCutterCutSizeY, self.stumpCutterCutSizeZ); |
150 | if shape ~= 0 then |
151 | self.curSplitShape = shape; |
152 | end |
153 | end |
154 | if self.stumpCutterParticleSystems ~= nil then |
155 | for _, ps in pairs(self.stumpCutterParticleSystems) do |
156 | ParticleUtil.setEmittingState(ps, self.curSplitShape ~= nil); |
157 | end |
158 | end; |
159 | |
160 | if self.curSplitShape ~= nil then |
161 | self.workFadeTime = math.min(self.maxWorkFadeTime, self.workFadeTime + dt); |
162 | if self.isServer then |
163 | self.resetCutTime = self.maxResetCutTime; |
164 | if self.nextCutTime > 0 then |
165 | self.nextCutTime = self.nextCutTime - dt; |
166 | if self.nextCutTime <= 0 then |
167 | -- cut |
168 | local lenBelow, lenAbove = getSplitShapePlaneExtents(self.curSplitShape, x,y,z, nx,ny,nz); |
169 | local _,ly,_ = worldToLocal(self.curSplitShape, x,y,z); |
170 | if (lenBelow <= 0.4 or ly < 0.21) and lenAbove < 1 then -- only delete tree if lenAbove < 1 to avoid full tree deletion |
171 | -- Delete full tree: Not much left below the cut or cutting near the ground |
172 | self:crushSplitShape(self.curSplitShape); |
173 | self.curSplitShape = nil; |
174 | elseif lenAbove >= 0.2 then |
175 | -- Normal cut: Splitting 20cm below the top |
176 | self.nextCutTime = self.maxCutTime; |
177 | local curSplitShape = self.curSplitShape; |
178 | self.curSplitShape = nil; |
179 | self.curLenAbove = lenAbove; |
180 | splitShape(curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.stumpCutterCutSizeY, self.stumpCutterCutSizeZ, "stumpCutterSplitShapeCallback", self); |
181 | else |
182 | self.nextCutTime = self.maxCutTime; |
183 | end; |
184 | end; |
185 | end; |
186 | end |
187 | else |
188 | self.workFadeTime = math.max(0, self.workFadeTime - dt); |
189 | if self.isServer then |
190 | if self.resetCutTime > 0 then |
191 | self.resetCutTime = self.resetCutTime - dt; |
192 | if self.resetCutTime <= 0 then |
193 | self.nextCutTime = self.maxCutTime; |
194 | end; |
195 | end; |
196 | end |
197 | end; |
198 | end |
199 | |
200 | if self.isClient then |
201 | if self:getIsActiveForSound() then |
202 | if not SoundUtil.isSamplePlaying(self.sampleStumpCutterStart, 1.8*dt) then |
203 | SoundUtil.playSample(self.sampleStumpCutterIdle, 0, 0, nil); |
204 | SoundUtil.playSample(self.sampleStumpCutterWork, 0, 0, nil); |
205 | end |
206 | local volume = self.sampleStumpCutterWork.volume * self.workFadeTime/self.maxWorkFadeTime; |
207 | SoundUtil.setSampleVolume(self.sampleStumpCutterWork, volume); |
208 | end |
209 | end; |
210 | end |
211 | end |
212 | end |
onDeactivate
DescriptionCalled on deactivateDefinition
onDeactivate()Code
219 | function StumpCutter:onDeactivate() |
220 | if self.stumpCutterParticleSystems ~= nil then |
221 | for _, ps in pairs(self.stumpCutterParticleSystems) do |
222 | ParticleUtil.setEmittingState(ps, false); |
223 | end |
224 | end; |
225 | end |
onDeactivateSounds
DescriptionCalled on deactivating soundsDefinition
onDeactivateSounds()Code
229 | function StumpCutter:onDeactivateSounds() |
230 | if self.isClient then |
231 | SoundUtil.stopSample(self.sampleStumpCutterIdle, true); |
232 | SoundUtil.stopSample(self.sampleStumpCutterWork, true); |
233 | SoundUtil.stopSample(self.sampleStumpCutterStart, true); |
234 | SoundUtil.stopSample(self.sampleStumpCutterStop, true); |
235 | end; |
236 | end |
onTurnedOn
DescriptionCalled on turn onDefinition
onTurnedOn(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
241 | function StumpCutter:onTurnedOn(noEventSend) |
242 | if self.isClient then |
243 | StumpCutter.onDeactivateSounds(self); |
244 | if self:getIsActiveForSound() then |
245 | SoundUtil.playSample(self.sampleStumpCutterStart, 1, 0, nil); |
246 | end; |
247 | end; |
248 | end; |
onTurnedOff
DescriptionCalled on turn offDefinition
onTurnedOff(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
253 | function StumpCutter:onTurnedOff(noEventSend) |
254 | if self.isClient then |
255 | self.workFadeTime = 0; |
256 | if self.stumpCutterParticleSystems ~= nil then |
257 | for _, ps in pairs(self.stumpCutterParticleSystems) do |
258 | ParticleUtil.setEmittingState(ps, false); |
259 | end |
260 | end; |
261 | StumpCutter.onDeactivateSounds(self); |
262 | if self:getIsActiveForSound() then |
263 | SoundUtil.playSample(self.sampleStumpCutterStop, 1, 0, nil); |
264 | end; |
265 | end; |
266 | end; |
crushSplitShape
DescriptionCrush slit shapeDefinition
crushSplitShape(integer shape)Arguments
integer | shape | shape |
271 | function StumpCutter:crushSplitShape(shape) |
272 | if self.isServer then |
273 | delete(shape); |
274 | end |
275 | 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 |
286 | function StumpCutter:stumpCutterSplitShapeCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ) |
287 | if not isBelow then |
288 | if self.curLenAbove < 1 then -- split tree if lenAbove > 1 to avoid fulltree deletion |
289 | self:crushSplitShape(shape); |
290 | end; |
291 | else |
292 | local yPos = minY + (maxY-minY)/2; |
293 | local zPos = minZ + (maxZ-minZ)/2; |
294 | local _,y,_ = localToWorld(self.stumpCutterCutNode, -0.05, yPos, zPos); |
295 | local height = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, getWorldTranslation(self.stumpCutterCutNode)); |
296 | if y < height then |
297 | self:crushSplitShape(shape); |
298 | else |
299 | self.curSplitShape = shape; |
300 | end; |
301 | end |
302 | end |
getDirtMultiplier
DescriptionReturns current dirt multiplierDefinition
getDirtMultiplier()Return Values
float | dirtMultiplier | current dirt multiplier |
307 | function StumpCutter:getDirtMultiplier(superFunc) |
308 | local multiplier = 0; |
309 | if superFunc ~= nil then |
310 | multiplier = multiplier + superFunc(self); |
311 | end; |
312 | |
313 | if self.curSplitShape ~= nil then |
314 | multiplier = multiplier + self.workMultiplier; |
315 | end; |
316 | |
317 | return multiplier; |
318 | end; |