LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

Rideable

Description
Specialization class for Rideables
XML Configuration Parameters
vehicle.rideable#speedBackwardsmax speed in gait type backwards (m/s)
vehicle.rideable#speedWalkmax speed in gait type walk (m/s)
vehicle.rideable#speedTrotmax speed in gait type trot (m/s)
vehicle.rideable#speedGallopmax speed in gait type gallop (m/s)
vehicle.rideable#turnAnglemax turn speed (deg/s)

Functions

actionEventAccelerate

Description
Callback on accelerate event
Definition
actionEventAccelerate(table self, string actionName, float inputValue, string callbackState, bool isAnalog)
Arguments
tableselfinstance
stringactionNameaction name
floatinputValueinput value
stringcallbackState
boolisAnalogtrue if input is analog
Code
1383function Rideable.actionEventAccelerate(self, actionName, inputValue, callbackState, isAnalog)
1384 local spec = self.spec_rideable
1385 local enterable = self.spec_enterable
1386
1387 if enterable.isEntered and enterable.isControlled and spec.haltTimer <= 0 and spec.isOnGround then
1388 self:setCurrentGait(math.min(self:getCurrentGait() + 1, Rideable.GAITTYPES.MAX))
1389 end
1390end

actionEventBrake

Description
Callback on brake event
Definition
actionEventBrake(table self, string actionName, float inputValue, string callbackState, bool isAnalog)
Arguments
tableselfinstance
stringactionNameaction name
floatinputValueinput value
stringcallbackState
boolisAnalogtrue if input is analog
Code
1399function Rideable.actionEventBrake(self, actionName, inputValue, callbackState, isAnalog)
1400 local spec = self.spec_rideable
1401 if self:getIsEntered() and spec.haltTimer <= 0 and spec.isOnGround then
1402 self:setCurrentGait(math.max(self:getCurrentGait() - 1, 1))
1403 end
1404end

actionEventJump

Description
Callback on jump event
Definition
actionEventJump(table self, string actionName, float inputValue, string callbackState, bool isAnalog)
Arguments
tableselfinstance
stringactionNameaction name
floatinputValueinput value
stringcallbackState
boolisAnalogtrue if input is analog
Code
1427function Rideable.actionEventJump(self, actionName, inputValue, callbackState, isAnalog)
1428 if self:getIsRideableJumpAllowed() then
1429 self:jump()
1430 end
1431end

actionEventSteer

Description
Callback on steer event
Definition
actionEventSteer(table self, string actionName, float inputValue, string callbackState, bool isAnalog)
Arguments
tableselfinstance
stringactionNameaction name
floatinputValueinput value
stringcallbackState
boolisAnalogtrue if input is analog
Code
1413function Rideable.actionEventSteer(self, actionName, inputValue, callbackState, isAnalog)
1414 local spec = self.spec_rideable
1415 if self:getIsEntered() and spec.haltTimer <= 0 then
1416 self:setRideableSteer(inputValue)
1417 end
1418end

calculateLegsDistance

Description
Gets legs distance from rootNode
Definition
calculateLegsDistance(integer left, integer right)
Arguments
integerleftleg node
integerrightleg node
Return Values
floatdistancefrom root node
Code
512function Rideable:calculateLegsDistance(leftLegNode, rightLegNode)
513 local distance = 0.0
514 if leftLegNode ~= nil and rightLegNode ~= nil then
515 local _, _, dzL = localToLocal(leftLegNode, self.rootNode, 0.0, 0.0, 0.0)
516 local _, _, dzR = localToLocal(rightLegNode, self.rootNode, 0.0, 0.0, 0.0)
517 distance = (dzL + dzR) * 0.5
518 end
519 return distance
520end

dayChanged

Description
Definition
dayChanged()
Code
1612function Rideable:dayChanged(superFunc)
1613 superFunc(self)
1614
1615 local spec = self.spec_rideable
1616 if spec.cluster ~= nil then
1617 spec.cluster:onDayChanged()
1618 end
1619end

deleteVehicleCharacter

Description
Definition
deleteVehicleCharacter()
Code
1637function Rideable:deleteVehicleCharacter(superFunc)
1638 self:setEquipmentVisibility(false)
1639 self:unlinkReins()
1640
1641 superFunc(self)
1642end

endFade

Description
Definition
endFade()
Code
662function Rideable:endFade()
663end

getCanBeReset

Description
Definition
getCanBeReset()
Code
1596function Rideable:getCanBeReset(superFunc)
1597 return false
1598end

getCluster

Description
Definition
getCluster()
Code
714function Rideable:getCluster()
715 return self.spec_rideable.cluster
716end

getCurrentGait

Description
Definition
getCurrentGait()
Code
984function Rideable:getCurrentGait()
985 return self.spec_rideable.inputValues.currentGait
986end

getFullName

Description
Definition
getFullName()
Code
1590function Rideable:getFullName(superFunc)
1591 return self:getName()
1592end

getHoofSurfaceSound

Description
Definition
getHoofSurfaceSound()
Code
1535function Rideable:getHoofSurfaceSound(x, y, z, hitTerrain)
1536 local spec = self.spec_rideable
1537
1538 if hitTerrain then
1539 local snowHeight = g_currentMission.snowSystem:getSnowHeightAtArea(x, z, x+0.1, z+0.1, x+0.1, z)
1540 if snowHeight > 0 then
1541 return spec.surfaceNameToSound["snow"]
1542 else
1543 local isOnField, _ = FSDensityMapUtil.getFieldDataAtWorldPosition(x, y, z)
1544 if isOnField then
1545 return spec.surfaceNameToSound["field"]
1546 elseif self.isInShallowWater then
1547 return spec.surfaceNameToSound["shallowWater"]
1548 elseif self.isInMediumWater then
1549 return spec.surfaceNameToSound["mediumWater"]
1550 end
1551 end
1552
1553 local _, _, _, _ , materialId = getTerrainAttributesAtWorldPos(g_currentMission.terrainRootNode, x, y, z, true, true, true, true, false)
1554 return spec.surfaceIdToSound[materialId]
1555 else
1556 return spec.surfaceNameToSound["asphalt"]
1557 end
1558end

getImageFilename

Description
Definition
getImageFilename()
Code
1623function Rideable:getImageFilename(superFunc)
1624 local imageFilename = superFunc(self)
1625
1626 local cluster = self:getCluster()
1627 if cluster ~= nil then
1628 local visual = g_currentMission.animalSystem:getVisualByAge(cluster.subTypeIndex, cluster:getAge())
1629 imageFilename = visual.store.imageFilename
1630 end
1631
1632 return imageFilename
1633end

getIsRideableJumpAllowed

Description
Definition
getIsRideableJumpAllowed()
Code
939function Rideable:getIsRideableJumpAllowed(allowWhileJump)
940 local spec = self.spec_rideable
941
942 if not spec.isOnGround and not allowWhileJump then
943 return false
944 end
945
946 if spec.inputValues.currentGait < Rideable.GAITTYPES.CANTER then
947 return false
948 end
949
950 if self.isBroken then
951 return false
952 end
953
954 return true
955end

getName

Description
Definition
getName()
Code
1583function Rideable:getName(superFunc)
1584 local spec = self.spec_rideable
1585 return spec.cluster:getName()
1586end

getPosition

Description
Definition
getPosition()
Code
1562function Rideable:getPosition()
1563 return getWorldTranslation(self.rootNode)
1564end

getRotation

Description
Definition
getRotation()
Code
1568function Rideable:getRotation()
1569 return getWorldRotation(self.rootNode)
1570end

groundRaycastCallback

Description
Callback used when raycast hists an object. Updates player information so it can be used to pickup the object.
Definition
groundRaycastCallback(integer hitObjectId, float x, float y, float z, float distance)
Arguments
integerhitObjectIdscenegraph object id
floatxworld x hit position
floatyworld y hit position
floatzworld z hit position
floatdistancedistance at which the cast hit the object
Return Values
boolreturnstrue object that was hit is valid
Code
1078function Rideable:groundRaycastCallback(hitObjectId, x, y, z, distance)
1079 local spec = self.spec_rideable
1080 if hitObjectId == self.spec_cctdrivable.cctNode then
1081 return true
1082 end
1083 -- DebugUtil.drawSimpleDebugCube(x, y, z, 0.05, 1, 0, 0)
1084 spec.groundRaycastResult.y = y
1085 spec.groundRaycastResult.object = hitObjectId
1086 spec.groundRaycastResult.distance = distance
1087
1088 return false
1089end

initSpecialization

