LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

AnimatedVehicle

Description
Specialization adding support for (keyframe)animations to vehicles
Functions

animPartSorter

Description
Returns true if anim parts are in the right order
Definition
animPartSorter(table a, table b)
Arguments
tableapart a to check
tablebpart b to check
Return Values
booleanrightOrderreturns true if parts are in right order
Code
1005function AnimatedVehicle.animPartSorter(a, b)
1006 if a.startTime < b.startTime then
1007 return true
1008 elseif a.startTime == b.startTime then
1009 return a.duration < b.duration
1010 end
1011 return false
1012end

animPartSorterReverse

Description
Returns true if anim parts are in the reverse right order
Definition
animPartSorterReverse(table a, table b)
Arguments
tableapart a to check
tablebpart b to check
Return Values
booleanrightOrderreturns true if parts are in reverse right order
Code
1019function AnimatedVehicle.animPartSorterReverse(a, b)
1020 local endTimeA = a.startTime + a.duration
1021 local endTimeB = b.startTime + b.duration
1022 if endTimeA > endTimeB then
1023 return true
1024 elseif endTimeA == endTimeB then
1025 return a.startTime > b.startTime
1026 end
1027 return false
1028end

findCurrentPartIndex

Description
Find current playing part
Definition
findCurrentPartIndex(table animation)
Arguments
tableanimationanimation
Return Values
integerindexof current playing part
Code
1090function AnimatedVehicle.findCurrentPartIndex(animation)
1091 if animation.currentSpeed > 0 then
1092 -- find the first part that is being played at the current time
1093 animation.currentPartIndex = #animation.parts+1
1094 for i, part in ipairs(animation.parts) do
1095 if part.startTime+part.duration >= animation.currentTime then
1096 animation.currentPartIndex = i
1097 break
1098 end
1099 end
1100 else
1101 -- find the last part that is being played at the current time (the first in partsReverse)
1102 animation.currentPartIndex = #animation.partsReverse+1
1103 for i, part in ipairs(animation.partsReverse) do
1104 if part.startTime <= animation.currentTime then
1105 animation.currentPartIndex = i
1106 break
1107 end
1108 end
1109 end
1110end

getAnimationByName

Description
Returns the animation by given name
Definition
getAnimationByName(string name)
Arguments
stringnamename of animation
Return Values
tableanimationanimation data
Code
716function AnimatedVehicle:getAnimationByName(name)
717 return self.spec_animatedVehicle.animations[name]
718end

getAnimationDuration

Description
Returns duration of animation
Definition
getAnimationDuration(string name)
Arguments
stringnamename of animation
Return Values
floatdurationduration in ms
Code
809function AnimatedVehicle:getAnimationDuration(name)
810 local spec = self.spec_animatedVehicle
811
812 local animation = spec.animations[name]
813 if animation ~= nil then
814 return animation.duration
815 end
816 return 1
817end

getAnimationExists

Description
Returns true if animation exits
Definition
getAnimationExists(string name)
Arguments
stringnamename of animation
Return Values
booleanexistsanimation axists
Code
706function AnimatedVehicle:getAnimationExists(name)
707 local spec = self.spec_animatedVehicle
708
709 return spec.animations[name] ~= nil
710end

getAnimationSpeed

Description
Returns speed of animation
Definition
getAnimationSpeed(string name)
Arguments
stringnamename of animation
Return Values
floatspeedspeed
Code
843function AnimatedVehicle:getAnimationSpeed(name)
844 local spec = self.spec_animatedVehicle
845
846 local animation = spec.animations[name]
847 if animation ~= nil then
848 return animation.currentSpeed
849 end
850
851 return 0
852end

getAnimationTime

Description
Returns animation time
Definition
getAnimationTime(string name)
Arguments
stringnamename of animation
Return Values
floatanimTimeanimation time [0..1]
Code
777function AnimatedVehicle:getAnimationTime(name)
778 local spec = self.spec_animatedVehicle
779
780 local animation = spec.animations[name]
781 if animation ~= nil then
782 return animation.currentTime/animation.duration
783 end
784 return 0
785end

getDurationToEndOfPart

Description
Returns duration to the end of current part
Definition
getDurationToEndOfPart(table part, table anim)
Arguments
tablepartpart
tableanimanimation
Return Values
floatdurationduration to end of current part
Code
1117function AnimatedVehicle.getDurationToEndOfPart(part, anim)
1118 if anim.currentSpeed > 0 then
1119 return part.startTime+part.duration - anim.currentTime
1120 else
1121 return anim.currentTime - part.startTime
1122 end
1123end

getIsAnimationPlaying

Description
Returns true if animation is playing
Definition
getIsAnimationPlaying(string name)
Arguments
stringnamename of animation
Return Values
booleanisPlayinganimation is playing
Code
725function AnimatedVehicle:getIsAnimationPlaying(name)
726 local spec = self.spec_animatedVehicle
727
728 return spec.activeAnimations[name] ~= nil
729end

getIsSpeedRotatingPartActive

Description
Definition
getIsSpeedRotatingPartActive()
Code
903function AnimatedVehicle:getIsSpeedRotatingPartActive(superFunc, speedRotatingPart)
904 if speedRotatingPart.animName ~= nil then
905 local animTime = self:getAnimationTime(speedRotatingPart.animName)
906 if speedRotatingPart.animOuterRange then
907 if animTime > speedRotatingPart.animMinLimit or animTime < speedRotatingPart.animMaxLimit then
908 return false
909 end
910 else
911 if animTime > speedRotatingPart.animMaxLimit or animTime < speedRotatingPart.animMinLimit then
912 return false
913 end
914 end
915 end
916
917 return superFunc(self, speedRotatingPart)
918end

getIsWorkAreaActive

Description
Definition
getIsWorkAreaActive()
Code
932function AnimatedVehicle:getIsWorkAreaActive(superFunc, workArea)
933 if workArea.animName ~= nil then
934 local animTime = self:getAnimationTime(workArea.animName)
935 if animTime > workArea.animMaxLimit or animTime < workArea.animMinLimit then
936 return false
937 end
938 end
939
940 return superFunc(self, workArea)
941end

getMovedLimitedValue

Description
Returns moved limited value
Definition
getMovedLimitedValue(float currentValue, float destValue, float speed, float dt)
Arguments
floatcurrentValuecurrent value
floatdestValuedest value
floatspeedspeed
floatdttime since last call in ms
Return Values
floatretlimited value
Code
1037function AnimatedVehicle.getMovedLimitedValue(currentValue, destValue, speed, dt)
1038 if destValue == currentValue then
1039 return currentValue
1040 end
1041
1042 -- we are moving towards -inf, we need to check for the maximum
1043 local limitF = destValue < currentValue and math.max or math.min
1044 return limitF(currentValue + speed * dt, destValue)
1045end

getNextPartIsPlaying

Description
Get next part is playing
Definition
getNextPartIsPlaying(table nextPart, table prevPart, table anim, boolean default)
Arguments
tablenextPartnext part
tableprevPartprevious part
tableanimanimation
booleandefaultdefault value
Return Values
booleanisPlayingnext part is playing
Code
1132function AnimatedVehicle.getNextPartIsPlaying(nextPart, prevPart, anim, default)
1133 if anim.currentSpeed > 0 then
1134 if nextPart ~= nil then
1135 return nextPart.startTime > anim.currentTime
1136 end
1137 else
1138 if prevPart ~= nil then
1139 return prevPart.startTime + prevPart.duration < anim.currentTime
1140 end
1141 end
1142 return default
1143end

getNumOfActiveAnimations

Description
Definition
getNumOfActiveAnimations()
Code
1443function AnimatedVehicle:getNumOfActiveAnimations()
1444 return self.spec_animatedVehicle.numActiveAnimations
1445end

getRealAnimationTime

Description
Returns real animation time
Definition
getRealAnimationTime(string name)
Arguments
stringnamename of animation
Return Values
floatanimTimereal animation time in ms
Code
735function AnimatedVehicle:getRealAnimationTime(name)
736 local spec = self.spec_animatedVehicle
737
738 local animation = spec.animations[name]
739 if animation ~= nil then
740 return animation.currentTime
741 end
742 return 0
743end

initializeAnimationPart

Description
Initialize part of animation
Definition
initializeAnimationPart(table part)
Arguments
tablepartpart
Code
598function AnimatedVehicle:initializeAnimationPart(animation, part, i, numParts)
599 for index=1, #part.animationValues do
600 part.animationValues[index]:init(i, numParts)
601 end
602end

initializeAnimationPartAttribute

Description
Definition
initializeAnimationPartAttribute()
Code
945function AnimatedVehicle.initializeAnimationPartAttribute(self, animation, part, i, numParts, nextName, prevName, startName, endName, warningName, startName2, endName2, additionalCompareParam)
946 -- find next part, check for overlapping, enter dependencies and set default start value if not already set
947 if part[endName] ~= nil then
948 for j=i+1, numParts do
949 local part2 = animation.parts[j]
950
951 local additionalCompare = true
952 if additionalCompareParam ~= nil then
953 if part[additionalCompareParam] ~= part2[additionalCompareParam] then
954 additionalCompare = false
955 end
956 end
957
958 -- check if the animations use the same range, if not they cannot collide
959 local sameRequiredRange = true
960 if part.requiredAnimation ~= nil then
961 if part.requiredAnimation == part2.requiredAnimation then
962 for n, v in ipairs(part.requiredAnimationRange) do
963 if part2.requiredAnimationRange[n] ~= v then
964 sameRequiredRange = false
965 end
966 end
967 end
968 end
969
970 local sameConfiguration = true
971 if part.requiredConfigurationName ~= nil then
972 if part.requiredConfigurationName == part2.requiredConfigurationName then
973 if part.requiredConfigurationIndex ~= part2.requiredConfigurationIndex then
974 sameConfiguration = false
975 end
976 end
977 end
978
979 if part.direction == part2.direction and part.node == part2.node and part2[endName] ~= nil and additionalCompare and sameRequiredRange and sameConfiguration then
980 if part.direction == part2.direction and part.startTime + part.duration > part2.startTime+0.001 then
981 Logging.xmlWarning(self.xmlFile, "Overlapping %s parts for node '%s' in animation '%s'", warningName, getName(part.node), animation.name)
982 end
983 part[nextName] = part2
984 part2[prevName] = part
985 if part2[startName] == nil then
986 part2[startName] = {unpack(part[endName])}
987 end
988 if startName2 ~= nil and endName2 ~= nil then
989 if part2[startName2] == nil then
990 part2[startName2] = {unpack(part[endName2])}
991 end
992 end
993
994 break
995 end
996 end
997 end
998end

initializeAnimationParts

Description
Initialize parts of animation
Definition
initializeAnimationParts(table animation)
Arguments
tableanimationanimation
Code
583function AnimatedVehicle:initializeAnimationParts(animation)
584 local numParts = #animation.parts
585
586 for i, part in ipairs(animation.parts) do
587 self:initializeAnimationPart(animation, part, i, numParts)
588 end
589
590 for i, part in ipairs(animation.parts) do
591 self:postInitializeAnimationPart(animation, part, i, numParts)
592 end
593end

initSpecialization

Description
Definition
initSpecialization()
Code
31function AnimatedVehicle.initSpecialization()
32 local schema = Vehicle.xmlSchema
33 schema:setXMLSpecializationType("AnimatedVehicle")
34
35 AnimatedVehicle.registerAnimationXMLPaths(schema, "vehicle.animations.animation(?)")
36
37 schema:register(XMLValueType.STRING, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animName", "Animation name")
38 schema:register(XMLValueType.BOOL, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animOuterRange", "Anim limit outer range", false)
39 schema:register(XMLValueType.FLOAT, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animMinLimit", "Min. anim limit", 0)
40 schema:register(XMLValueType.FLOAT, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#animMaxLimit", "Max. anim limit", 1)
41
42 schema:register(XMLValueType.STRING, WorkArea.WORK_AREA_XML_KEY .. "#animName", "Animation name")
43 schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_KEY .. "#animMinLimit", "Min. anim limit", 0)
44 schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_KEY .. "#animMaxLimit", "Max. anim limit", 1)
45
46 schema:register(XMLValueType.STRING, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#animName", "Animation name")
47 schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#animMinLimit", "Min. anim limit", 0)
48 schema:register(XMLValueType.FLOAT, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#animMaxLimit", "Max. anim limit", 1)
49
50 schema:setXMLSpecializationType()
51end

loadAnimation

Description
Definition
loadAnimation()
Code
339function AnimatedVehicle:loadAnimation(xmlFile, key, animation, components)
340
341 local name = xmlFile:getValue(key.."#name")
342 if name ~= nil then
343 animation.name = name
344 animation.parts = {}
345 animation.currentTime = 0
346 animation.previousTime = 0
347 animation.currentSpeed = 1
348 animation.looping = xmlFile:getValue(key .. "#looping", false)
349 animation.resetOnStart = xmlFile:getValue(key .. "#resetOnStart", true)
350 animation.soundVolumeFactor = xmlFile:getValue(key .. "#soundVolumeFactor", 1)
351 animation.isKeyframe = xmlFile:getValue(key .. "#isKeyframe", false)
352
353 if animation.isKeyframe then
354 animation.curvesByNode = {}
355 end
356
357 local partI = 0
358 while true do
359 local partKey = key..string.format(".part(%d)", partI)
360 if not xmlFile:hasProperty(partKey) then
361 break
362 end
363
364 local animationPart = {}
365 if not animation.isKeyframe then
366 if self:loadAnimationPart(xmlFile, partKey, animationPart, animation, components) then
367 table.insert(animation.parts, animationPart)
368 end
369 else
370 self:loadStaticAnimationPart(xmlFile, partKey, animationPart, animation, components)
371 end
372
373 partI = partI + 1
374 end
375
376 -- sort parts by start/end time
377 animation.partsReverse = {}
378 for _, part in ipairs(animation.parts) do
379 table.insert(animation.partsReverse, part)
380 end
381 table.sort(animation.parts, AnimatedVehicle.animPartSorter)
382 table.sort(animation.partsReverse, AnimatedVehicle.animPartSorterReverse)
383
384 self:initializeAnimationParts(animation)
385
386 animation.currentPartIndex = 1
387 animation.duration = 0
388 for _, part in ipairs(animation.parts) do
389 animation.duration = math.max(animation.duration, part.startTime + part.duration)
390 end
391 if animation.isKeyframe then
392 for node, curve in pairs(animation.curvesByNode) do
393 animation.duration = math.max(animation.duration, curve.maxTime)
394 end
395 end
396
397 animation.startTime = xmlFile:getValue(key .. "#startAnimTime", 0)
398 animation.currentTime = animation.startTime * animation.duration
399
400 if self.isClient then
401 animation.samples = {}
402
403 local i = 0
404 while true do
405 local soundKey = string.format("sound(%d)", i)
406 local baseKey = key .. "." .. soundKey
407 if not xmlFile:hasProperty(baseKey) then
408 break
409 end
410
411 local sample = g_soundManager:loadSampleFromXML(xmlFile, key, soundKey, self.baseDirectory, components or self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
412 if sample ~= nil then
413 sample.startTime = xmlFile:getValue(baseKey .. "#startTime", 0)
414 sample.endTime = xmlFile:getValue(baseKey .. "#endTime")
415 sample.direction = xmlFile:getValue(baseKey .. "#direction", 0)
416
417 -- if no end time and no loop count is defined we play the sound only once
418 if sample.endTime == nil and sample.loops == 0 then
419 sample.loops = 1
420 end
421
422 sample.volumeScale = sample.volumeScale * animation.soundVolumeFactor
423
424 table.insert(animation.samples, sample)
425 end
426
427 i = i + 1
428 end
429
430 animation.eventSamples = {}
431 animation.eventSamples.stopTimePos = {}
432 animation.eventSamples.stopTimeNeg = {}
433
434 xmlFile:iterate(key .. ".stopTimePosSound", function(index, _)
435 local sample = g_soundManager:loadSampleFromXML(xmlFile, key, string.format("stopTimePosSound(%d)", index - 1), self.baseDirectory, components or self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
436 if sample ~= nil then
437 table.insert(animation.eventSamples.stopTimePos, sample)
438 end
439 end)
440
441 xmlFile:iterate(key .. ".stopTimeNegSound", function(index, _)
442 local sample = g_soundManager:loadSampleFromXML(xmlFile, key, string.format("stopTimeNegSound(%d)", index - 1), self.baseDirectory, components or self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
443 if sample ~= nil then
444 table.insert(animation.eventSamples.stopTimeNeg, sample)
445 end
446 end)
447 end
448
449 return true
450 end
451
452 return false
453end

loadAnimationPart

Description
Definition
loadAnimationPart()
Code
457function AnimatedVehicle:loadAnimationPart(xmlFile, partKey, part, animation, components)
458 local startTime = xmlFile:getValue(partKey.."#startTime")
459 local duration = xmlFile:getValue(partKey.."#duration")
460 local endTime = xmlFile:getValue(partKey.."#endTime")
461 local direction = MathUtil.sign(xmlFile:getValue(partKey.."#direction", 0))
462
463 part.components = components or self.components
464 part.i3dMappings = self.i3dMappings
465
466 part.animationValues = {}
467
468 local spec = self.spec_animatedVehicle
469 for _, animationValueType in pairs(spec.animationValueTypes) do
470 local animationValueObject = animationValueType.classObject.new(self, animation, part, animationValueType.startName, animationValueType.endName, animationValueType.name, animationValueType.initialUpdate, animationValueType.get, animationValueType.set, animationValueType.load)
471 if animationValueObject:load(xmlFile, partKey) then
472 table.insert(part.animationValues, animationValueObject)
473 end
474 end
475
476 local requiredAnimation = xmlFile:getValue(partKey.."#requiredAnimation")
477 local requiredAnimationRange = xmlFile:getValue(partKey.."#requiredAnimationRange", nil, true)
478
479 local requiredConfigurationName = xmlFile:getValue(partKey.."#requiredConfigurationName")
480 local requiredConfigurationIndex = xmlFile:getValue(partKey.."#requiredConfigurationIndex")
481
482 for i=1, #part.animationValues do
483 part.animationValues[i].requiredAnimation = requiredAnimation
484 part.animationValues[i]:addCompareParameters("requiredAnimation")
485
486 if requiredAnimationRange ~= nil then
487 part.animationValues[i].requiredAnimationRange = string.format("%.2f %.2f", requiredAnimationRange[1], requiredAnimationRange[2])
488 part.animationValues[i]:addCompareParameters("requiredAnimationRange")
489 end
490 end
491
492 if #part.animationValues == 0 then
493 return false
494 end
495
496 if startTime ~= nil and (duration ~= nil or endTime ~= nil) then
497 if endTime ~= nil then
498 duration = endTime - startTime
499 end
500 part.startTime = startTime*1000
501 part.duration = duration*1000
502 part.direction = direction
503 part.requiredAnimation = requiredAnimation
504 part.requiredAnimationRange = requiredAnimationRange
505
506 part.requiredConfigurationName = requiredConfigurationName
507 part.requiredConfigurationIndex = requiredConfigurationIndex
508
509 return true
510 end
511
512 return false
513end

loadSpeedRotatingPartFromXML

Description
Definition
loadSpeedRotatingPartFromXML()
Code
888function AnimatedVehicle:loadSpeedRotatingPartFromXML(superFunc, speedRotatingPart, xmlFile, key)
889 if not superFunc(self, speedRotatingPart, xmlFile, key) then
890 return false
891 end
892
893 speedRotatingPart.animName = xmlFile:getValue(key.."#animName")
894 speedRotatingPart.animOuterRange = xmlFile:getValue(key.."#animOuterRange", false)
895 speedRotatingPart.animMinLimit = xmlFile:getValue(key.."#animMinLimit", 0)
896 speedRotatingPart.animMaxLimit = xmlFile:getValue(key.."#animMaxLimit", 1)
897
898 return true
899end

loadStaticAnimationPart

Description
Definition
loadStaticAnimationPart()
Code
517function AnimatedVehicle:loadStaticAnimationPart(xmlFile, partKey, part, animation, components)
518 local node = xmlFile:getValue(partKey .. "#node", nil, self.components, self.i3dMappings)
519 if node ~= nil then
520 local time = xmlFile:getValue(partKey.."#time")
521 local startTime = xmlFile:getValue(partKey.."#startTime")
522 local endTime = xmlFile:getValue(partKey.."#endTime")
523
524 if animation.curvesByNode[node] == nil then
525 animation.curvesByNode[node] = AnimCurve.new(linearInterpolatorTransRotScale)
526 end
527
528 local curve = animation.curvesByNode[node]
529
530 if time ~= nil then
531 self:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, "translation", "rotation", "scale", time * 1000)
532 elseif startTime ~= nil or endTime ~= nil then
533 if startTime ~= nil then
534 startTime = startTime * 1000
535 if curve.maxTime == 0 or curve.maxTime ~= startTime then
536 self:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, "startTrans", "startRot", "startScale", startTime)
537 end
538 end
539 if endTime ~= nil then
540 endTime = endTime * 1000
541 if curve.maxTime == 0 or curve.maxTime ~= endTime then
542 self:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, "endTrans", "endRot", "endScale", endTime)
543 end
544 end
545 end
546
547 return true
548 end
549
550 return false
551end

loadStaticAnimationPartValues

Description
Definition
loadStaticAnimationPartValues()
Code
555function AnimatedVehicle:loadStaticAnimationPartValues(xmlFile, partKey, curve, node, transName, rotName, scaleName, time)
556 local x, y, z = xmlFile:getValue(partKey.."#"..transName)
557 if x == nil then
558 x, y, z = getTranslation(node)
559 else
560 curve.hasTranslation = true
561 end
562
563 local rx, ry, rz = xmlFile:getValue(partKey.."#"..rotName)
564 if rx == nil then
565 rx, ry, rz = getRotation(node)
566 else
567 curve.hasRotation = true
568 end
569
570 local sx, sy, sz = xmlFile:getValue(partKey.."#"..scaleName)
571 if sx == nil then
572 sx, sy, sz = getScale(node)
573 else
574 curve.hasScale = true
575 end
576
577 curve:addKeyframe({x=x, y=y, z=z, rx=rx, ry=ry, rz=rz, sx=sx, sy=sy, sz=sz, time=time})
578end

loadWorkAreaFromXML

Description
Definition
loadWorkAreaFromXML()
Code
922function AnimatedVehicle:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
923 workArea.animName = xmlFile:getValue(key.."#animName")
924 workArea.animMinLimit = xmlFile:getValue(key.."#animMinLimit", 0)
925 workArea.animMaxLimit = xmlFile:getValue(key.."#animMaxLimit", 1)
926
927 return superFunc(self, workArea, xmlFile, key)
928end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
269function AnimatedVehicle:onDelete()
270 local spec = self.spec_animatedVehicle
271 if self.isClient and spec.animations ~= nil then
272 for _, animation in pairs(spec.animations) do
273 g_soundManager:deleteSamples(animation.samples)
274 g_soundManager:deleteSamples(animation.eventSamples.stopTimePos)
275 g_soundManager:deleteSamples(animation.eventSamples.stopTimeNeg)
276 end
277 end
278end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
222function AnimatedVehicle:onLoad(savegame)
223 local spec = self.spec_animatedVehicle
224
225 spec.animations = {}
226
227 local i = 0
228 while true do
229 local key = string.format("vehicle.animations.animation(%d)", i)
230 if not self.xmlFile:hasProperty(key) then
231 break
232 end
233
234 local animation = {}
235
236 if self:loadAnimation(self.xmlFile, key, animation) then
237 spec.animations[animation.name] = animation
238 end
239
240 i = i + 1
241 end
242
243 spec.activeAnimations = {}
244 spec.numActiveAnimations = 0
245 spec.fixedTimeSamplesDirtyDelay = 0
246end

onPostLoad

Description
Called after loading
Definition
onPostLoad(table savegame)
Arguments
tablesavegamesavegame
Code
251function AnimatedVehicle:onPostLoad(savegame)
252 local spec = self.spec_animatedVehicle
253 for name, animation in pairs(spec.animations) do
254 if animation.resetOnStart then
255 self:setAnimationTime(name, 1, true, false)
256 self:setAnimationStopTime(name, animation.startTime)
257 self:playAnimation(name, -1, 1, true, false)
258 AnimatedVehicle.updateAnimationByName(self, name, 9999999, true)
259 end
260 end
261
262 if next(spec.animations) == nil then
263 SpecializationUtil.removeEventListener(self, "onUpdate", AnimatedVehicle)
264 end
265end

onPreLoad

Description
Called on pre loading
Definition
onPreLoad(table savegame)
Arguments
tablesavegamesavegame
Code
212function AnimatedVehicle:onPreLoad(savegame)
213 local spec = self.spec_animatedVehicle
214 spec.animationValueTypes = {}
215
216 SpecializationUtil.raiseEvent(self, "onRegisterAnimationValueTypes")
217end

onRegisterAnimationValueTypes

Description
Called on pre load to register animation value types
Definition
onRegisterAnimationValueTypes()
Code
1449function AnimatedVehicle:onRegisterAnimationValueTypes()
1450 local loadNodeFunction = function(value, xmlFile, xmlKey)
1451 value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings)
1452
1453 if value.node ~= nil then
1454 value:setWarningInformation("node: " .. getName(value.node))
1455 value:addCompareParameters("node")
1456
1457 return true
1458 end
1459
1460 return false
1461 end
1462
1463 self:registerAnimationValueType("rotation", "startRot", "endRot", false, AnimationValueFloat, loadNodeFunction,
1464 function(value)
1465 return getRotation(value.node)
1466 end,
1467
1468 function(value, ...)
1469 setRotation(value.node, ...)
1470
1471 SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", value.node)
1472 end)
1473
1474 self:registerAnimationValueType("translation", "startTrans", "endTrans", false, AnimationValueFloat, loadNodeFunction,
1475 function(value)
1476 return getTranslation(value.node)
1477 end,
1478
1479 function(value, ...)
1480 setTranslation(value.node, ...)
1481
1482 SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", value.node)
1483 end)
1484
1485 self:registerAnimationValueType("scale", "startScale", "endScale", false, AnimationValueFloat, loadNodeFunction,
1486 function(value)
1487 return getScale(value.node)
1488 end,
1489
1490 function(value, ...)
1491 setScale(value.node, ...)
1492
1493 SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", value.node)
1494 end)
1495
1496 local updateShaderParameterMask = function(xmlFile, xmlKey, mask)
1497 local customMask = false
1498 local rawValuesStr = xmlFile:getString(xmlKey)
1499 if rawValuesStr ~= nil then
1500 local rawValues = rawValuesStr:split(" ")
1501 for i=1, #rawValues do
1502 if rawValues[i] == "-" then
1503 mask[i] = 0
1504 customMask = true
1505 end
1506 end
1507 end
1508
1509 return customMask
1510 end
1511
1512 self:registerAnimationValueType("shaderParameter", "shaderStartValues", "shaderEndValues", false, AnimationValueFloat,
1513 function(value, xmlFile, xmlKey)
1514 value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings)
1515 value.shaderParameter = xmlFile:getValue(xmlKey.."#shaderParameter")
1516 value.shaderParameterPrev = xmlFile:getValue(xmlKey.."#shaderParameterPrev")
1517
1518 if value.node ~= nil and value.shaderParameter ~= nil then
1519 if getHasClassId(value.node, ClassIds.SHAPE) and getHasShaderParameter(value.node, value.shaderParameter) then
1520 value:setWarningInformation("node: " .. getName(value.node) .. "with shaderParam: " .. value.shaderParameter)
1521 value:addCompareParameters("node", "shaderParameter")
1522
1523 value.shaderParameterMask = {1, 1, 1, 1}
1524 value.customShaderParameterMask = updateShaderParameterMask(xmlFile, xmlKey .. "#shaderStartValues", value.shaderParameterMask)
1525 value.customShaderParameterMask = updateShaderParameterMask(xmlFile, xmlKey .. "#shaderEndValues", value.shaderParameterMask) or value.customShaderParameterMask
1526
1527 if value.shaderParameterPrev ~= nil then
1528 if not getHasShaderParameter(value.node, value.shaderParameterPrev) then
1529 Logging.xmlWarning(xmlFile, "Node '%s' has no shaderParameterPrev '%s' for animation part '%s'!", getName(value.node), value.shaderParameterPrev, xmlKey)
1530 return false
1531 end
1532 else
1533 local prevName = "prev" .. value.shaderParameter:sub(1, 1):upper() .. value.shaderParameter:sub(2)
1534 if getHasShaderParameter(value.node, prevName) then
1535 value.shaderParameterPrev = prevName
1536 end
1537 end
1538
1539 return true
1540 else
1541 Logging.xmlWarning(xmlFile, "Node '%s' has no shaderParameter '%s' for animation part '%s'!", getName(value.node), value.shaderParameter, xmlKey)
1542 end
1543 end
1544
1545 return false
1546 end,
1547
1548 function(value)
1549 return getShaderParameter(value.node, value.shaderParameter)
1550 end,
1551
1552 function(value, x, y, z, w)
1553 if value.customShaderParameterMask then
1554 local sx, sy, sz, sw = getShaderParameter(value.node, value.shaderParameter)
1555 if value.shaderParameterMask[1] == 0 then x = sx end
1556 if value.shaderParameterMask[2] == 0 then y = sy end
1557 if value.shaderParameterMask[3] == 0 then z = sz end
1558 if value.shaderParameterMask[4] == 0 then w = sw end
1559 end
1560
1561 if value.shaderParameterPrev ~= nil then
1562 g_animationManager:setPrevShaderParameter(value.node, value.shaderParameter, x, y, z, w, false, value.shaderParameterPrev)
1563 else
1564 setShaderParameter(value.node, value.shaderParameter, x, y, z, w, false)
1565 end
1566 end)
1567
1568 self:registerAnimationValueType("visibility", "visibility", "", false, AnimationValueBool, loadNodeFunction,
1569 function(value)
1570 return getVisibility(value.node)
1571 end,
1572
1573 function(value, ...)
1574 setVisibility(value.node, ...)
1575 end)
1576
1577 self:registerAnimationValueType("visibilityInter", "startVisibility", "endVisibility", false, AnimationValueFloat,
1578 function(value, xmlFile, xmlKey)
1579 value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings)
1580 if value.node ~= nil and value.startValue ~= nil and value.endValue ~= nil then
1581 value:setWarningInformation("node: " .. getName(value.node))
1582 value:addCompareParameters("node")
1583
1584 return true
1585 end
1586
1587 return false
1588 end,
1589 function(value)
1590 if value.lastVisibilityValue ~= nil then
1591 return value.lastVisibilityValue
1592 end
1593
1594 return getVisibility(value.node) and 1 or 0
1595 end,
1596
1597 function(value, visibility)
1598 value.lastVisibilityValue = visibility
1599 setVisibility(value.node, visibility >= 0.5)
1600 end)
1601
1602 self:registerAnimationValueType("animationClip", "clipStartTime", "clipEndTime", true, AnimationValueFloat,
1603 function(value, xmlFile, xmlKey)
1604 value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings)
1605 value.animationClip = xmlFile:getValue(xmlKey.."#animationClip")
1606
1607 if value.node ~= nil and value.animationClip ~= nil then
1608 value.animationCharSet = getAnimCharacterSet(value.node)
1609 value.animationClipIndex = getAnimClipIndex(value.animationCharSet, value.animationClip)
1610
1611 value:setWarningInformation("node: " .. getName(value.node) .. "with animationClip: " .. value.animationClip)
1612 value:addCompareParameters("node", "animationClip")
1613
1614 return true
1615 end
1616
1617 return false
1618 end,
1619
1620 function(value)
1621 local oldClipIndex = getAnimTrackAssignedClip(value.animationCharSet, 0)
1622 clearAnimTrackClip(value.animationCharSet, 0)
1623 assignAnimTrackClip(value.animationCharSet, 0, value.animationClipIndex)
1624
1625 if oldClipIndex == value.animationClipIndex then
1626 return getAnimTrackTime(value.animationCharSet, 0)
1627 end
1628
1629 local startTime = value.startValue or value.endValue
1630 if value.animation.currentSpeed < 0 then
1631 startTime = value.endValue or value.startValue
1632 end
1633
1634 return startTime[1]
1635 end,
1636
1637 function(value, time)
1638 local oldClipIndex = getAnimTrackAssignedClip(value.animationCharSet, 0)
1639 if oldClipIndex ~= value.animationClipIndex then
1640 clearAnimTrackClip(value.animationCharSet, 0)
1641 assignAnimTrackClip(value.animationCharSet, 0, value.animationClipIndex)
1642 end
1643
1644 enableAnimTrack(value.animationCharSet, 0)
1645 setAnimTrackTime(value.animationCharSet, 0, time, true)
1646 disableAnimTrack(value.animationCharSet, 0)
1647 end)
1648
1649 self:registerAnimationValueType("dependentAnimation", "dependentAnimationStartTime", "dependentAnimationEndTime", true, AnimationValueFloat,
1650 function(value, xmlFile, xmlKey)
1651 value.dependentAnimation = xmlFile:getValue(xmlKey.."#dependentAnimation")
1652
1653 if value.dependentAnimation ~= nil then
1654 value:setWarningInformation("dependentAnimation: " .. value.dependentAnimation)
1655 value:addCompareParameters("dependentAnimation")
1656
1657 return true
1658 end
1659
1660 return false
1661 end,
1662
1663 function(value)
1664 return value.vehicle:getAnimationTime(value.dependentAnimation)
1665 end,
1666
1667 function(value, time)
1668 value.vehicle:setAnimationTime(value.dependentAnimation, time, true)
1669 end)
1670
1671 if self.isServer then
1672 self:registerAnimationValueType("rotLimit", "", "", false, AnimationValueFloat,
1673 function(value, xmlFile, xmlKey)
1674 value.startRotLimit = xmlFile:getValue(xmlKey.."#startRotLimit", nil, true)
1675 value.startRotMinLimit = xmlFile:getValue(xmlKey.."#startRotMinLimit", nil, true)
1676 value.startRotMaxLimit = xmlFile:getValue(xmlKey.."#startRotMaxLimit", nil, true)
1677
1678 if value.startRotLimit ~= nil then
1679 value.startRotMinLimit = {-value.startRotLimit[1], -value.startRotLimit[2], -value.startRotLimit[3]}
1680 value.startRotMaxLimit = {value.startRotLimit[1], value.startRotLimit[2], value.startRotLimit[3]}
1681 end
1682
1683 value.endRotLimit = xmlFile:getValue(xmlKey.."#endRotLimit", nil, true)
1684 value.endRotMinLimit = xmlFile:getValue(xmlKey.."#endRotMinLimit", nil, true)
1685 value.endRotMaxLimit = xmlFile:getValue(xmlKey.."#endRotMaxLimit", nil, true)
1686
1687 if value.endRotLimit ~= nil then
1688 value.endRotMinLimit = {-value.endRotLimit[1], -value.endRotLimit[2], -value.endRotLimit[3]}
1689 value.endRotMaxLimit = {value.endRotLimit[1], value.endRotLimit[2], value.endRotLimit[3]}
1690 end
1691
1692 local componentJointIndex = xmlFile:getValue(xmlKey.."#componentJointIndex")
1693 if componentJointIndex ~= nil then
1694 if componentJointIndex >= 1 then
1695 value.componentJoint = value.vehicle.componentJoints[componentJointIndex]
1696 end
1697
1698 if value.componentJoint == nil then
1699 Logging.xmlWarning(xmlFile, "Invalid componentJointIndex for animation part '%s'. Indexing starts with 1!", xmlKey)
1700 return false
1701 end
1702 end
1703
1704 if (value.endRotMinLimit ~= nil and value.endRotMaxLimit == nil) or (value.endRotMinLimit == nil and value.endRotMaxLimit ~= nil) then
1705 Logging.xmlWarning(xmlFile, "Incomplete end trans limit for animation part '%s'.", xmlKey)
1706 return false
1707 end
1708
1709 if value.componentJoint ~= nil and value.endRotMinLimit ~= nil and value.endRotMaxLimit ~= nil then
1710 if value.startRotMinLimit ~= nil and value.startRotMaxLimit ~= nil then
1711 value.startValue = {value.startRotMinLimit[1], value.startRotMinLimit[2], value.startRotMinLimit[3], value.startRotMaxLimit[1], value.startRotMaxLimit[2], value.startRotMaxLimit[3]}
1712 end
1713 if value.endRotMinLimit ~= nil and value.endRotMaxLimit ~= nil then
1714 value.endValue = {value.endRotMinLimit[1], value.endRotMinLimit[2], value.endRotMinLimit[3], value.endRotMaxLimit[1], value.endRotMaxLimit[2], value.endRotMaxLimit[3]}
1715 end
1716
1717 if value.endValue == nil then
1718 Logging.xmlWarning(xmlFile, "Missing end rot limit for animation part '%s'.", xmlKey)
1719 return false
1720 end
1721
1722 value.endName = "rotLimit" -- only for comparing parts
1723 value:setWarningInformation("componentJointIndex: " .. componentJointIndex)
1724 value:addCompareParameters("componentJoint")
1725
1726 return true
1727 end
1728
1729 return false
1730 end,
1731
1732 function(value)
1733 return value.componentJoint.rotMinLimit[1], value.componentJoint.rotMinLimit[2], value.componentJoint.rotMinLimit[3], value.componentJoint.rotLimit[1], value.componentJoint.rotLimit[2], value.componentJoint.rotLimit[3]
1734 end,
1735
1736 function(value, minX, minY, minZ, maxX, maxY, maxZ)
1737 value.vehicle:setComponentJointRotLimit(value.componentJoint, 1, minX, maxX)
1738 value.vehicle:setComponentJointRotLimit(value.componentJoint, 2, minY, maxY)
1739 value.vehicle:setComponentJointRotLimit(value.componentJoint, 3, minZ, maxZ)
1740 end)
1741
1742 self:registerAnimationValueType("transLimit", "", "", false, AnimationValueFloat,
1743 function(value, xmlFile, xmlKey)
1744 value.startTransLimit = xmlFile:getValue(xmlKey.."#startTransLimit", nil, true)
1745 value.startTransMinLimit = xmlFile:getValue(xmlKey.."#startTransMinLimit", nil, true)
1746 value.startTransMaxLimit = xmlFile:getValue(xmlKey.."#startTransMaxLimit", nil, true)
1747
1748 if value.startTransLimit ~= nil then
1749 value.startTransMinLimit = {-value.startTransLimit[1], -value.startTransLimit[2], -value.startTransLimit[3]}
1750 value.startTransMaxLimit = {value.startTransLimit[1], value.startTransLimit[2], value.startTransLimit[3]}
1751 end
1752
1753 value.endTransLimit = xmlFile:getValue(xmlKey.."#endTransLimit", nil, true)
1754 value.endTransMinLimit = xmlFile:getValue(xmlKey.."#endTransMinLimit", nil, true)
1755 value.endTransMaxLimit = xmlFile:getValue(xmlKey.."#endTransMaxLimit", nil, true)
1756
1757 if value.endTransLimit ~= nil then
1758 value.endTransMinLimit = {-value.endTransLimit[1], -value.endTransLimit[2], -value.endTransLimit[3]}
1759 value.endTransMaxLimit = {value.endTransLimit[1], value.endTransLimit[2], value.endTransLimit[3]}
1760 end
1761
1762 local componentJointIndex = xmlFile:getValue(xmlKey.."#componentJointIndex")
1763 if componentJointIndex ~= nil then
1764 if componentJointIndex >= 1 then
1765 value.componentJoint = value.vehicle.componentJoints[componentJointIndex]
1766 end
1767
1768 if value.componentJoint == nil then
1769 Logging.xmlWarning(xmlFile, "Invalid componentJointIndex for animation part '%s'. Indexing starts with 1!", xmlKey)
1770 return false
1771 end
1772 end
1773
1774 if (value.endTransMinLimit ~= nil and value.endTransMaxLimit == nil) or (value.endTransMinLimit == nil and value.endTransMaxLimit ~= nil) then
1775 Logging.xmlWarning(xmlFile, "Incomplete end trans limit for animation part '%s'.", xmlKey)
1776 return false
1777 end
1778
1779 if value.componentJoint ~= nil and value.endTransMinLimit ~= nil and value.endTransMaxLimit ~= nil then
1780 if value.startTransMinLimit ~= nil and value.startTransMaxLimit ~= nil then
1781 value.startValue = {value.startTransMinLimit[1], value.startTransMinLimit[2], value.startTransMinLimit[3], value.startTransMaxLimit[1], value.startTransMaxLimit[2], value.startTransMaxLimit[3]}
1782 end
1783 if value.endTransMinLimit ~= nil and value.endTransMaxLimit ~= nil then
1784 value.endValue = {value.endTransMinLimit[1], value.endTransMinLimit[2], value.endTransMinLimit[3], value.endTransMaxLimit[1], value.endTransMaxLimit[2], value.endTransMaxLimit[3]}
1785 end
1786
1787 if value.endValue == nil then
1788 Logging.xmlWarning(xmlFile, "Missing end trans limit for animation part '%s'.", xmlKey)
1789 return false
1790 end
1791
1792 value.endName = "transLimit" -- only for comparing parts
1793 value:setWarningInformation("componentJointIndex: " .. componentJointIndex)
1794 value:addCompareParameters("componentJoint")
1795
1796 return true
1797 end
1798
1799 return false
1800 end,
1801
1802 function(value)
1803 return value.componentJoint.transMinLimit[1], value.componentJoint.transMinLimit[2], value.componentJoint.transMinLimit[3], value.componentJoint.transLimit[1], value.componentJoint.transLimit[2], value.componentJoint.transLimit[3]
1804 end,
1805
1806 function(value, minX, minY, minZ, maxX, maxY, maxZ)
1807 value.vehicle:setComponentJointTransLimit(value.componentJoint, 1, minX, maxX)
1808 value.vehicle:setComponentJointTransLimit(value.componentJoint, 2, minY, maxY)
1809 value.vehicle:setComponentJointTransLimit(value.componentJoint, 3, minZ, maxZ)
1810 end)
1811
1812 self:registerAnimationValueType("componentMass", "startMass", "endMass", false, AnimationValueFloat,
1813 function(value, xmlFile, xmlKey)
1814 local componentIndex = xmlFile:getValue(xmlKey.."#componentIndex")
1815 if componentIndex ~= nil then
1816 if componentIndex >= 1 then
1817 value.component = value.vehicle.components[componentIndex]
1818 end
1819
1820 if value.component == nil then
1821 Logging.xmlWarning(xmlFile, "Invalid component for animation part '%s'. Indexing starts with 1!", xmlKey)
1822 return false
1823 end
1824 end
1825
1826 if value.component ~= nil then
1827 value:setWarningInformation("componentIndex: " .. componentIndex)
1828 value:addCompareParameters("component")
1829
1830 return true
1831 end
1832
1833 return false
1834 end,
1835
1836 function(value)
1837 return getMass(value.component.node) * 1000
1838 end,
1839
1840 function(value, mass)
1841 setMass(value.component.node, mass * 0.001)
1842 end)
1843
1844 self:registerAnimationValueType("centerOfMass", "startCenterOfMass", "endCenterOfMass", false, AnimationValueFloat,
1845 function(value, xmlFile, xmlKey)
1846 local componentIndex = xmlFile:getValue(xmlKey.."#componentIndex")
1847 if componentIndex ~= nil then
1848 if componentIndex >= 1 then
1849 value.component = value.vehicle.components[componentIndex]
1850 end
1851
1852 if value.component == nil then
1853 Logging.xmlWarning(xmlFile, "Invalid component for animation part '%s'. Indexing starts with 1!", xmlKey)
1854 return false
1855 end
1856 end
1857
1858 if value.component ~= nil then
1859 value:setWarningInformation("componentIndex: " .. componentIndex)
1860 value:addCompareParameters("component")
1861
1862 return true
1863 end
1864
1865 return false
1866 end,
1867
1868 function(value)
1869 return getCenterOfMass(value.component.node)
1870 end,
1871
1872 function(value, x, y, z)
1873 setCenterOfMass(value.component.node, x, y, z)
1874 end)
1875
1876 self:registerAnimationValueType("frictionVelocity", "startFrictionVelocity", "endFrictionVelocity", false, AnimationValueFloat, loadNodeFunction,
1877 function(value)
1878 return value.lastFrictionVelocity or 0
1879 end,
1880
1881 function(value, velocity)
1882 setFrictionVelocity(value.node, velocity)
1883 value.lastFrictionVelocity = velocity
1884
1885 if value.origTransX == nil then
1886 value.origTransX, value.origTransY, value.origTransZ = getTranslation(value.node)
1887 end
1888 setTranslation(value.node, value.origTransX + math.random()*0.001, value.origTransY, value.origTransZ)
1889 end)
1890 end
1891
1892 self:registerAnimationValueType("spline", "startSplinePos", "endSplinePos", false, AnimationValueFloat,
1893 function(value, xmlFile, xmlKey)
1894 value.node = xmlFile:getValue(xmlKey .. "#node", nil, value.part.components, value.part.i3dMappings)
1895 value.spline = xmlFile:getValue(xmlKey .. "#spline", nil, value.part.components, value.part.i3dMappings)
1896
1897 if value.node ~= nil and value.spline ~= nil then
1898 value:setWarningInformation("node:" .. getName(value.node) .. " with spline: " .. getName(value.spline))
1899 value:addCompareParameters("node", "spline")
1900
1901 return true
1902 end
1903
1904 return false
1905 end,
1906
1907 function(value)
1908 if value.lastSplineTime ~= nil then
1909 return value.lastSplineTime
1910 end
1911
1912 local startTime = value.startValue or value.endValue
1913 if value.animation.currentSpeed < 0 then
1914 startTime = value.endValue or value.startValue
1915 end
1916
1917 return startTime[1]
1918 end,
1919
1920 function(value, splineTime)
1921 local x, y, z = getSplinePosition(value.spline, splineTime % 1)
1922 x, y, z = worldToLocal(getParent(value.node), x, y, z)
1923 setTranslation(value.node, x, y, z)
1924
1925 value.lastSplineTime = splineTime
1926
1927 for _, part2 in ipairs(value.animation.parts) do
1928 for index=1, #part2.animationValues do
1929 local value2 = part2.animationValues[index]
1930 if value2.node == value.node then
1931 if value2.name == value.name then
1932 value2.lastSplineTime = splineTime
1933 end
1934 end
1935 end
1936 end
1937 end)
1938end

