Sprache Deutsch Language English

Script Dokumentation LS 2015 - Chainsaw (Patch 1.3)

Script Dokumentation Übersicht

scripts/handTools/Chainsaw.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
2
3Chainsaw = {}
4Chainsaw_mt = Class(Chainsaw, HandTool)
5
6InitStaticObjectClass(Chainsaw, "Chainsaw", ObjectIds.OBJECT_CHAINSAW);
7
8function Chainsaw:new(isServer, isClient, customMt)
9 local mt = customMt;
10 if mt == nil then
11 mt = Chainsaw_mt;
12 end;
13
14 local self = HandTool:new(isServer, isClient, mt);
15 return self;
16end;
17
18
19function Chainsaw:load(xmlFilename, player)
20 if not Chainsaw:superClass().load(self, xmlFilename, player) then
21 return false;
22 end;
23
24 local xmlFile = loadXMLFile("TempXML", xmlFilename);
25
26 self.rotationZ = 0;
27 self.rotationSpeedZ = 0.003;
28 self.cutSizeY = 1.1;
29 self.cutSizeZ = 1;
30 self.isCutting = false;
31 self.waitingForResetAfterCut = false;
32 self.cutNode = getChildAt(self.rootNode, 0);
33 self.graphicsNode = getChildAt(self.cutNode, 0);
34 self.chainNode = getChildAt(self.graphicsNode, 0);
35 self.psNode = getChildAt(self.graphicsNode, 1);
36
37 self.pricePerSecond = Utils.getNoNil(getXMLFloat(xmlFile, "handTool.pricePerMinute"), 50) / 1000;
38
39 if self.isClient then
40 self.particleSystems = {};
41 Utils.loadParticleSystem(xmlFile, self.particleSystems, "handTool.particleSystem", self.psNode, false, "data/vehicles/particleAnimations/shared/chainsaw.i3d", self.baseDirectory);
42
43 self.handNode = Utils.getNoNil(Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "handTool.handNode#index")), self.rootNode);
44 self.handNodeRotation = Utils.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, "handTool.handNode#rotation"), "0 0 0"), 3);
45
46 self.equipmentUVs = Utils.getVectorNFromString(Utils.getNoNil(getXMLString(xmlFile, "handTool.equipment#uvs"), "0 0"), 2);
47
48 self.chain = Utils.loadScrollers(self.rootNode, xmlFile, "handTool.chain", {}, false);
49 table.getn(self.chain);
50
51 self.sampleStart = Utils.loadSample(xmlFile, {}, "handTool.startSound", nil, self.baseDirectory);
52 self.sampleIdle = Utils.loadSample(xmlFile, {}, "handTool.idleSound", nil, self.baseDirectory);
53 self.sampleWorkUp = Utils.loadSample(xmlFile, {}, "handTool.workUpSound", nil, self.baseDirectory);
54 self.sampleWork = Utils.loadSample(xmlFile, {}, "handTool.workSound", nil, self.baseDirectory);
55 self.sampleWorkDown = Utils.loadSample(xmlFile, {}, "handTool.workDownSound", nil, self.baseDirectory);
56 self.sampleStop = Utils.loadSample(xmlFile, {}, "handTool.stopSound", nil, self.baseDirectory);
57 self.sampleQuickTap = Utils.loadSample(xmlFile, {}, "handTool.quickTapSound", nil, self.baseDirectory);
58
59 self.soundIdlePitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "handTool.idleSound#pitchMax"), 2.0);
60
61 self.samplesBranch = {};
62 local i=0;
63 while true do
64 if not hasXMLProperty(xmlFile, string.format("handTool.branchSounds.branchSound(%d)#file",i)) then
65 break;
66 end;
67 sampleBranch = Utils.loadSample(xmlFile, {}, string.format("handTool.branchSounds.branchSound(%d)",i), nil, self.baseDirectory);
68 table.insert(self.samplesBranch, sampleBranch);
69 i = i + 1;
70 end;
71 self.samplesBranchCount = i;
72 self.samplesBranchActiveTimer = 0;
73
74 local filename = getXMLString(xmlFile, "handTool.ringSelector#file");
75 if filename ~= nil then
76 local i3dNode = Utils.loadSharedI3DFile(filename, self.baseDirectory, false, false, false);
77 if i3dNode ~= 0 then
78 self.ringSelectorFilename = filename;
79 self.ringSelector = getChildAt(i3dNode, 0);
80 self.ringSelectorScaleOffset = Utils.getNoNil(getXMLFloat(xmlFile, "handTool.ringSelector#scaleOffset"), 0.3);
81 setVisibility(self.ringSelector, false);
82 link(self.cutNode, self.ringSelector);
83 delete(i3dNode);
84 end;
85 end;
86 end;
87
88 self.needGloves = true;
89 self.needHelmet = true;
90 self.lastWorkTime = 0;
91 self.maxWorkTime = 300;
92
93 self.speedFactor = 0;
94
95 self.offsetY = 0;
96 self.moveSpeedY = 0.0001;
97 self.speedFactor = 0;
98
99 self.startDuration = self.sampleStart.duration * 0.5; -- during the first half of the start sample the idle sample is faded in
100 self.startTime = 0;
101
102 self.quickTapDuration = 0;
103 self.quickTapDurationTime = 250; -- mouse/button presses shorter than this will play the quick tap sound
104 self.lastQuickTapTime = 0;
105 self.quickTapMinDelay = 250; -- quick tap sound won't play again until after this amount of time
106
107 self.workUpStartTime = 0;
108 self.workUpDuration = self.sampleWorkUp.duration - 20; -- shorter duration for transition between WorkUp & Work
109 self.workUpPlayed = false;
110 self.workPlaying = false;
111
112 self.isCutting = false;
113 self.isHorizontalCut = false;
114
115 self.currentHandNode = nil;
116
117 delete(xmlFile);
118
119 return true;
120end;
121
122function Chainsaw:delete()
123 Chainsaw:superClass().delete(self);
124 if self.isClient then
125 if self.particleSystems ~= nil then
126 Utils.deleteParticleSystem(self.particleSystems);
127 end;
128 Utils.deleteSample(self.sampleStart);
129 Utils.deleteSample(self.sampleIdle);
130 Utils.deleteSample(self.sampleWorkUp);
131 Utils.deleteSample(self.sampleWork);
132 Utils.deleteSample(self.sampleWorkDown);
133 Utils.deleteSample(self.sampleStop);
134 Utils.deleteSample(self.sampleQuickTap);
135 for _,v in pairs(self.samplesBranch) do
136 Utils.deleteSample(v);
137 end;
138 if self.ringSelectorFilename ~= nil then
139 Utils.releaseSharedI3DFile(self.ringSelectorFilename, self.baseDirectory, true);
140 end;
141 end;
142end;
143
144function Chainsaw:update(dt, allowInput)
145 Chainsaw:superClass().update(self, dt, allowInput);
146
147 Utils.updateScrollers(self.chain, dt*self.speedFactor, true);
148
149 if self.isServer then
150 local price = self.pricePerSecond * (dt / 1000);
151 g_currentMission.missionStats:updateStats("expenses", price);
152 g_currentMission:addSharedMoney(-price, "vehicleRunningCost");
153 end;
154
155 self.shouldDelimb = false;
156
157 if allowInput then
158 local isCutting = false;
159
160 if not Utils.isSamplePlaying(self.sampleStart, 1.5*dt) then
161 Utils.playSample(self.sampleIdle, 0, 0, nil);
162 Utils.playSample(self.sampleWork, 0, 0, 0);
163 Utils.setSampleVolume(self.sampleIdle, self.sampleIdle.volume);
164 else
165 local idleVolume = Utils.clamp((g_currentMission.time - self.startTime) / self.startDuration, 0, self.sampleIdle.volume);
166 Utils.setSampleVolume(self.sampleIdle, idleVolume); -- idle sound fades in during start sound
167 end;
168
169 setRotation(self.graphicsNode, math.rad(math.random(-1, 1))*0.1, math.rad(math.random(-1, 1))*0.1, math.rad(-180));
170
171 if self.curSplitShape == nil then
172 local input = InputBinding.getDigitalInputAxis(InputBinding.AXIS_ROTATE_HANDTOOL);
173 if InputBinding.isAxisZero(input) then
174 input = InputBinding.getAnalogInputAxis(InputBinding.AXIS_ROTATE_HANDTOOL);
175 end;
176 self.player:lockInput(input ~= 0);
177 if input ~= 0 then
178 self.rotationZ = Utils.clamp(self.rotationZ + self.rotationSpeedZ*input*dt, -0.1, 1.57);
179 setRotation(self.rootNode, 0, 0, self.rotationZ);
180 self.player:setIKDirty();
181 end
182
183 self.offsetY = math.max(self.offsetY - 5*self.moveSpeedY*dt, 0);
184 setTranslation(self.graphicsNode, 0, self.offsetY, 0);
185 if self.offsetY ~= 0 then
186 self.player:setIKDirty();
187 end;
188 end;
189
190 local shape = 0;
191 if not self.waitingForResetAfterCut then
192 local x,y,z = getWorldTranslation(self.cutNode);
193 local nx,ny,nz = localDirectionToWorld(self.cutNode, 1,0,0);
194 local yx,yy,yz = localDirectionToWorld(self.cutNode, 0,1,0);
195 if self.curSplitShape ~= nil or self.offsetY == 0 then
196 local minY,maxY, minZ,maxZ;
197 if self.curSplitShape == nil or not entityExists(self.curSplitShape) then
198 self.curSplitShape = nil;
199 shape, minY,maxY, minZ,maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ);
200
201 if shape ~= nil and shape ~= 0 then
202 local cutTooLow = false;
203 local x,y,z = localToLocal(self.cutNode, shape, 0,minY,minZ);
204 cutTooLow = cutTooLow or y < 0.01;
205 local x,y,z = localToLocal(self.cutNode, shape, 0,minY,maxZ);
206 cutTooLow = cutTooLow or y < 0.01;
207 local x,y,z = localToLocal(self.cutNode, shape, 0,maxY,minZ);
208 cutTooLow = cutTooLow or y < 0.01;
209 local x,y,z = localToLocal(self.cutNode, shape, 0,maxY,maxZ);
210 cutTooLow = cutTooLow or y < 0.01;
211 if cutTooLow then
212 self.player.walkingIsLocked = false;
213 self.curSplitShape = nil;
214 shape, minY,maxY, minZ,maxZ = 0, nil,nil, nil,nil;
215 end;
216 end;
217 end;
218
219 self.curSplitShapeMinY = minY;
220 self.curSplitShapeMaxY = maxY;
221 self.curSplitShapeMinZ = minZ;
222 self.curSplitShapeMaxZ = maxZ;
223 end;
224 end;
225
226 if self.ringSelector ~= nil then
227 setVisibility(self.ringSelector, (self.curSplitShapeMinY ~= nil or self.curSplitShape ~= nil) and g_woodCuttingMarkerEnabled);
228 if g_woodCuttingMarkerEnabled then
229 if self.curSplitShape ~= nil then
230 setShaderParameter(self.ringSelector, "colorScale", 0.395, 0.925, 0.115, 1, false);
231 else
232 setShaderParameter(self.ringSelector, "colorScale", 0.098, 0.450, 0.960, 1, false);
233 end;
234 if self.curSplitShapeMinY ~= nil then
235 local a,b,c = localToWorld(self.cutNode, 0, (self.curSplitShapeMinY+self.curSplitShapeMaxY)*0.5, (self.curSplitShapeMinZ+self.curSplitShapeMaxZ)*0.5);
236 x, y, z = worldToLocal(getParent(self.ringSelector), a,b,c);
237 setTranslation(self.ringSelector, x,y,z);
238 local scale = math.max(self.curSplitShapeMaxY-self.curSplitShapeMinY + self.ringSelectorScaleOffset, self.curSplitShapeMaxZ-self.curSplitShapeMinZ + self.ringSelectorScaleOffset);
239 setScale(self.ringSelector, 1, scale, scale);
240 end;
241 end;
242 end;
243
244 if InputBinding.isPressed(InputBinding.ACTIVATE_HANDTOOL) then
245 self.quickTapDuration = self.quickTapDuration + dt;
246
247 self.speedFactor = math.min(self.speedFactor + dt/self.maxWorkTime, 1);
248
249 if self.quickTapDuration > self.quickTapDurationTime then
250 if not self.workUpPlayed then
251 self.workUpStartTime = g_currentMission.time;
252 Utils.playSample(self.sampleWorkUp, 1, 0, nil);
253 self.workUpPlayed = true;
254 end;
255
256 self.lastWorkTime = math.min(self.lastWorkTime+dt, self.maxWorkTime);
257
258 if g_currentMission.time - self.workUpStartTime >= self.workUpDuration then
259 if not Utils.isSamplePlaying(self.sampleWorkUp, 1.5*dt) -- TEST THIS
260 and not self.workPlaying then
261 Utils.setSampleVolume(self.sampleWork, 1);
262 self.workPlaying = true;
263 end;
264 end;
265 end;
266
267 if not self.waitingForResetAfterCut then
268 self.shouldDelimb = true;
269
270 local x,y,z = getWorldTranslation(self.cutNode);
271 local nx,ny,nz = localDirectionToWorld(self.cutNode, 1,0,0);
272 local yx,yy,yz = localDirectionToWorld(self.cutNode, 0,1,0);
273
274 if self.curSplitShape ~= nil or self.offsetY == 0 then
275 if self.curSplitShape ~= nil and entityExists(self.curSplitShape) then
276 local minY,maxY, minZ,maxZ = testSplitShape(self.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ);
277 if minY == nil then
278 -- cancel cutting if shape can't be cut anymore from current position
279 self.player.walkingIsLocked = false;
280 self.curSplitShape = nil;
281 Utils.setSamplePitch(self.sampleWork, 1);
282 else
283 local cutTooLow = false;
284 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,minY,minZ);
285 cutTooLow = cutTooLow or y < 0.01;
286 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,minY,maxZ);
287 cutTooLow = cutTooLow or y < 0.01;
288 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,maxY,minZ);
289 cutTooLow = cutTooLow or y < 0.01;
290 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,maxY,maxZ);
291 cutTooLow = cutTooLow or y < 0.01;
292 if cutTooLow then
293 self.player.walkingIsLocked = false;
294 self.curSplitShape = nil;
295 end;
296 end
297 self.curSplitShapeMinY = minY;
298 self.curSplitShapeMaxY = maxY;
299 self.curSplitShapeMinZ = minZ;
300 self.curSplitShapeMaxZ = maxZ;
301 else
302 if shape ~= 0 then
303 self.player.walkingIsLocked = true;
304 self.curSplitShape = shape;
305 end
306 end
307
308 if self.curSplitShape ~= nil then
309 isCutting = true;
310 self.offsetY = self.offsetY + self.moveSpeedY*dt;
311 setTranslation(self.graphicsNode, 0, self.offsetY, 0);
312 self.player:setIKDirty();
313
314 if self.offsetY > self.curSplitShapeMinY then
315 self.lastWorkTime = math.min(self.lastWorkTime, self.maxWorkTime*0.7);
316 Utils.setSamplePitch(self.sampleWork, 0.96);
317 end;
318
319 if self.offsetY > self.curSplitShapeMaxY then
320 if g_currentMission:getIsServer() then
321 ChainsawUtil.cutSplitShape(self.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ);
322 else
323 g_client:getServerConnection():sendEvent(ChainsawCutEvent:new(self.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ));
324 end
325 self.player.walkingIsLocked = false;
326 self.waitingForResetAfterCut = true;
327 self.curSplitShape = nil;
328 Utils.setSamplePitch(self.sampleWork, 1);
329 end
330 end
331 end
332 end
333 else
334 self.speedFactor = math.max(self.speedFactor - dt/self.maxWorkTime, 0);
335 self.waitingForResetAfterCut = false;
336 self.player.walkingIsLocked = false;
337 self.curSplitShape = nil;
338 self.lastWorkTime = math.max(self.lastWorkTime - dt, 0);
339
340 if self.quickTapDuration > 0 then
341 if self.quickTapDuration < self.quickTapDurationTime then
342 if g_currentMission.time - self.lastQuickTapTime > self.quickTapMinDelay then
343 Utils.playSample(self.sampleQuickTap, 1, 0, nil);
344 self.lastQuickTapTime = g_currentMission.time;
345 end;
346 else
347 Utils.stopSample(self.sampleWorkUp, true);
348 Utils.setSampleVolume(self.sampleWork, 0);
349 self.workPlaying = false;
350 Utils.setSamplePitch(self.sampleWork, 1);
351 Utils.playSample(self.sampleWorkDown, 1, 0, nil);
352 end;
353 end;
354
355 self.workUpPlayed = false;
356 self.quickTapDuration = 0;
357 end
358
359 if (self.samplesBranchActiveTimer > g_currentMission.time) or
360 (self.curSplitShapeMinY ~= nil and self.curSplitShapeMaxY ~= nil and self.offsetY > self.curSplitShapeMinY and self.offsetY < self.curSplitShapeMaxY)
361 then
362 Utils.setEmittingState(self.particleSystems, true);
363 else
364 Utils.setEmittingState(self.particleSystems, false);
365 end;
366
367 local idlePitch = Utils.lerp(self.sampleIdle.pitchOffset, self.soundIdlePitchMax, Utils.clamp(self.lastWorkTime/self.maxWorkTime, 0, 1));
368 Utils.setSamplePitch(self.sampleIdle, idlePitch);
369
370 self:setCutting(isCutting, self.rotationZ > 0.7);
371 end
372end;
373
374function Chainsaw:updateTick(dt, allowInput)
375 Chainsaw:superClass().updateTick(self, dt, allowInput);
376 if self.isClient then
377 if self.shouldDelimb then
378 local x,y,z = getWorldTranslation(self.cutNode);
379 local nx,ny,nz = localDirectionToWorld(self.cutNode, 1,0,0);
380 local yx,yy,yz = localDirectionToWorld(self.cutNode, 0,1,0);
381 if g_server == nil then
382 g_client:getServerConnection():sendEvent(ChainsawDelimbEvent:new(self.player, x,y,z, nx,ny,nz, yx,yy,yz, false));
383 else
384 local ret = findAndRemoveSplitShapeAttachments(x,y,z, nx,ny,nz, yx,yy,yz, 0.7, self.cutSizeY, self.cutSizeZ);
385 if ret then
386 self:setOnDelimb(true);
387 end;
388 end;
389 end;
390 end;
391end;
392
393function Chainsaw:setCutting(isCutting, isHorizontalCut, noEventSend)
394 ChainsawStateEvent.sendEvent(self.player, isCutting, isHorizontalCut, noEventSend);
395 self.isCutting = isCutting;
396 self.isHorizontalCut = isHorizontalCut;
397 if g_currentMission.player ~= self.player then
398 self.player:setCuttingAnim(isCutting, isHorizontalCut);
399 end;
400end;
401
402function Chainsaw:setOnDelimb(state)
403 if state == true then
404 if not (self.samplesBranchActiveTimer > g_currentMission.time) then
405 local idx = math.floor(math.random(1, self.samplesBranchCount));
406 Utils.playSample(self.samplesBranch[idx], 1, 0, nil);
407 self.samplesBranchActiveTimer = g_currentMission.time + self.samplesBranch[idx].duration;
408
409 self.lastWorkTime = math.max(0, self.lastWorkTime - 160); --10*dt);
410 end;
411 end;
412end;
413
414function Chainsaw:draw()
415 Chainsaw:superClass().draw(self);
416 g_currentMission:addHelpButtonText(g_i18n:getText("ACTIVATE_HANDTOOL"), InputBinding.ACTIVATE_HANDTOOL);
417 if GS_IS_CONSOLE_VERSION then
418 g_currentMission:addHelpButtonText(g_i18n:getText("rotatePlaceable"), nil, InputBinding.AXIS_ROTATE_HANDTOOL);
419 end;
420end;
421
422function Chainsaw:setHandNode(handNode)
423 Chainsaw:superClass().setHandNode(self, handNode);
424 if self.currentHandNode ~= handNode then
425 if g_currentMission.player ~= self.player then
426 link(handNode, self.rootNode);
427 self.currentHandNode = handNode;
428 setRotation(self.rootNode, unpack(self.handNodeRotation));
429 local x,y,z = getWorldTranslation(self.handNode);
430 x,y,z = worldToLocal(getParent(self.rootNode), x,y,z);
431 local a,b,c = getTranslation(self.rootNode);
432 setTranslation(self.rootNode, a-x,b-y,c-z);
433 end;
434 end;
435end;
436
437function Chainsaw:onActivate(allowInput)
438 Chainsaw:superClass().onActivate(self);
439 self.startTime = g_currentMission.time;
440 self.player:setEquipmentUVs(self.equipmentUVs);
441 if self.isClient and allowInput then
442 Utils.playSample(self.sampleStart, 1, 0, nil);
443 Utils.playSample(self.sampleIdle, 0, 0, 0);
444 Utils.playSample(self.sampleWork, 0, 0, 0);
445 end;
446end;
447
448function Chainsaw:onDeactivate(allowInput)
449 Chainsaw:superClass().onDeactivate(self);
450 self.speedFactor = 0;
451 self.curSplitShape = nil;
452 self.player.walkingIsLocked = false;
453 if self.isClient then
454 if allowInput then
455 Utils.playSample(self.sampleStop, 1, 0, nil);
456 end;
457 Utils.setEmittingState(self.particleSystems, false);
458 Utils.stopSample(self.sampleStart, true);
459 Utils.stopSample(self.sampleIdle, true);
460 Utils.stopSample(self.sampleWorkUp, true);
461 Utils.stopSample(self.sampleWork, true);
462 Utils.stopSample(self.sampleWorkDown, true);
463 Utils.stopSample(self.sampleQuickTap, true);
464 end;
465end;
466
467ChainsawUtil = {}
468
469function ChainsawUtil.cutSplitShape(shape, x,y,z, nx,ny,nz, yx,yy,yz, cutSizeY, cutSizeZ)
470 -- only add a cut joint if we do a horizontal cut
471 if math.abs(ny) < 0.96 then
472 ChainsawUtil.curSplitShapes = {};
473 splitShape(shape, x,y,z, nx,ny,nz, yx,yy,yz, cutSizeY, cutSizeZ, "ChainsawUtil.cutSplitShapeCallback", nil);
474 else
475 ChainsawUtil.curSplitShapes = {};
476 splitShape(shape, x,y,z, nx,ny,nz, yx,yy,yz, cutSizeY, cutSizeZ, "ChainsawUtil.cutSplitShapeCallback", nil);
477
478 if table.getn(ChainsawUtil.curSplitShapes) == 2 then
479 local split0 = ChainsawUtil.curSplitShapes[1];
480 local split1 = ChainsawUtil.curSplitShapes[2];
481 local type0 = getRigidBodyType(split0.shape);
482 local type1 = getRigidBodyType(split1.shape);
483 local dynamicSplit = nil;
484 local staticSplit = nil;
485 if type0 == "Static" and type1 == "Dynamic" then
486 staticSplit = split0;
487 dynamicSplit = split1;
488 elseif type1 == "Static" and type0 == "Dynamic" then
489 staticSplit = split1;
490 dynamicSplit = split0;
491 end
492 if dynamicSplit ~= nil then
493 local distY = dynamicSplit.minY + (dynamicSplit.maxY-dynamicSplit.minY)*0.75; -- create hinge at 75% of the tree
494 local distZ = (dynamicSplit.minZ+dynamicSplit.maxZ)*0.5;
495
496 local zx,zy,zz = Utils.crossProduct(nx,ny,nz, yx,yy,yz);
497
498
499 -- Create notch, Humboldt style
500 -- Calculate new normal as slerp between normal and direction (those are 90° apart)
501 local angle = math.rad(40);
502 local scale0 = math.sin(1.5707-angle);
503 local scale1 = math.sin(angle);
504 if dynamicSplit.isBelow then
505 -- rotate towards -y direction if the normal points downwards
506 scale1 = -scale1;
507 end
508 local nx2 = nx*scale0 + yx*scale1;
509 local ny2 = ny*scale0 + yy*scale1;
510 local nz2 = nz*scale0 + yz*scale1;
511 local yx2,yy2,yz2 = Utils.crossProduct(zx,zy,zz, nx2,ny2,nz2);
512 -- the cut point is at the hinge, slightly moved out of the tree
513 local cx = x + yx*distY - yx2*cutSizeY*0.1;
514 local cy = y + yy*distY - yy2*cutSizeY*0.1;
515 local cz = z + yz*distY - yz2*cutSizeY*0.1;
516 splitShape(staticSplit.shape, cx,cy,cz, nx2,ny2,nz2, yx2,yy2,yz2, cutSizeY*1.1, cutSizeZ);
517
518
519 -- create a joint in the middle of the hinge
520 local jx = x + yx*distY + zx*distZ;
521 local jy = y + yy*distY + zy*distZ;
522 local jz = z + yz*distY + zz*distZ;
523
524 local constr = JointConstructor:new();
525 constr:setActors(0, dynamicSplit.shape);
526 constr:setJointWorldAxes(nx,ny,nz, nx,ny,nz);
527 constr:setJointWorldNormals(yx,yy,yz, yx,yy,yz);
528 constr:setJointWorldPositions(jx, jy, jz, jx, jy, jz);
529
530 constr:setRotationLimit(0, 0, 0);
531 constr:setTranslationLimit(0, false, 0, 0);
532 constr:setEnableCollision(true);
533 local jointIndex = constr:finalize();
534
535 --local torqueVal = 10;
536 --local tx,ty,tz = Utils.crossProduct(0,torqueVal,0, yx,yy, yz);
537 --addTorque(dynamicSplit.shape, tx,ty,tz);
538
539 local ax,ay,az = Utils.crossProduct(0,0.8,0, yx,yy, yz);
540 setAngularVelocity(dynamicSplit.shape, ax,ay,az);
541
542 --local f = 20;
543 --addForce(dynamicSplit.shape, yx*f,yy*f,yz*f, jx,jy+10,jz, false);
544
545 TreePlantUtil.addTreeCutJoint(g_currentMission.plantedTrees, jointIndex, dynamicSplit.shape, nx,ny,nz, math.rad(45), 2000);
546 end
547 end
548 end
549end
550
551function ChainsawUtil.cutSplitShapeCallback(unused, shape, isBelow, isAbove, minY, maxY, minZ, maxZ)
552 table.insert(ChainsawUtil.curSplitShapes, {shape=shape, isBelow=isBelow, isAbove=isAbove, minY=minY, maxY=maxY, minZ=minZ, maxZ=maxZ});
553end
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht