LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

Enterable

Description
This specialization enables the player to enter a vehicle. It also loads cameras and player character
Functions

actionEventCameraSwitch

Description
Definition
actionEventCameraSwitch()
Code
1548function Enterable.actionEventCameraSwitch(self, actionName, inputValue, callbackState, isAnalog)
1549 local spec = self.spec_enterable
1550 self:setActiveCameraIndex(spec.camIndex + 1)
1551end

actionEventCameraZoomIn

Description
Definition
actionEventCameraZoomIn()
Code
1555function Enterable.actionEventCameraZoomIn(self, actionName, inputValue, callbackState, isAnalog, isMouse)
1556 local spec = self.spec_enterable
1557 local offset = -0.2
1558 if isMouse then -- mouse wheel zoom, must use larger value because of engine input handling
1559 offset = offset * InputBinding.MOUSE_WHEEL_INPUT_FACTOR
1560 end
1561
1562 spec.activeCamera:zoomSmoothly(offset)
1563end

actionEventCameraZoomOut

Description
Definition
actionEventCameraZoomOut()
Code
1567function Enterable.actionEventCameraZoomOut(self, actionName, inputValue, callbackState, isAnalog, isMouse)
1568 local spec = self.spec_enterable
1569 local offset = 0.2
1570 if isMouse then -- mouse wheel zoom, must use larger value because of engine input handling
1571 offset = offset * InputBinding.MOUSE_WHEEL_INPUT_FACTOR
1572 end
1573
1574 spec.activeCamera:zoomSmoothly(offset)
1575end

actionEventLeave

Description
Definition
actionEventLeave()
Code
1542function Enterable.actionEventLeave(self, actionName, inputValue, callbackState, isAnalog)
1543 self:doLeaveVehicle()
1544end

actionEventResetHeadTracking

Description
Definition
actionEventResetHeadTracking()
Code
1579function Enterable.actionEventResetHeadTracking(self, actionName, inputValue, callbackState, isAnalog)
1580 centerHeadTracking()
1581end

addToolCameras

Description
Add cameras from tool
Definition
addToolCameras(table cameras)
Arguments
tablecamerascameras to add
Code
1002function Enterable:addToolCameras(cameras)
1003 local spec = self.spec_enterable
1004
1005 for _,toolCamera in pairs(cameras) do
1006 table.insert(spec.cameras, toolCamera)
1007 end
1008 spec.numCameras = #spec.cameras
1009end

deleteVehicleCharacter

Description
Definition
deleteVehicleCharacter()
Code
1137function Enterable:deleteVehicleCharacter()
1138 local spec = self.spec_enterable
1139 if spec.vehicleCharacter ~= nil then
1140 spec.vehicleCharacter:unloadCharacter()
1141 end
1142 g_messageCenter:unsubscribe(MessageType.PLAYER_STYLE_CHANGED, self)
1143end

doLeaveVehicle

Description
Definition
doLeaveVehicle()
Code
880function Enterable:doLeaveVehicle()
881 local spec = self.spec_enterable
882 if spec.isEntered then
883 g_currentMission:onLeaveVehicle()
884 end
885end

enterVehicle

Description
Enter vehicle
Definition
enterVehicle(boolean isControlling, integer playerIndex, integer playerColorIndex)
Arguments
booleanisControllingis controlling vehicle
integerplayerIndexindex of player who enters the vehicle
integerplayerColorIndexindex of player color
Code
808function Enterable:enterVehicle(isControlling, playerStyle, farmId, userId)
809 local spec = self.spec_enterable
810
811 self:raiseActive()
812
813 spec.isControlled = true
814 spec.isEntered = isControlling
815 spec.playerStyle = playerStyle
816 spec.canUseEnter = false
817 spec.controllerFarmId = farmId
818 spec.controllerUserId = userId
819
820 g_currentMission.controlledVehicles[self] = self
821
822 if spec.forceSelectionOnEnter then
823 local rootAttacherVehicle = self.rootVehicle
824 if rootAttacherVehicle ~= self then
825 rootAttacherVehicle:setSelectedImplementByObject(self)
826 end
827 end
828
829 if spec.isEntered then
830 -- if head tracking is available we want to use the first indoor camera
831 if g_gameSettings:getValue("isHeadTrackingEnabled") and isHeadTrackingAvailable() then
832 for i,camera in pairs(spec.cameras) do
833 if camera.isInside then
834 spec.camIndex = i
835 break
836 end
837 end
838 end
839
840 if g_gameSettings:getValue("resetCamera") then
841 spec.camIndex = 1
842 end
843 self:setActiveCameraIndex(spec.camIndex)
844 end
845
846 if spec.playerHotspot ~= nil then
847 spec.playerHotspot:setOwnerFarmId(self:getActiveFarm())
848 g_currentMission:addMapHotspot(spec.playerHotspot)
849 end
850
851 if not self:getIsAIActive() then
852 self:setVehicleCharacter(playerStyle)
853
854 if spec.enterAnimation ~= nil and self.playAnimation ~= nil then
855 self:playAnimation(spec.enterAnimation, 1, nil, true)
856 end
857 end
858
859 -- update state for sounds that are played while entering (e.g. motor start)
860 self.isActiveForLocalSound = self:getIsActiveForInput(true, true)
861
862 SpecializationUtil.raiseEvent(self, "onEnterVehicle", isControlling)
863 self.rootVehicle:raiseStateChange(Vehicle.STATE_CHANGE_ENTER_VEHICLE, self, isControlling)
864
865 -- activate actionEvents
866 if self.isClient then
867 g_messageCenter:subscribe(MessageType.INPUT_BINDINGS_CHANGED, self.requestActionEventUpdate, self)
868 self:requestActionEventUpdate()
869 end
870
871 if self.isServer and not isControlling and g_currentMission.trafficSystem ~= nil and g_currentMission.trafficSystem.trafficSystemId ~= 0 then
872 addTrafficSystemPlayer(g_currentMission.trafficSystem.trafficSystemId, self.components[1].node)
873 end
874
875 self:activate()
876end

getActiveCamera

Description
Definition
getActiveCamera()
Code
1363function Enterable:getActiveCamera()
1364 return self.spec_enterable.activeCamera
1365end

getActiveFarm

Description
Definition
getActiveFarm()
Code
1405function Enterable:getActiveFarm(superFunc)
1406 local spec = self.spec_enterable
1407
1408 local farmId = spec.controllerFarmId
1409 if farmId ~= 0 then
1410 return farmId
1411 else
1412 return superFunc(self)
1413 end
1414end

getAllowCharacterVisibilityUpdate

Description
Definition
getAllowCharacterVisibilityUpdate()
Code
1375function Enterable:getAllowCharacterVisibilityUpdate()
1376 return true
1377end

getCanToggleAttach

Description
Definition
getCanToggleAttach()
Code
1396function Enterable:getCanToggleAttach(superFunc)
1397 if not self:getIsEntered() then
1398 return false
1399 end
1400 return superFunc(self)
1401end

getCanToggleSelectable

Description
Definition
getCanToggleSelectable()
Code
1387function Enterable:getCanToggleSelectable(superFunc)
1388 if self:getIsEntered() then
1389 return true
1390 end
1391 return superFunc(self)
1392end

getControllerName

Description
Definition
getControllerName()
Code
1345function Enterable:getControllerName()
1346 local user
1347
1348 if self.isServer then
1349 user = g_currentMission.userManager:getUserByConnection(self:getOwner())
1350 else
1351 user = g_currentMission.userManager:getUserByUserId(self.spec_enterable.controllerUserId)
1352 end
1353
1354 if user == nil then
1355 return ""
1356 end
1357
1358 return user:getNickname()
1359end

getCurrentPlayerStyle

Description
Definition
getCurrentPlayerStyle()
Code
1060function Enterable:getCurrentPlayerStyle()
1061 local spec = self.spec_enterable
1062 if spec.vehicleCharacter ~= nil then
1063 return spec.vehicleCharacter:getPlayerStyle()
1064 end
1065end

getDisableVehicleCharacterOnLeave

Description
Definition
getDisableVehicleCharacterOnLeave()
Code
1381function Enterable:getDisableVehicleCharacterOnLeave()
1382 return self.spec_enterable.disableCharacterOnLeave
1383end

getDistanceToNode

Description
Returns distance between given object and enterReferenceNode
Definition
getDistanceToNode(integer object)
Arguments
integerobjectid of object
Return Values
floatdistancedistance
Code
1208function Enterable:getDistanceToNode(superFunc, node)
1209 local spec = self.spec_enterable
1210
1211 local superDistance = superFunc(self, node)
1212
1213 if spec == nil or spec.enterReferenceNode == nil then
1214 return superDistance
1215 end
1216
1217 local px, py, pz = getWorldTranslation(node)
1218 local vx, vy, vz = getWorldTranslation(spec.enterReferenceNode)
1219 local distance = MathUtil.vector3Length(px-vx, py-vy, pz-vz)
1220
1221 if distance < spec.interactionRadius and distance < superDistance then
1222 self.interactionFlag = Vehicle.INTERACTION_FLAG_ENTERABLE
1223 return distance
1224 end
1225
1226 return superDistance
1227end

getExitNode

Description
Definition
getExitNode()
Code
1047function Enterable:getExitNode()
1048 local spec = self.spec_enterable
1049 return spec.exitPoint
1050end

getFormattedOperatingTime

Description
Definition
getFormattedOperatingTime()
Code
1147function Enterable:getFormattedOperatingTime()
1148 local minutes = self.operatingTime / (1000 * 60)
1149 local hours = math.floor(minutes / 60)
1150 minutes = math.floor((minutes - hours * 60) / 6)
1151 local minutesString = string.format("%02d", minutes*10)
1152
1153 return tonumber(hours.."."..minutesString)
1154end

getInteractionHelp

Description
Returns interaction help text
Definition
getInteractionHelp()
Return Values
stringtexttext
Code
1232function Enterable:getInteractionHelp(superFunc)
1233 if self.interactionFlag == Vehicle.INTERACTION_FLAG_ENTERABLE then
1234 return g_i18n:getText("action_enter")
1235 else
1236 return superFunc(self)
1237 end
1238end

getIsActive

Description
Definition
getIsActive()
Code
1158function Enterable:getIsActive(superFunc)
1159 local spec = self.spec_enterable
1160 if spec.isEntered or spec.isControlled then
1161 return true
1162 else
1163 return superFunc(self)
1164 end
1165end

getIsActiveForInput

Description
Definition
getIsActiveForInput()
Code
1169function Enterable:getIsActiveForInput(superFunc, ignoreSelection, activeForAI)
1170 if not superFunc(self, ignoreSelection, activeForAI) then
1171 return false
1172 end
1173
1174 if g_currentMission.isPlayerFrozen then
1175 return false
1176 end
1177
1178 local spec = self.spec_enterable
1179 if not spec.isEntered or not spec.isControlled then
1180 -- if the vehicle we check if not entered we check if there is another enterable vehicle attached
1181 -- if yes we check if that vehicle is entered since only one vehicle in the "vehicle chain" has to be entered
1182 local noOtherEnterableIsEntered = true
1183
1184 local vehicles = self.rootVehicle:getChildVehicles()
1185 for _, vehicle in ipairs(vehicles) do
1186 local vehicleSpec = vehicle.spec_enterable
1187 if vehicleSpec ~= nil then
1188 if vehicle ~= self then
1189 if vehicleSpec.isEntered or vehicleSpec.isControlled then
1190 noOtherEnterableIsEntered = false
1191 end
1192 end
1193 end
1194 end
1195
1196 if noOtherEnterableIsEntered then
1197 return false
1198 end
1199 end
1200
1201 return true
1202end

getIsAdditionalCharacterActive

Description
Definition
getIsAdditionalCharacterActive()
Code
615function Enterable:getIsAdditionalCharacterActive()
616 return false
617end

getIsControlled

Description
Definition
getIsControlled()
Code
1339function Enterable:getIsControlled()
1340 return self.spec_enterable.isControlled
1341end

getIsDashboardGroupActive

Description
Definition
getIsDashboardGroupActive()
Code
1430function Enterable:getIsDashboardGroupActive(superFunc, group)
1431 if group.isEntered ~= nil then
1432 if group.isEntered ~= self:getIsEntered() then
1433 return false
1434 end
1435 end
1436
1437 return superFunc(self, group)
1438end

getIsEnterable

Description
Get whether current player can enter this vehicle Only works when isClient
Definition
getIsEnterable()
Code
1319function Enterable:getIsEnterable()
1320 local spec = self.spec_enterable
1321 return spec.enterReferenceNode ~= nil and spec.exitPoint ~= nil and not spec.isBroken and not spec.isControlled and g_currentMission.accessHandler:canPlayerAccess(self)
1322end

getIsEnterableFromMenu

Description
Get whether current player can enter this vehicle from menu Only works when isClient
Definition
getIsEnterableFromMenu()
Code
1327function Enterable:getIsEnterableFromMenu()
1328 return self:getIsEnterable() and self.spec_enterable.canBeEnteredFromMenu
1329end

getIsEntered

Description
Definition
getIsEntered()
Code
1333function Enterable:getIsEntered()
1334 return self.spec_enterable.isEntered
1335end

getIsInUse

Description
Definition
getIsInUse()
Code
1454function Enterable:getIsInUse(superFunc, connection)
1455 local spec = self.spec_enterable
1456 if spec.isControlled and self:getOwner() ~= connection then
1457 return true
1458 end
1459
1460 return superFunc(self, connection)
1461end

getIsMapHotspotVisible

Description
Definition
getIsMapHotspotVisible()
Code
958function Enterable:getIsMapHotspotVisible(superFunc)
959 if not superFunc(self) then
960 return false
961 end
962
963 return not self.spec_enterable.isEntered
964end

getIsTabbable

Description
Definition
getIsTabbable()
Code
1306function Enterable:getIsTabbable()
1307 return self.spec_enterable.isTabbable
1308end

getUserPlayerStyle

Description
Definition
getUserPlayerStyle()
Code
1054function Enterable:getUserPlayerStyle()
1055 return self.spec_enterable.playerStyle
1056end

getVehicleCharacter

Description
Definition
getVehicleCharacter()
Code
1369function Enterable:getVehicleCharacter()
1370 return self.spec_enterable.vehicleCharacter
1371end

initSpecialization

Description
Definition
initSpecialization()
Code
25function Enterable.initSpecialization()
26 Vehicle.registerStateChange("ENTER_VEHICLE")
27 Vehicle.registerStateChange("LEAVE_VEHICLE")
28
29 local schema = Vehicle.xmlSchema
30 schema:setXMLSpecializationType("Enterable")
31
32 schema:register(XMLValueType.BOOL, "vehicle.enterable#isTabbable", "Vehicle is tabbable", true)
33 schema:register(XMLValueType.BOOL, "vehicle.enterable#canBeEnteredFromMenu", "Vehicle can be entered from menu", "same as #isTabbable")
34 schema:register(XMLValueType.BOOL, "vehicle.enterable.forceSelectionOnEnter", "Vehicle is selected on entering", false)
35 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.enterReferenceNode#node", "Enter reference node")
36 schema:register(XMLValueType.FLOAT, "vehicle.enterable.enterReferenceNode#interactionRadius", "Interaction radius", 6)
37 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.exitPoint#node", "Exit point")
38
39 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.nicknameRenderNode#node", "Nickname rendering node", "root node")
40 schema:register(XMLValueType.VECTOR_TRANS, "vehicle.enterable.nicknameRenderNode#offset", "Nickname rendering offset")
41
42 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.reverb#referenceNode", "Reference node for reverb calculations", "center of vehicle +2m Y")
43
44 schema:register(XMLValueType.STRING, "vehicle.enterable.enterAnimation#name", "Enter animation name")
45
46 VehicleCharacter.registerCharacterXMLPaths(schema, "vehicle.enterable.characterNode")
47
48 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.additionalCharacter#node", "Additional character node")
49 VehicleCharacter.registerCharacterXMLPaths(schema, "vehicle.enterable.additionalCharacter")
50
51 VehicleCamera.registerCameraXMLPaths(schema, "vehicle.enterable.cameras.camera(?)")
52
53 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.characterTargetNodeModifier(?)#node", "Target node")
54 schema:register(XMLValueType.STRING, "vehicle.enterable.characterTargetNodeModifier(?)#poseId", "Modifier pose id")
55 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.characterTargetNodeModifier(?).state(?)#node", "State node")
56 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.characterTargetNodeModifier(?).state(?)#referenceNode", "State is activated if this node moves or rotates")
57 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.characterTargetNodeModifier(?).state(?)#directionReferenceNode", "State node is align to this node")
58 schema:register(XMLValueType.STRING, "vehicle.enterable.characterTargetNodeModifier(?).state(?)#poseId", "Pose id")
59 schema:register(XMLValueType.FLOAT, "vehicle.enterable.characterTargetNodeModifier(?)#transitionTime", "Time between state changes", 0.1)
60 schema:register(XMLValueType.FLOAT, "vehicle.enterable.characterTargetNodeModifier(?)#transitionIdleDelay", "State is changed after this delay", 0.5)
61
62 schema:register(XMLValueType.NODE_INDEX, "vehicle.enterable.mirrors.mirror(?)#node", "Mirror node")
63 schema:register(XMLValueType.INT, "vehicle.enterable.mirrors.mirror(?)#prio", "Priority", 2)
64
65 Dashboard.registerDashboardXMLPaths(schema, "vehicle.enterable.dashboards", "time | operatingTime | outsideTemperature")
66
67 SoundManager.registerSampleXMLPaths(schema, "vehicle.enterable.sounds", "rain(?)")
68
69 schema:register(XMLValueType.BOOL, Dashboard.GROUP_XML_KEY .. "#isEntered", "Is entered")
70
71 schema:register(XMLValueType.BOOL, Cylindered.MOVING_TOOL_XML_KEY .. "#updateCharacterTargetModifier", "Update character target modifier state", false)
72 schema:register(XMLValueType.BOOL, Cylindered.MOVING_PART_XML_KEY .. "#updateCharacterTargetModifier", "Update character target modifier state", false)
73
74 schema:setXMLSpecializationType()
75
76 local schemaSavegame = Vehicle.xmlSchemaSavegame
77 VehicleCamera.registerCameraSavegameXMLPaths(schemaSavegame, "vehicles.vehicle(?).enterable.camera(?)")
78 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).enterable#activeCameraIndex", "Index of active camera", 1)
79end