onUpdate

Description
Called on update
Definition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
285function AnimatedVehicle:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
286 AnimatedVehicle.updateAnimations(self, dt)
287
288 local spec = self.spec_animatedVehicle
289 if spec.fixedTimeSamplesDirtyDelay > 0 then
290 spec.fixedTimeSamplesDirtyDelay = spec.fixedTimeSamplesDirtyDelay - 1
291 if spec.fixedTimeSamplesDirtyDelay <= 0 then
292 for _, animation in pairs(spec.animations) do
293 if spec.activeAnimations[animation.name] == nil then
294 if self.isClient then
295 for i=1, #animation.samples do
296 local sample = animation.samples[i]
297 if g_soundManager:getIsSamplePlaying(sample) then
298 if sample.loops == 0 then
299 g_soundManager:stopSample(sample)
300 end
301 end
302 end
303 end
304 end
305 end
306
307 spec.fixedTimeSamplesDirtyDelay = 0
308 end
309 end
310
311 if spec.numActiveAnimations > 0 then
312 self:raiseActive()
313 end
314end

playAnimation

Description
Play animation
Definition
playAnimation(string name, float speed, float animTime, boolean noEventSend)
Arguments
stringnamename of animation
floatspeedspeed
floatanimTimestart time
booleannoEventSendno event send
Code
620function AnimatedVehicle:playAnimation(name, speed, animTime, noEventSend, allowSounds)
621 local spec = self.spec_animatedVehicle
622
623 local animation = spec.animations[name]
624 if animation ~= nil then
625 SpecializationUtil.raiseEvent(self, "onPlayAnimation", name)
626
627 if speed == nil then
628 speed = animation.currentSpeed
629 end
630
631 -- skip animation if speed is not set or 0 to allow skipping animations per xml speed attribute set to 0
632 if speed == nil or speed == 0 then
633 return
634 end
635
636 if animTime == nil then
637 if self:getIsAnimationPlaying(name) then
638 animTime = self:getAnimationTime(name)
639 elseif speed > 0 then
640 animTime = 0
641 else
642 animTime = 1
643 end
644 end
645 if noEventSend == nil or noEventSend == false then
646 if g_server ~= nil then
647 g_server:broadcastEvent(AnimatedVehicleStartEvent.new(self, name, speed, animTime), nil, nil, self)
648 else
649 g_client:getServerConnection():sendEvent(AnimatedVehicleStartEvent.new(self, name, speed, animTime))
650 end
651 end
652
653 if spec.activeAnimations[name] == nil then
654 spec.activeAnimations[name] = animation
655 spec.numActiveAnimations = spec.numActiveAnimations + 1
656 SpecializationUtil.raiseEvent(self, "onStartAnimation", name, speed)
657 end
658 animation.currentSpeed = speed
659 animation.currentTime = animTime*animation.duration
660 self:resetAnimationValues(animation)
661
662 self:raiseActive()
663 end
664end