Description
Definition
initSpecialization()
Code
60function Rideable.initSpecialization()
61 local schema = Vehicle.xmlSchema
62 schema:setXMLSpecializationType("Rideable")
63
64 schema:register(XMLValueType.FLOAT, "vehicle.rideable#speedBackwards", "Backward speed", -1)
65 schema:register(XMLValueType.FLOAT, "vehicle.rideable#speedWalk", "Walk speed", 2.5)
66 schema:register(XMLValueType.FLOAT, "vehicle.rideable#speedCanter", "Canter speed", 3.5)
67 schema:register(XMLValueType.FLOAT, "vehicle.rideable#speedTrot", "Trot speed", 5.0)
68 schema:register(XMLValueType.FLOAT, "vehicle.rideable#speedGallop", "Gallop speed", 10.0)
69
70 schema:register(XMLValueType.FLOAT, "vehicle.rideable#minTurnRadiusBackwards", "Min turning radius backward", 1)
71 schema:register(XMLValueType.FLOAT, "vehicle.rideable#minTurnRadiusWalk", "Min turning radius walk", 1)
72 schema:register(XMLValueType.FLOAT, "vehicle.rideable#minTurnRadiusCanter", "Min turning radius canter", 2.5)
73 schema:register(XMLValueType.FLOAT, "vehicle.rideable#minTurnRadiusTrot", "Min turning radius trot", 5)
74 schema:register(XMLValueType.FLOAT, "vehicle.rideable#minTurnRadiusGallop", "Min turning radius gallop", 10)
75
76 schema:register(XMLValueType.ANGLE, "vehicle.rideable#turnSpeed", "Turn speed (deg/s)", 45)
77 schema:register(XMLValueType.FLOAT, "vehicle.rideable#jumpHeight", "Jump height", 2)
78
79 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable#proxy", "Proxy node")
80 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofFrontLeft#node", "Hoof node")
81 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofFrontLeft.particleSystemSlow#node", "Slow step particle emitterShape")
82 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofFrontLeft.particleSystemSlow#particleType", "Slow step particle type")
83 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofFrontLeft.particleSystemSlow")
84 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofFrontLeft.particleSystemFast#node", "Fast step particle emitterShape")
85 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofFrontLeft.particleSystemFast#particleType", "Fast step particle type")
86 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofFrontLeft.particleSystemFast")
87
88 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofFrontRight#node", "Hoof node")
89 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofFrontRight.particleSystemSlow#node", "Slow step particle emitterShape")
90 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofFrontRight.particleSystemSlow#particleType", "Slow step particle type")
91 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofFrontRight.particleSystemSlow")
92 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofFrontRight.particleSystemFast#node", "Fast step particle emitterShape")
93 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofFrontRight.particleSystemFast#particleType", "Fast step particle type")
94 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofFrontRight.particleSystemFast")
95
96 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofBackLeft#node", "Hoof node")
97 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofBackLeft.particleSystemSlow#node", "Slow step particle emitterShape")
98 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofBackLeft.particleSystemSlow#particleType", "Slow step particle type")
99 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofBackLeft.particleSystemSlow")
100 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofBackLeft.particleSystemFast#node", "Fast step particle emitterShape")
101 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofBackLeft.particleSystemFast#particleType", "Fast step particle type")
102 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofBackLeft.particleSystemFast")
103
104 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofBackRight#node", "Hoof node")
105 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofBackRight.particleSystemSlow#node", "Slow step particle emitterShape")
106 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofBackRight.particleSystemSlow#particleType", "Slow step particle type")
107 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofBackRight.particleSystemSlow")
108 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo.hoofBackRight.particleSystemFast#node", "Fast step particle emitterShape")
109 schema:register(XMLValueType.STRING, "vehicle.rideable.modelInfo.hoofBackRight.particleSystemFast#particleType", "Fast step particle type")
110 ParticleUtil.registerParticleCopyXMLPaths(schema, "vehicle.rideable.modelInfo.hoofBackRight.particleSystemFast")
111
112 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo#animationNode", "Animation node")
113 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo#meshNode", "Mesh node")
114 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo#equipmentNode", "Equipment node")
115 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo#reinsNode", "Reins node")
116 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo#reinLeftNode", "Rein left node")
117 schema:register(XMLValueType.NODE_INDEX, "vehicle.rideable.modelInfo#reinRightNode", "Rein right node")
118
119 schema:register(XMLValueType.FLOAT, "vehicle.rideable.sounds#breathIntervalNoEffort", "Breath interval no effort", 1)
120 schema:register(XMLValueType.FLOAT, "vehicle.rideable.sounds#breathIntervalEffort", "Breath interval effort", 1)
121 schema:register(XMLValueType.FLOAT, "vehicle.rideable.sounds#minBreathIntervalIdle", "Min. breath interval idle", 1)
122 schema:register(XMLValueType.FLOAT, "vehicle.rideable.sounds#maxBreathIntervalIdle", "Max. breath interval idle", 1)
123
124 SoundManager.registerSampleXMLPaths(schema, "vehicle.rideable.sounds", "halt")
125 SoundManager.registerSampleXMLPaths(schema, "vehicle.rideable.sounds", "breathingNoEffort")
126 SoundManager.registerSampleXMLPaths(schema, "vehicle.rideable.sounds", "breathingEffort")
127
128 -- values loaded only by engine, registration just for documentation/validation purposes
129 local registerConditionalAnimation = function(xmlKey)
130 schema:register(XMLValueType.STRING, xmlKey .. ".item(?)#id", "")
131 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?)#entryTransitionDuration", "")
132 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?)#exitTransitionDuration", "")
133
134 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips#speedScaleType", "")
135 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).clips#speedScaleParameter", "")
136 schema:register(XMLValueType.BOOL, xmlKey .. ".item(?).clips#blended", "")
137 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips#blendingParameter", "")
138 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips#blendingParameterType", "")
139 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips.clip(?)#clipName", "")
140 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).clips.clip(?)#id", "")
141 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).clips.clip(?)#blendingThreshold", "")
142
143 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#parameter", "")
144 schema:register(XMLValueType.BOOL, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#equal", "")
145 schema:register(XMLValueType.STRING, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#between", "")
146 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#greater", "")
147 schema:register(XMLValueType.FLOAT, xmlKey .. ".item(?).conditions.conditionGroup(?).condition(?)#lower", "")
148 end
149
150 registerConditionalAnimation('vehicle.conditionalAnimation')
151 registerConditionalAnimation('vehicle.riderConditionalAnimation')
152
153 schema:setXMLSpecializationType()
154
155 local savegameSchema = Vehicle.xmlSchemaSavegame
156 savegameSchema:register(XMLValueType.STRING, "vehicles.vehicle(?).rideable#animalType", "Animal type name")
157end

jump

Description
Definition
jump()
Code
959function Rideable:jump()
960 local spec = self.spec_rideable
961
962 if not self.isServer then
963 g_client:getServerConnection():sendEvent(JumpEvent.new(self))
964 else
965 local stats = g_currentMission:farmStats(self:getOwnerFarmId())
966 local total = stats:updateStats("horseJumpCount", 1)
967 g_achievementManager:tryUnlock("HorseJumpsFirst", total)
968 g_achievementManager:tryUnlock("HorseJumps", total)
969 end
970
971 local velY = math.sqrt(-2.0 * spec.gravity * spec.jumpHeight)
972 spec.currentSpeedY = velY
973end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
524function Rideable:onDelete()
525 local spec = self.spec_rideable
526
527 g_currentMission.husbandrySystem:removeRideable(self)
528
529 g_soundManager:deleteSamples(spec.surfaceSounds)
530 g_soundManager:deleteSample(spec.horseStopSound)
531 g_soundManager:deleteSample(spec.horseBreathSoundsNoEffort)
532 g_soundManager:deleteSample(spec.horseBreathSoundsEffort)
533
534 if spec.hooves ~= nil then
535 for _, d in pairs(spec.hooves) do
536 ParticleUtil.deleteParticleSystem(d.psSlow)
537 ParticleUtil.deleteParticleSystem(d.psFast)
538 delete(d.psSlow.emitterShape)
539 delete(d.psFast.emitterShape)
540 end
541 end
542
543 if spec.animationPlayer ~= nil then
544 delete(spec.animationPlayer)
545 spec.animationPlayer = nil
546 end
547end

onDraw

Description
Definition
onDraw()
Code
892function Rideable:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
893 local spec = self.spec_rideable
894 if isActiveForInputIgnoreSelection and spec.cluster ~= nil then
895 g_currentMission:addExtraPrintText(string.format("%s: %d %%", g_i18n:getText("infohud_riding"), spec.cluster:getRidingFactor() * 100))
896 end
897end

onEnterVehicle

Description
Called on enter vehicle
Definition
onEnterVehicle(bool isControlling)
Arguments
boolisControlling
Code
1277function Rideable:onEnterVehicle(isControlling)
1278 local spec = self.spec_rideable
1279
1280 if self.isClient then
1281 spec.playerToEnter = nil
1282 spec.checkPlayerToEnter = false
1283
1284 spec.currentSpeed = 0.0
1285 spec.currentTurnSpeed = 0.0
1286 self:setCurrentGait(Rideable.GAITTYPES.STILL)
1287 spec.isOnGround = false
1288
1289 -- rider animation
1290-- local character = self:getVehicleCharacter()
1291 end
1292
1293 if self.isServer then
1294 spec.lastOwner = self:getOwner()
1295
1296 setCollisionMask(self.components[1].node, 0)
1297
1298 spec.doHusbandryCheck = 0
1299 end
1300end

onLeaveVehicle

Description
Called on leaving vehicle
Definition
onLeaveVehicle()
Code
1333function Rideable:onLeaveVehicle()
1334 local spec = self.spec_rideable
1335 if self.isClient then
1336 spec.inputValues.currentGait = Rideable.GAITTYPES.STILL
1337 self:resetInputs()
1338 if g_currentMission.hud.fadeScreenElement:getAlpha() > 0.0 then
1339 g_currentMission:fadeScreen(-1, spec.fadeDuration, self.endFade, self)
1340 end
1341 end
1342
1343 if self.isServer then
1344 setCollisionMask(self.components[1].node, spec.collisionMask)
1345 spec.doHusbandryCheck = 5000
1346 end
1347
1348 spec.leaveTimer = 15000
1349end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
233function Rideable:onLoad(savegame)
234 local spec = self.spec_rideable
235
236 -- Overwrite the Vehicle high precision setting. Otherwise the precision might lead to large jitter in speed in multiplayer
237 self.highPrecisionPositionSynchronization = true
238
239 spec.leaveTimer = 15000
240 spec.currentDirtScale = 0
241 spec.abandonTimerDuration = g_gameSettings:getValue("horseAbandonTimerDuration")
242 spec.abandonTimer = spec.abandonTimerDuration
243 spec.fadeDuration = 400
244 spec.isRideableRemoved = false
245 spec.justSpawned = true
246 spec.meshNode = nil
247 -- Animation
248 spec.animationNode = nil
249 spec.charsetId = nil
250 spec.animationPlayer = nil
251 spec.animationParameters = {}
252 spec.animationParameters.forwardVelocity = {id=1, value=0.0, type=1}
253 spec.animationParameters.verticalVelocity = {id=2, value=0.0, type=1}
254 spec.animationParameters.yawVelocity = {id=3, value=0.0, type=1}
255 spec.animationParameters.absForwardVelocity = {id=4, value=0.0, type=1}
256 spec.animationParameters.onGround = {id=5, value=false, type=0}
257 spec.animationParameters.inWater = {id=6, value=false, type=0}
258 spec.animationParameters.closeToGround = {id=7, value=false, type=0}
259 spec.animationParameters.leftRightWeight = {id=8, value=0.0, type=1}
260 spec.animationParameters.absYawVelocity = {id=9, value=0.0, type=1}
261 spec.animationParameters.halted = {id=10, value=false, type=0}
262 spec.animationParameters.smoothedForwardVelocity = {id=11, value=0.0, type=1}
263 spec.animationParameters.absSmoothedForwardVelocity = {id=12, value=0.0, type=1}
264
265 -- InputAction
266 spec.acceletateEventId = ""
267 spec.brakeEventId = ""
268 spec.steerEventId = ""
269 spec.jumpEventId = ""
270
271 -- movements
272 spec.currentTurnAngle = 0
273 spec.currentTurnSpeed = 0.0
274 spec.currentSpeed = 0.0
275 spec.currentSpeedY = 0.0
276 spec.cctMoveQueue = {}
277 spec.currentCCTPosX = 0.0
278 spec.currentCCTPosY = 0.0
279 spec.currentCCTPosZ = 0.0
280 spec.lastCCTPosX = 0.0
281 spec.lastCCTPosY = 0.0
282 spec.lastCCTPosZ = 0.0
283 spec.topSpeeds = {}
284 spec.topSpeeds[Rideable.GAITTYPES.BACKWARDS] = self.xmlFile:getValue("vehicle.rideable#speedBackwards", -1.0)
285 spec.topSpeeds[Rideable.GAITTYPES.STILL] = 0.0
286 spec.topSpeeds[Rideable.GAITTYPES.WALK] = self.xmlFile:getValue("vehicle.rideable#speedWalk", 2.5)
287 spec.topSpeeds[Rideable.GAITTYPES.CANTER] = self.xmlFile:getValue("vehicle.rideable#speedCanter", 3.5)
288 spec.topSpeeds[Rideable.GAITTYPES.TROT] = self.xmlFile:getValue("vehicle.rideable#speedTrot", 5.0)
289 spec.topSpeeds[Rideable.GAITTYPES.GALLOP] = self.xmlFile:getValue("vehicle.rideable#speedGallop", 10.0)
290 spec.minTurnRadius = {}
291 spec.minTurnRadius[Rideable.GAITTYPES.BACKWARDS] = self.xmlFile:getValue("vehicle.rideable#minTurnRadiusBackwards", 1.0)
292 spec.minTurnRadius[Rideable.GAITTYPES.STILL] = 1.0
293 spec.minTurnRadius[Rideable.GAITTYPES.WALK] = self.xmlFile:getValue("vehicle.rideable#minTurnRadiusWalk", 1.0)
294 spec.minTurnRadius[Rideable.GAITTYPES.CANTER] = self.xmlFile:getValue("vehicle.rideable#minTurnRadiusCanter", 2.5)
295 spec.minTurnRadius[Rideable.GAITTYPES.TROT] = self.xmlFile:getValue("vehicle.rideable#minTurnRadiusTrot", 5.0)
296 spec.minTurnRadius[Rideable.GAITTYPES.GALLOP] = self.xmlFile:getValue("vehicle.rideable#minTurnRadiusGallop", 10.0)
297 spec.groundRaycastResult = {}
298 spec.groundRaycastResult.y = 0.0
299 spec.groundRaycastResult.object = nil
300 spec.groundRaycastResult.distance = 0.0
301 spec.haltTimer = 0.0
302 spec.smoothedLeftRightWeight = 0.0
303 spec.interpolationDt = 16
304 spec.ridingTimer = 0
305 spec.doHusbandryCheck = 0
306
307 spec.proxy = self.xmlFile:getValue("vehicle.rideable#proxy", nil, self.components, self.i3dMappings)
308 if spec.proxy ~= nil then
309 setRigidBodyType(spec.proxy, RigidBodyType.NONE)
310 end
311 spec.collisionMask = getCollisionMask(self.components[1].node)
312
313 -- interpolation
314 -- spec.interpolationTime = InterpolationTime.new(1.0)
315 -- spec.interpolatorPosition = InterpolatorPosition.new(0.0, 0.0, 0.0)
316 -- spec.interpolatorQuaternion = InterpolatorQuaternion.new(0.0, 0.0, 0.0, 1.0) -- only used on server side for rotation of camera
317 -- spec.interpolatorOnGround = InterpolatorValue.new(0.0)
318
319 -- steer
320 spec.maxAcceleration = 5 -- m/s^2
321 spec.maxDeceleration = 10 -- m/s^2
322 spec.gravity = -18.8
323
324 -- ground orientation
325 spec.frontCheckDistance = 0.0
326 spec.backCheckDistance = 0.0
327 spec.isOnGround = true
328 spec.isCloseToGround = true
329
330 assert(spec.topSpeeds[Rideable.GAITTYPES.MIN] < spec.topSpeeds[Rideable.GAITTYPES.MAX])
331 spec.maxTurnSpeed = self.xmlFile:getValue("vehicle.rideable#turnSpeed", 45.0) -- xml: deg/s, script: rad/s
332 spec.jumpHeight = self.xmlFile:getValue("vehicle.rideable#jumpHeight", 2.0)
333
334 local function loadHoof(target, index, key)
335 local hoof = {}
336 hoof.node = self.xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings)
337 hoof.onGround = false
338
339 local nodeSlow = self.xmlFile:getValue(key..".particleSystemSlow#node", nil, self.components, self.i3dMappings)
340 local particleType = self.xmlFile:getValue(key .. ".particleSystemSlow#particleType")
341 if particleType == nil then
342 Logging.xmlWarning(self.xmlFile, "Missing horse step slow particleType in '%s'", key .. ".particleSystemSlow")
343 return false
344 end
345 local particleSystem = g_particleSystemManager:getParticleSystem(particleType)
346 if particleSystem ~= nil then
347 hoof.psSlow = ParticleUtil.copyParticleSystem(self.xmlFile, key .. ".particleSystemSlow", particleSystem, nodeSlow)
348 end
349
350 local nodeFast = self.xmlFile:getValue(key..".particleSystemFast#node", nil, self.components, self.i3dMappings)
351 local particleTypeFast = self.xmlFile:getValue(key .. ".particleSystemFast#particleType")
352 if particleTypeFast == nil then
353 Logging.xmlWarning(self.xmlFile, "Missing horse step fast particleType in '%s'", key .. ".particleSystemFast")
354 return false
355 end
356 local particleSystemFast = g_particleSystemManager:getParticleSystem(particleTypeFast)
357 if particleSystemFast ~= nil then
358 hoof.psFast = ParticleUtil.copyParticleSystem(self.xmlFile, key .. ".particleSystemFast", particleSystemFast, nodeFast)
359 end
360
361 target[index] = hoof
362 end
363
364 -- Hooves
365 spec.hooves = {}
366 loadHoof(spec.hooves, Rideable.HOOVES.FRONT_LEFT, "vehicle.rideable.modelInfo.hoofFrontLeft")
367 loadHoof(spec.hooves, Rideable.HOOVES.FRONT_RIGHT, "vehicle.rideable.modelInfo.hoofFrontRight")
368 loadHoof(spec.hooves, Rideable.HOOVES.BACK_LEFT, "vehicle.rideable.modelInfo.hoofBackLeft")
369 loadHoof(spec.hooves, Rideable.HOOVES.BACK_RIGHT, "vehicle.rideable.modelInfo.hoofBackRight")
370
371 for _, hoove in pairs(spec.hooves) do
372 link(getRootNode(), hoove.psSlow.emitterShape)
373 link(getRootNode(), hoove.psFast.emitterShape)
374 end
375
376 spec.frontCheckDistance = self:calculateLegsDistance(spec.hooves[Rideable.HOOVES.FRONT_LEFT].node, spec.hooves[Rideable.HOOVES.FRONT_RIGHT].node)
377 spec.backCheckDistance = self:calculateLegsDistance(spec.hooves[Rideable.HOOVES.BACK_LEFT].node, spec.hooves[Rideable.HOOVES.BACK_RIGHT].node)
378
379 spec.animationNode = self.xmlFile:getValue("vehicle.rideable.modelInfo#animationNode", nil, self.components, self.i3dMappings)
380 spec.meshNode = self.xmlFile:getValue("vehicle.rideable.modelInfo#meshNode", nil, self.components, self.i3dMappings)
381 spec.equipmentNode = self.xmlFile:getValue("vehicle.rideable.modelInfo#equipmentNode", nil, self.components, self.i3dMappings)
382 spec.reinsNode = self.xmlFile:getValue("vehicle.rideable.modelInfo#reinsNode", nil, self.components, self.i3dMappings)
383 spec.leftReinNode = self.xmlFile:getValue("vehicle.rideable.modelInfo#reinLeftNode", nil, self.components, self.i3dMappings)
384 spec.rightReinNode = self.xmlFile:getValue("vehicle.rideable.modelInfo#reinRightNode", nil, self.components, self.i3dMappings)
385 spec.leftReinParentNode = getParent(spec.leftReinNode)
386 spec.rightReinParentNode = getParent(spec.rightReinNode)
387
388 -- animation
389 if spec.animationNode ~= nil then
390 spec.charsetId = getAnimCharacterSet(spec.animationNode)
391 local animationPlayer = createConditionalAnimation()
392 if animationPlayer ~= 0 then
393 spec.animationPlayer = animationPlayer
394 for key, parameter in pairs(spec.animationParameters) do
395 conditionalAnimationRegisterParameter(spec.animationPlayer, parameter.id, parameter.type, key)
396 end
397 initConditionalAnimation(spec.animationPlayer, spec.charsetId, self.configFileName, "vehicle.conditionalAnimation")
398 setConditionalAnimationSpecificParameterIds(spec.animationPlayer, spec.animationParameters.absForwardVelocity.id, spec.animationParameters.absYawVelocity.id)
399 end
400 end
401
402 -- Sounds
403 spec.surfaceSounds = {}
404 spec.surfaceIdToSound = {}
405 spec.surfaceNameToSound = {}
406 spec.currentSurfaceSound = nil
407 for _, surfaceSound in pairs(g_currentMission.surfaceSounds) do
408 if surfaceSound.type == "hoofstep" and surfaceSound.sample ~= nil then
409 local sample = g_soundManager:cloneSample(surfaceSound.sample, self.components[1].node, self)
410 sample.sampleName = surfaceSound.name
411
412 table.insert(spec.surfaceSounds, sample)
413 spec.surfaceIdToSound[surfaceSound.materialId] = sample
414 spec.surfaceNameToSound[surfaceSound.name] = sample
415 end
416 end
417 spec.horseStopSound = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.rideable.sounds", "halt", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
418 spec.horseBreathSoundsNoEffort = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.rideable.sounds", "breathingNoEffort", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
419 spec.horseBreathSoundsEffort = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.rideable.sounds", "breathingEffort", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
420 spec.horseBreathIntervalNoEffort = self.xmlFile:getValue("vehicle.rideable.sounds#breathIntervalNoEffort", 1.0) * 1000.0
421 spec.horseBreathIntervalEffort = self.xmlFile:getValue("vehicle.rideable.sounds#breathIntervalEffort", 1.0) * 1000.0
422 spec.horseBreathMinIntervalIdle = self.xmlFile:getValue("vehicle.rideable.sounds#minBreathIntervalIdle", 1.0) * 1000.0
423 spec.horseBreathMaxIntervalIdle = self.xmlFile:getValue("vehicle.rideable.sounds#maxBreathIntervalIdle", 1.0) * 1000.0
424 spec.currentBreathTimer = 0.0
425
426 -- attributes set by action events
427 spec.inputValues = {}
428 spec.inputValues.axisSteer = 0.0
429 spec.inputValues.axisSteerSend = 0.0
430 spec.inputValues.currentGait = Rideable.GAITTYPES.STILL
431 self:resetInputs()
432
433 spec.interpolatorIsOnGround = InterpolatorValue.new(0.0)
434 if self.isServer then
435 spec.interpolatorTurnAngle = InterpolatorAngle.new(0.0)
436 self.networkTimeInterpolator.maxInterpolationAlpha = 1.2
437 end
438
439 -- Network
440 spec.dirtyFlag = self:getNextDirtyFlag()
441
442 if savegame ~= nil then
443 local xmlFile = savegame.xmlFile
444 local key = savegame.key .. ".rideable"
445
446 local subTypeName = xmlFile:getString(key .. "#subType", "HORSE_GRAY")
447 local subType = g_currentMission.animalSystem:getSubTypeByName(subTypeName)
448 if subType ~= nil then
449 local cluster = g_currentMission.animalSystem:createClusterFromSubTypeIndex(subType.subTypeIndex)
450 cluster:loadFromXMLFile(xmlFile, key .. ".animal")
451 self:setCluster(cluster)
452 else
453 Logging.xmlError(self.xmlFile, "No animal sub type found!", spec.fillUnitIndex)
454 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
455 return
456 end
457 end
458
459 g_currentMission.husbandrySystem:addRideable(self)
460end

onLoadFinished

Description
Definition
onLoadFinished()
Code
464function Rideable:onLoadFinished()
465 self:raiseActive()
466end

onReadPositionUpdateStream

Description
Definition
onReadPositionUpdateStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
641function Rideable:onReadPositionUpdateStream(streamId, connection)
642 local spec = self.spec_rideable
643 local isOnGround = streamReadBool(streamId)
644 if isOnGround then
645 spec.interpolatorIsOnGround:setValue(1.0)
646 else
647 spec.interpolatorIsOnGround:setValue(0.0)
648 end
649end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
553function Rideable:onReadStream(streamId, connection)
554 local spec = self.spec_rideable
555 if connection:getIsServer() then
556 local isOnGround = streamReadBool(streamId)
557 if isOnGround then
558 spec.interpolatorIsOnGround:setValue(1.0)
559 else
560 spec.interpolatorIsOnGround:setValue(0.0)
561 end
562 end
563 if streamReadBool(streamId) then
564 local subTypeIndex = streamReadUIntN(streamId, AnimalCluster.NUM_BITS_SUB_TYPE)
565 local cluster = g_currentMission.animalSystem:createClusterFromSubTypeIndex(subTypeIndex)
566 cluster:readStream(streamId, connection)
567 self:setCluster(cluster)
568 end
569 if streamReadBool(streamId) then
570 local player = NetworkUtil.readNodeObject(streamId)
571 self:setPlayerToEnter(player)
572 end
573end

onReadUpdateStream

Description
Called on on update
Definition
onReadUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
598function Rideable:onReadUpdateStream(streamId, timestamp, connection)
599 local spec = self.spec_rideable
600
601 if not connection:getIsServer() then
602 spec.inputValues.axisSteer = streamReadFloat32(streamId)
603 spec.inputValues.currentGait = streamReadUInt8(streamId)
604 else
605 spec.haltTimer = streamReadFloat32(streamId)
606 if spec.haltTimer > 0 then
607 spec.inputValues.currentGait = Rideable.GAITTYPES.STILL
608 spec.inputValues.axisSteerSend = 0
609 end
610
611 if streamReadBool(streamId) then
612 spec.cluster:readUpdateStream(streamId, connection)
613 self:updateDirt()
614 end
615 end
616end

onRegisterActionEvents

Description
Registers action events
Definition
onRegisterActionEvents()
Code
1245function Rideable:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
1246 if self.isClient then
1247 local spec = self.spec_rideable
1248 self:clearActionEventsTable(spec.actionEvents)
1249
1250 if isActiveForInputIgnoreSelection then
1251 local _, actionEventId
1252 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.AXIS_ACCELERATE_VEHICLE, self, Rideable.actionEventAccelerate, false, true, false, true, nil)
1253 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
1254 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1255 spec.acceletateEventId = actionEventId
1256
1257 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.AXIS_BRAKE_VEHICLE, self, Rideable.actionEventBrake, false, true, false, true, nil)
1258 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH)
1259 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1260 spec.brakeEventId = actionEventId
1261
1262 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.AXIS_MOVE_SIDE_VEHICLE, self, Rideable.actionEventSteer, false, false, true, true, nil)
1263 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1264 spec.steerEventId = actionEventId
1265
1266 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.JUMP, self, Rideable.actionEventJump, false, true, false, true, nil)
1267 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW)
1268 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1269 spec.jumpEventId = actionEventId
1270 end
1271 end
1272end

