Script v1_7_1_0
- AI
- Animals
- Collections
- Contracts
- Debug
- Economy
- Elements
- EnvironmentalScore
- Errors
- Events
- GUI
- Handtools
- Hud
- I3d
- Input
- Jobs
- Maps
- Materials
- Misc
- Objects
- Parameters
- Placeables
- Placement
- Player
- Shop
- Sounds
- Specialization
- Specializations
- AIConveyorBelt
- AIDrivable
- AIFieldWorker
- AIImplement
- AIJobVehicle
- AIVehicle
- AIVehicleObstacle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- AutoLoader
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BigBag
- BunkerSiloCompacter
- BunkerSiloInteractor
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- CropSensor
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- ExtendedAIVehicle
- ExtendedCombine
- ExtendedMotorized
- ExtendedMower
- ExtendedSowingMachine
- ExtendedSprayer
- ExtendedWearable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- HeadlandAnimation
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- InlineWrapper
- JigglingParts
- Leveler
- LicensePlates
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- ManureSensor
- MixerWagon
- Motorized
- Mountable
- Mower
- Mulcher
- MultipleItemPurchase
- Pallet
- Pickup
- Pipe
- PlaceableAI
- PlaceableAnimatedObjects
- PlaceableBeehive
- PlaceableBeehivePalletSpa...
- PlaceableBunkerSilo
- PlaceableBuyingStation
- PlaceableCartridgePlayer
- PlaceableChargingStation
- PlaceableClearAreas
- PlaceableColorable
- PlaceableDeletedNodes
- PlaceableDoghouse
- PlaceableDynamicallyLoade...
- PlaceableFarmhouse
- PlaceableFence
- PlaceableFoliageAreas
- PlaceableGreenhouse
- PlaceableHighPressureWash...
- PlaceableHotspots
- PlaceableHusbandry
- PlaceableHusbandryAnimals
- PlaceableHusbandryFeeding...
- PlaceableHusbandryFence
- PlaceableHusbandryFood
- PlaceableHusbandryLiquidM...
- PlaceableHusbandryMilk
- PlaceableHusbandryPallets
- PlaceableHusbandryStraw
- PlaceableHusbandryWater
- PlaceableIncomePerHour
- PlaceableIndoorAreas
- PlaceableInfoTrigger
- PlaceableLeveling
- PlaceableLights
- PlaceableManureHeap
- PlaceablePlacement
- PlaceableProductionPoint
- PlaceableSellingStation
- PlaceableSilo
- PlaceableSiloExtension
- PlaceableSolarPanels
- PlaceableTipOcclusionArea...
- PlaceableTrainSystem
- PlaceableTriggerMarkers
- PlaceableVine
- PlaceableWardrobe
- PlaceableWeatherStation
- PlaceableWeighingStation
- PlaceableWindTurbine
- PlaceableWorkshop
- Plow
- PlowPacker
- PowerConsumer
- PowerTakeOffs
- PrecisionFarmingStatistic
- PushHandTool
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- RTKStation
- SaltSpreader
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SoilSampler
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StonePicker
- StrawBlower
- StumpCutter
- SupportVehicle
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TestAreas
- TipOccluder
- Trailer
- TreePlanter
- TreeSaplingPallet
- TreeSaw
- TurnOnVehicle
- VariableWorkWidth
- VehicleSettings
- VineCutter
- VineDetector
- VinePrepruner
- Washable
- WaterTrailer
- Wearable
- Weeder
- WeedSpotSpray
- Wheels
- WindBending
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- StateMachine
- Statistics
- Tasks
- Triggers
- Utils
- Vehicles
Engine v1_7_1_0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- general
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- NoteNode
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- VoiceChat
- XML
Foundation Reference
Rideable
DescriptionSpecialization class for RideablesXML Configuration Parameters
vehicle.rideable#speedBackwards | max speed in gait type backwards (m/s) |
vehicle.rideable#speedWalk | max speed in gait type walk (m/s) |
vehicle.rideable#speedTrot | max speed in gait type trot (m/s) |
vehicle.rideable#speedGallop | max speed in gait type gallop (m/s) |
vehicle.rideable#turnAngle | max turn speed (deg/s) |
Functions
- actionEventAccelerate
- actionEventBrake
- actionEventJump
- actionEventSteer
- calculateLegsDistance
- dayChanged
- deleteVehicleCharacter
- endFade
- getCanBeReset
- getCluster
- getCurrentGait
- getFullName
- getHoofSurfaceSound
- getImageFilename
- getIsRideableJumpAllowed
- getName
- getPosition
- getRotation
- groundRaycastCallback
- initSpecialization
- jump
- onDelete
- onDraw
- onEnterVehicle
- onLeaveVehicle
- onLoad
- onLoadFinished
- onReadPositionUpdateStream
- onReadStream
- onReadUpdateStream
- onRegisterActionEvents
- onSetBroken
- onUpdate
- onUpdateInterpolation
- onVehicleCharacterChanged
- onWritePositionUpdateStream
- onWriteStream
- onWriteUpdateStream
- periodChanged
- prerequisitesPresent
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- resetInputs
- saveToXMLFile
- setCluster
- setCurrentGait
- setEquipmentVisibility
- setPlayerToEnter
- setRideableSteer
- setWorldPosition
- setWorldPositionQuat
- setWorldPositionQuaternion
- showInfo
- testCCTMove
- unlinkReins
- updateAnimation
- updateDebugValues
- updateDirt
- updateFootsteps
- updateInputText
- updateKinematic
- updateRiding
- updateSound
- updateVehicleSpeed
actionEventAccelerate
DescriptionCallback on accelerate eventDefinition
actionEventAccelerate(table self, string actionName, float inputValue, string callbackState, bool isAnalog)Arguments
table | self | instance |
string | actionName | action name |
float | inputValue | input value |
string | callbackState | |
bool | isAnalog | true if input is analog |
1383 | function 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 |
1390 | end |
actionEventBrake
DescriptionCallback on brake eventDefinition
actionEventBrake(table self, string actionName, float inputValue, string callbackState, bool isAnalog)Arguments
table | self | instance |
string | actionName | action name |
float | inputValue | input value |
string | callbackState | |
bool | isAnalog | true if input is analog |
1399 | function 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 |
1404 | end |
actionEventJump
DescriptionCallback on jump eventDefinition
actionEventJump(table self, string actionName, float inputValue, string callbackState, bool isAnalog)Arguments
table | self | instance |
string | actionName | action name |
float | inputValue | input value |
string | callbackState | |
bool | isAnalog | true if input is analog |
1427 | function Rideable.actionEventJump(self, actionName, inputValue, callbackState, isAnalog) |
1428 | if self:getIsRideableJumpAllowed() then |
1429 | self:jump() |
1430 | end |
1431 | end |
actionEventSteer
DescriptionCallback on steer eventDefinition
actionEventSteer(table self, string actionName, float inputValue, string callbackState, bool isAnalog)Arguments
table | self | instance |
string | actionName | action name |
float | inputValue | input value |
string | callbackState | |
bool | isAnalog | true if input is analog |
1413 | function 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 |
1418 | end |
calculateLegsDistance
DescriptionGets legs distance from rootNodeDefinition
calculateLegsDistance(integer left, integer right)Arguments
integer | left | leg node |
integer | right | leg node |
float | distance | from root node |
512 | function 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 |
520 | end |
dayChanged
DescriptionDefinitiondayChanged()Code
1612 | function 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 |
1619 | end |
deleteVehicleCharacter
DescriptionDefinitiondeleteVehicleCharacter()Code
1637 | function Rideable:deleteVehicleCharacter(superFunc) |
1638 | self:setEquipmentVisibility(false) |
1639 | self:unlinkReins() |
1640 | |
1641 | superFunc(self) |
1642 | end |
endFade
DescriptionDefinitionendFade()Code
662 | function Rideable:endFade() |
663 | end |
getCanBeReset
DescriptionDefinitiongetCanBeReset()Code
1596 | function Rideable:getCanBeReset(superFunc) |
1597 | return false |
1598 | end |
getCluster
DescriptionDefinitiongetCluster()Code
714 | function Rideable:getCluster() |
715 | return self.spec_rideable.cluster |
716 | end |
getCurrentGait
DescriptionDefinitiongetCurrentGait()Code
984 | function Rideable:getCurrentGait() |
985 | return self.spec_rideable.inputValues.currentGait |
986 | end |
getFullName
DescriptionDefinitiongetFullName()Code
1590 | function Rideable:getFullName(superFunc) |
1591 | return self:getName() |
1592 | end |
getHoofSurfaceSound
DescriptionDefinitiongetHoofSurfaceSound()Code
1535 | function 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 |
1558 | end |
getImageFilename
DescriptionDefinitiongetImageFilename()Code
1623 | function 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 |
1633 | end |
getIsRideableJumpAllowed
DescriptionDefinitiongetIsRideableJumpAllowed()Code
939 | function 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 |
955 | end |
getName
DescriptionDefinitiongetName()Code
1583 | function Rideable:getName(superFunc) |
1584 | local spec = self.spec_rideable |
1585 | return spec.cluster:getName() |
1586 | end |
getPosition
DescriptionDefinitiongetPosition()Code
1562 | function Rideable:getPosition() |
1563 | return getWorldTranslation(self.rootNode) |
1564 | end |
getRotation
DescriptionDefinitiongetRotation()Code
1568 | function Rideable:getRotation() |
1569 | return getWorldRotation(self.rootNode) |
1570 | end |
groundRaycastCallback
DescriptionCallback 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
integer | hitObjectId | scenegraph object id |
float | x | world x hit position |
float | y | world y hit position |
float | z | world z hit position |
float | distance | distance at which the cast hit the object |
bool | returns | true object that was hit is valid |
1078 | function 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 |
1089 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
60 | function 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") |
157 | end |
jump
DescriptionDefinitionjump()Code
959 | function 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 |
973 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
524 | function 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 |
547 | end |
onDraw
DescriptionDefinitiononDraw()Code
892 | function 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 |
897 | end |
onEnterVehicle
DescriptionCalled on enter vehicleDefinition
onEnterVehicle(bool isControlling)Arguments
bool | isControlling |
1277 | function 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 |
1300 | end |
onLeaveVehicle
DescriptionCalled on leaving vehicleDefinition
onLeaveVehicle()Code
1333 | function 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 |
1349 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
233 | function 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) |
460 | end |
onLoadFinished
DescriptionDefinitiononLoadFinished()Code
464 | function Rideable:onLoadFinished() |
465 | self:raiseActive() |
466 | end |
onReadPositionUpdateStream
DescriptionDefinitiononReadPositionUpdateStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
641 | function 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 |
649 | end |
onReadStream
DescriptionCalled on client side on joinDefinition
onReadStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
553 | function 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 |
573 | end |
onReadUpdateStream
DescriptionCalled on on updateDefinition
onReadUpdateStream(integer streamId, integer timestamp, table connection)Arguments
integer | streamId | stream ID |
integer | timestamp | timestamp |
table | connection | connection |
598 | function 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 |
616 | end |
onRegisterActionEvents
DescriptionRegisters action eventsDefinition
onRegisterActionEvents()Code
1245 | function 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 |
1272 | end |
onSetBroken
DescriptionDefinitiononSetBroken()Code
901 | function Rideable:onSetBroken() |
902 | self:unlinkReins() |
903 | end |
onUpdate
DescriptionCalled on on updateDefinition
onUpdate(float dt, bool isActiveForInput, bool isSelected)Arguments
float | dt | delta time |
bool | isActiveForInput | true if specializations is active for input |
bool | isSelected | true if specializations is selected |
723 | function 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 |
797 | end |
onUpdateInterpolation
DescriptionDefinitiononUpdateInterpolation()Code
801 | function 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 |
888 | end |
onVehicleCharacterChanged
DescriptionDefinitiononVehicleCharacterChanged()Code
1304 | function 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 |
1329 | end |
onWritePositionUpdateStream
DescriptionDefinitiononWritePositionUpdateStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
655 | function Rideable:onWritePositionUpdateStream(streamId, connection, dirtyMask) |
656 | local spec = self.spec_rideable |
657 | streamWriteBool(streamId, spec.isOnGround) |
658 | end |
onWriteStream
DescriptionCalled on client side on joinDefinition
onWriteStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
579 | function 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 |
591 | end |
onWriteUpdateStream
DescriptionCalled on on updateDefinition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)Arguments
integer | streamId | stream ID |
table | connection | connection |
integer | dirtyMask | dirty mask |
623 | function 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 |
635 | end |
periodChanged
DescriptionDefinitionperiodChanged()Code
1602 | function 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 |
1609 | end |
prerequisitesPresent
DescriptionChecks if all prerequisite specializations are loadedDefinition
prerequisitesPresent(table specializations)Arguments
table | specializations | specializations |
boolean | hasPrerequisite | true if all prerequisite specializations are loaded |
54 | function Rideable.prerequisitesPresent(specializations) |
55 | return SpecializationUtil.hasSpecialization(CCTDrivable, specializations) |
56 | end |
registerEventListeners
DescriptionRegisters event listenersDefinition
registerEventListeners(string vehicleType)Arguments
string | vehicleType | type of vehicle |
194 | function 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) |
212 | end |
registerFunctions
DescriptionRegisters functionsDefinition
registerFunctions(string vehicleType)Arguments
string | vehicleType | type of vehicle |
162 | function 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) |
189 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
216 | function 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) |
228 | end |
resetInputs
DescriptionResets all inputsDefinition
resetInputs()Code
999 | function Rideable:resetInputs() |
1000 | local spec = self.spec_rideable |
1001 | spec.inputValues.axisSteer = 0 |
1002 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
667 | function 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 |
677 | end |
setCluster
DescriptionDefinitionsetCluster()Code
681 | function 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 |
698 | end |
setCurrentGait
DescriptionDefinitionsetCurrentGait()Code
977 | function Rideable:setCurrentGait(gait) |
978 | local spec = self.spec_rideable |
979 | spec.inputValues.currentGait = gait |
980 | end |
setEquipmentVisibility
DescriptionCalled on leaving the vehicleDefinition
setEquipmentVisibility()Code
1365 | function 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 |
1374 | end |
setPlayerToEnter
DescriptionDefinitionsetPlayerToEnter()Code
1574 | function Rideable:setPlayerToEnter(player) |
1575 | local spec = self.spec_rideable |
1576 | spec.playerToEnter = player |
1577 | spec.checkPlayerToEnter = true |
1578 | self:raiseActive() |
1579 | end |
setRideableSteer
DescriptionDefinitionsetRideableSteer()Code
990 | function Rideable:setRideableSteer(axisSteer) |
991 | local spec = self.spec_rideable |
992 | if axisSteer ~= 0 then |
993 | spec.inputValues.axisSteer = -axisSteer |
994 | end |
995 | end |
setWorldPosition
DescriptionDefinitionsetWorldPosition()Code
470 | function 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 |
480 | end |
setWorldPositionQuat
DescriptionSet world position and quaternion rotation of componentDefinition
setWorldPositionQuat(float x, float y, float z, float qx, float qy, float qz, float qw, Integer i, boolean changeInterp)Arguments
float | x | x position |
float | y | y position |
float | z | z position |
float | qx | x rotation |
float | qy | y rotation |
float | qz | z rotation |
float | qw | w rotation |
Integer | i | index if component |
boolean | changeInterp | change interpolation |
1233 | function 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 |
1241 | end |
setWorldPositionQuaternion
DescriptionDefinitionsetWorldPositionQuaternion()Code
484 | function 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 |
494 | end |
showInfo
DescriptionDefinitionshowInfo()Code
1646 | function 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) |
1654 | end |
testCCTMove
DescriptionCheck if a requested CCT move was successful. We need a range for the error because of possible huge fps fluctuation.Definition
testCCTMove()Code
908 | function 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 |
935 | end |
unlinkReins
DescriptionDefinitionunlinkReins()Code
1353 | function 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 |
1361 | end |
updateAnimation
DescriptionUpdates the parameters that will drive the animationDefinition
updateAnimation(float dt)Arguments
float | dt | delta time in ms |
1094 | function 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)) |
1195 | end |
updateDebugValues
DescriptionDefinitionupdateDebugValues()Code
1658 | function 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 |
1664 | end |
updateDirt
DescriptionDefinitionupdateDirt()Code
702 | function 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 |
710 | end |
updateFootsteps
DescriptionDefinitionupdateFootsteps()Code
1435 | function 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 |
1496 | end |
updateInputText
DescriptionDefinitionupdateInputText()Code
1668 | function 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 |
1738 | end |
updateKinematic
DescriptionUpdate 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
float | dt | delta time in ms |
1007 | function 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}) |
1068 | end |
updateRiding
DescriptionDefinitionupdateRiding()Code
1500 | function 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 |
1531 | end |
updateSound
DescriptionDefinitionupdateSound()Code
1199 | function 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 |
1220 | end |
updateVehicleSpeed
DescriptionDefinitionupdateVehicleSpeed()Code
498 | function 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 |
505 | end |