postInitializeAnimationPart

Description
Post Initialize part of animation (normally used to set default start value if not set by the end value of the previous part)
Definition
postInitializeAnimationPart(table part)
Arguments
tablepartpart
Code
607function AnimatedVehicle:postInitializeAnimationPart(animation, part, i, numParts)
608 for index=1, #part.animationValues do
609 part.animationValues[index]:postInit()
610 end
611end

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
25function AnimatedVehicle.prerequisitesPresent(specializations)
26 return true
27end

registerAnimationValueType

Description
Definition
registerAnimationValueType()
Code
318function AnimatedVehicle:registerAnimationValueType(name, startName, endName, initialUpdate, classObject, load, get, set)
319 local spec = self.spec_animatedVehicle
320
321 if spec.animationValueTypes[name] == nil then
322 local animationValueType = {}
323
324 animationValueType.classObject = classObject
325 animationValueType.name = name
326 animationValueType.startName = startName
327 animationValueType.endName = endName
328 animationValueType.initialUpdate = initialUpdate
329 animationValueType.load = load
330 animationValueType.get = get
331 animationValueType.set = set
332
333 spec.animationValueTypes[name] = animationValueType
334 end
335end

registerAnimationXMLPaths

Description
Definition
registerAnimationXMLPaths()
Code
55function AnimatedVehicle.registerAnimationXMLPaths(schema, basePath)
56 schema:register(XMLValueType.STRING, basePath .. "#name", "Name of animation")
57 schema:register(XMLValueType.BOOL, basePath .. "#looping", "Animation is looping", false)
58 schema:register(XMLValueType.BOOL, basePath .. "#resetOnStart", "Animation is reseted while loading the vehicle", true)
59 schema:register(XMLValueType.FLOAT, basePath .. "#startAnimTime", "Animation is set to this time if resetOnStart is set", 0)
60 schema:register(XMLValueType.FLOAT, basePath .. "#soundVolumeFactor", "Sound volume factor that is applied for all sounds in this animation", 1)
61 schema:register(XMLValueType.BOOL, basePath .. "#isKeyframe", "Is static keyframe animation instead of dynamically interpolating animation (Keyframe animations only support trans/rot/scale!)", false)
62
63 schema:addDelayedRegistrationPath(basePath .. ".part(?)", "AnimatedVehicle:part")
64
65 schema:register(XMLValueType.NODE_INDEX, basePath .. ".part(?)#node", "Part node")
66 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startTime", "Start time")
67 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#duration", "Duration")
68 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endTime", "End time")
69 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#time", "Keyframe time (only for keyframe animations)")
70 schema:register(XMLValueType.INT, basePath .. ".part(?)#direction", "Part direction", 0)
71 schema:register(XMLValueType.STRING, basePath .. ".part(?)#tangentType", "Type of tangent to be used (linear, spline, step)", "linear")
72
73 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRot", "Start rotation")
74 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRot", "End rotation")
75 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTrans", "Start translation")
76 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTrans", "End translation")
77 schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".part(?)#startScale", "Start scale")
78 schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".part(?)#endScale", "End scale")
79 schema:register(XMLValueType.BOOL, basePath .. ".part(?)#visibility", "Visibility")
80 schema:register(XMLValueType.BOOL, basePath .. ".part(?)#startVisibility", "Visibility at start time (switched in the middle)")
81 schema:register(XMLValueType.BOOL, basePath .. ".part(?)#endVisibility", "Visibility at end time (switched in the middle)")
82 schema:register(XMLValueType.INT, basePath .. ".part(?)#componentJointIndex", "Component joint index")
83
84 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#rotation", "Rotation (only for keyframe animations)")
85 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#translation", "Translation (only for keyframe animations)")
86 schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".part(?)#scale", "Scale (only for keyframe animations)")
87
88 schema:register(XMLValueType.STRING, basePath .. ".part(?)#requiredAnimation", "Required animation needs to be in a specific range to play part")
89 schema:register(XMLValueType.VECTOR_2, basePath .. ".part(?)#requiredAnimationRange", "Animation range of required animation")
90
91 schema:register(XMLValueType.STRING, basePath .. ".part(?)#requiredConfigurationName", "This configuration needs to bet set to #requiredConfigurationIndex")
92 schema:register(XMLValueType.INT, basePath .. ".part(?)#requiredConfigurationIndex", "Required configuration needs to be in this state to activate the animation part")
93
94 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRotLimit", "Start rotation limit")
95 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRotMinLimit", "Start rotation min limit")
96 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#startRotMaxLimit", "Start rotation max limit")
97
98 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRotLimit", "End rotation limit")
99 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRotMinLimit", "End rotation min limit")
100 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".part(?)#endRotMaxLimit", "End rotation max limit")
101
102 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTransLimit", "Start translation limit")
103 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTransMinLimit", "Start translation min limit")
104 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startTransMaxLimit", "Start translation max limit")
105
106 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTransLimit", "End translation limit")
107 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTransMinLimit", "End translation min limit")
108 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endTransMaxLimit", "End translation max limit")
109
110 schema:register(XMLValueType.INT, basePath .. ".part(?)#componentIndex", "Component index")
111 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startMass", "Start mass of component")
112 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#startCenterOfMass", "Start center of mass")
113 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endMass", "End mass of component")
114 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".part(?)#endCenterOfMass", "End center of mass")
115
116 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startFrictionVelocity", "Start friction velocity applied to node")
117 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endFrictionVelocity", "End friction velocity applied to node")
118
119 schema:register(XMLValueType.STRING, basePath .. ".part(?)#shaderParameter", "Shader parameter")
120 schema:register(XMLValueType.STRING, basePath .. ".part(?)#shaderParameterPrev", "Shader parameter (prev)")
121 schema:register(XMLValueType.VECTOR_4, basePath .. ".part(?)#shaderStartValues", "Start shader values")
122 schema:register(XMLValueType.VECTOR_4, basePath .. ".part(?)#shaderEndValues", "End shader values")
123
124 schema:register(XMLValueType.STRING, basePath .. ".part(?)#animationClip", "Animation clip name")
125 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#clipStartTime", "Animation clip start time")
126 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#clipEndTime", "Animation clip end time")
127
128 schema:register(XMLValueType.STRING, basePath .. ".part(?)#dependentAnimation", "Dependent animation name")
129 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#dependentAnimationStartTime", "Dependent animation start time")
130 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#dependentAnimationEndTime", "Dependent animation end time")
131
132 schema:register(XMLValueType.NODE_INDEX, basePath .. ".part(?)#spline", "Spline node")
133 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#startSplinePos", "Start spline position")
134 schema:register(XMLValueType.FLOAT, basePath .. ".part(?)#endSplinePos", "End spline position")
135
136 SoundManager.registerSampleXMLPaths(schema, basePath, "sound(?)")
137 schema:register(XMLValueType.TIME, basePath .. ".sound(?)#startTime", "Start play time", 0)
138 schema:register(XMLValueType.TIME, basePath .. ".sound(?)#endTime", "End play time for loops or used on oposite direction")
139 schema:register(XMLValueType.INT, basePath .. ".sound(?)#direction", "Direction to play the sound (0 = any direction)", 0)
140
141 SoundManager.registerSampleXMLPaths(schema, basePath, "stopTimePosSound(?)")
142 SoundManager.registerSampleXMLPaths(schema, basePath, "stopTimeNegSound(?)")
143end