onSetBroken

Description
Definition
onSetBroken()
Code
901function Rideable:onSetBroken()
902 self:unlinkReins()
903end

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
723function Rideable:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
724 local spec = self.spec_rideable
725
726 if spec.playerToEnter ~= nil and spec.checkPlayerToEnter then
727 if spec.playerToEnter == g_currentMission.player then
728 g_currentMission:requestToEnterVehicle(self)
729 spec.checkPlayerToEnter = false
730 end
731 end
732
733 local isEntered = self:getIsEntered()
734 if isEntered then
735 if isActiveForInputIgnoreSelection then
736 self:updateInputText()
737 end
738 if not self.isServer then
739 spec.inputValues.axisSteerSend = spec.inputValues.axisSteer
740 self:raiseDirtyFlags(spec.dirtyFlag)
741 self:resetInputs()
742 end
743 end
744
745 self:updateAnimation(dt)
746 if self.isClient then
747 self:updateSound(dt)
748 end
749
750 if self.isServer then
751 self:updateRiding(dt)
752 end
753
754 if spec.haltTimer > 0 then
755 self:setCurrentGait(Rideable.GAITTYPES.STILL)
756 spec.haltTimer = spec.haltTimer - dt
757 end
758
759 -- steering based on mobile device orientation
760 if self:getIsActiveForInput(true) then
761 local inputHelpMode = g_inputBinding:getInputHelpMode()
762 if inputHelpMode ~= GS_INPUT_HELP_MODE_GAMEPAD or GS_PLATFORM_SWITCH then
763 if g_gameSettings:getValue(GameSettings.SETTING.GYROSCOPE_STEERING) then
764 local dx, dy, dz = getGravityDirection()
765 local steeringValue = MathUtil.getSteeringAngleFromDeviceGravity(dx, dy, dz)
766
767 self:setRideableSteer(steeringValue)
768 end
769 end
770 end
771
772 if self.isServer and spec.doHusbandryCheck > 0 then
773 spec.doHusbandryCheck = spec.doHusbandryCheck - dt
774 -- check if rideable is near husbandry
775 local isInRange, husbandry = g_currentMission.husbandrySystem:getHusbandryInRideableRange(self)
776
777 if isInRange then
778 local isInStable
779 if husbandry ~= nil then
780 local cluster = self:getCluster()
781 husbandry:addCluster(cluster)
782 g_currentMission:removeVehicle(self)
783
784 isInStable = true
785-- g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_OK, string.format(g_i18n:getText("ingameNotification_horseInStable"), spec.cluster:getName()))
786 else
787-- g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_CRITICAL, string.format(g_i18n:getText("ingameNotification_horseNotInStable"), spec.cluster:getName()))
788 isInStable = false
789 end
790
791 if spec.lastOwner ~= nil then
792 spec.lastOwner:sendEvent(RideableStableNotificationEvent.new(isInStable, spec.cluster:getName()), nil, true)
793 end
794 end
795 spec.lastOwner = nil
796 end
797end

