LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

PushHandTool

Functions

customVehicleCharacterLoaded

Description
Definition
customVehicleCharacterLoaded()
Code
444function PushHandTool:customVehicleCharacterLoaded(success, arguments)
445 local enterableSpec = self.spec_enterable
446 if success then
447 local character = enterableSpec.vehicleCharacter
448 if character ~= nil then
449 character:updateVisibility()
450 -- do not initial update the IK chains, so the character keeps the T pose while setting up the ik solver below
451 end
452
453 SpecializationUtil.raiseEvent(self, "onVehicleCharacterChanged", character)
454
455 local spec = self.spec_pushHandTool
456
457 spec.characterIKNodes = {}
458
459 for name, ikChain in pairs(character.playerModel.ikChains) do
460 if spec.ikChainTargets[name] ~= nil then
461 for k, nodeData in pairs(ikChain.nodes) do
462 if spec.characterIKNodes[nodeData.node] == nil then
463 local duplicate = createTransformGroup(getName(nodeData.node) .. "_ikChain")
464
465 local parent = getParent(nodeData.node)
466 if spec.characterIKNodes[parent] ~= nil then
467 parent = spec.characterIKNodes[parent]
468 end
469
470 link(parent, duplicate)
471 setTranslation(duplicate, getTranslation(nodeData.node))
472 setRotation(duplicate, getRotation(nodeData.node))
473
474 spec.characterIKNodes[nodeData.node] = duplicate
475 end
476 end
477 end
478
479 for k, nodeData in pairs(ikChain.nodes) do
480 if spec.characterIKNodes[nodeData.node] ~= nil then
481 nodeData.node = spec.characterIKNodes[nodeData.node]
482 end
483 end
484 end
485
486 character.ikChainTargets = spec.ikChainTargets
487 for ikChainId, target in pairs(spec.ikChainTargets) do
488 IKUtil.setTarget(character.playerModel.ikChains, ikChainId, target)
489 end
490
491 spec.ikChains = character.playerModel.ikChains
492
493 for name, ikChain in pairs(character.playerModel.ikChains) do
494 ikChain.ikChainSolver = IKChain.new(#ikChain.nodes)
495 for i, node in ipairs(ikChain.nodes) do
496 local minRx, maxRx, minRy, maxRy, minRz, maxRz, damping, localLimits = node.minRx, node.maxRx, node.minRy, node.maxRy, node.minRz, node.maxRz, node.damping, node.localLimits
497
498 for j=1, #spec.customChainLimits do
499 local customLimit = spec.customChainLimits[j]
500 if customLimit.chainId == name and customLimit.nodeIndex == i then
501 minRx = customLimit.minRx or minRx
502 maxRx = customLimit.maxRx or maxRx
503 minRy = customLimit.minRy or minRy
504 maxRy = customLimit.maxRy or maxRy
505 minRz = customLimit.minRz or minRz
506 maxRz = customLimit.maxRz or maxRz
507 damping = customLimit.damping or damping
508
509 if customLimit.localLimits ~= nil then
510 localLimits = customLimit.localLimits
511 end
512 end
513 end
514
515 ikChain.ikChainSolver:setJointTransformGroup(i-1, node.node, minRx, maxRx, minRy, maxRy, minRz, maxRz, damping, localLimits)
516 end
517
518 ikChain.numIterations = 40
519 ikChain.positionThreshold = 0.0001
520 end
521
522 character:setDirty()
523
524 if character ~= nil and character.animationCharsetId ~= nil and character.animationPlayer ~= nil then
525 for key, parameter in pairs(spec.animationParameters) do
526 conditionalAnimationRegisterParameter(character.animationPlayer, parameter.id, parameter.type, key)
527 end
528 initConditionalAnimation(character.animationPlayer, character.animationCharsetId, self.configFileName, "vehicle.pushHandTool.playerConditionalAnimation")
529
530 conditionalAnimationZeroiseTrackTimes(character.animationPlayer)
531 end
532
533 IKUtil.updateAlignNodes(character.playerModel.ikChains, self.getParentComponent, self)
534 end
535end

getAllowCharacterVisibilityUpdate

Description
Definition
getAllowCharacterVisibilityUpdate()
Code
539function PushHandTool:getAllowCharacterVisibilityUpdate(superFunc)
540 if not superFunc(self) then
541 return false
542 end
543
544 if self:getIsEntered() then
545 local activeCamera = self:getActiveCamera()
546 if activeCamera ~= nil then
547 if activeCamera.isInside then
548 return false
549 end
550 end
551 end
552
553 local spec = self.spec_pushHandTool
554 if not spec.raycastsValid then
555 return false
556 end
557
558 return true
559end

getCanStartAIVehicle

Description
Definition
getCanStartAIVehicle()
Code
587function PushHandTool:getCanStartAIVehicle(superFunc)
588 return false
589end

getRaycastPosition

Description
Definition
getRaycastPosition()
Code
713function PushHandTool:getRaycastPosition(node)
714 local spec = self.spec_pushHandTool
715 local x, y, z = getWorldTranslation(node)
716 local dirX, dirY, dirZ = localDirectionToWorld(node, 0, -1, 0)
717 dirY = dirY * 1.5 -- raycast a bit more straight along world Y so the player is moved a bit away from slope
718
719 spec.lastRaycastHit = false
720 raycastAll(x, y, z, dirX, dirY, dirZ, "playerRaycastCallback", 2, self, PushHandTool.PLAYER_COLLISION_MASK)
721 if spec.lastRaycastHit and spec.lastRaycastPosition[4] > 0.35 and spec.lastRaycastPosition[2] < y - 0.25 then
722 return unpack(spec.lastRaycastPosition)
723 end
724
725 return nil
726end

initSpecialization

Description
Definition
initSpecialization()
Code
19function PushHandTool.initSpecialization()
20 local schema = Vehicle.xmlSchema
21 schema:setXMLSpecializationType("PushHandTool")
22
23 schema:register(XMLValueType.NODE_INDEX, "vehicle.pushHandTool.raycast#node1", "Front raycast node")
24 schema:register(XMLValueType.NODE_INDEX, "vehicle.pushHandTool.raycast#node2", "Back raycast node")
25 schema:register(XMLValueType.NODE_INDEX, "vehicle.pushHandTool.raycast#playerNode", "Player node to adjust")
26
27 schema:register(XMLValueType.VECTOR_N, "vehicle.pushHandTool.wheels#front", "Indices of front wheels")
28 schema:register(XMLValueType.VECTOR_N, "vehicle.pushHandTool.wheels#back", "Indices of back wheels")
29
30 schema:register(XMLValueType.NODE_INDEX, "vehicle.pushHandTool.handle#node", "Handle node")
31 schema:register(XMLValueType.FLOAT, "vehicle.pushHandTool.handle#upperLimit", "Max. upper distance between handle node and hand ik root node", 0.4)
32 schema:register(XMLValueType.FLOAT, "vehicle.pushHandTool.handle#lowerLimit", "Max. lower distance between handle node and hand ik root node", 0.4)
33 schema:register(XMLValueType.FLOAT, "vehicle.pushHandTool.handle#interpolateDistance", "Interpolation distance if limit is exceeded", 0.4)
34 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.handle#minRot", "Min. rotation of handle", -20)
35 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.handle#maxRot", "Max. rotation of handle", 20)
36
37 IKUtil.registerIKChainTargetsXMLPaths(schema, "vehicle.pushHandTool.ikChains")
38 EffectManager.registerEffectXMLPaths(schema, "vehicle.pushHandTool.effect")
39
40 schema:register(XMLValueType.STRING, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#chainId", "Chain identifier string", 20)
41 schema:register(XMLValueType.INT, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#nodeIndex", "Index of node")
42 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#minRx", "Min. X rotation")
43 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#maxRx", "Max. X rotation")
44 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#minRy", "Min. Y rotation")
45 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#maxRy", "Max. Y rotation")
46 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#minRz", "Min. Z rotation")
47 schema:register(XMLValueType.ANGLE, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#maxRz", "Max. Z rotation")
48 schema:register(XMLValueType.FLOAT, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#damping", "Damping")
49 schema:register(XMLValueType.BOOL, "vehicle.pushHandTool.customChainLimits.customChainLimit(?)#localLimits", "Local limits")
50
51 -- values loaded only by engine, registration just for documentation/validation purposes
52 local registerConditionalAnimation = function(xmlKey)
53 schema:register(XMLValueType.STRING, xmlKey .. ".item(?)#id", "")
54 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?)#entryTransitionDuration", "")
55 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?)#exitTransitionDuration", "")
56
57 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips#speedScaleType", "")
58 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).clips#speedScaleParameter", "")
59 schema:register(XMLValueType.BOOL, xmlKey .. ".item(?).clips#blended", "")
60 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips#blendingParameter", "")
61 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips#blendingParameterType", "")
62 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips.clip(?)#clipName", "")
63 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips.clip(?)#id", "")
64 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).clips.clip(?)#blendingThreshold", "")
65
66 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#parameter", "")
67 schema:register(XMLValueType.BOOL, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#equal", "")
68 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#between", "")
69 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#greater", "")
70 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#lower", "")
71 end
72
73 registerConditionalAnimation("vehicle.pushHandTool.playerConditionalAnimation")
74
75 schema:setXMLSpecializationType()
76end

onCameraChanged

Description
Definition
onCameraChanged()
Code
626function PushHandTool:onCameraChanged(activeCamera, camIndex)
627 if self:getIsEntered() then
628 local character = self:getVehicleCharacter()
629 if character ~= nil then
630 if activeCamera.isInside then
631 character:setCharacterVisibility(false)
632 end
633 end
634 end
635end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
207function PushHandTool:onDelete()
208 local spec = self.spec_pushHandTool
209 g_effectManager:deleteEffects(spec.cutterEffects)
210
211 removePostAnimationCallback(spec.postAnimationCallback)
212end

onEnterVehicle

Description
Definition
onEnterVehicle()
Code
593function PushHandTool:onEnterVehicle(isControlling)
594 local hideCharacter = false
595 if isControlling then
596 local activeCamera = self:getActiveCamera()
597 if activeCamera ~= nil then
598 if activeCamera.isInside then
599 hideCharacter = true
600 end
601 end
602 end
603
604 local spec = self.spec_pushHandTool
605 if not spec.raycastsValid then
606 hideCharacter = true
607 end
608
609 if hideCharacter then
610 local character = self:getVehicleCharacter()
611 if character ~= nil then
612 character:setCharacterVisibility(false)
613 end
614 end
615end

onLeaveVehicle

Description
Definition
onLeaveVehicle()
Code
619function PushHandTool:onLeaveVehicle()
620 local spec = self.spec_pushHandTool
621 spec.characterIKNodes = {}
622end

onLoad

Description
Definition
onLoad()
Code
119function PushHandTool:onLoad(savegame)
120 local spec = self.spec_pushHandTool
121
122 spec.animationParameters = {}
123 spec.animationParameters.absSmoothedForwardVelocity = {id=1, value=0.0, type=1}
124 spec.animationParameters.smoothedForwardVelocity = {id=2, value=0.0, type=1}
125 spec.animationParameters.accelerate = {id=3, value=false, type=0}
126 spec.animationParameters.leftRightWeight = {id=4, value=0.0, type=1}
127
128
129 spec.raycastNode1 = self.xmlFile:getValue("vehicle.pushHandTool.raycast#node1", nil, self.components, self.i3dMappings)
130 spec.raycastNode2 = self.xmlFile:getValue("vehicle.pushHandTool.raycast#node2", nil, self.components, self.i3dMappings)
131 spec.playerNode = self.xmlFile:getValue("vehicle.pushHandTool.raycast#playerNode", nil, self.components, self.i3dMappings)
132 spec.playerTargetNode = createTransformGroup("playerTargetNode")
133 if spec.playerNode ~= nil then
134 link(getParent(spec.playerNode), spec.playerTargetNode)
135 setTranslation(spec.playerTargetNode, getTranslation(spec.playerNode))
136 end
137
138 local frontWheels = self.xmlFile:getValue("vehicle.pushHandTool.wheels#front", nil, true)
139 spec.frontWheels = {}
140 for i=1, #frontWheels do
141 local wheel = self:getWheelFromWheelIndex(frontWheels[i])
142 if wheel ~= nil then
143 table.insert(spec.frontWheels, wheel)
144 end
145 end
146
147 local backWheels = self.xmlFile:getValue("vehicle.pushHandTool.wheels#back", nil, true)
148 spec.backWheels = {}
149 for i=1, #backWheels do
150 local wheel = self:getWheelFromWheelIndex(backWheels[i])
151 if wheel ~= nil then
152 table.insert(spec.backWheels, wheel)
153 end
154 end
155
156 spec.handle = {}
157 spec.handle.node = self.xmlFile:getValue("vehicle.pushHandTool.handle#node", nil, self.components, self.i3dMappings)
158 spec.handle.upperLimit = self.xmlFile:getValue("vehicle.pushHandTool.handle#upperLimit", 0.4)
159 spec.handle.lowerLimit = self.xmlFile:getValue("vehicle.pushHandTool.handle#lowerLimit", 0.4)
160 spec.handle.interpolateDistance = self.xmlFile:getValue("vehicle.pushHandTool.handle#interpolateDistance", 0.4)
161 spec.handle.minRot = self.xmlFile:getValue("vehicle.pushHandTool.handle#minRot", -20)
162 spec.handle.maxRot = self.xmlFile:getValue("vehicle.pushHandTool.handle#maxRot", 20)
163
164 spec.characterIKNodes = {}
165 spec.ikChainTargets = {}
166 IKUtil.loadIKChainTargets(self.xmlFile, "vehicle.pushHandTool.ikChains", self.components, spec.ikChainTargets, self.i3dMappings)
167
168 spec.lastRaycastPosition = {0, 0, 0, 0}
169 spec.lastRaycastHit = false
170
171 if self.isClient then
172 spec.cutterEffects = g_effectManager:loadEffect(self.xmlFile, "vehicle.pushHandTool.effect", self.components, self, self.i3dMappings)
173 end
174
175 spec.customChainLimits = {}
176 self.xmlFile:iterate("vehicle.pushHandTool.customChainLimits.customChainLimit", function(index, key)
177 local entry = {}
178 entry.chainId = self.xmlFile:getValue(key .. "#chainId")
179 entry.nodeIndex = self.xmlFile:getValue(key .. "#nodeIndex")
180
181 if entry.chainId ~= nil and entry.nodeIndex ~= nil then
182 entry.minRx = self.xmlFile:getValue(key .. "#minRx")
183 entry.maxRx = self.xmlFile:getValue(key .. "#maxRx")
184 entry.minRy = self.xmlFile:getValue(key .. "#minRy")
185 entry.maxRy = self.xmlFile:getValue(key .. "#maxRy")
186 entry.minRz = self.xmlFile:getValue(key .. "#minRz")
187 entry.maxRz = self.xmlFile:getValue(key .. "#maxRz")
188 entry.damping = self.xmlFile:getValue(key .. "#damping")
189 entry.localLimits = self.xmlFile:getValue(key .. "#localLimits")
190
191 table.insert(spec.customChainLimits, entry)
192 end
193 end)
194
195 spec.effectDirtyFlag = self:getNextDirtyFlag()
196
197 spec.raycastsValid = true
198 spec.lastSmoothSpeed = 0
199
200 self:setTestAreaRequirements(FruitType.GRASS, nil, false)
201
202 spec.postAnimationCallback = addPostAnimationCallback(self.postAnimationUpdate, self)
203end

onUpdate

Description
Called on on update
Definition
onUpdate(float dt, bool isActiveForInput, bool isSelected)
Arguments
floatdtdelta time
boolisActiveForInputtrue if specializations is active for input
boolisSelectedtrue if specializations is selected
Code
219function PushHandTool:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
220 local spec = self.spec_pushHandTool
221
222 if self:getIsTurnedOn() and self:getLastSpeed() > 0.5 then
223 local currentTestAreaMinX, currentTestAreaMaxX, testAreaMinX, testAreaMaxX = self:getTestAreaWidthByWorkAreaIndex(1)
224
225 local reset = false
226 if currentTestAreaMinX == math.huge and currentTestAreaMaxX == -math.huge then
227 currentTestAreaMinX = 0
228 currentTestAreaMaxX = 0
229 reset = true
230 end
231
232 if spec.movingDirection > 0 then
233 currentTestAreaMinX = currentTestAreaMinX * -1
234 currentTestAreaMaxX = currentTestAreaMaxX * -1
235 if currentTestAreaMaxX < currentTestAreaMinX then
236 local t = currentTestAreaMinX
237 currentTestAreaMinX = currentTestAreaMaxX
238 currentTestAreaMaxX = t
239 end
240 end
241
242 if self.isClient then
243 local inputFruitType, inputGrowthState = FruitType.UNKNOWN, 3
244 if self.spec_mower ~= nil then
245 local specMower = self.spec_mower
246 if g_time - specMower.workAreaParameters.lastCutTime < 500 then
247 inputFruitType = specMower.workAreaParameters.lastInputFruitType
248 inputGrowthState = specMower.workAreaParameters.lastInputGrowthState
249 end
250 end
251
252 if inputFruitType ~= nil and inputFruitType ~= FruitType.UNKNOWN then
253 g_effectManager:setFruitType(spec.cutterEffects, inputFruitType, inputGrowthState)
254 g_effectManager:setMinMaxWidth(spec.cutterEffects, currentTestAreaMinX, currentTestAreaMaxX, currentTestAreaMinX / testAreaMinX, currentTestAreaMaxX / testAreaMaxX, reset)
255 g_effectManager:startEffects(spec.cutterEffects)
256 spec.effectsAreRunning = not reset
257 else
258 if spec.effectsAreRunning then
259 g_effectManager:stopEffects(spec.cutterEffects)
260 spec.effectsAreRunning = false
261 end
262 end
263 end
264 else
265 if spec.effectsAreRunning then
266 g_effectManager:stopEffects(spec.cutterEffects)
267 spec.effectsAreRunning = false
268 end
269 end
270
271 local lastSpeed = self.lastSignedSpeed * 1000.0
272
273 local avgSpeed = 0
274 local numWheels = 0
275 for _, wheel in pairs(spec.backWheels) do
276 if wheel.netInfo.xDriveSpeed ~= nil then
277 local wheelSpeed = MathUtil.rpmToMps(wheel.netInfo.xDriveSpeed / (2*math.pi) * 60, wheel.radius) * 1000
278 avgSpeed = avgSpeed + wheelSpeed
279 numWheels = numWheels + 1
280 end
281 end
282
283 if numWheels > 0 then
284 lastSpeed = avgSpeed / numWheels
285 end
286
287 spec.lastSmoothSpeed = spec.lastSmoothSpeed * 0.9 + lastSpeed * 0.1
288
289 spec.animationParameters.smoothedForwardVelocity.value = spec.lastSmoothSpeed
290 spec.animationParameters.absSmoothedForwardVelocity.value = math.abs(spec.lastSmoothSpeed)
291 spec.animationParameters.leftRightWeight.value = self.rotatedTime
292
293 spec.animationParameters.accelerate.value = self:getAccelerationAxis() > 0
294
295 if self:getIsEntered() or self:getIsControlled() then
296 local character = self:getVehicleCharacter()
297 if character ~= nil and character.animationCharsetId ~= nil and character.animationPlayer ~= nil then
298 for _, parameter in pairs(spec.animationParameters) do
299 if parameter.type == 0 then
300 setConditionalAnimationBoolValue(character.animationPlayer, parameter.id, parameter.value)
301 elseif parameter.type == 1 then
302 setConditionalAnimationFloatValue(character.animationPlayer, parameter.id, parameter.value)
303 end
304 end
305
306 setConditionalAnimationSpecificParameterIds(character.animationPlayer, spec.animationParameters.absSmoothedForwardVelocity.id, 0)
307
308 updateConditionalAnimation(character.animationPlayer, dt)
309
310 --local x,y,z = getWorldTranslation(self.rootNode)
311 --conditionalAnimationDebugDraw(character.animationPlayer, x,y,z)
312 end
313 end
314
315
316 if spec.raycastNode1 ~= nil and spec.raycastNode2 ~= nil and spec.playerNode ~= nil and #spec.frontWheels >= 1 and #spec.backWheels >= 1 then
317 local x1, y1, z1 = self:getRaycastPosition(spec.raycastNode1)
318 local x2, y2, z2 = self:getRaycastPosition(spec.raycastNode2)
319 --#debug drawDebugLine(x1, y1, z1, 0, 1, 0, x2, y2, z2, 0, 1, 0)
320
321 if x1 ~= nil and x2 ~= nil then
322 local tx, ty, tz = (x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5
323 setWorldTranslation(spec.playerTargetNode, tx, ty, tz)
324
325 local dirX, dirY, dirZ = x1-x2, y1-y2, z1-z2
326 dirX, dirY, dirZ = MathUtil.vector3Normalize(dirX, dirY, dirZ)
327
328 -- smoothly blend Y direction when raycasts is hitting a small step
329 if spec.lastYDirection == nil then
330 spec.lastYDirection = dirY
331 else
332 dirY = spec.lastYDirection * 0.9 + dirY * 0.1
333 spec.lastYDirection = dirY
334 end
335
336 I3DUtil.setWorldDirection(spec.playerTargetNode, dirX, dirY, dirZ, 0, 1, 0)
337
338 --#debug drawDebugLine(tx, ty, tz, 0, 1, 0, tx+dirX*4, ty+dirY*4, tz+dirZ*4, 0, 1, 0)
339 --#debug DebugUtil.drawDebugNode(spec.playerTargetNode, "", false)
340
341 if spec.lastWorldTrans == nil then
342 spec.lastWorldTrans = {getWorldTranslation(spec.playerNode)}
343 end
344 local cx, cy, cz = spec.lastWorldTrans[1],spec.lastWorldTrans[2], spec.lastWorldTrans[3]
345
346 local smoothFactor = 0.5 - math.abs(math.min(self.rotatedTime / 0.5), 1) * 0.15
347 local moveX, moveY, moveZ = (cx - tx) * smoothFactor, (cy - ty) * smoothFactor, (cz - tz) * smoothFactor
348
349 local newX, newY, newZ = cx - moveX, cy - moveY, cz - moveZ
350 setWorldTranslation(spec.playerNode, newX, newY, newZ)
351
352 spec.lastWorldTrans[1], spec.lastWorldTrans[2], spec.lastWorldTrans[3] = newX, newY, newZ
353
354 local direction = self.movingDirection
355 if direction == 0 then
356 direction = 1
357 end
358
359 -- use direction from last player point to the current target node
360 tx, ty, tz = localToWorld(spec.playerTargetNode, 0, 0, 0.2 * direction)
361 local dirY2, _
362 dirX, dirY2, dirZ = tx-newX, ty-newY, tz-newZ
363 dirX, _, dirZ = MathUtil.vector3Normalize(dirX, dirY2, dirZ)
364 if direction < 0 then
365 dirX, dirZ = -dirX, -dirZ
366 end
367
368 -- calculate direction of the tool based on the wheels
369 local fcx, fcy, fcz = 0, 0, 0
370 local numFrontWheels = #spec.frontWheels
371 for i=1, numFrontWheels do
372 local wheel = spec.frontWheels[i]
373
374 local wx, wy, wz = wheel.netInfo.x, wheel.netInfo.y, wheel.netInfo.z
375 wy = wy - wheel.radius
376 wx = wx + wheel.xOffset
377 wx, wy, wz = localToWorld(wheel.node, wx,wy,wz)
378
379 fcx, fcy, fcz = fcx + wx, fcy + wy, fcz + wz
380 end
381 fcx, fcy, fcz = fcx / numFrontWheels, fcy / numFrontWheels, fcz / numFrontWheels
382
383 local bcx, bcy, bcz = 0, 0, 0
384 local numBackWheels = #spec.backWheels
385 for i=1, numBackWheels do
386 local wheel = spec.backWheels[i]
387
388 local wx, wy, wz = wheel.netInfo.x, wheel.netInfo.y, wheel.netInfo.z
389 wy = wy - wheel.radius
390 wx = wx + wheel.xOffset
391 wx, wy, wz = localToWorld(wheel.node, wx,wy,wz)
392
393 bcx, bcy, bcz = bcx + wx, bcy + wy, bcz + wz
394 end
395 bcx, bcy, bcz = bcx / numBackWheels, bcy / numBackWheels, bcz / numBackWheels
396
397 local wDirX, wDirY, wDirZ = bcx - fcx, bcy - fcy, bcz - fcz
398 _, wDirY, _ = MathUtil.vector3Normalize(wDirX, wDirY, wDirZ)
399
400 -- allow player offset of 8.5° to tool in Y
401 local dir = wDirY < 0 and 1 or -1
402 dirY = wDirY + math.min(0.15, math.abs(wDirY)) * dir
403
404 -- move the up vector towards the world y so we have some side adjustment
405 local upX, upY, upZ = localDirectionToWorld(self.rootNode, 0, 1, 0)
406 upY = upY + 0.5
407 upX, upY, upZ = MathUtil.vector3Normalize(upX, upY, upZ)
408
409 I3DUtil.setWorldDirection(spec.playerNode, dirX, dirY, dirZ, upX, upY, upZ)
410
411 --#debug drawDebugLine(tx, ty, tz, 0, 0, 1, tx+dirX*4, ty+dirY*4, tz+dirZ*4, 0, 0, 1)
412 --#debug DebugUtil.drawDebugNode(spec.playerNode, "n", false)
413
414 spec.raycastsValid = true
415 else
416 if spec.raycastsValid then
417 if self:getIsEntered() then
418 spec.raycastsValid = false
419 local character = self:getVehicleCharacter()
420 if character ~= nil then
421 character:setCharacterVisibility(false)
422 end
423
424 -- force camera update -> will select the exterior one while raycast is invalid
425 self:setActiveCameraIndex(self.spec_enterable.camIndex)
426 end
427 end
428 end
429 end
430end

onVehicleCharacterChanged

Description
Definition
onVehicleCharacterChanged()
Code
639function PushHandTool:onVehicleCharacterChanged(character)
640 if self:getIsEntered() then
641 if character ~= nil then
642 local activeCamera = self:getActiveCamera()
643 if activeCamera ~= nil and activeCamera.isInside then
644 character:setCharacterVisibility(false)
645 end
646 end
647 end
648end

playerRaycastCallback

Description
Definition
playerRaycastCallback()
Code
730function PushHandTool:playerRaycastCallback(hitObjectId, x, y, z, distance)
731 local spec = self.spec_pushHandTool
732 local vehicle = g_currentMission.nodeToObject[hitObjectId]
733 if vehicle ~= nil and vehicle == self then
734 return true
735 end
736
737 spec.lastRaycastPosition[1] = x
738 spec.lastRaycastPosition[2] = y
739 spec.lastRaycastPosition[3] = z
740 spec.lastRaycastPosition[4] = distance
741 spec.lastRaycastHit = true
742
743 return false
744end

postAnimationUpdate

Description
Definition
postAnimationUpdate()
Code
653function PushHandTool:postAnimationUpdate(dt)
654 if self.isActive then
655 local spec = self.spec_pushHandTool
656
657 if spec.raycastsValid then
658 if spec.handle.node ~= nil and spec.ikChains ~= nil then
659 local yDifference
660 for name, ikChain in pairs(spec.ikChains) do
661 local node = ikChain.nodes[1].node
662 if node ~= nil then
663 if spec.ikChainTargets[name] ~= nil then
664 local targetNode = spec.ikChainTargets[name].targetNode
665 if targetNode ~= nil then
666 local x, y, z = getRotation(spec.handle.node)
667 setRotation(spec.handle.node, 0, 0, 0)
668
669 if yDifference == nil then
670 yDifference = calcDistanceFrom(node, targetNode)
671 else
672 yDifference = (yDifference + (calcDistanceFrom(node, targetNode))) / 2
673 end
674
675 setRotation(spec.handle.node, x, y, z)
676 end
677 end
678 end
679 end
680
681 if yDifference ~= nil then
682 if yDifference < spec.handle.upperLimit then
683 local alpha = (spec.handle.upperLimit - yDifference) / spec.handle.interpolateDistance
684 setRotation(spec.handle.node, spec.handle.minRot * alpha, 0, 0)
685 elseif yDifference > spec.handle.lowerLimit then
686 local alpha = (yDifference - spec.handle.lowerLimit) / spec.handle.interpolateDistance
687 setRotation(spec.handle.node, spec.handle.maxRot * alpha, 0, 0)
688 end
689 end
690 end
691 end
692
693 if spec.ikChains ~= nil then
694 for chainId, target in pairs(spec.ikChainTargets) do
695 IKUtil.setIKChainDirty(spec.ikChains, chainId)
696 end
697
698 IKUtil.updateIKChains(spec.ikChains)
699
700 for target, source in pairs(spec.characterIKNodes) do
701 setRotation(target, getRotation(source))
702 end
703
704 for ikChainId, target in pairs(spec.ikChainTargets) do
705 IKUtil.setIKChainPose(spec.ikChains, ikChainId, target.poseId)
706 end
707 end
708 end
709end

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
83function PushHandTool.prerequisitesPresent(specializations)
84 return SpecializationUtil.hasSpecialization(WorkArea, specializations) and SpecializationUtil.hasSpecialization(TestAreas, specializations)
85end

registerEventListeners

Description
Definition
registerEventListeners()
Code
107function PushHandTool.registerEventListeners(vehicleType)
108 SpecializationUtil.registerEventListener(vehicleType, "onLoad", PushHandTool)
109 SpecializationUtil.registerEventListener(vehicleType, "onDelete", PushHandTool)
110 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", PushHandTool)
111 SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", PushHandTool)
112 SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", PushHandTool)
113 SpecializationUtil.registerEventListener(vehicleType, "onCameraChanged", PushHandTool)
114 SpecializationUtil.registerEventListener(vehicleType, "onVehicleCharacterChanged", PushHandTool)
115end

registerFunctions

Description
Definition
registerFunctions()
Code
89function PushHandTool.registerFunctions(vehicleType)
90 SpecializationUtil.registerFunction(vehicleType, "getRaycastPosition", PushHandTool.getRaycastPosition)
91 SpecializationUtil.registerFunction(vehicleType, "playerRaycastCallback", PushHandTool.playerRaycastCallback)
92 SpecializationUtil.registerFunction(vehicleType, "postAnimationUpdate", PushHandTool.postAnimationUpdate)
93 SpecializationUtil.registerFunction(vehicleType, "customVehicleCharacterLoaded", PushHandTool.customVehicleCharacterLoaded)
94end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
98function PushHandTool.registerOverwrittenFunctions(vehicleType)
99 SpecializationUtil.registerOverwrittenFunction(vehicleType, "setVehicleCharacter", PushHandTool.setVehicleCharacter)
100 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAllowCharacterVisibilityUpdate", PushHandTool.getAllowCharacterVisibilityUpdate)
101 SpecializationUtil.registerOverwrittenFunction(vehicleType, "setActiveCameraIndex", PushHandTool.setActiveCameraIndex)
102 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanStartAIVehicle", PushHandTool.getCanStartAIVehicle)
103end

setActiveCameraIndex

Description
Definition
setActiveCameraIndex()
Code
563function PushHandTool:setActiveCameraIndex(superFunc, index)
564 local spec = self.spec_pushHandTool
565 if not spec.raycastsValid then
566 local specEnterable = self.spec_enterable
567
568 if index > specEnterable.numCameras then
569 index = 1
570 end
571 local activeCamera = specEnterable.cameras[index]
572 if activeCamera.isInside then
573 for i, camera in pairs(specEnterable.cameras) do
574 if not camera.isInside then
575 index = i
576 break
577 end
578 end
579 end
580 end
581
582 return superFunc(self, index)
583end

setVehicleCharacter

Description
Definition
setVehicleCharacter()
Code
434function PushHandTool:setVehicleCharacter(superFunc, playerStyle)
435 local enterableSpec = self.spec_enterable
436 if enterableSpec.vehicleCharacter ~= nil then
437 enterableSpec.vehicleCharacter:delete()
438 enterableSpec.vehicleCharacter:loadCharacter(playerStyle, self, self.customVehicleCharacterLoaded)
439 end
440end