interact

Description
Interact
Definition
interact()
Code
1242function Enterable:interact(superFunc)
1243 if self.interactionFlag == Vehicle.INTERACTION_FLAG_ENTERABLE then
1244 g_currentMission:requestToEnterVehicle(self)
1245 else
1246 superFunc(self)
1247 end
1248end

leaveVehicle

Description
Leave vehicle
Definition
leaveVehicle()
Code
889function Enterable:leaveVehicle()
890 local spec = self.spec_enterable
891
892 g_currentMission:removePauseListeners(self)
893
894 local wasEntered = spec.isEntered
895 if spec.activeCamera ~= nil and spec.isEntered then
896 spec.activeCamera:onDeactivate()
897 g_soundManager:setIsIndoor(false)
898 g_currentMission.ambientSoundSystem:setIsIndoor(false)
899 g_currentMission.activatableObjectsSystem:deactivate(Vehicle.INPUT_CONTEXT_NAME)
900
901 g_depthOfFieldManager:reset()
902
903 if self.isClient then
904 g_soundManager:stopSamples(spec.rainSamples)
905 spec.lastIsRaining = false
906 end
907 end
908
909 if spec.playerHotspot ~= nil then
910 g_currentMission:removeMapHotspot(spec.playerHotspot)
911 end
912
913 spec.isControlled = false
914 spec.isEntered = false
915 spec.playerIndex = 0
916 spec.playerColorIndex = 0
917 spec.canUseEnter = true
918 spec.controllerFarmId = 0
919 spec.controllerUserId = 0
920
921 g_currentMission.controlledVehicles[self] = nil
922 g_currentMission:setLastInteractionTime(200)
923
924 if spec.vehicleCharacter ~= nil and self:getDisableVehicleCharacterOnLeave() then
925 self:deleteVehicleCharacter()
926 end
927
928 if spec.enterAnimation ~= nil and self.playAnimation ~= nil then
929 self:playAnimation(spec.enterAnimation, -1, nil, true)
930 end
931
932 self:setMirrorVisible(false)
933
934 SpecializationUtil.raiseEvent(self, "onLeaveVehicle", wasEntered)
935 self.rootVehicle:raiseStateChange(Vehicle.STATE_CHANGE_LEAVE_VEHICLE, self)
936
937 -- deactivate actionEvents
938 if self.isClient then
939 g_messageCenter:unsubscribe(MessageType.INPUT_BINDINGS_CHANGED, self)
940 self:requestActionEventUpdate()
941
942 if g_touchHandler ~= nil then
943 g_touchHandler:removeGestureListener(self.touchListenerDoubleTab)
944 end
945 end
946
947 if self.isServer and not spec.isEntered and g_currentMission.trafficSystem ~= nil and g_currentMission.trafficSystem.trafficSystemId ~= 0 then
948 removeTrafficSystemPlayer(g_currentMission.trafficSystem.trafficSystemId, self.components[1].node)
949 end
950
951 if self:getDeactivateOnLeave() then
952 self:deactivate()
953 end
954end

loadAdditionalCharacterFromXML

Description
Definition
loadAdditionalCharacterFromXML()
Code
600function Enterable:loadAdditionalCharacterFromXML(xmlFile)
601 local spec = self.spec_enterable
602
603 spec.additionalCharacterNode = xmlFile:getValue("vehicle.enterable.additionalCharacter#node", nil, self.components, self.i3dMappings)
604 spec.additionalCharacterTargets = {}
605 IKUtil.loadIKChainTargets(xmlFile, "vehicle.enterable.additionalCharacter", self.components, spec.additionalCharacterTargets, self.i3dMappings)
606 spec.additionalCharacterActive = false
607 if spec.vehicleCharacter ~= nil then
608 spec.defaultCharacterNode = spec.vehicleCharacter.characterNode
609 spec.defaultCharacterTargets = spec.vehicleCharacter:getIKChainTargets()
610 end
611end

loadCamerasFromXML

Description
Definition
loadCamerasFromXML()
Code
573function Enterable:loadCamerasFromXML(xmlFile, savegame)
574 local spec = self.spec_enterable
575
576 XMLUtil.checkDeprecatedXMLElements(xmlFile, "vehicle.cameras.camera(0)#index", "vehicle.enterable.cameras.camera(0)#node") -- FS17
577 XMLUtil.checkDeprecatedXMLElements(xmlFile, "vehicle.cameras.camera(0).raycastNode(0)#index", "vehicle.enterable.cameras.camera(0).raycastNode(0)#node") -- FS17
578
579 spec.cameras = {}
580 local i = 0
581 while true do
582 local cameraKey = string.format("vehicle.enterable.cameras.camera(%d)", i)
583 if not xmlFile:hasProperty(cameraKey) then
584 break
585 end
586
587 local camera = VehicleCamera.new(self)
588 if camera:loadFromXML(xmlFile, cameraKey, savegame, i) then
589 table.insert(spec.cameras, camera)
590 end
591 i = i + 1
592 end
593 spec.numCameras = #spec.cameras
594
595 spec.camIndex = 1
596end

loadCharacterTargetNodeModifier