onUpdateInterpolation

Description
Definition
onUpdateInterpolation()
Code
801function Rideable:onUpdateInterpolation(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
802 local spec = self.spec_rideable
803
804 if self.isServer then
805 if not self:getIsControlled() then
806 self:setCurrentGait(Rideable.GAITTYPES.STILL)
807 end
808 -- for key, moveInfo in pairs(spec.cctMoveQueue) do
809 -- print(string.format("-- [Rideable:onUpdateInterpolation][A][%d]\t%d\t%d\t%d\t%s\t%.6f", g_updateLoopIndex, getPhysicsUpdateIndex(), key, moveInfo.physicsIndex, tostring(getIsPhysicsUpdateIndexSimulated(moveInfo.physicsIndex)), moveInfo.dt))
810 -- end
811
812 local interpolationDt = dt
813 local oldestMoveInfo = spec.cctMoveQueue[1]
814 if oldestMoveInfo ~= nil and getIsPhysicsUpdateIndexSimulated(oldestMoveInfo.physicsIndex) then
815 interpolationDt = oldestMoveInfo.dt
816 end
817 spec.interpolationDt = interpolationDt
818
819 self:testCCTMove(interpolationDt)
820 self:updateKinematic(dt)
821
822 if self:getIsEntered() then
823 self:resetInputs()
824 end
825
826 local component = self.components[1]
827 local x,y,z = self:getCCTWorldTranslation()
828 component.networkInterpolators.position:setTargetPosition(x,y,z)
829 spec.interpolatorTurnAngle:setTargetAngle(spec.currentTurnAngle)
830 spec.interpolatorIsOnGround:setTargetValue(self:getIsCCTOnGround() and 1.0 or 0.0)
831
832 -- use 75 or if dt > 75 then dt + 20
833 local phaseDuration = interpolationDt + 30
834
835
836 self.networkTimeInterpolator:startNewPhase(phaseDuration)
837 self.networkTimeInterpolator:update(interpolationDt)
838
839 -- local deltax, deltay, deltaz = component.networkInterpolators.position.targetPositionX - component.networkInterpolators.position.lastPositionX, component.networkInterpolators.position.targetPositionY - component.networkInterpolators.position.lastPositionY, component.networkInterpolators.position.targetPositionZ - component.networkInterpolators.position.lastPositionZ
840 -- local deltamag = math.sqrt(deltax*deltax+deltay*deltay+deltaz*deltaz)
841 -- print(string.format("-- [Rideable:onUpdateInterpolation][B][%d]\t%.6f\t%.6f\t%d\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f", g_updateLoopIndex, dt, interpolationDt, getPhysicsUpdateIndex(), self.networkTimeInterpolator.interpolationAlpha, self.networkTimeInterpolator.interpolationDuration, component.networkInterpolators.position.targetPositionX, component.networkInterpolators.position.targetPositionY, component.networkInterpolators.position.targetPositionZ, component.networkInterpolators.position.lastPositionX, component.networkInterpolators.position.lastPositionY, component.networkInterpolators.position.lastPositionZ, deltax, deltay, deltaz, deltamag))
842
843 x, y, z = component.networkInterpolators.position:getInterpolatedValues(self.networkTimeInterpolator.interpolationAlpha)
844 setTranslation(self.rootNode, x, y, z)
845
846 local turnAngle = spec.interpolatorTurnAngle:getInterpolatedValue(self.networkTimeInterpolator.interpolationAlpha)
847 local _, dirY, _ = localDirectionToWorld(self.rootNode, 0.0, 0.0, 1.0)
848 local dirX, dirZ = math.sin(turnAngle), math.cos(turnAngle)
849
850 -- rescale direction to length, keeping the original y (but keep it to some reasonable value)
851 local scale = math.sqrt(1-math.min(dirY*dirY, 0.9))
852 dirX = dirX * scale
853 dirZ = dirZ * scale
854 setDirection(self.rootNode, dirX, dirY, dirZ, 0,1,0)
855 end
856
857 if not self:getIsEntered() then
858 if spec.leaveTimer > 0 then
859 spec.leaveTimer = spec.leaveTimer - dt
860 self:raiseActive()
861 end
862 end
863
864 local isOnGroundFloat = spec.interpolatorIsOnGround:getInterpolatedValue(self.networkTimeInterpolator:getAlpha())
865 spec.isOnGround = isOnGroundFloat > 0.9
866 spec.isCloseToGround = false
867
868 if spec.isOnGround and (math.abs(spec.currentSpeed) > 0.001 or math.abs(spec.currentTurnSpeed) > 0.001) then
869 -- orientation from ground
870 local posX, posY, posZ = getWorldTranslation(self.rootNode)
871 local dirX, dirY, dirZ = localDirectionToWorld(self.rootNode, 0.0, 0.0, 1.0)
872 local fx, fy, fz = posX + dirX * spec.frontCheckDistance, posY + dirY * spec.frontCheckDistance, posZ + dirZ * spec.frontCheckDistance
873 spec.groundRaycastResult.y = fy + Rideable.GROUND_RAYCAST_OFFSET - Rideable.GROUND_RAYCAST_MAXDISTANCE
874 raycastClosest(fx, fy + Rideable.GROUND_RAYCAST_OFFSET, fz, 0.0, -1.0, 0.0, "groundRaycastCallback", Rideable.GROUND_RAYCAST_MAXDISTANCE, self, Rideable.GROUND_RAYCAST_COLLISIONMASK)
875 fy = spec.groundRaycastResult.y
876 local bx, by, bz = posX + dirX * spec.backCheckDistance, posY + dirY * spec.backCheckDistance, posZ + dirZ * spec.backCheckDistance
877 spec.groundRaycastResult.y = by + Rideable.GROUND_RAYCAST_OFFSET - Rideable.GROUND_RAYCAST_MAXDISTANCE
878 raycastClosest(bx, by + Rideable.GROUND_RAYCAST_OFFSET, bz, 0.0, -1.0, 0.0, "groundRaycastCallback", Rideable.GROUND_RAYCAST_MAXDISTANCE, self, Rideable.GROUND_RAYCAST_COLLISIONMASK)
879 by = spec.groundRaycastResult.y
880 local dx, dy, dz = fx - bx, fy - by, fz - bz
881 setDirection(self.rootNode, dx, dy, dz, 0, 1, 0)
882 else
883 local posX, posY, posZ = getWorldTranslation(self.rootNode)
884 spec.groundRaycastResult.distance = Rideable.GROUND_RAYCAST_MAXDISTANCE
885 raycastClosest(posX, posY, posZ, 0.0, -1.0, 0.0, "groundRaycastCallback", Rideable.GROUND_RAYCAST_MAXDISTANCE, self, Rideable.GROUND_RAYCAST_COLLISIONMASK)
886 spec.isCloseToGround = spec.groundRaycastResult.distance < 1.25
887 end
888end

onVehicleCharacterChanged

Description
Definition
onVehicleCharacterChanged()
Code
1304function Rideable:onVehicleCharacterChanged(character)
1305 if self.isClient then
1306 local spec = self.spec_rideable
1307 link(character.playerModel.thirdPersonLeftHandNode, spec.leftReinNode)
1308 link(character.playerModel.thirdPersonRightHandNode, spec.rightReinNode)
1309 setVisibility(spec.reinsNode, true)
1310
1311 if character ~= nil and character.animationCharsetId ~= nil and character.animationPlayer ~= nil then
1312 for key, parameter in pairs(spec.animationParameters) do
1313 conditionalAnimationRegisterParameter(character.animationPlayer, parameter.id, parameter.type, key)
1314 end
1315 initConditionalAnimation(character.animationPlayer, character.animationCharsetId, self.configFileName, "vehicle.riderConditionalAnimation")
1316 setConditionalAnimationSpecificParameterIds(character.animationPlayer, spec.animationParameters.absForwardVelocity.id, spec.animationParameters.absYawVelocity.id)
1317
1318 self:setEquipmentVisibility(true)
1319 conditionalAnimationZeroiseTrackTimes(character.animationPlayer)
1320 conditionalAnimationZeroiseTrackTimes(spec.animationPlayer)
1321 end
1322
1323 if self:getIsControlled() then
1324 if g_currentMission.hud.fadeScreenElement:getAlpha() > 0.0 then
1325 g_currentMission:fadeScreen(-1, spec.fadeDuration, self.endFade, self)
1326 end
1327 end
1328 end
1329end

onWritePositionUpdateStream

Description
Definition
onWritePositionUpdateStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
655function Rideable:onWritePositionUpdateStream(streamId, connection, dirtyMask)
656 local spec = self.spec_rideable
657 streamWriteBool(streamId, spec.isOnGround)
658end

onWriteStream

Description
Called on client side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
579function Rideable:onWriteStream(streamId, connection)
580 local spec = self.spec_rideable
581 if not connection:getIsServer() then
582 streamWriteBool(streamId, spec.isOnGround)
583 end
584 if streamWriteBool(streamId, spec.cluster ~= nil) then
585 streamWriteUIntN(streamId, spec.cluster:getSubTypeIndex(), AnimalCluster.NUM_BITS_SUB_TYPE)
586 spec.cluster:writeStream(streamId, connection)
587 end
588 if streamWriteBool(streamId, spec.playerToEnter ~= nil) then
589 NetworkUtil.writeNodeObject(streamId, spec.playerToEnter)
590 end
591end

onWriteUpdateStream

Description
Called on on update
Definition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
623function Rideable:onWriteUpdateStream(streamId, connection, dirtyMask)
624 local spec = self.spec_rideable
625 if connection:getIsServer() then
626 streamWriteFloat32(streamId, spec.inputValues.axisSteerSend)
627 streamWriteUInt8(streamId, spec.inputValues.currentGait)
628 else
629 streamWriteFloat32(streamId, spec.haltTimer)
630
631 if streamWriteBool(streamId, spec.cluster ~= nil) then
632 spec.cluster:writeUpdateStream(streamId, connection)
633 end
634 end
635end

periodChanged

Description
Definition
periodChanged()
Code
1602function Rideable:periodChanged(superFunc)
1603 superFunc(self)
1604
1605 local spec = self.spec_rideable
1606 if spec.cluster ~= nil then
1607 spec.cluster:onPeriodChanged()
1608 end
1609end

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
54function Rideable.prerequisitesPresent(specializations)
55 return SpecializationUtil.hasSpecialization(CCTDrivable, specializations)
56end

registerEventListeners

Description
Registers event listeners
Definition
registerEventListeners(string vehicleType)
Arguments
stringvehicleTypetype of vehicle
Code
194function Rideable.registerEventListeners(vehicleType)
195 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Rideable)
196 SpecializationUtil.registerEventListener(vehicleType, "onLoadFinished", Rideable)
197 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Rideable)
198 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Rideable)
199 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Rideable)
200 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Rideable)
201 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Rideable)
202 SpecializationUtil.registerEventListener(vehicleType, "onReadPositionUpdateStream", Rideable)
203 SpecializationUtil.registerEventListener(vehicleType, "onWritePositionUpdateStream", Rideable)
204 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Rideable)
205 SpecializationUtil.registerEventListener(vehicleType, "onUpdateInterpolation", Rideable)
206 SpecializationUtil.registerEventListener(vehicleType, "onDraw", Rideable)
207 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Rideable)
208 SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", Rideable)
209 SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", Rideable)
210 SpecializationUtil.registerEventListener(vehicleType, "onSetBroken", Rideable)
211 SpecializationUtil.registerEventListener(vehicleType, "onVehicleCharacterChanged", Rideable)
212end

