Script v1.7.1.0
- AI
- Animals
- Contracts
- Debug
- Economy
- Effects
- Events
- Farms
- GUI
- Handtools
- I3d
- Materials
- Misc
- Objects
- Placeables
- Player
- Shop
- Sounds
- Specializations
- Triggers
- Utils
- Vehicles
- Weather
Engine v1.7.1.0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- XML
- general
Foundation Reference
Enterable
DescriptionThis specialization enables the player to enter a vehicle. It also loads cameras and player characterFunctions
- actionEventActivateObject
- actionEventCameraSwitch
- actionEventCameraZoomIn
- actionEventCameraZoomOut
- actionEventLeave
- actionEventResetHeadTracking
- addToolCameras
- deleteVehicleCharacter
- drawUIInfo
- enterVehicle
- getActiveCamera
- getActiveFarm
- getAllowCharacterVisibilityUpdate
- getCanToggleAttach
- getCanToggleSelectable
- getControllerName
- getCurrentPlayerStyle
- getDisableVehicleCharacterOnLeave
- getDistanceToNode
- getExitNode
- getFormattedOperatingTime
- getInteractionHelp
- getIsActive
- getIsActiveForInput
- getIsAdditionalCharacterActive
- getIsControlled
- getIsDashboardGroupActive
- getIsEnterable
- getIsEntered
- getIsInUse
- getIsTabbable
- getPlayerColorIndex
- getPlayerModelIndex
- getUserPlayerStyle
- getVehicleCharacter
- interact
- leaveVehicle
- loadAdditionalCharacterFromXML
- loadCamerasFromXML
- loadCharacterTargetNodeModifier
- loadDashboardGroupFromXML
- mountDynamic
- onDelete
- onLoad
- onPostUpdate
- onPreLoad
- onReadStream
- onRegisterActionEvents
- onSetBroken
- onUpdate
- onWriteStream
- prerequisitesPresent
- registerEventListeners
- registerEvents
- registerFunctions
- registerOverwrittenFunctions
- removeToolCameras
- restoreVehicleCharacter
- saveStatsToXMLFile
- setActiveCameraIndex
- setIsTabbable
- setMirrorVisible
- setRandomVehicleCharacter
- setVehicleCharacter
- updateCharacterTargetNodeModifier
actionEventActivateObject
DescriptionDefinitionactionEventActivateObject()Code
1294 | function Enterable.actionEventActivateObject(self, actionName, inputValue, callbackState, isAnalog) |
1295 | -- take an object which is active-able and was added latest |
1296 | for key, object in pairs(g_currentMission.activatableObjects) do |
1297 | if object:getIsActivatable() then |
1298 | g_currentMission.activatableObjects[key] = nil |
1299 | |
1300 | object:onActivateObject() |
1301 | |
1302 | for _, v in pairs(g_currentMission.activateListeners) do |
1303 | v:onActivateObject(object) |
1304 | end |
1305 | break |
1306 | end |
1307 | end |
1308 | end |
actionEventCameraSwitch
DescriptionDefinitionactionEventCameraSwitch()Code
1257 | function Enterable.actionEventCameraSwitch(self, actionName, inputValue, callbackState, isAnalog) |
1258 | local spec = self.spec_enterable |
1259 | self:setActiveCameraIndex(spec.camIndex + 1) |
1260 | end |
actionEventCameraZoomIn
DescriptionDefinitionactionEventCameraZoomIn()Code
1264 | function Enterable.actionEventCameraZoomIn(self, actionName, inputValue, callbackState, isAnalog, isMouse) |
1265 | local spec = self.spec_enterable |
1266 | local offset = -0.2 |
1267 | if isMouse then -- mouse wheel zoom, must use larger value because of engine input handling |
1268 | offset = offset * InputBinding.MOUSE_WHEEL_INPUT_FACTOR |
1269 | end |
1270 | |
1271 | spec.activeCamera:zoomSmoothly(offset) |
1272 | end |
actionEventCameraZoomOut
DescriptionDefinitionactionEventCameraZoomOut()Code
1276 | function Enterable.actionEventCameraZoomOut(self, actionName, inputValue, callbackState, isAnalog, isMouse) |
1277 | local spec = self.spec_enterable |
1278 | local offset = 0.2 |
1279 | if isMouse then -- mouse wheel zoom, must use larger value because of engine input handling |
1280 | offset = offset * InputBinding.MOUSE_WHEEL_INPUT_FACTOR |
1281 | end |
1282 | |
1283 | spec.activeCamera:zoomSmoothly(offset) |
1284 | end |
actionEventLeave
DescriptionDefinitionactionEventLeave()Code
1247 | function Enterable.actionEventLeave(self, actionName, inputValue, callbackState, isAnalog) |
1248 | local spec = self.spec_enterable |
1249 | if spec.isEntered then |
1250 | g_currentMission:onLeaveVehicle() |
1251 | g_currentMission.eventActivateObject = "" |
1252 | end |
1253 | end |
actionEventResetHeadTracking
DescriptionDefinitionactionEventResetHeadTracking()Code
1288 | function Enterable.actionEventResetHeadTracking(self, actionName, inputValue, callbackState, isAnalog) |
1289 | centerHeadTracking() |
1290 | end |
addToolCameras
DescriptionAdd cameras from toolDefinition
addToolCameras(table cameras)Arguments
table | cameras | cameras to add |
723 | function Enterable:addToolCameras(cameras) |
724 | local spec = self.spec_enterable |
725 | |
726 | for _,toolCamera in pairs(cameras) do |
727 | table.insert(spec.cameras, toolCamera) |
728 | end |
729 | spec.numCameras = #spec.cameras |
730 | end |
deleteVehicleCharacter
DescriptionDefinitiondeleteVehicleCharacter()Code
867 | function Enterable:deleteVehicleCharacter() |
868 | local spec = self.spec_enterable |
869 | if spec.vehicleCharacter ~= nil then |
870 | spec.vehicleCharacter:delete() |
871 | end |
872 | end |
drawUIInfo
DescriptionCalled on ui info draw, renders nicknames in multiplayerDefinition
drawUIInfo()Code
937 | function Enterable:drawUIInfo(superFunc) |
938 | local spec = self.spec_enterable |
939 | |
940 | superFunc(self) |
941 | |
942 | if not spec.isEntered and self.isClient and self:getIsActive() and spec.isControlled and not g_gui:getIsGuiVisible() and not g_flightAndNoHUDKeysEnabled then |
943 | local x,y,z = getWorldTranslation(spec.nicknameRendering.node) |
944 | local x1,y1,z1 = getWorldTranslation(getCamera()) |
945 | local distSq = MathUtil.vector3LengthSq(x-x1,y-y1,z-z1) |
946 | if distSq <= 100*100 then |
947 | x = x + spec.nicknameRendering.offset[1] |
948 | y = y + spec.nicknameRendering.offset[2] |
949 | z = z + spec.nicknameRendering.offset[3] |
950 | |
951 | Utils.renderTextAtWorldPosition(x,y,z, self:getControllerName(), getCorrectTextSize(0.02), 0) |
952 | end |
953 | end |
954 | end |
enterVehicle
DescriptionEnter vehicleDefinition
enterVehicle(boolean isControlling, integer playerIndex, integer playerColorIndex)Arguments
boolean | isControlling | is controlling vehicle |
integer | playerIndex | index of player who enters the vehicle |
integer | playerColorIndex | index of player color |
573 | function Enterable:enterVehicle(isControlling, playerStyle, farmId) |
574 | local spec = self.spec_enterable |
575 | |
576 | self:raiseActive() |
577 | |
578 | spec.isControlled = true |
579 | spec.isEntered = isControlling |
580 | spec.playerStyle = playerStyle |
581 | spec.canUseEnter = false |
582 | spec.controllerFarmId = farmId |
583 | |
584 | g_currentMission.controlledVehicles[self] = self |
585 | |
586 | if spec.forceSelectionOnEnter then |
587 | local rootAttacherVehicle = self:getRootVehicle() |
588 | if rootAttacherVehicle ~= self then |
589 | rootAttacherVehicle:setSelectedImplementByObject(self) |
590 | end |
591 | end |
592 | |
593 | if spec.isEntered then |
594 | -- if head tracking is available we want to use the first indoor camera |
595 | if g_gameSettings:getValue("isHeadTrackingEnabled") and isHeadTrackingAvailable() then |
596 | for i,camera in pairs(spec.cameras) do |
597 | if camera.isInside then |
598 | spec.camIndex = i |
599 | break |
600 | end |
601 | end |
602 | end |
603 | |
604 | if g_gameSettings:getValue("resetCamera") then |
605 | spec.camIndex = 1 |
606 | end |
607 | self:setActiveCameraIndex(spec.camIndex) |
608 | end |
609 | |
610 | if not self:getIsAIActive() then |
611 | local playerModel = g_playerModelManager:getPlayerModelByIndex(spec.playerStyle.selectedModelIndex) |
612 | self:setVehicleCharacter(playerModel.xmlFilename, spec.playerStyle) |
613 | |
614 | if spec.enterAnimation ~= nil and self.playAnimation ~= nil then |
615 | self:playAnimation(spec.enterAnimation, 1, nil, true) |
616 | end |
617 | end |
618 | |
619 | SpecializationUtil.raiseEvent(self, "onEnterVehicle", isControlling) |
620 | |
621 | -- activate actionEvents |
622 | if self.isClient then |
623 | g_messageCenter:subscribe(MessageType.INPUT_BINDINGS_CHANGED, self.requestActionEventUpdate, self) |
624 | self:requestActionEventUpdate() |
625 | end |
626 | |
627 | if self.isServer and not isControlling and g_currentMission.trafficSystem ~= nil and g_currentMission.trafficSystem.trafficSystemId ~= 0 then |
628 | addTrafficSystemPlayer(g_currentMission.trafficSystem.trafficSystemId, self.components[1].node) |
629 | end |
630 | |
631 | self:activate() |
632 | end |
getActiveCamera
DescriptionDefinitiongetActiveCamera()Code
1097 | function Enterable:getActiveCamera() |
1098 | return self.spec_enterable.activeCamera |
1099 | end |
getActiveFarm
DescriptionDefinitiongetActiveFarm()Code
1139 | function Enterable:getActiveFarm(superFunc) |
1140 | local spec = self.spec_enterable |
1141 | |
1142 | local farmId = spec.controllerFarmId |
1143 | if farmId ~= 0 then |
1144 | return farmId |
1145 | else |
1146 | return superFunc(self) |
1147 | end |
1148 | end |
getAllowCharacterVisibilityUpdate
DescriptionDefinitiongetAllowCharacterVisibilityUpdate()Code
1109 | function Enterable:getAllowCharacterVisibilityUpdate() |
1110 | return true |
1111 | end |
getCanToggleAttach
DescriptionDefinitiongetCanToggleAttach()Code
1130 | function Enterable:getCanToggleAttach(superFunc) |
1131 | if not self:getIsEntered() then |
1132 | return false |
1133 | end |
1134 | return superFunc(self) |
1135 | end |
getCanToggleSelectable
DescriptionDefinitiongetCanToggleSelectable()Code
1121 | function Enterable:getCanToggleSelectable(superFunc) |
1122 | if self:getIsEntered() then |
1123 | return true |
1124 | end |
1125 | return superFunc(self) |
1126 | end |
getControllerName
DescriptionDefinitiongetControllerName()Code
1091 | function Enterable:getControllerName() |
1092 | return self.spec_enterable.playerStyle.playerName |
1093 | end |
getCurrentPlayerStyle
DescriptionDefinitiongetCurrentPlayerStyle()Code
793 | function Enterable:getCurrentPlayerStyle() |
794 | local spec = self.spec_enterable |
795 | if spec.vehicleCharacter ~= nil then |
796 | return spec.vehicleCharacter:getPlayerStyle() |
797 | end |
798 | end |
getDisableVehicleCharacterOnLeave
DescriptionDefinitiongetDisableVehicleCharacterOnLeave()Code
1115 | function Enterable:getDisableVehicleCharacterOnLeave() |
1116 | return self.spec_enterable.disableCharacterOnLeave |
1117 | end |
getDistanceToNode
DescriptionReturns distance between given object and enterReferenceNodeDefinition
getDistanceToNode(integer object)Arguments
integer | object | id of object |
float | distance | distance |
961 | function Enterable:getDistanceToNode(superFunc, node) |
962 | local spec = self.spec_enterable |
963 | |
964 | local superDistance = superFunc(self, node) |
965 | |
966 | if spec == nil or spec.enterReferenceNode == nil then |
967 | return superDistance |
968 | end |
969 | |
970 | local px, py, pz = getWorldTranslation(node) |
971 | local vx, vy, vz = getWorldTranslation(spec.enterReferenceNode) |
972 | local distance = MathUtil.vector3Length(px-vx, py-vy, pz-vz) |
973 | |
974 | if distance < spec.interactionRadius and distance < superDistance then |
975 | self.interactionFlag = Vehicle.INTERACTION_FLAG_ENTERABLE |
976 | return distance |
977 | end |
978 | |
979 | return superDistance |
980 | end |
getExitNode
DescriptionDefinitiongetExitNode()Code
768 | function Enterable:getExitNode() |
769 | local spec = self.spec_enterable |
770 | return spec.exitPoint |
771 | end |
getFormattedOperatingTime
DescriptionDefinitiongetFormattedOperatingTime()Code
876 | function Enterable:getFormattedOperatingTime() |
877 | local minutes = self.operatingTime / (1000 * 60) |
878 | local hours = math.floor(minutes / 60) |
879 | minutes = math.floor((minutes - hours * 60) / 6) |
880 | local minutesString = string.format("%02d", minutes*10) |
881 | |
882 | return tonumber(hours.."."..minutesString) |
883 | end |
getInteractionHelp
DescriptionReturns interaction help textDefinition
getInteractionHelp()Return Values
string | text | text |
985 | function Enterable:getInteractionHelp(superFunc) |
986 | if self.interactionFlag == Vehicle.INTERACTION_FLAG_ENTERABLE then |
987 | return g_i18n:getText("action_enter") |
988 | else |
989 | return superFunc(self) |
990 | end |
991 | end |
getIsActive
DescriptionDefinitiongetIsActive()Code
887 | function Enterable:getIsActive(superFunc) |
888 | local spec = self.spec_enterable |
889 | if spec.isEntered or spec.isControlled then |
890 | return true |
891 | else |
892 | return superFunc(self) |
893 | end |
894 | end |
getIsActiveForInput
DescriptionDefinitiongetIsActiveForInput()Code
898 | function Enterable:getIsActiveForInput(superFunc, ignoreSelection, activeForAI) |
899 | if not superFunc(self, ignoreSelection, activeForAI) then |
900 | return false |
901 | end |
902 | |
903 | if g_currentMission.isPlayerFrozen then |
904 | return false |
905 | end |
906 | |
907 | local spec = self.spec_enterable |
908 | if not spec.isEntered or not spec.isControlled then |
909 | -- if the vehicle we check if not entered we check if there is another enterable vehicle attached |
910 | -- if yes we check if that vehicle is entered since only one vehicle in the "vehicle chain" has to be entered |
911 | local noOtherEnterableIsEntered = true |
912 | |
913 | local vehicles = {} |
914 | self:getRootVehicle():getChildVehicles(vehicles) |
915 | |
916 | for _, vehicle in ipairs(vehicles) do |
917 | local vehicleSpec = vehicle.spec_enterable |
918 | if vehicleSpec ~= nil then |
919 | if vehicle ~= self then |
920 | if vehicleSpec.isEntered or vehicleSpec.isControlled then |
921 | noOtherEnterableIsEntered = false |
922 | end |
923 | end |
924 | end |
925 | end |
926 | |
927 | if noOtherEnterableIsEntered then |
928 | return false |
929 | end |
930 | end |
931 | |
932 | return true |
933 | end |
getIsAdditionalCharacterActive
DescriptionDefinitiongetIsAdditionalCharacterActive()Code
413 | function Enterable:getIsAdditionalCharacterActive() |
414 | return false |
415 | end |
getIsControlled
DescriptionDefinitiongetIsControlled()Code
1085 | function Enterable:getIsControlled() |
1086 | return self.spec_enterable.isControlled |
1087 | end |
getIsDashboardGroupActive
DescriptionDefinitiongetIsDashboardGroupActive()Code
1164 | function Enterable:getIsDashboardGroupActive(superFunc, group) |
1165 | if group.isEntered ~= nil then |
1166 | if group.isEntered ~= self:getIsEntered() then |
1167 | return false |
1168 | end |
1169 | end |
1170 | |
1171 | return superFunc(self, group) |
1172 | end |
getIsEnterable
DescriptionGet whether current player can enter this vehicle Only works when isClientDefinition
getIsEnterable()Code
1072 | function Enterable:getIsEnterable() |
1073 | local spec = self.spec_enterable |
1074 | return not spec.isBroken and not spec.isControlled and g_currentMission.accessHandler:canPlayerAccess(self) |
1075 | end |
getIsEntered
DescriptionDefinitiongetIsEntered()Code
1079 | function Enterable:getIsEntered() |
1080 | return self.spec_enterable.isEntered |
1081 | end |
getIsInUse
DescriptionDefinitiongetIsInUse()Code
1188 | function Enterable:getIsInUse(superFunc, connection) |
1189 | local spec = self.spec_enterable |
1190 | if spec.isControlled and self:getOwner() ~= connection then |
1191 | return true |
1192 | end |
1193 | |
1194 | return superFunc(self, connection) |
1195 | end |
getIsTabbable
DescriptionDefinitiongetIsTabbable()Code
1059 | function Enterable:getIsTabbable() |
1060 | return self.spec_enterable.isTabbable |
1061 | end |
getPlayerColorIndex
DescriptionDefinitiongetPlayerColorIndex()Code
781 | function Enterable:getPlayerColorIndex() |
782 | return self.spec_enterable.playerStyle.selectedColorIndex |
783 | end |
getPlayerModelIndex
DescriptionDefinitiongetPlayerModelIndex()Code
775 | function Enterable:getPlayerModelIndex() |
776 | return self.spec_enterable.playerStyle.selectedModelIndex |
777 | end |
getUserPlayerStyle
DescriptionDefinitiongetUserPlayerStyle()Code
787 | function Enterable:getUserPlayerStyle() |
788 | return self.spec_enterable.playerStyle |
789 | end |
getVehicleCharacter
DescriptionDefinitiongetVehicleCharacter()Code
1103 | function Enterable:getVehicleCharacter() |
1104 | return self.spec_enterable.vehicleCharacter |
1105 | end |
interact
DescriptionInteractDefinition
interact()Code
995 | function Enterable:interact(superFunc) |
996 | if self.interactionFlag == Vehicle.INTERACTION_FLAG_ENTERABLE then |
997 | g_currentMission:requestToEnterVehicle(self) |
998 | else |
999 | superFunc(self) |
1000 | end |
1001 | end |
leaveVehicle
DescriptionLeave vehicleDefinition
leaveVehicle()Code
636 | function Enterable:leaveVehicle() |
637 | local spec = self.spec_enterable |
638 | |
639 | g_currentMission:removePauseListeners(self) |
640 | |
641 | if spec.activeCamera ~= nil and spec.isEntered then |
642 | spec.activeCamera:onDeactivate() |
643 | g_soundManager:setIsIndoor(false) |
644 | |
645 | g_depthOfFieldManager:reset() |
646 | end |
647 | |
648 | if self.spec_rideable ~= nil then |
649 | -- To be called before "spec.vehicleCharacter:delete()" |
650 | self:setEquipmentVisibility(false) |
651 | self:unlinkReins() |
652 | end |
653 | |
654 | spec.isControlled = false |
655 | spec.isEntered = false |
656 | spec.playerIndex = 0 |
657 | spec.playerColorIndex = 0 |
658 | spec.canUseEnter = true |
659 | spec.controllerFarmId = 0 |
660 | |
661 | g_currentMission.controlledVehicles[self] = nil |
662 | g_currentMission:setLastInteractionTime(200) |
663 | |
664 | if spec.vehicleCharacter ~= nil and self:getDisableVehicleCharacterOnLeave() then |
665 | spec.vehicleCharacter:delete() |
666 | end |
667 | |
668 | if spec.enterAnimation ~= nil and self.playAnimation ~= nil then |
669 | self:playAnimation(spec.enterAnimation, -1, nil, true) |
670 | end |
671 | |
672 | self:setMirrorVisible(false) |
673 | |
674 | SpecializationUtil.raiseEvent(self, "onLeaveVehicle") |
675 | |
676 | -- deactivate actionEvents |
677 | if self.isClient then |
678 | g_messageCenter:unsubscribe(MessageType.INPUT_BINDINGS_CHANGED, self) |
679 | self:requestActionEventUpdate() |
680 | end |
681 | |
682 | if self.isServer and not spec.isEntered and g_currentMission.trafficSystem ~= nil and g_currentMission.trafficSystem.trafficSystemId ~= 0 then |
683 | removeTrafficSystemPlayer(g_currentMission.trafficSystem.trafficSystemId, self.components[1].node) |
684 | end |
685 | |
686 | if self:getDeactivateOnLeave() then |
687 | self:deactivate() |
688 | end |
689 | end |
loadAdditionalCharacterFromXML
DescriptionDefinitionloadAdditionalCharacterFromXML()Code
398 | function Enterable:loadAdditionalCharacterFromXML(xmlFile) |
399 | local spec = self.spec_enterable |
400 | |
401 | spec.additionalCharacterNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.enterable.additionalCharacter#node"), self.i3dMappings) |
402 | spec.additionalCharacterTargets = {} |
403 | IKUtil.loadIKChainTargets(self.xmlFile, "vehicle.enterable.additionalCharacter", self.components, spec.additionalCharacterTargets, self.i3dMappings) |
404 | spec.additionalCharacterActive = false |
405 | if spec.vehicleCharacter ~= nil then |
406 | spec.defaultCharacterNode = spec.vehicleCharacter.characterNode |
407 | spec.defaultCharacterTargets = spec.vehicleCharacter:getIKChainTargets() |
408 | end |
409 | end |
loadCamerasFromXML
DescriptionDefinitionloadCamerasFromXML()Code
371 | function Enterable:loadCamerasFromXML(xmlFile) |
372 | local spec = self.spec_enterable |
373 | |
374 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cameras.camera(0)#index", "vehicle.enterable.cameras.camera(0)#node") -- FS17 |
375 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cameras.camera(0).raycastNode(0)#index", "vehicle.enterable.cameras.camera(0).raycastNode(0)#node") -- FS17 |
376 | |
377 | spec.cameras = {} |
378 | local i = 0 |
379 | while true do |
380 | local cameraKey = string.format("vehicle.enterable.cameras.camera(%d)", i) |
381 | if not hasXMLProperty(xmlFile, cameraKey) then |
382 | break |
383 | end |
384 | |
385 | local camera = VehicleCamera:new(self) |
386 | if camera:loadFromXML(xmlFile, cameraKey) then |
387 | table.insert(spec.cameras, camera) |
388 | end |
389 | i = i + 1 |
390 | end |
391 | spec.numCameras = table.getn(spec.cameras) |
392 | |
393 | spec.camIndex = 1 |
394 | end |
loadCharacterTargetNodeModifier
DescriptionDefinitionloadCharacterTargetNodeModifier()Code
419 | function Enterable:loadCharacterTargetNodeModifier(entry, xmlFile, xmlKey) |
420 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, xmlKey .. "#index", xmlKey .. "#node") --FS17 to FS19 |
421 | |
422 | entry.node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, xmlKey .. "#node"), self.i3dMappings) |
423 | if entry.node ~= nil then |
424 | entry.parent = getParent(entry.node) |
425 | entry.translationOffset = {getTranslation(entry.node)} |
426 | entry.rotationOffset = {getRotation(entry.node)} |
427 | entry.poseId = getXMLString(xmlFile, xmlKey .. "#poseId") |
428 | |
429 | entry.states = {} |
430 | |
431 | local j = 0 |
432 | while true do |
433 | local stateKey = string.format("%s.state(%d)", xmlKey, j) |
434 | if not hasXMLProperty(xmlFile, stateKey) then |
435 | break |
436 | end |
437 | |
438 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, stateKey .. "#index", stateKey .. "#node") --FS17 to FS19 |
439 | |
440 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, stateKey .. "#node"), self.i3dMappings) |
441 | if node ~= nil then |
442 | local state = {} |
443 | state.node = node |
444 | state.referenceNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, stateKey .. "#referenceNode"), self.i3dMappings) |
445 | state.directionReferenceNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, stateKey .. "#directionReferenceNode"), self.i3dMappings) |
446 | state.poseId = getXMLString(xmlFile, stateKey .. "#poseId") |
447 | |
448 | if state.referenceNode ~= nil then |
449 | state.defaultRotation = {getRotation(state.referenceNode)} |
450 | state.defaultTranslation = {getTranslation(state.referenceNode)} |
451 | |
452 | table.insert(entry.states, state) |
453 | end |
454 | else |
455 | g_logManager:xmlWarning(self.configFileName, "Missing node for state '%s'", stateKey) |
456 | end |
457 | |
458 | j = j + 1 |
459 | end |
460 | |
461 | entry.transitionTime = Utils.getNoNil(getXMLFloat(self.xmlFile, xmlKey .. "#transitionTime"), 0.1) * 1000 |
462 | entry.transitionAlpha = 1.0 |
463 | |
464 | entry.transitionIdleDelay = Utils.getNoNil(getXMLFloat(self.xmlFile, xmlKey .. "#transitionIdleDelay"), 0.5) * 1000 |
465 | entry.transitionIdleTime = 0 |
466 | |
467 | return true |
468 | end |
469 | |
470 | return false |
471 | end |
loadDashboardGroupFromXML
DescriptionDefinitionloadDashboardGroupFromXML()Code
1152 | function Enterable:loadDashboardGroupFromXML(superFunc, xmlFile, key, group) |
1153 | if not superFunc(self, xmlFile, key, group) then |
1154 | return false |
1155 | end |
1156 | |
1157 | group.isEntered = getXMLBool(xmlFile, key .. "#isEntered") |
1158 | |
1159 | return true |
1160 | end |
mountDynamic
DescriptionDefinitionmountDynamic()Code
1176 | function Enterable:mountDynamic(superFunc, object, objectActorId, jointNode, mountType, forceAcceleration) |
1177 | local spec = self.spec_enterable |
1178 | |
1179 | if spec.isControlled then |
1180 | return false |
1181 | end |
1182 | |
1183 | return superFunc(self, object, objectActorId, jointNode, mountType, forceAcceleration) |
1184 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
238 | function Enterable:onDelete() |
239 | local spec = self.spec_enterable |
240 | |
241 | if spec.vehicleCharacter ~= nil then |
242 | spec.vehicleCharacter:delete() |
243 | end |
244 | for _, camera in ipairs(spec.cameras) do |
245 | camera:delete() |
246 | end |
247 | |
248 | g_currentMission:removeEnterableVehicle(self) |
249 | g_currentMission:removeInteractiveVehicle(self) |
250 | end |
onLoad
DescriptionDefinitiononLoad()Code
104 | function Enterable:onLoad(savegame) |
105 | |
106 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.mirrors.mirror(0)#index", "vehicle.enterable.mirrors.mirror(0)#node") --FS17 to FS19 |
107 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterReferenceNode", "vehicle.enterable.enterReferenceNode") --FS17 to FS19 |
108 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterReferenceNode#index", "vehicle.enterable.enterReferenceNode#node") --FS17 to FS19 |
109 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterable.enterReferenceNode#index", "vehicle.enterable.enterReferenceNode#node") --FS17 to FS19 |
110 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.exitPoint", "vehicle.enterable.exitPoint") --FS17 to FS19 |
111 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.exitPoint#index", "vehicle.enterable.exitPoint#node") --FS17 to FS19 |
112 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterable.exitPoint#index", "vehicle.enterable.exitPoint#node") --FS17 to FS19 |
113 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.characterNode", "vehicle.enterable.characterNode") --FS17 to FS19 |
114 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.characterNode#index", "vehicle.enterable.characterNode#node") --FS17 to FS19 |
115 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterable.characterNode#index", "vehicle.enterable.characterNode#node") --FS17 to FS19 |
116 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.nicknameRenderNode", "vehicle.enterable.nicknameRenderNode") --FS17 to FS19 |
117 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterAnimation", "vehicle.enterable.enterAnimation") --FS17 to FS19 |
118 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cameras.camera1", "vehicle.enterable.cameras.camera") --FS17 to FS19 |
119 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.enterable.cameras.camera1", "vehicle.enterable.cameras.camera") --FS17 to FS19 |
120 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.time", "vehicle.enterable.dashboards.dashboard with valueType 'time'") --FS17 to FS19 |
121 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.operatingTime", "vehicle.enterable.dashboards.dashboard with valueType 'operatingTime'") --FS17 to FS19 |
122 | |
123 | local spec = self.spec_enterable |
124 | |
125 | spec.isTabbable = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.enterable#isTabbable"), true) |
126 | spec.isEntered = false |
127 | spec.isControlled = false |
128 | spec.playerStyle = nil |
129 | spec.canUseEnter = true |
130 | spec.controllerFarmId = 0 |
131 | |
132 | spec.disableCharacterOnLeave = true |
133 | |
134 | spec.forceSelectionOnEnter = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.enterable.forceSelectionOnEnter"), false) |
135 | |
136 | spec.enterReferenceNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.enterable.enterReferenceNode#node"), self.i3dMappings) |
137 | spec.exitPoint = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.enterable.exitPoint#node"), self.i3dMappings) |
138 | |
139 | spec.interactionRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.enterable.enterReferenceNode#interactionRadius"), 6.0) |
140 | |
141 | spec.vehicleCharacter = VehicleCharacter:new(self) |
142 | if spec.vehicleCharacter ~= nil and not spec.vehicleCharacter:load(self.xmlFile, "vehicle.enterable.characterNode", self.i3dMappings) then |
143 | spec.vehicleCharacter = nil |
144 | end |
145 | |
146 | self:loadAdditionalCharacterFromXML(self.xmlFile) |
147 | |
148 | spec.nicknameRendering = {} |
149 | spec.nicknameRendering.node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.enterable.nicknameRenderNode#index"), self.i3dMappings) |
150 | spec.nicknameRendering.offset = StringUtil.getVectorNFromString(getXMLString(self.xmlFile, "vehicle.enterable.nicknameRenderNode#offset"), 3) |
151 | if spec.nicknameRendering.node == nil then |
152 | if spec.vehicleCharacter ~= nil and spec.vehicleCharacter.characterDistanceRefNode ~= nil then |
153 | spec.nicknameRendering.node = spec.vehicleCharacter.characterDistanceRefNode |
154 | if spec.nicknameRendering.offset == nil then |
155 | spec.nicknameRendering.offset = {0, 1.5, 0} |
156 | end |
157 | else |
158 | spec.nicknameRendering.node = self.components[1].node |
159 | end |
160 | end |
161 | if spec.nicknameRendering.offset == nil then |
162 | spec.nicknameRendering.offset = {0, 4, 0} |
163 | end |
164 | |
165 | spec.enterAnimation = getXMLString(self.xmlFile, "vehicle.enterable.enterAnimation#name") |
166 | if spec.enterAnimation ~= nil and not self:getAnimationExists(spec.enterAnimation) then |
167 | g_logManager:xmlWarning(self.configFileName, "Unable to find enter animation '%s'", spec.enterAnimation) |
168 | end |
169 | |
170 | self:loadCamerasFromXML(self.xmlFile) |
171 | |
172 | if spec.numCameras == 0 then |
173 | g_logManager:xmlError(self.configFileName, "No cameras defined!") |
174 | self:setLoadingState(BaseMission.VEHICLE_LOAD_ERROR) |
175 | return |
176 | end |
177 | |
178 | spec.characterTargetNodeModifiers = {} |
179 | local i = 0 |
180 | while true do |
181 | local key = string.format("vehicle.enterable.characterTargetNodeModifier(%d)", i) |
182 | if not hasXMLProperty(self.xmlFile, key) then |
183 | break |
184 | end |
185 | |
186 | local modifier = {} |
187 | if self:loadCharacterTargetNodeModifier(modifier, self.xmlFile, key) then |
188 | table.insert(spec.characterTargetNodeModifiers, modifier) |
189 | end |
190 | i = i + 1 |
191 | end |
192 | |
193 | spec.mirrors = {} |
194 | local useMirrors = g_gameSettings:getValue("maxNumMirrors") > 0 |
195 | i = 0 |
196 | while true do |
197 | local key = string.format("vehicle.enterable.mirrors.mirror(%d)", i) |
198 | if not hasXMLProperty(self.xmlFile, key) then |
199 | break |
200 | end |
201 | |
202 | local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node"), self.i3dMappings) |
203 | if node ~= nil then |
204 | local prio = Utils.getNoNil(getXMLInt(self.xmlFile, key.."#prio"), 2) |
205 | setReflectionMapObjectMasks(node, 32896, 2147483648, true) --0x8080, 0x80000000 |
206 | if getObjectMask(node) == 0 then |
207 | -- Mirrors should not be visible in other mirrors |
208 | setObjectMask(node, 16711807) -- 0x00FF007F |
209 | end |
210 | |
211 | if useMirrors then |
212 | table.insert(spec.mirrors, {node=node, prio=prio, cosAngle=1}) |
213 | else |
214 | setVisibility(node, false) |
215 | end |
216 | end |
217 | i = i + 1 |
218 | end |
219 | |
220 | self:setMirrorVisible(spec.cameras[spec.camIndex].useMirror) |
221 | |
222 | if self.loadDashboardsFromXML ~= nil then |
223 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.enterable.dashboards", {valueTypeToLoad = "time", |
224 | valueObject = g_currentMission.environment, |
225 | valueFunc = "getEnvironmentTime"}) |
226 | |
227 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.enterable.dashboards", {valueTypeToLoad = "operatingTime", |
228 | valueObject = self, |
229 | valueFunc = "getFormattedOperatingTime"}) |
230 | end |
231 | |
232 | g_currentMission:addInteractiveVehicle(self) |
233 | g_currentMission:addEnterableVehicle(self) |
234 | end |
onPostUpdate
DescriptionCalled on postUpdateDefinition
onPostUpdate(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
337 | function Enterable:onPostUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
338 | local spec = self.spec_enterable |
339 | |
340 | if self.isClient then |
341 | if spec.isEntered and spec.vehicleCharacter ~= nil then |
342 | if spec.vehicleCharacter.characterSpineNode ~= nil and spec.vehicleCharacter.characterSpineSpeedDepended then |
343 | spec.vehicleCharacter:setSpineDirty(self.lastSpeedAcceleration) |
344 | end |
345 | end |
346 | |
347 | if self.firstTimeRun then |
348 | if self:getIsEntered() then |
349 | spec.activeCamera:update(dt) |
350 | end |
351 | |
352 | -- update character visiblity |
353 | if self:getAllowCharacterVisibilityUpdate() then |
354 | if spec.vehicleCharacter ~= nil then |
355 | spec.vehicleCharacter:updateVisibility() |
356 | end |
357 | end |
358 | end |
359 | |
360 | if self:getIsControlled() then |
361 | -- do mirror checks |
362 | if spec.activeCamera ~= nil and spec.activeCamera.useMirror then |
363 | self:setMirrorVisible(true) |
364 | end |
365 | end |
366 | end |
367 | end |
onPreLoad
DescriptionDefinitiononPreLoad()Code
98 | function Enterable:onPreLoad(savegame) |
99 | Vehicle.registerInteractionFlag("Enterable") |
100 | end |
onReadStream
DescriptionCalled on client side on joinDefinition
onReadStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
256 | function Enterable:onReadStream(streamId, connection) |
257 | local isControlled = streamReadBool(streamId) |
258 | if isControlled then |
259 | local playerStyle = PlayerStyle:new() |
260 | playerStyle:readStream(streamId, connection) |
261 | local farmId = streamReadUIntN(streamId, FarmManager.FARM_ID_SEND_NUM_BITS) |
262 | self:enterVehicle(false, playerStyle, farmId) |
263 | end |
264 | end |
onRegisterActionEvents
DescriptionDefinitiononRegisterActionEvents()Code
1199 | function Enterable:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
1200 | if self:getIsEntered() then |
1201 | local spec = self.spec_enterable |
1202 | self:clearActionEventsTable(spec.actionEvents) |
1203 | |
1204 | if self:getIsActiveForInput(true, true) then |
1205 | local actionEventId |
1206 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.ENTER, self, Enterable.actionEventLeave, false, true, false, true, nil) |
1207 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH) |
1208 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
1209 | |
1210 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.ACTIVATE_OBJECT, self, Enterable.actionEventActivateObject, false, true, false, false, nil) |
1211 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH) |
1212 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
1213 | g_currentMission.eventActivateObject = actionEventId |
1214 | |
1215 | if spec.numCameras > 1 then |
1216 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CAMERA_SWITCH, self, Enterable.actionEventCameraSwitch, false, true, false, true, nil) |
1217 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW) |
1218 | g_inputBinding:setActionEventTextVisibility(actionEventId, true) |
1219 | end |
1220 | |
1221 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CAMERA_ZOOM_IN, self, Enterable.actionEventCameraZoomIn, false, true, true, true, nil) |
1222 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW) |
1223 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
1224 | |
1225 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CAMERA_ZOOM_OUT, self, Enterable.actionEventCameraZoomOut, false, true, true, true, nil) |
1226 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW) |
1227 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
1228 | |
1229 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.RESET_HEAD_TRACKING, self, Enterable.actionEventResetHeadTracking, false, true, false, true, nil) |
1230 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW) |
1231 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
1232 | end |
1233 | end |
1234 | end |
onSetBroken
DescriptionDefinitiononSetBroken()Code
1238 | function Enterable:onSetBroken() |
1239 | local spec = self.spec_enterable |
1240 | if spec.isEntered then |
1241 | g_currentMission:onLeaveVehicle() |
1242 | end |
1243 | end |
onUpdate
DescriptionCalled on updateDefinition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
294 | function Enterable:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
295 | local spec = self.spec_enterable |
296 | for _,modifier in ipairs(spec.characterTargetNodeModifiers) do |
297 | self:updateCharacterTargetNodeModifier(dt, modifier) |
298 | end |
299 | |
300 | if self:getIsControlled() then |
301 | if self.isClient then |
302 | if spec.vehicleCharacter ~= nil and spec.vehicleCharacter.isCharacterLoaded then |
303 | spec.vehicleCharacter:update(dt) |
304 | end |
305 | |
306 | if self:getIsAdditionalCharacterActive() ~= spec.additionalCharacterActive then |
307 | spec.additionalCharacterActive = not spec.additionalCharacterActive |
308 | |
309 | local character = self:getVehicleCharacter() |
310 | if character ~= nil then |
311 | local node = spec.defaultCharacterNode |
312 | local targets = spec.defaultCharacterTargets |
313 | if spec.additionalCharacterActive then |
314 | targets = spec.additionalCharacterTargets |
315 | node =spec.additionalCharacterNode |
316 | end |
317 | |
318 | character:setIKChainTargets(targets) |
319 | |
320 | character.characterNode = node |
321 | character.characterDistanceRefNode = node |
322 | link(node, character.skeletonThirdPerson) |
323 | character.visualInformation:linkProtectiveWear(node) |
324 | end |
325 | end |
326 | end |
327 | |
328 | self:getRootVehicle():raiseActive() |
329 | end |
330 | end |
onWriteStream
DescriptionCalled on server side on joinDefinition
onWriteStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
270 | function Enterable:onWriteStream(streamId, connection) |
271 | local spec = self.spec_enterable |
272 | if streamWriteBool(streamId, spec.isControlled) then |
273 | spec.playerStyle:writeStream(streamId, connection) |
274 | streamWriteUIntN(streamId, spec.controllerFarmId, FarmManager.FARM_ID_SEND_NUM_BITS) |
275 | end |
276 | end |
prerequisitesPresent
DescriptionDefinitionprerequisitesPresent()Code
15 | function Enterable.prerequisitesPresent(specializations) |
16 | return true |
17 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
84 | function Enterable.registerEventListeners(vehicleType) |
85 | SpecializationUtil.registerEventListener(vehicleType, "onPreLoad", Enterable) |
86 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Enterable) |
87 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Enterable) |
88 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Enterable) |
89 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Enterable) |
90 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Enterable) |
91 | SpecializationUtil.registerEventListener(vehicleType, "onPostUpdate", Enterable) |
92 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Enterable) |
93 | SpecializationUtil.registerEventListener(vehicleType, "onSetBroken", Enterable) |
94 | end |
registerEvents
DescriptionDefinitionregisterEvents()Code
21 | function Enterable.registerEvents(vehicleType) |
22 | SpecializationUtil.registerEvent(vehicleType, "onEnterVehicle") |
23 | SpecializationUtil.registerEvent(vehicleType, "onLeaveVehicle") |
24 | SpecializationUtil.registerEvent(vehicleType, "onCameraChanged") |
25 | SpecializationUtil.registerEvent(vehicleType, "onVehicleCharacterChanged") |
26 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
30 | function Enterable.registerFunctions(vehicleType) |
31 | SpecializationUtil.registerFunction(vehicleType, "enterVehicle", Enterable.enterVehicle) |
32 | SpecializationUtil.registerFunction(vehicleType, "leaveVehicle", Enterable.leaveVehicle) |
33 | SpecializationUtil.registerFunction(vehicleType, "setActiveCameraIndex", Enterable.setActiveCameraIndex) |
34 | SpecializationUtil.registerFunction(vehicleType, "addToolCameras", Enterable.addToolCameras) |
35 | SpecializationUtil.registerFunction(vehicleType, "removeToolCameras", Enterable.removeToolCameras) |
36 | SpecializationUtil.registerFunction(vehicleType, "getExitNode", Enterable.getExitNode) |
37 | SpecializationUtil.registerFunction(vehicleType, "getPlayerModelIndex", Enterable.getPlayerModelIndex) |
38 | SpecializationUtil.registerFunction(vehicleType, "getPlayerColorIndex", Enterable.getPlayerColorIndex) |
39 | SpecializationUtil.registerFunction(vehicleType, "getUserPlayerStyle", Enterable.getUserPlayerStyle) |
40 | SpecializationUtil.registerFunction(vehicleType, "getCurrentPlayerStyle", Enterable.getCurrentPlayerStyle) |
41 | SpecializationUtil.registerFunction(vehicleType, "setVehicleCharacter", Enterable.setVehicleCharacter) |
42 | SpecializationUtil.registerFunction(vehicleType, "setRandomVehicleCharacter", Enterable.setRandomVehicleCharacter) |
43 | SpecializationUtil.registerFunction(vehicleType, "restoreVehicleCharacter", Enterable.restoreVehicleCharacter) |
44 | SpecializationUtil.registerFunction(vehicleType, "deleteVehicleCharacter", Enterable.deleteVehicleCharacter) |
45 | SpecializationUtil.registerFunction(vehicleType, "getFormattedOperatingTime", Enterable.getFormattedOperatingTime) |
46 | SpecializationUtil.registerFunction(vehicleType, "loadCharacterTargetNodeModifier", Enterable.loadCharacterTargetNodeModifier) |
47 | SpecializationUtil.registerFunction(vehicleType, "updateCharacterTargetNodeModifier", Enterable.updateCharacterTargetNodeModifier) |
48 | SpecializationUtil.registerFunction(vehicleType, "setMirrorVisible", Enterable.setMirrorVisible) |
49 | SpecializationUtil.registerFunction(vehicleType, "getIsTabbable", Enterable.getIsTabbable) |
50 | SpecializationUtil.registerFunction(vehicleType, "setIsTabbable", Enterable.setIsTabbable) |
51 | SpecializationUtil.registerFunction(vehicleType, "getIsEnterable", Enterable.getIsEnterable) |
52 | SpecializationUtil.registerFunction(vehicleType, "getIsEntered", Enterable.getIsEntered) |
53 | SpecializationUtil.registerFunction(vehicleType, "getIsControlled", Enterable.getIsControlled) |
54 | SpecializationUtil.registerFunction(vehicleType, "getControllerName", Enterable.getControllerName) |
55 | SpecializationUtil.registerFunction(vehicleType, "getActiveCamera", Enterable.getActiveCamera) |
56 | SpecializationUtil.registerFunction(vehicleType, "getVehicleCharacter", Enterable.getVehicleCharacter) |
57 | SpecializationUtil.registerFunction(vehicleType, "getAllowCharacterVisibilityUpdate", Enterable.getAllowCharacterVisibilityUpdate) |
58 | SpecializationUtil.registerFunction(vehicleType, "getDisableVehicleCharacterOnLeave", Enterable.getDisableVehicleCharacterOnLeave) |
59 | SpecializationUtil.registerFunction(vehicleType, "loadCamerasFromXML", Enterable.loadCamerasFromXML) |
60 | SpecializationUtil.registerFunction(vehicleType, "loadAdditionalCharacterFromXML", Enterable.loadAdditionalCharacterFromXML) |
61 | SpecializationUtil.registerFunction(vehicleType, "getIsAdditionalCharacterActive", Enterable.getIsAdditionalCharacterActive) |
62 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
66 | function Enterable.registerOverwrittenFunctions(vehicleType) |
67 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsActive", Enterable.getIsActive) |
68 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsActiveForInput", Enterable.getIsActiveForInput) |
69 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "drawUIInfo", Enterable.drawUIInfo) |
70 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDistanceToNode", Enterable.getDistanceToNode) |
71 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getInteractionHelp", Enterable.getInteractionHelp) |
72 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "interact", Enterable.interact) |
73 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleSelectable", Enterable.getCanToggleSelectable) |
74 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleAttach", Enterable.getCanToggleAttach) |
75 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getActiveFarm", Enterable.getActiveFarm) |
76 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadDashboardGroupFromXML", Enterable.loadDashboardGroupFromXML) |
77 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDashboardGroupActive", Enterable.getIsDashboardGroupActive) |
78 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "mountDynamic", Enterable.mountDynamic) |
79 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsInUse", Enterable.getIsInUse) |
80 | end |
removeToolCameras
DescriptionRemove cameras from toolDefinition
removeToolCameras(table cameras)Arguments
table | cameras | cameras to remove |
735 | function Enterable:removeToolCameras(cameras) |
736 | local spec = self.spec_enterable |
737 | |
738 | local isToolCameraActive = false |
739 | |
740 | for j = #spec.cameras, 1, -1 do |
741 | local camera = spec.cameras[j] |
742 | for _,toolCamera in pairs(cameras) do |
743 | if toolCamera == camera then |
744 | table.remove(spec.cameras, j) |
745 | if j == spec.camIndex then |
746 | isToolCameraActive = true |
747 | end |
748 | break |
749 | end |
750 | end |
751 | end |
752 | |
753 | spec.numCameras = #spec.cameras |
754 | |
755 | -- only reset camera if current camera was a tool camera which is not available anymore |
756 | if isToolCameraActive then |
757 | if spec.activeCamera ~= nil then |
758 | spec.activeCamera:onDeactivate() |
759 | end |
760 | |
761 | spec.camIndex = 1 |
762 | self:setActiveCameraIndex(spec.camIndex) |
763 | end |
764 | end |
restoreVehicleCharacter
DescriptionDefinitionrestoreVehicleCharacter()Code
853 | function Enterable:restoreVehicleCharacter() |
854 | local spec = self.spec_enterable |
855 | if spec.vehicleCharacter ~= nil then |
856 | if self:getIsControlled() then |
857 | local playerModel = g_playerModelManager:getPlayerModelByIndex(self:getPlayerModelIndex()) |
858 | self:setVehicleCharacter(playerModel.xmlFilename, self:getUserPlayerStyle()) |
859 | else |
860 | self:deleteVehicleCharacter() |
861 | end |
862 | end |
863 | end |
saveStatsToXMLFile
DescriptionReturns string with name of controller for game stats xmlDefinition
saveStatsToXMLFile()Return Values
string | statesAttributes | states attributes |
281 | function Enterable:saveStatsToXMLFile(xmlFile, key) |
282 | local spec = self.spec_enterable |
283 | if spec.isControlled and spec.playerStyle ~= nil and spec.playerStyle.playerName ~= nil then |
284 | setXMLString(xmlFile, key.."#controller", HTMLUtil.encodeToHTML(tostring(spec.playerStyle.playerName))) |
285 | end |
286 | return nil |
287 | end |
setActiveCameraIndex
DescriptionChange active camera indexDefinition
setActiveCameraIndex(integer index)Arguments
integer | index | index of camera to set |
694 | function Enterable:setActiveCameraIndex(index) |
695 | local spec = self.spec_enterable |
696 | |
697 | if spec.activeCamera ~= nil then |
698 | spec.activeCamera:onDeactivate() |
699 | end |
700 | spec.camIndex = index |
701 | if spec.camIndex > spec.numCameras then |
702 | spec.camIndex = 1 |
703 | end |
704 | local activeCamera = spec.cameras[spec.camIndex] |
705 | spec.activeCamera = activeCamera |
706 | activeCamera:onActivate() |
707 | |
708 | g_soundManager:setIsIndoor(not activeCamera.useOutdoorSounds) |
709 | self:setMirrorVisible(activeCamera.useMirror) |
710 | |
711 | if activeCamera.isInside then |
712 | g_depthOfFieldManager:setManipulatedParams(nil, 0.6, nil, nil, nil) |
713 | else |
714 | g_depthOfFieldManager:reset() |
715 | end |
716 | |
717 | SpecializationUtil.raiseEvent(self, "onCameraChanged", activeCamera, spec.camIndex) |
718 | end |
setIsTabbable
DescriptionDefinitionsetIsTabbable()Code
1065 | function Enterable:setIsTabbable(isTabbable) |
1066 | self.spec_enterable.isTabbable = isTabbable |
1067 | end |
setMirrorVisible
DescriptionDefinitionsetMirrorVisible()Code
1005 | function Enterable:setMirrorVisible(visible) |
1006 | local spec = self.spec_enterable |
1007 | |
1008 | if next(spec.mirrors) == nil then |
1009 | return |
1010 | end |
1011 | |
1012 | if visible then |
1013 | local numVisibleMirrors = 0 |
1014 | for _, mirror in pairs(spec.mirrors) do |
1015 | -- only use mirrors which are visible on screen |
1016 | if getIsInCameraFrustum(mirror.node, spec.activeCamera.cameraNode, g_presentedScreenAspectRatio) then |
1017 | -- calculate angle between mirror and camera |
1018 | --local dirX, dirY, dirZ = worldToLocal(spec.activeCamera.cameraNode, getWorldTranslation(mirror.node)) |
1019 | local dirX, dirY, dirZ = localToLocal(spec.activeCamera.cameraNode, mirror.node, 0,0,0) |
1020 | |
1021 | dirY = dirY * g_screenAspectRatio |
1022 | local length = MathUtil.vector3Length(dirX, dirY, dirZ) |
1023 | mirror.cosAngle = -dirZ / length |
1024 | else |
1025 | mirror.cosAngle = math.huge |
1026 | end |
1027 | end |
1028 | |
1029 | -- sort mirrors based on prio and angle |
1030 | table.sort(spec.mirrors, |
1031 | function(mirror1, mirror2) |
1032 | if mirror1.prio == mirror2.prio then |
1033 | -- the bigger cosAngle, the smaller the angle to the z-axis |
1034 | return mirror1.cosAngle > mirror2.cosAngle |
1035 | else |
1036 | return mirror1.prio < mirror2.prio |
1037 | end |
1038 | end) |
1039 | |
1040 | local maxNumMirrors = g_gameSettings:getValue("maxNumMirrors") |
1041 | -- show first mirrors within the limit |
1042 | for _, mirror in ipairs(spec.mirrors) do |
1043 | if mirror.cosAngle ~= math.huge and numVisibleMirrors < maxNumMirrors then |
1044 | setVisibility(mirror.node, true) |
1045 | numVisibleMirrors = numVisibleMirrors + 1 |
1046 | else |
1047 | setVisibility(mirror.node, false) |
1048 | end |
1049 | end |
1050 | else |
1051 | for _, mirror in pairs(spec.mirrors) do |
1052 | setVisibility(mirror.node, false) |
1053 | end |
1054 | end |
1055 | end |
setRandomVehicleCharacter
DescriptionDefinitionsetRandomVehicleCharacter()Code
818 | function Enterable:setRandomVehicleCharacter() |
819 | local spec = self.spec_enterable |
820 | if spec.vehicleCharacter ~= nil then |
821 | local aiPlayerModelIndex = math.random(1, g_playerModelManager:getNumOfPlayerModels()) |
822 | local playerModel = g_playerModelManager:getPlayerModelByIndex(aiPlayerModelIndex) |
823 | |
824 | self:setVehicleCharacter(playerModel.xmlFilename, PlayerStyle:new()) |
825 | |
826 | -- get new player style since it is duplicated |
827 | local aiStyle = self:getCurrentPlayerStyle() |
828 | local oldStyle = self:getUserPlayerStyle() |
829 | |
830 | -- get random body that is not equal with the current one if the same model is selected |
831 | local numOfBodys = #aiStyle.bodies |
832 | local aiBodyIndex = math.random(1, numOfBodys) |
833 | if oldStyle ~= nil then |
834 | if aiStyle.selectedModelIndex == oldStyle.selectedModelIndex then |
835 | local oldBodyIndex = oldStyle.selectedBodyIndex |
836 | if numOfBodys > 1 then |
837 | while aiBodyIndex == oldBodyIndex do |
838 | aiBodyIndex = math.random(1, numOfBodys) |
839 | end |
840 | end |
841 | end |
842 | end |
843 | aiStyle:setBody(aiBodyIndex) |
844 | |
845 | aiStyle:setColor(math.random(1, #g_playerColors)) |
846 | aiStyle:setHair(math.random(1, #aiStyle.hairs.styles)) |
847 | aiStyle:setJacket(math.random(0, #aiStyle.jackets)) |
848 | end |
849 | end |
setVehicleCharacter
DescriptionDefinitionsetVehicleCharacter()Code
802 | function Enterable:setVehicleCharacter(xmlFilename, playerStyle) |
803 | local spec = self.spec_enterable |
804 | if spec.vehicleCharacter ~= nil then |
805 | spec.vehicleCharacter:delete() |
806 | spec.vehicleCharacter:loadCharacter(xmlFilename, playerStyle) |
807 | spec.vehicleCharacter:updateVisibility() |
808 | spec.vehicleCharacter:updateIKChains() |
809 | |
810 | spec.additionalCharacterActive = false |
811 | end |
812 | |
813 | SpecializationUtil.raiseEvent(self, "onVehicleCharacterChanged", spec.vehicleCharacter) |
814 | end |
updateCharacterTargetNodeModifier
DescriptionDefinitionupdateCharacterTargetNodeModifier()Code
475 | function Enterable:updateCharacterTargetNodeModifier(dt, modifier) |
476 | local node = modifier.parent |
477 | local poseId = modifier.poseId |
478 | for _,state in pairs(modifier.states) do |
479 | -- check if the rotation is different than the rotation on loading |
480 | local x, y, z = getRotation(state.referenceNode) |
481 | local refX, refY, refZ = unpack(state.defaultRotation) |
482 | |
483 | if math.abs(x-refX) + math.abs(y-refY) + math.abs(z-refZ) > 0.001 then |
484 | node = state.node |
485 | poseId = state.poseId or poseId |
486 | end |
487 | |
488 | -- check if the translation is different than the translation on loading |
489 | x, y, z = getTranslation(state.referenceNode) |
490 | refX, refY, refZ = unpack(state.defaultTranslation) |
491 | |
492 | if math.abs(x-refX) + math.abs(y-refY) + math.abs(z-refZ) > 0.001 then |
493 | node = state.node |
494 | poseId = state.poseId or poseId |
495 | end |
496 | |
497 | -- align the target node to the direction reference node |
498 | if node == state.node and state.directionReferenceNode ~= nil then |
499 | local wx, wy, wz = getWorldTranslation(state.directionReferenceNode) |
500 | local lx, ly, lz = getTranslation(state.node) |
501 | local dx, dy, dz = worldToLocal(getParent(state.node), wx, wy, wz) |
502 | setDirection(state.node, dx-lx, dy-ly, dz-lz, 0, 1, 0) |
503 | end |
504 | end |
505 | |
506 | local isDirty = modifier.transitionAlpha < 1 |
507 | local allowSwitch = node ~= modifier.parent |
508 | |
509 | if not allowSwitch then |
510 | modifier.transitionIdleTime = modifier.transitionIdleTime + dt |
511 | |
512 | if modifier.transitionIdleTime > modifier.transitionIdleDelay then |
513 | allowSwitch = true |
514 | modifier.transitionIdleTime = 0 |
515 | end |
516 | end |
517 | |
518 | if allowSwitch and getParent(modifier.node) ~= node then |
519 | local transStartPos = {localToLocal(modifier.node, node, 0,0,0)} |
520 | local transEndPos = {0, 0, 0} |
521 | if node == modifier.parent then |
522 | transEndPos = modifier.translationOffset |
523 | end |
524 | modifier.transitionStartPos = transStartPos |
525 | modifier.transitionEndPos = transEndPos |
526 | |
527 | 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 |
528 | modifier.transitionAlpha = 1.0 |
529 | else |
530 | modifier.transitionAlpha = 0 |
531 | end |
532 | |
533 | isDirty = true |
534 | |
535 | local rx,ry,rz = localRotationToLocal(getParent(modifier.node), node, 0,0,0) |
536 | modifier.transitionStartQuat = {mathEulerToQuaternion(rx, ry, rz)} |
537 | modifier.transitionEndQuat = {0, 0, 0, 1} |
538 | if node == modifier.parent then |
539 | modifier.transitionEndQuat = {mathEulerToQuaternion(unpack(modifier.rotationOffset))} |
540 | end |
541 | |
542 | link(node, modifier.node) |
543 | |
544 | if poseId ~= nil then |
545 | local character = self:getVehicleCharacter() |
546 | if character ~= nil then |
547 | local chain = IKUtil.getIKChainByTarget(character.ikChains, modifier.node) |
548 | if chain ~= nil then |
549 | IKUtil.setIKChainPose(character.ikChains, chain.id, poseId) |
550 | end |
551 | end |
552 | end |
553 | end |
554 | |
555 | if isDirty then |
556 | modifier.transitionAlpha = math.min(1.0, modifier.transitionAlpha + (dt/modifier.transitionTime)) |
557 | |
558 | local x,y,z = MathUtil.vector3ArrayLerp(modifier.transitionStartPos, modifier.transitionEndPos, modifier.transitionAlpha) |
559 | setTranslation(modifier.node, x,y,z) |
560 | |
561 | local qx,qy,qz,qw = MathUtil.slerpQuaternionShortestPath(modifier.transitionStartQuat[1], modifier.transitionStartQuat[2], modifier.transitionStartQuat[3], modifier.transitionStartQuat[4], |
562 | modifier.transitionEndQuat[1], modifier.transitionEndQuat[2], modifier.transitionEndQuat[3], modifier.transitionEndQuat[4], |
563 | modifier.transitionAlpha) |
564 | setQuaternion(modifier.node, qx,qy,qz,qw) |
565 | end |
566 | end |