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
AttacherJoints
DescriptionSpecialization for vehicles with attacherJoints allowing attaching/coupling of toolsFunctions
- actionEventAttach
- actionEventDetach
- actionEventLowerAllImplements
- actionEventLowerImplement
- activateAttachments
- addChildVehicles
- additionalAttachmentLoaded
- addToPhysics
- addVehicleToAIImplementList
- attachableAddToolCameras
- attachableRemoveToolCameras
- attachAdditionalAttachment
- attachImplementFromInfo
- calculateAttacherJointMoveUpperLowerAlpha
- callFunctionOnAllImplements
- collectAIAgentAttachments
- createAttachmentJoint
- deactivateAttachments
- deactivateAttachmentsLights
- detachAdditionalAttachment
- detachAttachedImplement
- detachImplement
- detachImplementByObject
- detachingIsPossible
- doGroundHeightNodeCheck
- findVehicleInAttachRange
- finishGroundHeightNodeCheck
- getAirConsumerUsage
- getAreControlledActionsAllowed
- getAttachedImplements
- getAttacherJointByJointDescIndex
- getAttacherJointCompatibility
- getAttacherJointDescFromObject
- getAttacherJointIndexByNode
- getAttacherJointIndexFromImplementIndex
- getAttacherJointIndexFromObject
- getAttacherJoints
- getCanSteerAttachable
- getCanToggleAttach
- getConnectionHoseConfigIndex
- getDirectionSnapAngle
- getFillLevelInformation
- getImplementByJointDescIndex
- getImplementByObject
- getImplementFromAttacherJointIndex
- getImplementIndexByJointDescIndex
- getImplementIndexByObject
- getIsAttacherJointHeightNodeActive
- getIsAttachingAllowed
- getIsAutomaticShiftingAllowed
- getIsDashboardGroupActive
- getIsFoldAllowed
- getIsHardAttachAllowed
- getIsReadyForAutomatedTrainTravel
- getIsWheelFoliageDestructionAllowed
- getJointMoveDown
- getObjectFromImplementIndex
- getPowerTakeOffConfigIndex
- getSelectedImplement
- getShowDetachAttachedImplement
- getTotalMass
- groundHeightNodeCheckCallback
- handleLowerImplementByAttacherJointIndex
- handleLowerImplementEvent
- hardAttachImplement
- hardDetachImplement
- initSpecialization
- isDetachAllowed
- loadAttacherJointFromXML
- loadAttacherJointHeightNode
- loadAttachmentsFinished
- loadAttachmentsFromXMLFile
- loadDashboardGroupFromXML
- onActivate
- onBeaconLightsVisibilityChanged
- onBottomArmToolbarI3DLoaded
- onBrake
- onBrakeLightsVisibilityChanged
- onDeactivate
- onDelete
- onLeaveVehicle
- onLightsTypesMaskChanged
- onLoad
- onPostLoad
- onPostUpdate
- onPreDelete
- onPreLoad
- onReadStream
- onRegisterActionEvents
- onReverseDirectionChanged
- onReverseLightsVisibilityChanged
- onStateChange
- onTopArmI3DLoaded
- onTurnedOff
- onTurnedOn
- onTurnLightStateChanged
- onUpdate
- onUpdateEnd
- onUpdateTick
- onWriteStream
- playAttachSound
- playDetachSound
- postAttachImplement
- prerequisitesPresent
- raiseActive
- registerActionEvents
- registerAttacherJointXMLPaths
- registerEventListeners
- registerEvents
- registerFunctions
- registerJointType
- registerOverwrittenFunctions
- registerSelectableObjects
- registerSelfLoweringActionEvent
- removeActionEvents
- removeFromPhysics
- saveAttachmentsToXMLFile
- saveToXMLFile
- setAIVehicleObstacleStateDirty
- setJointMoveDown
- setSelectedImplementByObject
- startAttacherJointCombo
- updateActionEvents
- updateAttacherJointGraphics
- updateAttacherJointLimits
- updateAttacherJointRotation
- updateAttacherJointRotationLimit
- updateAttacherJointRotationNodes
- updateAttacherJointSettingsByObject
- updateAttacherJointTranslationLimit
- updateVehiclesInAttachRange
actionEventAttach
DescriptionDefinitionactionEventAttach()Code
4247 | function AttacherJoints.actionEventAttach(self, actionName, inputValue, callbackState, isAnalog) |
4248 | -- attach or detach something |
4249 | local info = self.spec_attacherJoints.attachableInfo |
4250 | if info.attachable ~= nil then |
4251 | -- attach |
4252 | local attachAllowed, warning = info.attachable:isAttachAllowed(self:getActiveFarm(), info.attacherVehicle) |
4253 | if attachAllowed then |
4254 | if self.isServer then |
4255 | self:attachImplementFromInfo(info) |
4256 | else |
4257 | g_client:getServerConnection():sendEvent(VehicleAttachRequestEvent.new(info)) |
4258 | end |
4259 | else |
4260 | if warning ~= nil then |
4261 | g_currentMission:showBlinkingWarning(warning, 2000) |
4262 | end |
4263 | end |
4264 | else |
4265 | -- detach |
4266 | local object = self:getSelectedVehicle() |
4267 | if object ~= nil and object ~= self and object.isDetachAllowed ~= nil then |
4268 | local detachAllowed, warning, showWarning = object:isDetachAllowed() |
4269 | if detachAllowed then |
4270 | object:startDetachProcess() |
4271 | elseif showWarning == nil or showWarning then |
4272 | g_currentMission:showBlinkingWarning(warning or self.spec_attacherJoints.texts.detachNotAllowed, 2000) |
4273 | end |
4274 | end |
4275 | end |
4276 | end |
actionEventDetach
DescriptionDefinitionactionEventDetach()Code
4280 | function AttacherJoints.actionEventDetach(self, actionName, inputValue, callbackState, isAnalog) |
4281 | -- detach |
4282 | local object = self:getSelectedVehicle() |
4283 | if object ~= nil and object ~= self and object.isDetachAllowed ~= nil then |
4284 | local detachAllowed, warning, showWarning = object:isDetachAllowed() |
4285 | if detachAllowed then |
4286 | object:startDetachProcess() |
4287 | elseif showWarning == nil or showWarning then |
4288 | g_currentMission:showBlinkingWarning(warning or self.spec_attacherJoints.texts.detachNotAllowed, 2000) |
4289 | end |
4290 | end |
4291 | end |
actionEventLowerAllImplements
DescriptionDefinitionactionEventLowerAllImplements()Code
4304 | function AttacherJoints.actionEventLowerAllImplements(self, actionName, inputValue, callbackState, isAnalog) |
4305 | self:startAttacherJointCombo(true) |
4306 | |
4307 | self.rootVehicle:raiseStateChange(Vehicle.STATE_CHANGE_LOWER_ALL_IMPLEMENTS) |
4308 | end |
actionEventLowerImplement
DescriptionDefinitionactionEventLowerImplement()Code
4295 | function AttacherJoints.actionEventLowerImplement(self, actionName, inputValue, callbackState, isAnalog) |
4296 | -- self is the implement object to lower, so we call the function on the attacher vehicle |
4297 | if self.getAttacherVehicle ~= nil then |
4298 | self:getAttacherVehicle():handleLowerImplementEvent() |
4299 | end |
4300 | end |
activateAttachments
DescriptionCall "activate" on all attachmentsDefinition
activateAttachments()Code
2758 | function AttacherJoints:activateAttachments() |
2759 | local spec = self.spec_attacherJoints |
2760 | |
2761 | for _,v in pairs(spec.attachedImplements) do |
2762 | if v.object ~= nil then |
2763 | v.object:activate() |
2764 | end |
2765 | end |
2766 | end |
addChildVehicles
DescriptionInserts all child vehicles into the given tableDefinition
addChildVehicles(table vehicles)Arguments
table | vehicles | child vehicles table |
3475 | function AttacherJoints:addChildVehicles(superFunc, vehicles) |
3476 | local spec = self.spec_attacherJoints |
3477 | |
3478 | for _, implement in pairs(spec.attachedImplements) do |
3479 | local object = implement.object |
3480 | if object ~= nil and object.addChildVehicles ~= nil then |
3481 | object:addChildVehicles(vehicles) |
3482 | end |
3483 | end |
3484 | |
3485 | return superFunc(self, vehicles) |
3486 | end |
additionalAttachmentLoaded
DescriptionCalled after the additional attachment was loadedDefinition
additionalAttachmentLoaded()Code
2654 | function AttacherJoints:additionalAttachmentLoaded(vehicle, vehicleLoadState, asyncCallbackArguments) |
2655 | local offset = {0, 0, 0} |
2656 | if vehicle.getInputAttacherJoints ~= nil then |
2657 | local inputAttacherJoints = vehicle:getInputAttacherJoints() |
2658 | if inputAttacherJoints[asyncCallbackArguments[2]] ~= nil then |
2659 | offset = inputAttacherJoints[asyncCallbackArguments[2]].jointOrigOffsetComponent |
2660 | end |
2661 | end |
2662 | |
2663 | local x, y, z = localToWorld(asyncCallbackArguments[3], unpack(offset)) |
2664 | local dirX, _, dirZ = localDirectionToWorld(asyncCallbackArguments[3], 1, 0, 0) |
2665 | local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ) |
2666 | local terrainY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z) |
2667 | |
2668 | vehicle:setAbsolutePosition(x, math.max(y, terrainY + 0.05), z, 0, yRot, 0) |
2669 | self:attachImplement(vehicle, asyncCallbackArguments[2], asyncCallbackArguments[1], true, nil, nil, true) |
2670 | vehicle:setIsAdditionalAttachment(asyncCallbackArguments[4], true) |
2671 | if vehicle.addDirtAmount ~= nil and asyncCallbackArguments[5] ~= nil and asyncCallbackArguments[5].getDirtAmount ~= nil then |
2672 | vehicle:addDirtAmount(asyncCallbackArguments[5]:getDirtAmount()) |
2673 | end |
2674 | |
2675 | self.rootVehicle:updateSelectableObjects() |
2676 | self.rootVehicle:setSelectedVehicle(asyncCallbackArguments[5] or self) |
2677 | end |
addToPhysics
DescriptionAdd to physicsDefinition
addToPhysics()Return Values
boolean | success | success |
3413 | function AttacherJoints:addToPhysics(superFunc) |
3414 | local spec = self.spec_attacherJoints |
3415 | |
3416 | if not superFunc(self) then |
3417 | return false |
3418 | end |
3419 | |
3420 | for _, implement in pairs(spec.attachedImplements) do |
3421 | if not implement.object.spec_attachable.isHardAttached then |
3422 | self:createAttachmentJoint(implement) |
3423 | end |
3424 | end |
3425 | |
3426 | return true |
3427 | end |
addVehicleToAIImplementList
DescriptionDefinitionaddVehicleToAIImplementList()Code
3507 | function AttacherJoints:addVehicleToAIImplementList(superFunc, list) |
3508 | superFunc(self, list) |
3509 | |
3510 | for _, implement in pairs(self:getAttachedImplements()) do |
3511 | local object = implement.object |
3512 | if object ~= nil and object.addVehicleToAIImplementList ~= nil then |
3513 | object:addVehicleToAIImplementList(list) |
3514 | end |
3515 | end |
3516 | end |
attachableAddToolCameras
DescriptionDefinitionattachableAddToolCameras()Code
3578 | function AttacherJoints:attachableAddToolCameras(superFunc) |
3579 | local spec = self.spec_attacherJoints |
3580 | superFunc(self) |
3581 | |
3582 | for _,implement in pairs(spec.attachedImplements) do |
3583 | local object = implement.object |
3584 | if object ~= nil and object.attachableAddToolCameras ~= nil then |
3585 | object:attachableAddToolCameras() |
3586 | end |
3587 | end |
3588 | end |
attachableRemoveToolCameras
DescriptionDefinitionattachableRemoveToolCameras()Code
3592 | function AttacherJoints:attachableRemoveToolCameras(superFunc) |
3593 | local spec = self.spec_attacherJoints |
3594 | superFunc(self) |
3595 | |
3596 | for _,implement in pairs(spec.attachedImplements) do |
3597 | local object = implement.object |
3598 | if object ~= nil and object.attachableRemoveToolCameras ~= nil then |
3599 | object:attachableRemoveToolCameras() |
3600 | end |
3601 | end |
3602 | end |
attachAdditionalAttachment
DescriptionCreates and attaches additional attachmentDefinition
attachAdditionalAttachment()Code
2592 | function AttacherJoints:attachAdditionalAttachment(jointDesc, inputJointDesc, object) |
2593 | if jointDesc.additionalAttachment.attacherJointDirection ~= nil and inputJointDesc.additionalAttachment.filename ~= nil then |
2594 | local storeItem = g_storeManager:getItemByXMLFilename(inputJointDesc.additionalAttachment.filename) |
2595 | if storeItem ~= nil then |
2596 | local targetDirection = -jointDesc.additionalAttachment.attacherJointDirection |
2597 | local attacherJoint, attacherJointIndex |
2598 | for index, attacherJointToCheck in ipairs(self:getAttacherJoints()) do |
2599 | if attacherJointToCheck.additionalAttachment.attacherJointDirection == targetDirection then |
2600 | if attacherJointToCheck.jointIndex ~= 0 then |
2601 | attacherJoint = nil |
2602 | break |
2603 | else |
2604 | if attacherJointToCheck.jointType == inputJointDesc.additionalAttachment.jointType then |
2605 | attacherJoint = attacherJointToCheck |
2606 | attacherJointIndex = index |
2607 | end |
2608 | end |
2609 | end |
2610 | end |
2611 | |
2612 | if attacherJoint ~= nil then |
2613 | local x, y, z = localToWorld(attacherJoint.jointTransform, 0, 0, 0) |
2614 | local dirX, _, dirZ = localDirectionToWorld(attacherJoint.jointTransform, 1, 0, 0) |
2615 | local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ) |
2616 | local location = {x=x, y=y, z=z, yRot=yRot} |
2617 | |
2618 | jointDesc.additionalAttachment.currentAttacherJointIndex = attacherJointIndex |
2619 | local asyncCallbackArguments = {attacherJointIndex, |
2620 | inputJointDesc.additionalAttachment.inputAttacherJointIndex, |
2621 | attacherJoint.jointTransform, |
2622 | inputJointDesc.additionalAttachment.needsLowering, |
2623 | object} |
2624 | |
2625 | local vehicle = VehicleLoadingUtil.loadVehicle(storeItem.xmlFilename, location, false, 0, Vehicle.PROPERTY_STATE_NONE, self:getActiveFarm(), {}, nil, AttacherJoints.additionalAttachmentLoaded, self, asyncCallbackArguments) |
2626 | if vehicle ~= nil and vehicle.setIsAdditionalAttachment ~= nil then |
2627 | vehicle:setIsAdditionalAttachment(inputJointDesc.additionalAttachment.needsLowering, false) |
2628 | else |
2629 | Logging.warning("Failed to load additional attachment '%s'.", storeItem.xmlFilename) |
2630 | end |
2631 | end |
2632 | end |
2633 | end |
2634 | end |
attachImplementFromInfo
DescriptionDefinitionattachImplementFromInfo()Code
1637 | function AttacherJoints:attachImplementFromInfo(info) |
1638 | if info.attachable ~= nil then |
1639 | local attacherJoints = info.attacherVehicle.spec_attacherJoints.attacherJoints |
1640 | if attacherJoints[info.attacherVehicleJointDescIndex].jointIndex == 0 and info.attachable.isAddedToMission then |
1641 | if info.attachable:getActiveInputAttacherJointDescIndex() ~= nil then |
1642 | if info.attachable:getAllowMultipleAttachments() then |
1643 | info.attachable:resolveMultipleAttachments() |
1644 | else |
1645 | return false |
1646 | end |
1647 | end |
1648 | |
1649 | -- do not allow multiple implements in the same direction for mobile |
1650 | if GS_IS_MOBILE_VERSION then |
1651 | local attacherJointDirection = attacherJoints[info.attacherVehicleJointDescIndex].additionalAttachment.attacherJointDirection |
1652 | if attacherJointDirection ~= nil then |
1653 | local attachedImplements = info.attacherVehicle:getAttachedImplements() |
1654 | for i=1, #attachedImplements do |
1655 | local jointDesc = attacherJoints[attachedImplements[i].jointDescIndex] |
1656 | |
1657 | if attacherJointDirection == jointDesc.additionalAttachment.attacherJointDirection then |
1658 | return false |
1659 | end |
1660 | end |
1661 | end |
1662 | end |
1663 | |
1664 | info.attacherVehicle:attachImplement(info.attachable, info.attachableJointDescIndex, info.attacherVehicleJointDescIndex) |
1665 | return true |
1666 | end |
1667 | end |
1668 | |
1669 | return false |
1670 | end |
calculateAttacherJointMoveUpperLowerAlpha
DescriptionCalculate move upper and lower alpha of attacher jointDefinition
calculateAttacherJointMoveUpperLowerAlpha(table jointDesc, table object, boolean initial)Arguments
table | jointDesc | joint desc of used attacher |
table | object | object of attached vehicle |
boolean | initial | initial call to reset |
1318 | function AttacherJoints:calculateAttacherJointMoveUpperLowerAlpha(jointDesc, object, initial) |
1319 | local objectAttacherJoint = object.spec_attachable.attacherJoint |
1320 | |
1321 | if jointDesc.allowsLowering then |
1322 | |
1323 | local lowerDistanceToGround = jointDesc.lowerDistanceToGround |
1324 | local upperDistanceToGround = jointDesc.upperDistanceToGround |
1325 | |
1326 | local upperAlpha |
1327 | local lowerAlpha |
1328 | |
1329 | if #objectAttacherJoint.heightNodes > 0 and jointDesc.rotationNode ~= nil then |
1330 | local checkData = self.spec_attacherJoints.groundHeightNodeCheckData |
1331 | if initial then |
1332 | checkData.heightNodes = objectAttacherJoint.heightNodes |
1333 | checkData.jointDesc = jointDesc |
1334 | checkData.objectAttacherJoint = objectAttacherJoint |
1335 | checkData.object = object |
1336 | checkData.index = -1 |
1337 | |
1338 | lowerDistanceToGround = jointDesc.lowerDistanceToGround |
1339 | upperDistanceToGround = jointDesc.upperDistanceToGround |
1340 | |
1341 | for i=1, #objectAttacherJoint.heightNodes do |
1342 | local heightNode = objectAttacherJoint.heightNodes[i] |
1343 | local offX, offY, offZ = localToLocal(heightNode.node, heightNode.attacherJointNode, 0, 0, 0) |
1344 | |
1345 | self:updateAttacherJointRotationNodes(jointDesc, 1) |
1346 | setRotation(jointDesc.jointTransform, unpack(jointDesc.jointOrigRot)) |
1347 | local _, y, _ = localToLocal(jointDesc.jointTransform, jointDesc.rootNode, 0, 0, 0) |
1348 | local delta = jointDesc.lowerDistanceToGround - y |
1349 | local _, hy, _ = localToLocal(jointDesc.jointTransform, jointDesc.rootNode, offX, offY, offZ) |
1350 | lowerDistanceToGround = hy + delta |
1351 | |
1352 | self:updateAttacherJointRotationNodes(jointDesc, 0) |
1353 | _, y, _ = localToLocal(jointDesc.jointTransform, jointDesc.rootNode, 0, 0, 0) |
1354 | delta = jointDesc.upperDistanceToGround - y |
1355 | _, hy, _ = localToLocal(jointDesc.jointTransform, jointDesc.rootNode, offX, offY, offZ) |
1356 | upperDistanceToGround = hy + delta |
1357 | end |
1358 | else |
1359 | if (jointDesc.moveAlpha or 0) > 0 then |
1360 | if checkData.index == -1 then |
1361 | checkData.index = 1 |
1362 | |
1363 | checkData.minDistance = math.huge |
1364 | checkData.hit = false |
1365 | self:doGroundHeightNodeCheck() |
1366 | end |
1367 | |
1368 | if checkData.isDirty then |
1369 | checkData.isDirty = false |
1370 | self:doGroundHeightNodeCheck() |
1371 | end |
1372 | |
1373 | if jointDesc.upperAlpha ~= nil and checkData.upperAlpha ~= nil then |
1374 | upperAlpha = jointDesc.upperAlpha * 0.9 + checkData.upperAlpha * 0.1 |
1375 | lowerAlpha = jointDesc.lowerAlpha * 0.9 + checkData.lowerAlpha * 0.1 |
1376 | else |
1377 | upperAlpha = checkData.upperAlpha |
1378 | lowerAlpha = checkData.lowerAlpha |
1379 | end |
1380 | else |
1381 | upperAlpha = jointDesc.upperAlpha |
1382 | lowerAlpha = jointDesc.lowerAlpha |
1383 | end |
1384 | end |
1385 | end |
1386 | |
1387 | upperAlpha = upperAlpha or MathUtil.clamp((objectAttacherJoint.upperDistanceToGround - upperDistanceToGround) / (lowerDistanceToGround - upperDistanceToGround), 0, 1) |
1388 | lowerAlpha = lowerAlpha or MathUtil.clamp((objectAttacherJoint.lowerDistanceToGround - upperDistanceToGround) / (lowerDistanceToGround - upperDistanceToGround), 0, 1) |
1389 | |
1390 | if initial then |
1391 | local checkData = self.spec_attacherJoints.groundHeightNodeCheckData |
1392 | checkData.upperAlpha = upperAlpha |
1393 | checkData.lowerAlpha = lowerAlpha |
1394 | end |
1395 | |
1396 | if objectAttacherJoint.allowsLowering and jointDesc.allowsLowering then |
1397 | return upperAlpha, lowerAlpha |
1398 | else |
1399 | if objectAttacherJoint.isDefaultLowered then |
1400 | return lowerAlpha,lowerAlpha |
1401 | else |
1402 | return upperAlpha,upperAlpha |
1403 | end |
1404 | end |
1405 | end |
1406 | |
1407 | if objectAttacherJoint.isDefaultLowered then |
1408 | return 1,1 |
1409 | else |
1410 | return 0,0 |
1411 | end |
1412 | end |
callFunctionOnAllImplements
DescriptionDefinitioncallFunctionOnAllImplements()Code
2745 | function AttacherJoints:callFunctionOnAllImplements(functionName, ...) |
2746 | for _, implement in pairs(self:getAttachedImplements()) do |
2747 | local vehicle = implement.object |
2748 | if vehicle ~= nil then |
2749 | if vehicle[functionName] ~= nil then |
2750 | vehicle[functionName](vehicle, ...) |
2751 | end |
2752 | end |
2753 | end |
2754 | end |
collectAIAgentAttachments
DescriptionDefinitioncollectAIAgentAttachments()Code
3520 | function AttacherJoints:collectAIAgentAttachments(superFunc, aiDrivableVehicle) |
3521 | superFunc(self, aiDrivableVehicle) |
3522 | |
3523 | for _, implement in pairs(self:getAttachedImplements()) do |
3524 | local object = implement.object |
3525 | if object ~= nil and object.collectAIAgentAttachments ~= nil then |
3526 | object:collectAIAgentAttachments(aiDrivableVehicle) |
3527 | aiDrivableVehicle:startNewAIAgentAttachmentChain() |
3528 | end |
3529 | end |
3530 | end |
createAttachmentJoint
DescriptionCreate attacher joint between vehicle and implementDefinition
createAttachmentJoint(table implement, boolean noSmoothAttach)Arguments
table | implement | implement to attach |
boolean | noSmoothAttach | dont use smooth attach |
1926 | function AttacherJoints:createAttachmentJoint(implement, noSmoothAttach) |
1927 | |
1928 | local spec = self.spec_attacherJoints |
1929 | local jointDesc = spec.attacherJoints[implement.jointDescIndex] |
1930 | local objectAttacherJoint = implement.object.spec_attachable.attacherJoint |
1931 | |
1932 | if self.isServer and objectAttacherJoint ~= nil then |
1933 | if (getRigidBodyType(jointDesc.rootNode) ~= RigidBodyType.DYNAMIC and getRigidBodyType(jointDesc.rootNode) ~= RigidBodyType.KINEMATIC) |
1934 | or (getRigidBodyType(objectAttacherJoint.rootNode) ~= RigidBodyType.DYNAMIC and getRigidBodyType(objectAttacherJoint.rootNode) ~= RigidBodyType.KINEMATIC) then |
1935 | return |
1936 | end |
1937 | |
1938 | local xNew = jointDesc.jointOrigTrans[1] + jointDesc.jointPositionOffset[1] |
1939 | local yNew = jointDesc.jointOrigTrans[2] + jointDesc.jointPositionOffset[2] |
1940 | local zNew = jointDesc.jointOrigTrans[3] + jointDesc.jointPositionOffset[3] |
1941 | |
1942 | -- transform offset position to world coord and to jointTransform coord to get position offset dependend on angle and position |
1943 | local x,y,z = localToWorld(getParent(jointDesc.jointTransform), xNew, yNew, zNew) |
1944 | local x1,y1,z1 = worldToLocal(jointDesc.jointTransform, x,y,z) |
1945 | |
1946 | -- move jointTransform to offset pos |
1947 | setTranslation(jointDesc.jointTransform, xNew, yNew, zNew) |
1948 | |
1949 | -- transform it to implement position and angle |
1950 | x,y,z = localToWorld(objectAttacherJoint.node,x1,y1,z1) |
1951 | local x2,y2,z2 = worldToLocal(getParent(objectAttacherJoint.node), x,y,z) |
1952 | setTranslation(objectAttacherJoint.node, x2,y2, z2) |
1953 | |
1954 | |
1955 | local constr = JointConstructor.new() |
1956 | constr:setActors(jointDesc.rootNode, objectAttacherJoint.rootNode) |
1957 | constr:setJointTransforms(jointDesc.jointTransform, objectAttacherJoint.node) |
1958 | --constr:setBreakable(20, 10) |
1959 | |
1960 | implement.jointRotLimit = {} |
1961 | implement.jointTransLimit = {} |
1962 | |
1963 | implement.lowerRotLimit = {} |
1964 | implement.lowerTransLimit = {} |
1965 | |
1966 | implement.upperRotLimit = {} |
1967 | implement.upperTransLimit = {} |
1968 | |
1969 | if noSmoothAttach == nil or not noSmoothAttach then |
1970 | local dx,dy,dz = localToLocal(objectAttacherJoint.node, jointDesc.jointTransform, 0,0,0) |
1971 | local _,y,z = localDirectionToLocal(objectAttacherJoint.node, jointDesc.jointTransform, 0,1,0) |
1972 | local rX = math.atan2(z,y) |
1973 | local x,_,z = localDirectionToLocal(objectAttacherJoint.node, jointDesc.jointTransform, 0,0,1) |
1974 | local rY = math.atan2(x,z) |
1975 | local x,y,_ = localDirectionToLocal(objectAttacherJoint.node, jointDesc.jointTransform, 1,0,0) |
1976 | local rZ = math.atan2(y,x) |
1977 | implement.attachingTransLimit = { math.abs(dx), math.abs(dy), math.abs(dz) } |
1978 | implement.attachingRotLimit = { math.abs(rX), math.abs(rY), math.abs(rZ) } |
1979 | implement.attachingTransLimitSpeed = {} |
1980 | implement.attachingRotLimitSpeed = {} |
1981 | for i=1,3 do |
1982 | implement.attachingTransLimitSpeed[i] = implement.attachingTransLimit[i] / AttacherJoints.SMOOTH_ATTACH_TIME |
1983 | implement.attachingRotLimitSpeed[i] = implement.attachingRotLimit[i] / AttacherJoints.SMOOTH_ATTACH_TIME |
1984 | end |
1985 | implement.attachingIsInProgress = true |
1986 | else |
1987 | implement.attachingTransLimit = { 0,0,0 } |
1988 | implement.attachingRotLimit = { 0,0,0 } |
1989 | end |
1990 | |
1991 | implement.rotLimitThreshold = objectAttacherJoint.rotLimitThreshold or 0 |
1992 | implement.transLimitThreshold = objectAttacherJoint.transLimitThreshold or 0 |
1993 | |
1994 | for i=1, 3 do |
1995 | local rotLimit, transLimit = AttacherJoints.updateAttacherJointLimits(implement, jointDesc, objectAttacherJoint, i) |
1996 | |
1997 | local limitRot = rotLimit |
1998 | local limitTrans = transLimit |
1999 | if noSmoothAttach == nil or not noSmoothAttach then |
2000 | limitRot = math.max(rotLimit, implement.attachingRotLimit[i]) |
2001 | limitTrans = math.max(transLimit, implement.attachingTransLimit[i]) |
2002 | end |
2003 | |
2004 | local rotLimitDown, rotLimitUp = -limitRot, limitRot |
2005 | if i == 3 then |
2006 | if jointDesc.lockDownRotLimit then |
2007 | rotLimitDown = math.min(-implement.attachingRotLimit[i], 0) |
2008 | end |
2009 | if jointDesc.lockUpRotLimit then |
2010 | rotLimitUp = math.max(implement.attachingRotLimit[i], 0) |
2011 | end |
2012 | end |
2013 | constr:setRotationLimit(i-1, rotLimitDown, rotLimitUp) |
2014 | implement.jointRotLimit[i] = limitRot |
2015 | |
2016 | local transLimitDown, transLimitUp = -limitTrans, limitTrans |
2017 | if i == 2 then |
2018 | if jointDesc.lockDownTransLimit then |
2019 | transLimitDown = math.min(-implement.attachingTransLimit[i], 0) |
2020 | end |
2021 | if jointDesc.lockUpTransLimit then |
2022 | transLimitUp = math.max(implement.attachingTransLimit[i], 0) |
2023 | end |
2024 | end |
2025 | constr:setTranslationLimit(i-1, true, transLimitDown, transLimitUp) |
2026 | implement.jointTransLimit[i] = limitTrans |
2027 | end |
2028 | |
2029 | if jointDesc.enableCollision then |
2030 | constr:setEnableCollision(true) |
2031 | else |
2032 | for _, component in pairs(self.components) do |
2033 | if component.node ~= jointDesc.rootNodeBackup and not component.collideWithAttachables then |
2034 | setPairCollision(component.node, objectAttacherJoint.rootNode, false) |
2035 | end |
2036 | end |
2037 | end |
2038 | |
2039 | local springX = math.max(jointDesc.rotLimitSpring[1], objectAttacherJoint.rotLimitSpring[1]) |
2040 | local springY = math.max(jointDesc.rotLimitSpring[2], objectAttacherJoint.rotLimitSpring[2]) |
2041 | local springZ = math.max(jointDesc.rotLimitSpring[3], objectAttacherJoint.rotLimitSpring[3]) |
2042 | local dampingX = math.max(jointDesc.rotLimitDamping[1], objectAttacherJoint.rotLimitDamping[1]) |
2043 | local dampingY = math.max(jointDesc.rotLimitDamping[2], objectAttacherJoint.rotLimitDamping[2]) |
2044 | local dampingZ = math.max(jointDesc.rotLimitDamping[3], objectAttacherJoint.rotLimitDamping[3]) |
2045 | local forceLimitX = Utils.getMaxJointForceLimit(jointDesc.rotLimitForceLimit[1], objectAttacherJoint.rotLimitForceLimit[1]) |
2046 | local forceLimitY = Utils.getMaxJointForceLimit(jointDesc.rotLimitForceLimit[2], objectAttacherJoint.rotLimitForceLimit[2]) |
2047 | local forceLimitZ = Utils.getMaxJointForceLimit(jointDesc.rotLimitForceLimit[3], objectAttacherJoint.rotLimitForceLimit[3]) |
2048 | constr:setRotationLimitSpring(springX, dampingX, springY, dampingY, springZ, dampingZ) |
2049 | constr:setRotationLimitForceLimit(forceLimitX, forceLimitY, forceLimitZ) |
2050 | |
2051 | local springX = math.max(jointDesc.transLimitSpring[1], objectAttacherJoint.transLimitSpring[1]) |
2052 | local springY = math.max(jointDesc.transLimitSpring[2], objectAttacherJoint.transLimitSpring[2]) |
2053 | local springZ = math.max(jointDesc.transLimitSpring[3], objectAttacherJoint.transLimitSpring[3]) |
2054 | local dampingX = math.max(jointDesc.transLimitDamping[1], objectAttacherJoint.transLimitDamping[1]) |
2055 | local dampingY = math.max(jointDesc.transLimitDamping[2], objectAttacherJoint.transLimitDamping[2]) |
2056 | local dampingZ = math.max(jointDesc.transLimitDamping[3], objectAttacherJoint.transLimitDamping[3]) |
2057 | local forceLimitX = Utils.getMaxJointForceLimit(jointDesc.transLimitForceLimit[1], objectAttacherJoint.transLimitForceLimit[1]) |
2058 | local forceLimitY = Utils.getMaxJointForceLimit(jointDesc.transLimitForceLimit[2], objectAttacherJoint.transLimitForceLimit[2]) |
2059 | local forceLimitZ = Utils.getMaxJointForceLimit(jointDesc.transLimitForceLimit[3], objectAttacherJoint.transLimitForceLimit[3]) |
2060 | constr:setTranslationLimitSpring(springX, dampingX, springY, dampingY, springZ, dampingZ) |
2061 | constr:setTranslationLimitForceLimit(forceLimitX, forceLimitY, forceLimitZ) |
2062 | |
2063 | jointDesc.jointIndex = constr:finalize() |
2064 | |
2065 | -- restore implement attacher joint position (to ensure correct bottom arm alignment) |
2066 | setTranslation(objectAttacherJoint.node, unpack(objectAttacherJoint.jointOrigTrans)) |
2067 | else |
2068 | -- set joint index to '1' on client side, so we can check if something is attached |
2069 | jointDesc.jointIndex = 1 |
2070 | end |
2071 | end |
deactivateAttachments
DescriptionCall "deactivate" on all attachmentsDefinition
deactivateAttachments()Code
2770 | function AttacherJoints:deactivateAttachments() |
2771 | local spec = self.spec_attacherJoints |
2772 | |
2773 | for _,v in pairs(spec.attachedImplements) do |
2774 | if v.object ~= nil then |
2775 | v.object:deactivate() |
2776 | end |
2777 | end |
2778 | end |
deactivateAttachmentsLights
DescriptionCall "deactivateLights" on all attachmentsDefinition
deactivateAttachmentsLights()Code
2782 | function AttacherJoints:deactivateAttachmentsLights() |
2783 | local spec = self.spec_attacherJoints |
2784 | |
2785 | for _,v in pairs(spec.attachedImplements) do |
2786 | if v.object ~= nil and v.object.deactivateLights ~= nil then |
2787 | v.object:deactivateLights() |
2788 | end |
2789 | end |
2790 | end |
detachAdditionalAttachment
DescriptionCreates and attaches additional attachmentDefinition
detachAdditionalAttachment()Code
2638 | function AttacherJoints:detachAdditionalAttachment(jointDesc, inputJointDesc) |
2639 | if jointDesc.additionalAttachment.currentAttacherJointIndex ~= nil and inputJointDesc.additionalAttachment.filename ~= nil then |
2640 | local implement = self:getImplementByJointDescIndex(jointDesc.additionalAttachment.currentAttacherJointIndex) |
2641 | if implement ~= nil then |
2642 | if implement.object:getIsAdditionalAttachment() then |
2643 | -- on the exit the vehicle will be removed by BaseMission.delete |
2644 | if not g_currentMission.isExitingGame then |
2645 | g_currentMission:removeVehicle(implement.object) |
2646 | end |
2647 | end |
2648 | end |
2649 | end |
2650 | end |
detachAttachedImplement
DescriptionDefinitiondetachAttachedImplement()Code
2477 | function AttacherJoints:detachAttachedImplement() |
2478 | if self:getCanToggleAttach() then |
2479 | AttacherJoints.actionEventAttach(self) |
2480 | end |
2481 | end |
detachImplement
DescriptionDetach implementDefinition
detachImplement(integer implementIndex, boolean noEventSend)Arguments
integer | implementIndex | index of implement in self.attachedImplements |
boolean | noEventSend | no event send |
boolean | success | success |
2216 | function AttacherJoints:detachImplement(implementIndex, noEventSend) |
2217 | local spec = self.spec_attacherJoints |
2218 | |
2219 | if noEventSend == nil or noEventSend == false then |
2220 | if g_server ~= nil then |
2221 | g_server:broadcastEvent(VehicleDetachEvent.new(self, spec.attachedImplements[implementIndex].object), nil, nil, self) |
2222 | else |
2223 | -- Send detach request to server and return |
2224 | local implement = spec.attachedImplements[implementIndex] |
2225 | if implement.object ~= nil then |
2226 | g_client:getServerConnection():sendEvent(VehicleDetachEvent.new(self, implement.object)) |
2227 | end |
2228 | return |
2229 | end |
2230 | end |
2231 | |
2232 | local implement = spec.attachedImplements[implementIndex] |
2233 | |
2234 | SpecializationUtil.raiseEvent(self, "onPreDetachImplement", implement) |
2235 | implement.object:preDetach(self, implement) |
2236 | |
2237 | local jointDesc |
2238 | if implement.object ~= nil then |
2239 | jointDesc = spec.attacherJoints[implement.jointDescIndex] |
2240 | if jointDesc.transNode ~= nil then |
2241 | setTranslation(jointDesc.transNode, unpack(jointDesc.transNodeOrgTrans)) |
2242 | |
2243 | if jointDesc.transNodeDependentBottomArm ~= nil then |
2244 | local bottomArmJointDesc = jointDesc.transNodeDependentBottomArmAttacherJoint |
2245 | local interpolator = ValueInterpolator.new(bottomArmJointDesc.bottomArm.interpolatorKey, bottomArmJointDesc.bottomArm.interpolatorGet, bottomArmJointDesc.bottomArm.interpolatorSet, {bottomArmJointDesc.bottomArm.rotX, bottomArmJointDesc.bottomArm.rotY, bottomArmJointDesc.bottomArm.rotZ}, AttacherJoints.SMOOTH_ATTACH_TIME * 2) |
2246 | if interpolator ~= nil then |
2247 | interpolator:setDeleteListenerObject(self) |
2248 | interpolator:setFinishedFunc(bottomArmJointDesc.bottomArm.interpolatorFinished, bottomArmJointDesc.bottomArm) |
2249 | bottomArmJointDesc.bottomArm.bottomArmInterpolating = true |
2250 | end |
2251 | end |
2252 | end |
2253 | if not implement.object.spec_attachable.isHardAttached then |
2254 | if self.isServer then |
2255 | if jointDesc.jointIndex ~= 0 then |
2256 | removeJoint(jointDesc.jointIndex) |
2257 | end |
2258 | |
2259 | if not jointDesc.enableCollision then |
2260 | for _, component in pairs(self.components) do |
2261 | if component.node ~= jointDesc.rootNodeBackup and not component.collideWithAttachables then |
2262 | local attacherJoint = implement.object:getActiveInputAttacherJoint() |
2263 | setPairCollision(component.node, attacherJoint.rootNode, true) |
2264 | end |
2265 | end |
2266 | end |
2267 | end |
2268 | end |
2269 | jointDesc.jointIndex = 0 |
2270 | end |
2271 | |
2272 | if not jointDesc.delayedObjectChanges or jointDesc.bottomArm == nil then |
2273 | ObjectChangeUtil.setObjectChanges(jointDesc.changeObjects, false, self, self.setMovingToolDirty) |
2274 | end |
2275 | |
2276 | for i=1, #jointDesc.hideVisuals do |
2277 | local node = jointDesc.hideVisuals[i] |
2278 | |
2279 | local allowedToShow = true |
2280 | local attacherJoints = spec.hideVisualNodeToAttacherJoints[node] |
2281 | if attacherJoints ~= nil then |
2282 | for j=1, #attacherJoints do |
2283 | if attacherJoints[j].jointIndex ~= 0 then |
2284 | allowedToShow = false |
2285 | end |
2286 | end |
2287 | end |
2288 | |
2289 | if allowedToShow then |
2290 | setVisibility(node, true) |
2291 | end |
2292 | end |
2293 | |
2294 | for i=1, #jointDesc.visualNodes do |
2295 | local node = jointDesc.visualNodes[i] |
2296 | |
2297 | local hideNode = false |
2298 | local attacherJoints = spec.hideVisualNodeToAttacherJoints[node] |
2299 | if attacherJoints ~= nil then |
2300 | for j=1, #attacherJoints do |
2301 | if attacherJoints[j].jointIndex ~= 0 then |
2302 | hideNode = true |
2303 | end |
2304 | end |
2305 | end |
2306 | |
2307 | if hideNode then |
2308 | setVisibility(node, false) |
2309 | end |
2310 | end |
2311 | |
2312 | if implement.object ~= nil then |
2313 | local object = implement.object |
2314 | |
2315 | if object.spec_attachable.isHardAttached then |
2316 | self:hardDetachImplement(implement) |
2317 | end |
2318 | |
2319 | if self.isClient then |
2320 | if jointDesc.topArm ~= nil then |
2321 | setRotation(jointDesc.topArm.rotationNode, jointDesc.topArm.rotX, jointDesc.topArm.rotY, jointDesc.topArm.rotZ) |
2322 | if jointDesc.topArm.translationNode ~= nil then |
2323 | setTranslation(jointDesc.topArm.translationNode, 0, 0, 0) |
2324 | end |
2325 | if jointDesc.topArm.scaleNode ~= nil then |
2326 | setScale(jointDesc.topArm.scaleNode, 1, 1, 1) |
2327 | end |
2328 | if jointDesc.topArm.toggleVisibility then |
2329 | setVisibility(jointDesc.topArm.rotationNode, false) |
2330 | end |
2331 | end |
2332 | if jointDesc.bottomArm ~= nil then |
2333 | local interpolator = ValueInterpolator.new(jointDesc.bottomArm.interpolatorKey, jointDesc.bottomArm.interpolatorGet, jointDesc.bottomArm.interpolatorSet, {jointDesc.bottomArm.rotX, jointDesc.bottomArm.rotY, jointDesc.bottomArm.rotZ}, nil, jointDesc.bottomArm.resetSpeed) |
2334 | if interpolator ~= nil then |
2335 | interpolator:setDeleteListenerObject(self) |
2336 | interpolator:setFinishedFunc(jointDesc.bottomArm.interpolatorFinished, jointDesc.bottomArm) |
2337 | jointDesc.bottomArm.bottomArmInterpolating = true |
2338 | |
2339 | if jointDesc.delayedObjectChanges then |
2340 | interpolator:setFinishedFunc(function() |
2341 | jointDesc.bottomArm.interpolatorFinished(jointDesc.bottomArm) |
2342 | ObjectChangeUtil.setObjectChanges(jointDesc.changeObjects, false, self, self.setMovingToolDirty) |
2343 | end) |
2344 | end |
2345 | end |
2346 | |
2347 | jointDesc.bottomArm.lastDirection[1], jointDesc.bottomArm.lastDirection[2], jointDesc.bottomArm.lastDirection[3] = 0, 0, 0 |
2348 | |
2349 | if jointDesc.bottomArm.translationNode ~= nil then |
2350 | setTranslation(jointDesc.bottomArm.translationNode, 0, 0, 0) |
2351 | end |
2352 | if jointDesc.bottomArm.toolbar ~= nil then |
2353 | setVisibility(jointDesc.bottomArm.toolbar, false) |
2354 | end |
2355 | if jointDesc.bottomArm.toggleVisibility then |
2356 | setVisibility(jointDesc.bottomArm.rotationNode, false) |
2357 | end |
2358 | end |
2359 | end |
2360 | -- restore original translation |
2361 | setTranslation(jointDesc.jointTransform, unpack(jointDesc.jointOrigTrans)) |
2362 | local attacherJoint = object:getActiveInputAttacherJoint() |
2363 | setTranslation(attacherJoint.node, unpack(attacherJoint.jointOrigTrans)) |
2364 | if jointDesc.rotationNode ~= nil then |
2365 | setRotation(jointDesc.rotationNode, jointDesc.rotX, jointDesc.rotY, jointDesc.rotZ) |
2366 | end |
2367 | |
2368 | SpecializationUtil.raiseEvent(self, "onPostDetachImplement", implementIndex) |
2369 | object:postDetach(implementIndex) |
2370 | |
2371 | self:detachAdditionalAttachment(jointDesc, attacherJoint) |
2372 | end |
2373 | |
2374 | table.remove(spec.attachedImplements, implementIndex) |
2375 | |
2376 | self:playDetachSound(jointDesc) |
2377 | |
2378 | spec.wasInAttachRange = nil |
2379 | |
2380 | self:updateVehicleChain() |
2381 | implement.object:updateVehicleChain() |
2382 | |
2383 | local data = {attacherVehicle=self, attachedVehicle=implement.object} |
2384 | implement.object:raiseStateChange(Vehicle.STATE_CHANGE_DETACH, data) |
2385 | local rootVehicle = self.rootVehicle |
2386 | rootVehicle:raiseStateChange(Vehicle.STATE_CHANGE_DETACH, data) |
2387 | |
2388 | self.rootVehicle:updateSelectableObjects() |
2389 | if GS_IS_MOBILE_VERSION then |
2390 | -- for mobile we select the next vehicle that can be detached, if non available we select the root |
2391 | local nextImplement = next(spec.attachedImplements) |
2392 | if spec.attachedImplements[nextImplement] ~= nil then |
2393 | self.rootVehicle:setSelectedVehicle(spec.attachedImplements[nextImplement].object, nil, true) |
2394 | else |
2395 | self.rootVehicle:setSelectedVehicle(self, nil, true) |
2396 | end |
2397 | else |
2398 | self.rootVehicle:setSelectedVehicle(self, nil, true) |
2399 | end |
2400 | self.rootVehicle:requestActionEventUpdate() -- do action event update independent of a successful selection (important since we cannot select every vehicle) |
2401 | implement.object:updateSelectableObjects() |
2402 | implement.object:setSelectedVehicle(implement.object, nil, true) |
2403 | implement.object:requestActionEventUpdate() -- do action event update independent of a successful selection (important since we cannot select every vehicle) |
2404 | |
2405 | return true |
2406 | end |
detachImplementByObject
DescriptionDetach implement by object of implementDefinition
detachImplementByObject(table object, boolean noEventSend)Arguments
table | object | object of implement to detach |
boolean | noEventSend | no event send |
boolean | success | success |
2413 | function AttacherJoints:detachImplementByObject(object, noEventSend) |
2414 | local spec = self.spec_attacherJoints |
2415 | |
2416 | for i,implement in ipairs(spec.attachedImplements) do |
2417 | if implement.object == object then |
2418 | self:detachImplement(i, noEventSend) |
2419 | break |
2420 | end |
2421 | end |
2422 | |
2423 | return true |
2424 | end |
detachingIsPossible
DescriptionReturns true if it is possible to detach selected implementDefinition
detachingIsPossible()Return Values
boolean | possibleToDetach | possible to detach selected implement |
2576 | function AttacherJoints:detachingIsPossible() |
2577 | local implement = self:getImplementByObject(self:getSelectedVehicle()) |
2578 | if implement ~= nil then |
2579 | local object = implement.object |
2580 | if object ~= nil and object.attacherVehicle ~= nil and object:isDetachAllowed() then |
2581 | local implementIndex = object.attacherVehicle:getImplementIndexByObject(object) |
2582 | if implementIndex ~= nil then |
2583 | return true |
2584 | end |
2585 | end |
2586 | end |
2587 | return false |
2588 | end |
doGroundHeightNodeCheck
DescriptionStarts the next step in the ground height node check (raycast)Definition
doGroundHeightNodeCheck()Code
1416 | function AttacherJoints:doGroundHeightNodeCheck() |
1417 | local checkData = self.spec_attacherJoints.groundHeightNodeCheckData |
1418 | |
1419 | local heightNode = checkData.heightNodes[checkData.index] |
1420 | if heightNode ~= nil and checkData.object:getIsAttacherJointHeightNodeActive(heightNode) then |
1421 | local offX, offY, offZ = localToLocal(heightNode.node, heightNode.attacherJointNode, 0, 0, 0) |
1422 | |
1423 | self:updateAttacherJointRotationNodes(checkData.jointDesc, 1) |
1424 | local lWx, lWy, lWz = localToWorld(checkData.jointDesc.jointTransformOrig, offX, offY, offZ) |
1425 | |
1426 | self:updateAttacherJointRotationNodes(checkData.jointDesc, 0) |
1427 | local uWx, uWy, uWz = localToWorld(checkData.jointDesc.jointTransformOrig, offX, offY, offZ) |
1428 | |
1429 | --#debug if VehicleDebug.state == VehicleDebug.DEBUG then |
1430 | --#debug DebugUtil.drawDebugGizmoAtWorldPos(lWx, lWy, lWz, 0, 0, 1, 0, 1, 0, "", false) |
1431 | --#debug DebugUtil.drawDebugGizmoAtWorldPos(uWx, uWy, uWz, 0, 0, 1, 0, 1, 0, "", false) |
1432 | --#debug drawDebugLine(uWx, uWy, uWz, 0, 1, 0, lWx, lWy, lWz, 1, 0, 0, true) |
1433 | --#debug end |
1434 | |
1435 | local dirX, dirY, dirZ = lWx - uWx, lWy - uWy, lWz - uWz |
1436 | local distance = MathUtil.vector3Length(dirX, dirY, dirZ) |
1437 | dirX, dirY, dirZ = MathUtil.vector3Normalize(dirX, dirY, dirZ) |
1438 | |
1439 | checkData.currentRaycastDistance = distance |
1440 | checkData.currentRaycastWorldPos[1] = uWx |
1441 | checkData.currentRaycastWorldPos[2] = uWy |
1442 | checkData.currentRaycastWorldPos[3] = uWz |
1443 | checkData.currentRaycastWorldDir[1] = dirX |
1444 | checkData.currentRaycastWorldDir[2] = dirY |
1445 | checkData.currentRaycastWorldDir[3] = dirZ |
1446 | |
1447 | checkData.currentJointTransformPos[1], checkData.currentJointTransformPos[2], checkData.currentJointTransformPos[3] = getWorldTranslation(checkData.jointDesc.jointTransform) |
1448 | |
1449 | -- as real raycast distance we also add the lower distance to ground |
1450 | distance = distance + checkData.objectAttacherJoint.lowerDistanceToGround |
1451 | checkData.minDistance = math.min(checkData.minDistance, distance) |
1452 | raycastAll(uWx, uWy, uWz, dirX, dirY, dirZ, "groundHeightNodeCheckCallback", distance, self, CollisionMask.TERRAIN, false, true) |
1453 | |
1454 | self:updateAttacherJointRotationNodes(checkData.jointDesc, checkData.jointDesc.moveAlpha or 0) |
1455 | else |
1456 | checkData.index = checkData.index + 1 |
1457 | if checkData.index > #checkData.heightNodes then |
1458 | self:finishGroundHeightNodeCheck() |
1459 | else |
1460 | checkData.isDirty = true |
1461 | end |
1462 | end |
1463 | end |
findVehicleInAttachRange
DescriptionDefinitionfindVehicleInAttachRange()Code
4129 | function AttacherJoints.findVehicleInAttachRange() |
4130 | log("function 'AttacherJoints.findVehicleInAttachRange' is deprecated. Use 'AttacherJoints.updateVehiclesInAttachRange' instead. Valid output of this function is now up to 5 frames delayed, if parameter 4 is not 'true'.") |
4131 | end |
finishGroundHeightNodeCheck
DescriptionCalled to finish the ground height node check and calculate the upper and lower alpha based on the resultsDefinition
finishGroundHeightNodeCheck()Code
1467 | function AttacherJoints:finishGroundHeightNodeCheck() |
1468 | local checkData = self.spec_attacherJoints.groundHeightNodeCheckData |
1469 | |
1470 | if checkData.minDistance ~= math.huge then |
1471 | if not checkData.hit then |
1472 | checkData.raycastDistance = checkData.currentRaycastDistance |
1473 | |
1474 | checkData.raycastWorldPos[1] = checkData.currentRaycastWorldPos[1] |
1475 | checkData.raycastWorldPos[2] = checkData.currentRaycastWorldPos[2] |
1476 | checkData.raycastWorldPos[3] = checkData.currentRaycastWorldPos[3] |
1477 | |
1478 | checkData.raycastWorldDir[1] = checkData.currentRaycastWorldDir[1] |
1479 | checkData.raycastWorldDir[2] = checkData.currentRaycastWorldDir[2] |
1480 | checkData.raycastWorldDir[3] = checkData.currentRaycastWorldDir[3] |
1481 | |
1482 | checkData.jointTransformPos[1] = checkData.currentJointTransformPos[1] |
1483 | checkData.jointTransformPos[2] = checkData.currentJointTransformPos[2] |
1484 | checkData.jointTransformPos[3] = checkData.currentJointTransformPos[3] |
1485 | end |
1486 | |
1487 | local upperAlpha = (checkData.minDistance - checkData.objectAttacherJoint.upperDistanceToGround) / checkData.raycastDistance |
1488 | local lowerAlpha = (checkData.minDistance - checkData.objectAttacherJoint.lowerDistanceToGround) / checkData.raycastDistance |
1489 | |
1490 | local uWx, uWy, uWz = checkData.raycastWorldPos[1], checkData.raycastWorldPos[2], checkData.raycastWorldPos[3] |
1491 | local dirX, dirY, dirZ = checkData.raycastWorldDir[1], checkData.raycastWorldDir[2], checkData.raycastWorldDir[3] |
1492 | |
1493 | -- correction since we raycast straight to lower point, but rotate in a circle |
1494 | local x1, y1, z1 = uWx + dirX * checkData.raycastDistance * lowerAlpha, uWy + dirY * checkData.raycastDistance * lowerAlpha, uWz + dirZ * checkData.raycastDistance * lowerAlpha |
1495 | |
1496 | local x3, y3, z3 = checkData.jointTransformPos[1], checkData.jointTransformPos[2], checkData.jointTransformPos[3] |
1497 | local straightToCenter = MathUtil.vector3Length(x1-x3, y1-y3, z1-z3) |
1498 | local circleToCenter = MathUtil.vector3Length(uWx-x3, uWy-y3, uWz-z3) |
1499 | local straightOffset = circleToCenter - straightToCenter |
1500 | |
1501 | local _, h1, h2 |
1502 | _, h1, _ = worldToLocal(self.rootNode, x1, y1, z1) |
1503 | _, h2, _ = worldToLocal(self.rootNode, uWx, uWy, uWz) |
1504 | |
1505 | local angle = math.atan(straightOffset / (h2 - h1)) |
1506 | local offset = straightOffset * math.sin(angle) |
1507 | lowerAlpha = (checkData.minDistance - checkData.objectAttacherJoint.lowerDistanceToGround - offset) / checkData.raycastDistance |
1508 | |
1509 | checkData.lowerAlpha = MathUtil.clamp(lowerAlpha, 0, 1) |
1510 | checkData.upperAlpha = MathUtil.clamp(upperAlpha, 0, 1) |
1511 | end |
1512 | |
1513 | checkData.index = -1 |
1514 | end |
getAirConsumerUsage
DescriptionReturns air consumer usage of attached vehiclesDefinition
getAirConsumerUsage()Return Values
float | usage | air usage |
3491 | function AttacherJoints:getAirConsumerUsage(superFunc) |
3492 | local spec = self.spec_attacherJoints |
3493 | local usage = superFunc(self) |
3494 | |
3495 | for _, implement in pairs(spec.attachedImplements) do |
3496 | local object = implement.object |
3497 | if object ~= nil and object.getAttachbleAirConsumerUsage ~= nil then |
3498 | usage = usage + object:getAttachbleAirConsumerUsage() |
3499 | end |
3500 | end |
3501 | |
3502 | return usage |
3503 | end |
getAreControlledActionsAllowed
DescriptionReturns if controlled actions are allowedDefinition
getAreControlledActionsAllowed()Return Values
boolean | allow | allow controlled actions |
string | warning | not allowed warning |
3777 | function AttacherJoints:getAreControlledActionsAllowed(superFunc) |
3778 | local allowed, warning = superFunc(self) |
3779 | if not allowed then |
3780 | return false, warning |
3781 | end |
3782 | |
3783 | local spec = self.spec_attacherJoints |
3784 | for _, implement in pairs(spec.attachedImplements) do |
3785 | local object = implement.object |
3786 | if object ~= nil then |
3787 | if object.getAreControlledActionsAllowed ~= nil then |
3788 | allowed, warning = object:getAreControlledActionsAllowed() |
3789 | if not allowed then |
3790 | return false, warning |
3791 | end |
3792 | end |
3793 | end |
3794 | end |
3795 | |
3796 | return true, warning |
3797 | end |
getAttachedImplements
DescriptionDefinitiongetAttachedImplements()Code
1094 | function AttacherJoints:getAttachedImplements() |
1095 | return self.spec_attacherJoints.attachedImplements |
1096 | end |
getAttacherJointByJointDescIndex
DescriptionDefinitiongetAttacherJointByJointDescIndex()Code
1106 | function AttacherJoints:getAttacherJointByJointDescIndex(jointDescIndex) |
1107 | return self.spec_attacherJoints.attacherJoints[jointDescIndex] |
1108 | end |
getAttacherJointCompatibility
DescriptionDefinitiongetAttacherJointCompatibility()Code
4045 | function AttacherJoints.getAttacherJointCompatibility(vehicle, attacherJoint, inputAttacherVehicle, inputAttacherJoint) |
4046 | if inputAttacherJoint.forcedAttachingDirection ~= 0 and attacherJoint.additionalAttachment.attacherJointDirection ~= nil then |
4047 | if inputAttacherJoint.forcedAttachingDirection ~= attacherJoint.additionalAttachment.attacherJointDirection then |
4048 | return false |
4049 | end |
4050 | end |
4051 | |
4052 | if attacherJoint.subTypes ~= nil then |
4053 | if inputAttacherJoint.subTypes == nil then |
4054 | return false, vehicle.spec_attacherJoints.texts.warningToolNotCompatible |
4055 | end |
4056 | |
4057 | local found = false |
4058 | for i=1, #attacherJoint.subTypes do |
4059 | for j=1, #inputAttacherJoint.subTypes do |
4060 | if attacherJoint.subTypes[i] == inputAttacherJoint.subTypes[j] then |
4061 | found = true |
4062 | break |
4063 | end |
4064 | end |
4065 | end |
4066 | |
4067 | if not found then |
4068 | if attacherJoint.subTypeShowWarning then |
4069 | return false, vehicle.spec_attacherJoints.texts.warningToolNotCompatible |
4070 | end |
4071 | |
4072 | return false |
4073 | end |
4074 | else |
4075 | if inputAttacherJoint.subTypes ~= nil then |
4076 | if inputAttacherJoint.subTypeShowWarning then |
4077 | return false, vehicle.spec_attacherJoints.texts.warningToolNotCompatible |
4078 | end |
4079 | |
4080 | return false |
4081 | end |
4082 | end |
4083 | |
4084 | if attacherJoint.brandRestrictions ~= nil then |
4085 | local found = false |
4086 | for i=1, #attacherJoint.brandRestrictions do |
4087 | if inputAttacherVehicle.brand ~= nil then |
4088 | if inputAttacherVehicle.brand == attacherJoint.brandRestrictions[i] then |
4089 | found = true |
4090 | break |
4091 | end |
4092 | end |
4093 | end |
4094 | |
4095 | if not found then |
4096 | local brandString = "" |
4097 | for i=1, #attacherJoint.brandRestrictions do |
4098 | if i > 1 then |
4099 | brandString = brandString .. ", " |
4100 | end |
4101 | brandString = brandString .. attacherJoint.brandRestrictions[i].title |
4102 | end |
4103 | |
4104 | return false, string.format(vehicle.spec_attacherJoints.texts.warningToolBrandNotCompatible, brandString) |
4105 | end |
4106 | end |
4107 | |
4108 | if attacherJoint.vehicleRestrictions ~= nil then |
4109 | local found = false |
4110 | for i=1, #attacherJoint.vehicleRestrictions do |
4111 | if inputAttacherVehicle.configFileName:find(attacherJoint.vehicleRestrictions[i]) ~= nil then |
4112 | found = true |
4113 | break |
4114 | end |
4115 | end |
4116 | |
4117 | if not found then |
4118 | return false, vehicle.spec_attacherJoints.texts.warningToolNotCompatible |
4119 | end |
4120 | end |
4121 | |
4122 | return true |
4123 | end |
getAttacherJointDescFromObject
DescriptionDefinitiongetAttacherJointDescFromObject()Code
1148 | function AttacherJoints:getAttacherJointDescFromObject(object) |
1149 | local spec = self.spec_attacherJoints |
1150 | for _,attachedImplement in pairs(spec.attachedImplements) do |
1151 | if attachedImplement.object == object then |
1152 | return spec.attacherJoints[attachedImplement.jointDescIndex] |
1153 | end |
1154 | end |
1155 | end |
getAttacherJointIndexByNode
DescriptionDefinitiongetAttacherJointIndexByNode()Code
1112 | function AttacherJoints:getAttacherJointIndexByNode(node) |
1113 | local spec = self.spec_attacherJoints |
1114 | for i=1, #spec.attacherJoints do |
1115 | local attacherJoint = spec.attacherJoints[i] |
1116 | if attacherJoint.jointTransform == node then |
1117 | return i |
1118 | end |
1119 | end |
1120 | |
1121 | return nil |
1122 | end |
getAttacherJointIndexFromImplementIndex
DescriptionDefinitiongetAttacherJointIndexFromImplementIndex()Code
1159 | function AttacherJoints:getAttacherJointIndexFromImplementIndex(implementIndex) |
1160 | local spec = self.spec_attacherJoints |
1161 | local attachedImplement = spec.attachedImplements[implementIndex] |
1162 | if attachedImplement ~= nil then |
1163 | return attachedImplement.jointDescIndex |
1164 | end |
1165 | return nil |
1166 | end |
getAttacherJointIndexFromObject
DescriptionDefinitiongetAttacherJointIndexFromObject()Code
1137 | function AttacherJoints:getAttacherJointIndexFromObject(object) |
1138 | local spec = self.spec_attacherJoints |
1139 | for _,attachedImplement in pairs(spec.attachedImplements) do |
1140 | if attachedImplement.object == object then |
1141 | return attachedImplement.jointDescIndex |
1142 | end |
1143 | end |
1144 | end |
getAttacherJoints
DescriptionDefinitiongetAttacherJoints()Code
1100 | function AttacherJoints:getAttacherJoints() |
1101 | return self.spec_attacherJoints.attacherJoints |
1102 | end |
getCanSteerAttachable
DescriptionReturns if the vehicle can control the steering axles of the given attachableDefinition
getCanSteerAttachable(table jointDesc)Arguments
table | jointDesc | joint desc |
boolean | success | success |
2517 | function AttacherJoints:getCanSteerAttachable(attachable) |
2518 | local jointDesc = self:getAttacherJointDescFromObject(attachable) |
2519 | if jointDesc ~= nil then |
2520 | if jointDesc.steeringBarLeftNode ~= nil or jointDesc.steeringBarRightNode ~= nil or jointDesc.steeringBarForceUsage then |
2521 | return true |
2522 | end |
2523 | end |
2524 | |
2525 | return false |
2526 | end |
getCanToggleAttach
DescriptionDefinitiongetCanToggleAttach()Code
2449 | function AttacherJoints:getCanToggleAttach() |
2450 | return true |
2451 | end |
getConnectionHoseConfigIndex
DescriptionDefinitiongetConnectionHoseConfigIndex()Code
3801 | function AttacherJoints:getConnectionHoseConfigIndex(superFunc) |
3802 | local index = superFunc(self) |
3803 | index = self.xmlFile:getValue("vehicle.attacherJoints#connectionHoseConfigId", index) |
3804 | |
3805 | if self.configurations["attacherJoint"] ~= nil then |
3806 | local configKey = string.format("vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(%d)", self.configurations["attacherJoint"] - 1) |
3807 | index = self.xmlFile:getValue(configKey .. "#connectionHoseConfigId", index) |
3808 | end |
3809 | |
3810 | return index |
3811 | end |
getDirectionSnapAngle
DescriptionDefinitiongetDirectionSnapAngle()Code
3547 | function AttacherJoints:getDirectionSnapAngle(superFunc) |
3548 | local spec = self.spec_attacherJoints |
3549 | local maxAngle = superFunc(self) |
3550 | |
3551 | for _, implement in pairs(spec.attachedImplements) do |
3552 | local object = implement.object |
3553 | if object ~= nil and object.getDirectionSnapAngle ~= nil then |
3554 | maxAngle = math.max(maxAngle + object:getDirectionSnapAngle()) |
3555 | end |
3556 | end |
3557 | |
3558 | return maxAngle |
3559 | end |
getFillLevelInformation
DescriptionDefinitiongetFillLevelInformation()Code
3563 | function AttacherJoints:getFillLevelInformation(superFunc, display) |
3564 | local spec = self.spec_attacherJoints |
3565 | |
3566 | superFunc(self, display) |
3567 | |
3568 | for _, implement in pairs(spec.attachedImplements) do |
3569 | local object = implement.object |
3570 | if object ~= nil and object.getFillLevelInformation ~= nil then |
3571 | object:getFillLevelInformation(display) |
3572 | end |
3573 | end |
3574 | end |
getImplementByJointDescIndex
DescriptionReturns implement by jointDescIndexDefinition
getImplementByJointDescIndex(integer jointDescIndex)Arguments
integer | jointDescIndex | joint desc index |
table | implement | implement |
2699 | function AttacherJoints:getImplementByJointDescIndex(jointDescIndex) |
2700 | local spec = self.spec_attacherJoints |
2701 | |
2702 | for i, implement in pairs(spec.attachedImplements) do |
2703 | if implement.jointDescIndex == jointDescIndex then |
2704 | return implement |
2705 | end |
2706 | end |
2707 | |
2708 | return nil |
2709 | end |
getImplementByObject
DescriptionReturns implement by objectDefinition
getImplementByObject(table object)Arguments
table | object | object of attached implement |
table | implement | implement |
2731 | function AttacherJoints:getImplementByObject(object) |
2732 | local spec = self.spec_attacherJoints |
2733 | |
2734 | for i, implement in pairs(spec.attachedImplements) do |
2735 | if implement.object == object then |
2736 | return implement |
2737 | end |
2738 | end |
2739 | |
2740 | return nil |
2741 | end |
getImplementFromAttacherJointIndex
DescriptionDefinitiongetImplementFromAttacherJointIndex()Code
1126 | function AttacherJoints:getImplementFromAttacherJointIndex(attacherJointIndex) |
1127 | local spec = self.spec_attacherJoints |
1128 | for _,attachedImplement in pairs(spec.attachedImplements) do |
1129 | if attachedImplement.jointDescIndex == attacherJointIndex then |
1130 | return attachedImplement |
1131 | end |
1132 | end |
1133 | end |
getImplementIndexByJointDescIndex
DescriptionReturns implement index in 'self.attachedImplements' by jointDescIndexDefinition
getImplementIndexByJointDescIndex(integer jointDescIndex)Arguments
integer | jointDescIndex | joint desc index |
integer | index | index of implement |
2683 | function AttacherJoints:getImplementIndexByJointDescIndex(jointDescIndex) |
2684 | local spec = self.spec_attacherJoints |
2685 | |
2686 | for i, implement in pairs(spec.attachedImplements) do |
2687 | if implement.jointDescIndex == jointDescIndex then |
2688 | return i |
2689 | end |
2690 | end |
2691 | |
2692 | return nil |
2693 | end |
getImplementIndexByObject
DescriptionReturns implement index in 'self.attachedImplements' by objectDefinition
getImplementIndexByObject(table object)Arguments
table | object | object of attached implement |
integer | index | index of implement |
2715 | function AttacherJoints:getImplementIndexByObject(object) |
2716 | local spec = self.spec_attacherJoints |
2717 | |
2718 | for i, implement in pairs(spec.attachedImplements) do |
2719 | if implement.object == object then |
2720 | return i |
2721 | end |
2722 | end |
2723 | |
2724 | return nil |
2725 | end |
getIsAttacherJointHeightNodeActive
DescriptionDefinitiongetIsAttacherJointHeightNodeActive()Code
3698 | function AttacherJoints:getIsAttacherJointHeightNodeActive(superFunc, heightNode) |
3699 | for _, jointIndex in ipairs(heightNode.disablingAttacherJointIndices) do |
3700 | if self:getImplementFromAttacherJointIndex(jointIndex) ~= nil then |
3701 | return false |
3702 | end |
3703 | end |
3704 | |
3705 | return superFunc(self, heightNode) |
3706 | end |
getIsAttachingAllowed
DescriptionDefinitiongetIsAttachingAllowed()Code
2496 | function AttacherJoints:getIsAttachingAllowed(attacherJoint) |
2497 | if attacherJoint.jointIndex ~= 0 then |
2498 | return false |
2499 | end |
2500 | |
2501 | if attacherJoint.disabledByAttacherJoints ~= nil and #attacherJoint.disabledByAttacherJoints > 0 then |
2502 | for i=1, #attacherJoint.disabledByAttacherJoints do |
2503 | local jointIndex = attacherJoint.disabledByAttacherJoints[i] |
2504 | if self:getImplementByJointDescIndex(jointIndex) ~= nil then |
2505 | return false |
2506 | end |
2507 | end |
2508 | end |
2509 | |
2510 | return true |
2511 | end |
getIsAutomaticShiftingAllowed
DescriptionDefinitiongetIsAutomaticShiftingAllowed()Code
3636 | function AttacherJoints:getIsAutomaticShiftingAllowed(superFunc) |
3637 | local spec = self.spec_attacherJoints |
3638 | local lastSpeed = self:getLastSpeed() |
3639 | for _, implement in pairs(spec.attachedImplements) do |
3640 | if lastSpeed < 2 then |
3641 | if implement.attachingIsInProgress then |
3642 | return false |
3643 | else |
3644 | local jointDescIndex = implement.jointDescIndex |
3645 | local jointDesc = spec.attacherJoints[jointDescIndex] |
3646 | if jointDesc.isMoving then |
3647 | return false |
3648 | end |
3649 | end |
3650 | end |
3651 | |
3652 | local object = implement.object |
3653 | if object ~= nil and object.getIsAutomaticShiftingAllowed ~= nil then |
3654 | if not object:getIsAutomaticShiftingAllowed() then |
3655 | return false |
3656 | end |
3657 | end |
3658 | end |
3659 | |
3660 | return superFunc(self) |
3661 | end |
getIsDashboardGroupActive
DescriptionDefinitiongetIsDashboardGroupActive()Code
3677 | function AttacherJoints:getIsDashboardGroupActive(superFunc, group) |
3678 | local hasAttachment = #group.attacherJointIndices == 0 |
3679 | for _, jointIndex in ipairs(group.attacherJointIndices) do |
3680 | if self:getImplementFromAttacherJointIndex(jointIndex) ~= nil then |
3681 | hasAttachment = true |
3682 | end |
3683 | end |
3684 | |
3685 | return superFunc(self, group) and hasAttachment |
3686 | end |
getIsFoldAllowed
DescriptionDefinitiongetIsFoldAllowed()Code
3737 | function AttacherJoints:getIsFoldAllowed(superFunc, direction, onAiTurnOn) |
3738 | local spec = self.spec_attacherJoints |
3739 | for attacherJointIndex, attacherJoint in ipairs(spec.attacherJoints) do |
3740 | if not attacherJoint.allowFoldingWhileAttached then |
3741 | if attacherJoint.jointIndex ~= 0 then |
3742 | return false, spec.texts.warningFoldingAttacherJoint |
3743 | end |
3744 | end |
3745 | end |
3746 | |
3747 | return superFunc(self, direction, onAiTurnOn) |
3748 | end |
getIsHardAttachAllowed
DescriptionReturns if attacher joint supports hard attachDefinition
getIsHardAttachAllowed(integer jointDescIndex)Arguments
integer | jointDescIndex | index of joint |
boolean | supportsHardAttach | attacher joint supports hard attach |
2839 | function AttacherJoints:getIsHardAttachAllowed(jointDescIndex) |
2840 | local spec = self.spec_attacherJoints |
2841 | |
2842 | return spec.attacherJoints[jointDescIndex].supportsHardAttach |
2843 | end |
getIsReadyForAutomatedTrainTravel
DescriptionDefinitiongetIsReadyForAutomatedTrainTravel()Code
3620 | function AttacherJoints:getIsReadyForAutomatedTrainTravel(superFunc) |
3621 | local spec = self.spec_attacherJoints |
3622 | for _,implement in pairs(spec.attachedImplements) do |
3623 | local object = implement.object |
3624 | if object ~= nil and object.getIsReadyForAutomatedTrainTravel ~= nil then |
3625 | if not object:getIsReadyForAutomatedTrainTravel() then |
3626 | return false |
3627 | end |
3628 | end |
3629 | end |
3630 | |
3631 | return superFunc(self) |
3632 | end |
getIsWheelFoliageDestructionAllowed
DescriptionReturns true if foliage destruction is allowedDefinition
getIsWheelFoliageDestructionAllowed()Return Values
boolean | isAllowed | tfoliage destruction is allowed |
3753 | function AttacherJoints:getIsWheelFoliageDestructionAllowed(superFunc, wheel) |
3754 | if not superFunc(self, wheel) then |
3755 | return false |
3756 | end |
3757 | |
3758 | local spec = self.spec_attacherJoints |
3759 | for _,implement in pairs(spec.attachedImplements) do |
3760 | local object = implement.object |
3761 | if object ~= nil then |
3762 | if object.getBlockFoliageDestruction ~= nil then |
3763 | if object:getBlockFoliageDestruction() then |
3764 | return false |
3765 | end |
3766 | end |
3767 | end |
3768 | end |
3769 | |
3770 | return true |
3771 | end |
getJointMoveDown
DescriptionReturns the current joint move down stateDefinition
getJointMoveDown(integer jointDescIndex)Arguments
integer | jointDescIndex | index of joint desc |
boolean | moveDown | move down |
2826 | function AttacherJoints:getJointMoveDown(jointDescIndex) |
2827 | local jointDesc = self.spec_attacherJoints.attacherJoints[jointDescIndex] |
2828 | if jointDesc.allowsLowering then |
2829 | return jointDesc.moveDown |
2830 | end |
2831 | |
2832 | return false |
2833 | end |
getObjectFromImplementIndex
DescriptionDefinitiongetObjectFromImplementIndex()Code
1170 | function AttacherJoints:getObjectFromImplementIndex(implementIndex) |
1171 | local spec = self.spec_attacherJoints |
1172 | local attachedImplement = spec.attachedImplements[implementIndex] |
1173 | if attachedImplement ~= nil then |
1174 | return attachedImplement.object |
1175 | end |
1176 | return nil |
1177 | end |
getPowerTakeOffConfigIndex
DescriptionDefinitiongetPowerTakeOffConfigIndex()Code
3815 | function AttacherJoints:getPowerTakeOffConfigIndex(superFunc) |
3816 | local index = superFunc(self) |
3817 | index = self.xmlFile:getValue("vehicle.attacherJoints#powerTakeOffConfigId", index) |
3818 | |
3819 | if self.configurations["attacherJoint"] ~= nil then |
3820 | local configKey = string.format("vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(%d)", self.configurations["attacherJoint"] - 1) |
3821 | index = self.xmlFile:getValue(configKey .. "#powerTakeOffConfigId", index) |
3822 | end |
3823 | |
3824 | return index |
3825 | end |
getSelectedImplement
DescriptionDefinitiongetSelectedImplement()Code
2434 | function AttacherJoints:getSelectedImplement() |
2435 | local spec = self.spec_attacherJoints |
2436 | |
2437 | -- check if implement is still attached |
2438 | if spec.selectedImplement ~= nil then |
2439 | if spec.selectedImplement.object:getAttacherVehicle() ~= self then |
2440 | return nil |
2441 | end |
2442 | end |
2443 | |
2444 | return spec.selectedImplement |
2445 | end |
getShowDetachAttachedImplement
DescriptionDefinitiongetShowDetachAttachedImplement()Code
2455 | function AttacherJoints:getShowDetachAttachedImplement() |
2456 | if self:getIsAIActive() then |
2457 | return false |
2458 | end |
2459 | |
2460 | local spec = self.spec_attacherJoints |
2461 | local info = spec.attachableInfo |
2462 | |
2463 | if info.attacherVehicle == nil then |
2464 | local selectedVehicle = self:getSelectedVehicle() |
2465 | if selectedVehicle ~= nil and not selectedVehicle.isDeleted then |
2466 | if selectedVehicle.getAttacherVehicle ~= nil and selectedVehicle:getAttacherVehicle() ~= nil then |
2467 | return true |
2468 | end |
2469 | end |
2470 | end |
2471 | |
2472 | return false |
2473 | end |
getTotalMass
DescriptionReturns total mass of vehicle (optional including attached vehicles)Definition
getTotalMass(boolean onlyGivenVehicle)Arguments
boolean | onlyGivenVehicle | use only the given vehicle, if false or nil it includes all attachables |
float | totalMass | total mass |
3456 | function AttacherJoints:getTotalMass(superFunc, onlyGivenVehicle) |
3457 | local spec = self.spec_attacherJoints |
3458 | local mass = superFunc(self) |
3459 | |
3460 | if onlyGivenVehicle == nil or not onlyGivenVehicle then |
3461 | for _, implement in pairs(spec.attachedImplements) do |
3462 | local object = implement.object |
3463 | if object ~= nil then |
3464 | mass = mass + object:getTotalMass(onlyGivenVehicle) |
3465 | end |
3466 | end |
3467 | end |
3468 | |
3469 | return mass |
3470 | end |
groundHeightNodeCheckCallback
DescriptionCallback used when raycast hits an object.Definition
groundHeightNodeCheckCallback(integer hitObjectId, float x, float y, float z, float distance, float nx, float ny, float nz, integer subShapeIndex, integer shapeId, boolean isLast)Arguments
integer | hitObjectId | scenegraph object id |
float | x | world x hit position |
float | y | world y hit position |
float | z | world z hit position |
float | distance | distance at which the cast hit the object |
float | nx | normal x direction |
float | ny | normal y direction |
float | nz | normal z direction |
integer | subShapeIndex | sub shape index |
integer | shapeId | id of shape |
boolean | isLast | is last hit |
bool | return | false to stop raycast |
1530 | function AttacherJoints:groundHeightNodeCheckCallback(hitObjectId, x, y, z, distance, nx, ny, nz, subShapeIndex, shapeId, isLast) |
1531 | if self.isDeleted then |
1532 | return |
1533 | end |
1534 | |
1535 | local checkData = self.spec_attacherJoints.groundHeightNodeCheckData |
1536 | |
1537 | if hitObjectId ~= 0 then |
1538 | if getRigidBodyType(hitObjectId) == RigidBodyType.STATIC then |
1539 | if distance < checkData.minDistance then |
1540 | --#debug if VehicleDebug.state == VehicleDebug.DEBUG then |
1541 | --#debug DebugUtil.drawDebugGizmoAtWorldPos(x, y, z, 0, 0, 1, 0, 1, 0, "", false) |
1542 | --#debug end |
1543 | |
1544 | checkData.raycastDistance = checkData.currentRaycastDistance |
1545 | checkData.minDistance = distance |
1546 | checkData.hit = true |
1547 | |
1548 | checkData.raycastWorldPos[1] = checkData.currentRaycastWorldPos[1] |
1549 | checkData.raycastWorldPos[2] = checkData.currentRaycastWorldPos[2] |
1550 | checkData.raycastWorldPos[3] = checkData.currentRaycastWorldPos[3] |
1551 | |
1552 | checkData.raycastWorldDir[1] = checkData.currentRaycastWorldDir[1] |
1553 | checkData.raycastWorldDir[2] = checkData.currentRaycastWorldDir[2] |
1554 | checkData.raycastWorldDir[3] = checkData.currentRaycastWorldDir[3] |
1555 | |
1556 | checkData.jointTransformPos[1] = checkData.currentJointTransformPos[1] |
1557 | checkData.jointTransformPos[2] = checkData.currentJointTransformPos[2] |
1558 | checkData.jointTransformPos[3] = checkData.currentJointTransformPos[3] |
1559 | end |
1560 | else |
1561 | if not isLast then |
1562 | return true |
1563 | end |
1564 | end |
1565 | end |
1566 | |
1567 | checkData.index = checkData.index + 1 |
1568 | if checkData.index > #checkData.heightNodes then |
1569 | self:finishGroundHeightNodeCheck() |
1570 | else |
1571 | checkData.isDirty = true |
1572 | end |
1573 | |
1574 | return false |
1575 | end |
handleLowerImplementByAttacherJointIndex
DescriptionDefinitionhandleLowerImplementByAttacherJointIndex()Code
1071 | function AttacherJoints:handleLowerImplementByAttacherJointIndex(attacherJointIndex, direction) |
1072 | if attacherJointIndex ~= nil then |
1073 | local implement = self:getImplementByJointDescIndex(attacherJointIndex) |
1074 | if implement ~= nil then |
1075 | local object = implement.object |
1076 | local attacherJoints = self:getAttacherJoints() |
1077 | local attacherJoint = attacherJoints[attacherJointIndex] |
1078 | |
1079 | local allowsLowering, warning = object:getAllowsLowering() |
1080 | if allowsLowering and attacherJoint.allowsLowering then |
1081 | if direction == nil then |
1082 | direction = not attacherJoint.moveDown |
1083 | end |
1084 | self:setJointMoveDown(implement.jointDescIndex, direction, false) |
1085 | elseif not allowsLowering and warning ~= nil then |
1086 | g_currentMission:showBlinkingWarning(warning, 2000) |
1087 | end |
1088 | end |
1089 | end |
1090 | end |
handleLowerImplementEvent
DescriptionDefinitionhandleLowerImplementEvent()Code
1053 | function AttacherJoints:handleLowerImplementEvent(vehicle) |
1054 | local implement = self:getImplementByObject(vehicle or self:getSelectedVehicle()) |
1055 | if implement ~= nil then |
1056 | local object = implement.object |
1057 | if object ~= nil and object.getAttacherVehicle ~= nil then |
1058 | |
1059 | local attacherVehicle = object:getAttacherVehicle() |
1060 | if attacherVehicle ~= nil then |
1061 | |
1062 | local attacherJointIndex = attacherVehicle:getAttacherJointIndexFromObject(object) |
1063 | attacherVehicle:handleLowerImplementByAttacherJointIndex(attacherJointIndex) |
1064 | end |
1065 | end |
1066 | end |
1067 | end |
hardAttachImplement
DescriptionHard attach implementDefinition
hardAttachImplement(table implement)Arguments
table | implement | implement to attach |
2076 | function AttacherJoints:hardAttachImplement(implement) |
2077 | local spec = self.spec_attacherJoints |
2078 | |
2079 | local implements = {} |
2080 | local attachedImplements |
2081 | if implement.object.getAttachedImplements ~= nil then |
2082 | attachedImplements = implement.object:getAttachedImplements() |
2083 | end |
2084 | if attachedImplements ~= nil then |
2085 | for i=#attachedImplements, 1, -1 do |
2086 | local impl = attachedImplements[i] |
2087 | local object = impl.object |
2088 | local jointDescIndex = impl.jointDescIndex |
2089 | local jointDesc = implement.object.spec_attacherJoints.attacherJoints[jointDescIndex] |
2090 | local inputJointDescIndex = object.spec_attachable.inputAttacherJointDescIndex |
2091 | local moveDown = jointDesc.moveDown |
2092 | table.insert(implements, 1, {object=object, implementIndex=i, jointDescIndex=jointDescIndex, inputJointDescIndex=inputJointDescIndex, moveDown=moveDown}) |
2093 | implement.object:detachImplement(1, true) |
2094 | end |
2095 | end |
2096 | |
2097 | local attacherJoint = spec.attacherJoints[implement.jointDescIndex] |
2098 | local implementJoint = implement.object.spec_attachable.attacherJoint |
2099 | |
2100 | local baseVehicleComponentNode = self:getParentComponent(attacherJoint.jointTransform) |
2101 | local attachedVehicleComponentNode = implement.object:getParentComponent(implement.object.spec_attachable.attacherJoint.node) |
2102 | |
2103 | -- remove all components from physics |
2104 | local currentVehicle = self |
2105 | while currentVehicle ~= nil do |
2106 | currentVehicle:removeFromPhysics() |
2107 | currentVehicle = currentVehicle.attacherVehicle |
2108 | end |
2109 | implement.object:removeFromPhysics() |
2110 | |
2111 | -- set valid baseVehicle compound |
2112 | if spec.attacherVehicle == nil then |
2113 | setIsCompound(baseVehicleComponentNode, true) |
2114 | end |
2115 | -- set attachedVehicle to compound child |
2116 | setIsCompoundChild(attachedVehicleComponentNode, true) |
2117 | |
2118 | -- set direction and local position |
2119 | local dirX, dirY, dirZ = localDirectionToLocal(attachedVehicleComponentNode, implementJoint.node, 0, 0, 1) |
2120 | local upX, upY, upZ = localDirectionToLocal(attachedVehicleComponentNode, implementJoint.node, 0, 1, 0) |
2121 | setDirection(attachedVehicleComponentNode, dirX, dirY, dirZ, upX, upY, upZ) |
2122 | local x,y,z = localToLocal(attachedVehicleComponentNode, implementJoint.node, 0, 0, 0) |
2123 | setTranslation(attachedVehicleComponentNode, x, y, z) |
2124 | link(attacherJoint.jointTransform, attachedVehicleComponentNode) |
2125 | |
2126 | -- link visual and set to correct position |
2127 | if implementJoint.visualNode ~= nil and attacherJoint.jointTransformVisual ~= nil then |
2128 | local dirX, dirY, dirZ = localDirectionToLocal(implementJoint.visualNode, implementJoint.node, 0, 0, 1) |
2129 | local upX, upY, upZ = localDirectionToLocal(implementJoint.visualNode, implementJoint.node, 0, 1, 0) |
2130 | setDirection(implementJoint.visualNode, dirX, dirY, dirZ, upX, upY, upZ) |
2131 | local x,y,z = localToLocal(implementJoint.visualNode, implementJoint.node, 0, 0, 0) |
2132 | setTranslation(implementJoint.visualNode, x, y, z) |
2133 | link(attacherJoint.jointTransformVisual, implementJoint.visualNode) |
2134 | end |
2135 | |
2136 | implement.object.spec_attachable.isHardAttached = true |
2137 | |
2138 | -- add to physics again |
2139 | local currentVehicle = self |
2140 | while currentVehicle ~= nil do |
2141 | currentVehicle:addToPhysics() |
2142 | currentVehicle = currentVehicle.attacherVehicle |
2143 | end |
2144 | |
2145 | -- set new joint rootNodes |
2146 | for _, attacherJoint in pairs(implement.object.spec_attacherJoints.attacherJoints) do |
2147 | attacherJoint.rootNode = self.rootNode |
2148 | end |
2149 | |
2150 | for _, impl in pairs(implements) do |
2151 | implement.object:attachImplement(impl.object, impl.inputJointDescIndex, impl.jointDescIndex, true, impl.implementIndex, impl.moveDown, true) |
2152 | end |
2153 | |
2154 | if self.isServer then |
2155 | self:raiseDirtyFlags(self.vehicleDirtyFlag) |
2156 | end |
2157 | |
2158 | return true |
2159 | end |
hardDetachImplement
DescriptionHard detach implementDefinition
hardDetachImplement(table implement)Arguments
table | implement | implement to detach |
2164 | function AttacherJoints:hardDetachImplement(implement) |
2165 | -- restore original joint rootNode |
2166 | for _, attacherJoint in pairs(implement.object.spec_attacherJoints.attacherJoints) do |
2167 | attacherJoint.rootNode = attacherJoint.rootNodeBackup |
2168 | end |
2169 | |
2170 | local implementJoint = implement.object.spec_attachable.attacherJoint |
2171 | |
2172 | local attachedVehicleComponentNode = implement.object:getParentComponent(implementJoint.node) |
2173 | |
2174 | local currentVehicle = self |
2175 | while currentVehicle ~= nil do |
2176 | currentVehicle:removeFromPhysics() |
2177 | currentVehicle = currentVehicle.attacherVehicle |
2178 | end |
2179 | --implement.object:removeFromPhysics() |
2180 | |
2181 | setIsCompound(attachedVehicleComponentNode, true) |
2182 | |
2183 | local x,y,z = getWorldTranslation(attachedVehicleComponentNode) |
2184 | setTranslation(attachedVehicleComponentNode, x,y,z) |
2185 | local dirX, dirY, dirZ = localDirectionToWorld(implement.object.rootNode, 0, 0, 1) |
2186 | local upX, upY, upZ = localDirectionToWorld(implement.object.rootNode, 0, 1, 0) |
2187 | setDirection(attachedVehicleComponentNode, dirX, dirY, dirZ, upX, upY, upZ) |
2188 | link(getRootNode(), attachedVehicleComponentNode) |
2189 | |
2190 | if implementJoint.visualNode ~= nil and getParent(implementJoint.visualNode) ~= implementJoint.visualNodeData.parent then |
2191 | link(implementJoint.visualNodeData.parent, implementJoint.visualNode, implementJoint.visualNodeData.index) |
2192 | setRotation(implementJoint.visualNode, implementJoint.visualNodeData.rotation[1], implementJoint.visualNodeData.rotation[2], implementJoint.visualNodeData.rotation[3]) |
2193 | setTranslation(implementJoint.visualNode, implementJoint.visualNodeData.translation[1], implementJoint.visualNodeData.translation[2], implementJoint.visualNodeData.translation[3]) |
2194 | end |
2195 | |
2196 | local currentVehicle = self |
2197 | while currentVehicle ~= nil do |
2198 | currentVehicle:addToPhysics() |
2199 | currentVehicle = currentVehicle.attacherVehicle |
2200 | end |
2201 | implement.object:addToPhysics() |
2202 | implement.object.spec_attachable.isHardAttached = false |
2203 | |
2204 | if self.isServer then |
2205 | self:raiseDirtyFlags(self.vehicleDirtyFlag) |
2206 | end |
2207 | |
2208 | return true |
2209 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
23 | function AttacherJoints.initSpecialization() |
24 | g_configurationManager:addConfigurationType("attacherJoint", g_i18n:getText("configuration_attacherJoint"), "attacherJoints", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION) |
25 | |
26 | Vehicle.registerStateChange("ATTACH") |
27 | Vehicle.registerStateChange("DETACH") |
28 | Vehicle.registerStateChange("LOWER_ALL_IMPLEMENTS") |
29 | |
30 | local schema = Vehicle.xmlSchema |
31 | schema:setXMLSpecializationType("AttacherJoints") |
32 | |
33 | AttacherJoints.registerAttacherJointXMLPaths(schema, "vehicle.attacherJoints.attacherJoint(?)") |
34 | AttacherJoints.registerAttacherJointXMLPaths(schema, "vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(?).attacherJoint(?)") |
35 | |
36 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(?)") |
37 | SoundManager.registerSampleXMLPaths(schema, "vehicle.attacherJoints.sounds", "hydraulic") |
38 | SoundManager.registerSampleXMLPaths(schema, "vehicle.attacherJoints.sounds", "attach") |
39 | SoundManager.registerSampleXMLPaths(schema, "vehicle.attacherJoints.sounds", "detach") |
40 | |
41 | schema:register(XMLValueType.FLOAT, "vehicle.attacherJoints#comboDuration", "Combo duration", 2) |
42 | |
43 | schema:register(XMLValueType.INT, "vehicle.attacherJoints#connectionHoseConfigId", "Connection hose configuration index to use") |
44 | schema:register(XMLValueType.INT, "vehicle.attacherJoints#powerTakeOffConfigId", "Power take off configuration index to use") |
45 | schema:register(XMLValueType.INT, "vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(?)#connectionHoseConfigId", "Connection hose configuration index to use") |
46 | schema:register(XMLValueType.INT, "vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(?)#powerTakeOffConfigId", "Power take off configuration index to use") |
47 | |
48 | schema:register(XMLValueType.FLOAT, "vehicle.attacherJoints#maxUpdateDistance", "Max. distance to vehicle root to update attacher joint graphics", AttacherJoints.DEFAULT_MAX_UPDATE_DISTANCE) |
49 | |
50 | schema:register(XMLValueType.VECTOR_N, Dashboard.GROUP_XML_KEY .. "#attacherJointIndices", "Attacher joint indices") |
51 | |
52 | schema:register(XMLValueType.VECTOR_N, Attachable.INPUT_ATTACHERJOINT_XML_KEY .. ".heightNode(?)#disablingAttacherJointIndices", "Attacher joint indices that disable heigth node if something is attached") |
53 | schema:register(XMLValueType.VECTOR_N, Attachable.INPUT_ATTACHERJOINT_CONFIG_XML_KEY .. ".heightNode(?)#disablingAttacherJointIndices", "Attacher joint indices that disable heigth node if something is attached") |
54 | |
55 | schema:setXMLSpecializationType() |
56 | |
57 | local schemaSavegame = Vehicle.xmlSchemaSavegame |
58 | schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).attacherJoints#comboDirection", "Current combo direction") |
59 | |
60 | schemaSavegame:register(XMLValueType.INT, "vehicles.attachments(?)#rootVehicleId", "Root vehicle id") |
61 | schemaSavegame:register(XMLValueType.INT, "vehicles.attachments(?).attachment(?)#attachmentId", "Attachment vehicle id") |
62 | schemaSavegame:register(XMLValueType.INT, "vehicles.attachments(?).attachment(?)#inputJointDescIndex", "Index of input attacher joint", 1) |
63 | schemaSavegame:register(XMLValueType.INT, "vehicles.attachments(?).attachment(?)#jointIndex", "Index of attacher joint") |
64 | schemaSavegame:register(XMLValueType.BOOL, "vehicles.attachments(?).attachment(?)#moveDown", "Attachment lowered or lifted") |
65 | end |
isDetachAllowed
DescriptionReturns true if detach is allowedDefinition
isDetachAllowed()Return Values
boolean | detachAllowed | detach is allowed |
3711 | function AttacherJoints:isDetachAllowed(superFunc) |
3712 | local detachAllowed, warning, showWarning = superFunc(self) |
3713 | if not detachAllowed then |
3714 | return detachAllowed, warning, showWarning |
3715 | end |
3716 | |
3717 | local spec = self.spec_attacherJoints |
3718 | for attacherJointIndex, attacherJoint in ipairs(spec.attacherJoints) do |
3719 | if not attacherJoint.allowDetachingWhileLifted then |
3720 | if not attacherJoint.moveDown then |
3721 | local implement = self:getImplementByJointDescIndex(attacherJointIndex) |
3722 | if implement ~= nil then |
3723 | local inputAttacherJoint = implement.object:getInputAttacherJointByJointDescIndex(implement.inputJointDescIndex) |
3724 | if inputAttacherJoint ~= nil and not inputAttacherJoint.forceAllowDetachWhileLifted then |
3725 | return false, string.format(spec.texts.lowerImplementFirst, implement.object.typeDesc) |
3726 | end |
3727 | end |
3728 | end |
3729 | end |
3730 | end |
3731 | |
3732 | return true |
3733 | end |
loadAttacherJointFromXML
DescriptionLoad attacher joint from xmlDefinition
loadAttacherJointFromXML(table attacherJoint, integer fileId, string baseName, integer index)Arguments
table | attacherJoint | attacherJoint |
integer | fileId | xml file id |
string | baseName | baseName |
integer | index | index of attacher joint |
2851 | function AttacherJoints:loadAttacherJointFromXML(attacherJoint, xmlFile, baseName, index) |
2852 | local spec = self.spec_attacherJoints |
2853 | |
2854 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#index", baseName .. "#node") -- FS17 |
2855 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#indexVisual", baseName .. "#nodeVisual") -- FS17 |
2856 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#ptoOutputNode", "vehicle.powerTakeOffs.output") -- FS17 to FS19 |
2857 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#lowerDistanceToGround", baseName..".distanceToGround#lower") -- FS17 to FS19 |
2858 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#upperDistanceToGround", baseName..".distanceToGround#upper") -- FS17 to FS19 |
2859 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#rotationNode", baseName..".rotationNode#node") -- FS17 to FS19 |
2860 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#upperRotation", baseName..".rotationNode#upperRotation") -- FS17 to FS19 |
2861 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#lowerRotation", baseName..".rotationNode#lowerRotation") -- FS17 to FS19 |
2862 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#startRotation", baseName..".rotationNode#startRotation") -- FS17 to FS19 |
2863 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#rotationNode2", baseName..".rotationNode2#node") -- FS17 to FS19 |
2864 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#upperRotation2", baseName..".rotationNode2#upperRotation") -- FS17 to FS19 |
2865 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#lowerRotation2", baseName..".rotationNode2#lowerRotation") -- FS17 to FS19 |
2866 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#transNode", baseName..".transNode#node") -- FS17 to FS19 |
2867 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#transNodeMinY", baseName..".transNode#minY") -- FS17 to FS19 |
2868 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#transNodeMaxY", baseName..".transNode#maxY") -- FS17 to FS19 |
2869 | XMLUtil.checkDeprecatedXMLElements(xmlFile, baseName .. "#transNodeHeight", baseName..".transNode#height") -- FS17 to FS19 |
2870 | |
2871 | |
2872 | local node = xmlFile:getValue(baseName.. "#node", nil, self.components, self.i3dMappings) |
2873 | if node == nil then |
2874 | Logging.xmlWarning(self.xmlFile, "Missing node for attacherJoint '%s'", baseName) |
2875 | return false |
2876 | end |
2877 | |
2878 | attacherJoint.jointTransform = node |
2879 | attacherJoint.jointComponent = self:getParentComponent(attacherJoint.jointTransform) |
2880 | |
2881 | attacherJoint.jointTransformVisual = xmlFile:getValue(baseName .. "#nodeVisual", nil, self.components, self.i3dMappings) |
2882 | attacherJoint.supportsHardAttach = xmlFile:getValue(baseName.."#supportsHardAttach", true) |
2883 | |
2884 | attacherJoint.jointOrigOffsetComponent = { localToLocal(attacherJoint.jointComponent, attacherJoint.jointTransform, 0, 0, 0) } |
2885 | attacherJoint.jointOrigDirOffsetComponent = { localDirectionToLocal(attacherJoint.jointComponent, attacherJoint.jointTransform, 0, 0, 1) } |
2886 | |
2887 | attacherJoint.jointTransformOrig = createTransformGroup("jointTransformOrig") |
2888 | link(getParent(node), attacherJoint.jointTransformOrig) |
2889 | setTranslation(attacherJoint.jointTransformOrig, getTranslation(node)) |
2890 | setRotation(attacherJoint.jointTransformOrig, getRotation(node)) |
2891 | |
2892 | local jointTypeStr = xmlFile:getValue(baseName.. "#jointType") |
2893 | local jointType |
2894 | if jointTypeStr ~= nil then |
2895 | jointType = AttacherJoints.jointTypeNameToInt[jointTypeStr] |
2896 | if jointType == nil then |
2897 | Logging.xmlWarning(self.xmlFile, "Invalid jointType '%s' for attacherJoint '%s'!", tostring(jointTypeStr), baseName) |
2898 | end |
2899 | end |
2900 | if jointType == nil then |
2901 | jointType = AttacherJoints.JOINTTYPE_IMPLEMENT |
2902 | end |
2903 | attacherJoint.jointType = jointType |
2904 | |
2905 | local subTypeStr = xmlFile:getValue(baseName.. ".subType#name") |
2906 | attacherJoint.subTypes = string.split(subTypeStr, " ") |
2907 | if #attacherJoint.subTypes == 0 then |
2908 | attacherJoint.subTypes = nil |
2909 | end |
2910 | |
2911 | local brandRestrictionStr = xmlFile:getValue(baseName.. ".subType#brandRestriction") |
2912 | attacherJoint.brandRestrictions = string.split(brandRestrictionStr, " ") |
2913 | if #attacherJoint.brandRestrictions == 0 then |
2914 | attacherJoint.brandRestrictions = nil |
2915 | else |
2916 | for i=1, #attacherJoint.brandRestrictions do |
2917 | local brand = g_brandManager:getBrandByName(attacherJoint.brandRestrictions[i]) |
2918 | if brand ~= nil then |
2919 | attacherJoint.brandRestrictions[i] = brand |
2920 | else |
2921 | Logging.xmlError(xmlFile, "Unknown brand '%s' in '%s'", attacherJoint.brandRestrictions[i], baseName.. ".subType#brandRestriction") |
2922 | attacherJoint.brandRestrictions = nil |
2923 | break |
2924 | end |
2925 | end |
2926 | end |
2927 | |
2928 | local vehicleRestrictionStr = xmlFile:getValue(baseName.. ".subType#vehicleRestriction") |
2929 | attacherJoint.vehicleRestrictions = string.split(vehicleRestrictionStr, " ") |
2930 | if #attacherJoint.vehicleRestrictions == 0 then |
2931 | attacherJoint.vehicleRestrictions = nil |
2932 | end |
2933 | |
2934 | attacherJoint.subTypeShowWarning = xmlFile:getValue(baseName.. ".subType#subTypeShowWarning", true) |
2935 | |
2936 | attacherJoint.allowsJointLimitMovement = xmlFile:getValue(baseName.."#allowsJointLimitMovement", true) |
2937 | attacherJoint.allowsLowering = xmlFile:getValue(baseName.."#allowsLowering", true) |
2938 | attacherJoint.isDefaultLowered = xmlFile:getValue(baseName.."#isDefaultLowered", false) |
2939 | |
2940 | attacherJoint.allowDetachingWhileLifted = xmlFile:getValue(baseName.."#allowDetachingWhileLifted", true) |
2941 | attacherJoint.allowFoldingWhileAttached = xmlFile:getValue(baseName.."#allowFoldingWhileAttached", true) |
2942 | |
2943 | if jointType == AttacherJoints.JOINTTYPE_TRAILER or jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then |
2944 | attacherJoint.allowsLowering = false |
2945 | end |
2946 | |
2947 | attacherJoint.canTurnOnImplement = xmlFile:getValue(baseName.."#canTurnOnImplement", true) |
2948 | |
2949 | local rotationNode = xmlFile:getValue(baseName.. ".rotationNode#node", nil, self.components, self.i3dMappings) |
2950 | if rotationNode ~= nil then |
2951 | attacherJoint.rotationNode = rotationNode |
2952 | |
2953 | attacherJoint.lowerRotation = xmlFile:getValue(baseName..".rotationNode#lowerRotation", "0 0 0", true) |
2954 | attacherJoint.upperRotation = xmlFile:getValue(baseName..".rotationNode#upperRotation", {getRotation(rotationNode)}, true) |
2955 | attacherJoint.rotX, attacherJoint.rotY, attacherJoint.rotZ = xmlFile:getValue(baseName..".rotationNode#startRotation", {getRotation(rotationNode)}) |
2956 | |
2957 | local lowerValues = {attacherJoint.lowerRotation[1], attacherJoint.lowerRotation[2], attacherJoint.lowerRotation[3]} |
2958 | local upperValues = {attacherJoint.upperRotation[1], attacherJoint.upperRotation[2], attacherJoint.upperRotation[3]} |
2959 | |
2960 | for i=1, 3 do |
2961 | local l = lowerValues[i] |
2962 | local u = upperValues[i] |
2963 | |
2964 | if l > u then |
2965 | upperValues[i] = l |
2966 | lowerValues[i] = u |
2967 | end |
2968 | end |
2969 | |
2970 | attacherJoint.rotX = MathUtil.clamp(attacherJoint.rotX, lowerValues[1], upperValues[1]) |
2971 | attacherJoint.rotY = MathUtil.clamp(attacherJoint.rotY, lowerValues[2], upperValues[2]) |
2972 | attacherJoint.rotZ = MathUtil.clamp(attacherJoint.rotZ, lowerValues[3], upperValues[3]) |
2973 | end |
2974 | |
2975 | local rotationNode2 = xmlFile:getValue(baseName.. ".rotationNode2#node", nil, self.components, self.i3dMappings) |
2976 | if rotationNode2 ~= nil then |
2977 | attacherJoint.rotationNode2 = rotationNode2 |
2978 | |
2979 | local defaultLowerRotation2 = {-attacherJoint.lowerRotation[1], -attacherJoint.lowerRotation[2], -attacherJoint.lowerRotation[3]} |
2980 | attacherJoint.lowerRotation2 = xmlFile:getValue(baseName..".rotationNode2#lowerRotation", defaultLowerRotation2, true) |
2981 | |
2982 | local defaultUpperRotation2 = {-attacherJoint.upperRotation[1], -attacherJoint.upperRotation[2], -attacherJoint.upperRotation[3]} |
2983 | attacherJoint.upperRotation2 = xmlFile:getValue(baseName..".rotationNode2#upperRotation", defaultUpperRotation2, true) |
2984 | end |
2985 | |
2986 | attacherJoint.transNode = xmlFile:getValue(baseName..".transNode#node", nil, self.components, self.i3dMappings) |
2987 | if attacherJoint.transNode ~= nil then |
2988 | attacherJoint.transNodeOrgTrans = {getTranslation(attacherJoint.transNode)} |
2989 | attacherJoint.transNodeHeight = xmlFile:getValue(baseName..".transNode#height", 0.12) |
2990 | attacherJoint.transNodeMinY = xmlFile:getValue(baseName..".transNode#minY") |
2991 | attacherJoint.transNodeMaxY = xmlFile:getValue(baseName..".transNode#maxY") |
2992 | |
2993 | attacherJoint.transNodeDependentBottomArm = xmlFile:getValue(baseName..".transNode.dependentBottomArm#node", nil, self.components, self.i3dMappings) |
2994 | attacherJoint.transNodeDependentBottomArmThreshold = xmlFile:getValue(baseName..".transNode.dependentBottomArm#threshold", math.huge) |
2995 | attacherJoint.transNodeDependentBottomArmRotation = xmlFile:getValue(baseName..".transNode.dependentBottomArm#rotation", "0 0 0", true) |
2996 | end |
2997 | |
2998 | -- lowerDistanceToGround is a mandatory attribute if a rotationNode is available |
2999 | if (attacherJoint.rotationNode ~= nil or attacherJoint.transNode ~= nil) and xmlFile:getValue(baseName..".distanceToGround#lower") == nil then |
3000 | Logging.xmlWarning(self.xmlFile, "Missing '.distanceToGround#lower' for attacherJoint '%s'. Use console command 'gsVehicleAnalyze' to get correct values!", baseName) |
3001 | end |
3002 | attacherJoint.lowerDistanceToGround = xmlFile:getValue(baseName..".distanceToGround#lower", 0.7) |
3003 | |
3004 | -- upperDistanceToGround is a mandatory attribute if a rotationNode is available |
3005 | if (attacherJoint.rotationNode ~= nil or attacherJoint.transNode ~= nil) and xmlFile:getValue(baseName..".distanceToGround#upper") == nil then |
3006 | Logging.xmlWarning(self.xmlFile, "Missing '.distanceToGround#upper' for attacherJoint '%s'. Use console command 'gsVehicleAnalyze' to get correct values!", baseName) |
3007 | end |
3008 | attacherJoint.upperDistanceToGround = xmlFile:getValue(baseName..".distanceToGround#upper", 1.0) |
3009 | |
3010 | if attacherJoint.lowerDistanceToGround > attacherJoint.upperDistanceToGround then |
3011 | Logging.xmlWarning(self.xmlFile, "distanceToGround#lower may not be larger than distanceToGround#upper for attacherJoint '%s'. Switching values!", baseName) |
3012 | local copy = attacherJoint.lowerDistanceToGround |
3013 | attacherJoint.lowerDistanceToGround = attacherJoint.upperDistanceToGround |
3014 | attacherJoint.upperDistanceToGround = copy |
3015 | end |
3016 | |
3017 | attacherJoint.lowerRotationOffset = xmlFile:getValue(baseName.."#lowerRotationOffset", 0) |
3018 | attacherJoint.upperRotationOffset = xmlFile:getValue(baseName.."#upperRotationOffset", 0) |
3019 | |
3020 | attacherJoint.lockDownRotLimit = xmlFile:getValue(baseName.."#lockDownRotLimit", false) |
3021 | attacherJoint.lockUpRotLimit = xmlFile:getValue(baseName.."#lockUpRotLimit", false) |
3022 | -- only use translimit in +y. Set -y to 0 |
3023 | attacherJoint.lockDownTransLimit = xmlFile:getValue(baseName.."#lockDownTransLimit", true) |
3024 | attacherJoint.lockUpTransLimit = xmlFile:getValue(baseName.."#lockUpTransLimit", false) |
3025 | |
3026 | local lowerRotLimitStr = "20 20 20" |
3027 | if jointType ~= AttacherJoints.JOINTTYPE_IMPLEMENT then |
3028 | lowerRotLimitStr = "0 0 0" |
3029 | end |
3030 | local lx, ly, lz = xmlFile:getValue(baseName.."#lowerRotLimit", lowerRotLimitStr) |
3031 | attacherJoint.lowerRotLimit = {} |
3032 | attacherJoint.lowerRotLimit[1] = math.abs(Utils.getNoNil(lx, 20)) |
3033 | attacherJoint.lowerRotLimit[2] = math.abs(Utils.getNoNil(ly, 20)) |
3034 | attacherJoint.lowerRotLimit[3] = math.abs(Utils.getNoNil(lz, 20)) |
3035 | local ux, uy, uz = xmlFile:getValue(baseName.."#upperRotLimit") |
3036 | attacherJoint.upperRotLimit = {} |
3037 | attacherJoint.upperRotLimit[1] = math.abs(Utils.getNoNil(Utils.getNoNil(ux, lx), 20)) |
3038 | attacherJoint.upperRotLimit[2] = math.abs(Utils.getNoNil(Utils.getNoNil(uy, ly), 20)) |
3039 | attacherJoint.upperRotLimit[3] = math.abs(Utils.getNoNil(Utils.getNoNil(uz, lz), 20)) |
3040 | |
3041 | local lowerTransLimitStr = "0.5 0.5 0.5" |
3042 | if jointType ~= AttacherJoints.JOINTTYPE_IMPLEMENT then |
3043 | lowerTransLimitStr = "0 0 0" |
3044 | end |
3045 | lx, ly, lz = xmlFile:getValue(baseName.."#lowerTransLimit", lowerTransLimitStr) |
3046 | attacherJoint.lowerTransLimit = {} |
3047 | attacherJoint.lowerTransLimit[1] = math.abs(Utils.getNoNil(lx, 0)) |
3048 | attacherJoint.lowerTransLimit[2] = math.abs(Utils.getNoNil(ly, 0)) |
3049 | attacherJoint.lowerTransLimit[3] = math.abs(Utils.getNoNil(lz, 0)) |
3050 | ux, uy, uz = xmlFile:getValue(baseName.."#upperTransLimit") |
3051 | attacherJoint.upperTransLimit = {} |
3052 | attacherJoint.upperTransLimit[1] = math.abs(Utils.getNoNil(Utils.getNoNil(ux, lx), 0)) |
3053 | attacherJoint.upperTransLimit[2] = math.abs(Utils.getNoNil(Utils.getNoNil(uy, ly), 0)) |
3054 | attacherJoint.upperTransLimit[3] = math.abs(Utils.getNoNil(Utils.getNoNil(uz, lz), 0)) |
3055 | |
3056 | |
3057 | attacherJoint.jointPositionOffset = xmlFile:getValue(baseName.."#jointPositionOffset", "0 0 0", true) |
3058 | |
3059 | attacherJoint.rotLimitSpring = xmlFile:getValue( baseName.."#rotLimitSpring", "0 0 0", true) |
3060 | attacherJoint.rotLimitDamping = xmlFile:getValue( baseName.."#rotLimitDamping", "1 1 1", true) |
3061 | attacherJoint.rotLimitForceLimit = xmlFile:getValue( baseName.."#rotLimitForceLimit", "-1 -1 -1", true) |
3062 | |
3063 | attacherJoint.transLimitSpring = xmlFile:getValue( baseName.."#transLimitSpring", "0 0 0", true) |
3064 | attacherJoint.transLimitDamping = xmlFile:getValue( baseName.."#transLimitDamping", "1 1 1", true) |
3065 | attacherJoint.transLimitForceLimit = xmlFile:getValue( baseName.."#transLimitForceLimit", "-1 -1 -1", true) |
3066 | |
3067 | attacherJoint.moveDefaultTime = xmlFile:getValue(baseName.."#moveTime", 0.5) * 1000 |
3068 | attacherJoint.moveTime = attacherJoint.moveDefaultTime |
3069 | |
3070 | attacherJoint.disabledByAttacherJoints = xmlFile:getValue(baseName.."#disabledByAttacherJoints", nil, true) |
3071 | |
3072 | attacherJoint.enableCollision = xmlFile:getValue(baseName.."#enableCollision", false) |
3073 | |
3074 | local topArmFilename = xmlFile:getValue(baseName.. ".topArm#filename") |
3075 | if topArmFilename ~= nil then |
3076 | local baseNode = xmlFile:getValue(baseName.. ".topArm#baseNode", nil, self.components, self.i3dMappings) |
3077 | if baseNode ~= nil then |
3078 | topArmFilename = Utils.getFilename(topArmFilename, self.baseDirectory) |
3079 | local arguments = { |
3080 | xmlFile = xmlFile, |
3081 | baseName = baseName, |
3082 | attacherJoint = attacherJoint, |
3083 | baseNode = baseNode |
3084 | } |
3085 | |
3086 | attacherJoint.sharedLoadRequestIdTopArm = self:loadSubSharedI3DFile(topArmFilename, false, false, self.onTopArmI3DLoaded, self, arguments) |
3087 | end |
3088 | else |
3089 | local topArmRotationNode = xmlFile:getValue(baseName.. ".topArm#rotationNode", nil, self.components, self.i3dMappings) |
3090 | local translationNode = xmlFile:getValue(baseName.. ".topArm#translationNode", nil, self.components, self.i3dMappings) |
3091 | local referenceNode = xmlFile:getValue(baseName.. ".topArm#referenceNode", nil, self.components, self.i3dMappings) |
3092 | if topArmRotationNode ~= nil then |
3093 | local topArm = {} |
3094 | topArm.rotationNode = topArmRotationNode |
3095 | topArm.rotX, topArm.rotY, topArm.rotZ = getRotation(topArmRotationNode) |
3096 | if translationNode ~= nil and referenceNode ~= nil then |
3097 | topArm.translationNode = translationNode |
3098 | |
3099 | local x,y,z = getTranslation(translationNode) |
3100 | if math.abs(x) >= 0.0001 or math.abs(y) >= 0.0001 or math.abs(z) >= 0.0001 then |
3101 | Logging.xmlWarning(self.xmlFile, "TopArm translation of attacherJoint '%s' is not 0/0/0!", baseName) |
3102 | end |
3103 | topArm.referenceDistance = calcDistanceFrom(referenceNode, translationNode) |
3104 | end |
3105 | topArm.zScale = MathUtil.sign(xmlFile:getValue(baseName.. ".topArm#zScale", 1)) |
3106 | topArm.toggleVisibility = xmlFile:getValue(baseName.. ".topArm#toggleVisibility", false) |
3107 | if topArm.toggleVisibility then |
3108 | setVisibility(topArm.rotationNode, false) |
3109 | end |
3110 | |
3111 | attacherJoint.topArm = topArm |
3112 | end |
3113 | end |
3114 | |
3115 | local bottomArmRotationNode = xmlFile:getValue(baseName.. ".bottomArm#rotationNode", nil, self.components, self.i3dMappings) |
3116 | local translationNode = xmlFile:getValue(baseName.. ".bottomArm#translationNode", nil, self.components, self.i3dMappings) |
3117 | local referenceNode = xmlFile:getValue(baseName.. ".bottomArm#referenceNode", nil, self.components, self.i3dMappings) |
3118 | if bottomArmRotationNode ~= nil then |
3119 | local bottomArm = {} |
3120 | bottomArm.rotationNode = bottomArmRotationNode |
3121 | bottomArm.rotationNodeDir = createTransformGroup("rotationNodeDirTemp") |
3122 | link(getParent(bottomArmRotationNode), bottomArm.rotationNodeDir) |
3123 | setTranslation(bottomArm.rotationNodeDir, getTranslation(bottomArmRotationNode)) |
3124 | setRotation(bottomArm.rotationNodeDir, getRotation(bottomArmRotationNode)) |
3125 | bottomArm.lastDirection = {0, 0, 0} |
3126 | bottomArm.rotX, bottomArm.rotY, bottomArm.rotZ = xmlFile:getValue(baseName..".bottomArm#startRotation", {getRotation(bottomArmRotationNode)}) |
3127 | |
3128 | bottomArm.interpolatorGet = function() |
3129 | return getRotation(bottomArm.rotationNode) |
3130 | end |
3131 | bottomArm.interpolatorSet = function(x, y, z) |
3132 | setRotation(bottomArm.rotationNode, x, y, z) |
3133 | if self.setMovingToolDirty ~= nil then |
3134 | self:setMovingToolDirty(bottomArm.rotationNode) |
3135 | end |
3136 | end |
3137 | bottomArm.interpolatorFinished = function(_) |
3138 | bottomArm.bottomArmInterpolating = false |
3139 | end |
3140 | |
3141 | bottomArm.interpolatorKey = bottomArmRotationNode .. "rotation" |
3142 | bottomArm.bottomArmInterpolating = false |
3143 | |
3144 | if translationNode ~= nil and referenceNode ~= nil then |
3145 | bottomArm.translationNode = translationNode |
3146 | |
3147 | local x,y,z = getTranslation(translationNode) |
3148 | if math.abs(x) >= 0.0001 or math.abs(y) >= 0.0001 or math.abs(z) >= 0.0001 then |
3149 | Logging.xmlWarning(self.xmlFile, "BottomArm translation of attacherJoint '%s' is not 0/0/0!", baseName) |
3150 | end |
3151 | bottomArm.referenceDistance = calcDistanceFrom(referenceNode, translationNode) |
3152 | end |
3153 | bottomArm.zScale = MathUtil.sign(xmlFile:getValue(baseName.. ".bottomArm#zScale", 1)) |
3154 | bottomArm.lockDirection = xmlFile:getValue(baseName.. ".bottomArm#lockDirection", true) |
3155 | bottomArm.resetSpeed = xmlFile:getValue(baseName.. ".bottomArm#resetSpeed", 45) |
3156 | |
3157 | bottomArm.toggleVisibility = xmlFile:getValue(baseName.. ".bottomArm#toggleVisibility", false) |
3158 | if bottomArm.toggleVisibility then |
3159 | setVisibility(bottomArm.rotationNode, false) |
3160 | end |
3161 | |
3162 | if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT then |
3163 | local toolbarI3dFilename = Utils.getFilename(xmlFile:getValue(baseName.. ".toolbar#filename", "$data/shared/assets/toolbar.i3d"), self.baseDirectory) |
3164 | local arguments = { |
3165 | bottomArm = bottomArm, |
3166 | referenceNode = referenceNode |
3167 | } |
3168 | bottomArm.sharedLoadRequestIdToolbar = self:loadSubSharedI3DFile(toolbarI3dFilename, false, false, self.onBottomArmToolbarI3DLoaded, self, arguments) |
3169 | end |
3170 | |
3171 | attacherJoint.bottomArm = bottomArm |
3172 | end |
3173 | |
3174 | if self.isClient then |
3175 | attacherJoint.sampleAttach = g_soundManager:loadSampleFromXML(xmlFile, baseName, "attachSound", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
3176 | attacherJoint.sampleDetach = g_soundManager:loadSampleFromXML(xmlFile, baseName, "detachSound", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
3177 | end |
3178 | |
3179 | attacherJoint.steeringBarLeftNode = xmlFile:getValue(baseName.. ".steeringBars#leftNode", nil, self.components, self.i3dMappings) |
3180 | attacherJoint.steeringBarRightNode = xmlFile:getValue(baseName.. ".steeringBars#rightNode", nil, self.components, self.i3dMappings) |
3181 | attacherJoint.steeringBarForceUsage = xmlFile:getValue(baseName.. ".steeringBars#forceUsage", true) |
3182 | |
3183 | attacherJoint.visualNodes = xmlFile:getValue(baseName.. ".visuals#nodes", nil, self.components, self.i3dMappings, true) |
3184 | for i=1, #attacherJoint.visualNodes do |
3185 | local visualNode = attacherJoint.visualNodes[i] |
3186 | |
3187 | if spec.visualNodeToAttacherJoints[visualNode] == nil then |
3188 | spec.visualNodeToAttacherJoints[visualNode] = {} |
3189 | end |
3190 | |
3191 | table.insert(spec.visualNodeToAttacherJoints[visualNode], attacherJoint) |
3192 | end |
3193 | |
3194 | attacherJoint.hideVisuals = xmlFile:getValue(baseName.. ".visuals#hide", nil, self.components, self.i3dMappings, true) |
3195 | for i=1, #attacherJoint.hideVisuals do |
3196 | local hideNode = attacherJoint.hideVisuals[i] |
3197 | |
3198 | if spec.hideVisualNodeToAttacherJoints[hideNode] == nil then |
3199 | spec.hideVisualNodeToAttacherJoints[hideNode] = {} |
3200 | end |
3201 | |
3202 | table.insert(spec.hideVisualNodeToAttacherJoints[hideNode], attacherJoint) |
3203 | end |
3204 | |
3205 | attacherJoint.changeObjects = {} |
3206 | ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, baseName, attacherJoint.changeObjects, self.components, self) |
3207 | ObjectChangeUtil.setObjectChanges(attacherJoint.changeObjects, false, self, self.setMovingToolDirty, true) |
3208 | attacherJoint.delayedObjectChanges = xmlFile:getValue(baseName.."#delayedObjectChanges", true) |
3209 | attacherJoint.delayedObjectChangesOnAttach = xmlFile:getValue(baseName.."#delayedObjectChangesOnAttach", false) |
3210 | |
3211 | attacherJoint.additionalAttachment = {} |
3212 | attacherJoint.additionalAttachment.attacherJointDirection = xmlFile:getValue(baseName..".additionalAttachment#attacherJointDirection") |
3213 | |
3214 | attacherJoint.rootNode = xmlFile:getValue(baseName.."#rootNode", self.components[1].node, self.components, self.i3dMappings) |
3215 | attacherJoint.rootNodeBackup = attacherJoint.rootNode |
3216 | attacherJoint.jointIndex = 0 |
3217 | |
3218 | attacherJoint.comboTime = xmlFile:getValue(baseName .. "#comboTime") |
3219 | |
3220 | local schemaKey = baseName.. ".schema" |
3221 | if xmlFile:hasProperty(schemaKey) then |
3222 | local x, y = xmlFile:getValue(schemaKey .. "#position") |
3223 | local liftedOffsetX, liftedOffsetY = xmlFile:getValue(schemaKey.."#liftedOffset", "0 5") |
3224 | |
3225 | self.schemaOverlay:addAttacherJoint(x, y, |
3226 | xmlFile:getValue(schemaKey .. "#rotation", 0), |
3227 | xmlFile:getValue(schemaKey .. "#invertX", false), |
3228 | liftedOffsetX, liftedOffsetY) |
3229 | else |
3230 | Logging.xmlWarning(self.xmlFile, "Missing schema overlay attacherJoint '%s'!", baseName) |
3231 | end |
3232 | |
3233 | return true |
3234 | end |
loadAttacherJointHeightNode
DescriptionDefinitionloadAttacherJointHeightNode()Code
3690 | function AttacherJoints:loadAttacherJointHeightNode(superFunc, xmlFile, key, heightNode, attacherJointNode) |
3691 | heightNode.disablingAttacherJointIndices = xmlFile:getValue(key .. "#disablingAttacherJointIndices", "", true) |
3692 | |
3693 | return superFunc(self, xmlFile, key, heightNode, attacherJointNode) |
3694 | end |
loadAttachmentsFinished
DescriptionCalled after all attachments were loadedDefinition
loadAttachmentsFinished()Code
1036 | function AttacherJoints:loadAttachmentsFinished() |
1037 | -- apply loaded selection from savegame after all implemented were attached |
1038 | if self.rootVehicle == self then |
1039 | if self.loadedSelectedObjectIndex ~= nil then |
1040 | local object = self.selectableObjects[self.loadedSelectedObjectIndex] |
1041 | if object ~= nil then |
1042 | self:setSelectedObject(object, self.loadedSubSelectedObjectIndex or 1) |
1043 | end |
1044 | |
1045 | self.loadedSelectedObjectIndex = nil |
1046 | self.loadedSubSelectedObjectIndex = nil |
1047 | end |
1048 | end |
1049 | end |
loadAttachmentsFromXMLFile
DescriptionLoads attachment from key from xmlDefinition
loadAttachmentsFromXMLFile(table xmlFile, string key, table idsToVehicle)Arguments
table | xmlFile | xml file object |
string | key | key |
table | idsToVehicle | id to vehicle mapping |
994 | function AttacherJoints:loadAttachmentsFromXMLFile(xmlFile, key, idsToVehicle) |
995 | local spec = self.spec_attacherJoints |
996 | |
997 | local i = 0 |
998 | while true do |
999 | local attachmentKey = string.format("%s.attachment(%d)", key, i) |
1000 | if not xmlFile:hasProperty(attachmentKey) then |
1001 | break |
1002 | end |
1003 | |
1004 | local attachmentId = xmlFile:getValue(attachmentKey.."#attachmentId") |
1005 | local jointIndex = xmlFile:getValue(attachmentKey.."#jointIndex") |
1006 | local inputJointDescIndex = xmlFile:getValue(attachmentKey.."#inputJointDescIndex", 1) |
1007 | if attachmentId ~= nil and jointIndex ~= nil then |
1008 | local attachment = idsToVehicle[attachmentId] |
1009 | |
1010 | local inputAttacherJoints |
1011 | if attachment ~= nil and attachment.getInputAttacherJoints ~= nil then |
1012 | inputAttacherJoints = attachment:getInputAttacherJoints() |
1013 | end |
1014 | local inputAttacherJoint |
1015 | if inputAttacherJoints ~= nil then |
1016 | inputAttacherJoint = inputAttacherJoints[inputJointDescIndex] |
1017 | end |
1018 | |
1019 | if inputAttacherJoint ~= nil and spec.attacherJoints[jointIndex] ~= nil and spec.attacherJoints[jointIndex].jointIndex == 0 then |
1020 | local moveDown = xmlFile:getValue(attachmentKey.."#moveDown") |
1021 | |
1022 | self:attachImplement(attachment, inputJointDescIndex, jointIndex, true, nil, moveDown, true, true) |
1023 | |
1024 | if moveDown ~= nil then |
1025 | self:setJointMoveDown(jointIndex, moveDown, true) |
1026 | end |
1027 | end |
1028 | end |
1029 | |
1030 | i = i + 1 |
1031 | end |
1032 | end |
loadDashboardGroupFromXML
DescriptionDefinitionloadDashboardGroupFromXML()Code
3665 | function AttacherJoints:loadDashboardGroupFromXML(superFunc, xmlFile, key, group) |
3666 | if not superFunc(self, xmlFile, key, group) then |
3667 | return false |
3668 | end |
3669 | |
3670 | group.attacherJointIndices = xmlFile:getValue(key .. "#attacherJointIndices", "", true) |
3671 | |
3672 | return true |
3673 | end |
onActivate
DescriptionCalled on activateDefinition
onActivate()Code
3880 | function AttacherJoints:onActivate() |
3881 | self:activateAttachments() |
3882 | end |
onBeaconLightsVisibilityChanged
DescriptionDefinitiononBeaconLightsVisibilityChanged()Code
3975 | function AttacherJoints:onBeaconLightsVisibilityChanged(visibility) |
3976 | local spec = self.spec_attacherJoints |
3977 | for _, implement in pairs(spec.attachedImplements) do |
3978 | local vehicle = implement.object |
3979 | if vehicle ~= nil and vehicle.setBeaconLightsVisibility ~= nil then |
3980 | vehicle:setBeaconLightsVisibility(visibility, true, true) |
3981 | end |
3982 | end |
3983 | end |
onBottomArmToolbarI3DLoaded
DescriptionCalled when toolbar was loadedDefinition
onBottomArmToolbarI3DLoaded(integer i3dNode, table args)Arguments
integer | i3dNode | top arm i3d node |
table | args | async arguments |
3346 | function AttacherJoints:onBottomArmToolbarI3DLoaded(i3dNode, failedReason, args) |
3347 | local bottomArm = args.bottomArm |
3348 | local referenceNode = args.referenceNode |
3349 | |
3350 | if i3dNode ~= 0 then |
3351 | local rootNode = getChildAt(i3dNode, 0) |
3352 | link(referenceNode, rootNode) |
3353 | delete(i3dNode) |
3354 | setTranslation(rootNode, 0,0,0) |
3355 | bottomArm.toolbar = rootNode |
3356 | setVisibility(rootNode, false) |
3357 | end |
3358 | end |
onBrake
DescriptionDefinitiononBrake()Code
3987 | function AttacherJoints:onBrake(brakePedal) |
3988 | local spec = self.spec_attacherJoints |
3989 | for _, implement in pairs(spec.attachedImplements) do |
3990 | local vehicle = implement.object |
3991 | if vehicle ~= nil and vehicle.brake ~= nil then |
3992 | vehicle:brake(brakePedal) |
3993 | end |
3994 | end |
3995 | end |
onBrakeLightsVisibilityChanged
DescriptionDefinitiononBrakeLightsVisibilityChanged()Code
3951 | function AttacherJoints:onBrakeLightsVisibilityChanged(visibility) |
3952 | local spec = self.spec_attacherJoints |
3953 | for _, implement in pairs(spec.attachedImplements) do |
3954 | local vehicle = implement.object |
3955 | if vehicle ~= nil and vehicle.setBrakeLightsVisibility ~= nil then |
3956 | vehicle:setBrakeLightsVisibility(visibility) |
3957 | end |
3958 | end |
3959 | end |
onDeactivate
DescriptionCalled on deactivateDefinition
onDeactivate()Code
3886 | function AttacherJoints:onDeactivate() |
3887 | self:deactivateAttachments() |
3888 | if self.isClient then |
3889 | local spec = self.spec_attacherJoints |
3890 | g_soundManager:stopSample(spec.samples.hydraulic) |
3891 | spec.isHydraulicSamplePlaying = false |
3892 | end |
3893 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
617 | function AttacherJoints:onDelete() |
618 | local spec = self.spec_attacherJoints |
619 | |
620 | if spec.attacherJoints ~= nil then |
621 | for _, jointDesc in pairs(spec.attacherJoints) do |
622 | g_soundManager:deleteSample(jointDesc.sampleAttach) |
623 | g_soundManager:deleteSample(jointDesc.sampleDetach) |
624 | |
625 | if jointDesc.sharedLoadRequestIdTopArm ~= nil then |
626 | g_i3DManager:releaseSharedI3DFile(jointDesc.sharedLoadRequestIdTopArm) |
627 | jointDesc.sharedLoadRequestIdTopArm = nil |
628 | end |
629 | |
630 | local bottomArm = jointDesc.bottomArm |
631 | if bottomArm ~= nil then |
632 | if bottomArm.sharedLoadRequestIdToolbar ~= nil then |
633 | g_i3DManager:releaseSharedI3DFile(bottomArm.sharedLoadRequestIdToolbar) |
634 | bottomArm.sharedLoadRequestIdToolbar = nil |
635 | end |
636 | end |
637 | end |
638 | |
639 | g_soundManager:deleteSamples(spec.samples) |
640 | end |
641 | end |
onLeaveVehicle
DescriptionDefinitiononLeaveVehicle()Code
4033 | function AttacherJoints:onLeaveVehicle() |
4034 | local spec = self.spec_attacherJoints |
4035 | for _, implement in pairs(spec.attachedImplements) do |
4036 | local vehicle = implement.object |
4037 | if vehicle ~= nil then |
4038 | SpecializationUtil.raiseEvent(vehicle, "onLeaveRootVehicle") |
4039 | end |
4040 | end |
4041 | end |
onLightsTypesMaskChanged
DescriptionDefinitiononLightsTypesMaskChanged()Code
3927 | function AttacherJoints:onLightsTypesMaskChanged(lightsTypesMask) |
3928 | local spec = self.spec_attacherJoints |
3929 | for _, implement in pairs(spec.attachedImplements) do |
3930 | local vehicle = implement.object |
3931 | if vehicle ~= nil and vehicle.setLightsTypesMask ~= nil then |
3932 | vehicle:setLightsTypesMask(lightsTypesMask, true, true) |
3933 | end |
3934 | end |
3935 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
382 | function AttacherJoints:onLoad(savegame) |
383 | local spec = self.spec_attacherJoints |
384 | |
385 | spec.attacherJointCombos = {} |
386 | spec.attacherJointCombos.duration = self.xmlFile:getValue("vehicle.attacherJoints#comboDuration", 2) * 1000 |
387 | spec.attacherJointCombos.currentTime = 0 |
388 | spec.attacherJointCombos.direction = -1 |
389 | spec.attacherJointCombos.isRunning = false |
390 | spec.attacherJointCombos.joints = {} |
391 | |
392 | spec.maxUpdateDistance = self.xmlFile:getValue("vehicle.attacherJoints#maxUpdateDistance", AttacherJoints.DEFAULT_MAX_UPDATE_DISTANCE) |
393 | |
394 | spec.visualNodeToAttacherJoints = {} |
395 | spec.hideVisualNodeToAttacherJoints = {} |
396 | |
397 | spec.attacherJoints = {} |
398 | local i = 0 |
399 | while true do |
400 | local baseName = string.format("vehicle.attacherJoints.attacherJoint(%d)", i) |
401 | if not self.xmlFile:hasProperty(baseName) then |
402 | break |
403 | end |
404 | local attacherJoint = {} |
405 | if self:loadAttacherJointFromXML(attacherJoint, self.xmlFile, baseName, i) then |
406 | table.insert(spec.attacherJoints, attacherJoint) |
407 | attacherJoint.index = #spec.attacherJoints |
408 | end |
409 | i = i + 1 |
410 | end |
411 | |
412 | if self.configurations["attacherJoint"] ~= nil then |
413 | local attacherConfigs = string.format("vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(%d)", self.configurations["attacherJoint"]-1) |
414 | i = 0 |
415 | while true do |
416 | local baseName = string.format(attacherConfigs..".attacherJoint(%d)", i) |
417 | if not self.xmlFile:hasProperty(baseName) then |
418 | break |
419 | end |
420 | local attacherJoint = {} |
421 | if self:loadAttacherJointFromXML(attacherJoint, self.xmlFile, baseName, i) then |
422 | table.insert(spec.attacherJoints, attacherJoint) |
423 | end |
424 | i = i + 1 |
425 | end |
426 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration", self.configurations["attacherJoint"], self.components, self) |
427 | end |
428 | |
429 | -- data structure to store information about eventually attachable vehicles |
430 | spec.attachableInfo = {} |
431 | spec.attachableInfo.attacherVehicle = nil |
432 | spec.attachableInfo.attacherVehicleJointDescIndex = nil |
433 | spec.attachableInfo.attachable = nil |
434 | spec.attachableInfo.attachableJointDescIndex = nil |
435 | |
436 | spec.pendingAttachableInfo = {} |
437 | spec.pendingAttachableInfo.minDistance = math.huge |
438 | spec.pendingAttachableInfo.minDistanceY = math.huge |
439 | spec.pendingAttachableInfo.attacherVehicle = nil |
440 | spec.pendingAttachableInfo.attacherVehicleJointDescIndex = nil |
441 | spec.pendingAttachableInfo.attachable = nil |
442 | spec.pendingAttachableInfo.attachableJointDescIndex = nil |
443 | spec.pendingAttachableInfo.warning = nil |
444 | |
445 | if self.isClient then |
446 | spec.samples = {} |
447 | spec.isHydraulicSamplePlaying = false |
448 | spec.samples.hydraulic = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.attacherJoints.sounds", "hydraulic", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
449 | spec.samples.attach = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.attacherJoints.sounds", "attach", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
450 | spec.samples.detach = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.attacherJoints.sounds", "detach", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
451 | end |
452 | |
453 | if self.isClient and g_isDevelopmentVersion then |
454 | for k, attacherJoint in ipairs(spec.attacherJoints) do |
455 | if spec.samples.attach == nil and attacherJoint.sampleAttach == nil then |
456 | Logging.xmlDevWarning(self.xmlFile, "Missing attach sound for attacherjoint '%d'", k) |
457 | end |
458 | if attacherJoint.rotationNode ~= nil and spec.samples.hydraulic == nil then |
459 | Logging.xmlDevWarning(self.xmlFile, "Missing hydraulic sound for attacherjoint '%d'", k) |
460 | end |
461 | end |
462 | end |
463 | |
464 | spec.showAttachNotAllowedText = 0 |
465 | spec.wasInAttachRange = false |
466 | |
467 | spec.texts = {} |
468 | spec.texts.warningToolNotCompatible = g_i18n:getText("warning_toolNotCompatible") |
469 | spec.texts.warningToolBrandNotCompatible = g_i18n:getText("warning_toolBrandNotCompatible") |
470 | spec.texts.infoAttachNotAllowed = g_i18n:getText("info_attach_not_allowed") |
471 | spec.texts.lowerImplementFirst = g_i18n:getText("warning_lowerImplementFirst") |
472 | spec.texts.detachNotAllowed = g_i18n:getText("warning_detachNotAllowed") |
473 | spec.texts.actionAttach = g_i18n:getText("action_attach") |
474 | spec.texts.actionDetach = g_i18n:getText("action_detach") |
475 | spec.texts.warningFoldingAttacherJoint = g_i18n:getText("warning_foldingNotWhileAttachedToAttacherJoint") |
476 | |
477 | spec.groundHeightNodeCheckData = { |
478 | isDirty = false, |
479 | minDistance = math.huge, |
480 | hit = false, |
481 | raycastDistance = 1, |
482 | currentRaycastDistance = 1, |
483 | heightNodes = {}, |
484 | jointDesc = {}, |
485 | index = -1, |
486 | lowerDistanceToGround = 0, |
487 | upperDistanceToGround = 0, |
488 | currentRaycastWorldPos = {0, 0, 0}, |
489 | currentRaycastWorldDir = {0, 0, 0}, |
490 | currentJointTransformPos = {0, 0, 0}, |
491 | raycastWorldPos = {0, 0, 0}, |
492 | raycastWorldDir = {0, 0, 0}, |
493 | jointTransformPos = {0, 0, 0}, |
494 | upperAlpha = 0, |
495 | lowerAlpha = 0, |
496 | } |
497 | |
498 | spec.dirtyFlag = self:getNextDirtyFlag() |
499 | end |
onPostLoad
DescriptionCalled after loadingDefinition
onPostLoad(table savegame)Arguments
table | savegame | savegame |
504 | function AttacherJoints:onPostLoad(savegame) |
505 | local spec = self.spec_attacherJoints |
506 | |
507 | for attacherJointIndex, attacherJoint in pairs(spec.attacherJoints) do |
508 | attacherJoint.jointOrigRot = { getRotation(attacherJoint.jointTransform) } |
509 | attacherJoint.jointOrigTrans = { getTranslation(attacherJoint.jointTransform) } |
510 | if attacherJoint.transNode ~= nil then |
511 | local _ |
512 | attacherJoint.transNodeMinY = Utils.getNoNil(attacherJoint.transNodeMinY, attacherJoint.jointOrigTrans[2]) |
513 | attacherJoint.transNodeMaxY = Utils.getNoNil(attacherJoint.transNodeMaxY, attacherJoint.jointOrigTrans[2]) |
514 | _, attacherJoint.transNodeOffsetY, _ = localToLocal(attacherJoint.jointTransform, attacherJoint.transNode, 0, 0, 0) |
515 | _, attacherJoint.transNodeMinY, _ = localToLocal(getParent(attacherJoint.transNode), self.rootNode, 0, attacherJoint.transNodeMinY, 0) |
516 | _, attacherJoint.transNodeMaxY, _ = localToLocal(getParent(attacherJoint.transNode), self.rootNode, 0, attacherJoint.transNodeMaxY, 0) |
517 | end |
518 | |
519 | if attacherJoint.transNodeDependentBottomArm ~= nil then |
520 | for _, attacherJoint2 in pairs(spec.attacherJoints) do |
521 | if attacherJoint2.bottomArm ~= nil then |
522 | if attacherJoint2.bottomArm.rotationNode == attacherJoint.transNodeDependentBottomArm then |
523 | attacherJoint.transNodeDependentBottomArmAttacherJoint = attacherJoint2 |
524 | end |
525 | end |
526 | end |
527 | |
528 | if attacherJoint.transNodeDependentBottomArmAttacherJoint == nil then |
529 | Logging.xmlWarning(self.xmlFile, "Unable to find dependent bottom arm '%s' in any attacher joint.", getName(attacherJoint.transNodeDependentBottomArm)) |
530 | attacherJoint.transNodeDependentBottomArm = nil |
531 | end |
532 | end |
533 | |
534 | if attacherJoint.bottomArm ~= nil then |
535 | setRotation(attacherJoint.bottomArm.rotationNode, attacherJoint.bottomArm.rotX, attacherJoint.bottomArm.rotY, attacherJoint.bottomArm.rotZ) |
536 | if self.setMovingToolDirty ~= nil then |
537 | self:setMovingToolDirty(attacherJoint.bottomArm.rotationNode) |
538 | end |
539 | end |
540 | if attacherJoint.rotationNode ~= nil then |
541 | setRotation(attacherJoint.rotationNode, attacherJoint.rotX, attacherJoint.rotY, attacherJoint.rotZ) |
542 | end |
543 | |
544 | if self.getInputAttacherJoints ~= nil then |
545 | attacherJoint.inputAttacherJointOffsets = {} |
546 | for _, inputAttacherJoint in ipairs(self:getInputAttacherJoints()) do |
547 | local xDir, yDir, zDir = localDirectionToLocal(attacherJoint.jointTransform, inputAttacherJoint.node, 0, 0, 1) |
548 | local xUp, yUp, zUp = localDirectionToLocal(attacherJoint.jointTransform, inputAttacherJoint.node, 0, 1, 0) |
549 | local xNorm, yNorm, zNorm = localDirectionToLocal(attacherJoint.jointTransform, inputAttacherJoint.node, 1, 0, 0) |
550 | local xOffset, yOffset, zOffset = localToLocal(attacherJoint.jointTransform, inputAttacherJoint.node, 0, 0, 0) |
551 | table.insert(attacherJoint.inputAttacherJointOffsets, {xOffset, yOffset, zOffset, xDir, yDir, zDir, xUp, yUp, zUp, xNorm, yNorm, zNorm}) |
552 | end |
553 | end |
554 | |
555 | if self.getAIRootNode ~= nil then |
556 | local aiRootNode = self:getAIRootNode() |
557 | local xDir, yDir, zDir = localDirectionToLocal(attacherJoint.jointTransform, aiRootNode, 0, 0, 1) |
558 | local xUp, yUp, zUp = localDirectionToLocal(attacherJoint.jointTransform, aiRootNode, 0, 1, 0) |
559 | local xNorm, yNorm, zNorm = localDirectionToLocal(attacherJoint.jointTransform, aiRootNode, 1, 0, 0) |
560 | local xOffset, yOffset, zOffset = localToLocal(attacherJoint.jointTransform, aiRootNode, 0, 0, 0) |
561 | attacherJoint.aiRootNodeOffset = {xOffset, yOffset, zOffset, xDir, yDir, zDir, xUp, yUp, zUp, xNorm, yNorm, zNorm} |
562 | end |
563 | |
564 | if attacherJoint.comboTime ~= nil then |
565 | table.insert(spec.attacherJointCombos.joints, {jointIndex = attacherJointIndex, time = MathUtil.clamp(attacherJoint.comboTime, 0, 1) * spec.attacherJointCombos.duration}) |
566 | end |
567 | end |
568 | |
569 | if savegame ~= nil and not savegame.resetVehicles then |
570 | if spec.attacherJointCombos ~= nil then |
571 | local comboDirection = savegame.xmlFile:getValue(savegame.key..".attacherJoints#comboDirection") |
572 | if comboDirection ~= nil then |
573 | spec.attacherJointCombos.direction = comboDirection |
574 | if comboDirection == 1 then |
575 | spec.attacherJointCombos.currentTime = spec.attacherJointCombos.duration |
576 | end |
577 | end |
578 | end |
579 | end |
580 | |
581 | if #spec.attacherJoints == 0 then |
582 | SpecializationUtil.removeEventListener(self, "onReadStream", AttacherJoints) |
583 | SpecializationUtil.removeEventListener(self, "onWriteStream", AttacherJoints) |
584 | SpecializationUtil.removeEventListener(self, "onUpdate", AttacherJoints) |
585 | SpecializationUtil.removeEventListener(self, "onUpdateEnd", AttacherJoints) |
586 | SpecializationUtil.removeEventListener(self, "onPostUpdate", AttacherJoints) |
587 | SpecializationUtil.removeEventListener(self, "onStateChange", AttacherJoints) |
588 | SpecializationUtil.removeEventListener(self, "onLightsTypesMaskChanged", AttacherJoints) |
589 | SpecializationUtil.removeEventListener(self, "onTurnLightStateChanged", AttacherJoints) |
590 | SpecializationUtil.removeEventListener(self, "onBrakeLightsVisibilityChanged", AttacherJoints) |
591 | SpecializationUtil.removeEventListener(self, "onReverseLightsVisibilityChanged", AttacherJoints) |
592 | SpecializationUtil.removeEventListener(self, "onBeaconLightsVisibilityChanged", AttacherJoints) |
593 | SpecializationUtil.removeEventListener(self, "onBrake", AttacherJoints) |
594 | SpecializationUtil.removeEventListener(self, "onTurnedOn", AttacherJoints) |
595 | SpecializationUtil.removeEventListener(self, "onTurnedOff", AttacherJoints) |
596 | SpecializationUtil.removeEventListener(self, "onLeaveVehicle", AttacherJoints) |
597 | SpecializationUtil.removeEventListener(self, "onActivate", AttacherJoints) |
598 | SpecializationUtil.removeEventListener(self, "onDeactivate", AttacherJoints) |
599 | SpecializationUtil.removeEventListener(self, "onReverseDirectionChanged", AttacherJoints) |
600 | end |
601 | end |
onPostUpdate
DescriptionCalled on after updateDefinition
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 |
784 | function AttacherJoints:onPostUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
785 | local spec = self.spec_attacherJoints |
786 | |
787 | for _,implement in pairs(spec.attachedImplements) do |
788 | if not implement.attachingIsInProgress then |
789 | local attacherJoint = implement.object:getActiveInputAttacherJoint() |
790 | if attacherJoint ~= nil then |
791 | if spec.attacherJoints[implement.jointDescIndex].steeringBarLeftNode ~= nil and attacherJoint.steeringBarLeftMovingPart ~= nil then |
792 | Cylindered.updateMovingPart(self, attacherJoint.steeringBarLeftMovingPart, nil, true) |
793 | end |
794 | if spec.attacherJoints[implement.jointDescIndex].steeringBarRightNode ~= nil and attacherJoint.steeringBarRightMovingPart ~= nil then |
795 | Cylindered.updateMovingPart(self, attacherJoint.steeringBarRightMovingPart, nil, true) |
796 | end |
797 | end |
798 | end |
799 | end |
800 | end |
onPreDelete
DescriptionCalled on before deletingDefinition
onPreDelete()Code
605 | function AttacherJoints:onPreDelete() |
606 | local spec = self.spec_attacherJoints |
607 | |
608 | if spec.attachedImplements ~= nil then |
609 | for i=#spec.attachedImplements, 1, -1 do |
610 | self:detachImplement(1, true) |
611 | end |
612 | end |
613 | end |
onPreLoad
DescriptionCalled before loadingDefinition
onPreLoad(table savegame)Arguments
table | savegame | savegame |
371 | function AttacherJoints:onPreLoad(savegame) |
372 | local spec = self.spec_attacherJoints |
373 | spec.attachedImplements = {} |
374 | spec.selectedImplement = nil |
375 | |
376 | spec.lastInputAttacherCheckIndex = 0 |
377 | end |
onReadStream
DescriptionCalled on client side on joinDefinition
onReadStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
689 | function AttacherJoints:onReadStream(streamId, connection) |
690 | local numImplements = streamReadInt8(streamId) |
691 | for i=1, numImplements do |
692 | local object = NetworkUtil.readNodeObject(streamId) |
693 | local inputJointDescIndex = streamReadInt8(streamId) |
694 | local jointDescIndex = streamReadInt8(streamId) |
695 | local moveDown = streamReadBool(streamId) |
696 | if object ~= nil and object:getIsSynchronized() then |
697 | self:attachImplement(object, inputJointDescIndex, jointDescIndex, true, i, moveDown, true, true) |
698 | self:setJointMoveDown(jointDescIndex, moveDown, true) |
699 | end |
700 | end |
701 | end |
onRegisterActionEvents
DescriptionDefinitiononRegisterActionEvents()Code
3829 | function AttacherJoints:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
3830 | if self.isClient then |
3831 | local spec = self.spec_attacherJoints |
3832 | self:clearActionEventsTable(spec.actionEvents) |
3833 | |
3834 | -- ignore vehicle selection on 'getIsActiveForInput', so we can select the target vehicle and attach or lower it |
3835 | if isActiveForInputIgnoreSelection then |
3836 | if #spec.attacherJoints > 0 then |
3837 | -- only display lower and attach action if selected implement is direct child of vehicle, not sub child |
3838 | local selectedImplement = self:getSelectedImplement() |
3839 | if selectedImplement ~= nil and selectedImplement.object ~= self then |
3840 | for _, attachedImplement in pairs(spec.attachedImplements) do |
3841 | if attachedImplement == selectedImplement then |
3842 | -- custom registration of the action event. This allows us to overwritte it in the implement (e.g in Foldable) |
3843 | selectedImplement.object:registerLoweringActionEvent(spec.actionEvents, InputAction.LOWER_IMPLEMENT, selectedImplement.object, AttacherJoints.actionEventLowerImplement, false, true, false, true, nil, nil, true) |
3844 | end |
3845 | end |
3846 | end |
3847 | |
3848 | local _, actionEventId = self:addPoweredActionEvent(spec.actionEvents, InputAction.LOWER_ALL_IMPLEMENTS, self, AttacherJoints.actionEventLowerAllImplements, false, true, false, true, nil, nil, true) |
3849 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
3850 | end |
3851 | |
3852 | if self:getSelectedVehicle() == self then |
3853 | local state, _ = self:registerSelfLoweringActionEvent(spec.actionEvents, InputAction.LOWER_IMPLEMENT, self, AttacherJoints.actionEventLowerImplement, false, true, false, true, nil, nil, true) |
3854 | |
3855 | -- if the selected attacher vehicle can not be lowered and we got only one implement that can be lowered |
3856 | -- we add the lowering action for the first implement |
3857 | if state == nil or not state then |
3858 | if #spec.attachedImplements == 1 then |
3859 | local firstImplement = spec.attachedImplements[1] |
3860 | if firstImplement ~= nil then |
3861 | firstImplement.object:registerLoweringActionEvent(spec.actionEvents, InputAction.LOWER_IMPLEMENT, firstImplement.object, AttacherJoints.actionEventLowerImplement, false, true, false, true, nil, nil, true) |
3862 | end |
3863 | end |
3864 | end |
3865 | end |
3866 | |
3867 | local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.ATTACH, self, AttacherJoints.actionEventAttach, false, true, false, true, nil, nil, true) |
3868 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH) |
3869 | |
3870 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.DETACH, self, AttacherJoints.actionEventDetach, false, true, false, true, nil, nil, true) |
3871 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
3872 | |
3873 | AttacherJoints.updateActionEvents(self) |
3874 | end |
3875 | end |
3876 | end |
onReverseDirectionChanged
DescriptionDefinitiononReverseDirectionChanged()Code
3897 | function AttacherJoints:onReverseDirectionChanged(direction) |
3898 | local spec = self.spec_attacherJoints |
3899 | |
3900 | if spec.attacherJointCombos ~= nil then |
3901 | for _, joint in pairs(spec.attacherJointCombos.joints) do |
3902 | joint.time = math.abs(joint.time - spec.attacherJointCombos.duration) |
3903 | end |
3904 | end |
3905 | end |
onReverseLightsVisibilityChanged
DescriptionDefinitiononReverseLightsVisibilityChanged()Code
3963 | function AttacherJoints:onReverseLightsVisibilityChanged(visibility) |
3964 | local spec = self.spec_attacherJoints |
3965 | for _, implement in pairs(spec.attachedImplements) do |
3966 | local vehicle = implement.object |
3967 | if vehicle ~= nil and vehicle.setReverseLightsVisibility ~= nil then |
3968 | vehicle:setReverseLightsVisibility(visibility) |
3969 | end |
3970 | end |
3971 | end |
onStateChange
DescriptionDefinitiononStateChange()Code
3909 | function AttacherJoints:onStateChange(state, data) |
3910 | local spec = self.spec_attacherJoints |
3911 | |
3912 | for _, implement in pairs(spec.attachedImplements) do |
3913 | if implement.object ~= nil then |
3914 | implement.object:raiseStateChange(state, data) |
3915 | end |
3916 | end |
3917 | |
3918 | if state == Vehicle.STATE_CHANGE_LOWER_ALL_IMPLEMENTS then |
3919 | if #spec.attacherJoints > 0 then |
3920 | self:startAttacherJointCombo() |
3921 | end |
3922 | end |
3923 | end |
onTopArmI3DLoaded
DescriptionCalled when top arm was loadedDefinition
onTopArmI3DLoaded(integer i3dNode, table args)Arguments
integer | i3dNode | top arm i3d node |
table | args | async arguments |
3240 | function AttacherJoints:onTopArmI3DLoaded(i3dNode, failedReason, args) |
3241 | if i3dNode ~= 0 then |
3242 | local xmlFile = args.xmlFile |
3243 | local baseName = args.baseName |
3244 | local attacherJoint = args.attacherJoint |
3245 | local baseNode = args.baseNode |
3246 | |
3247 | local rootNode = getChildAt(i3dNode, 0) |
3248 | link(baseNode, rootNode) |
3249 | delete(i3dNode) |
3250 | setTranslation(rootNode, 0,0,0) |
3251 | local translationNode = getChildAt(rootNode, 0) |
3252 | local referenceNode = getChildAt(translationNode, 0) |
3253 | |
3254 | |
3255 | local topArm = {} |
3256 | topArm.rotationNode = rootNode |
3257 | topArm.rotX, topArm.rotY, topArm.rotZ = 0,0,0 |
3258 | topArm.translationNode = translationNode |
3259 | |
3260 | local _,_,referenceDistance = getTranslation(referenceNode) |
3261 | topArm.referenceDistance = referenceDistance |
3262 | |
3263 | topArm.zScale = 1 |
3264 | local zScale = MathUtil.sign(xmlFile:getValue(baseName.. ".topArm#zScale", 1)) |
3265 | if zScale < 0 then |
3266 | topArm.rotY = math.pi |
3267 | setRotation(rootNode, topArm.rotX, topArm.rotY, topArm.rotZ) |
3268 | end |
3269 | |
3270 | if getNumOfChildren(rootNode) > 1 then |
3271 | topArm.scaleNode = getChildAt(rootNode, 1) |
3272 | local scaleReferenceNode = getChildAt(topArm.scaleNode, 0) |
3273 | local _,_,scaleReferenceDistance = getTranslation(scaleReferenceNode) |
3274 | topArm.scaleReferenceDistance = scaleReferenceDistance |
3275 | end |
3276 | |
3277 | topArm.toggleVisibility = xmlFile:getValue(baseName.. ".topArm#toggleVisibility", false) |
3278 | if topArm.toggleVisibility then |
3279 | setVisibility(topArm.rotationNode, false) |
3280 | end |
3281 | |
3282 | local colorValue = xmlFile:getValue(baseName..".topArm#color", nil, true) |
3283 | local colorValue2 = xmlFile:getValue(baseName..".topArm#color2", nil, true) |
3284 | local decalColor = xmlFile:getValue(baseName..".topArm#decalColor", nil, true) |
3285 | local useMainColor = xmlFile:getValue(baseName..".topArm#secondPartUseMainColor", true) |
3286 | local useBrandDecal = xmlFile:getValue(baseName..".topArm#useBrandDecal", true) |
3287 | if not useBrandDecal then |
3288 | local brandDecal = I3DUtil.getChildByName(rootNode, "brandDecal") |
3289 | if brandDecal ~= nil then |
3290 | delete(brandDecal) |
3291 | else |
3292 | Logging.xmlDevWarning(xmlFile, "Unable to find brand decal to remove for '%s'", baseName..".topArm") |
3293 | end |
3294 | end |
3295 | |
3296 | -- on dark colors we use a white decal and on bright colors a black decal |
3297 | if decalColor == nil and colorValue ~= nil then |
3298 | local brightness = MathUtil.getBrightnessFromColor(colorValue[1], colorValue[2], colorValue[3]) |
3299 | brightness = (brightness > 0.075 and 1) or 0 |
3300 | |
3301 | decalColor = {1-brightness, 1-brightness, 1-brightness} |
3302 | end |
3303 | |
3304 | local _, _, _, mat0 = I3DUtil.getShaderParameterRec(rootNode, "colorMat0") |
3305 | local _, _, _, mat1 = I3DUtil.getShaderParameterRec(rootNode, "colorMat1") |
3306 | |
3307 | if colorValue ~= nil then |
3308 | local material = xmlFile:getValue(baseName..".topArm#material") |
3309 | I3DUtil.setShaderParameterRec(rootNode, "colorMat0", colorValue[1], colorValue[2], colorValue[3], material or mat0) |
3310 | end |
3311 | if colorValue2 ~= nil then |
3312 | local material2 = xmlFile:getValue(baseName..".topArm#material2") |
3313 | I3DUtil.setShaderParameterRec(rootNode, "colorMat1", colorValue2[1], colorValue2[2], colorValue2[3], material2 or mat1) |
3314 | end |
3315 | |
3316 | if useMainColor then |
3317 | if colorValue ~= nil then |
3318 | local material = xmlFile:getValue(baseName..".topArm#material") |
3319 | I3DUtil.setShaderParameterRec(rootNode, "colorMat3", colorValue[1], colorValue[2], colorValue[3], material or mat0) |
3320 | else |
3321 | local x, y, z, w = I3DUtil.getShaderParameterRec(rootNode, "colorMat0") |
3322 | I3DUtil.setShaderParameterRec(rootNode, "colorMat3", x, y, z, w) |
3323 | end |
3324 | else |
3325 | if colorValue2 ~= nil then |
3326 | local material2 = xmlFile:getValue(baseName..".topArm#material2") |
3327 | I3DUtil.setShaderParameterRec(rootNode, "colorMat3", colorValue2[1], colorValue2[2], colorValue2[3], material2 or mat1) |
3328 | else |
3329 | local x, y, z, w = I3DUtil.getShaderParameterRec(rootNode, "colorMat1") |
3330 | I3DUtil.setShaderParameterRec(rootNode, "colorMat3", x, y, z, w) |
3331 | end |
3332 | end |
3333 | |
3334 | if decalColor ~= nil then |
3335 | I3DUtil.setShaderParameterRec(rootNode, "colorMat2", decalColor[1], decalColor[2], decalColor[3], 1) |
3336 | end |
3337 | |
3338 | attacherJoint.topArm = topArm |
3339 | end |
3340 | end |
onTurnedOff
DescriptionDefinitiononTurnedOff()Code
4016 | function AttacherJoints:onTurnedOff() |
4017 | local spec = self.spec_attacherJoints |
4018 | for _, implement in pairs(spec.attachedImplements) do |
4019 | local vehicle = implement.object |
4020 | if vehicle ~= nil then |
4021 | local turnedOnVehicleSpec = vehicle.spec_turnOnVehicle |
4022 | if turnedOnVehicleSpec then |
4023 | if turnedOnVehicleSpec.turnedOnByAttacherVehicle then |
4024 | vehicle:setIsTurnedOn(false, true) |
4025 | end |
4026 | end |
4027 | end |
4028 | end |
4029 | end |
onTurnedOn
DescriptionDefinitiononTurnedOn()Code
3999 | function AttacherJoints:onTurnedOn() |
4000 | local spec = self.spec_attacherJoints |
4001 | for _, implement in pairs(spec.attachedImplements) do |
4002 | local vehicle = implement.object |
4003 | if vehicle ~= nil then |
4004 | local turnedOnVehicleSpec = vehicle.spec_turnOnVehicle |
4005 | if turnedOnVehicleSpec then |
4006 | if turnedOnVehicleSpec.turnedOnByAttacherVehicle then |
4007 | vehicle:setIsTurnedOn(true, true) |
4008 | end |
4009 | end |
4010 | end |
4011 | end |
4012 | end |
onTurnLightStateChanged
DescriptionDefinitiononTurnLightStateChanged()Code
3939 | function AttacherJoints:onTurnLightStateChanged(state) |
3940 | local spec = self.spec_attacherJoints |
3941 | for _, implement in pairs(spec.attachedImplements) do |
3942 | local vehicle = implement.object |
3943 | if vehicle ~= nil and vehicle.setTurnLightState ~= nil then |
3944 | vehicle:setTurnLightState(state, true, true) |
3945 | end |
3946 | end |
3947 | 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 |
731 | function AttacherJoints:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
732 | local spec = self.spec_attacherJoints |
733 | |
734 | if self.currentUpdateDistance < spec.maxUpdateDistance then |
735 | for _, implement in pairs(spec.attachedImplements) do |
736 | if implement.object ~= nil then |
737 | if self.updateLoopIndex == implement.object.updateLoopIndex then |
738 | self:updateAttacherJointGraphics(implement, dt) |
739 | end |
740 | end |
741 | end |
742 | end |
743 | |
744 | if self.isClient then |
745 | spec.showAttachNotAllowedText = math.max(spec.showAttachNotAllowedText - dt, 0) |
746 | if spec.showAttachNotAllowedText > 0 then |
747 | g_currentMission:addExtraPrintText(spec.texts.infoAttachNotAllowed) |
748 | end |
749 | end |
750 | |
751 | -- update attachables in range |
752 | local info = spec.attachableInfo |
753 | |
754 | if (Platform.gameplay.automaticAttach and self.isServer) |
755 | or (self.isClient and spec.actionEvents ~= nil and spec.actionEvents[InputAction.ATTACH] ~= nil) then |
756 | if self:getCanToggleAttach() then |
757 | AttacherJoints.updateVehiclesInAttachRange(self, AttacherJoints.MAX_ATTACH_DISTANCE_SQ, AttacherJoints.MAX_ATTACH_ANGLE, true) |
758 | else |
759 | info.attacherVehicle, info.attacherVehicleJointDescIndex, info.attachable, info.attachableJointDescIndex = nil, nil, nil, nil |
760 | end |
761 | end |
762 | end |
onUpdateEnd
DescriptionDefinitiononUpdateEnd()Code
766 | function AttacherJoints:onUpdateEnd(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
767 | -- force update of all attacher joint graphics independent of camera distance right before vehicles starts to sleep |
768 | -- so if we get into the update distance agan we are already in the right state without waking up the vehicle |
769 | local spec = self.spec_attacherJoints |
770 | for _, implement in pairs(spec.attachedImplements) do |
771 | if implement.object ~= nil then |
772 | if self.updateLoopIndex == implement.object.updateLoopIndex then |
773 | self:updateAttacherJointGraphics(implement, dt) |
774 | end |
775 | end |
776 | end |
777 | end |
onUpdateTick
DescriptionCalled on update tickDefinition
onUpdateTick(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 |
807 | function AttacherJoints:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
808 | local spec = self.spec_attacherJoints |
809 | |
810 | local playHydraulicSound = false |
811 | |
812 | for _, implement in pairs(spec.attachedImplements) do |
813 | if implement.object ~= nil then |
814 | local jointDesc = spec.attacherJoints[implement.jointDescIndex] |
815 | |
816 | if not implement.object.spec_attachable.isHardAttached then |
817 | if self.isServer then |
818 | if implement.attachingIsInProgress then |
819 | local done = true |
820 | for i=1,3 do |
821 | local lastRotLimit = implement.attachingRotLimit[i] |
822 | local lastTransLimit = implement.attachingTransLimit[i] |
823 | implement.attachingRotLimit[i] = math.max(0, implement.attachingRotLimit[i] - implement.attachingRotLimitSpeed[i] * dt) |
824 | implement.attachingTransLimit[i] = math.max(0, implement.attachingTransLimit[i] - implement.attachingTransLimitSpeed[i] * dt) |
825 | if (implement.attachingRotLimit[i] > 0 or implement.attachingTransLimit[i] > 0) or |
826 | (lastRotLimit > 0 or lastTransLimit > 0) |
827 | then |
828 | done = false |
829 | end |
830 | end |
831 | implement.attachingIsInProgress = not done |
832 | |
833 | if done then |
834 | if implement.object.spec_attachable.attacherJoint.hardAttach and self:getIsHardAttachAllowed(implement.jointDescIndex) then |
835 | self:hardAttachImplement(implement) |
836 | end |
837 | self:postAttachImplement(implement) |
838 | end |
839 | end |
840 | end |
841 | if not implement.attachingIsInProgress then |
842 | local jointFrameInvalid = false |
843 | if jointDesc.allowsLowering then |
844 | if self:getIsActive() then |
845 | local upperAlpha, lowerAlpha = jointDesc.upperAlpha, jointDesc.lowerAlpha |
846 | if jointDesc.moveDown then |
847 | upperAlpha, lowerAlpha = self:calculateAttacherJointMoveUpperLowerAlpha(jointDesc, implement.object) |
848 | jointDesc.moveTime = jointDesc.moveDefaultTime * math.abs(upperAlpha - lowerAlpha) |
849 | end |
850 | |
851 | local moveAlpha = Utils.getMovedLimitedValue(jointDesc.moveAlpha, lowerAlpha, upperAlpha, jointDesc.moveTime, dt, not jointDesc.moveDown) |
852 | if moveAlpha ~= jointDesc.moveAlpha or upperAlpha ~= jointDesc.upperAlpha or lowerAlpha ~= jointDesc.lowerAlpha then |
853 | jointDesc.upperAlpha = upperAlpha |
854 | jointDesc.lowerAlpha = lowerAlpha |
855 | |
856 | if jointDesc.moveDown then |
857 | if math.abs(jointDesc.moveAlpha - jointDesc.lowerAlpha) < 0.05 then |
858 | jointDesc.isMoving = false |
859 | end |
860 | else |
861 | if math.abs(jointDesc.moveAlpha - jointDesc.upperAlpha) < 0.05 then |
862 | jointDesc.isMoving = false |
863 | end |
864 | end |
865 | |
866 | playHydraulicSound = jointDesc.isMoving |
867 | |
868 | jointDesc.moveAlpha = moveAlpha |
869 | jointDesc.moveLimitAlpha = 1- (moveAlpha-jointDesc.lowerAlpha) / (jointDesc.upperAlpha-jointDesc.lowerAlpha) |
870 | jointFrameInvalid = true |
871 | self:updateAttacherJointRotationNodes(jointDesc, jointDesc.moveAlpha) |
872 | self:updateAttacherJointRotation(jointDesc, implement.object) |
873 | end |
874 | end |
875 | end |
876 | |
877 | jointFrameInvalid = jointFrameInvalid or jointDesc.jointFrameInvalid |
878 | if jointFrameInvalid then |
879 | jointDesc.jointFrameInvalid = false |
880 | if self.isServer then |
881 | setJointFrame(jointDesc.jointIndex, 0, jointDesc.jointTransform) |
882 | end |
883 | end |
884 | end |
885 | if self.isServer then |
886 | local force = implement.attachingIsInProgress |
887 | if force or (jointDesc.allowsLowering and jointDesc.allowsJointLimitMovement) then |
888 | if jointDesc.jointIndex ~= nil and jointDesc.jointIndex ~= 0 then |
889 | if force or implement.object.spec_attachable.attacherJoint.allowsJointRotLimitMovement then |
890 | local alpha = math.max(jointDesc.moveLimitAlpha - implement.rotLimitThreshold, 0) / (1-implement.rotLimitThreshold) |
891 | |
892 | for i=1, 3 do |
893 | AttacherJoints.updateAttacherJointRotationLimit(implement, jointDesc, i, force, alpha) |
894 | end |
895 | end |
896 | |
897 | if force or implement.object.spec_attachable.attacherJoint.allowsJointTransLimitMovement then |
898 | local alpha = math.max(jointDesc.moveLimitAlpha - implement.transLimitThreshold, 0) / (1-implement.transLimitThreshold) |
899 | |
900 | for i=1, 3 do |
901 | AttacherJoints.updateAttacherJointTranslationLimit(implement, jointDesc, i, force, alpha) |
902 | end |
903 | end |
904 | end |
905 | end |
906 | end |
907 | end |
908 | end |
909 | end |
910 | |
911 | if self.isClient and spec.samples.hydraulic ~= nil then |
912 | for i=1, #spec.attacherJoints do |
913 | local jointDesc = spec.attacherJoints[i] |
914 | if jointDesc.bottomArm ~= nil and jointDesc.bottomArm.bottomArmInterpolating then |
915 | playHydraulicSound = true |
916 | end |
917 | end |
918 | |
919 | if playHydraulicSound then |
920 | if not spec.isHydraulicSamplePlaying then |
921 | g_soundManager:playSample(spec.samples.hydraulic) |
922 | spec.isHydraulicSamplePlaying = true |
923 | end |
924 | else |
925 | if spec.isHydraulicSamplePlaying then |
926 | g_soundManager:stopSample(spec.samples.hydraulic) |
927 | spec.isHydraulicSamplePlaying = false |
928 | end |
929 | end |
930 | end |
931 | |
932 | local combos = spec.attacherJointCombos |
933 | if combos ~= nil and combos.isRunning then |
934 | for _, joint in pairs(combos.joints) do |
935 | local doLowering |
936 | if combos.direction == 1 and combos.currentTime >= joint.time then |
937 | doLowering = true |
938 | elseif combos.direction == -1 and combos.currentTime <= combos.duration-joint.time then |
939 | doLowering = false |
940 | end |
941 | |
942 | if doLowering ~= nil then |
943 | local implement = self:getImplementFromAttacherJointIndex(joint.jointIndex) |
944 | if implement ~= nil then |
945 | if implement.object.setLoweredAll ~= nil then |
946 | implement.object:setLoweredAll(doLowering, joint.jointIndex) |
947 | log("set lowered", doLowering, joint.jointIndex) |
948 | end |
949 | end |
950 | end |
951 | end |
952 | |
953 | if (combos.direction == -1 and combos.currentTime == 0) or |
954 | (combos.direction == 1 and combos.currentTime == combos.duration) then |
955 | combos.isRunning = false |
956 | end |
957 | |
958 | combos.currentTime = MathUtil.clamp(combos.currentTime + dt*combos.direction, 0, combos.duration) |
959 | end |
960 | |
961 | AttacherJoints.updateActionEvents(self) |
962 | |
963 | -- auto attach for mobile version |
964 | if Platform.gameplay.automaticAttach then |
965 | if self.isServer then |
966 | if self:getCanToggleAttach() then |
967 | local info = spec.attachableInfo |
968 | |
969 | if info.attachable ~= nil and not spec.wasInAttachRange and info.attacherVehicle == self then |
970 | local attachAllowed, warning = info.attachable:isAttachAllowed(self:getActiveFarm(), info.attacherVehicle) |
971 | if attachAllowed then |
972 | -- wasInAttachRange is nil after detach until the detached implement is in range |
973 | if spec.wasInAttachRange == nil then |
974 | spec.wasInAttachRange = true |
975 | else |
976 | self:attachImplementFromInfo(info) |
977 | end |
978 | elseif warning ~= nil then |
979 | g_currentMission:showBlinkingWarning(warning, 2000) |
980 | end |
981 | elseif info.attachable == nil and spec.wasInAttachRange then |
982 | spec.wasInAttachRange = false |
983 | end |
984 | end |
985 | end |
986 | end |
987 | end |
onWriteStream
DescriptionCalled on server side on joinDefinition
onWriteStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
707 | function AttacherJoints:onWriteStream(streamId, connection) |
708 | local spec = self.spec_attacherJoints |
709 | |
710 | -- write attached implements |
711 | streamWriteInt8(streamId, #spec.attachedImplements) |
712 | for i=1, #spec.attachedImplements do |
713 | local implement = spec.attachedImplements[i] |
714 | local inputJointDescIndex = implement.object.spec_attachable.inputAttacherJointDescIndex |
715 | local jointDescIndex = implement.jointDescIndex |
716 | local jointDesc = spec.attacherJoints[jointDescIndex] |
717 | local moveDown = jointDesc.moveDown |
718 | NetworkUtil.writeNodeObject(streamId, implement.object) |
719 | streamWriteInt8(streamId, inputJointDescIndex) |
720 | streamWriteInt8(streamId, jointDescIndex) |
721 | streamWriteBool(streamId, moveDown) |
722 | end |
723 | end |
playAttachSound
DescriptionPlay attach soundDefinition
playAttachSound(table jointDesc)Arguments
table | jointDesc | joint desc |
boolean | success | success |
2537 | function AttacherJoints:playAttachSound(jointDesc) |
2538 | local spec = self.spec_attacherJoints |
2539 | |
2540 | if self.isClient then |
2541 | if jointDesc ~= nil and jointDesc.sampleAttach ~= nil then |
2542 | g_soundManager:playSample(jointDesc.sampleAttach) |
2543 | else |
2544 | g_soundManager:playSample(spec.samples.attach) |
2545 | end |
2546 | end |
2547 | |
2548 | return true |
2549 | end |
playDetachSound
DescriptionPlay detach soundDefinition
playDetachSound(table jointDesc)Arguments
table | jointDesc | joint desc |
boolean | success | success |
2555 | function AttacherJoints:playDetachSound(jointDesc) |
2556 | local spec = self.spec_attacherJoints |
2557 | |
2558 | if self.isClient then |
2559 | if jointDesc ~= nil and jointDesc.sampleDetach ~= nil then |
2560 | g_soundManager:playSample(jointDesc.sampleDetach) |
2561 | elseif spec.samples.detach ~= nil then |
2562 | g_soundManager:playSample(spec.samples.detach) |
2563 | elseif jointDesc ~= nil and jointDesc.sampleAttach ~= nil then |
2564 | g_soundManager:playSample(jointDesc.sampleAttach) |
2565 | else |
2566 | g_soundManager:playSample(spec.samples.attach) |
2567 | end |
2568 | end |
2569 | |
2570 | return true |
2571 | end |
postAttachImplement
DescriptionDefinitionpostAttachImplement()Code
1883 | function AttacherJoints:postAttachImplement(implement) |
1884 | local spec = self.spec_attacherJoints |
1885 | |
1886 | local object = implement.object |
1887 | local inputJointDescIndex = implement.inputJointDescIndex |
1888 | local jointDescIndex = implement.jointDescIndex |
1889 | local objectAttacherJoint = object.spec_attachable.inputAttacherJoints[inputJointDescIndex] |
1890 | local jointDesc = spec.attacherJoints[jointDescIndex] |
1891 | |
1892 | if objectAttacherJoint.topReferenceNode ~= nil then |
1893 | if jointDesc.topArm ~= nil and jointDesc.topArm.toggleVisibility then |
1894 | setVisibility(jointDesc.topArm.rotationNode, true) |
1895 | end |
1896 | end |
1897 | |
1898 | if jointDesc.bottomArm ~= nil then |
1899 | if jointDesc.bottomArm.toggleVisibility then |
1900 | setVisibility(jointDesc.bottomArm.rotationNode, true) |
1901 | end |
1902 | |
1903 | if objectAttacherJoint.needsToolbar and jointDesc.bottomArm.toolbar ~= nil then |
1904 | setVisibility(jointDesc.bottomArm.toolbar, true) |
1905 | end |
1906 | end |
1907 | |
1908 | if jointDesc.delayedObjectChangesOnAttach then |
1909 | ObjectChangeUtil.setObjectChanges(jointDesc.changeObjects, true, self, self.setMovingToolDirty) |
1910 | end |
1911 | |
1912 | self:updateAttacherJointGraphics(implement, 0) |
1913 | |
1914 | SpecializationUtil.raiseEvent(self, "onPostAttachImplement", object, inputJointDescIndex, jointDescIndex) |
1915 | object:postAttach(self, inputJointDescIndex, jointDescIndex, implement.loadFromSavegame) |
1916 | |
1917 | local data = {attacherVehicle=self, attachedVehicle=implement.object} |
1918 | local rootVehicle = self.rootVehicle |
1919 | rootVehicle:raiseStateChange(Vehicle.STATE_CHANGE_ATTACH, data) |
1920 | end |
prerequisitesPresent
DescriptionDefinitionprerequisitesPresent()Code
229 | function AttacherJoints.prerequisitesPresent(specializations) |
230 | return true |
231 | end |
raiseActive
DescriptionDefinitionraiseActive()Code
3362 | function AttacherJoints:raiseActive(superFunc) |
3363 | local spec = self.spec_attacherJoints |
3364 | |
3365 | superFunc(self) |
3366 | for _,implement in pairs(spec.attachedImplements) do |
3367 | if implement.object ~= nil then |
3368 | implement.object:raiseActive() |
3369 | end |
3370 | end |
3371 | end |
registerActionEvents
DescriptionDefinitionregisterActionEvents()Code
3375 | function AttacherJoints:registerActionEvents(superFunc, excludedVehicle) |
3376 | local spec = self.spec_attacherJoints |
3377 | |
3378 | superFunc(self, excludedVehicle) |
3379 | if self ~= excludedVehicle then |
3380 | -- at first we register the inputs of the selected vehicle |
3381 | -- so they got the higest prio and cannot be overwritten by another vehicle |
3382 | local selectedObject = self:getSelectedObject() |
3383 | if selectedObject ~= nil and self ~= selectedObject.vehicle and excludedVehicle ~= selectedObject.vehicle then |
3384 | selectedObject.vehicle:registerActionEvents() |
3385 | end |
3386 | |
3387 | for _,implement in pairs(spec.attachedImplements) do |
3388 | if implement.object ~= nil then |
3389 | if selectedObject == nil then printCallstack() end |
3390 | implement.object:registerActionEvents(selectedObject.vehicle) |
3391 | end |
3392 | end |
3393 | end |
3394 | end |
registerAttacherJointXMLPaths
DescriptionDefinitionregisterAttacherJointXMLPaths()Code
69 | function AttacherJoints.registerAttacherJointXMLPaths(schema, baseName) |
70 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#node", "Node") |
71 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#nodeVisual", "Visual node") |
72 | |
73 | schema:register(XMLValueType.BOOL, baseName .. "#supportsHardAttach", "Supports hard attach") |
74 | schema:register(XMLValueType.STRING, baseName .. "#jointType", "Joint type", "implement") |
75 | |
76 | schema:register(XMLValueType.STRING, baseName .. ".subType#name", "If defined this type needs to match with the sub type in the tool") |
77 | schema:register(XMLValueType.STRING, baseName .. ".subType#brandRestriction", "If defined it's only possible to attach tools from these brands (can be multiple separated by ' ')") |
78 | schema:register(XMLValueType.STRING, baseName .. ".subType#vehicleRestriction", "If defined it's only possible to attach tools containing these strings in there xml path (can be multiple separated by ' ')") |
79 | schema:register(XMLValueType.BOOL, baseName .. ".subType#subTypeShowWarning", "Show warning if sub type does not match", true) |
80 | |
81 | schema:register(XMLValueType.BOOL, baseName .. "#allowsJointLimitMovement", "Allows joint limit movement", true) |
82 | schema:register(XMLValueType.BOOL, baseName .. "#allowsLowering", "Allows lowering", true) |
83 | schema:register(XMLValueType.BOOL, baseName .. "#isDefaultLowered", "Default lowered state", false) |
84 | schema:register(XMLValueType.BOOL, baseName .. "#allowDetachingWhileLifted", "Allow detach while lifted", true) |
85 | schema:register(XMLValueType.BOOL, baseName .. "#allowFoldingWhileAttached", "Allow folding while attached", true) |
86 | |
87 | schema:register(XMLValueType.BOOL, baseName .. "#canTurnOnImplement", "Can turn on implement", true) |
88 | |
89 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".rotationNode#node", "Rotation node") |
90 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".rotationNode#lowerRotation", "Lower rotation", "0 0 0") |
91 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".rotationNode#upperRotation", "Upper rotation", "rotation in i3d") |
92 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".rotationNode#startRotation", "Start rotation", "rotation in i3d") |
93 | |
94 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".rotationNode2#node", "Rotation node") |
95 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".rotationNode2#lowerRotation", "Lower rotation", "0 0 0") |
96 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".rotationNode2#upperRotation", "Upper rotation", "rotation in i3d") |
97 | |
98 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".transNode#node", "Translation node") |
99 | schema:register(XMLValueType.FLOAT, baseName .. ".transNode#height", "Height of visual translation node", 0.12) |
100 | schema:register(XMLValueType.FLOAT, baseName .. ".transNode#minY", "Min Y translation") |
101 | schema:register(XMLValueType.FLOAT, baseName .. ".transNode#maxY", "Max Y translation") |
102 | |
103 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".transNode.dependentBottomArm#node", "Dependent bottom arm node") |
104 | schema:register(XMLValueType.FLOAT, baseName .. ".transNode.dependentBottomArm#threshold", "If the trans node Y translation is below this threshold the rotation will be set", "unlimited, so rotation is always set") |
105 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".transNode.dependentBottomArm#rotation", "Rotation to be set when the translation node is below the threshold", "0 0 0") |
106 | |
107 | schema:register(XMLValueType.FLOAT, baseName .. ".distanceToGround#lower", "Lower distance to ground", 0.7) |
108 | schema:register(XMLValueType.FLOAT, baseName .. ".distanceToGround#upper", "Upper distance to ground", 1.0) |
109 | |
110 | |
111 | schema:register(XMLValueType.ANGLE, baseName .. "#lowerRotationOffset", "Upper rotation offset", 0) |
112 | schema:register(XMLValueType.ANGLE, baseName .. "#upperRotationOffset", "Lower rotation offset", 0) |
113 | |
114 | schema:register(XMLValueType.BOOL, baseName .. "#lockDownRotLimit", "Lock down rotation limit", false) |
115 | schema:register(XMLValueType.BOOL, baseName .. "#lockUpRotLimit", "Lock up rotation limit", false) |
116 | |
117 | schema:register(XMLValueType.BOOL, baseName .. "#lockDownTransLimit", "Lock down translation limit", true) |
118 | schema:register(XMLValueType.BOOL, baseName .. "#lockUpTransLimit", "Lock up translation limit", false) |
119 | |
120 | |
121 | schema:register(XMLValueType.VECTOR_ROT, baseName .. "#lowerRotLimit", "Lower rotation limit", "(20 20 20) for implement type, otherwise (0 0 0)") |
122 | schema:register(XMLValueType.VECTOR_ROT, baseName .. "#upperRotLimit", "Upper rotation limit", "Lower rot limit") |
123 | |
124 | schema:register(XMLValueType.VECTOR_3, baseName .. "#lowerTransLimit", "Lower translation limit", "(0.5 0.5 0.5) for implement type, otherwise (0 0 0)") |
125 | schema:register(XMLValueType.VECTOR_3, baseName .. "#upperTransLimit", "Upper translation limit", "Lower trans limit") |
126 | |
127 | schema:register(XMLValueType.VECTOR_3, baseName .. "#jointPositionOffset", "Joint position offset", "0 0 0") |
128 | |
129 | schema:register(XMLValueType.VECTOR_3, baseName .. "#rotLimitSpring", "Rotation limit spring", "0 0 0") |
130 | schema:register(XMLValueType.VECTOR_3, baseName .. "#rotLimitDamping", "Rotation limit damping", "1 1 1") |
131 | schema:register(XMLValueType.VECTOR_3, baseName .. "#rotLimitForceLimit", "Rotation limit force limit", "-1 -1 -1") |
132 | |
133 | schema:register(XMLValueType.VECTOR_3, baseName .. "#transLimitSpring", "Translation limit spring", "0 0 0") |
134 | schema:register(XMLValueType.VECTOR_3, baseName .. "#transLimitDamping", "Translation limit damping", "1 1 1") |
135 | schema:register(XMLValueType.VECTOR_3, baseName .. "#transLimitForceLimit", "Translation limit force limit", "-1 -1 -1") |
136 | |
137 | schema:register(XMLValueType.FLOAT, baseName .. "#moveTime", "Move time", 0.5) |
138 | schema:register(XMLValueType.VECTOR_N, baseName .. "#disabledByAttacherJoints", "This attacher becomes unavailable after attaching something to these attacher joint indices") |
139 | schema:register(XMLValueType.BOOL, baseName .. "#enableCollision", "Collision between vehicle is enabled", false) |
140 | |
141 | schema:register(XMLValueType.STRING, baseName .. ".topArm#filename", "Path to top arm i3d file") |
142 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".topArm#baseNode", "Link node for upper link") |
143 | schema:register(XMLValueType.INT, baseName .. ".topArm#zScale", "Inverts top arm direction", 1) |
144 | schema:register(XMLValueType.BOOL, baseName .. ".topArm#toggleVisibility", "Top arm will be hidden on detach", false) |
145 | schema:register(XMLValueType.COLOR, baseName .. ".topArm#color", "Top arm color") |
146 | schema:register(XMLValueType.COLOR, baseName .. ".topArm#color2", "Top arm color 2") |
147 | schema:register(XMLValueType.COLOR, baseName .. ".topArm#decalColor", "Top arm decal color") |
148 | schema:register(XMLValueType.BOOL, baseName .. ".topArm#secondPartUseMainColor", "Second part of upper link (parts on colorMat3) will use main color or color2", true) |
149 | schema:register(XMLValueType.BOOL, baseName .. ".topArm#useBrandDecal", "Defines if the brand decal on the top arm is allowed or not", true) |
150 | schema:register(XMLValueType.INT, baseName .. ".topArm#material", "Top arm material index") |
151 | schema:register(XMLValueType.INT, baseName .. ".topArm#material2", "Top arm material index 2") |
152 | |
153 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".topArm#rotationNode", "Rotation node if top arm not loaded from i3d") |
154 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".topArm#translationNode", "Translation node if top arm not loaded from i3d") |
155 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".topArm#referenceNode", "Reference node if top arm not loaded from i3d") |
156 | |
157 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".bottomArm#rotationNode", "Rotation node of bottom arm") |
158 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".bottomArm#translationNode", "Translation node of bottom arm") |
159 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".bottomArm#referenceNode", "Reference node of bottom arm") |
160 | schema:register(XMLValueType.VECTOR_ROT, baseName .. ".bottomArm#startRotation", "Start rotation", "values set in i3d") |
161 | schema:register(XMLValueType.INT, baseName .. ".bottomArm#zScale", "Inverts bottom arm direction", 1) |
162 | schema:register(XMLValueType.BOOL, baseName .. ".bottomArm#lockDirection", "Lock direction", true) |
163 | schema:register(XMLValueType.ANGLE, baseName .. ".bottomArm#resetSpeed", "Speed of bottom arm to return to idle position (deg/sec)", 45) |
164 | schema:register(XMLValueType.BOOL, baseName .. ".bottomArm#toggleVisibility", "Bottom arm will be hidden on detach", false) |
165 | |
166 | schema:register(XMLValueType.STRING, baseName .. ".toolbar#filename", "Filename to toolbar i3d", "$data/shared/assets/toolbar.i3d") |
167 | |
168 | SoundManager.registerSampleXMLPaths(schema, baseName, "attachSound") |
169 | SoundManager.registerSampleXMLPaths(schema, baseName, "detachSound") |
170 | |
171 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".steeringBars#leftNode", "Steering bar left node") |
172 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".steeringBars#rightNode", "Steering bar right node") |
173 | schema:register(XMLValueType.BOOL, baseName .. ".steeringBars#forceUsage", "Forces usage of tools steering axle even if no steering bars are defined", true) |
174 | |
175 | schema:register(XMLValueType.NODE_INDICES, baseName .. ".visuals#nodes", "Visual nodes of attacher joint that will be visible when the joint is active") |
176 | schema:register(XMLValueType.NODE_INDICES, baseName .. ".visuals#hide", "Visual nodes that will be hidden while attacher joint is active if there attacher is inactive") |
177 | |
178 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, baseName) |
179 | schema:register(XMLValueType.BOOL, baseName .. "#delayedObjectChanges", "Defines if object change is deactivated after the bottomArm has moved (if available)", true) |
180 | schema:register(XMLValueType.BOOL, baseName .. "#delayedObjectChangesOnAttach", "Defines if object change is activated on attach or post attach", false) |
181 | |
182 | schema:register(XMLValueType.INT, baseName .. ".additionalAttachment#attacherJointDirection", "Attacher joint direction") |
183 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#rootNode", "Root node", "first component") |
184 | |
185 | schema:register(XMLValueType.FLOAT, baseName .. "#comboTime", "Combo time") |
186 | |
187 | schema:register(XMLValueType.VECTOR_2, baseName .. ".schema#position", "Schema position") |
188 | schema:register(XMLValueType.VECTOR_2, baseName .. ".schema#liftedOffset", "Offset if lifted", "0 5") |
189 | schema:register(XMLValueType.ANGLE, baseName .. ".schema#rotation", "Schema rotation", 0) |
190 | schema:register(XMLValueType.BOOL, baseName .. ".schema#invertX", "Invert X", false) |
191 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
340 | function AttacherJoints.registerEventListeners(vehicleType) |
341 | SpecializationUtil.registerEventListener(vehicleType, "onPreLoad", AttacherJoints) |
342 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", AttacherJoints) |
343 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", AttacherJoints) |
344 | SpecializationUtil.registerEventListener(vehicleType, "onPreDelete", AttacherJoints) |
345 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", AttacherJoints) |
346 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", AttacherJoints) |
347 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", AttacherJoints) |
348 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", AttacherJoints) |
349 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateEnd", AttacherJoints) |
350 | SpecializationUtil.registerEventListener(vehicleType, "onPostUpdate", AttacherJoints) |
351 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", AttacherJoints) |
352 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", AttacherJoints) |
353 | SpecializationUtil.registerEventListener(vehicleType, "onStateChange", AttacherJoints) |
354 | SpecializationUtil.registerEventListener(vehicleType, "onLightsTypesMaskChanged", AttacherJoints) |
355 | SpecializationUtil.registerEventListener(vehicleType, "onTurnLightStateChanged", AttacherJoints) |
356 | SpecializationUtil.registerEventListener(vehicleType, "onBrakeLightsVisibilityChanged", AttacherJoints) |
357 | SpecializationUtil.registerEventListener(vehicleType, "onReverseLightsVisibilityChanged", AttacherJoints) |
358 | SpecializationUtil.registerEventListener(vehicleType, "onBeaconLightsVisibilityChanged", AttacherJoints) |
359 | SpecializationUtil.registerEventListener(vehicleType, "onBrake", AttacherJoints) |
360 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", AttacherJoints) |
361 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", AttacherJoints) |
362 | SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", AttacherJoints) |
363 | SpecializationUtil.registerEventListener(vehicleType, "onActivate", AttacherJoints) |
364 | SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", AttacherJoints) |
365 | SpecializationUtil.registerEventListener(vehicleType, "onReverseDirectionChanged", AttacherJoints) |
366 | end |
registerEvents
DescriptionDefinitionregisterEvents()Code
235 | function AttacherJoints.registerEvents(vehicleType) |
236 | SpecializationUtil.registerEvent(vehicleType, "onPreAttachImplement") |
237 | SpecializationUtil.registerEvent(vehicleType, "onPostAttachImplement") |
238 | SpecializationUtil.registerEvent(vehicleType, "onPreDetachImplement") |
239 | SpecializationUtil.registerEvent(vehicleType, "onPostDetachImplement") |
240 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
244 | function AttacherJoints.registerFunctions(vehicleType) |
245 | SpecializationUtil.registerFunction(vehicleType, "saveAttachmentsToXMLFile", AttacherJoints.saveAttachmentsToXMLFile) |
246 | SpecializationUtil.registerFunction(vehicleType, "loadAttachmentsFromXMLFile", AttacherJoints.loadAttachmentsFromXMLFile) |
247 | SpecializationUtil.registerFunction(vehicleType, "loadAttachmentsFinished", AttacherJoints.loadAttachmentsFinished) |
248 | SpecializationUtil.registerFunction(vehicleType, "handleLowerImplementEvent", AttacherJoints.handleLowerImplementEvent) |
249 | SpecializationUtil.registerFunction(vehicleType, "handleLowerImplementByAttacherJointIndex", AttacherJoints.handleLowerImplementByAttacherJointIndex) |
250 | SpecializationUtil.registerFunction(vehicleType, "getAttachedImplements", AttacherJoints.getAttachedImplements) |
251 | SpecializationUtil.registerFunction(vehicleType, "getAttacherJoints", AttacherJoints.getAttacherJoints) |
252 | SpecializationUtil.registerFunction(vehicleType, "getAttacherJointByJointDescIndex", AttacherJoints.getAttacherJointByJointDescIndex) |
253 | SpecializationUtil.registerFunction(vehicleType, "getAttacherJointIndexByNode", AttacherJoints.getAttacherJointIndexByNode) |
254 | SpecializationUtil.registerFunction(vehicleType, "getImplementFromAttacherJointIndex", AttacherJoints.getImplementFromAttacherJointIndex) |
255 | SpecializationUtil.registerFunction(vehicleType, "getAttacherJointIndexFromObject", AttacherJoints.getAttacherJointIndexFromObject) |
256 | SpecializationUtil.registerFunction(vehicleType, "getAttacherJointDescFromObject", AttacherJoints.getAttacherJointDescFromObject) |
257 | SpecializationUtil.registerFunction(vehicleType, "getAttacherJointIndexFromImplementIndex", AttacherJoints.getAttacherJointIndexFromImplementIndex) |
258 | SpecializationUtil.registerFunction(vehicleType, "getObjectFromImplementIndex", AttacherJoints.getObjectFromImplementIndex) |
259 | SpecializationUtil.registerFunction(vehicleType, "updateAttacherJointGraphics", AttacherJoints.updateAttacherJointGraphics) |
260 | SpecializationUtil.registerFunction(vehicleType, "calculateAttacherJointMoveUpperLowerAlpha", AttacherJoints.calculateAttacherJointMoveUpperLowerAlpha) |
261 | SpecializationUtil.registerFunction(vehicleType, "doGroundHeightNodeCheck", AttacherJoints.doGroundHeightNodeCheck) |
262 | SpecializationUtil.registerFunction(vehicleType, "finishGroundHeightNodeCheck", AttacherJoints.finishGroundHeightNodeCheck) |
263 | SpecializationUtil.registerFunction(vehicleType, "groundHeightNodeCheckCallback", AttacherJoints.groundHeightNodeCheckCallback) |
264 | SpecializationUtil.registerFunction(vehicleType, "updateAttacherJointRotation", AttacherJoints.updateAttacherJointRotation) |
265 | SpecializationUtil.registerFunction(vehicleType, "updateAttacherJointRotationNodes", AttacherJoints.updateAttacherJointRotationNodes) |
266 | SpecializationUtil.registerFunction(vehicleType, "updateAttacherJointSettingsByObject", AttacherJoints.updateAttacherJointSettingsByObject) |
267 | SpecializationUtil.registerFunction(vehicleType, "attachImplementFromInfo", AttacherJoints.attachImplementFromInfo) |
268 | SpecializationUtil.registerFunction(vehicleType, "attachImplement", AttacherJoints.attachImplement) |
269 | SpecializationUtil.registerFunction(vehicleType, "postAttachImplement", AttacherJoints.postAttachImplement) |
270 | SpecializationUtil.registerFunction(vehicleType, "createAttachmentJoint", AttacherJoints.createAttachmentJoint) |
271 | SpecializationUtil.registerFunction(vehicleType, "hardAttachImplement", AttacherJoints.hardAttachImplement) |
272 | SpecializationUtil.registerFunction(vehicleType, "hardDetachImplement", AttacherJoints.hardDetachImplement) |
273 | SpecializationUtil.registerFunction(vehicleType, "detachImplement", AttacherJoints.detachImplement) |
274 | SpecializationUtil.registerFunction(vehicleType, "detachImplementByObject", AttacherJoints.detachImplementByObject) |
275 | SpecializationUtil.registerFunction(vehicleType, "playAttachSound", AttacherJoints.playAttachSound) |
276 | SpecializationUtil.registerFunction(vehicleType, "playDetachSound", AttacherJoints.playDetachSound) |
277 | SpecializationUtil.registerFunction(vehicleType, "detachingIsPossible", AttacherJoints.detachingIsPossible) |
278 | SpecializationUtil.registerFunction(vehicleType, "attachAdditionalAttachment", AttacherJoints.attachAdditionalAttachment) |
279 | SpecializationUtil.registerFunction(vehicleType, "detachAdditionalAttachment", AttacherJoints.detachAdditionalAttachment) |
280 | SpecializationUtil.registerFunction(vehicleType, "getImplementIndexByJointDescIndex", AttacherJoints.getImplementIndexByJointDescIndex) |
281 | SpecializationUtil.registerFunction(vehicleType, "getImplementByJointDescIndex", AttacherJoints.getImplementByJointDescIndex) |
282 | SpecializationUtil.registerFunction(vehicleType, "getImplementIndexByObject", AttacherJoints.getImplementIndexByObject) |
283 | SpecializationUtil.registerFunction(vehicleType, "getImplementByObject", AttacherJoints.getImplementByObject) |
284 | SpecializationUtil.registerFunction(vehicleType, "callFunctionOnAllImplements", AttacherJoints.callFunctionOnAllImplements) |
285 | SpecializationUtil.registerFunction(vehicleType, "activateAttachments", AttacherJoints.activateAttachments) |
286 | SpecializationUtil.registerFunction(vehicleType, "deactivateAttachments", AttacherJoints.deactivateAttachments) |
287 | SpecializationUtil.registerFunction(vehicleType, "deactivateAttachmentsLights", AttacherJoints.deactivateAttachmentsLights) |
288 | SpecializationUtil.registerFunction(vehicleType, "setJointMoveDown", AttacherJoints.setJointMoveDown) |
289 | SpecializationUtil.registerFunction(vehicleType, "getJointMoveDown", AttacherJoints.getJointMoveDown) |
290 | SpecializationUtil.registerFunction(vehicleType, "getIsHardAttachAllowed", AttacherJoints.getIsHardAttachAllowed) |
291 | SpecializationUtil.registerFunction(vehicleType, "loadAttacherJointFromXML", AttacherJoints.loadAttacherJointFromXML) |
292 | SpecializationUtil.registerFunction(vehicleType, "onTopArmI3DLoaded", AttacherJoints.onTopArmI3DLoaded) |
293 | SpecializationUtil.registerFunction(vehicleType, "onBottomArmToolbarI3DLoaded", AttacherJoints.onBottomArmToolbarI3DLoaded) |
294 | SpecializationUtil.registerFunction(vehicleType, "setSelectedImplementByObject", AttacherJoints.setSelectedImplementByObject) |
295 | SpecializationUtil.registerFunction(vehicleType, "getSelectedImplement", AttacherJoints.getSelectedImplement) |
296 | SpecializationUtil.registerFunction(vehicleType, "getCanToggleAttach", AttacherJoints.getCanToggleAttach) |
297 | SpecializationUtil.registerFunction(vehicleType, "getShowDetachAttachedImplement", AttacherJoints.getShowDetachAttachedImplement) |
298 | SpecializationUtil.registerFunction(vehicleType, "detachAttachedImplement", AttacherJoints.detachAttachedImplement) |
299 | SpecializationUtil.registerFunction(vehicleType, "startAttacherJointCombo", AttacherJoints.startAttacherJointCombo) |
300 | SpecializationUtil.registerFunction(vehicleType, "registerSelfLoweringActionEvent", AttacherJoints.registerSelfLoweringActionEvent) |
301 | SpecializationUtil.registerFunction(vehicleType, "getIsAttachingAllowed", AttacherJoints.getIsAttachingAllowed) |
302 | SpecializationUtil.registerFunction(vehicleType, "getCanSteerAttachable", AttacherJoints.getCanSteerAttachable) |
303 | end |
registerJointType
DescriptionRegistration of attacher joint typeDefinition
registerJointType(string name)Arguments
string | name | name if attacher type |
196 | function AttacherJoints.registerJointType(name) |
197 | local key = "JOINTTYPE_"..string.upper(name) |
198 | if AttacherJoints[key] == nil then |
199 | AttacherJoints.NUM_JOINTTYPES = AttacherJoints.NUM_JOINTTYPES+1 |
200 | AttacherJoints[key] = AttacherJoints.NUM_JOINTTYPES |
201 | AttacherJoints.jointTypeNameToInt[name] = AttacherJoints.NUM_JOINTTYPES |
202 | end |
203 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
307 | function AttacherJoints.registerOverwrittenFunctions(vehicleType) |
308 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "raiseActive", AttacherJoints.raiseActive) |
309 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "registerActionEvents", AttacherJoints.registerActionEvents) |
310 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "removeActionEvents", AttacherJoints.removeActionEvents) |
311 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "addToPhysics", AttacherJoints.addToPhysics) |
312 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "removeFromPhysics", AttacherJoints.removeFromPhysics) |
313 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getTotalMass", AttacherJoints.getTotalMass) |
314 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "addChildVehicles", AttacherJoints.addChildVehicles) |
315 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAirConsumerUsage", AttacherJoints.getAirConsumerUsage) |
316 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "addVehicleToAIImplementList", AttacherJoints.addVehicleToAIImplementList) |
317 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "collectAIAgentAttachments", AttacherJoints.collectAIAgentAttachments) |
318 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "setAIVehicleObstacleStateDirty", AttacherJoints.setAIVehicleObstacleStateDirty) |
319 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirectionSnapAngle", AttacherJoints.getDirectionSnapAngle) |
320 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillLevelInformation", AttacherJoints.getFillLevelInformation) |
321 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "attachableAddToolCameras", AttacherJoints.attachableAddToolCameras) |
322 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "attachableRemoveToolCameras", AttacherJoints.attachableRemoveToolCameras) |
323 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "registerSelectableObjects", AttacherJoints.registerSelectableObjects) |
324 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsReadyForAutomatedTrainTravel", AttacherJoints.getIsReadyForAutomatedTrainTravel) |
325 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAutomaticShiftingAllowed", AttacherJoints.getIsAutomaticShiftingAllowed) |
326 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadDashboardGroupFromXML", AttacherJoints.loadDashboardGroupFromXML) |
327 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDashboardGroupActive", AttacherJoints.getIsDashboardGroupActive) |
328 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadAttacherJointHeightNode", AttacherJoints.loadAttacherJointHeightNode) |
329 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAttacherJointHeightNodeActive", AttacherJoints.getIsAttacherJointHeightNodeActive) |
330 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "isDetachAllowed", AttacherJoints.isDetachAllowed) |
331 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", AttacherJoints.getIsFoldAllowed) |
332 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWheelFoliageDestructionAllowed", AttacherJoints.getIsWheelFoliageDestructionAllowed) |
333 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAreControlledActionsAllowed", AttacherJoints.getAreControlledActionsAllowed) |
334 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getConnectionHoseConfigIndex", AttacherJoints.getConnectionHoseConfigIndex) |
335 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getPowerTakeOffConfigIndex", AttacherJoints.getPowerTakeOffConfigIndex) |
336 | end |
registerSelectableObjects
DescriptionDefinitionregisterSelectableObjects()Code
3606 | function AttacherJoints:registerSelectableObjects(superFunc, selectableObjects) |
3607 | superFunc(self, selectableObjects) |
3608 | |
3609 | local spec = self.spec_attacherJoints |
3610 | for _,implement in pairs(spec.attachedImplements) do |
3611 | local object = implement.object |
3612 | if object ~= nil and object.registerSelectableObjects ~= nil then |
3613 | object:registerSelectableObjects(selectableObjects) |
3614 | end |
3615 | end |
3616 | end |
registerSelfLoweringActionEvent
DescriptionDefinitionregisterSelfLoweringActionEvent()Code
2530 | function AttacherJoints:registerSelfLoweringActionEvent(actionEventsTable, inputAction, target, callback, triggerUp, triggerDown, triggerAlways, startActive, callbackState, customIconName, ignoreCollisions) |
2531 | end |
removeActionEvents
DescriptionDefinitionremoveActionEvents()Code
3398 | function AttacherJoints:removeActionEvents(superFunc) |
3399 | local spec = self.spec_attacherJoints |
3400 | |
3401 | superFunc(self) |
3402 | |
3403 | for _,implement in pairs(spec.attachedImplements) do |
3404 | if implement.object ~= nil then |
3405 | implement.object:removeActionEvents() |
3406 | end |
3407 | end |
3408 | end |
removeFromPhysics
DescriptionAdd to physicsDefinition
removeFromPhysics()Return Values
boolean | success | success |
3432 | function AttacherJoints:removeFromPhysics(superFunc) |
3433 | local spec = self.spec_attacherJoints |
3434 | |
3435 | for _, implement in pairs(spec.attachedImplements) do |
3436 | if not implement.object.spec_attachable.isHardAttached then |
3437 | local jointDesc = spec.attacherJoints[implement.jointDescIndex] |
3438 | if jointDesc.jointIndex ~= 0 then |
3439 | jointDesc.jointIndex = 0 |
3440 | --removeJoint(jointDesc.jointIndex) |
3441 | end |
3442 | end |
3443 | end |
3444 | |
3445 | if not superFunc(self) then |
3446 | return false |
3447 | end |
3448 | |
3449 | return true |
3450 | end |
saveAttachmentsToXMLFile
DescriptionDefinitionsaveAttachmentsToXMLFile()Code
654 | function AttacherJoints:saveAttachmentsToXMLFile(xmlFile, key, vehiclesToId) |
655 | local spec = self.spec_attacherJoints |
656 | local added = false |
657 | |
658 | local id = vehiclesToId[self] |
659 | if id ~= nil then |
660 | local i = 0 |
661 | for _, implement in ipairs(spec.attachedImplements) do |
662 | local object = implement.object |
663 | if object ~= nil and vehiclesToId[object] ~= nil then |
664 | local attachmentKey = string.format("%s.attachment(%d)", key, i) |
665 | local jointDescIndex = implement.jointDescIndex |
666 | local jointDesc = spec.attacherJoints[jointDescIndex] |
667 | local inputJointDescIndex = object:getActiveInputAttacherJointDescIndex() |
668 | xmlFile:setValue(attachmentKey.."#attachmentId", vehiclesToId[object]) |
669 | xmlFile:setValue(attachmentKey.."#inputJointDescIndex", inputJointDescIndex) |
670 | xmlFile:setValue(attachmentKey.."#jointIndex", jointDescIndex) |
671 | xmlFile:setValue(attachmentKey.."#moveDown", jointDesc.moveDown) |
672 | added = true |
673 | i = i + 1 |
674 | end |
675 | end |
676 | |
677 | if added then |
678 | xmlFile:setValue(key.."#rootVehicleId", id) |
679 | end |
680 | end |
681 | |
682 | return added |
683 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
645 | function AttacherJoints:saveToXMLFile(xmlFile, key, usedModNames) |
646 | local spec = self.spec_attacherJoints |
647 | if spec.attacherJointCombos ~= nil then |
648 | xmlFile:setValue(key.."#comboDirection", spec.attacherJointCombos.direction) |
649 | end |
650 | end |
setAIVehicleObstacleStateDirty
DescriptionDefinitionsetAIVehicleObstacleStateDirty()Code
3534 | function AttacherJoints:setAIVehicleObstacleStateDirty(superFunc) |
3535 | superFunc(self) |
3536 | |
3537 | for _, implement in pairs(self:getAttachedImplements()) do |
3538 | local object = implement.object |
3539 | if object ~= nil and object.setAIVehicleObstacleStateDirty ~= nil then |
3540 | object:setAIVehicleObstacleStateDirty() |
3541 | end |
3542 | end |
3543 | end |
setJointMoveDown
DescriptionSet joint move downDefinition
setJointMoveDown(integer jointDescIndex, boolean moveDown, boolean noEventSend)Arguments
integer | jointDescIndex | index of joint desc |
boolean | moveDown | move down |
boolean | noEventSend | no event send |
boolean | success | success |
2798 | function AttacherJoints:setJointMoveDown(jointDescIndex, moveDown, noEventSend) |
2799 | local spec = self.spec_attacherJoints |
2800 | |
2801 | local jointDesc = spec.attacherJoints[jointDescIndex] |
2802 | if moveDown ~= jointDesc.moveDown then |
2803 | if jointDesc.allowsLowering then |
2804 | jointDesc.moveDown = moveDown |
2805 | jointDesc.isMoving = true |
2806 | |
2807 | local implementIndex = self:getImplementIndexByJointDescIndex(jointDescIndex) |
2808 | if implementIndex ~= nil then |
2809 | local implement = spec.attachedImplements[implementIndex] |
2810 | if implement.object ~= nil then |
2811 | implement.object:setLowered(moveDown) |
2812 | end |
2813 | end |
2814 | end |
2815 | |
2816 | VehicleLowerImplementEvent.sendEvent(self, jointDescIndex, moveDown, noEventSend) |
2817 | end |
2818 | |
2819 | return true |
2820 | end |
setSelectedImplementByObject
DescriptionDefinitionsetSelectedImplementByObject()Code
2428 | function AttacherJoints:setSelectedImplementByObject(object) |
2429 | self.spec_attacherJoints.selectedImplement = self:getImplementByObject(object) |
2430 | end |
startAttacherJointCombo
DescriptionDefinitionstartAttacherJointCombo()Code
2485 | function AttacherJoints:startAttacherJointCombo(force) |
2486 | local spec = self.spec_attacherJoints |
2487 | |
2488 | if not spec.attacherJointCombos.isRunning or force then |
2489 | spec.attacherJointCombos.direction = -spec.attacherJointCombos.direction |
2490 | spec.attacherJointCombos.isRunning = true |
2491 | end |
2492 | end |
updateActionEvents
DescriptionDefinitionupdateActionEvents()Code
4312 | function AttacherJoints.updateActionEvents(self) |
4313 | local spec = self.spec_attacherJoints |
4314 | local info = spec.attachableInfo |
4315 | |
4316 | if self.isClient then |
4317 | if spec.actionEvents ~= nil then |
4318 | local attachActionEvent = spec.actionEvents[InputAction.ATTACH] |
4319 | if attachActionEvent ~= nil then |
4320 | local visible = false |
4321 | |
4322 | if self:getCanToggleAttach() then |
4323 | if info.warning ~= nil then |
4324 | g_currentMission:showBlinkingWarning(info.warning, 500) |
4325 | end |
4326 | |
4327 | local text = "" |
4328 | local prio = GS_PRIO_VERY_LOW |
4329 | |
4330 | local selectedVehicle = self:getSelectedVehicle() |
4331 | if selectedVehicle ~= nil and not selectedVehicle.isDeleted and selectedVehicle.isDetachAllowed ~= nil and selectedVehicle:isDetachAllowed() then |
4332 | if selectedVehicle:getAttacherVehicle() ~= nil then |
4333 | visible = true |
4334 | text = spec.texts.actionDetach |
4335 | end |
4336 | end |
4337 | |
4338 | if info.attacherVehicle ~= nil then |
4339 | if g_currentMission.accessHandler:canFarmAccess(self:getActiveFarm(), info.attachable) then |
4340 | visible = true |
4341 | text = spec.texts.actionAttach |
4342 | g_currentMission:showAttachContext(info.attachable) |
4343 | prio = GS_PRIO_VERY_HIGH |
4344 | else |
4345 | spec.showAttachNotAllowedText = 100 |
4346 | end |
4347 | end |
4348 | |
4349 | g_inputBinding:setActionEventText(attachActionEvent.actionEventId, text) |
4350 | g_inputBinding:setActionEventTextPriority(attachActionEvent.actionEventId, prio) |
4351 | end |
4352 | |
4353 | g_inputBinding:setActionEventTextVisibility(attachActionEvent.actionEventId, visible) |
4354 | end |
4355 | |
4356 | local lowerActionEvent = spec.actionEvents[InputAction.LOWER_IMPLEMENT] |
4357 | if lowerActionEvent ~= nil then |
4358 | local showLower = false |
4359 | local text = "" |
4360 | local selectedImplement = self:getSelectedImplement() |
4361 | for _,attachedImplement in pairs(spec.attachedImplements) do |
4362 | if attachedImplement == selectedImplement then |
4363 | showLower, text = attachedImplement.object:getLoweringActionEventState() |
4364 | break |
4365 | end |
4366 | end |
4367 | |
4368 | g_inputBinding:setActionEventActive(lowerActionEvent.actionEventId, showLower) |
4369 | g_inputBinding:setActionEventText(lowerActionEvent.actionEventId, text) |
4370 | g_inputBinding:setActionEventTextPriority(lowerActionEvent.actionEventId, GS_PRIO_NORMAL) |
4371 | end |
4372 | end |
4373 | end |
4374 | end |
updateAttacherJointGraphics
DescriptionUpdate attacher joint graphicsDefinition
updateAttacherJointGraphics(table implement, float dt)Arguments
table | implement | implement |
float | dt | time since last call in ms |
1183 | function AttacherJoints:updateAttacherJointGraphics(implement, dt, forceUpdate) |
1184 | local spec = self.spec_attacherJoints |
1185 | |
1186 | if implement.object ~= nil then |
1187 | local jointDesc = spec.attacherJoints[implement.jointDescIndex] |
1188 | |
1189 | local attacherJoint = implement.object:getActiveInputAttacherJoint() |
1190 | |
1191 | if jointDesc.topArm ~= nil and attacherJoint.topReferenceNode ~= nil then |
1192 | local ax, ay, az = getWorldTranslation(jointDesc.topArm.rotationNode) |
1193 | local bx, by, bz = getWorldTranslation(attacherJoint.topReferenceNode) |
1194 | |
1195 | local x, y, z = worldDirectionToLocal(getParent(jointDesc.topArm.rotationNode), bx-ax, by-ay, bz-az) |
1196 | local distance = MathUtil.vector3Length(x,y,z) |
1197 | |
1198 | -- different approach I) rotate actual direction of topArm by 90degree around x-axis |
1199 | local alpha = math.rad(-90) |
1200 | -- check if rotationNode is at back of tractor => inverted rotation direction, could be dismissed by rotating TG in i3d |
1201 | local px,py,pz = getWorldTranslation(jointDesc.topArm.rotationNode) |
1202 | local _,_,lz = worldToLocal(self.components[1].node, px,py,pz) |
1203 | if lz < 0 then |
1204 | alpha = math.rad(90) |
1205 | end |
1206 | |
1207 | local dx, dy, dz = localDirectionToWorld(jointDesc.topArm.rotationNode, 0,0,1) |
1208 | dx, dy, dz = worldDirectionToLocal(getParent(jointDesc.topArm.rotationNode), dx, dy, dz) |
1209 | local upX = dx |
1210 | local upY = math.cos(alpha)*dy - math.sin(alpha)*dz |
1211 | local upZ = math.sin(alpha)*dy + math.cos(alpha)*dz |
1212 | |
1213 | if not implement.attachingIsInProgress then |
1214 | setDirection(jointDesc.topArm.rotationNode, x*jointDesc.topArm.zScale, y*jointDesc.topArm.zScale, z*jointDesc.topArm.zScale, upX, upY, upZ) |
1215 | |
1216 | if jointDesc.topArm.translationNode ~= nil then |
1217 | local translation = (distance-jointDesc.topArm.referenceDistance) |
1218 | setTranslation(jointDesc.topArm.translationNode, 0, 0, translation*jointDesc.topArm.zScale) |
1219 | if jointDesc.topArm.scaleNode ~= nil then |
1220 | setScale(jointDesc.topArm.scaleNode, 1, 1, math.max((translation+jointDesc.topArm.scaleReferenceDistance)/jointDesc.topArm.scaleReferenceDistance, 0)) |
1221 | end |
1222 | end |
1223 | end |
1224 | end |
1225 | if jointDesc.bottomArm ~= nil then |
1226 | local ax, ay, az = getWorldTranslation(jointDesc.bottomArm.rotationNode) |
1227 | local bx, by, bz = getWorldTranslation(attacherJoint.node) |
1228 | |
1229 | local x, y, z = worldDirectionToLocal(getParent(jointDesc.bottomArm.rotationNode), bx-ax, by-ay, bz-az) |
1230 | local distance = MathUtil.vector3Length(x,y,z) |
1231 | local upX, upY, upZ = 0,1,0 |
1232 | if math.abs(y) > 0.99*distance then |
1233 | -- direction and up is parallel |
1234 | upY = 0 |
1235 | if y > 0 then |
1236 | upZ = 1 |
1237 | else |
1238 | upZ = -1 |
1239 | end |
1240 | end |
1241 | local dirX, dirY, dirZ = 0, y*jointDesc.bottomArm.zScale, z*jointDesc.bottomArm.zScale |
1242 | if not jointDesc.bottomArm.lockDirection then |
1243 | dirX = x*jointDesc.bottomArm.zScale |
1244 | end |
1245 | |
1246 | local changed = false |
1247 | if math.abs(jointDesc.bottomArm.lastDirection[1] - dirX) > 0.001 or |
1248 | math.abs(jointDesc.bottomArm.lastDirection[2] - dirY) > 0.001 or |
1249 | math.abs(jointDesc.bottomArm.lastDirection[3] - dirZ) > 0.001 then |
1250 | |
1251 | if implement.attachingIsInProgress then |
1252 | -- set only direction node so we can use this rotation as reference for the interpolator |
1253 | setDirection(jointDesc.bottomArm.rotationNodeDir, dirX, dirY, dirZ, upX, upY, upZ) |
1254 | else |
1255 | setDirection(jointDesc.bottomArm.rotationNode, dirX, dirY, dirZ, upX, upY, upZ) |
1256 | end |
1257 | |
1258 | jointDesc.bottomArm.lastDirection[1] = dirX |
1259 | jointDesc.bottomArm.lastDirection[2] = dirY |
1260 | jointDesc.bottomArm.lastDirection[3] = dirZ |
1261 | |
1262 | changed = true |
1263 | end |
1264 | |
1265 | if implement.attachingIsInProgress then |
1266 | if changed then |
1267 | if not implement.bottomArmInterpolating then |
1268 | local interpolator = ValueInterpolator.new(jointDesc.bottomArm.interpolatorKey, jointDesc.bottomArm.interpolatorGet, jointDesc.bottomArm.interpolatorSet, {getRotation(jointDesc.bottomArm.rotationNodeDir)}, AttacherJoints.SMOOTH_ATTACH_TIME) |
1269 | if interpolator ~= nil then |
1270 | interpolator:setDeleteListenerObject(self) |
1271 | interpolator:setFinishedFunc(jointDesc.bottomArm.interpolatorFinished, jointDesc.bottomArm) |
1272 | |
1273 | jointDesc.bottomArm.bottomArmInterpolating = true |
1274 | implement.bottomArmInterpolating = true |
1275 | implement.bottomArmInterpolator = interpolator |
1276 | end |
1277 | else |
1278 | local rx, ry, rz = getRotation(jointDesc.bottomArm.rotationNodeDir) |
1279 | local target = implement.bottomArmInterpolator:getTarget() |
1280 | target[1], target[2], target[3] = rx, ry, rz |
1281 | implement.bottomArmInterpolator:updateSpeed() |
1282 | end |
1283 | end |
1284 | else |
1285 | ValueInterpolator.removeInterpolator(jointDesc.bottomArm.interpolatorKey) |
1286 | jointDesc.bottomArm.bottomArmInterpolating = false |
1287 | implement.bottomArmInterpolating = false |
1288 | implement.bottomArmInterpolator = nil |
1289 | end |
1290 | |
1291 | if jointDesc.bottomArm.translationNode ~= nil and not implement.attachingIsInProgress then |
1292 | setTranslation(jointDesc.bottomArm.translationNode, 0, 0, (distance-jointDesc.bottomArm.referenceDistance)*jointDesc.bottomArm.zScale) |
1293 | end |
1294 | if self.setMovingToolDirty ~= nil then |
1295 | self:setMovingToolDirty(jointDesc.bottomArm.rotationNode, forceUpdate, dt) |
1296 | end |
1297 | |
1298 | if attacherJoint.needsToolbar and jointDesc.bottomArm.toolbar ~= nil then |
1299 | local parent = getParent(jointDesc.bottomArm.toolbar) |
1300 | |
1301 | local _, yDir, zDir = localDirectionToLocal(attacherJoint.node, jointDesc.rootNode, 1, 0, 0) |
1302 | local xDir, yDir, zDir = localDirectionToLocal(jointDesc.rootNode, parent, 0, yDir, zDir) |
1303 | |
1304 | local _, yUp, zUp = localDirectionToLocal(attacherJoint.node, jointDesc.rootNode, 0, 1, 0) |
1305 | local xUp, yUp, zUp = localDirectionToLocal(jointDesc.rootNode, parent, 0, yUp, zUp) |
1306 | |
1307 | setDirection(jointDesc.bottomArm.toolbar, xDir, yDir, zDir, xUp, yUp, zUp) |
1308 | end |
1309 | end |
1310 | end |
1311 | end |
updateAttacherJointLimits
DescriptionDefinitionupdateAttacherJointLimits()Code
4378 | function AttacherJoints.updateAttacherJointLimits(implement, attacherJointDesc, inputAttacherJointDesc, axis) |
4379 | local lowerRotLimit = attacherJointDesc.lowerRotLimit[axis]*inputAttacherJointDesc.lowerRotLimitScale[axis] |
4380 | local upperRotLimit = attacherJointDesc.upperRotLimit[axis]*inputAttacherJointDesc.upperRotLimitScale[axis] |
4381 | if inputAttacherJointDesc.fixedRotation then |
4382 | lowerRotLimit = 0 |
4383 | upperRotLimit = 0 |
4384 | end |
4385 | |
4386 | local upperTransLimit = attacherJointDesc.lowerTransLimit[axis]*inputAttacherJointDesc.lowerTransLimitScale[axis] |
4387 | local lowerTransLimit = attacherJointDesc.upperTransLimit[axis]*inputAttacherJointDesc.upperTransLimitScale[axis] |
4388 | implement.lowerRotLimit[axis] = lowerRotLimit |
4389 | implement.upperRotLimit[axis] = upperRotLimit |
4390 | |
4391 | implement.lowerTransLimit[axis] = upperTransLimit |
4392 | implement.upperTransLimit[axis] = lowerTransLimit |
4393 | |
4394 | if not attacherJointDesc.allowsLowering then |
4395 | implement.upperRotLimit[axis] = lowerRotLimit |
4396 | implement.upperTransLimit[axis] = upperTransLimit |
4397 | end |
4398 | |
4399 | local rotLimit = lowerRotLimit |
4400 | local transLimit = upperTransLimit |
4401 | if attacherJointDesc.allowsLowering and attacherJointDesc.allowsJointLimitMovement then |
4402 | if inputAttacherJointDesc.allowsJointRotLimitMovement then |
4403 | rotLimit = MathUtil.lerp(upperRotLimit, lowerRotLimit, attacherJointDesc.moveAlpha) |
4404 | end |
4405 | if inputAttacherJointDesc.allowsJointTransLimitMovement then |
4406 | transLimit = MathUtil.lerp(lowerTransLimit, upperTransLimit, attacherJointDesc.moveAlpha) |
4407 | end |
4408 | end |
4409 | |
4410 | return rotLimit, transLimit |
4411 | end |
updateAttacherJointRotation
DescriptionUpdate attacher joint rotations depending on move alphaDefinition
updateAttacherJointRotation(table jointDesc, table object)Arguments
table | jointDesc | joint desc of used attacher |
table | object | object of attached vehicle |
1581 | function AttacherJoints:updateAttacherJointRotation(jointDesc, object) |
1582 | local objectAttacherJoint = object.spec_attachable.attacherJoint |
1583 | |
1584 | -- rotate attacher such that |
1585 | local targetRot = MathUtil.lerp(objectAttacherJoint.upperRotationOffset, objectAttacherJoint.lowerRotationOffset, jointDesc.moveAlpha) |
1586 | local curRot = MathUtil.lerp(jointDesc.upperRotationOffset, jointDesc.lowerRotationOffset, jointDesc.moveAlpha) |
1587 | local rotDiff = targetRot - curRot |
1588 | |
1589 | setRotation(jointDesc.jointTransform, unpack(jointDesc.jointOrigRot)) |
1590 | rotateAboutLocalAxis(jointDesc.jointTransform, rotDiff, 0, 0, 1) |
1591 | end |
updateAttacherJointRotationLimit
DescriptionDefinitionupdateAttacherJointRotationLimit()Code
4416 | function AttacherJoints.updateAttacherJointRotationLimit(implement, attacherJointDesc, axis, force, alpha) |
4417 | local newRotLimit = MathUtil.lerp( math.max(implement.attachingRotLimit[axis], implement.upperRotLimit[axis]), |
4418 | math.max(implement.attachingRotLimit[axis], implement.lowerRotLimit[axis]), alpha) |
4419 | if force or math.abs(newRotLimit - implement.jointRotLimit[axis]) > 0.0005 then |
4420 | local rotLimitDown = -newRotLimit |
4421 | local rotLimitUp = newRotLimit |
4422 | if axis == 3 then |
4423 | if attacherJointDesc.lockDownRotLimit then |
4424 | rotLimitDown = math.min(-implement.attachingRotLimit[axis], 0) |
4425 | end |
4426 | if attacherJointDesc.lockUpRotLimit then |
4427 | rotLimitUp = math.max(implement.attachingRotLimit[axis], 0) |
4428 | end |
4429 | end |
4430 | setJointRotationLimit(attacherJointDesc.jointIndex, axis-1, true, rotLimitDown, rotLimitUp) |
4431 | implement.jointRotLimit[axis] = newRotLimit |
4432 | end |
4433 | end |
updateAttacherJointRotationNodes
DescriptionDefinitionupdateAttacherJointRotationNodes()Code
1595 | function AttacherJoints:updateAttacherJointRotationNodes(jointDesc, alpha) |
1596 | if jointDesc.rotationNode ~= nil then |
1597 | setRotation(jointDesc.rotationNode, MathUtil.vector3ArrayLerp(jointDesc.upperRotation, jointDesc.lowerRotation, alpha)) |
1598 | end |
1599 | if jointDesc.rotationNode2 ~= nil then |
1600 | setRotation(jointDesc.rotationNode2, MathUtil.vector3ArrayLerp(jointDesc.upperRotation2, jointDesc.lowerRotation2, alpha)) |
1601 | end |
1602 | end |
updateAttacherJointSettingsByObject
DescriptionDefinitionupdateAttacherJointSettingsByObject()Code
1606 | function AttacherJoints:updateAttacherJointSettingsByObject(vehicle, updateLimit, updateRotationOffset, updateDistanceToGround) |
1607 | local jointDesc = self:getAttacherJointDescFromObject(vehicle) |
1608 | local implement = self:getImplementByObject(vehicle) |
1609 | local objectAttacherJoint = vehicle:getActiveInputAttacherJoint() |
1610 | if jointDesc ~= nil and implement ~= nil then |
1611 | if updateLimit then |
1612 | for i=1, 3 do |
1613 | AttacherJoints.updateAttacherJointLimits(implement, jointDesc, objectAttacherJoint, i) |
1614 | AttacherJoints.updateAttacherJointRotationLimit(implement, jointDesc, i, false, jointDesc.moveLimitAlpha) |
1615 | AttacherJoints.updateAttacherJointTranslationLimit(implement, jointDesc, i, false, jointDesc.moveLimitAlpha) |
1616 | end |
1617 | end |
1618 | |
1619 | if updateRotationOffset then |
1620 | self:updateAttacherJointRotation(jointDesc, vehicle) |
1621 | if self.isServer then |
1622 | setJointFrame(jointDesc.jointIndex, 0, jointDesc.jointTransform) |
1623 | end |
1624 | end |
1625 | |
1626 | if updateDistanceToGround then |
1627 | local upperAlpha, lowerAlpha = self:calculateAttacherJointMoveUpperLowerAlpha(jointDesc, vehicle) |
1628 | jointDesc.moveTime = jointDesc.moveDefaultTime * math.abs(upperAlpha - lowerAlpha) |
1629 | jointDesc.upperAlpha = upperAlpha |
1630 | jointDesc.lowerAlpha = lowerAlpha |
1631 | end |
1632 | end |
1633 | end |
updateAttacherJointTranslationLimit
DescriptionDefinitionupdateAttacherJointTranslationLimit()Code
4437 | function AttacherJoints.updateAttacherJointTranslationLimit(implement, attacherJointDesc, axis, force, alpha) |
4438 | local newTransLimit = MathUtil.lerp( math.max(implement.attachingTransLimit[axis], implement.upperTransLimit[axis]), |
4439 | math.max(implement.attachingTransLimit[axis], implement.lowerTransLimit[axis]), alpha) |
4440 | |
4441 | if force or math.abs(newTransLimit - implement.jointTransLimit[axis]) > 0.0005 then |
4442 | local transLimitDown = -newTransLimit |
4443 | local transLimitUp = newTransLimit |
4444 | if axis == 2 then |
4445 | if attacherJointDesc.lockDownTransLimit then |
4446 | transLimitDown = math.min(-implement.attachingTransLimit[axis], 0) |
4447 | end |
4448 | if attacherJointDesc.lockUpTransLimit then |
4449 | transLimitUp = math.max(implement.attachingTransLimit[axis], 0) |
4450 | end |
4451 | end |
4452 | |
4453 | setJointTranslationLimit(attacherJointDesc.jointIndex, axis-1, true, transLimitDown, transLimitUp) |
4454 | implement.jointTransLimit[axis] = newTransLimit |
4455 | end |
4456 | end |
updateVehiclesInAttachRange
DescriptionDefinitionupdateVehiclesInAttachRange()Code
4135 | function AttacherJoints.updateVehiclesInAttachRange(vehicle, maxDistanceSq, maxAngle, fullUpdate) |
4136 | local spec = vehicle.spec_attacherJoints |
4137 | |
4138 | if spec ~= nil then |
4139 | local attachableInfo = spec.attachableInfo |
4140 | local pendingInfo = spec.pendingAttachableInfo |
4141 | |
4142 | -- first, check if attached implements can attach something |
4143 | if vehicle.getAttachedImplements ~= nil then |
4144 | local implements = vehicle:getAttachedImplements() |
4145 | for _,implement in pairs(implements) do |
4146 | if implement.object ~= nil then |
4147 | local attacherVehicle, attacherVehicleJointDescIndex, attachable, attachableJointDescIndex, warning = AttacherJoints.updateVehiclesInAttachRange(implement.object, maxDistanceSq, maxAngle, fullUpdate) |
4148 | if attacherVehicle ~= nil then |
4149 | attachableInfo.attacherVehicle, attachableInfo.attacherVehicleJointDescIndex, attachableInfo.attachable, attachableInfo.attachableJointDescIndex, attachableInfo.warning = attacherVehicle, attacherVehicleJointDescIndex, attachable, attachableJointDescIndex, warning |
4150 | return attacherVehicle, attacherVehicleJointDescIndex, attachable, attachableJointDescIndex, warning |
4151 | end |
4152 | end |
4153 | end |
4154 | end |
4155 | |
4156 | local numJoints = #g_currentMission.inputAttacherJoints |
4157 | local minUpdateJoints = math.max(math.floor(numJoints / 5), 1) -- update each joint at least every 5 frames |
4158 | local firstJoint = spec.lastInputAttacherCheckIndex % numJoints + 1 |
4159 | local lastJoint = math.min(firstJoint + minUpdateJoints, numJoints) |
4160 | |
4161 | if fullUpdate then |
4162 | firstJoint = 1 |
4163 | lastJoint = numJoints |
4164 | end |
4165 | |
4166 | spec.lastInputAttacherCheckIndex = lastJoint % numJoints |
4167 | |
4168 | for attacherJointIndex=1, #spec.attacherJoints do |
4169 | local attacherJoint = spec.attacherJoints[attacherJointIndex] |
4170 | |
4171 | if attacherJoint.jointIndex == 0 then |
4172 | if vehicle:getIsAttachingAllowed(attacherJoint) then |
4173 | local x, y, z = getWorldTranslation(attacherJoint.jointTransform) |
4174 | |
4175 | for i=firstJoint, lastJoint do |
4176 | local jointInfo = g_currentMission.inputAttacherJoints[i] |
4177 | |
4178 | if jointInfo.jointType == attacherJoint.jointType then |
4179 | if jointInfo.vehicle:getIsInputAttacherActive(jointInfo.inputAttacherJoint) then |
4180 | local distSq = MathUtil.vector2LengthSq(x-jointInfo.translation[1], z-jointInfo.translation[3]) |
4181 | if distSq < maxDistanceSq and distSq < pendingInfo.minDistance then |
4182 | local distY = y-jointInfo.translation[2] |
4183 | local distSqY = distY*distY |
4184 | |
4185 | if distSqY < maxDistanceSq*4 and distSqY < pendingInfo.minDistanceY then |
4186 | if jointInfo.vehicle:getActiveInputAttacherJointDescIndex() == nil or jointInfo.vehicle:getAllowMultipleAttachments() then |
4187 | local compatibility, notAllowedWarning = getAttacherJointCompatibility(vehicle, attacherJoint, jointInfo.vehicle, jointInfo.inputAttacherJoint) |
4188 | if compatibility then |
4189 | local angleInRange |
4190 | local attachAngleLimitAxis = jointInfo.inputAttacherJoint.attachAngleLimitAxis |
4191 | if attachAngleLimitAxis == 1 then |
4192 | local dx, _, _ = localDirectionToLocal(jointInfo.node, attacherJoint.jointTransform, 1, 0, 0) |
4193 | angleInRange = dx > maxAngle |
4194 | elseif attachAngleLimitAxis == 2 then |
4195 | local _, dy, _ = localDirectionToLocal(jointInfo.node, attacherJoint.jointTransform, 0, 1, 0) |
4196 | angleInRange = dy > maxAngle |
4197 | else |
4198 | local _, _, dz = localDirectionToLocal(jointInfo.node, attacherJoint.jointTransform, 0, 0, 1) |
4199 | angleInRange = dz > maxAngle |
4200 | end |
4201 | |
4202 | if angleInRange then |
4203 | pendingInfo.minDistance = distSq |
4204 | pendingInfo.minDistanceY = distSqY |
4205 | pendingInfo.attacherVehicle = vehicle |
4206 | pendingInfo.attacherVehicleJointDescIndex = attacherJointIndex |
4207 | pendingInfo.attachable = jointInfo.vehicle |
4208 | pendingInfo.attachableJointDescIndex = jointInfo.jointIndex |
4209 | end |
4210 | else |
4211 | pendingInfo.warning = pendingInfo.warning or notAllowedWarning |
4212 | end |
4213 | end |
4214 | end |
4215 | end |
4216 | end |
4217 | end |
4218 | end |
4219 | end |
4220 | end |
4221 | end |
4222 | |
4223 | if spec.lastInputAttacherCheckIndex == 0 then |
4224 | attachableInfo.attacherVehicle = pendingInfo.attacherVehicle |
4225 | attachableInfo.attacherVehicleJointDescIndex = pendingInfo.attacherVehicleJointDescIndex |
4226 | attachableInfo.attachable = pendingInfo.attachable |
4227 | attachableInfo.attachableJointDescIndex = pendingInfo.attachableJointDescIndex |
4228 | attachableInfo.warning = pendingInfo.warning |
4229 | |
4230 | pendingInfo.minDistance = math.huge |
4231 | pendingInfo.minDistanceY = math.huge |
4232 | pendingInfo.attacherVehicle = nil |
4233 | pendingInfo.attacherVehicleJointDescIndex = nil |
4234 | pendingInfo.attachable = nil |
4235 | pendingInfo.attachableJointDescIndex = nil |
4236 | pendingInfo.warning = nil |
4237 | end |
4238 | |
4239 | return attachableInfo.attacherVehicle, attachableInfo.attacherVehicleJointDescIndex, attachableInfo.attachable, attachableInfo.attachableJointDescIndex, attachableInfo.warning |
4240 | end |
4241 | |
4242 | return nil, nil, nil, nil |
4243 | end |