registerFunctions

Description
Registers functions
Definition
registerFunctions(string vehicleType)
Arguments
stringvehicleTypetype of vehicle
Code
162function Rideable.registerFunctions(vehicleType)
163 SpecializationUtil.registerFunction(vehicleType, "getIsRideableJumpAllowed", Rideable.getIsRideableJumpAllowed)
164 SpecializationUtil.registerFunction(vehicleType, "jump", Rideable.jump)
165 SpecializationUtil.registerFunction(vehicleType, "setCurrentGait", Rideable.setCurrentGait)
166 SpecializationUtil.registerFunction(vehicleType, "getCurrentGait", Rideable.getCurrentGait)
167 SpecializationUtil.registerFunction(vehicleType, "setRideableSteer", Rideable.setRideableSteer)
168 SpecializationUtil.registerFunction(vehicleType, "resetInputs", Rideable.resetInputs)
169 SpecializationUtil.registerFunction(vehicleType, "updateKinematic", Rideable.updateKinematic)
170 SpecializationUtil.registerFunction(vehicleType, "testCCTMove", Rideable.testCCTMove)
171 SpecializationUtil.registerFunction(vehicleType, "updateAnimation", Rideable.updateAnimation)
172 SpecializationUtil.registerFunction(vehicleType, "updateSound", Rideable.updateSound)
173 SpecializationUtil.registerFunction(vehicleType, "updateRiding", Rideable.updateRiding)
174 SpecializationUtil.registerFunction(vehicleType, "updateDirt", Rideable.updateDirt)
175 SpecializationUtil.registerFunction(vehicleType, "calculateLegsDistance", Rideable.calculateLegsDistance)
176 SpecializationUtil.registerFunction(vehicleType, "setWorldPositionQuat", Rideable.setWorldPositionQuat)
177 SpecializationUtil.registerFunction(vehicleType, "updateFootsteps", Rideable.updateFootsteps)
178 SpecializationUtil.registerFunction(vehicleType, "getPosition", Rideable.getPosition)
179 SpecializationUtil.registerFunction(vehicleType, "getRotation", Rideable.getRotation)
180 SpecializationUtil.registerFunction(vehicleType, "setEquipmentVisibility", Rideable.setEquipmentVisibility)
181 SpecializationUtil.registerFunction(vehicleType, "getHoofSurfaceSound", Rideable.getHoofSurfaceSound)
182 SpecializationUtil.registerFunction(vehicleType, "groundRaycastCallback", Rideable.groundRaycastCallback)
183 SpecializationUtil.registerFunction(vehicleType, "unlinkReins", Rideable.unlinkReins)
184 SpecializationUtil.registerFunction(vehicleType, "updateInputText", Rideable.updateInputText)
185 SpecializationUtil.registerFunction(vehicleType, "setPlayerToEnter", Rideable.setPlayerToEnter)
186 SpecializationUtil.registerFunction(vehicleType, "endFade", Rideable.endFade)
187 SpecializationUtil.registerFunction(vehicleType, "setCluster", Rideable.setCluster)
188 SpecializationUtil.registerFunction(vehicleType, "getCluster", Rideable.getCluster)
189end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
216function Rideable.registerOverwrittenFunctions(vehicleType)
217 SpecializationUtil.registerOverwrittenFunction(vehicleType, "setWorldPosition", Rideable.setWorldPosition)
218 SpecializationUtil.registerOverwrittenFunction(vehicleType, "setWorldPositionQuaternion", Rideable.setWorldPositionQuaternion)
219 SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateVehicleSpeed", Rideable.updateVehicleSpeed)
220 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getName", Rideable.getName)
221 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFullName", Rideable.getFullName)
222 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeReset", Rideable.getCanBeReset)
223 SpecializationUtil.registerOverwrittenFunction(vehicleType, "periodChanged", Rideable.periodChanged)
224 SpecializationUtil.registerOverwrittenFunction(vehicleType, "dayChanged", Rideable.dayChanged)
225 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getImageFilename", Rideable.getImageFilename)
226 SpecializationUtil.registerOverwrittenFunction(vehicleType, "showInfo", Rideable.showInfo)
227 SpecializationUtil.registerOverwrittenFunction(vehicleType, "deleteVehicleCharacter", Rideable.deleteVehicleCharacter)
228end

