Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1 | -- |
2 | -- WoodCrusher |
3 | -- This is the specialization for wood crushers |
4 | -- |
5 | -- @author Stefan Geiger |
6 | -- @date 22/09/14 |
7 | -- |
8 | -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved. |
9 | |
10 | WoodCrusher = {}; |
11 | |
12 | function WoodCrusher.prerequisitesPresent(specializations) |
13 | return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations) and SpecializationUtil.hasSpecialization(Fillable, specializations); |
14 | end |
15 | |
16 | function WoodCrusher:load(xmlFile) |
17 | self.getDirtMultiplier = Utils.overwrittenFunction(self.getDirtMultiplier, WoodCrusher.getDirtMultiplier); |
18 | self.woodCrusherSplitShapeCallback = WoodCrusher.woodCrusherSplitShapeCallback; |
19 | self.woodCrusherMoveTriggerCallback = WoodCrusher.woodCrusherMoveTriggerCallback; |
20 | self.crushSplitShape = WoodCrusher.crushSplitShape; |
21 | |
22 | self.woodCrusherCutNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.woodCrusher#cutNode")); |
23 | self.woodCrusherMainDrumRefNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.woodCrusher#mainDrumRefNode")); |
24 | self.woodCrusherMoveTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.woodCrusher#moveTrigger")); |
25 | self.woodCrusherMoveColNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.woodCrusher#moveCol")); |
26 | local moveColDisableCollisionPairs = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.woodCrusher#moveColDisableCollisionPairs"), true); |
27 | self.woodCrusherMoveVelocityZ = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.woodCrusher#moveVelocityZ"), 0.8); -- m/s |
28 | self.woodCrusherMoveMaxForce = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.woodCrusher#moveMaxForce"), 7); -- input is kN |
29 | self.woodCrusherDownForceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.woodCrusher#downForceNode")); |
30 | self.woodCrusherDownForce = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.woodCrusher#downForce"), 2); |
31 | self.woodCrusherCutSizeY = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.woodCrusher#cutSizeY"), 1); |
32 | self.woodCrusherCutSizeZ = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.woodCrusher#cutSizeZ"), 1); |
33 | |
34 | if self.woodCrusherMoveColNode ~= nil and moveColDisableCollisionPairs then |
35 | for _, component in pairs(self.components) do |
36 | setPairCollision(component.node, self.woodCrusherMoveColNode, false); |
37 | end |
38 | end |
39 | |
40 | self.woodCrusherMoveTriggerNodes = {}; |
41 | if self.isServer and self.woodCrusherMoveTrigger ~= nil then |
42 | addTrigger(self.woodCrusherMoveTrigger, "woodCrusherMoveTriggerCallback", self); |
43 | end |
44 | |
45 | self.woodCrusherCrushNodes = {}; |
46 | |
47 | if self.isClient then |
48 | self.woodCrusherParticleSystems = {}; |
49 | |
50 | local i=0; |
51 | while true do |
52 | local key = string.format("vehicle.woodCrusher.particleSystem(%d)", i); |
53 | if not hasXMLProperty(xmlFile, key) then |
54 | break; |
55 | end |
56 | Utils.loadParticleSystem(xmlFile, self.woodCrusherParticleSystems, key, self.components, false, nil, self.baseDirectory); |
57 | i = i+1; |
58 | end; |
59 | |
60 | self.woodCrusherTurnedOnRotationNode = Utils.loadRotationNodes(xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "woodCrusher", self.components); |
61 | self.woodCrusherTurnedOnScrollers = Utils.loadScrollers(self.components, xmlFile, "vehicle.turnedOnScrollers.turnedOnScroller", {}, false); |
62 | |
63 | self.sampleWoodCrusherStart = Utils.loadSample(xmlFile, {}, "vehicle.woodCrusherStartSound", nil, self.baseDirectory); |
64 | self.sampleWoodCrusherStop = Utils.loadSample(xmlFile, {}, "vehicle.woodCrusherStopSound", nil, self.baseDirectory); |
65 | self.sampleWoodCrusherIdle = Utils.loadSample(xmlFile, {}, "vehicle.woodCrusherIdleSound", nil, self.baseDirectory); |
66 | self.sampleWoodCrusherWork = Utils.loadSample(xmlFile, {}, "vehicle.woodCrusherWorkSound", nil, self.baseDirectory); |
67 | |
68 | self.maxWorkFadeTime = 300; |
69 | self.workFadeTime = 0; |
70 | end; |
71 | |
72 | self.crushingTime = 0; |
73 | |
74 | self.woodCrusherDirtyFlag = self:getNextDirtyFlag(); |
75 | end |
76 | |
77 | function WoodCrusher:delete() |
78 | if self.isClient then |
79 | if self.woodCrusherParticleSystems ~= nil then |
80 | Utils.deleteParticleSystem(self.woodCrusherParticleSystems); |
81 | end; |
82 | Utils.deleteSample(self.sampleWoodCrusherStart); |
83 | Utils.deleteSample(self.sampleWoodCrusherStop); |
84 | Utils.deleteSample(self.sampleWoodCrusherIdle); |
85 | Utils.deleteSample(self.sampleWoodCrusherWork); |
86 | end; |
87 | if self.isServer and self.woodCrusherMoveTrigger ~= nil then |
88 | removeTrigger(self.woodCrusherMoveTrigger); |
89 | end; |
90 | end |
91 | |
92 | function WoodCrusher:readStream(streamId, connection) |
93 | end |
94 | |
95 | function WoodCrusher:writeStream(streamId, connection) |
96 | end |
97 | |
98 | function WoodCrusher:readUpdateStream(streamId, timestamp, connection) |
99 | if connection:getIsServer() then |
100 | if streamReadBool(streamId) then |
101 | self.crushingTime = 1000; |
102 | else |
103 | self.crushingTime = 0; |
104 | end |
105 | end |
106 | end |
107 | |
108 | function WoodCrusher:writeUpdateStream(streamId, connection, dirtyMask) |
109 | if not connection:getIsServer() then |
110 | streamWriteBool(streamId, self.crushingTime > 0); |
111 | end |
112 | end |
113 | |
114 | function WoodCrusher:loadFromAttributesAndNodes(xmlFile, key, resetVehicles) |
115 | return BaseMission.VEHICLE_LOAD_OK; |
116 | end; |
117 | |
118 | function WoodCrusher:getSaveAttributesAndNodes(nodeIdent) |
119 | local attributes = ''; |
120 | local nodes = ""; |
121 | return attributes, nodes; |
122 | end; |
123 | |
124 | function WoodCrusher:mouseEvent(posX, posY, isDown, isUp, button) |
125 | end |
126 | |
127 | function WoodCrusher:keyEvent(unicode, sym, modifier, isDown) |
128 | end |
129 | |
130 | function WoodCrusher:update(dt) |
131 | if self:getIsActive() then |
132 | if self:getIsTurnedOn() then |
133 | if self.isServer then |
134 | for node in pairs(self.woodCrusherCrushNodes) do |
135 | self:crushSplitShape(node); |
136 | self.woodCrusherCrushNodes[node] = nil; |
137 | self.woodCrusherMoveTriggerNodes[node] = nil; |
138 | end |
139 | |
140 | local x,y,z = getTranslation(self.woodCrusherMainDrumRefNode); |
141 | local tx = 0; |
142 | local ty = 0; |
143 | local tz = 0; |
144 | local maxTreeSizeY = 0; |
145 | for id in pairs(self.woodCrusherMoveTriggerNodes) do |
146 | if not entityExists(id) then |
147 | self.woodCrusherMoveTriggerNodes[id] = nil; |
148 | else |
149 | if self.woodCrusherMoveColNode == nil then |
150 | local vx,vy,vz = getLinearVelocity(id); |
151 | local _,_,lvz = worldDirectionToLocal(self.woodCrusherMoveTrigger, vx,vy,vz); |
152 | if lvz < self.woodCrusherMoveVelocityZ then |
153 | local dvz = math.min(self.woodCrusherMoveVelocityZ - lvz, self.woodCrusherMoveMaxForce*dt*0.001/getMass(id)); |
154 | local dvx,dvy,dvz = localDirectionToWorld(self.woodCrusherMoveTrigger, 0,0,dvz); |
155 | setLinearVelocity(id, vx+dvx, vy+dvy, vz+dvz); |
156 | end |
157 | end |
158 | if self.woodCrusherDownForceNode ~= nil then |
159 | local x,y,z = getWorldTranslation(self.woodCrusherDownForceNode); |
160 | local nx,ny,nz = localDirectionToWorld(self.woodCrusherDownForceNode, 1,0,0); |
161 | local yx,yy,yz = localDirectionToWorld(self.woodCrusherDownForceNode, 0,1,0); |
162 | |
163 | local minY,maxY, minZ,maxZ = testSplitShape(id, x,y,z, nx,ny,nz, yx,yy,yz, self.woodCrusherCutSizeY, self.woodCrusherCutSizeZ); |
164 | if minY ~= nil then |
165 | local cx,cy,cz = localToWorld(self.woodCrusherDownForceNode, 0, (minY+maxY)*0.5, (minZ+maxZ)*0.5); |
166 | local downX,downY,downZ = localDirectionToWorld(self.woodCrusherDownForceNode, 0,-self.woodCrusherDownForce,0); |
167 | addForce(id, downX, downY, downZ, cx,cy,cz, false); |
168 | |
169 | if self.woodCrusherMainDrumRefNode ~= nil then |
170 | maxTreeSizeY = math.max(maxTreeSizeY, maxY); |
171 | end; |
172 | end |
173 | end |
174 | end |
175 | end |
176 | if self.woodCrusherMainDrumRefNode ~= nil then |
177 | if maxTreeSizeY > 0 then |
178 | local a,b,c = localToWorld(self.woodCrusherDownForceNode, 0, maxTreeSizeY, 0); |
179 | _, ty, _ = worldToLocal(getParent(self.woodCrusherMainDrumRefNode), a,b,c); |
180 | end; |
181 | if ty > y then |
182 | y = math.min(y + 0.0003*dt, ty); |
183 | else |
184 | y = math.max(y - 0.0003*dt, ty); |
185 | end; |
186 | setTranslation(self.woodCrusherMainDrumRefNode, x,y,z); |
187 | end; |
188 | end |
189 | end |
190 | end |
191 | |
192 | if self.isClient then |
193 | Utils.updateRotationNodes(self, self.woodCrusherTurnedOnRotationNode, dt, self:getIsActive() and self:getIsTurnedOn()); |
194 | Utils.updateScrollers(self.woodCrusherTurnedOnScrollers, dt, self:getIsActive() and self:getIsTurnedOn()); |
195 | end; |
196 | end |
197 | |
198 | function WoodCrusher:updateTick(dt) |
199 | if self:getIsActive() then |
200 | if self:getIsTurnedOn() then |
201 | if self:getCapacity() <= 0 then |
202 | self.lastLostFillLevel = self.fillLevel; |
203 | if self.fillLevel > 0 then |
204 | self:setFillLevel(0, Fillable.FILLTYPE_WOODCHIPS); |
205 | end |
206 | end |
207 | |
208 | if self.crushingTime > 0 then |
209 | self.crushingTime = self.crushingTime - dt; |
210 | if self.crushingTime <= 0 then |
211 | self:raiseDirtyFlags(self.woodCrusherDirtyFlag); |
212 | end |
213 | self.workFadeTime = math.min(self.maxWorkFadeTime, self.workFadeTime + dt); |
214 | else |
215 | self.workFadeTime = math.max(0, self.workFadeTime - dt); |
216 | end; |
217 | if self.isClient and self.woodCrusherParticleSystems ~= nil then |
218 | Utils.setEmittingState(self.woodCrusherParticleSystems, self.crushingTime > 0); |
219 | end; |
220 | |
221 | if self.isServer then |
222 | if self.woodCrusherCutNode ~= nil and next(self.woodCrusherMoveTriggerNodes) ~= nil then |
223 | local x,y,z = getWorldTranslation(self.woodCrusherCutNode); |
224 | local nx,ny,nz = localDirectionToWorld(self.woodCrusherCutNode, 1,0,0); |
225 | local yx,yy,yz = localDirectionToWorld(self.woodCrusherCutNode, 0,1,0); |
226 | for id in pairs(self.woodCrusherMoveTriggerNodes) do |
227 | local lenBelow, lenAbove = getSplitShapePlaneExtents(id, x,y,z, nx,ny,nz); |
228 | if lenAbove ~= nil and lenBelow ~= nil then |
229 | if lenBelow <= 0.4 then |
230 | self.woodCrusherMoveTriggerNodes[id] = nil; |
231 | self:crushSplitShape(id); |
232 | elseif lenAbove >= 0.2 then |
233 | local minY = splitShape(id, x,y,z, nx,ny,nz, yx,yy,yz, self.woodCrusherCutSizeY, self.woodCrusherCutSizeZ, "woodCrusherSplitShapeCallback", self); |
234 | if minY ~= nil then |
235 | self.woodCrusherMoveTriggerNodes[id] = nil; |
236 | end |
237 | end |
238 | end; |
239 | end |
240 | end |
241 | end |
242 | |
243 | if self.isClient then |
244 | if self:getIsActiveForSound() then |
245 | if not Utils.isSamplePlaying(self.sampleWoodCrusherStart, 1.8*dt) then |
246 | Utils.playSample(self.sampleWoodCrusherIdle, 0, 0, nil); |
247 | Utils.playSample(self.sampleWoodCrusherWork, 0, 0, nil); |
248 | end |
249 | local volume = self.sampleWoodCrusherWork.volume * self.workFadeTime/self.maxWorkFadeTime; |
250 | Utils.setSampleVolume(self.sampleWoodCrusherWork, volume); |
251 | end |
252 | end; |
253 | end |
254 | end |
255 | end |
256 | |
257 | function WoodCrusher:draw() |
258 | end |
259 | |
260 | function WoodCrusher:onDeactivate() |
261 | WoodCrusher.onDeactivateSounds(self); |
262 | if self.isClient then |
263 | if self.woodCrusherParticleSystems ~= nil then |
264 | Utils.setEmittingState(self.woodCrusherParticleSystems, false); |
265 | end; |
266 | end; |
267 | end |
268 | |
269 | function WoodCrusher:onDeactivateSounds() |
270 | if self.isClient then |
271 | Utils.stopSample(self.sampleWoodCrusherIdle, true); |
272 | Utils.stopSample(self.sampleWoodCrusherWork, true); |
273 | Utils.stopSample(self.sampleWoodCrusherStart, true); |
274 | end; |
275 | end |
276 | |
277 | function WoodCrusher:onTurnedOn(noEventSend) |
278 | if self.isClient then |
279 | WoodCrusher.onDeactivateSounds(self); |
280 | Utils.stopSample(self.sampleWoodCrusherStop, true); |
281 | if self:getIsActiveForSound() then |
282 | Utils.playSample(self.sampleWoodCrusherStart, 1, 0, nil); |
283 | end; |
284 | if self.woodCrusherMoveColNode ~= nil then |
285 | setFrictionVelocity(self.woodCrusherMoveColNode, self.woodCrusherMoveVelocityZ); |
286 | end |
287 | end; |
288 | end; |
289 | |
290 | function WoodCrusher:onTurnedOff(noEventSend) |
291 | if self.isServer then |
292 | for node in pairs(self.woodCrusherCrushNodes) do |
293 | self:crushSplitShape(node); |
294 | self.woodCrusherCrushNodes[node] = nil; |
295 | end |
296 | if self.woodCrusherMoveColNode ~= nil then |
297 | setFrictionVelocity(self.woodCrusherMoveColNode, 0.0); |
298 | end |
299 | end |
300 | if self.isClient then |
301 | self.workFadeTime = 0; |
302 | if self.woodCrusherParticleSystems ~= nil then |
303 | Utils.setEmittingState(self.woodCrusherParticleSystems, false); |
304 | end; |
305 | WoodCrusher.onDeactivateSounds(self); |
306 | if self:getIsActiveForSound() then |
307 | Utils.playSample(self.sampleWoodCrusherStop, 1, 0, nil); |
308 | end; |
309 | end; |
310 | end |
311 | |
312 | function WoodCrusher:crushSplitShape(shape) |
313 | local splitType = SplitUtil.splitTypes[getSplitType(shape)]; |
314 | if splitType ~= nil and splitType.woodChipsPerLiter > 0 then |
315 | local volume = getVolume(shape); |
316 | self.crushingTime = 1000; |
317 | self:raiseDirtyFlags(self.woodCrusherDirtyFlag); |
318 | delete(shape); |
319 | |
320 | local newFillLevel = self.fillLevel+volume*1000*splitType.woodChipsPerLiter; |
321 | |
322 | local x,y,z = getWorldTranslation(self.fillVolumeLoadInfo.node); |
323 | local d1x,d1y,d1z = localDirectionToWorld(self.fillVolumeLoadInfo.node, self.fillVolumeLoadInfo.width,0,0); |
324 | local d2x,d2y,d2z = localDirectionToWorld(self.fillVolumeLoadInfo.node, 0,0,self.fillVolumeLoadInfo.length); |
325 | local fillSourceStruct = {x=x,y=y,z=z, d1x=d1x,d1y=d1y,d1z=d1z, d2x=d2x,d2y=d2y,d2z=d2z}; |
326 | self:setFillLevel(newFillLevel, Fillable.FILLTYPE_WOODCHIPS, false, fillSourceStruct); |
327 | end |
328 | end |
329 | |
330 | function WoodCrusher:woodCrusherSplitShapeCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ) |
331 | if not isBelow then |
332 | self.woodCrusherCrushNodes[shape] = shape; |
333 | end |
334 | end |
335 | |
336 | function WoodCrusher:woodCrusherMoveTriggerCallback(triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId) |
337 | local vehicle = g_currentMission.nodeToVehicle[otherActorId]; |
338 | if vehicle == nil and getRigidBodyType(otherActorId) == "Dynamic" then |
339 | local splitType = SplitUtil.splitTypes[getSplitType(otherActorId)]; |
340 | if splitType ~= nil and splitType.woodChipsPerLiter > 0 then |
341 | if onEnter then |
342 | self.woodCrusherMoveTriggerNodes[otherActorId] = Utils.getNoNil(self.woodCrusherMoveTriggerNodes[otherActorId],0)+1; |
343 | elseif onLeave then |
344 | local c = self.woodCrusherMoveTriggerNodes[otherActorId]; |
345 | if c ~= nil then |
346 | c = c-1; |
347 | if c == 0 then |
348 | self.woodCrusherMoveTriggerNodes[otherActorId] = nil; |
349 | else |
350 | self.woodCrusherMoveTriggerNodes[otherActorId] = c; |
351 | end |
352 | end |
353 | end |
354 | end |
355 | end |
356 | end |
357 | |
358 | function WoodCrusher:getDirtMultiplier(superFunc) |
359 | local multiplier = 0; |
360 | if superFunc ~= nil then |
361 | multiplier = multiplier + superFunc(self); |
362 | end; |
363 | |
364 | if self.crushingTime > 0 then |
365 | multiplier = multiplier + self.workMultiplier; |
366 | end; |
367 | |
368 | return multiplier; |
369 | end;
|
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de