Description
Definition
loadCharacterTargetNodeModifier()
Code
621function Enterable:loadCharacterTargetNodeModifier(entry, xmlFile, xmlKey)
622 XMLUtil.checkDeprecatedXMLElements(xmlFile, xmlKey .. "#index", xmlKey .. "#node") --FS17 to FS19
623
624 entry.node = xmlFile:getValue(xmlKey .. "#node", nil, self.components, self.i3dMappings)
625 if entry.node ~= nil then
626 entry.parent = getParent(entry.node)
627 entry.translationOffset = {getTranslation(entry.node)}
628 entry.rotationOffset = {getRotation(entry.node)}
629 entry.poseId = xmlFile:getValue(xmlKey .. "#poseId")
630
631 entry.states = {}
632
633 local j = 0
634 while true do
635 local stateKey = string.format("%s.state(%d)", xmlKey, j)
636 if not xmlFile:hasProperty(stateKey) then
637 break
638 end
639
640 XMLUtil.checkDeprecatedXMLElements(xmlFile, stateKey .. "#index", stateKey .. "#node") --FS17 to FS19
641
642 local node = xmlFile:getValue(stateKey .. "#node", nil, self.components, self.i3dMappings)
643 if node ~= nil then
644 local state = {}
645 state.node = node
646 state.referenceNode = xmlFile:getValue(stateKey .. "#referenceNode", nil, self.components, self.i3dMappings)
647 state.directionReferenceNode = xmlFile:getValue(stateKey .. "#directionReferenceNode", nil, self.components, self.i3dMappings)
648 state.poseId = self.xmlFile:getValue(stateKey .. "#poseId")
649
650 if state.referenceNode ~= nil then
651 state.defaultRotation = {getRotation(state.referenceNode)}
652 state.defaultTranslation = {getTranslation(state.referenceNode)}
653
654 local spec = self.spec_enterable
655 if spec.characterTargetNodeReferenceToState[state.referenceNode] == nil then
656 spec.characterTargetNodeReferenceToState[state.referenceNode] = {}
657 end
658
659 table.insert(spec.characterTargetNodeReferenceToState[state.referenceNode], state)
660
661 table.insert(entry.states, state)
662 end
663 else
664 Logging.xmlWarning(self.xmlFile, "Missing node for state '%s'", stateKey)
665 end
666
667 j = j + 1
668 end
669
670 entry.transitionTime = self.xmlFile:getValue(xmlKey .. "#transitionTime", 0.1) * 1000
671 entry.transitionAlpha = 1.0
672
673 entry.transitionIdleDelay = self.xmlFile:getValue(xmlKey .. "#transitionIdleDelay", 0.5) * 1000
674 entry.transitionIdleTime = 0
675
676 return true
677 end
678
679 return false
680end

loadDashboardGroupFromXML

Description
Definition
loadDashboardGroupFromXML()
Code
1418function Enterable:loadDashboardGroupFromXML(superFunc, xmlFile, key, group)
1419 if not superFunc(self, xmlFile, key, group) then
1420 return false
1421 end
1422
1423 group.isEntered = xmlFile:getValue(key .. "#isEntered")
1424
1425 return true
1426end

loadExtraDependentParts

Description
Definition
loadExtraDependentParts()
Code
1465function Enterable:loadExtraDependentParts(superFunc, xmlFile, baseName, entry)
1466 if not superFunc(self, xmlFile, baseName, entry) then
1467 return false
1468 end
1469
1470 entry.updateCharacterTargetModifier = xmlFile:getValue(baseName.. "#updateCharacterTargetModifier", false)
1471
1472 return true
1473end

mountDynamic

Description
Definition
mountDynamic()
Code
1442function Enterable:mountDynamic(superFunc, object, objectActorId, jointNode, mountType, forceAcceleration)
1443 local spec = self.spec_enterable
1444
1445 if spec.isControlled then
1446 return false
1447 end
1448
1449 return superFunc(self, object, objectActorId, jointNode, mountType, forceAcceleration)
1450end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
374function Enterable:onDelete()
375 local spec = self.spec_enterable
376
377 if spec.vehicleCharacter ~= nil then
378 spec.vehicleCharacter:delete()
379 spec.vehicleCharacter = nil
380 end
381 if spec.cameras ~= nil then
382 for _, camera in ipairs(spec.cameras) do
383 camera:delete()
384 end
385 end
386
387 if spec.playerHotspot ~= nil then
388 g_currentMission:removeMapHotspot(spec.playerHotspot)
389 spec.playerHotspot:delete()
390 spec.playerHotspot = nil
391 end
392
393 g_soundManager:deleteSamples(spec.rainSamples)
394
395 spec.weatherObject = nil
396
397 g_currentMission:removeEnterableVehicle(self)
398 g_currentMission:removeInteractiveVehicle(self)
399end

onDrawUIInfo

Description
Called on ui info draw, renders nicknames in multiplayer
Definition
onDrawUIInfo()
Code
553function Enterable:onDrawUIInfo()
554 local spec = self.spec_enterable
555
556 local visible = not g_gui:getIsGuiVisible() and not g_noHudModeEnabled and g_gameSettings:getValue(GameSettings.SETTING.SHOW_MULTIPLAYER_NAMES)
557 if not spec.isEntered and self.isClient and self:getIsActive() and spec.isControlled and visible then
558 local x,y,z = getWorldTranslation(spec.nicknameRendering.node)
559 local x1,y1,z1 = getWorldTranslation(getCamera())
560 local distSq = MathUtil.vector3LengthSq(x-x1,y-y1,z-z1)
561 if distSq <= 100*100 then
562 x = x + spec.nicknameRendering.offset[1]
563 y = y + spec.nicknameRendering.offset[2]
564 z = z + spec.nicknameRendering.offset[3]
565
566 Utils.renderTextAtWorldPosition(x,y,z, self:getControllerName(), getCorrectTextSize(0.02), 0)
567 end
568 end
569end

onLoad