registerEventListeners

Description
Definition
registerEventListeners()
Code
198function AnimatedVehicle.registerEventListeners(vehicleType)
199 SpecializationUtil.registerEventListener(vehicleType, "onPreLoad", AnimatedVehicle)
200 SpecializationUtil.registerEventListener(vehicleType, "onLoad", AnimatedVehicle)
201 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", AnimatedVehicle)
202 SpecializationUtil.registerEventListener(vehicleType, "onDelete", AnimatedVehicle)
203 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", AnimatedVehicle)
204 SpecializationUtil.registerEventListener(vehicleType, "onRegisterAnimationValueTypes", AnimatedVehicle)
205end

registerEvents

Description
Definition
registerEvents()
Code
147function AnimatedVehicle.registerEvents(vehicleType)
148 SpecializationUtil.registerEvent(vehicleType, "onRegisterAnimationValueTypes")
149 SpecializationUtil.registerEvent(vehicleType, "onPlayAnimation")
150 SpecializationUtil.registerEvent(vehicleType, "onStartAnimation")
151 SpecializationUtil.registerEvent(vehicleType, "onUpdateAnimation")
152 SpecializationUtil.registerEvent(vehicleType, "onFinishAnimation")
153 SpecializationUtil.registerEvent(vehicleType, "onStopAnimation")
154 SpecializationUtil.registerEvent(vehicleType, "onAnimationPartChanged")
155end