resetInputs

Description
Resets all inputs
Definition
resetInputs()
Code
999function Rideable:resetInputs()
1000 local spec = self.spec_rideable
1001 spec.inputValues.axisSteer = 0
1002end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
667function Rideable:saveToXMLFile(xmlFile, key, usedModNames)
668 local spec = self.spec_rideable
669
670 if spec.cluster ~= nil then
671 local animalSystem = g_currentMission.animalSystem
672 local subTypeIndex = spec.cluster:getSubTypeIndex()
673 local subType = animalSystem:getSubTypeByIndex(subTypeIndex)
674 xmlFile:setString(key .. "#subType", subType.name)
675 spec.cluster:saveToXMLFile(xmlFile, key .. ".animal", usedModNames)
676 end
677end

setCluster

Description
Definition
setCluster()
Code
681function Rideable:setCluster(cluster)
682 local spec = self.spec_rideable
683 spec.cluster = cluster
684
685 if cluster ~= nil then
686 -- set texture
687 local animalSystem = g_currentMission.animalSystem
688 local subTypeIndex = cluster:getSubTypeIndex()
689 local visual = animalSystem:getVisualByAge(subTypeIndex, cluster:getAge())
690 local variation = visual.visualAnimal.variations[1]
691 local tileU = variation.tileUIndex / variation.numTilesU
692 local tileV = variation.tileVIndex / variation.numTilesV
693
694 I3DUtil.setShaderParameterRec(spec.meshNode, "atlasInvSizeAndOffsetUV", nil, nil, tileU, tileV)
695
696 self:updateDirt()
697 end
698end

setCurrentGait

Description
Definition
setCurrentGait()
Code
977function Rideable:setCurrentGait(gait)
978 local spec = self.spec_rideable
979 spec.inputValues.currentGait = gait
980end

setEquipmentVisibility

Description
Called on leaving the vehicle
Definition
setEquipmentVisibility()
Code
1365function Rideable:setEquipmentVisibility(val)
1366 if self.isClient then
1367 local spec = self.spec_rideable
1368
1369 if spec.equipmentNode ~= nil then
1370 setVisibility(spec.equipmentNode, val)
1371 setVisibility(spec.reinsNode, val)
1372 end
1373 end
1374end

setPlayerToEnter

Description
Definition
setPlayerToEnter()
Code
1574function Rideable:setPlayerToEnter(player)
1575 local spec = self.spec_rideable
1576 spec.playerToEnter = player
1577 spec.checkPlayerToEnter = true
1578 self:raiseActive()
1579end

setRideableSteer

Description
Definition
setRideableSteer()
Code
990function Rideable:setRideableSteer(axisSteer)
991 local spec = self.spec_rideable
992 if axisSteer ~= 0 then
993 spec.inputValues.axisSteer = -axisSteer
994 end
995end

setWorldPosition

Description
Definition
setWorldPosition()
Code
470function Rideable:setWorldPosition(superFunc, x,y,z, xRot,yRot,zRot, i, changeInterp)
471 superFunc(self, x,y,z, xRot,yRot,zRot, i, changeInterp)
472 if self.isServer and i == 1 then
473 local spec = self.spec_rideable
474 local dx, _, dz = localDirectionToWorld(self.rootNode, 0,0,1)
475 spec.currentTurnAngle = MathUtil.getYRotationFromDirection(dx, dz)
476 if changeInterp then
477 spec.interpolatorTurnAngle:setAngle(spec.currentTurnAngle)
478 end
479 end
480end

setWorldPositionQuat

Description
Set world position and quaternion rotation of component
Definition
setWorldPositionQuat(float x, float y, float z, float qx, float qy, float qz, float qw, Integer i, boolean changeInterp)
Arguments
floatxx position
floatyy position
floatzz position
floatqxx rotation
floatqyy rotation
floatqzz rotation
floatqww rotation
Integeriindex if component
booleanchangeInterpchange interpolation
Code
1233function Rideable:setWorldPositionQuat(x,y,z, qx,qy,qz,qw, changeInterp)
1234 setWorldTranslation(self.rootNode, x,y,z)
1235 setWorldQuaternion(self.rootNode, qx,qy,qz,qw)
1236 if changeInterp then
1237 local spec = self.spec_rideable
1238 spec.networkInterpolators.position:setPosition(x,y,z)
1239 spec.networkInterpolators.quaternion:setQuaternion(qx, qy, qz, qw)
1240 end
1241end

setWorldPositionQuaternion

Description
Definition
setWorldPositionQuaternion()
Code
484function Rideable:setWorldPositionQuaternion(superFunc, x, y, z, qx, qy, qz, qw, i, changeInterp)
485 superFunc(self, x, y, z, qx, qy, qz, qw, i, changeInterp)
486 if self.isServer and i == 1 then
487 local spec = self.spec_rideable
488 local dx, _, dz = localDirectionToWorld(self.rootNode, 0,0,1)
489 spec.currentTurnAngle = MathUtil.getYRotationFromDirection(dx, dz)
490 if changeInterp then
491 spec.interpolatorTurnAngle:setAngle(spec.currentTurnAngle)
492 end
493 end
494end

showInfo

Description
Definition
showInfo()
Code
1646function Rideable:showInfo(superFunc, box)
1647 local spec = self.spec_rideable
1648
1649 if spec.cluster ~= nil then
1650 spec.cluster:showInfo(box)
1651 end
1652
1653 superFunc(self, box)
1654end

testCCTMove

Description
Check if a requested CCT move was successful. We need a range for the error because of possible huge fps fluctuation.
Definition
testCCTMove()
Code
908function Rideable:testCCTMove(dt)
909 local spec = self.spec_rideable
910 spec.lastCCTPosX, spec.lastCCTPosY, spec.lastCCTPosZ = spec.currentCCTPosX, spec.currentCCTPosY, spec.currentCCTPosZ
911 spec.currentCCTPosX, spec.currentCCTPosY, spec.currentCCTPosZ = getWorldTranslation(self.spec_cctdrivable.cctNode)
912
913 local expectedMovementX, expectedMovementZ = 0,0
914
915 while spec.cctMoveQueue[1] ~= nil and getIsPhysicsUpdateIndexSimulated(spec.cctMoveQueue[1].physicsIndex) do
916 expectedMovementX = expectedMovementX + spec.cctMoveQueue[1].moveX
917 expectedMovementZ = expectedMovementZ + spec.cctMoveQueue[1].moveZ
918 table.remove(spec.cctMoveQueue, 1)
919 end
920
921 local expectedMovement = math.sqrt(expectedMovementX * expectedMovementX + expectedMovementZ * expectedMovementZ)
922 if expectedMovement > 0.001*dt then -- only check if we are supposed to move faster than 3.6km/h
923 local movementX = spec.currentCCTPosX - spec.lastCCTPosX
924 local movementZ = spec.currentCCTPosZ - spec.lastCCTPosZ
925 local movement = math.sqrt(movementX * movementX + movementZ * movementZ)
926 if movement <= expectedMovement*0.7 and spec.haltTimer <= 0.0 then
927 -- print(string.format("-- [Rideable:testCCTMove][%d] movement(%.3f), expectedMovement(%.3f) haltTimer(%.3f)", g_updateLoopIndex, movement, expectedMovement, spec.haltTimer))
928 self:setCurrentGait(Rideable.GAITTYPES.STILL)
929 spec.haltTimer = 900
930 if spec.horseStopSound ~= nil then
931 g_soundManager:playSample(spec.horseStopSound)
932 end
933 end
934 end
935end

unlinkReins

Description
Definition
unlinkReins()
Code
1353function Rideable:unlinkReins()
1354 if self.isClient then
1355 local spec = self.spec_rideable
1356
1357 link(spec.leftReinParentNode, spec.leftReinNode)
1358 link(spec.rightReinParentNode, spec.rightReinNode)
1359 setVisibility(spec.reinsNode, false)
1360 end
1361end

updateAnimation