Description
Definition
onLoad()
Code
175function Enterable:onLoad(savegame)
176
177 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.mirrors.mirror(0)#index", "vehicle.enterable.mirrors.mirror(0)#node") --FS17 to FS19
178 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterReferenceNode", "vehicle.enterable.enterReferenceNode") --FS17 to FS19
179 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterReferenceNode#index", "vehicle.enterable.enterReferenceNode#node") --FS17 to FS19
180 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterable.enterReferenceNode#index", "vehicle.enterable.enterReferenceNode#node") --FS17 to FS19
181 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.exitPoint", "vehicle.enterable.exitPoint") --FS17 to FS19
182 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.exitPoint#index", "vehicle.enterable.exitPoint#node") --FS17 to FS19
183 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterable.exitPoint#index", "vehicle.enterable.exitPoint#node") --FS17 to FS19
184 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.characterNode", "vehicle.enterable.characterNode") --FS17 to FS19
185 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.characterNode#index", "vehicle.enterable.characterNode#node") --FS17 to FS19
186 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterable.characterNode#index", "vehicle.enterable.characterNode#node") --FS17 to FS19
187 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.nicknameRenderNode", "vehicle.enterable.nicknameRenderNode") --FS17 to FS19
188 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterAnimation", "vehicle.enterable.enterAnimation") --FS17 to FS19
189 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.cameras.camera1", "vehicle.enterable.cameras.camera") --FS17 to FS19
190 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterable.cameras.camera1", "vehicle.enterable.cameras.camera") --FS17 to FS19
191 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.indoorHud.time", "vehicle.enterable.dashboards.dashboard with valueType 'time'") --FS17 to FS19
192 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.indoorHud.operatingTime", "vehicle.enterable.dashboards.dashboard with valueType 'operatingTime'") --FS17 to FS19
193 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.enterable.nicknameRenderNode#index", "vehicle.enterable.nicknameRenderNode#node") --FS19 to FS21
194
195 local spec = self.spec_enterable
196
197 spec.isTabbable = self.xmlFile:getValue("vehicle.enterable#isTabbable", true)
198 spec.canBeEnteredFromMenu = self.xmlFile:getValue("vehicle.enterable#canBeEnteredFromMenu", spec.isTabbable)
199 spec.isEntered = false
200 spec.isControlled = false
201 spec.playerStyle = nil
202 spec.canUseEnter = true
203 spec.controllerFarmId = 0
204 spec.controllerUserId = 0
205
206 spec.disableCharacterOnLeave = true
207
208 spec.forceSelectionOnEnter = self.xmlFile:getValue("vehicle.enterable.forceSelectionOnEnter", false)
209
210 spec.enterReferenceNode = self.xmlFile:getValue("vehicle.enterable.enterReferenceNode#node", nil, self.components, self.i3dMappings)
211 spec.exitPoint = self.xmlFile:getValue("vehicle.enterable.exitPoint#node", nil, self.components, self.i3dMappings)
212
213 spec.interactionRadius = self.xmlFile:getValue("vehicle.enterable.enterReferenceNode#interactionRadius", 6.0)
214
215 spec.vehicleCharacter = VehicleCharacter.new(self)
216 if spec.vehicleCharacter ~= nil and not spec.vehicleCharacter:load(self.xmlFile, "vehicle.enterable.characterNode", self.i3dMappings) then
217 spec.vehicleCharacter = nil
218 end
219
220 self:loadAdditionalCharacterFromXML(self.xmlFile)
221
222 spec.nicknameRendering = {}
223 spec.nicknameRendering.node = self.xmlFile:getValue("vehicle.enterable.nicknameRenderNode#node", nil, self.components, self.i3dMappings)
224 spec.nicknameRendering.offset = self.xmlFile:getValue("vehicle.enterable.nicknameRenderNode#offset", nil, true)
225 if spec.nicknameRendering.node == nil then
226 if spec.vehicleCharacter ~= nil and spec.vehicleCharacter.characterDistanceRefNode ~= nil then
227 spec.nicknameRendering.node = spec.vehicleCharacter.characterDistanceRefNode
228 if spec.nicknameRendering.offset == nil then
229 spec.nicknameRendering.offset = {0, 1.5, 0}
230 end
231 else
232 spec.nicknameRendering.node = self.components[1].node
233 end
234 end
235 if spec.nicknameRendering.offset == nil then
236 spec.nicknameRendering.offset = {0, 4, 0}
237 end
238
239 spec.enterAnimation = self.xmlFile:getValue("vehicle.enterable.enterAnimation#name")
240 if spec.enterAnimation ~= nil and not self:getAnimationExists(spec.enterAnimation) then
241 Logging.xmlWarning(self.xmlFile, "Unable to find enter animation '%s'", spec.enterAnimation)
242 end
243
244 self:loadCamerasFromXML(self.xmlFile, savegame)
245
246 if spec.numCameras == 0 then
247 Logging.xmlError(self.xmlFile, "No cameras defined!")
248 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
249 return
250 end
251
252 spec.characterTargetNodeReferenceToState = {}
253 spec.characterTargetNodeModifiers = {}
254 local i = 0
255 while true do
256 local key = string.format("vehicle.enterable.characterTargetNodeModifier(%d)", i)
257 if not self.xmlFile:hasProperty(key) then
258 break
259 end
260
261 local modifier = {}
262 if self:loadCharacterTargetNodeModifier(modifier, self.xmlFile, key) then
263 table.insert(spec.characterTargetNodeModifiers, modifier)
264 end
265 i = i + 1
266 end
267
268 -- for development version we get all mirror meshes from the vehicle
269 -- and check if all of them are entered in the xml and the objectMasks are correctly set
270 local allMirrors = {}
271 if g_isDevelopmentVersion then
272 I3DUtil.getNodesByShaderParam(self.rootNode, "reflectionScale", allMirrors)
273 end
274
275 spec.mirrors = {}
276 local useMirrors = g_gameSettings:getValue("maxNumMirrors") > 0
277 i = 0
278 while true do
279 local key = string.format("vehicle.enterable.mirrors.mirror(%d)", i)
280 if not self.xmlFile:hasProperty(key) then
281 break
282 end
283
284 local node = self.xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings)
285 if node ~= nil then
286 local prio = self.xmlFile:getValue(key.."#prio", 2)
287 setReflectionMapObjectMasks(node, 32896, 2147483648, true) --0x8080, 0x80000000
288 if getObjectMask(node) == 0 then
289 -- Mirrors should not be visible in other mirrors
290 setObjectMask(node, 16711807) -- 0x00FF007F
291 end
292
293 if useMirrors then
294 table.insert(spec.mirrors, {node=node, prio=prio, cosAngle=1})
295 else
296 setVisibility(node, false)
297 end
298
299 allMirrors[node] = nil
300 end
301 i = i + 1
302 end
303
304 for node, _ in pairs(allMirrors) do
305 Logging.xmlError(self.xmlFile, "Found Mesh '%s' with mirrorShader that is not entered in the vehicle XML", getName(node))
306 end
307
308 self:setMirrorVisible(spec.cameras[spec.camIndex].useMirror)
309
310 if self.loadDashboardsFromXML ~= nil then
311 self:loadDashboardsFromXML(self.xmlFile, "vehicle.enterable.dashboards", {valueTypeToLoad = "time",
312 valueObject = g_currentMission.environment,
313 valueFunc = "getEnvironmentTime"})
314
315 self:loadDashboardsFromXML(self.xmlFile, "vehicle.enterable.dashboards", {valueTypeToLoad = "operatingTime",
316 valueObject = self,
317 valueFunc = "getFormattedOperatingTime"})
318
319 self:loadDashboardsFromXML(self.xmlFile, "vehicle.enterable.dashboards", {valueTypeToLoad = "outsideTemperature",
320 valueObject = g_currentMission.environment.weather,
321 valueFunc = "getCurrentTemperature"})
322
323 end
324
325 spec.lastIsRaining = false
326 spec.weatherObject = g_currentMission.environment.weather
327
328 if self.isClient then
329 spec.rainSamples = g_soundManager:loadSamplesFromXML(self.xmlFile, "vehicle.enterable.sounds", "rain", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
330 end
331
332 spec.reverbReferenceNode = self.xmlFile:getValue("vehicle.enterable.reverb#referenceNode", nil, self.components, self.i3dMappings)
333 if spec.reverbReferenceNode == nil then
334 spec.reverbReferenceNode = createTransformGroup("ReverebRefNode")
335 link(self.rootNode, spec.reverbReferenceNode)
336 setTranslation(spec.reverbReferenceNode, 0, 2, 0)
337 end
338
339 spec.dirtyFlag = self:getNextDirtyFlag()
340
341 spec.playerHotspot = PlayerHotspot.new()
342 spec.playerHotspot:setVehicle(self)
343
344 g_currentMission:addInteractiveVehicle(self)
345 g_currentMission:addEnterableVehicle(self)
346end

onLoadFinished

Description
Definition
onLoadFinished()
Code
364function Enterable:onLoadFinished(savegame)
365 local spec = self.spec_enterable
366 if spec.isControlled then
367 spec.playerHotspot:setOwnerFarmId(self:getActiveFarm())
368 g_currentMission:addMapHotspot(spec.playerHotspot)
369 end
370end

onPlayerStyleChanged

Description
Definition
onPlayerStyleChanged()
Code
1095function Enterable:onPlayerStyleChanged(style, userId)
1096 if self.isServer then
1097 local connection = self:getOwner()
1098 local currentUserId = g_currentMission.userManager:getUserIdByConnection(connection)
1099 if currentUserId == userId then
1100 self:setVehicleCharacter(style)
1101 g_server:broadcastEvent(VehiclePlayerStyleChangedEvent.new(self, style))
1102 end
1103 end
1104end

onPostLoad

Description
Definition
onPostLoad()
Code
350function Enterable:onPostLoad(savegame)
351 local spec = self.spec_enterable
352 for i=1, #spec.cameras do
353 local camera = spec.cameras[i]
354 camera:onPostLoad(savegame)
355 end
356
357 if savegame ~= nil and not savegame.resetVehicles then
358 spec.camIndex = savegame.xmlFile:getValue(savegame.key..".enterable#activeCameraIndex", 1)
359 end
360end

onPostUpdate

Description
Called on postUpdate
Definition
onPostUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
519function Enterable:onPostUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
520 local spec = self.spec_enterable
521
522 if self.isClient then
523 if spec.isEntered and spec.vehicleCharacter ~= nil then
524 if spec.vehicleCharacter.characterSpineNode ~= nil and spec.vehicleCharacter.characterSpineSpeedDepended then
525 spec.vehicleCharacter:setSpineDirty(self.lastSpeedAcceleration)
526 end
527 end
528
529 if self.finishedFirstUpdate then
530 if self:getIsEntered() then
531 spec.activeCamera:update(dt)
532 end
533
534 -- update character visiblity
535 if self:getAllowCharacterVisibilityUpdate() then
536 if spec.vehicleCharacter ~= nil then
537 spec.vehicleCharacter:updateVisibility()
538 end
539 end
540 end
541
542 if self:getIsControlled() then
543 -- do mirror checks
544 if spec.activeCamera ~= nil and spec.activeCamera.useMirror then
545 self:setMirrorVisible(true)
546 end
547 end
548 end
549end

onPreLoad

Description
Definition
onPreLoad()
Code
169function Enterable:onPreLoad(savegame)
170 Vehicle.registerInteractionFlag("Enterable")
171end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
405function Enterable:onReadStream(streamId, connection)
406 local isControlled = streamReadBool(streamId)
407 if isControlled then
408 local playerStyle = PlayerStyle.new()
409 playerStyle:readStream(streamId, connection)
410 local farmId = streamReadUIntN(streamId, FarmManager.FARM_ID_SEND_NUM_BITS)
411 local userId = streamReadInt32(streamId)
412 self:enterVehicle(false, playerStyle, farmId, userId)
413 end
414end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
1487function Enterable:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
1488 if self:getIsEntered() then
1489 local spec = self.spec_enterable
1490 self:clearActionEventsTable(spec.actionEvents)
1491 if g_touchHandler ~= nil then
1492 g_touchHandler:removeGestureListener(self.touchListenerDoubleTab)
1493 end
1494
1495 if self:getIsActiveForInput(true, true) then
1496 local actionEventId, _
1497 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.ENTER, self, Enterable.actionEventLeave, false, true, false, true, nil)
1498 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
1499 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1500
1501 if spec.numCameras > 1 then
1502 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CAMERA_SWITCH, self, Enterable.actionEventCameraSwitch, false, true, false, true, nil)
1503 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW)
1504 g_inputBinding:setActionEventTextVisibility(actionEventId, true)
1505 end
1506
1507 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CAMERA_ZOOM_IN, self, Enterable.actionEventCameraZoomIn, false, true, true, true, nil)
1508 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW)
1509 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1510
1511 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CAMERA_ZOOM_OUT, self, Enterable.actionEventCameraZoomOut, false, true, true, true, nil)
1512 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW)
1513 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1514
1515 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.RESET_HEAD_TRACKING, self, Enterable.actionEventResetHeadTracking, false, true, false, true, nil)
1516 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW)
1517 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
1518
1519 if g_touchHandler ~= nil then
1520 self.touchListenerDoubleTab = g_touchHandler:registerGestureListener(TouchHandler.GESTURE_DOUBLE_TAP, Enterable.actionEventCameraSwitch, self)
1521 end
1522
1523 -- stop and reenter modification of vehicle context since activatableObjectsSystem is doing this on it's own and leaving the modification after this call
1524 g_inputBinding:endActionEventsModification()
1525 g_currentMission.activatableObjectsSystem:activate(Vehicle.INPUT_CONTEXT_NAME)
1526 g_inputBinding:beginActionEventsModification(Vehicle.INPUT_CONTEXT_NAME)
1527 end
1528 end
1529end

