79 | function Chainsaw:postLoad(xmlFile) |
80 | if not Chainsaw:superClass().postLoad(self, xmlFile) then |
81 | return false |
82 | end |
83 | |
84 | self.rotateInput = 0 |
85 | self.activatePressed = false |
86 | self.eventIdRotateHandtool = "" |
87 | |
88 | self.rotationZ = 0 |
89 | self.rotationSpeedZ = 0.003 |
90 | self.cutSizeY = xmlFile:getValue("handTool.chainsaw#cutSizeY", 1.1) |
91 | self.cutSizeZ = xmlFile:getValue("handTool.chainsaw#cutSizeZ", 1.0) |
92 | self.isCutting = false |
93 | self.waitingForResetAfterCut = false |
94 | self.cutNode = getChildAt(self.rootNode, 0) |
95 | self.graphicsNode = getChildAt(self.cutNode, 0) |
96 | self.chainNode = getChildAt(self.graphicsNode, 0) |
97 | self.psNode = getChildAt(self.graphicsNode, 1) |
98 | self.cutPositionNode = getChildAt(self.graphicsNode, 5) |
99 | |
100 | self.pricePerSecond = xmlFile:getValue("handTool.chainsaw.pricePerMinute", 50) / 1000 |
101 | self.quicktapThreshold = xmlFile:getValue("handTool.chainsaw#quicktapThreshold", 0.0) * 1000 |
102 | |
103 | self.minCutDistance = xmlFile:getValue("handTool.chainsaw.targetSelection#minCutDistance", 0.5) |
104 | self.maxCutDistance = xmlFile:getValue("handTool.chainsaw.targetSelection#maxCutDistance", 1.0) |
105 | self.cutDetectionDistance = xmlFile:getValue("handTool.chainsaw.targetSelection#cutDetectionDistance", 10.0) |
106 | |
107 | if self.isClient then |
108 | self.particleSystems = {} |
109 | |
110 | xmlFile:iterate("handTool.chainsaw.particleSystems.emitterShape", function(_, key) |
111 | local emitterShape = xmlFile:getValue(key.."#node", nil, self.rootNode) |
112 | local particleType = xmlFile:getValue(key.."#particleType") |
113 | |
114 | if emitterShape ~= nil then |
115 | local fillType = FillType.WOODCHIPS |
116 | local particleSystem = g_particleSystemManager:getParticleSystem(particleType) |
117 | |
118 | if particleSystem ~= nil then |
119 | local material = g_materialManager:getParticleMaterial(fillType, particleType, 1) |
120 | if material ~= nil then |
121 | ParticleUtil.setMaterial(particleSystem, material) |
122 | end |
123 | |
124 | table.insert(self.particleSystems, ParticleUtil.copyParticleSystem(xmlFile, key, particleSystem, emitterShape)) |
125 | end |
126 | end |
127 | end) |
128 | |
129 | |
130 | if #self.particleSystems == 0 then |
131 | self.particleSystems = nil |
132 | end |
133 | |
134 | self.equipmentUVs = xmlFile:getValue("handTool.chainsaw.equipment#uvs", "0 0", true) |
135 | |
136 | self.chains = g_animationManager:loadAnimations(xmlFile, "handTool.chainsaw.chain", self.rootNode, self, nil) |
137 | self.samples = {} |
138 | self.samples.start = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "start", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
139 | self.samples.idle = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "idle", self.baseDirectory, self.rootNode, 0, AudioGroup.VEHICLE, nil, nil) |
140 | self.samples.cutStart = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "cutStart", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
141 | self.samples.cutStop = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "cutStop", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
142 | self.samples.cutLoop = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "cutLoop", self.baseDirectory, self.rootNode, 0, AudioGroup.VEHICLE, nil, nil) |
143 | self.samples.activeStart = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "activeStart", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
144 | self.samples.activeStop = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "activeStop", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
145 | self.samples.activeLoop = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "activeLoop", self.baseDirectory, self.rootNode, 0, AudioGroup.VEHICLE, nil, nil) |
146 | self.samples.stop = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds", "stop", self.baseDirectory, self.rootNode, 0, AudioGroup.VEHICLE, nil, nil) |
147 | |
148 | self.samplesQuicktap = {} |
149 | local j = 0 |
150 | while true do |
151 | local sampleQuicktap = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.sounds.quickTapSounds", string.format("quickTap(%d)", j), self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
152 | if sampleQuicktap == nil then |
153 | break |
154 | end |
155 | table.insert(self.samplesQuicktap, sampleQuicktap) |
156 | j = j + 1 |
157 | end |
158 | self.samplesQuicktapCount = j |
159 | |
160 | self.samplesTree = {} |
161 | -- TODO: load more than one sample |
162 | self.samplesTree.cut = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.treeSounds", "cut", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
163 | --self.samplesTree.falling = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.treeSounds", "falling", self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
164 | self.samplesBranch = {} |
165 | local k = 0 |
166 | while true do |
167 | local sampleBranch = g_soundManager:loadSampleFromXML(xmlFile, "handTool.chainsaw.branchSounds", string.format("branch(%d)", k), self.baseDirectory, self.rootNode, 1, AudioGroup.VEHICLE, nil, nil) |
168 | if sampleBranch == nil then |
169 | break |
170 | end |
171 | table.insert(self.samplesBranch, sampleBranch) |
172 | k = k + 1 |
173 | end |
174 | self.samplesBranchCount = k |
175 | self.samplesBranchActiveTimer = 0 |
176 | |
177 | self.samplesTreeLinkNode = createTransformGroup("cutSoundLinkNode") |
178 | link(self.cutNode, self.samplesTreeLinkNode) |
179 | |
180 | if self.samplesTree.cut ~= nil and self.samplesTree.cut.soundNode ~= nil then |
181 | link(self.samplesTreeLinkNode, self.samplesTree.cut.soundNode) |
182 | --link(self.samplesTreeLinkNode, self.samplesTree.falling.soundNode) |
183 | end |
184 | |
185 | self.soundFSM = FSMUtil.create() |
186 | self.soundFSM:addState(Chainsaw.SOUND_STATES.START, ChainsawSoundStateStart.new(Chainsaw.SOUND_STATES.START, self, self.soundFSM)) |
187 | self.soundFSM:addState(Chainsaw.SOUND_STATES.STOP, ChainsawSoundStateStop.new(Chainsaw.SOUND_STATES.STOP, self, self.soundFSM)) |
188 | self.soundFSM:addState(Chainsaw.SOUND_STATES.IDLE, ChainsawSoundStateIdle.new(Chainsaw.SOUND_STATES.IDLE, self, self.soundFSM)) |
189 | self.soundFSM:addState(Chainsaw.SOUND_STATES.ACTIVE, ChainsawSoundStateActive.new(Chainsaw.SOUND_STATES.ACTIVE, self, self.soundFSM)) |
190 | self.soundFSM:addState(Chainsaw.SOUND_STATES.CUT, ChainsawSoundStateCut.new(Chainsaw.SOUND_STATES.CUT, self, self.soundFSM)) |
191 | self.soundFSM:addState(Chainsaw.SOUND_STATES.QUICKTAP, ChainsawSoundStateQuicktap.new(Chainsaw.SOUND_STATES.QUICKTAP, self, self.soundFSM)) |
192 | |
193 | self.ringSelectorScaleOffset = xmlFile:getValue("handTool.chainsaw.ringSelector#scaleOffset", 0.3) |
194 | |
195 | self.rotationNode = createTransformGroup("chainsaw_rotationNode") |
196 | link(getRootNode(), self.rotationNode) |
197 | self.chainsawCameraFocus = createTransformGroup("chainsaw_cameraFocus") |
198 | link(self.rotationNode, self.chainsawCameraFocus) |
199 | self.chainsawSplitShapeFocus = createTransformGroup("chainsaw_splitShapeFocus") |
200 | link(self.chainsawCameraFocus, self.chainsawSplitShapeFocus) |
201 | |
202 | local cutFocusOffset = xmlFile:getVector("handTool.chainsaw.cutAnimation#cutFocusOffset", "0 0 -1", 3) |
203 | setTranslation(self.chainsawSplitShapeFocus, unpack(cutFocusOffset)) |
204 | local cutFocusRotation = xmlFile:getVector("handTool.chainsaw.cutAnimation#cutFocusRotation", "0 0 0", 3) |
205 | local rotX, rotY, rotZ = unpack(cutFocusRotation) |
206 | setRotation(self.chainsawSplitShapeFocus, math.rad(rotX), math.rad(rotY), math.rad(rotZ)) |
207 | |
208 | local filename = xmlFile:getValue("handTool.chainsaw.ringSelector#file") |
209 | if filename ~= nil then |
210 | filename = Utils.getFilename(filename, self.baseDirectory) |
211 | g_i3DManager:pinSharedI3DFileInCache(filename) |
212 | self.sharedLoadRequestIdRingSelector = g_i3DManager:loadSharedI3DFileAsync(filename, false, false, self.onRingSelectorLoaded, self, self.player) |
213 | end |
214 | end |
215 | |
216 | if self.player ~= g_currentMission.player then |
217 | self.handNodePositionInCutting = xmlFile:getValue("handTool.handNode.thirdPersonCutting#position", "0 0 0", true) |
218 | self.handNodeRotationInCutting = xmlFile:getValue("handTool.handNode.thirdPersonCutting#rotation", "0 0 0", true) |
219 | self.referenceNodeInCutting = xmlFile:getValue("handTool.handNode.thirdPersonCutting#referenceNode", nil, self.rootNode) |
220 | end |
221 | |
222 | self.lastWorkTime = 0 |
223 | self.maxWorkTime = 300 |
224 | |
225 | self.moveSpeedY = 0.0001 |
226 | self.speedFactor = 0 |
227 | self.defaultCutDuration = 8.0 -- in s |
228 | self.maxTrunkWidthSq = 1.0 -- in m |
229 | self.outDuration = 0.15 -- in s |
230 | self.inDuration = 0.15 -- in s |
231 | self.cutTimer = 0.0 -- in s |
232 | self.outTimer = self.outDuration -- in s |
233 | self.transitionAlpha = 0.0 -- [0,1] |
234 | self.cameraTransitionState = Chainsaw.CAMERA_TRANSITION_STATES.NONE -- 0=in 1=cut 2=out |
235 | self.minRotationZ = math.rad(90) -- in rad |
236 | self.maxRotationZ = math.rad(-90) -- in rad |
237 | self.maxModelTranslation = 0.0 -- in m |
238 | self.cutFocusDistance = -1.0 |
239 | self.startCameraDirectionY = { 0, 1, 0 } |
240 | self.startCameraDirectionZ = { 0, 0, 1 } |
241 | self.endCameraDirectionY = { 0, 1, 0 } |
242 | self.endCameraDirectionZ = { 0, 0, 1 } |
243 | self.startChainsawPosition = { 0, 0, 0 } |
244 | self.endChainsawPosition = { 0, 0, 0 } |
245 | self.showNotOwnedWarning = false |
246 | |
247 | self.isCutting = false |
248 | self.isHorizontalCut = false |
249 | |
250 | return true |
251 | end |
595 | function Chainsaw:update(dt, allowInput) |
596 | Chainsaw:superClass().update(self, dt, allowInput) |
597 | |
598 | if self.isServer then |
599 | local price = self.pricePerSecond * (dt / 1000) |
600 | g_farmManager:getFarmById(self.player.farmId).stats:updateStats("expenses", price) |
601 | g_currentMission:addMoney(-price, self.player.farmId, MoneyType.VEHICLE_RUNNING_COSTS) |
602 | end |
603 | |
604 | -- Update camera changes to our chainsaw focus so rotation of the player affects the focus ring |
605 | local wrx, wry, wrz = getWorldRotation(self.player.cameraNode) |
606 | setWorldRotation(self.rotationNode, wrx, wry, wrz) |
607 | |
608 | if self.isClient then |
609 | if not self.isCutting then |
610 | self:updateCutRaycast() |
611 | end |
612 | |
613 | if self.showNotOwnedWarning then |
614 | g_currentMission:showBlinkingWarning(g_i18n:getText("warning_youAreNotAllowedToCutThisTree"), 2000) |
615 | self.showNotOwnedWarning = false -- reset so it can be set to true later |
616 | end |
617 | end |
618 | |
619 | self.shouldDelimb = false |
620 | |
621 | local lockPlayerInput = false |
622 | |
623 | if allowInput then |
624 | local isCutting = false |
625 | local hasBeenCut = false |
626 | |
627 | setRotation(self.graphicsNode, math.rad(math.random(-1, 1)) * 0.1, math.rad(math.random(-1, 1)) * 0.1, math.rad(-180)) |
628 | |
629 | if self.curSplitShape == nil then |
630 | lockPlayerInput = self.rotateInput ~= 0 |
631 | |
632 | -- Rotate over Z axis chainsaw based on input |
633 | if self.rotateInput ~= 0 then |
634 | self.rotationZ = MathUtil.clamp(self.rotationZ + self.rotationSpeedZ * self.rotateInput * dt, self.maxRotationZ, self.minRotationZ ) |
635 | -- Visual |
636 | setRotation(self.rootNode, self.handNodeRotation[1], self.handNodeRotation[2], self.handNodeRotation[3] -self.rotationZ) |
637 | |
638 | -- Cutting |
639 | setRotation(self.chainsawCameraFocus, 0, 0, -self.rotationZ) |
640 | end |
641 | end |
642 | |
643 | local shape = 0 |
644 | if not self.waitingForResetAfterCut then |
645 | if self.curSplitShape ~= nil or self.cutTimer == 0 then |
646 | if self.curSplitShape == nil or not entityExists(self.curSplitShape) then |
647 | self.curSplitShape = nil |
648 | |
649 | local x, y, z, nx, ny, nz, yx, yy, yz = self:getCutShapeInformation() |
650 | local minY,maxY, minZ,maxZ |
651 | shape, minY, maxY, minZ, maxZ = findSplitShape(x, y, z, nx, ny, nz, yx, yy, yz, self.cutSizeY, self.cutSizeZ) |
652 | |
653 | if shape ~= nil and shape ~= 0 then |
654 | if self:isCuttingAllowed(x, y, z, shape) then |
655 | self.showNotOwnedWarning = false |
656 | |
657 | local cutTooLow = self:testTooLow(shape, minY, maxY, minZ, maxZ) |
658 | local outsideRange = (self.cutFocusDistance < 0.0 or self.cutFocusDistance >= self.cutDetectionDistance) |
659 | |
660 | if cutTooLow or outsideRange then |
661 | self.player.walkingIsLocked = false |
662 | self.curSplitShape = nil |
663 | shape, minY,maxY, minZ,maxZ = 0, nil,nil, nil,nil |
664 | end |
665 | else |
666 | self.showNotOwnedWarning = true |
667 | end |
668 | end |
669 | self.curSplitShapeMinY = minY |
670 | self.curSplitShapeMaxY = maxY |
671 | self.curSplitShapeMinZ = minZ |
672 | self.curSplitShapeMaxZ = maxZ |
673 | else |
674 | shape = self.curSplitShape |
675 | end |
676 | |
677 | self:updateRingSelector(shape) |
678 | end |
679 | end |
680 | |
681 | if self.activatePressed then |
682 | self.speedFactor = math.min(self.speedFactor + dt/self.maxWorkTime, 1) |
683 | |
684 | if not self.waitingForResetAfterCut then |
685 | local inRange = (self.cutFocusDistance >= self.minCutDistance and self.cutFocusDistance < self.maxCutDistance) |
686 | self.shouldDelimb = inRange |
687 | |
688 | if (self.curSplitShape ~= nil or self.cutTimer == 0) and inRange then |
689 | if self.curSplitShape ~= nil and entityExists(self.curSplitShape) then |
690 | lockPlayerInput = true |
691 | local x, y, z, nx, ny, nz, yx, yy, yz = self:getCutShapeInformation() |
692 | local minY, maxY, minZ, maxZ = testSplitShape(self.curSplitShape, x, y, z, nx, ny, nz, yx, yy, yz, self.cutSizeY, self.cutSizeZ) |
693 | |
694 | if minY == nil then |
695 | -- cancel cutting if shape can't be cut anymore from current position |
696 | self.player.walkingIsLocked = false |
697 | self.curSplitShape = nil |
698 | else |
699 | local cutTooLow = self:testTooLow(self.curSplitShape, minY,maxY, minZ,maxZ) |
700 | if cutTooLow then |
701 | self.player.walkingIsLocked = false |
702 | self.curSplitShape = nil |
703 | end |
704 | end |
705 | |
706 | self.curSplitShapeMinY = minY |
707 | self.curSplitShapeMaxY = maxY |
708 | self.curSplitShapeMinZ = minZ |
709 | self.curSplitShapeMaxZ = maxZ |
710 | else |
711 | -- log("FIND SHAPE", shape) |
712 | if shape ~= 0 then |
713 | self.player.walkingIsLocked = true |
714 | self.curSplitShape = shape |
715 | end |
716 | end |
717 | |
718 | if self.curSplitShape ~= nil then |
719 | local x,y,z, nx,ny,nz, yx,yy,yz = self:getCutShapeInformation() |
720 | |
721 | if self:isCuttingAllowed(x, y, z, self.curSplitShape) then |
722 | isCutting = true |
723 | end |
724 | |
725 | if self.cutTimer > 0 then |
726 | self.lastWorkTime = math.min(self.lastWorkTime, self.maxWorkTime*0.7) |
727 | end |
728 | |
729 | local cutDuration = self:calculateCutDuration() |
730 | if self.cutTimer >= cutDuration then |
731 | if g_currentMission:getIsServer() then |
732 | ChainsawUtil.cutSplitShape(self.curSplitShape, x, y, z, nx, ny, nz, yx, yy, yz, self.cutSizeY, self.cutSizeZ, self.player.farmId) |
733 | else |
734 | g_client:getServerConnection():sendEvent(ChainsawCutEvent.new(self.curSplitShape, x, y, z, nx, ny, nz, yx, yy, yz, self.cutSizeY, self.cutSizeZ, self.player.farmId)) |
735 | end |
736 | |
737 | hasBeenCut = true |
738 | self.waitingForResetAfterCut = true |
739 | self.player.walkingIsLocked = false |
740 | self.curSplitShape = nil |
741 | self.curSplitShapeMinY = nil |
742 | self:updateRingSelector(0) |
743 | end |
744 | end |
745 | end |
746 | end |
747 | else |
748 | self.speedFactor = math.max(self.speedFactor - dt / self.maxWorkTime, 0) |
749 | self.waitingForResetAfterCut = false |
750 | self.player.walkingIsLocked = false |
751 | self.curSplitShape = nil |
752 | self.curSplitShapeMinY = nil |
753 | self.lastWorkTime = math.max(self.lastWorkTime - dt, 0) |
754 | self.workUpPlayed = false |
755 | end |
756 | |
757 | self.player:lockInput(lockPlayerInput) |
758 | |
759 | self:updateCuttingTimers(dt, isCutting) |
760 | self:updateCuttingCamera(isCutting) |
761 | self:updateChainsawModel(isCutting) |
762 | self:updateDelimb() |
763 | self:setCutting(isCutting, self.rotationZ > 0.7, hasBeenCut) |
764 | end |
765 | self.soundFSM:update(dt) |
766 | self:updateParticles() |
767 | |
768 | self.rotateInput = 0 |
769 | self.activatePressed = false |
770 | end |
522 | function Chainsaw:updateChainsawModel(isCutting) |
523 | local currentPos = {getWorldTranslation(self.graphicsNode)} |
524 | |
525 | if isCutting then |
526 | local startPos = {} |
527 | local endPos = {} |
528 | startPos[1], startPos[2], startPos[3], endPos[1], endPos[2], endPos[3] = self:getCutStartEnd() |
529 | |
530 | if self.cameraTransitionState == Chainsaw.CAMERA_TRANSITION_STATES.IN then |
531 | self.startChainsawPosition = currentPos |
532 | self.endChainsawPosition = startPos |
533 | elseif self.cameraTransitionState == Chainsaw.CAMERA_TRANSITION_STATES.CUT then |
534 | self.startChainsawPosition = startPos |
535 | self.endChainsawPosition = endPos |
536 | end |
537 | else |
538 | if self.cameraTransitionState == Chainsaw.CAMERA_TRANSITION_STATES.OUT then |
539 | self.startChainsawPosition = currentPos |
540 | setTranslation(self.graphicsNode, 0, 0, 0) |
541 | self.endChainsawPosition = {getWorldTranslation(self.graphicsNode)} |
542 | end |
543 | end |
544 | |
545 | if isCutting or self.outTimer < self.outDuration then |
546 | local smoothPosition = { MathUtil.lerp( self.startChainsawPosition[1], self.endChainsawPosition[1], self.transitionAlpha ), |
547 | MathUtil.lerp( self.startChainsawPosition[2], self.endChainsawPosition[2], self.transitionAlpha ), |
548 | MathUtil.lerp( self.startChainsawPosition[3], self.endChainsawPosition[3], self.transitionAlpha )} |
549 | local offset = {localToLocal(self.cutPositionNode, self.graphicsNode, 0,0,0)} |
550 | local cutDirection = {localDirectionToWorld(self.ringSelector, 0, 0, offset[3])} |
551 | local destination = {smoothPosition[1] - cutDirection[1], smoothPosition[2] - cutDirection[2], smoothPosition[3] - cutDirection[3]} |
552 | local modelTranslation = {worldToLocal(getParent(self.graphicsNode), destination[1], destination[2], destination[3])} |
553 | local distance = MathUtil.vector3Length(modelTranslation[1], modelTranslation[2], modelTranslation[3]) |
554 | |
555 | if distance > self.maxModelTranslation then |
556 | modelTranslation = {MathUtil.vector3Normalize(modelTranslation[1], modelTranslation[2], modelTranslation[3])} |
557 | modelTranslation = {modelTranslation[1]*self.maxModelTranslation, modelTranslation[2]*self.maxModelTranslation, modelTranslation[3]*self.maxModelTranslation} |
558 | local screen = { project(destination[1], destination[2], destination[3]) } |
559 | setTranslation(self.graphicsNode, modelTranslation[1], modelTranslation[2], modelTranslation[3]) |
560 | local graph = {getWorldTranslation(self.graphicsNode)} |
561 | local screen2 = { project(graph[1], graph[2], graph[3]) } |
562 | local world2 = { unProject(screen[1], screen[2], screen2[3]) } |
563 | |
564 | setWorldTranslation(self.graphicsNode, world2[1], world2[2], world2[3]) |
565 | else |
566 | setTranslation(self.graphicsNode, modelTranslation[1], modelTranslation[2], modelTranslation[3]) |
567 | end |
568 | else |
569 | setTranslation(self.graphicsNode, 0, 0, 0) |
570 | end |
571 | end |
461 | function Chainsaw:updateCuttingCamera(isCutting) |
462 | -- if isCutting then |
463 | -- if self.cameraTransitionState == Chainsaw.CAMERA_TRANSITION_STATES.IN then |
464 | -- setRotation(self.player.model.cuttingCameraNode, 0, 0, 0) |
465 | -- local yx, yy, yz = localDirectionToWorld(self.player.model.cuttingCameraNode, 0, 1, 0) |
466 | -- local zx, zy, zz = localDirectionToWorld(self.player.model.cuttingCameraNode, 0, 0, 1) |
467 | -- local startX, startY, startZ, _, _, _ = self:getCutStartEnd() |
468 | |
469 | -- self.startCameraDirectionY = {yx, yy, yz} |
470 | -- self.startCameraDirectionZ = {zx, zy, zz} |
471 | -- self.endCameraDirectionY[1], self.endCameraDirectionY[2], self.endCameraDirectionY[3], |
472 | -- self.endCameraDirectionZ[1], self.endCameraDirectionZ[2], self.endCameraDirectionZ[3] = self:getLookAt(self.player.model.cuttingCameraNode, startX, startY, startZ) |
473 | -- elseif self.cameraTransitionState == Chainsaw.CAMERA_TRANSITION_STATES.CUT then |
474 | -- local startX, startY, startZ, endX, endY, endZ = self:getCutStartEnd() |
475 | |
476 | -- self.startCameraDirectionY[1], self.startCameraDirectionY[2], self.startCameraDirectionY[3], |
477 | -- self.startCameraDirectionZ[1], self.startCameraDirectionZ[2], self.startCameraDirectionZ[3] = self:getLookAt(self.player.model.cuttingCameraNode, startX, startY, startZ) |
478 | -- self.endCameraDirectionY[1], self.endCameraDirectionY[2], self.endCameraDirectionY[3], |
479 | -- self.endCameraDirectionZ[1], self.endCameraDirectionZ[2], self.endCameraDirectionZ[3] = self:getLookAt(self.player.model.cuttingCameraNode, endX, endY, endZ) |
480 | -- end |
481 | -- else |
482 | -- if self.cameraTransitionState == Chainsaw.CAMERA_TRANSITION_STATES.OUT then |
483 | -- local yx, yy, yz = localDirectionToWorld(self.player.model.cuttingCameraNode, 0, 1, 0) |
484 | -- local zx, zy, zz = localDirectionToWorld(self.player.model.cuttingCameraNode, 0, 0, 1) |
485 | -- self.startCameraDirectionY = {yx, yy, yz} |
486 | -- self.startCameraDirectionZ = {zx, zy, zz} |
487 | -- setRotation(self.player.cuttingCameraNode, 0, 0, 0) |
488 | -- yx, yy, yz = localDirectionToWorld(self.player.model.cuttingCameraNode, 0, 1, 0) |
489 | -- zx, zy, zz = localDirectionToWorld(self.player.model.cuttingCameraNode, 0, 0, 1) |
490 | -- self.endCameraDirectionY = {yx, yy, yz} |
491 | -- self.endCameraDirectionZ = {zx, zy, zz} |
492 | -- end |
493 | -- end |
494 | |
495 | -- local currentCamera = getCamera() |
496 | -- if isCutting or self.outTimer < self.outDuration then |
497 | -- if (currentCamera ~= self.player.model.cuttingCameraNode) then |
498 | -- setCamera(self.player.model.cuttingCameraNode) |
499 | -- end |
500 | |
501 | -- local smoothDirY = { MathUtil.lerp(self.startCameraDirectionY[1], self.endCameraDirectionY[1], self.transitionAlpha), |
502 | -- MathUtil.lerp(self.startCameraDirectionY[2], self.endCameraDirectionY[2], self.transitionAlpha), |
503 | -- MathUtil.lerp(self.startCameraDirectionY[3], self.endCameraDirectionY[3], self.transitionAlpha) } |
504 | -- local smoothDirZ = { MathUtil.lerp(self.startCameraDirectionZ[1], self.endCameraDirectionZ[1], self.transitionAlpha), |
505 | -- MathUtil.lerp(self.startCameraDirectionZ[2], self.endCameraDirectionZ[2], self.transitionAlpha), |
506 | -- MathUtil.lerp(self.startCameraDirectionZ[3], self.endCameraDirectionZ[3], self.transitionAlpha) } |
507 | |
508 | -- smoothDirY = { worldDirectionToLocal(getParent(self.player.model.cuttingCameraNode), smoothDirY[1], smoothDirY[2], smoothDirY[3]) } |
509 | -- smoothDirZ = { worldDirectionToLocal(getParent(self.player.model.cuttingCameraNode), smoothDirZ[1], smoothDirZ[2], smoothDirZ[3]) } |
510 | -- setDirection(self.player.model.cuttingCameraNode, smoothDirZ[1], smoothDirZ[2], smoothDirZ[3], smoothDirY[1], smoothDirY[2], smoothDirY[3]) |
511 | -- else |
512 | -- if (currentCamera ~= self.player.cameraNode) then |
513 | -- setRotation(self.player.model.cuttingCameraNode, 0, 0, 0) |
514 | -- setCamera(self.player.cameraNode) |
515 | -- end |
516 | -- end |
517 | end |
827 | function Chainsaw:updateRingSelector(shape) |
828 | if self.ringSelector ~= nil then |
829 | local hasShape = (shape ~= nil) and (shape ~= 0) |
830 | |
831 | if g_woodCuttingMarkerEnabled and hasShape then |
832 | local inDetectionRange = false |
833 | local inCutRange = false |
834 | |
835 | if self.cutFocusDistance ~= nil and (self.cutFocusDistance >= 0.0 and self.cutFocusDistance < self.cutDetectionDistance) then |
836 | inDetectionRange = true |
837 | inCutRange = (self.cutFocusDistance >= self.minCutDistance and self.cutFocusDistance < self.maxCutDistance) |
838 | end |
839 | |
840 | if not getVisibility(self.ringSelector) and inDetectionRange then |
841 | local x, y, z = getWorldTranslation(self.ringSelector) |
842 | if self:isCuttingAllowed(x, y, z, shape) then |
843 | setVisibility(self.ringSelector, true) |
844 | else |
845 | setVisibility(self.ringSelector, false) |
846 | end |
847 | elseif getVisibility(self.ringSelector) and not inDetectionRange then |
848 | setVisibility(self.ringSelector, false) |
849 | end |
850 | |
851 | if getVisibility(self.ringSelector) then |
852 | if inCutRange then |
853 | setShaderParameter(self.ringSelector, "colorScale", 0.395, 0.925, 0.115, 1, false) |
854 | else |
855 | setShaderParameter(self.ringSelector, "colorScale", 0.098, 0.450, 0.960, 1, false) |
856 | end |
857 | |
858 | if self.curSplitShapeMinY ~= nil then |
859 | local scale = math.max(self.curSplitShapeMaxY - self.curSplitShapeMinY + self.ringSelectorScaleOffset, self.curSplitShapeMaxZ-self.curSplitShapeMinZ + self.ringSelectorScaleOffset) |
860 | setScale(self.ringSelector, 1, scale, scale) |
861 | |
862 | local a,b,c = localToWorld(self.chainsawSplitShapeFocus, 0, (self.curSplitShapeMinY+self.curSplitShapeMaxY)*0.5, (self.curSplitShapeMinZ+self.curSplitShapeMaxZ)*0.5) |
863 | local x, y, z = worldToLocal(getParent(self.ringSelector), a,b,c) |
864 | setTranslation(self.ringSelector, x,y,z) |
865 | else |
866 | setScale(self.ringSelector, 1, 1, 1) |
867 | end |
868 | end |
869 | else |
870 | setVisibility(self.ringSelector, false) |
871 | end |
872 | end |
873 | end |