Description
Updates the parameters that will drive the animation
Definition
updateAnimation(float dt)
Arguments
floatdtdelta time in ms
Code
1094function Rideable:updateAnimation(dt)
1095 local spec = self.spec_rideable
1096 local params = spec.animationParameters
1097 local speed = self.lastSignedSpeedReal * 1000.0
1098 local smoothedSpeed = self.lastSignedSpeed * 1000.0
1099 speed = MathUtil.clamp(speed, spec.topSpeeds[Rideable.GAITTYPES.BACKWARDS], spec.topSpeeds[Rideable.GAITTYPES.MAX])
1100 smoothedSpeed = MathUtil.clamp(smoothedSpeed, spec.topSpeeds[Rideable.GAITTYPES.BACKWARDS], spec.topSpeeds[Rideable.GAITTYPES.MAX])
1101
1102 local turnSpeed
1103 if self.isServer then
1104 turnSpeed = (spec.interpolatorTurnAngle.targetValue - spec.interpolatorTurnAngle.lastValue) / (self.networkTimeInterpolator.interpolationDuration * 0.001)
1105 else
1106 local interpQuat = self.components[1].networkInterpolators.quaternion
1107 local lastDirX, _, lastDirZ = mathQuaternionRotateVector(interpQuat.lastQuaternionX, interpQuat.lastQuaternionY, interpQuat.lastQuaternionZ, interpQuat.lastQuaternionW, 0,0,1)
1108 local targetDirX, _, targetDirZ = mathQuaternionRotateVector(interpQuat.targetQuaternionX, interpQuat.targetQuaternionY, interpQuat.targetQuaternionZ, interpQuat.targetQuaternionW, 0,0,1)
1109 local lastTurnAngle = MathUtil.getYRotationFromDirection(lastDirX, lastDirZ)
1110 local targetTurnAngle = MathUtil.getYRotationFromDirection(targetDirX, targetDirZ)
1111 local turnAngleDiff = targetTurnAngle - lastTurnAngle
1112 -- normalize to -180,180deg
1113 if turnAngleDiff > math.pi then
1114 turnAngleDiff = turnAngleDiff - 2*math.pi
1115 elseif turnAngleDiff < -math.pi then
1116 turnAngleDiff = turnAngleDiff + 2*math.pi
1117 end
1118 turnSpeed = turnAngleDiff / (self.networkTimeInterpolator.interpolationDuration * 0.001)
1119 end
1120
1121 local interpPos = self.components[1].networkInterpolators.position
1122 local speedY = (interpPos.targetPositionY - interpPos.lastPositionY) / (self.networkTimeInterpolator.interpolationDuration * 0.001)
1123
1124
1125 local leftRightWeight
1126 if math.abs(speed) > 0.01 then
1127 local closestGait = Rideable.GAITTYPES.STILL
1128 local closestDiff = math.huge
1129 for i=1,Rideable.GAITTYPES.MAX do
1130 local diff = math.abs(speed - spec.topSpeeds[i])
1131 if diff < closestDiff then
1132 closestGait = i
1133 closestDiff = diff
1134 end
1135 end
1136 local minTurnRadius = spec.minTurnRadius[closestGait]
1137 leftRightWeight = minTurnRadius * turnSpeed / speed
1138 else
1139 leftRightWeight = turnSpeed / spec.maxTurnSpeed
1140 end
1141 if leftRightWeight < spec.smoothedLeftRightWeight then
1142 spec.smoothedLeftRightWeight = math.max(leftRightWeight, spec.smoothedLeftRightWeight-1/500*dt, -1)
1143 else
1144 spec.smoothedLeftRightWeight = math.min(leftRightWeight, spec.smoothedLeftRightWeight+1/500*dt, 1)
1145 end
1146
1147 -- print(string.format("-- [Rideable:updateAnimation][%d][%s]\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f", g_updateLoopIndex, tostring(self), dt, leftRightWeight, spec.smoothedLeftRightWeight, MathUtil.clamp(leftRightWeight, -1.0, 1.0), turnSpeed / spec.maxTurnSpeed, MathUtil.clamp(turnSpeed / spec.maxTurnSpeed, -1.0, 1.0), turnSpeed, speed, self.movingDirection, self.lastSpeedAcceleration * 1000 * 1000))
1148
1149 params.forwardVelocity.value = speed
1150 params.absForwardVelocity.value = math.abs(speed)
1151 params.verticalVelocity.value = speedY
1152 params.yawVelocity.value = turnSpeed
1153 params.absYawVelocity.value = math.abs(turnSpeed)
1154 params.leftRightWeight.value = spec.smoothedLeftRightWeight
1155 params.onGround.value = spec.isOnGround-- or spec.justSpawned
1156 params.closeToGround.value = spec.isCloseToGround
1157 params.inWater.value = self.isInWater
1158 params.halted.value = spec.haltTimer > 0
1159 params.smoothedForwardVelocity.value = smoothedSpeed
1160 params.absSmoothedForwardVelocity.value = math.abs(smoothedSpeed)
1161
1162 -- horse animation
1163 if spec.animationPlayer ~= nil then
1164 for _, parameter in pairs(params) do
1165 if parameter.type == 0 then
1166 setConditionalAnimationBoolValue(spec.animationPlayer, parameter.id, parameter.value)
1167 elseif parameter.type == 1 then
1168 setConditionalAnimationFloatValue(spec.animationPlayer, parameter.id, parameter.value)
1169 end
1170 end
1171 updateConditionalAnimation(spec.animationPlayer, dt)
1172 -- local x,y,z = getWorldTranslation(self.rootNode)
1173 -- conditionalAnimationDebugDraw(spec.animationPlayer, x,y,z)
1174 end
1175 local isEntered = self.getIsEntered ~= nil and self:getIsEntered()
1176 local isControlled = self.getIsControlled ~= nil and self:getIsControlled()
1177
1178 if isEntered or isControlled then
1179 -- rider animation
1180 local character = self:getVehicleCharacter()
1181 if character ~= nil and character.animationCharsetId ~= nil and character.animationPlayer ~= nil then
1182 for _, parameter in pairs(params) do
1183 if parameter.type == 0 then
1184 setConditionalAnimationBoolValue(character.animationPlayer, parameter.id, parameter.value)
1185 elseif parameter.type == 1 then
1186 setConditionalAnimationFloatValue(character.animationPlayer, parameter.id, parameter.value)
1187 end
1188 end
1189 updateConditionalAnimation(character.animationPlayer, dt)
1190 -- local x,y,z = getWorldTranslation(self.rootNode)
1191 -- conditionalAnimationDebugDraw(character.animationPlayer, x,y,z)
1192 end
1193 end
1194 self:updateFootsteps(dt, math.abs(speed))
1195end

updateDebugValues

Description
Definition
updateDebugValues()
Code
1658function Rideable:updateDebugValues(values)
1659 local spec = self.spec_rideable
1660
1661 for k, hoofInfo in pairs(spec.hooves) do
1662 table.insert(values, {name="hoof sample " .. k, value=hoofInfo.sampleDebug})
1663 end
1664end

updateDirt

Description
Definition
updateDirt()
Code
702function Rideable:updateDirt()
703 local spec = self.spec_rideable
704 local cluster = spec.cluster
705
706 if cluster ~= nil and cluster.getDirtFactor ~= nil then
707 local dirtFactor = cluster:getDirtFactor()
708 I3DUtil.setShaderParameterRec(spec.meshNode, "RDT", nil, dirtFactor, nil, nil)
709 end
710end

updateFootsteps

Description
Definition
updateFootsteps()
Code
1435function Rideable:updateFootsteps(dt, speed)
1436 local spec = self.spec_rideable
1437 local epsilon = 0.001
1438
1439 if speed > epsilon then
1440 local dirX, _, dirZ = localDirectionToWorld(self.rootNode, 0, 0, 1)
1441 local rotY = MathUtil.getYRotationFromDirection(dirX, dirZ)
1442 for k, hoofInfo in pairs(spec.hooves) do
1443 local posX, posY, posZ = getWorldTranslation(hoofInfo.node)
1444 spec.groundRaycastResult.object = 0
1445 spec.groundRaycastResult.y = posY - 1
1446 raycastClosest(posX, posY + Rideable.GROUND_RAYCAST_OFFSET, posZ, 0.0, -1.0, 0.0, "groundRaycastCallback", Rideable.GROUND_RAYCAST_MAXDISTANCE, self, Rideable.GROUND_RAYCAST_COLLISIONMASK)
1447
1448 local hitTerrain = spec.groundRaycastResult.object == g_currentMission.terrainRootNode
1449 local terrainY = spec.groundRaycastResult.y
1450 local onGround = ((posY - terrainY) < 0.05)
1451
1452 -- DebugUtil.drawDebugNode(hoofInfo.node, string.format("[%s] (%.6f/%.6f|%s)", getName(hoofInfo.node), posY, terrainY, tostring(((posY - terrainY) < 0.05))))
1453 if onGround and not hoofInfo.onGround then
1454 local r, g, b, _, _ = getTerrainAttributesAtWorldPos(g_currentMission.terrainRootNode, posX, posY, posZ, true, true, true, true, false)
1455 hoofInfo.onGround = true
1456 -- particles
1457 if spec.inputValues.currentGait < Rideable.GAITTYPES.CANTER then
1458 if hoofInfo.psSlow.emitterShape ~= nil then
1459 ParticleUtil.resetNumOfEmittedParticles(hoofInfo.psSlow)
1460 ParticleUtil.setEmittingState(hoofInfo.psSlow, true)
1461 setShaderParameter(hoofInfo.psSlow.shape, "psColor", r, g, b, 1, false)
1462
1463 -- emittershapes are linked to world rootnode
1464 setWorldTranslation(hoofInfo.psSlow.emitterShape, posX, terrainY, posZ)
1465 setWorldRotation(hoofInfo.psSlow.emitterShape, 0, rotY, 0)
1466 end
1467 else
1468 if hoofInfo.psFast.emitterShape ~= nil then
1469 ParticleUtil.resetNumOfEmittedParticles(hoofInfo.psFast)
1470 ParticleUtil.setEmittingState(hoofInfo.psFast, true)
1471 setShaderParameter(hoofInfo.psFast.shape, "psColor", r, g, b, 1, false)
1472
1473 -- emittershapes are linked to world rootnode
1474 setWorldTranslation(hoofInfo.psFast.emitterShape, posX, terrainY, posZ)
1475 setWorldRotation(hoofInfo.psSlow.emitterShape, 0, rotY, 0)
1476 end
1477 end
1478
1479 local sample = self:getHoofSurfaceSound(posX, posY, posZ, hitTerrain)
1480 if sample ~= nil then
1481 hoofInfo.sampleDebug = string.format("%s - %s", sample.sampleName, sample.filename)
1482 g_soundManager:playSample(sample)
1483 end
1484
1485 elseif not onGround and hoofInfo.onGround then
1486 hoofInfo.onGround = false
1487 if hoofInfo.psSlow.emitterShape ~= nil then
1488 ParticleUtil.setEmittingState(hoofInfo.psSlow, false)
1489 end
1490 if hoofInfo.psFast.emitterShape ~= nil then
1491 ParticleUtil.setEmittingState(hoofInfo.psFast, false)
1492 end
1493 end
1494 end
1495 end
1496end

updateInputText