onSetBroken

Description
Definition
onSetBroken()
Code
1533function Enterable:onSetBroken()
1534 local spec = self.spec_enterable
1535 if spec.isEntered then
1536 g_currentMission:onLeaveVehicle()
1537 end
1538end

onUpdate

Description
Called on update
Definition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
459function Enterable:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
460 if self:getIsControlled() then
461 if self.isClient then
462 local spec = self.spec_enterable
463 for _,modifier in ipairs(spec.characterTargetNodeModifiers) do
464 self:updateCharacterTargetNodeModifier(dt, modifier)
465 end
466
467 if spec.vehicleCharacter ~= nil then
468 spec.vehicleCharacter:update(dt)
469 end
470
471 if self:getIsAdditionalCharacterActive() ~= spec.additionalCharacterActive then
472 spec.additionalCharacterActive = not spec.additionalCharacterActive
473
474 local character = self:getVehicleCharacter()
475 if character ~= nil then
476 local node = spec.defaultCharacterNode
477 local targets = spec.defaultCharacterTargets
478 if spec.additionalCharacterActive then
479 targets = spec.additionalCharacterTargets
480 node = spec.additionalCharacterNode
481 end
482
483 character:setIKChainTargets(targets)
484 character.characterNode = node
485
486 -- character may not be loaded yet
487 if character.playerModel.rootNode ~= nil then
488 link(node, character.playerModel.rootNode)
489 end
490 end
491 end
492
493 if spec.rainSamples ~= nil and #spec.rainSamples > 0 then
494 local isRaining = spec.weatherObject:getRainFallScale() > 0
495 if isRaining ~= spec.lastIsRaining then
496 if isRaining then
497 g_soundManager:playSamples(spec.rainSamples)
498 else
499 g_soundManager:stopSamples(spec.rainSamples)
500 end
501
502 spec.lastIsRaining = isRaining
503 end
504 end
505
506 local x, y, z = getWorldTranslation(self.rootNode)
507 g_currentMission.activatableObjectsSystem:setPosition(x, y, z)
508 end
509
510 self.rootVehicle:raiseActive()
511 end
512end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
420function Enterable:onWriteStream(streamId, connection)
421 local spec = self.spec_enterable
422 if streamWriteBool(streamId, spec.isControlled) then
423 spec.playerStyle:writeStream(streamId, connection)
424 streamWriteUIntN(streamId, spec.controllerFarmId, FarmManager.FARM_ID_SEND_NUM_BITS)
425 streamWriteInt32(streamId, spec.controllerUserId)
426 end
427end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
19function Enterable.prerequisitesPresent(specializations)
20 return true
21end

registerEventListeners

Description
Definition
registerEventListeners()
Code
152function Enterable.registerEventListeners(vehicleType)
153 SpecializationUtil.registerEventListener(vehicleType, "onPreLoad", Enterable)
154 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Enterable)
155 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Enterable)
156 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Enterable)
157 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Enterable)
158 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Enterable)
159 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Enterable)
160 SpecializationUtil.registerEventListener(vehicleType, "onPostUpdate", Enterable)
161 SpecializationUtil.registerEventListener(vehicleType, "onDrawUIInfo", Enterable)
162 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Enterable)
163 SpecializationUtil.registerEventListener(vehicleType, "onSetBroken", Enterable)
164 SpecializationUtil.registerEventListener(vehicleType, "onLoadFinished", Enterable)
165end

registerEvents

Description
Definition
registerEvents()
Code
83function Enterable.registerEvents(vehicleType)
84 SpecializationUtil.registerEvent(vehicleType, "onEnterVehicle")
85 SpecializationUtil.registerEvent(vehicleType, "onLeaveVehicle")
86 SpecializationUtil.registerEvent(vehicleType, "onCameraChanged")
87 SpecializationUtil.registerEvent(vehicleType, "onVehicleCharacterChanged")
88end

registerFunctions