registerFunctions

Description
Definition
registerFunctions()
Code
159function AnimatedVehicle.registerFunctions(vehicleType)
160 SpecializationUtil.registerFunction(vehicleType, "registerAnimationValueType", AnimatedVehicle.registerAnimationValueType)
161 SpecializationUtil.registerFunction(vehicleType, "loadAnimation", AnimatedVehicle.loadAnimation)
162 SpecializationUtil.registerFunction(vehicleType, "loadAnimationPart", AnimatedVehicle.loadAnimationPart)
163 SpecializationUtil.registerFunction(vehicleType, "loadStaticAnimationPart", AnimatedVehicle.loadStaticAnimationPart)
164 SpecializationUtil.registerFunction(vehicleType, "loadStaticAnimationPartValues", AnimatedVehicle.loadStaticAnimationPartValues)
165 SpecializationUtil.registerFunction(vehicleType, "initializeAnimationParts", AnimatedVehicle.initializeAnimationParts)
166 SpecializationUtil.registerFunction(vehicleType, "initializeAnimationPart", AnimatedVehicle.initializeAnimationPart)
167 SpecializationUtil.registerFunction(vehicleType, "postInitializeAnimationPart", AnimatedVehicle.postInitializeAnimationPart)
168 SpecializationUtil.registerFunction(vehicleType, "playAnimation", AnimatedVehicle.playAnimation)
169 SpecializationUtil.registerFunction(vehicleType, "stopAnimation", AnimatedVehicle.stopAnimation)
170 SpecializationUtil.registerFunction(vehicleType, "getAnimationExists", AnimatedVehicle.getAnimationExists)
171 SpecializationUtil.registerFunction(vehicleType, "getAnimationByName", AnimatedVehicle.getAnimationByName)
172 SpecializationUtil.registerFunction(vehicleType, "getIsAnimationPlaying", AnimatedVehicle.getIsAnimationPlaying)
173 SpecializationUtil.registerFunction(vehicleType, "getRealAnimationTime", AnimatedVehicle.getRealAnimationTime)
174 SpecializationUtil.registerFunction(vehicleType, "setRealAnimationTime", AnimatedVehicle.setRealAnimationTime)
175 SpecializationUtil.registerFunction(vehicleType, "getAnimationTime", AnimatedVehicle.getAnimationTime)
176 SpecializationUtil.registerFunction(vehicleType, "setAnimationTime", AnimatedVehicle.setAnimationTime)
177 SpecializationUtil.registerFunction(vehicleType, "getAnimationDuration", AnimatedVehicle.getAnimationDuration)
178 SpecializationUtil.registerFunction(vehicleType, "setAnimationSpeed", AnimatedVehicle.setAnimationSpeed)
179 SpecializationUtil.registerFunction(vehicleType, "getAnimationSpeed", AnimatedVehicle.getAnimationSpeed)
180 SpecializationUtil.registerFunction(vehicleType, "setAnimationStopTime", AnimatedVehicle.setAnimationStopTime)
181 SpecializationUtil.registerFunction(vehicleType, "resetAnimationValues", AnimatedVehicle.resetAnimationValues)
182 SpecializationUtil.registerFunction(vehicleType, "resetAnimationPartValues", AnimatedVehicle.resetAnimationPartValues)
183 SpecializationUtil.registerFunction(vehicleType, "updateAnimationPart", AnimatedVehicle.updateAnimationPart)
184 SpecializationUtil.registerFunction(vehicleType, "getNumOfActiveAnimations", AnimatedVehicle.getNumOfActiveAnimations)
185end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
189function AnimatedVehicle.registerOverwrittenFunctions(vehicleType)
190 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadSpeedRotatingPartFromXML", AnimatedVehicle.loadSpeedRotatingPartFromXML)
191 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsSpeedRotatingPartActive", AnimatedVehicle.getIsSpeedRotatingPartActive)
192 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", AnimatedVehicle.loadWorkAreaFromXML)
193 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", AnimatedVehicle.getIsWorkAreaActive)
194end