Description
Definition
updateInputText()
Code
1668function Rideable:updateInputText()
1669 local spec = self.spec_rideable
1670
1671 if spec.inputValues.currentGait == Rideable.GAITTYPES.BACKWARDS then
1672 g_inputBinding:setActionEventText(spec.acceletateEventId, g_i18n:getText("action_stop"))
1673 g_inputBinding:setActionEventActive(spec.acceletateEventId, true)
1674 g_inputBinding:setActionEventTextVisibility(spec.acceletateEventId, true)
1675
1676 g_inputBinding:setActionEventActive(spec.brakeEventId, false)
1677 g_inputBinding:setActionEventTextVisibility(spec.brakeEventId, false)
1678
1679 g_inputBinding:setActionEventActive(spec.jumpEventId, false)
1680 g_inputBinding:setActionEventTextVisibility(spec.jumpEventId, false)
1681 elseif spec.inputValues.currentGait == Rideable.GAITTYPES.STILL then
1682 g_inputBinding:setActionEventText(spec.acceletateEventId, g_i18n:getText("action_walk"))
1683 g_inputBinding:setActionEventActive(spec.acceletateEventId, true)
1684 g_inputBinding:setActionEventTextVisibility(spec.acceletateEventId, true)
1685
1686 g_inputBinding:setActionEventText(spec.brakeEventId, g_i18n:getText("action_walkBackwards"))
1687 g_inputBinding:setActionEventActive(spec.brakeEventId, true)
1688 g_inputBinding:setActionEventTextVisibility(spec.brakeEventId, true)
1689
1690 g_inputBinding:setActionEventActive(spec.jumpEventId, false)
1691 g_inputBinding:setActionEventTextVisibility(spec.jumpEventId, false)
1692 elseif spec.inputValues.currentGait == Rideable.GAITTYPES.WALK then
1693 g_inputBinding:setActionEventText(spec.acceletateEventId, g_i18n:getText("action_trot"))
1694 g_inputBinding:setActionEventActive(spec.acceletateEventId, true)
1695 g_inputBinding:setActionEventTextVisibility(spec.acceletateEventId, true)
1696
1697 g_inputBinding:setActionEventText(spec.brakeEventId, g_i18n:getText("action_stop"))
1698 g_inputBinding:setActionEventActive(spec.brakeEventId, true)
1699 g_inputBinding:setActionEventTextVisibility(spec.brakeEventId, true)
1700
1701 g_inputBinding:setActionEventActive(spec.jumpEventId, false)
1702 g_inputBinding:setActionEventTextVisibility(spec.jumpEventId, false)
1703 elseif spec.inputValues.currentGait == Rideable.GAITTYPES.TROT then
1704 g_inputBinding:setActionEventText(spec.acceletateEventId, g_i18n:getText("action_canter"))
1705 g_inputBinding:setActionEventActive(spec.acceletateEventId, true)
1706 g_inputBinding:setActionEventTextVisibility(spec.acceletateEventId, true)
1707
1708 g_inputBinding:setActionEventText(spec.brakeEventId, g_i18n:getText("action_walk"))
1709 g_inputBinding:setActionEventActive(spec.brakeEventId, true)
1710 g_inputBinding:setActionEventTextVisibility(spec.brakeEventId, true)
1711
1712 g_inputBinding:setActionEventActive(spec.jumpEventId, false)
1713 g_inputBinding:setActionEventTextVisibility(spec.jumpEventId, false)
1714 elseif spec.inputValues.currentGait == Rideable.GAITTYPES.CANTER then
1715 g_inputBinding:setActionEventText(spec.acceletateEventId, g_i18n:getText("action_gallop"))
1716 g_inputBinding:setActionEventActive(spec.acceletateEventId, true)
1717 g_inputBinding:setActionEventTextVisibility(spec.acceletateEventId, true)
1718
1719 g_inputBinding:setActionEventText(spec.brakeEventId, g_i18n:getText("action_trot"))
1720 g_inputBinding:setActionEventActive(spec.brakeEventId, true)
1721 g_inputBinding:setActionEventTextVisibility(spec.brakeEventId, true)
1722
1723 g_inputBinding:setActionEventText(spec.jumpEventId, g_i18n:getText("input_JUMP"))
1724 g_inputBinding:setActionEventActive(spec.jumpEventId, true)
1725 g_inputBinding:setActionEventTextVisibility(spec.jumpEventId, true)
1726 elseif spec.inputValues.currentGait == Rideable.GAITTYPES.GALLOP then
1727 g_inputBinding:setActionEventActive(spec.acceletateEventId, false)
1728 g_inputBinding:setActionEventTextVisibility(spec.acceletateEventId, false)
1729
1730 g_inputBinding:setActionEventText(spec.brakeEventId, g_i18n:getText("action_canter"))
1731 g_inputBinding:setActionEventActive(spec.brakeEventId, true)
1732 g_inputBinding:setActionEventTextVisibility(spec.brakeEventId, true)
1733
1734 g_inputBinding:setActionEventText(spec.jumpEventId, g_i18n:getText("input_JUMP"))
1735 g_inputBinding:setActionEventActive(spec.jumpEventId, true)
1736 g_inputBinding:setActionEventTextVisibility(spec.jumpEventId, true)
1737 end
1738end

updateKinematic

Description
Update animal kinematic; if we reach max speed? we fix velocity else we add force to accelerate. If we need to break, we add a break force. At the end we add gravity force and change direction when needed.
Definition
updateKinematic(float dt)
Arguments
floatdtdelta time in ms
Code
1007function Rideable:updateKinematic(dt)
1008 local spec = self.spec_rideable
1009 local dtInSec = dt*0.001
1010
1011 -- Update movement in current direction
1012 local desiredSpeed = spec.topSpeeds[spec.inputValues.currentGait]
1013 local maxSpeedChange = spec.maxAcceleration
1014 if desiredSpeed == 0.0 then
1015 maxSpeedChange = spec.maxDeceleration
1016 end
1017 maxSpeedChange = maxSpeedChange * dtInSec
1018 if not spec.isOnGround then
1019 -- reduce acceleration when in the air
1020 maxSpeedChange = maxSpeedChange * 0.2
1021 end
1022
1023 local speedChange = (desiredSpeed - spec.currentSpeed)
1024 speedChange = MathUtil.clamp(speedChange, -maxSpeedChange, maxSpeedChange)
1025
1026 --local movement = (spec.currentSpeed + 0.5 * speedChange) * dtInSec
1027 if spec.haltTimer <= 0.0 then
1028 spec.currentSpeed = spec.currentSpeed + speedChange
1029 else
1030 spec.currentSpeed = 0.0
1031 end
1032
1033 local movement = spec.currentSpeed * dtInSec
1034
1035 -- Update gravity / vertical movement
1036 local gravitySpeedChange = spec.gravity * dtInSec
1037 spec.currentSpeedY = spec.currentSpeedY + gravitySpeedChange
1038 local movementY = spec.currentSpeedY * dtInSec
1039
1040 -- Update rotation
1041 local slowestSpeed = spec.topSpeeds[Rideable.GAITTYPES.WALK]
1042 local fastestSpeed = spec.topSpeeds[Rideable.GAITTYPES.MAX]
1043
1044 local maxTurnSpeedChange = (MathUtil.clamp((fastestSpeed - spec.currentSpeed) / (fastestSpeed - slowestSpeed), 0, 1) * 0.4 + 0.8) -- Use smaller changes when walking slowly (between 0.8 and 1.2 rad/s^2)
1045 maxTurnSpeedChange = maxTurnSpeedChange * dtInSec
1046 if not spec.isOnGround then
1047 -- reduce turn acceleration when in the air
1048 maxTurnSpeedChange = maxTurnSpeedChange * 0.25
1049 end
1050
1051 if self.isServer then
1052 if not self:getIsEntered() and not self:getIsControlled() and spec.inputValues.axisSteer ~= 0.0 then
1053 spec.inputValues.axisSteer = 0.0
1054 end
1055 end
1056
1057 local desiredTurnSpeed = spec.maxTurnSpeed * spec.inputValues.axisSteer
1058 local turnSpeedChange = (desiredTurnSpeed - spec.currentTurnSpeed)
1059 turnSpeedChange = MathUtil.clamp(turnSpeedChange, -maxTurnSpeedChange, maxTurnSpeedChange)
1060 spec.currentTurnSpeed = spec.currentTurnSpeed + turnSpeedChange
1061 spec.currentTurnAngle = spec.currentTurnAngle + spec.currentTurnSpeed * dtInSec * (movement >= 0 and 1 or -1)
1062
1063 local movementX, movementZ = math.sin(spec.currentTurnAngle) * movement, math.cos(spec.currentTurnAngle) * movement
1064 -- print(string.format("-- [Rideable:updateKinematic][%d]\t%.6f\t%.6f\t%.6f\t%d", g_updateLoopIndex, dt, spec.currentSpeed, movement, getPhysicsUpdateIndex()))
1065 self:moveCCT(movementX, movementY, movementZ, true)
1066
1067 table.insert(spec.cctMoveQueue, {physicsIndex = getPhysicsUpdateIndex(), moveX = movementX, moveY = movementY, moveZ = movementZ, dt = dt})
1068end

updateRiding

Description
Definition
updateRiding()
Code
1500function Rideable:updateRiding(dt)
1501 local spec = self.spec_rideable
1502
1503 if spec.cluster ~= nil and spec.currentSpeed ~= 0.0 then
1504 local ridingTime = spec.cluster:getDailyRidingTime()
1505 local changeDelta = ridingTime / 100
1506 local speedFactor = 1
1507
1508 local gaitType = spec.inputValues.currentGait
1509 if gaitType == Rideable.GAITTYPES.CANTER then
1510 speedFactor = 2
1511 elseif gaitType == Rideable.GAITTYPES.GALLOP then
1512 speedFactor = 3
1513 end
1514
1515 spec.ridingTimer = spec.ridingTimer + (dt*speedFactor)
1516
1517 if spec.ridingTimer > changeDelta then
1518 spec.ridingTimer = 0
1519 spec.cluster:changeRiding(1)
1520 spec.cluster:changeDirt(1)
1521 end
1522
1523 if self.lastMovedDistance > 0.001 then
1524 local stats = g_currentMission:farmStats(self:getOwnerFarmId())
1525 local distance = self.lastMovedDistance*0.001
1526 stats:updateStats("horseDistance", distance)
1527 end
1528
1529 self:updateDirt()
1530 end
1531end

updateSound

Description
Definition
updateSound()
Code
1199function Rideable:updateSound(dt)
1200 local spec = self.spec_rideable
1201
1202 if spec.horseBreathSoundsEffort ~= nil and spec.horseBreathSoundsNoEffort ~= nil and spec.isOnGround then
1203 spec.currentBreathTimer = spec.currentBreathTimer - dt
1204 spec.currentBreathTimer = math.max(spec.currentBreathTimer, 0.0)
1205
1206 if spec.currentBreathTimer == 0.0 then
1207 if spec.inputValues.currentGait == Rideable.GAITTYPES.GALLOP then
1208 g_soundManager:playSample(spec.horseBreathSoundsEffort)
1209 spec.currentBreathTimer = spec.horseBreathIntervalEffort
1210 else
1211 g_soundManager:playSample(spec.horseBreathSoundsNoEffort)
1212 if spec.inputValues.currentGait == Rideable.GAITTYPES.STILL then
1213 spec.currentBreathTimer = spec.horseBreathMinIntervalIdle + (math.random() * (spec.horseBreathMaxIntervalIdle - spec.horseBreathMinIntervalIdle))
1214 else
1215 spec.currentBreathTimer = spec.horseBreathIntervalNoEffort
1216 end
1217 end
1218 end
1219 end
1220end

updateVehicleSpeed

Description
Definition
updateVehicleSpeed()
Code
498function Rideable:updateVehicleSpeed(superFunc, dt)
499 if self.isServer then
500 local spec = self.spec_rideable
501 superFunc(self, spec.interpolationDt)
502 else
503 superFunc(self, dt)
504 end
505end