Description
Definition
registerFunctions()
Code
92function Enterable.registerFunctions(vehicleType)
93 SpecializationUtil.registerFunction(vehicleType, "enterVehicle", Enterable.enterVehicle)
94 SpecializationUtil.registerFunction(vehicleType, "doLeaveVehicle", Enterable.doLeaveVehicle)
95 SpecializationUtil.registerFunction(vehicleType, "leaveVehicle", Enterable.leaveVehicle)
96 SpecializationUtil.registerFunction(vehicleType, "setActiveCameraIndex", Enterable.setActiveCameraIndex)
97 SpecializationUtil.registerFunction(vehicleType, "addToolCameras", Enterable.addToolCameras)
98 SpecializationUtil.registerFunction(vehicleType, "removeToolCameras", Enterable.removeToolCameras)
99 SpecializationUtil.registerFunction(vehicleType, "getExitNode", Enterable.getExitNode)
100 SpecializationUtil.registerFunction(vehicleType, "getUserPlayerStyle", Enterable.getUserPlayerStyle)
101 SpecializationUtil.registerFunction(vehicleType, "getCurrentPlayerStyle", Enterable.getCurrentPlayerStyle)
102 SpecializationUtil.registerFunction(vehicleType, "setVehicleCharacter", Enterable.setVehicleCharacter)
103 SpecializationUtil.registerFunction(vehicleType, "vehicleCharacterLoaded", Enterable.vehicleCharacterLoaded)
104 SpecializationUtil.registerFunction(vehicleType, "onPlayerStyleChanged", Enterable.onPlayerStyleChanged)
105 SpecializationUtil.registerFunction(vehicleType, "setRandomVehicleCharacter", Enterable.setRandomVehicleCharacter)
106 SpecializationUtil.registerFunction(vehicleType, "restoreVehicleCharacter", Enterable.restoreVehicleCharacter)
107 SpecializationUtil.registerFunction(vehicleType, "deleteVehicleCharacter", Enterable.deleteVehicleCharacter)
108 SpecializationUtil.registerFunction(vehicleType, "getFormattedOperatingTime", Enterable.getFormattedOperatingTime)
109 SpecializationUtil.registerFunction(vehicleType, "loadCharacterTargetNodeModifier", Enterable.loadCharacterTargetNodeModifier)
110 SpecializationUtil.registerFunction(vehicleType, "updateCharacterTargetNodeModifier", Enterable.updateCharacterTargetNodeModifier)
111 SpecializationUtil.registerFunction(vehicleType, "setCharacterTargetNodeStateDirty", Enterable.setCharacterTargetNodeStateDirty)
112 SpecializationUtil.registerFunction(vehicleType, "resetCharacterTargetNodeStateDefaults", Enterable.resetCharacterTargetNodeStateDefaults)
113 SpecializationUtil.registerFunction(vehicleType, "setMirrorVisible", Enterable.setMirrorVisible)
114 SpecializationUtil.registerFunction(vehicleType, "getIsTabbable", Enterable.getIsTabbable)
115 SpecializationUtil.registerFunction(vehicleType, "setIsTabbable", Enterable.setIsTabbable)
116 SpecializationUtil.registerFunction(vehicleType, "getIsEnterable", Enterable.getIsEnterable)
117 SpecializationUtil.registerFunction(vehicleType, "getIsEnterableFromMenu", Enterable.getIsEnterableFromMenu)
118 SpecializationUtil.registerFunction(vehicleType, "getIsEntered", Enterable.getIsEntered)
119 SpecializationUtil.registerFunction(vehicleType, "getIsControlled", Enterable.getIsControlled)
120 SpecializationUtil.registerFunction(vehicleType, "getControllerName", Enterable.getControllerName)
121 SpecializationUtil.registerFunction(vehicleType, "getActiveCamera", Enterable.getActiveCamera)
122 SpecializationUtil.registerFunction(vehicleType, "getVehicleCharacter", Enterable.getVehicleCharacter)
123 SpecializationUtil.registerFunction(vehicleType, "getAllowCharacterVisibilityUpdate", Enterable.getAllowCharacterVisibilityUpdate)
124 SpecializationUtil.registerFunction(vehicleType, "getDisableVehicleCharacterOnLeave", Enterable.getDisableVehicleCharacterOnLeave)
125 SpecializationUtil.registerFunction(vehicleType, "loadCamerasFromXML", Enterable.loadCamerasFromXML)
126 SpecializationUtil.registerFunction(vehicleType, "loadAdditionalCharacterFromXML", Enterable.loadAdditionalCharacterFromXML)
127 SpecializationUtil.registerFunction(vehicleType, "getIsAdditionalCharacterActive", Enterable.getIsAdditionalCharacterActive)
128end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
132function Enterable.registerOverwrittenFunctions(vehicleType)
133 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsActive", Enterable.getIsActive)
134 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsActiveForInput", Enterable.getIsActiveForInput)
135 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDistanceToNode", Enterable.getDistanceToNode)
136 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getInteractionHelp", Enterable.getInteractionHelp)
137 SpecializationUtil.registerOverwrittenFunction(vehicleType, "interact", Enterable.interact)
138 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleSelectable", Enterable.getCanToggleSelectable)
139 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleAttach", Enterable.getCanToggleAttach)
140 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getActiveFarm", Enterable.getActiveFarm)
141 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadDashboardGroupFromXML", Enterable.loadDashboardGroupFromXML)
142 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDashboardGroupActive", Enterable.getIsDashboardGroupActive)
143 SpecializationUtil.registerOverwrittenFunction(vehicleType, "mountDynamic", Enterable.mountDynamic)
144 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsInUse", Enterable.getIsInUse)
145 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadExtraDependentParts", Enterable.loadExtraDependentParts)
146 SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateExtraDependentParts", Enterable.updateExtraDependentParts)
147 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsMapHotspotVisible", Enterable.getIsMapHotspotVisible)
148end

removeToolCameras

Description
Remove cameras from tool
Definition
removeToolCameras(table cameras)
Arguments
tablecamerascameras to remove
Code
1014function Enterable:removeToolCameras(cameras)
1015 local spec = self.spec_enterable
1016
1017 local isToolCameraActive = false
1018
1019 for j = #spec.cameras, 1, -1 do
1020 local camera = spec.cameras[j]
1021 for _,toolCamera in pairs(cameras) do
1022 if toolCamera == camera then
1023 table.remove(spec.cameras, j)
1024 if j == spec.camIndex then
1025 isToolCameraActive = true
1026 end
1027 break
1028 end
1029 end
1030 end
1031
1032 spec.numCameras = #spec.cameras
1033
1034 -- only reset camera if current camera was a tool camera which is not available anymore
1035 if isToolCameraActive then
1036 if spec.activeCamera ~= nil then
1037 spec.activeCamera:onDeactivate()
1038 end
1039
1040 spec.camIndex = 1
1041 self:setActiveCameraIndex(spec.camIndex)
1042 end
1043end

resetCharacterTargetNodeStateDefaults

Description
Definition
resetCharacterTargetNodeStateDefaults()
Code
791function Enterable:resetCharacterTargetNodeStateDefaults(referenceNode)
792 local spec = self.spec_enterable
793 local states = spec.characterTargetNodeReferenceToState[referenceNode]
794 if states ~= nil then
795 for i=1, #states do
796 local state = states[i]
797 state.defaultRotation[1], state.defaultRotation[2], state.defaultRotation[3] = getRotation(state.referenceNode)
798 state.defaultTranslation[1], state.defaultTranslation[2], state.defaultTranslation[3] = getTranslation(state.referenceNode)
799 end
800 end
801end

restoreVehicleCharacter

Description
Definition
restoreVehicleCharacter()
Code
1124function Enterable:restoreVehicleCharacter()
1125 local spec = self.spec_enterable
1126 if spec.vehicleCharacter ~= nil then
1127 if self:getIsControlled() then
1128 self:setVehicleCharacter(self:getUserPlayerStyle())
1129 else
1130 self:deleteVehicleCharacter()
1131 end
1132 end
1133end

saveStatsToXMLFile

Description
Returns string with name of controller for game stats xml
Definition
saveStatsToXMLFile()
Return Values
stringstatesAttributesstates attributes
Code
443function Enterable:saveStatsToXMLFile(xmlFile, key)
444 local spec = self.spec_enterable
445 if spec.isControlled then
446 local name = self:getControllerName()
447 if name ~= nil then
448 setXMLString(xmlFile, key.."#controller", HTMLUtil.encodeToHTML(name))
449 end
450 end
451 return nil
452end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
431function Enterable:saveToXMLFile(xmlFile, key, usedModNames)
432 local spec = self.spec_enterable
433 for i=1, #spec.cameras do
434 spec.cameras[i]:saveToXMLFile(xmlFile, string.format("%s.camera(%d)", key, i-1), usedModNames)
435 end
436
437 xmlFile:setValue(key .. "#activeCameraIndex", spec.camIndex)
438end

setActiveCameraIndex

Description
Change active camera index
Definition
setActiveCameraIndex(integer index)
Arguments
integerindexindex of camera to set
Code
969function Enterable:setActiveCameraIndex(index)
970 local spec = self.spec_enterable
971
972 if spec.activeCamera ~= nil then
973 spec.activeCamera:onDeactivate()
974 end
975 spec.camIndex = index
976 if spec.camIndex > spec.numCameras then
977 spec.camIndex = 1
978 end
979 local activeCamera = spec.cameras[spec.camIndex]
980 spec.activeCamera = activeCamera
981 activeCamera:onActivate()
982
983 g_soundManager:setIsIndoor(not activeCamera.useOutdoorSounds)
984 g_currentMission.ambientSoundSystem:setIsIndoor(not activeCamera.useOutdoorSounds)
985
986 self:setMirrorVisible(activeCamera.useMirror)
987
988 if activeCamera.isInside then
989 g_depthOfFieldManager:setManipulatedParams(nil, 0.6, nil, nil, nil)
990 else
991 g_depthOfFieldManager:reset()
992 end
993
994 g_currentMission.environmentAreaSystem:setReferenceNode(activeCamera.cameraNode)
995
996 SpecializationUtil.raiseEvent(self, "onCameraChanged", activeCamera, spec.camIndex)
997end

setCharacterTargetNodeStateDirty

Description
Definition
setCharacterTargetNodeStateDirty()
Code
763function Enterable:setCharacterTargetNodeStateDirty(referenceNode, forceActive)
764 local spec = self.spec_enterable
765 local states = spec.characterTargetNodeReferenceToState[referenceNode]
766 if states ~= nil then
767 for i=1, #states do
768 local state = states[i]
769 state.isActive = forceActive == true
770
771 local x, y, z = getRotation(state.referenceNode)
772 local refX, refY, refZ = unpack(state.defaultRotation)
773
774 if math.abs(x-refX) + math.abs(y-refY) + math.abs(z-refZ) > 0.001 then
775 state.isActive = true
776 end
777
778 -- check if the translation is different than the translation on loading
779 x, y, z = getTranslation(state.referenceNode)
780 refX, refY, refZ = unpack(state.defaultTranslation)
781
782 if math.abs(x-refX) + math.abs(y-refY) + math.abs(z-refZ) > 0.001 then
783 state.isActive = true
784 end
785 end
786 end
787end