resetAnimationPartValues

Description
Resets animation part
Definition
resetAnimationPartValues(table part)
Arguments
tablepartpart to reset
Code
880function AnimatedVehicle:resetAnimationPartValues(part)
881 for index=1, #part.animationValues do
882 part.animationValues[index]:reset()
883 end
884end

resetAnimationValues

Description
Resets animation values
Definition
resetAnimationValues(table animation)
Arguments
tableanimationanimation
Code
870function AnimatedVehicle:resetAnimationValues(animation)
871 AnimatedVehicle.findCurrentPartIndex(animation)
872 for _, part in ipairs(animation.parts) do
873 self:resetAnimationPartValues(part)
874 end
875end

setAnimationSpeed

Description
Sets speed of animation
Definition
setAnimationSpeed(string name, float speed)
Arguments
stringnamename of animation
floatspeedspeed
Code
823function AnimatedVehicle:setAnimationSpeed(name, speed)
824 local spec = self.spec_animatedVehicle
825
826 local animation = spec.animations[name]
827 if animation ~= nil then
828 local speedReversed = false
829 if (animation.currentSpeed > 0) ~= (speed > 0) then
830 speedReversed = true
831 end
832 animation.currentSpeed = speed
833 if self:getIsAnimationPlaying(name) and speedReversed then
834 self:resetAnimationValues(animation)
835 end
836 end
837end

setAnimationStopTime

Description
Sets animation stop time
Definition
setAnimationStopTime(string name, float stopTime)
Arguments
stringnamename of animation
floatstopTimestop time [0..1]
Code
858function AnimatedVehicle:setAnimationStopTime(name, stopTime)
859 local spec = self.spec_animatedVehicle
860
861 local animation = spec.animations[name]
862 if animation ~= nil then
863 animation.stopTime = stopTime*animation.duration
864 end
865end

setAnimationTime

Description
Set animation time
Definition
setAnimationTime(string name, float animTime, boolean update)
Arguments
stringnamename of animation
floatanimTimeanimation time [0..1]
booleanupdateupdate animation
Code
792function AnimatedVehicle:setAnimationTime(name, animTime, update, playSounds)
793 local spec = self.spec_animatedVehicle
794
795 if spec.animations == nil then
796 printCallstack()
797 end
798
799 local animation = spec.animations[name]
800 if animation ~= nil then
801 self:setRealAnimationTime(name, animTime*animation.duration, update, playSounds)
802 end
803end

setMovedLimitedValues3

Description
Sets moved limited values (3)
Definition
setMovedLimitedValues3(table currentValues, table destValues, table speeds, float dt)
Arguments
tablecurrentValuescurrent values
tabledestValuesdest values
tablespeedsspeeds
floatdttime since last call in ms
Code
1072function AnimatedVehicle.setMovedLimitedValues3(currentValues, destValues, speeds, dt)
1073 return AnimatedVehicle.setMovedLimitedValuesN(3, currentValues, destValues, speeds, dt)
1074end

setMovedLimitedValues4

Description
Sets moved limited values (4)
Definition
setMovedLimitedValues4(table currentValues, table destValues, table speeds, float dt)
Arguments
tablecurrentValuescurrent values
tabledestValuesdest values
tablespeedsspeeds
floatdttime since last call in ms
Code
1082function AnimatedVehicle.setMovedLimitedValues4(currentValues, destValues, speeds, dt)
1083 return AnimatedVehicle.setMovedLimitedValuesN(4, currentValues, destValues, speeds, dt)
1084end

setMovedLimitedValuesN

Description
Sets moved limited values on N values
Definition
setMovedLimitedValuesN(int n, table currentValues, table destValues, table speeds, float dt)
Arguments
intnnumber of values
tablecurrentValuescurrent values
tabledestValuesdest values
tablespeedsspeeds
floatdttime since last call in ms
Code
1054function AnimatedVehicle.setMovedLimitedValuesN(n, currentValues, destValues, speeds, dt)
1055 local hasChanged = false
1056 for i=1, n do
1057 local newValue = AnimatedVehicle.getMovedLimitedValue(currentValues[i], destValues[i], speeds[i], dt)
1058 if currentValues[i] ~= newValue then
1059 hasChanged = true
1060 currentValues[i] = newValue
1061 end
1062 end
1063 return hasChanged
1064end

setRealAnimationTime

Description
Set animation real time
Definition
setRealAnimationTime(string name, float animTime, boolean update)
Arguments
stringnamename of animation
floatanimTimereal animation time in ms
booleanupdateupdate animation
Code
750function AnimatedVehicle:setRealAnimationTime(name, animTime, update, playSounds)
751 local spec = self.spec_animatedVehicle
752
753 local animation = spec.animations[name]
754 if animation ~= nil then
755 if update == nil or update then
756 local currentSpeed = animation.currentSpeed
757 animation.currentSpeed = 1
758 if animation.currentTime > animTime then
759 animation.currentSpeed = -1
760 end
761
762 self:resetAnimationValues(animation)
763
764 local dtToUse, _ = AnimatedVehicle.updateAnimationCurrentTime(self, animation, 99999999, animTime)
765 AnimatedVehicle.updateAnimation(self, animation, dtToUse, true, true, playSounds)
766 animation.currentSpeed = currentSpeed
767 else
768 animation.currentTime = animTime
769 end
770 end
771end

stopAnimation

Description
Stop animation
Definition
stopAnimation(string name, boolean noEventSend)
Arguments
stringnamename of animation
booleannoEventSendno event send
Code
670function AnimatedVehicle:stopAnimation(name, noEventSend)
671 local spec = self.spec_animatedVehicle
672
673 if noEventSend == nil or noEventSend == false then
674 if g_server ~= nil then
675 g_server:broadcastEvent(AnimatedVehicleStopEvent.new(self, name), nil, nil, self)
676 else
677 g_client:getServerConnection():sendEvent(AnimatedVehicleStopEvent.new(self, name))
678 end
679 end
680 local animation = spec.animations[name]
681 if animation ~= nil then
682 SpecializationUtil.raiseEvent(self, "onStopAnimation", name)
683 animation.stopTime = nil
684
685 if self.isClient then
686 for i=1, #animation.samples do
687 local sample = animation.samples[i]
688 if sample.loops == 0 then
689 g_soundManager:stopSample(sample)
690 end
691 end
692 end
693 end
694
695 if spec.activeAnimations[name] ~= nil then
696 spec.numActiveAnimations = spec.numActiveAnimations - 1
697 spec.activeAnimations[name] = nil
698 SpecializationUtil.raiseEvent(self, "onFinishAnimation", name)
699 end
700end

updateAnimation

