Sprache Deutsch Language English

Script Dokumentation LS 2015 - WoodHarvester (Patch 1.3)

Script Dokumentation Übersicht

scripts/vehicles/specializations/WoodHarvester.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1--
2-- WoodHarvester
3-- This is the specialization for wood harvesters
4--
5-- @author Stefan Geiger
6-- @date 14/09/14
7--
8-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
9
10source("dataS/scripts/vehicles/specializations/WoodHarvesterCutTreeEvent.lua")
11source("dataS/scripts/vehicles/specializations/WoodHarvesterOnCutTreeEvent.lua")
12source("dataS/scripts/vehicles/specializations/WoodHarvesterOnDelimbTreeEvent.lua")
13
14WoodHarvester = {};
15
16function WoodHarvester.prerequisitesPresent(specializations)
17 return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations);
18end
19
20function WoodHarvester:load(xmlFile)
21
22 self.woodHarvesterSplitShapeCallback = WoodHarvester.woodHarvesterSplitShapeCallback;
23
24 self.cutTree = SpecializationUtil.callSpecializationsFunction("cutTree");
25 self.onCutTree = SpecializationUtil.callSpecializationsFunction("onCutTree");
26 self.onDelimbTree = SpecializationUtil.callSpecializationsFunction("onDelimbTree");
27
28 self.curSplitShape = nil;
29 self.attachedSplitShape = nil;
30 self.hasAttachedSplitShape = false;
31 self.isAttachedSplitShapeMoving = false;
32 self.attachedSplitShapeX = 0;
33 self.attachedSplitShapeY = 0;
34 self.attachedSplitShapeZ = 0;
35 self.attachedSplitShapeTargetY = 0;
36 self.attachedSplitShapeLastCutY = 0;
37 self.attachedSplitShapeStartY = 0;
38 self.cutTimer = -1;
39 self.cutTimer = -1;
40
41 self.cutNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.cutNode#node"));
42 self.cutMaxRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutNode#maxRadius"), 1);
43 self.cutSizeY = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutNode#sizeY"), 1);
44 self.cutSizeZ = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutNode#sizeZ"), 1);
45 self.cutAttachNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.cutNode#attachNode"));
46 self.cutAttachReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.cutNode#attachReferenceNode"));
47 self.cutAttachMoveSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutNode#attachMoveSpeed"), 3)*0.001;
48 local cutReleasedComponentJointIndex = getXMLInt(xmlFile, "vehicle.cutNode#releasedComponentJointIndex");
49 if cutReleasedComponentJointIndex ~= nil then
50 self.cutReleasedComponentJoint = self.componentJoints[cutReleasedComponentJointIndex+1];
51 self.cutReleasedComponentJointRotLimitX = 0;
52 self.cutReleasedComponentJointRotLimitXSpeed = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutNode#releasedComponentJointRotLimitXSpeed"), 100)*0.001);
53 end
54 local cutReleasedComponentJoint2Index = getXMLInt(xmlFile, "vehicle.cutNode#releasedComponentJoint2Index");
55 if cutReleasedComponentJoint2Index ~= nil then
56 self.cutReleasedComponentJoint2 = self.componentJoints[cutReleasedComponentJoint2Index+1];
57 self.cutReleasedComponentJoint2RotLimitX = 0;
58 self.cutReleasedComponentJoint2RotLimitXSpeed = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutNode#releasedComponentJointRotLimitXSpeed"), 100)*0.001);
59 end
60
61 if self.cutAttachReferenceNode ~= nil and self.cutAttachNode ~= nil then
62 self.cutAttachHelperNode = createTransformGroup("helper");
63 link(self.cutAttachReferenceNode, self.cutAttachHelperNode);
64 setTranslation(self.cutAttachHelperNode, 0,0,0);
65 setRotation(self.cutAttachHelperNode, 0,0,0);
66 end
67
68 self.delimbNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.delimbNode#node"));
69 self.delimbSizeX = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.delimbNode#sizeX"), 0.1);
70 self.delimbSizeY = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.delimbNode#sizeY"), 1);
71 self.delimbSizeZ = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.delimbNode#sizeZ"), 1);
72 self.delimbOnCut = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.delimbNode#delimbOnCut"), false);
73
74 self.cutLengthMin = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutLengths#min"), 1);
75 self.cutLengthMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutLengths#max"), 5);
76 self.cutLengthStep = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutLengths#step"), 0.5);
77
78 self.cutParticleSystems = {};
79 local i = 0;
80 while true do
81 local keyPS = string.format("vehicle.cutParticleSystems.cutParticleSystem(%d)", i);
82 if not hasXMLProperty(xmlFile, keyPS) then
83 break;
84 end;
85 local currentPS = {};
86 local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, keyPS, self.components, false, nil, self.baseDirectory);
87 table.insert(self.cutParticleSystems, currentPS);
88 i = i + 1;
89 end;
90
91 self.delimbParticleSystems = {};
92 local i = 0;
93 while true do
94 local keyPS = string.format("vehicle.delimbParticleSystems.delimbParticleSystem(%d)", i);
95 if not hasXMLProperty(xmlFile, keyPS) then
96 break;
97 end;
98 local currentPS = {};
99 local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, keyPS, self.components, false, nil, self.baseDirectory);
100 table.insert(self.delimbParticleSystems, currentPS);
101 i = i + 1;
102 end;
103
104 self.cutAnimation = {};
105 self.cutAnimation.name = getXMLString(xmlFile, "vehicle.cutAnimation#name");
106 self.cutAnimation.speedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutAnimation#speedScale"), 1);
107 self.cutAnimation.cutTime = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cutAnimation#cutTime"), 1);
108
109 self.grabAnimation = {};
110 self.grabAnimation.name = getXMLString(xmlFile, "vehicle.grabAnimation#name");
111 self.grabAnimation.speedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.grabAnimation#speedScale"), 1);
112
113 self.forwardingWheels = {};
114 local i = 0;
115 while true do
116 local wheelString = string.format("vehicle.forwardingWheels.wheel(%d)",i);
117 if not hasXMLProperty(xmlFile, wheelString) then
118 break;
119 end;
120 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelString.."#index"));
121 local rotSpeed = Utils.getRadiansFromString(getXMLString(xmlFile, wheelString.."#rotSpeed"), 3);
122 local wheel = {node=node, rotSpeed=rotSpeed};
123 table.insert(self.forwardingWheels, wheel);
124 i = i + 1;
125 end;
126
127 self.treeSizeMeasure = {};
128 self.treeSizeMeasure.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.treeSizeMeasure#index"));
129 self.treeSizeMeasure.rotMaxRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.treeSizeMeasure#rotMaxRadius"), 1);
130
131 self.harvesterSounds = {};
132 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.harvesterSounds.delimbSound#node"));
133 self.harvesterSounds.delimbSample = Utils.loadSample(xmlFile, {}, "vehicle.harvesterSounds.delimbSound", nil, self.baseDirectory, node);
134 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.harvesterSounds.delimbSound#node"));
135 self.harvesterSounds.cutSample = Utils.loadSample(xmlFile, {}, "vehicle.harvesterSounds.cutSound", nil, self.baseDirectory, node);
136
137 self.motorSoundPitchOffsetFactor = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.harvesterSounds#motorSoundPitchOffset"), 1.0);
138 self.motorRunSoundPitchOffsetFactor = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.harvesterSounds#motorRunSoundPitchOffset"), 1.0);
139
140 self.sampleMotor.pitchOffsetBackup = self.sampleMotor.pitchOffset;
141 self.sampleMotorRun.pitchOffsetBackup = self.sampleMotorRun.pitchOffset;
142
143 self.warnInvalidTree = false;
144 self.warnInvalidTreeRadius = false;
145
146 self.currentCutLength = self.cutLengthMin;
147 self.lastDiameter = 0;
148end
149
150function WoodHarvester:delete()
151 if self.attachedSplitShapeJointIndex ~= nil then
152 removeJoint(self.attachedSplitShapeJointIndex);
153 self.attachedSplitShapeJointIndex = nil;
154 end;
155 if self.cutAttachHelperNode ~= nil then
156 delete(self.cutAttachHelperNode);
157 end
158 for _, particleSystem in pairs(self.cutParticleSystems) do
159 Utils.deleteParticleSystem(particleSystem);
160 end
161 for _, particleSystem in pairs(self.delimbParticleSystems) do
162 Utils.deleteParticleSystem(particleSystem);
163 end
164 Utils.deleteSample(self.harvesterSounds.delimbSample);
165 Utils.deleteSample(self.harvesterSounds.cutSample);
166end
167
168function WoodHarvester:readStream(streamId, connection)
169 self.hasAttachedSplitShape = streamReadBool(streamId);
170 self.isAttachedSplitShapeMoving = streamReadBool(streamId);
171end
172
173function WoodHarvester:writeStream(streamId, connection)
174 streamWriteBool(streamId, self.hasAttachedSplitShape);
175 streamWriteBool(streamId, self.isAttachedSplitShapeMoving);
176end
177
178function WoodHarvester:readUpdateStream(streamId, timestamp, connection)
179end
180
181function WoodHarvester:writeUpdateStream(streamId, connection, dirtyMask)
182end
183
184function WoodHarvester:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
185 return BaseMission.VEHICLE_LOAD_OK;
186end;
187
188function WoodHarvester:getSaveAttributesAndNodes(nodeIdent)
189 local attributes = '';
190 local nodes = "";
191 return attributes, nodes;
192end;
193
194function WoodHarvester:mouseEvent(posX, posY, isDown, isUp, button)
195end
196
197function WoodHarvester:keyEvent(unicode, sym, modifier, isDown)
198end
199
200function WoodHarvester:update(dt)
201 if self:getIsActive() then
202 -- Verify that the split shapes still exist (possible that someone has cut them)
203 if self.isServer then
204 local lostShape = false;
205 if self.attachedSplitShape ~= nil then
206 if not entityExists(self.attachedSplitShape) then
207 self.attachedSplitShape = nil;
208 self.attachedSplitShapeJointIndex = nil;
209 self.isAttachedSplitShapeMoving = false;
210 self.cutTimer = -1;
211 lostShape = true;
212 end
213 elseif self.curSplitShape ~= nil then
214 if not entityExists(self.curSplitShape) then
215 self.curSplitShape = nil;
216 lostShape = true;
217 end
218 end
219 if lostShape then
220 self:onCutTree(0);
221 if g_server ~= nil then
222 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent:new(self, 0), nil, nil, self);
223 end;
224 end;
225 end;
226
227 -- Check for input
228 if self:getIsActiveForInput(true) and self:getIsTurnedOn() then
229 if self.cutNode ~= nil then
230 if self.hasAttachedSplitShape then
231 if not self.isAttachedSplitShapeMoving and self:getAnimationTime(self.cutAnimation.name) == 1 then
232 if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
233 self:cutTree(self.currentCutLength);
234 end
235 end
236 elseif self.curSplitShape ~= nil then
237 if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
238 self:cutTree(0);
239 end
240 end
241 if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
242 if not self.isAttachedSplitShapeMoving then
243 self.currentCutLength = self.currentCutLength + self.cutLengthStep;
244 if self.currentCutLength > self.cutLengthMax+0.0001 then
245 self.currentCutLength = self.cutLengthMin;
246 end
247 end;
248 end
249 end;
250 end
251
252 --
253 if self.isServer and (self.attachedSplitShape ~= nil or self.curSplitShape ~= nil) then
254
255 local readyToCut = false;
256 if self.cutTimer > 0 then
257 if self.cutAnimation.name ~= nil then
258 if self:getAnimationTime(self.cutAnimation.name) > self.cutAnimation.cutTime then
259 self.cutTimer = 0;
260 end;
261 else
262 self.cutTimer = math.max(self.cutTimer - dt, 0);
263 end;
264 end;
265 local readyToCut = self.cutTimer == 0;
266
267 -- cut
268 if readyToCut then
269 self.cutTimer = -1;
270
271 local x,y,z = getWorldTranslation(self.cutNode);
272 local nx,ny,nz = localDirectionToWorld(self.cutNode, 1,0,0);
273 local yx,yy,yz = localDirectionToWorld(self.cutNode, 0,1,0);
274
275 local currentSplitShape;
276 if self.attachedSplitShapeJointIndex ~= nil then
277 removeJoint(self.attachedSplitShapeJointIndex);
278 self.attachedSplitShapeJointIndex = nil;
279 currentSplitShape = self.attachedSplitShape;
280 self.attachedSplitShape = nil;
281 else
282 currentSplitShape = self.curSplitShape;
283 self.curSplitShape = nil;
284 end
285
286 if self.delimbOnCut then
287 local xD,yD,zD = getWorldTranslation(self.delimbNode);
288 local nxD,nyD,nzD = localDirectionToWorld(self.delimbNode, 1,0,0);
289 local yxD,yyD,yzD = localDirectionToWorld(self.delimbNode, 0,1,0);
290 local vx,vy,vz = x-xD,y-yD,z-zD;
291 local sizeX = Utils.vector3Length(vx,vy,vz);
292 removeSplitShapeAttachments(currentSplitShape, xD+vx*0.5,yD+vy*0.5,zD+vz*0.5, nxD,nyD,nzD, yxD,yyD,yzD, sizeX*0.7+self.delimbSizeX, self.delimbSizeY, self.delimbSizeZ);
293 end;
294
295 self.attachedSplitShape = nil;
296 self.curSplitShape = nil;
297 splitShape(currentSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ, "woodHarvesterSplitShapeCallback", self);
298
299 if self.attachedSplitShape == nil then
300 self:onCutTree(0);
301 if g_server ~= nil then
302 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent:new(self, 0), nil, nil, self);
303 end;
304 else
305 if self.delimbOnCut then
306 local xD,yD,zD = getWorldTranslation(self.delimbNode);
307 local nxD,nyD,nzD = localDirectionToWorld(self.delimbNode, 1,0,0);
308 local yxD,yyD,yzD = localDirectionToWorld(self.delimbNode, 0,1,0);
309 local vx,vy,vz = x-xD,y-yD,z-zD;
310 local sizeX = Utils.vector3Length(vx,vy,vz);
311 removeSplitShapeAttachments(self.attachedSplitShape, xD+vx*3,yD+vy*3,zD+vz*3, nxD,nyD,nzD, yxD,yyD,yzD, sizeX*3+self.delimbSizeX, self.delimbSizeY, self.delimbSizeZ);
312 end;
313 end;
314
315 end;
316
317 -- delimb
318 if self.attachedSplitShape ~= nil and self.isAttachedSplitShapeMoving then
319 if self.delimbNode ~= nil then
320 local x,y,z = getWorldTranslation(self.delimbNode);
321 local nx,ny,nz = localDirectionToWorld(self.delimbNode, 1,0,0);
322 local yx,yy,yz = localDirectionToWorld(self.delimbNode, 0,1,0);
323
324 removeSplitShapeAttachments(self.attachedSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.delimbSizeX, self.delimbSizeY, self.delimbSizeZ);
325 end
326
327 if self.cutNode ~= nil and self.attachedSplitShapeJointIndex ~= nil then
328 local x,y,z = getWorldTranslation(self.cutAttachReferenceNode);
329 local nx,ny,nz = localDirectionToWorld(self.cutAttachReferenceNode, 0,1,0);
330 local _, lengthRem = getSplitShapePlaneExtents(self.attachedSplitShape, x,y,z, nx,ny,nz);
331
332 if lengthRem == nil or lengthRem <= 0.1 then
333
334 -- end of tree
335 removeJoint(self.attachedSplitShapeJointIndex);
336 self.attachedSplitShapeJointIndex = nil;
337 self.attachedSplitShape = nil;
338
339 self:onDelimbTree(false);
340 if g_server ~= nil then
341 g_server:broadcastEvent(WoodHarvesterOnDelimbTreeEvent:new(self, false), nil, nil, self);
342 end;
343
344 self:onCutTree(0);
345 if g_server ~= nil then
346 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent:new(self, 0), nil, nil, self);
347 end;
348 else
349 self.attachedSplitShapeY = self.attachedSplitShapeY + self.cutAttachMoveSpeed*dt;
350
351 if self.attachedSplitShapeY >= self.attachedSplitShapeTargetY then
352 self.attachedSplitShapeY = self.attachedSplitShapeTargetY;
353 self:onDelimbTree(false);
354 if g_server ~= nil then
355 g_server:broadcastEvent(WoodHarvesterOnDelimbTreeEvent:new(self, false), nil, nil, self);
356 end;
357 end
358 if self.attachedSplitShapeJointIndex ~= nil then
359 --local x,y,z = localToWorld(self.attachedSplitShape, self.attachedSplitShapeX, self.attachedSplitShapeY, self.attachedSplitShapeZ);
360 --setJointPosition(self.attachedSplitShapeJointIndex, 1, x,y,z);
361
362 local x,y,z = localToWorld(self.cutNode, 0.3,0,0);
363 local nx,ny,nz = localDirectionToWorld(self.cutNode, 1,0,0);
364 local yx,yy,yz = localDirectionToWorld(self.cutNode, 0,1,0);
365 local shape, minY, maxY, minZ, maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ);
366 if shape == self.attachedSplitShape then
367 local treeCenterX,treeCenterY,treeCenterZ = localToWorld(self.cutNode, 0, (minY+maxY)*0.5, (minZ+maxZ)*0.5);
368 self.attachedSplitShapeX, _, self.attachedSplitShapeZ = worldToLocal(self.attachedSplitShape, treeCenterX,treeCenterY,treeCenterZ);
369 self.lastDiameter = (maxY-minY + maxZ-minZ)*0.5;
370 end;
371 local x,y,z = localToWorld(self.attachedSplitShape, self.attachedSplitShapeX, self.attachedSplitShapeY, self.attachedSplitShapeZ);
372 setJointPosition(self.attachedSplitShapeJointIndex, 1, x,y,z);
373 end;
374 end
375 end
376 end;
377 end;
378 end;
379
380 -- PS and sound for cut and delimb
381 if self.isClient then
382 if self:getIsActive() then
383 -- cut
384 if self.cutAnimation.name ~= nil then
385 if self:getIsAnimationPlaying(self.cutAnimation.name) and self:getAnimationTime(self.cutAnimation.name) < self.cutAnimation.cutTime then
386 self.cutParticleSystemsActive = true;
387 for _,ps in pairs(self.cutParticleSystems) do
388 Utils.setEmittingState(ps, true);
389 end;
390 if self.harvesterSounds.cutSample.sound3D ~= nil then
391 setVisibility(self.harvesterSounds.cutSample.sound3D, true);
392 end;
393 else
394 self.cutParticleSystemsActive = false;
395 for _,ps in pairs(self.cutParticleSystems) do
396 Utils.setEmittingState(ps, false);
397 end;
398 if self.harvesterSounds.cutSample.sound3D ~= nil then
399 setVisibility(self.harvesterSounds.cutSample.sound3D, false);
400 end;
401 end;
402 end;
403 -- delimb
404 if self.isAttachedSplitShapeMoving then
405 if #self.forwardingWheels > 0 then
406 local f = dt/1000;
407 for _,wheel in pairs(self.forwardingWheels) do
408 if wheel.node ~= nil then
409 rotate(wheel.node, wheel.rotSpeed[1]*f, wheel.rotSpeed[2]*f, wheel.rotSpeed[3]*f);
410 end;
411 end;
412 end;
413 if self.harvesterSounds.delimbSample ~= nil and self.harvesterSounds.delimbSample.sound3D ~= nil then
414 setVisibility(self.harvesterSounds.delimbSample.sound3D, true);
415 end;
416 for _,ps in pairs(self.delimbParticleSystems) do
417 self.delimbParticleSystemsActive = true;
418 Utils.setEmittingState(ps, true);
419 end;
420 else
421 if self.harvesterSounds.delimbSample ~= nil and self.harvesterSounds.delimbSample.sound3D ~= nil then
422 setVisibility(self.harvesterSounds.delimbSample.sound3D, false);
423 end;
424 for _,ps in pairs(self.delimbParticleSystems) do
425 Utils.setEmittingState(ps, false);
426 end;
427 end;
428 else -- turn all off, done in onDeactivateSounds()
429 end
430 end;
431end
432
433function WoodHarvester:updateTick(dt)
434 if self:getIsActive() then
435 self.warnInvalidTree = false;
436 self.warnInvalidTreeRadius = false;
437
438 if self:getIsTurnedOn() then
439 if self.attachedSplitShape == nil and self.cutNode ~= nil then
440 local x,y,z = getWorldTranslation(self.cutNode);
441 local nx,ny,nz = localDirectionToWorld(self.cutNode, 1,0,0);
442 local yx,yy,yz = localDirectionToWorld(self.cutNode, 0,1,0);
443
444
445 if self.curSplitShape == nil and (self.cutReleasedComponentJoint == nil or self.cutReleasedComponentJointRotLimitX == 0) then
446
447 local shape, minY, maxY, minZ, maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ);
448 if shape ~= 0 then
449 local splitType = SplitUtil.splitTypes[getSplitType(shape)];
450 if splitType == nil or not splitType.allowsWoodHarvester then
451 self.warnInvalidTree = true;
452 else
453 local treeDx,treeDy,treeDz = localDirectionToWorld(shape, 0,1,0); -- wood harvester trees always grow in the y direction
454 local cosTreeAngle = Utils.dotProduct(nx,ny,nz, treeDx,treeDy,treeDz);
455 -- Only allow cutting if the cut header is approximately parallel to the tree (70° offset)
456 if cosTreeAngle >= 0.35 then
457 local radius = math.max(maxY-minY, maxZ-minZ)*0.5 * cosTreeAngle;
458 if radius > self.cutMaxRadius then
459 self.warnInvalidTreeRadius = true;
460 else
461 self.lastDiameter = math.max(maxY-minY, maxZ-minZ);
462 self.curSplitShape = shape;
463 end
464 end
465 end
466 end
467 end
468
469 if self.curSplitShape ~= nil then
470 local minY,maxY, minZ,maxZ = testSplitShape(self.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, self.cutSizeY, self.cutSizeZ)
471 if minY == nil then
472 self.curSplitShape = nil;
473 else
474 -- check if cut would be below y=0 (tree CoSy)
475 local cutTooLow = false;
476 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,minY,minZ);
477 cutTooLow = cutTooLow or y < 0.01;
478 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,minY,maxZ);
479 cutTooLow = cutTooLow or y < 0.01;
480 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,maxY,minZ);
481 cutTooLow = cutTooLow or y < 0.01;
482 local x,y,z = localToLocal(self.cutNode, self.curSplitShape, 0,maxY,maxZ);
483 cutTooLow = cutTooLow or y < 0.01;
484 if cutTooLow then
485 self.curSplitShape = nil;
486 end;
487 end
488 end
489
490 if self.curSplitShape == nil and self.cutTimer > -1 then
491 self:onCutTree(0);
492 if g_server ~= nil then
493 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent:new(self, 0), nil, nil, self);
494 end;
495 end;
496
497 end
498 end
499
500 if self.isServer then
501 if self.attachedSplitShape == nil then
502 if self.cutReleasedComponentJoint ~= nil and self.cutReleasedComponentJointRotLimitX ~= 0 then
503 self.cutReleasedComponentJointRotLimitX = math.min(self.cutReleasedComponentJointRotLimitX+self.cutReleasedComponentJointRotLimitXSpeed*dt, 0);
504 setJointRotationLimit(self.cutReleasedComponentJoint.jointIndex, 0, true, self.cutReleasedComponentJointRotLimitX, 0);
505 end;
506 if self.cutReleasedComponentJoint2 ~= nil and self.cutReleasedComponentJoint2RotLimitX ~= 0 then
507 self.cutReleasedComponentJoint2RotLimitX = math.max(self.cutReleasedComponentJoint2RotLimitX-self.cutReleasedComponentJoint2RotLimitXSpeed*dt, 0);
508 setJointRotationLimit(self.cutReleasedComponentJoint2.jointIndex, 0, true, -self.cutReleasedComponentJoint2RotLimitX, self.cutReleasedComponentJoint2RotLimitX);
509 end;
510 end
511 end;
512 end
513
514 if self.isServer then
515 if self.playDelayedGrabAnimationTime ~= nil then
516 if self.playDelayedGrabAnimationTime < g_currentMission.time then
517 self.playDelayedGrabAnimationTime = nil;
518 if self:getAnimationTime(self.grabAnimation.name) > 0 then
519 if self.grabAnimation.name ~= nil and self.attachedSplitShape == nil then
520 self:setAnimationStopTime(self.grabAnimation.name, 0);
521 self:playAnimation(self.grabAnimation.name, -self.grabAnimation.speedScale, self:getAnimationTime(self.grabAnimation.name), false);
522 end;
523 end;
524 end;
525 end;
526 end;
527
528end
529
530function WoodHarvester:draw()
531 if self:getIsActiveForInput(true) and self:getIsTurnedOn() then
532 if self.cutNode ~= nil then
533 if self.hasAttachedSplitShape then
534 if not self.isAttachedSplitShapeMoving and self:getAnimationTime(self.cutAnimation.name) == 1 then
535 g_currentMission:addHelpButtonText(g_i18n:getText("woodHarvester_cut"), InputBinding.IMPLEMENT_EXTRA2);
536 end
537 elseif self.curSplitShape ~= nil then
538 g_currentMission:addHelpButtonText(g_i18n:getText("woodHarvester_cut"), InputBinding.IMPLEMENT_EXTRA2);
539 end
540 if not self.isAttachedSplitShapeMoving then
541 g_currentMission:addHelpButtonText(string.format(g_i18n:getText("woodHarvester_cutLength"), string.format("%.1f",self.currentCutLength)), InputBinding.IMPLEMENT_EXTRA3);
542 end;
543 if self.warnInvalidTreeRadius then
544 g_currentMission:showBlinkingWarning(g_i18n:getText("InvalidTreeDiameterWarning"), 1000);
545 elseif self.warnInvalidTree then
546 g_currentMission:showBlinkingWarning(g_i18n:getText("InvalidTreeTypeWarning"), 1000);
547 end
548 end;
549 end
550end
551
552function WoodHarvester:onDeactivate()
553 self.curSplitShape = nil;
554 self.lastDiameter = 0;
555 WoodHarvester.onDeactivateSounds(self);
556end
557
558function WoodHarvester:onDeactivateSounds()
559 if self.isClient then
560 if self.delimbParticleSystemsActive then
561 self.delimbParticleSystemsActive = false;
562 for _,ps in pairs(self.delimbParticleSystems) do
563 Utils.setEmittingState(ps, false);
564 end;
565 end;
566 if self.cutParticleSystemsActive then
567 self.cutParticleSystemsActive = false;
568 for _,ps in pairs(self.cutParticleSystems) do
569 Utils.setEmittingState(ps, false);
570 end;
571 end;
572 if self.harvesterSounds.cutSample.sound3D ~= nil then
573 setVisibility(self.harvesterSounds.cutSample.sound3D, false);
574 end;
575 if self.harvesterSounds.delimbSample.sound3D ~= nil then
576 setVisibility(self.harvesterSounds.delimbSample.sound3D, false);
577 end;
578 end;
579end
580
581function WoodHarvester:onTurnedOn(noEventSend)
582 self.playDelayedGrabAnimationTime = nil;
583 if self.grabAnimation.name ~= nil then
584 self:setAnimationStopTime(self.grabAnimation.name, 1);
585 self:playAnimation(self.grabAnimation.name, self.grabAnimation.speedScale, self:getAnimationTime(self.grabAnimation.name), true);
586 end;
587 self.sampleMotor.pitchOffset = self.sampleMotor.pitchOffset * self.motorSoundPitchOffsetFactor;
588 self.sampleMotorRun.pitchOffset = self.sampleMotorRun.pitchOffset * self.motorRunSoundPitchOffsetFactor;
589end;
590
591function WoodHarvester:onTurnedOff(noEventSend)
592 self.curSplitShape = nil;
593 self.lastDiameter = 0;
594 self.attachedSplitShape = nil;
595 self.hasAttachedSplitShape = false;
596 self.isAttachedSplitShapeMoving = false;
597 if self.attachedSplitShapeJointIndex ~= nil then
598 removeJoint(self.attachedSplitShapeJointIndex);
599 self.attachedSplitShapeJointIndex = nil;
600 end;
601 -- first open the cutter
602 self.playDelayedGrabAnimationTime = g_currentMission.time + 500;
603 if self.grabAnimation.name ~= nil and self.attachedSplitShape == nil then
604 self:setAnimationStopTime(self.grabAnimation.name, 1);
605 self:playAnimation(self.grabAnimation.name, self.grabAnimation.speedScale, self:getAnimationTime(self.grabAnimation.name), true);
606 end;
607 self.sampleMotor.pitchOffset = self.sampleMotor.pitchOffsetBackup;
608 self.sampleMotorRun.pitchOffset = self.sampleMotorRun.pitchOffsetBackup;
609end
610
611function WoodHarvester:cutTree(length, noEventSend)
612 WoodHarvesterCutTreeEvent.sendEvent(self, length, noEventSend);
613 if self.isServer then
614 if length == 0 then
615
616 if self.attachedSplitShape ~= nil or self.curSplitShape ~= nil then
617 self.cutTimer = 100;
618 if self.cutAnimation.name ~= nil then
619 self:setAnimationTime(self.cutAnimation.name, 0, true);
620 self:playAnimation(self.cutAnimation.name, self.cutAnimation.speedScale, self:getAnimationTime(self.cutAnimation.name));
621 end;
622 end;
623
624 elseif length > 0 and self.attachedSplitShape ~= nil then
625
626 self.attachedSplitShapeTargetY = self.attachedSplitShapeLastCutY + length;
627 self.delimbDistance = length;
628
629 self:onDelimbTree(true);
630 if g_server ~= nil then
631 g_server:broadcastEvent(WoodHarvesterOnDelimbTreeEvent:new(self, true), nil, nil, self);
632 end;
633
634 end;
635 end;
636
637end;
638
639function WoodHarvester:onCutTree(radius)
640 if radius > 0 then
641
642 if self.isClient then
643 if self.grabAnimation.name ~= nil then
644 local targetAnimTime = math.min( 1.0, radius / self.treeSizeMeasure.rotMaxRadius );
645
646 self:setAnimationStopTime(self.grabAnimation.name, targetAnimTime);
647 if targetAnimTime > self:getAnimationTime(self.grabAnimation.name) then
648 self:playAnimation(self.grabAnimation.name, self.grabAnimation.speedScale, self:getAnimationTime(self.grabAnimation.name), true);
649 else
650 self:playAnimation(self.grabAnimation.name, -self.grabAnimation.speedScale, self:getAnimationTime(self.grabAnimation.name), true);
651 end;
652 end;
653
654 self.lastDiameter = 2*radius;
655 end;
656
657 self.hasAttachedSplitShape = true;
658
659 else
660 if self.grabAnimation.name ~= nil then
661 self:setAnimationStopTime(self.grabAnimation.name, 1);
662 self:playAnimation(self.grabAnimation.name, self.grabAnimation.speedScale, self:getAnimationTime(self.grabAnimation.name), true);
663 end;
664 self.hasAttachedSplitShape = false;
665 self.cutTimer = -1;
666 end;
667end;
668
669function WoodHarvester:onDelimbTree(state)
670 if state then
671 self.isAttachedSplitShapeMoving = true;
672 else
673 self.isAttachedSplitShapeMoving = false;
674 self:cutTree(0);
675 end;
676end;
677
678function WoodHarvester:woodHarvesterSplitShapeCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ)
679
680 if self.attachedSplitShape == nil and isAbove and not isBelow and self.cutAttachNode ~= nil and self.cutAttachReferenceNode ~= nil then
681 self.attachedSplitShape = shape;
682
683 -- Current tree center (mid of cut area)
684 local treeCenterX,treeCenterY,treeCenterZ = localToWorld(self.cutNode, 0, (minY+maxY)*0.5, (minZ+maxZ)*0.5);
685
686 -- Target tree center (half tree size in front of the reference node)
687 local x,y,z = localToWorld(self.cutAttachReferenceNode, 0, 0, (maxZ-minZ)*0.5);
688
689 local dx,dy,dz = localDirectionToWorld(shape, 0,0,1);
690
691 local upx,upy,upz = localDirectionToWorld(self.cutAttachReferenceNode, 0,1,0);
692 local sideX,sideY,sizeZ = Utils.crossProduct(upx,upy,upz, dx,dy,dz);
693 dx,dy,dz = Utils.crossProduct(sideX,sideY,sizeZ, upx,upy,upz); -- Note: we want the up axis to be exact, thus orthogonalize the direction here
694 Utils.setWorldDirection(self.cutAttachHelperNode, dx,dy,dz, upx,upy,upz, 2);
695
696 local constr = JointConstructor:new();
697 constr:setActors(self.cutAttachNode, shape);
698 -- Note: we assume that the direction of the tree is equal to the y axis
699 constr:setJointTransforms(self.cutAttachHelperNode, shape);
700 constr:setJointWorldPositions(x,y,z, treeCenterX,treeCenterY,treeCenterZ);
701
702 constr:setRotationLimit(0, 0, 0);
703 constr:setRotationLimit(1, 0, 0);
704 constr:setRotationLimit(2, 0, 0);
705
706 constr:setEnableCollision(false);
707
708 self.attachedSplitShapeJointIndex = constr:finalize();
709
710 if self.cutReleasedComponentJoint ~= nil then
711 self.cutReleasedComponentJointRotLimitX = -math.pi*0.8;
712 setJointRotationLimit(self.cutReleasedComponentJoint.jointIndex, 0, true, self.cutReleasedComponentJointRotLimitX, 0);
713 end
714 if self.cutReleasedComponentJoint2 ~= nil then
715 self.cutReleasedComponentJoint2RotLimitX = math.pi*0.9;
716 setJointRotationLimit(self.cutReleasedComponentJoint2.jointIndex, 0, true, -self.cutReleasedComponentJoint2RotLimitX, self.cutReleasedComponentJoint2RotLimitX);
717 end
718
719 self.attachedSplitShapeX, self.attachedSplitShapeY, self.attachedSplitShapeZ = worldToLocal(shape, treeCenterX,treeCenterY,treeCenterZ);
720 self.attachedSplitShapeLastCutY = self.attachedSplitShapeY;
721 self.attachedSplitShapeStartY = self.attachedSplitShapeY;
722
723 local radius = ((maxY - minY) + (maxZ - minZ)) / 4;
724 self:onCutTree(radius);
725 if g_server ~= nil then
726 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent:new(self, radius), nil, nil, self);
727 end;
728 else
729 end
730end
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