Script v1_7_1_0
- AI
- Animals
- Collections
- Contracts
- Debug
- Economy
- Elements
- EnvironmentalScore
- Errors
- Events
- GUI
- Handtools
- Hud
- I3d
- Input
- Jobs
- Maps
- Materials
- Misc
- Objects
- Parameters
- Placeables
- Placement
- Player
- Shop
- Sounds
- Specialization
- Specializations
- AIConveyorBelt
- AIDrivable
- AIFieldWorker
- AIImplement
- AIJobVehicle
- AIVehicle
- AIVehicleObstacle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- AutoLoader
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BigBag
- BunkerSiloCompacter
- BunkerSiloInteractor
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- CropSensor
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- ExtendedAIVehicle
- ExtendedCombine
- ExtendedMotorized
- ExtendedMower
- ExtendedSowingMachine
- ExtendedSprayer
- ExtendedWearable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- HeadlandAnimation
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- InlineWrapper
- JigglingParts
- Leveler
- LicensePlates
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- ManureSensor
- MixerWagon
- Motorized
- Mountable
- Mower
- Mulcher
- MultipleItemPurchase
- Pallet
- Pickup
- Pipe
- PlaceableAI
- PlaceableAnimatedObjects
- PlaceableBeehive
- PlaceableBeehivePalletSpa...
- PlaceableBunkerSilo
- PlaceableBuyingStation
- PlaceableCartridgePlayer
- PlaceableChargingStation
- PlaceableClearAreas
- PlaceableColorable
- PlaceableDeletedNodes
- PlaceableDoghouse
- PlaceableDynamicallyLoade...
- PlaceableFarmhouse
- PlaceableFence
- PlaceableFoliageAreas
- PlaceableGreenhouse
- PlaceableHighPressureWash...
- PlaceableHotspots
- PlaceableHusbandry
- PlaceableHusbandryAnimals
- PlaceableHusbandryFeeding...
- PlaceableHusbandryFence
- PlaceableHusbandryFood
- PlaceableHusbandryLiquidM...
- PlaceableHusbandryMilk
- PlaceableHusbandryPallets
- PlaceableHusbandryStraw
- PlaceableHusbandryWater
- PlaceableIncomePerHour
- PlaceableIndoorAreas
- PlaceableInfoTrigger
- PlaceableLeveling
- PlaceableLights
- PlaceableManureHeap
- PlaceablePlacement
- PlaceableProductionPoint
- PlaceableSellingStation
- PlaceableSilo
- PlaceableSiloExtension
- PlaceableSolarPanels
- PlaceableTipOcclusionArea...
- PlaceableTrainSystem
- PlaceableTriggerMarkers
- PlaceableVine
- PlaceableWardrobe
- PlaceableWeatherStation
- PlaceableWeighingStation
- PlaceableWindTurbine
- PlaceableWorkshop
- Plow
- PlowPacker
- PowerConsumer
- PowerTakeOffs
- PrecisionFarmingStatistic
- PushHandTool
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- RTKStation
- SaltSpreader
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SoilSampler
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StonePicker
- StrawBlower
- StumpCutter
- SupportVehicle
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TestAreas
- TipOccluder
- Trailer
- TreePlanter
- TreeSaplingPallet
- TreeSaw
- TurnOnVehicle
- VariableWorkWidth
- VehicleSettings
- VineCutter
- VineDetector
- VinePrepruner
- Washable
- WaterTrailer
- Wearable
- Weeder
- WeedSpotSpray
- Wheels
- WindBending
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- StateMachine
- Statistics
- Tasks
- Triggers
- Utils
- Vehicles
Engine v1_7_1_0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- general
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- NoteNode
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- VoiceChat
- XML
Foundation Reference
Enterable
DescriptionThis specialization enables the player to enter a vehicle. It also loads cameras and player characterFunctions
- actionEventCameraSwitch
- actionEventCameraZoomIn
- actionEventCameraZoomOut
- actionEventLeave
- actionEventResetHeadTracking
- addToolCameras
- deleteVehicleCharacter
- doLeaveVehicle
- enterVehicle
- getActiveCamera
- getActiveFarm
- getAllowCharacterVisibilityUpdate
- getCanToggleAttach
- getCanToggleSelectable
- getControllerName
- getCurrentPlayerStyle
- getDisableVehicleCharacterOnLeave
- getDistanceToNode
- getExitNode
- getFormattedOperatingTime
- getInteractionHelp
- getIsActive
- getIsActiveForInput
- getIsAdditionalCharacterActive
- getIsControlled
- getIsDashboardGroupActive
- getIsEnterable
- getIsEnterableFromMenu
- getIsEntered
- getIsInUse
- getIsMapHotspotVisible
- getIsTabbable
- getUserPlayerStyle
- getVehicleCharacter
- initSpecialization
- interact
- leaveVehicle
- loadAdditionalCharacterFromXML
- loadCamerasFromXML
- loadCharacterTargetNodeModifier
- loadDashboardGroupFromXML
- loadExtraDependentParts
- mountDynamic
- onDelete
- onDrawUIInfo
- onLoad
- onLoadFinished
- onPlayerStyleChanged
- onPostLoad
- onPostUpdate
- onPreLoad
- onReadStream
- onRegisterActionEvents
- onSetBroken
- onUpdate
- onWriteStream
- prerequisitesPresent
- registerEventListeners
- registerEvents
- registerFunctions
- registerOverwrittenFunctions
- removeToolCameras
- resetCharacterTargetNodeStateDefaults
- restoreVehicleCharacter
- saveStatsToXMLFile
- saveToXMLFile
- setActiveCameraIndex
- setCharacterTargetNodeStateDirty
- setIsTabbable
- setMirrorVisible
- setRandomVehicleCharacter
- setVehicleCharacter
- updateCharacterTargetNodeModifier
- updateExtraDependentParts
- vehicleCharacterLoaded
actionEventCameraSwitch
DescriptionDefinitionactionEventCameraSwitch()Code
1548 | function Enterable.actionEventCameraSwitch(self, actionName, inputValue, callbackState, isAnalog) |
1549 | local spec = self.spec_enterable |
1550 | self:setActiveCameraIndex(spec.camIndex + 1) |
1551 | end |
actionEventCameraZoomIn
DescriptionDefinitionactionEventCameraZoomIn()Code
1555 | function 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) |
1563 | end |
actionEventCameraZoomOut
DescriptionDefinitionactionEventCameraZoomOut()Code
1567 | function 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) |
1575 | end |
actionEventLeave
DescriptionDefinitionactionEventLeave()Code
1542 | function Enterable.actionEventLeave(self, actionName, inputValue, callbackState, isAnalog) |
1543 | self:doLeaveVehicle() |
1544 | end |
actionEventResetHeadTracking
DescriptionDefinitionactionEventResetHeadTracking()Code
1579 | function Enterable.actionEventResetHeadTracking(self, actionName, inputValue, callbackState, isAnalog) |
1580 | centerHeadTracking() |
1581 | end |
addToolCameras
DescriptionAdd cameras from toolDefinition
addToolCameras(table cameras)Arguments
table | cameras | cameras to add |
1002 | function 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 |
1009 | end |
deleteVehicleCharacter
DescriptionDefinitiondeleteVehicleCharacter()Code
1137 | function 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) |
1143 | end |
doLeaveVehicle
DescriptionDefinitiondoLeaveVehicle()Code
880 | function Enterable:doLeaveVehicle() |
881 | local spec = self.spec_enterable |
882 | if spec.isEntered then |
883 | g_currentMission:onLeaveVehicle() |
884 | end |
885 | 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 |
808 | function 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() |
876 | end |
getActiveCamera
DescriptionDefinitiongetActiveCamera()Code
1363 | function Enterable:getActiveCamera() |
1364 | return self.spec_enterable.activeCamera |
1365 | end |
getActiveFarm
DescriptionDefinitiongetActiveFarm()Code
1405 | function 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 |
1414 | end |
getAllowCharacterVisibilityUpdate
DescriptionDefinitiongetAllowCharacterVisibilityUpdate()Code
1375 | function Enterable:getAllowCharacterVisibilityUpdate() |
1376 | return true |
1377 | end |
getCanToggleAttach
DescriptionDefinitiongetCanToggleAttach()Code
1396 | function Enterable:getCanToggleAttach(superFunc) |
1397 | if not self:getIsEntered() then |
1398 | return false |
1399 | end |
1400 | return superFunc(self) |
1401 | end |
getCanToggleSelectable
DescriptionDefinitiongetCanToggleSelectable()Code
1387 | function Enterable:getCanToggleSelectable(superFunc) |
1388 | if self:getIsEntered() then |
1389 | return true |
1390 | end |
1391 | return superFunc(self) |
1392 | end |
getControllerName
DescriptionDefinitiongetControllerName()Code
1345 | function 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() |
1359 | end |
getCurrentPlayerStyle
DescriptionDefinitiongetCurrentPlayerStyle()Code
1060 | function Enterable:getCurrentPlayerStyle() |
1061 | local spec = self.spec_enterable |
1062 | if spec.vehicleCharacter ~= nil then |
1063 | return spec.vehicleCharacter:getPlayerStyle() |
1064 | end |
1065 | end |
getDisableVehicleCharacterOnLeave
DescriptionDefinitiongetDisableVehicleCharacterOnLeave()Code
1381 | function Enterable:getDisableVehicleCharacterOnLeave() |
1382 | return self.spec_enterable.disableCharacterOnLeave |
1383 | end |
getDistanceToNode
DescriptionReturns distance between given object and enterReferenceNodeDefinition
getDistanceToNode(integer object)Arguments
integer | object | id of object |
float | distance | distance |
1208 | function 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 |
1227 | end |
getExitNode
DescriptionDefinitiongetExitNode()Code
1047 | function Enterable:getExitNode() |
1048 | local spec = self.spec_enterable |
1049 | return spec.exitPoint |
1050 | end |
getFormattedOperatingTime
DescriptionDefinitiongetFormattedOperatingTime()Code
1147 | function 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) |
1154 | end |
getInteractionHelp
DescriptionReturns interaction help textDefinition
getInteractionHelp()Return Values
string | text | text |
1232 | function 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 |
1238 | end |
getIsActive
DescriptionDefinitiongetIsActive()Code
1158 | function 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 |
1165 | end |
getIsActiveForInput
DescriptionDefinitiongetIsActiveForInput()Code
1169 | function 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 |
1202 | end |
getIsAdditionalCharacterActive
DescriptionDefinitiongetIsAdditionalCharacterActive()Code
615 | function Enterable:getIsAdditionalCharacterActive() |
616 | return false |
617 | end |
getIsControlled
DescriptionDefinitiongetIsControlled()Code
1339 | function Enterable:getIsControlled() |
1340 | return self.spec_enterable.isControlled |
1341 | end |
getIsDashboardGroupActive
DescriptionDefinitiongetIsDashboardGroupActive()Code
1430 | function 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) |
1438 | end |
getIsEnterable
DescriptionGet whether current player can enter this vehicle Only works when isClientDefinition
getIsEnterable()Code
1319 | function 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) |
1322 | end |
getIsEnterableFromMenu
DescriptionGet whether current player can enter this vehicle from menu Only works when isClientDefinition
getIsEnterableFromMenu()Code
1327 | function Enterable:getIsEnterableFromMenu() |
1328 | return self:getIsEnterable() and self.spec_enterable.canBeEnteredFromMenu |
1329 | end |
getIsEntered
DescriptionDefinitiongetIsEntered()Code
1333 | function Enterable:getIsEntered() |
1334 | return self.spec_enterable.isEntered |
1335 | end |
getIsInUse
DescriptionDefinitiongetIsInUse()Code
1454 | function 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) |
1461 | end |
getIsMapHotspotVisible
DescriptionDefinitiongetIsMapHotspotVisible()Code
958 | function Enterable:getIsMapHotspotVisible(superFunc) |
959 | if not superFunc(self) then |
960 | return false |
961 | end |
962 | |
963 | return not self.spec_enterable.isEntered |
964 | end |
getIsTabbable
DescriptionDefinitiongetIsTabbable()Code
1306 | function Enterable:getIsTabbable() |
1307 | return self.spec_enterable.isTabbable |
1308 | end |
getUserPlayerStyle
DescriptionDefinitiongetUserPlayerStyle()Code
1054 | function Enterable:getUserPlayerStyle() |
1055 | return self.spec_enterable.playerStyle |
1056 | end |
getVehicleCharacter
DescriptionDefinitiongetVehicleCharacter()Code
1369 | function Enterable:getVehicleCharacter() |
1370 | return self.spec_enterable.vehicleCharacter |
1371 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
25 | function 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) |
79 | end |
interact
DescriptionInteractDefinition
interact()Code
1242 | function Enterable:interact(superFunc) |
1243 | if self.interactionFlag == Vehicle.INTERACTION_FLAG_ENTERABLE then |
1244 | g_currentMission:requestToEnterVehicle(self) |
1245 | else |
1246 | superFunc(self) |
1247 | end |
1248 | end |
leaveVehicle
DescriptionLeave vehicleDefinition
leaveVehicle()Code
889 | function 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 |
954 | end |
loadAdditionalCharacterFromXML
DescriptionDefinitionloadAdditionalCharacterFromXML()Code
600 | function 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 |
611 | end |
loadCamerasFromXML
DescriptionDefinitionloadCamerasFromXML()Code
573 | function 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 |
596 | end |
loadCharacterTargetNodeModifier
DescriptionDefinitionloadCharacterTargetNodeModifier()Code
621 | function 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 |
680 | end |
loadDashboardGroupFromXML
DescriptionDefinitionloadDashboardGroupFromXML()Code
1418 | function 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 |
1426 | end |
loadExtraDependentParts
DescriptionDefinitionloadExtraDependentParts()Code
1465 | function 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 |
1473 | end |
mountDynamic
DescriptionDefinitionmountDynamic()Code
1442 | function 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) |
1450 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
374 | function 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) |
399 | end |
onDrawUIInfo
DescriptionCalled on ui info draw, renders nicknames in multiplayerDefinition
onDrawUIInfo()Code
553 | function 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 |
569 | end |
onLoad
DescriptionDefinitiononLoad()Code
175 | function 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) |
346 | end |
onLoadFinished
DescriptionDefinitiononLoadFinished()Code
364 | function 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 |
370 | end |
onPlayerStyleChanged
DescriptionDefinitiononPlayerStyleChanged()Code
1095 | function 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 |
1104 | end |
onPostLoad
DescriptionDefinitiononPostLoad()Code
350 | function 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 |
360 | 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 |
519 | function 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 |
549 | end |
onPreLoad
DescriptionDefinitiononPreLoad()Code
169 | function Enterable:onPreLoad(savegame) |
170 | Vehicle.registerInteractionFlag("Enterable") |
171 | end |
onReadStream
DescriptionCalled on client side on joinDefinition
onReadStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
405 | function 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 |
414 | end |
onRegisterActionEvents
DescriptionDefinitiononRegisterActionEvents()Code
1487 | function 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 |
1529 | end |
onSetBroken
DescriptionDefinitiononSetBroken()Code
1533 | function Enterable:onSetBroken() |
1534 | local spec = self.spec_enterable |
1535 | if spec.isEntered then |
1536 | g_currentMission:onLeaveVehicle() |
1537 | end |
1538 | 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 |
459 | function 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 |
512 | end |
onWriteStream
DescriptionCalled on server side on joinDefinition
onWriteStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
420 | function 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 |
427 | end |
prerequisitesPresent
DescriptionDefinitionprerequisitesPresent()Code
19 | function Enterable.prerequisitesPresent(specializations) |
20 | return true |
21 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
152 | function 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) |
165 | end |
registerEvents
DescriptionDefinitionregisterEvents()Code
83 | function Enterable.registerEvents(vehicleType) |
84 | SpecializationUtil.registerEvent(vehicleType, "onEnterVehicle") |
85 | SpecializationUtil.registerEvent(vehicleType, "onLeaveVehicle") |
86 | SpecializationUtil.registerEvent(vehicleType, "onCameraChanged") |
87 | SpecializationUtil.registerEvent(vehicleType, "onVehicleCharacterChanged") |
88 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
92 | function 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) |
128 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
132 | function 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) |
148 | end |
removeToolCameras
DescriptionRemove cameras from toolDefinition
removeToolCameras(table cameras)Arguments
table | cameras | cameras to remove |
1014 | function 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 |
1043 | end |
resetCharacterTargetNodeStateDefaults
DescriptionDefinitionresetCharacterTargetNodeStateDefaults()Code
791 | function 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 |
801 | end |
restoreVehicleCharacter
DescriptionDefinitionrestoreVehicleCharacter()Code
1124 | function 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 |
1133 | end |
saveStatsToXMLFile
DescriptionReturns string with name of controller for game stats xmlDefinition
saveStatsToXMLFile()Return Values
string | statesAttributes | states attributes |
443 | function 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 |
452 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
431 | function 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) |
438 | end |
setActiveCameraIndex
DescriptionChange active camera indexDefinition
setActiveCameraIndex(integer index)Arguments
integer | index | index of camera to set |
969 | function 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) |
997 | end |
setCharacterTargetNodeStateDirty
DescriptionDefinitionsetCharacterTargetNodeStateDirty()Code
763 | function 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 |
787 | end |
setIsTabbable
DescriptionDefinitionsetIsTabbable()Code
1312 | function Enterable:setIsTabbable(isTabbable) |
1313 | self.spec_enterable.isTabbable = isTabbable |
1314 | end |
setMirrorVisible
DescriptionDefinitionsetMirrorVisible()Code
1252 | function 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 |
1302 | end |
setRandomVehicleCharacter
DescriptionDefinitionsetRandomVehicleCharacter()Code
1108 | function 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 |
1120 | end |
setVehicleCharacter
DescriptionDefinitionsetVehicleCharacter()Code
1069 | function 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 |
1077 | end |
updateCharacterTargetNodeModifier
DescriptionDefinitionupdateCharacterTargetNodeModifier()Code
684 | function 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 |
759 | end |
updateExtraDependentParts
DescriptionDefinitionupdateExtraDependentParts()Code
1477 | function Enterable:updateExtraDependentParts(superFunc, part, dt) |
1478 | superFunc(self, part, dt) |
1479 | |
1480 | if part.updateCharacterTargetModifier then |
1481 | self:setCharacterTargetNodeStateDirty(part.node, false) |
1482 | end |
1483 | end |
vehicleCharacterLoaded
DescriptionDefinitionvehicleCharacterLoaded()Code
1081 | function 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) |
1091 | end |