Description
Update animation
Definition
updateAnimation(table anim, float dtToUse, boolean stopAnimation, boolean fixedTimeUpdate, playSounds playSounds)
Arguments
tableanimanimation
floatdtToUsedt to use
booleanstopAnimationstop animation
booleanfixedTimeUpdateis a fixed time update (e.g. from setAnimationTime) -> no sound, no looping, fixed setting between start and end values
playSoundsplaySoundsif true it still plays sounds while doing fixed time updates
Code
1210function AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim, fixedTimeUpdate, playSounds)
1211 local spec = self.spec_animatedVehicle
1212 local isStopTimeStop = stopAnim
1213
1214 local numParts = #anim.parts
1215 local parts = anim.parts
1216 if anim.currentSpeed < 0 then
1217 parts = anim.partsReverse
1218 end
1219
1220 if dtToUse > 0 then
1221 local hasChanged = false
1222 local nothingToChangeYet = false
1223
1224 if not anim.isKeyframe then
1225 for partI=anim.currentPartIndex, numParts do
1226 local part = parts[partI]
1227
1228 local isInRange = true
1229 if part.requiredAnimation ~= nil then
1230 local time = self:getAnimationTime(part.requiredAnimation)
1231 if time < part.requiredAnimationRange[1] or time > part.requiredAnimationRange[2] then
1232 isInRange = false
1233 end
1234 end
1235
1236 local sameConfiguration = true
1237 if part.requiredConfigurationName ~= nil then
1238 if self.configurations[part.requiredConfigurationName] ~= nil then
1239 if self.configurations[part.requiredConfigurationName] ~= part.requiredConfigurationIndex then
1240 sameConfiguration = false
1241 end
1242 end
1243 end
1244
1245 if (part.direction == 0 or ((part.direction > 0) == (anim.currentSpeed >= 0))) and isInRange and sameConfiguration then
1246 local durationToEnd = AnimatedVehicle.getDurationToEndOfPart(part, anim)
1247
1248 -- is this part not playing yet?
1249 if durationToEnd > part.duration then
1250 nothingToChangeYet = true
1251 break
1252 end
1253
1254 local realDt = dtToUse
1255
1256 if anim.currentSpeed > 0 then
1257 local startT = anim.currentTime-dtToUse
1258 if startT < part.startTime then
1259 realDt = dtToUse - part.startTime + startT
1260 end
1261 else
1262 local startT = anim.currentTime+dtToUse
1263 local endTime = part.startTime + part.duration
1264 if startT > endTime then
1265 realDt = dtToUse - (startT - endTime)
1266 end
1267 end
1268
1269 durationToEnd = durationToEnd + realDt
1270
1271 if self:updateAnimationPart(anim, part, durationToEnd, dtToUse, realDt, fixedTimeUpdate) then
1272 hasChanged = true
1273 end
1274 end
1275
1276 if partI == anim.currentPartIndex then
1277 -- is this part finished?
1278 if (anim.currentSpeed > 0 and part.startTime + part.duration < anim.currentTime) or
1279 (anim.currentSpeed <= 0 and part.startTime > anim.currentTime)
1280 then
1281 self:resetAnimationPartValues(part)
1282 anim.currentPartIndex = anim.currentPartIndex+1
1283 end
1284 end
1285 end
1286 if not nothingToChangeYet and not hasChanged and anim.currentPartIndex >= numParts then
1287 -- end the animation
1288 anim.previousTime = anim.currentTime
1289 if anim.currentSpeed > 0 then
1290 anim.currentTime = anim.duration
1291 else
1292 anim.currentTime = 0
1293 end
1294 stopAnim = true
1295 end
1296 else
1297 for node, curve in pairs(anim.curvesByNode) do
1298 local x, y, z, rx, ry, rz, sx, sy, sz = curve:get(anim.currentTime)
1299 if curve.hasTranslation then
1300 setTranslation(node, x, y, z)
1301 end
1302 if curve.hasRotation then
1303 setRotation(node, rx, ry, rz)
1304 end
1305 if curve.hasScale then
1306 setScale(node, sx, sy, sz)
1307 end
1308
1309 SpecializationUtil.raiseEvent(self, "onAnimationPartChanged", node)
1310 end
1311
1312 stopAnim = anim.currentTime <= 0 or anim.currentTime >= anim.duration
1313 end
1314
1315 if spec.activeAnimations[anim.name] ~= nil or playSounds == true then
1316 if fixedTimeUpdate ~= true or playSounds == true then
1317 for i=1, #anim.samples do
1318 local sample = anim.samples[i]
1319 if g_soundManager:getIsSamplePlaying(sample) then
1320 if sample.endTime ~= nil then
1321 if anim.currentSpeed > 0 then
1322 if anim.currentTime > sample.endTime then
1323 g_soundManager:stopSample(sample)
1324 end
1325 else
1326 if anim.currentTime < sample.startTime then
1327 g_soundManager:stopSample(sample)
1328 end
1329 end
1330 end
1331 else
1332 if sample.direction == 0 or ((sample.direction >= 0) == (anim.currentSpeed >= 0)) then
1333 if sample.loops ~= 0 then
1334 if sample.endTime ~= nil then
1335 sample.readyToStart = anim.previousTime < sample.startTime or anim.previousTime > sample.endTime
1336 else
1337 if anim.currentSpeed < 0 then
1338 sample.readyToStart = anim.previousTime > sample.startTime
1339
1340 else
1341 sample.readyToStart = anim.previousTime < sample.startTime
1342 end
1343 end
1344 else
1345 sample.readyToStart = true
1346 end
1347
1348 local inRange = anim.currentTime >= sample.startTime
1349 if sample.endTime ~= nil then
1350 inRange = anim.currentTime >= sample.startTime and anim.currentTime <= sample.endTime
1351 else
1352 if anim.currentSpeed < 0 then
1353 inRange = anim.currentTime <= sample.startTime
1354 end
1355 end
1356
1357 if sample.readyToStart and inRange then
1358 g_soundManager:playSample(sample)
1359 end
1360 end
1361 end
1362 end
1363 end
1364
1365 SpecializationUtil.raiseEvent(self, "onUpdateAnimation", anim.name)
1366
1367 if spec.activeAnimations[anim.name] == nil then
1368 spec.fixedTimeSamplesDirtyDelay = 2
1369 end
1370 end
1371 end
1372 if stopAnim or (numParts > 0 and (anim.currentPartIndex > numParts or anim.currentPartIndex < 1)) then
1373 anim.previousTime = anim.currentTime
1374 if not stopAnim then
1375 if anim.currentSpeed > 0 then
1376 anim.currentTime = anim.duration
1377 else
1378 anim.currentTime = 0
1379 end
1380 end
1381 anim.currentTime = math.min(math.max(anim.currentTime, 0), anim.duration)
1382 local allowLooping = anim.stopTime ~= anim.currentTime
1383 anim.stopTime = nil
1384 if spec.activeAnimations[anim.name] ~= nil then
1385 spec.numActiveAnimations = spec.numActiveAnimations - 1
1386
1387 if self.isClient then
1388 local animation = spec.activeAnimations[anim.name]
1389 for i=1, #animation.samples do
1390 local sample = animation.samples[i]
1391 if sample.loops == 0 then
1392 g_soundManager:stopSample(sample)
1393 end
1394 end
1395
1396 if isStopTimeStop then
1397 if anim.currentSpeed > 0 then
1398 for i=1, #animation.eventSamples.stopTimePos do
1399 g_soundManager:playSample(animation.eventSamples.stopTimePos[i])
1400 end
1401 else
1402 for i=1, #animation.eventSamples.stopTimeNeg do
1403 g_soundManager:playSample(animation.eventSamples.stopTimeNeg[i])
1404 end
1405 end
1406 end
1407 end
1408
1409 spec.activeAnimations[anim.name] = nil
1410 SpecializationUtil.raiseEvent(self, "onFinishAnimation", anim.name)
1411 end
1412
1413 if allowLooping and fixedTimeUpdate ~= true then
1414 if anim.looping then
1415 -- restart animation
1416 self:setAnimationTime(anim.name, math.abs((anim.currentTime/anim.duration) - 1), true)
1417 self:playAnimation(anim.name, anim.currentSpeed, nil, true)
1418 end
1419 end
1420 end
1421end

updateAnimationByName

Description
Update animation by name
Definition
updateAnimationByName(string animName, float dt)
Arguments
stringanimNamename of animation to update
floatdttime since last call in ms
Code
1161function AnimatedVehicle.updateAnimationByName(self, animName, dt, fixedTimeUpdate)
1162 local spec = self.spec_animatedVehicle
1163
1164 local anim = spec.animations[animName]
1165 if anim ~= nil then
1166 local dtToUse, stopAnim = AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, anim.stopTime)
1167 AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim, fixedTimeUpdate)
1168 end
1169end

updateAnimationCurrentTime

Description
Update current animation time
Definition
updateAnimationCurrentTime(table anim, float dt, float stopTime)
Arguments
tableanimanimation
floatdttime since last call in ms
floatstopTimestop time
Return Values
floatdtToUsedt to use
booleanstopAnimationstop animation
Code
1178function AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, stopTime)
1179 anim.previousTime = anim.currentTime
1180 anim.currentTime = anim.currentTime + dt*anim.currentSpeed
1181
1182 local absSpeed = math.abs(anim.currentSpeed)
1183 local dtToUse = dt*absSpeed
1184 local stopAnim = false
1185 if stopTime ~= nil then
1186 if anim.currentSpeed > 0 then
1187 if stopTime <= anim.currentTime then
1188 dtToUse = dtToUse-(anim.currentTime-stopTime)
1189 anim.currentTime = stopTime
1190 stopAnim = true
1191 end
1192 else
1193 if stopTime >= anim.currentTime then
1194 dtToUse = dtToUse-(stopTime-anim.currentTime)
1195 anim.currentTime = stopTime
1196 stopAnim = true
1197 end
1198 end
1199 end
1200 return dtToUse, stopAnim
1201end

updateAnimationPart

Description
Update animation part
Definition
updateAnimationPart(table anim, table part, float durationToEnd, float dtToUse, float realDt)
Arguments
tableanimanimation
tablepartpart
floatdurationToEndduration to end
floatdtToUsedt to use
floatrealDtreal dt
Code
1430function AnimatedVehicle:updateAnimationPart(animation, part, durationToEnd, dtToUse, realDt, fixedTimeUpdate)
1431 local hasPartChanged = false
1432
1433 for index=1, #part.animationValues do
1434 local valueChanged = part.animationValues[index]:update(durationToEnd, dtToUse, realDt, fixedTimeUpdate)
1435 hasPartChanged = hasPartChanged or valueChanged
1436 end
1437
1438 return hasPartChanged
1439end

updateAnimations

Description
Update animations
Definition
updateAnimations(float dt)
Arguments
floatdttime since last call in ms
Code
1148function AnimatedVehicle.updateAnimations(self, dt, fixedTimeUpdate)
1149 local spec = self.spec_animatedVehicle
1150
1151 for _, anim in pairs(spec.activeAnimations) do
1152 local dtToUse, stopAnim = AnimatedVehicle.updateAnimationCurrentTime(self, anim, dt, anim.stopTime)
1153 AnimatedVehicle.updateAnimation(self, anim, dtToUse, stopAnim, fixedTimeUpdate)
1154 end
1155end