setIsTabbable

Description
Definition
setIsTabbable()
Code
1312function Enterable:setIsTabbable(isTabbable)
1313 self.spec_enterable.isTabbable = isTabbable
1314end

setMirrorVisible

Description
Definition
setMirrorVisible()
Code
1252function Enterable:setMirrorVisible(visible)
1253 local spec = self.spec_enterable
1254
1255 if spec.mirrors == nil or next(spec.mirrors) == nil then
1256 return
1257 end
1258
1259 if visible then
1260 local numVisibleMirrors = 0
1261 for _, mirror in pairs(spec.mirrors) do
1262 -- only use mirrors which are visible on screen
1263 if getIsInCameraFrustum(mirror.node, spec.activeCamera.cameraNode, g_presentedScreenAspectRatio) then
1264 -- calculate angle between mirror and camera
1265 --local dirX, dirY, dirZ = worldToLocal(spec.activeCamera.cameraNode, getWorldTranslation(mirror.node))
1266 local dirX, dirY, dirZ = localToLocal(spec.activeCamera.cameraNode, mirror.node, 0,0,0)
1267
1268 dirY = dirY * g_screenAspectRatio
1269 local length = MathUtil.vector3Length(dirX, dirY, dirZ)
1270 mirror.cosAngle = -dirZ / length
1271 else
1272 mirror.cosAngle = math.huge
1273 end
1274 end
1275
1276 -- sort mirrors based on prio and angle
1277 table.sort(spec.mirrors,
1278 function(mirror1, mirror2)
1279 if mirror1.prio == mirror2.prio then
1280 -- the bigger cosAngle, the smaller the angle to the z-axis
1281 return mirror1.cosAngle > mirror2.cosAngle
1282 else
1283 return mirror1.prio < mirror2.prio
1284 end
1285 end)
1286
1287 local maxNumMirrors = g_gameSettings:getValue("maxNumMirrors")
1288 -- show first mirrors within the limit
1289 for _, mirror in ipairs(spec.mirrors) do
1290 if mirror.cosAngle ~= math.huge and numVisibleMirrors < maxNumMirrors then
1291 setVisibility(mirror.node, true)
1292 numVisibleMirrors = numVisibleMirrors + 1
1293 else
1294 setVisibility(mirror.node, false)
1295 end
1296 end
1297 else
1298 for _, mirror in pairs(spec.mirrors) do
1299 setVisibility(mirror.node, false)
1300 end
1301 end
1302end

setRandomVehicleCharacter

Description
Definition
setRandomVehicleCharacter()
Code
1108function Enterable:setRandomVehicleCharacter(helper)
1109 local spec = self.spec_enterable
1110 if spec.vehicleCharacter ~= nil then
1111 local playerStyle
1112 if helper ~= nil then
1113 playerStyle = PlayerStyle.newHelper(helper)
1114 else
1115 playerStyle = PlayerStyle.newRandomHelper()
1116 end
1117
1118 self:setVehicleCharacter(playerStyle)
1119 end
1120end

setVehicleCharacter

Description
Definition
setVehicleCharacter()
Code
1069function Enterable:setVehicleCharacter(playerStyle)
1070 local spec = self.spec_enterable
1071
1072 self:deleteVehicleCharacter()
1073
1074 if spec.vehicleCharacter ~= nil then
1075 spec.vehicleCharacter:loadCharacter(playerStyle, self, self.vehicleCharacterLoaded)
1076 end
1077end

updateCharacterTargetNodeModifier

Description
Definition
updateCharacterTargetNodeModifier()
Code
684function Enterable:updateCharacterTargetNodeModifier(dt, modifier)
685 local node = modifier.parent
686 local poseId = modifier.poseId
687 for _,state in pairs(modifier.states) do
688 if state.isActive then
689 node = state.node
690 poseId = state.poseId or poseId
691
692 -- align the target node to the direction reference node
693 if state.directionReferenceNode ~= nil then
694 local wx, wy, wz = getWorldTranslation(state.directionReferenceNode)
695 local lx, ly, lz = getTranslation(state.node)
696 local dx, dy, dz = worldToLocal(getParent(state.node), wx, wy, wz)
697 setDirection(state.node, dx-lx, dy-ly, dz-lz, 0, 1, 0)
698 end
699 end
700 end
701
702 local isDirty = modifier.transitionAlpha < 1
703 local allowSwitch = node ~= modifier.parent
704
705 if not allowSwitch then
706 modifier.transitionIdleTime = modifier.transitionIdleTime + dt
707
708 if modifier.transitionIdleTime > modifier.transitionIdleDelay then
709 allowSwitch = true
710 modifier.transitionIdleTime = 0
711 end
712 end
713
714 if allowSwitch and getParent(modifier.node) ~= node then
715 local transStartPos = {localToLocal(modifier.node, node, 0,0,0)}
716 local transEndPos = {0, 0, 0}
717 if node == modifier.parent then
718 transEndPos = modifier.translationOffset
719 end
720 modifier.transitionStartPos = transStartPos
721 modifier.transitionEndPos = transEndPos
722
723 if math.abs(transEndPos[1] - transStartPos[1]) < 0.001 and math.abs(transEndPos[2] - transStartPos[2]) < 0.001 and math.abs(transEndPos[3] - transStartPos[3]) < 0.001 then
724 modifier.transitionAlpha = 1.0
725 else
726 modifier.transitionAlpha = 0
727 end
728
729 isDirty = true
730
731 local rx,ry,rz = localRotationToLocal(modifier.node, node, 0,0,0)
732 modifier.transitionStartQuat = {mathEulerToQuaternion(rx, ry, rz)}
733 modifier.transitionEndQuat = {0, 0, 0, 1}
734 if node == modifier.parent then
735 modifier.transitionEndQuat = {mathEulerToQuaternion(unpack(modifier.rotationOffset))}
736 end
737
738 link(node, modifier.node)
739
740 if poseId ~= nil then
741 local character = self:getVehicleCharacter()
742 if character ~= nil then
743 character:setIKChainPoseByTarget(modifier.node, poseId)
744 end
745 end
746 end
747
748 if isDirty then
749 modifier.transitionAlpha = math.min(1.0, modifier.transitionAlpha + (dt/modifier.transitionTime))
750
751 local x,y,z = MathUtil.vector3ArrayLerp(modifier.transitionStartPos, modifier.transitionEndPos, modifier.transitionAlpha)
752 setTranslation(modifier.node, x,y,z)
753
754 local qx,qy,qz,qw = MathUtil.slerpQuaternionShortestPath(modifier.transitionStartQuat[1], modifier.transitionStartQuat[2], modifier.transitionStartQuat[3], modifier.transitionStartQuat[4],
755 modifier.transitionEndQuat[1], modifier.transitionEndQuat[2], modifier.transitionEndQuat[3], modifier.transitionEndQuat[4],
756 modifier.transitionAlpha)
757 setQuaternion(modifier.node, qx,qy,qz,qw)
758 end
759end

updateExtraDependentParts

Description
Definition
updateExtraDependentParts()
Code
1477function Enterable:updateExtraDependentParts(superFunc, part, dt)
1478 superFunc(self, part, dt)
1479
1480 if part.updateCharacterTargetModifier then
1481 self:setCharacterTargetNodeStateDirty(part.node, false)
1482 end
1483end

vehicleCharacterLoaded

Description
Definition
vehicleCharacterLoaded()
Code
1081function Enterable:vehicleCharacterLoaded(success, arguments)
1082 local spec = self.spec_enterable
1083 if success then
1084 spec.vehicleCharacter:updateVisibility()
1085 spec.vehicleCharacter:updateIKChains()
1086 end
1087
1088 SpecializationUtil.raiseEvent(self, "onVehicleCharacterChanged", spec.vehicleCharacter)
1089
1090 g_messageCenter:subscribe(MessageType.PLAYER_STYLE_CHANGED, self.onPlayerStyleChanged, self)
1091end