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
Pipe
DescriptionSpecialization for vehicles unloading via (foldable) pipe/conveyor (combine, augar wagon, potato/sugarBeet harvester, ...)Functions
- actionEventToggleDischargeToGround
- actionEventTogglePipe
- dischargeToGround
- getCanBeSelected
- getCanBeTurnedOn
- getCanToggleDischargeToGround
- getCanToggleDischargeToObject
- getIsAIPreparingToDrive
- getIsAIReadyToDrive
- getIsDischargeNodeActive
- getIsFoldAllowed
- getIsMovingToolActive
- getIsNextCoverStateAllowed
- getIsPipeStateChangeAllowed
- getPipeDischargeNodeIndex
- getTurnedOnNotAllowedWarning
- handleDischarge
- handleDischargeRaycast
- initSpecialization
- loadCoverFromXML
- loadMovingToolFromXML
- loadPipeNodes
- loadUnloadingTriggers
- onAIImplementPrepare
- onDelete
- onDeletePipeObject
- onDischargeStateChanged
- onLoad
- onMovingToolChanged
- onPostLoad
- onReadStream
- onReadUpdateStream
- onRegisterActionEvents
- onUpdate
- onUpdateTick
- onWriteStream
- onWriteUpdateStream
- prerequisitesPresent
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- registers
- saveToXMLFile
- setPipeDischargeToGround
- setPipeState
- unloadingTriggerCallback
- updateActionEventText
- updateBendingRegulationNodes
- updateNearestObjectInTriggers
- updatePipeNodes
actionEventToggleDischargeToGround
DescriptionDefinitionactionEventToggleDischargeToGround()Code
1379 | function Pipe.actionEventToggleDischargeToGround(self, actionName, inputValue, callbackState, isAnalog) |
1380 | self:setPipeDischargeToGround() |
1381 | end |
actionEventTogglePipe
DescriptionDefinitionactionEventTogglePipe()Code
1363 | function Pipe.actionEventTogglePipe(self, actionName, inputValue, callbackState, isAnalog) |
1364 | local spec = self.spec_pipe |
1365 | local nextState = spec.targetState + 1 |
1366 | if nextState > spec.numStates then |
1367 | nextState = 1 |
1368 | end |
1369 | if self:getIsPipeStateChangeAllowed(nextState) then |
1370 | self:setPipeState(nextState) |
1371 | elseif nextState ~= 1 and self:getIsPipeStateChangeAllowed(1) then |
1372 | -- also try to close the pipe if other states are not allowed |
1373 | self:setPipeState(1) |
1374 | end |
1375 | end |
dischargeToGround
DescriptionDefinitiondischargeToGround()Code
1125 | function Pipe:dischargeToGround(superFunc, dischargeNode, emptyLiters) |
1126 | local spec = self.spec_pipe |
1127 | if spec.toggleableDischargeToGround and not spec.dischargeToGroundState then |
1128 | local unloadInfo = self:getFillVolumeUnloadInfo(dischargeNode.unloadInfoIndex) |
1129 | self:addFillUnitFillLevel(self:getOwnerFarmId(), dischargeNode.fillUnitIndex, -emptyLiters, self:getFillUnitFillType(dischargeNode.fillUnitIndex), ToolType.UNDEFINED, unloadInfo) |
1130 | |
1131 | return -emptyLiters, emptyLiters > 0, emptyLiters > 0 |
1132 | end |
1133 | |
1134 | return superFunc(self, dischargeNode, emptyLiters) |
1135 | end |
getCanBeSelected
DescriptionDefinitiongetCanBeSelected()Code
1266 | function Pipe:getCanBeSelected(superFunc) |
1267 | return true |
1268 | end |
getCanBeTurnedOn
DescriptionDefinitiongetCanBeTurnedOn()Code
1021 | function Pipe:getCanBeTurnedOn(superFunc) |
1022 | local spec = self.spec_pipe |
1023 | |
1024 | if spec.hasMovablePipe then |
1025 | if next(spec.turnOnAllowedStates) ~= nil then |
1026 | local isAllowed = false |
1027 | for pipeState,_ in pairs(spec.turnOnAllowedStates) do |
1028 | if pipeState == spec.currentState then |
1029 | isAllowed = true |
1030 | break |
1031 | end |
1032 | end |
1033 | if not isAllowed then |
1034 | return false |
1035 | end |
1036 | end |
1037 | end |
1038 | |
1039 | return superFunc(self) |
1040 | end |
getCanToggleDischargeToGround
DescriptionDefinitiongetCanToggleDischargeToGround()Code
1150 | function Pipe:getCanToggleDischargeToGround(superFunc) |
1151 | local spec = self.spec_pipe |
1152 | if spec.automaticDischarge and spec.toggleableDischargeToGround then |
1153 | return false |
1154 | end |
1155 | |
1156 | return superFunc(self) |
1157 | end |
getCanToggleDischargeToObject
DescriptionDefinitiongetCanToggleDischargeToObject()Code
1139 | function Pipe:getCanToggleDischargeToObject(superFunc) |
1140 | local spec = self.spec_pipe |
1141 | if spec.automaticDischarge then |
1142 | return false |
1143 | end |
1144 | |
1145 | return superFunc(self) |
1146 | end |
getIsAIPreparingToDrive
DescriptionDefinitiongetIsAIPreparingToDrive()Code
1285 | function Pipe:getIsAIPreparingToDrive(superFunc) |
1286 | local spec = self.spec_pipe |
1287 | if spec.hasMovablePipe then |
1288 | if spec.currentState ~= spec.targetState then |
1289 | return true |
1290 | end |
1291 | end |
1292 | |
1293 | return superFunc(self) |
1294 | end |
getIsAIReadyToDrive
DescriptionDefinitiongetIsAIReadyToDrive()Code
1272 | function Pipe:getIsAIReadyToDrive(superFunc) |
1273 | local spec = self.spec_pipe |
1274 | if spec.hasMovablePipe then |
1275 | if spec.currentState ~= 1 then |
1276 | return false |
1277 | end |
1278 | end |
1279 | |
1280 | return superFunc(self) |
1281 | end |
getIsDischargeNodeActive
DescriptionDefinitiongetIsDischargeNodeActive()Code
1009 | function Pipe:getIsDischargeNodeActive(superFunc, dischargeNode) |
1010 | local spec = self.spec_pipe |
1011 | if dischargeNode.index == self:getPipeDischargeNodeIndex() then |
1012 | -- do an explicit true check to avoid nil issues |
1013 | return spec.unloadingStates[spec.currentState] == true |
1014 | end |
1015 | |
1016 | return superFunc(self, dischargeNode) |
1017 | end |
getIsFoldAllowed
DescriptionDefinitiongetIsFoldAllowed()Code
1067 | function Pipe:getIsFoldAllowed(superFunc, direction, onAiTurnOn) |
1068 | local spec = self.spec_pipe |
1069 | |
1070 | if spec.hasMovablePipe then |
1071 | if spec.currentState > spec.foldMaxState or spec.currentState < spec.foldMinState then |
1072 | return false, spec.texts.warningFoldingPipe |
1073 | end |
1074 | end |
1075 | |
1076 | return superFunc(self, direction, onAiTurnOn) |
1077 | end |
getIsMovingToolActive
DescriptionDefinitiongetIsMovingToolActive()Code
1173 | function Pipe:getIsMovingToolActive(superFunc, movingTool) |
1174 | local spec = self.spec_pipe |
1175 | if movingTool.freezingPipeStates ~= nil then |
1176 | for _, state in pairs(movingTool.freezingPipeStates) do |
1177 | if spec.currentState == state or spec.targetState == state or spec.currentState == 0 then |
1178 | return false |
1179 | end |
1180 | end |
1181 | end |
1182 | |
1183 | return superFunc(self, movingTool) |
1184 | end |
getIsNextCoverStateAllowed
DescriptionDefinitiongetIsNextCoverStateAllowed()Code
1197 | function Pipe:getIsNextCoverStateAllowed(superFunc, nextState) |
1198 | if not superFunc(self, nextState) then |
1199 | return false |
1200 | end |
1201 | |
1202 | local spec = self.spec_pipe |
1203 | local cover = self.spec_cover.covers[nextState] |
1204 | if nextState ~= 0 then |
1205 | if spec.currentState < cover.minPipeState or spec.currentState > cover.maxPipeState then |
1206 | return false |
1207 | end |
1208 | end |
1209 | |
1210 | return true |
1211 | end |
getIsPipeStateChangeAllowed
DescriptionDefinitiongetIsPipeStateChangeAllowed()Code
596 | function Pipe:getIsPipeStateChangeAllowed(pipeState) |
597 | local spec = self.spec_pipe |
598 | |
599 | local foldAnimTime |
600 | if self.getFoldAnimTime ~= nil then |
601 | foldAnimTime = self:getFoldAnimTime() |
602 | end |
603 | |
604 | if foldAnimTime ~= nil and (foldAnimTime < spec.foldMinTime or foldAnimTime > spec.foldMaxTime) then |
605 | return false |
606 | end |
607 | |
608 | return true |
609 | end |
getPipeDischargeNodeIndex
DescriptionDefinitiongetPipeDischargeNodeIndex()Code
1230 | function Pipe:getPipeDischargeNodeIndex(state) |
1231 | local spec = self.spec_pipe |
1232 | |
1233 | if state == nil then |
1234 | state = spec.currentState |
1235 | end |
1236 | |
1237 | if spec.dischargeNodeMapping[state] ~= nil then |
1238 | return spec.dischargeNodeMapping[state] |
1239 | end |
1240 | |
1241 | return spec.dischargeNodeIndex |
1242 | end |
getTurnedOnNotAllowedWarning
DescriptionDefinitiongetTurnedOnNotAllowedWarning()Code
1044 | function Pipe:getTurnedOnNotAllowedWarning(superFunc) |
1045 | local spec = self.spec_pipe |
1046 | |
1047 | if spec.hasMovablePipe then |
1048 | if next(spec.turnOnAllowedStates) ~= nil then |
1049 | local isAllowed = false |
1050 | for pipeState,_ in pairs(spec.turnOnAllowedStates) do |
1051 | if pipeState == spec.currentState then |
1052 | isAllowed = true |
1053 | break |
1054 | end |
1055 | end |
1056 | if not isAllowed then |
1057 | return spec.turnOnStateWarning |
1058 | end |
1059 | end |
1060 | end |
1061 | |
1062 | return superFunc(self) |
1063 | end |
handleDischarge
DescriptionDefinitionhandleDischarge()Code
1081 | function Pipe:handleDischarge(superFunc, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel) |
1082 | local spec = self.spec_pipe |
1083 | if spec.automaticDischarge then |
1084 | -- do nothing if it is pipe dischargenode |
1085 | if dischargeNode.index ~= self:getPipeDischargeNodeIndex() then |
1086 | superFunc(self, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel) |
1087 | end |
1088 | else |
1089 | superFunc(self, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel) |
1090 | end |
1091 | end |
handleDischargeRaycast
DescriptionDefinitionhandleDischargeRaycast()Code
1095 | function Pipe:handleDischargeRaycast(superFunc, dischargeNode, hitObject, hitShape, hitDistance, hitFillUnitIndex, hitTerrain) |
1096 | local spec = self.spec_pipe |
1097 | if spec.automaticDischarge then |
1098 | local stopDischarge = false |
1099 | if self:getIsPowered() and hitObject ~= nil then |
1100 | local fillType = self:getDischargeFillType(dischargeNode) |
1101 | local allowFillType = hitObject:getFillUnitAllowsFillType(hitFillUnitIndex, fillType) |
1102 | if allowFillType and hitObject:getFillUnitFreeCapacity(hitFillUnitIndex, fillType, self:getOwnerFarmId()) > 0 then |
1103 | self:setDischargeState(Dischargeable.DISCHARGE_STATE_OBJECT, true) |
1104 | else |
1105 | stopDischarge = true |
1106 | end |
1107 | elseif self:getIsPowered() and spec.toggleableDischargeToGround then |
1108 | self:setDischargeState(Dischargeable.DISCHARGE_STATE_GROUND, true) |
1109 | else |
1110 | stopDischarge = true |
1111 | end |
1112 | |
1113 | if stopDischarge and self:getDischargeState() == Dischargeable.DISCHARGE_STATE_OBJECT then |
1114 | self:setDischargeState(Dischargeable.DISCHARGE_STATE_OFF, true) |
1115 | end |
1116 | |
1117 | return |
1118 | end |
1119 | |
1120 | superFunc(self, dischargeNode, hitObject, hitShape, hitDistance, hitFillUnitIndex, hitTerrain) |
1121 | end |
initSpecialization
DescriptionCalled on specialization initializingDefinition
initSpecialization()Code
24 | function Pipe.initSpecialization() |
25 | g_configurationManager:addConfigurationType("pipe", g_i18n:getText("configuration_pipe"), "pipe", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION) |
26 | |
27 | local schema = Vehicle.xmlSchema |
28 | schema:setXMLSpecializationType("Pipe") |
29 | |
30 | AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.pipe.animationNodes") |
31 | |
32 | schema:register(XMLValueType.VECTOR_N, Cylindered.MOVING_TOOL_XML_KEY .. "#freezingPipeStates", "Freezing pipe states") |
33 | |
34 | schema:register(XMLValueType.INT, Cover.COVER_XML_KEY .. "#minPipeState", "Min. pipe state", 0) |
35 | schema:register(XMLValueType.INT, Cover.COVER_XML_KEY .. "#maxPipeState", "Max. pipe state", "inf.") |
36 | |
37 | Pipe.registers(schema, "vehicle.pipe") |
38 | Pipe.registers(schema, "vehicle.pipe.pipeConfigurations.pipeConfiguration(?)") |
39 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.pipe.pipeConfigurations.pipeConfiguration(?)") |
40 | |
41 | schema:setXMLSpecializationType() |
42 | |
43 | local schemaSavegame = Vehicle.xmlSchemaSavegame |
44 | schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).pipe#state", "Current pipe state") |
45 | end |
loadCoverFromXML
DescriptionDefinitionloadCoverFromXML()Code
1188 | function Pipe:loadCoverFromXML(superFunc, xmlFile, key, cover) |
1189 | cover.minPipeState = xmlFile:getValue(key.."#minPipeState", 0) |
1190 | cover.maxPipeState = xmlFile:getValue(key.."#maxPipeState", math.huge) |
1191 | |
1192 | return superFunc(self, xmlFile, key, cover) |
1193 | end |
loadMovingToolFromXML
DescriptionDefinitionloadMovingToolFromXML()Code
1161 | function Pipe:loadMovingToolFromXML(superFunc, xmlFile, key, entry) |
1162 | if not superFunc(self, xmlFile, key, entry) then |
1163 | return false |
1164 | end |
1165 | |
1166 | entry.freezingPipeStates = xmlFile:getValue(key.."#freezingPipeStates", nil, true) |
1167 | |
1168 | return true |
1169 | end |
loadPipeNodes
DescriptionDefinitionloadPipeNodes()Code
469 | function Pipe:loadPipeNodes(pipeNodes, xmlFile, baseKey) |
470 | local spec = self.spec_pipe |
471 | |
472 | local maxPriority = 0 |
473 | local i = 0 |
474 | while true do |
475 | local key = string.format("%s(%d)", baseKey, i) |
476 | if not xmlFile:hasProperty(key) then |
477 | break |
478 | end |
479 | local node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
480 | if node ~= nil then |
481 | local entry = {} |
482 | entry.node = node |
483 | entry.autoAimXRotation = xmlFile:getValue(key.."#autoAimXRotation", false) |
484 | entry.autoAimYRotation = xmlFile:getValue(key.."#autoAimYRotation", false) |
485 | entry.autoAimInvertZ = xmlFile:getValue(key.."#autoAimInvertZ", false) |
486 | entry.states = {} |
487 | |
488 | entry.subPipeNode = xmlFile:getValue(key.."#subPipeNode", nil, self.components, self.i3dMappings) |
489 | if entry.subPipeNode ~= nil then |
490 | local x1, _, _ = getRotation(entry.node) |
491 | local x2, _, _ = localRotationToLocal(entry.subPipeNode, getParent(entry.node), 0, 0, 0) |
492 | entry.subPipeNodeRatio = xmlFile:getValue(key.."#subPipeNodeRatio", math.abs(x1 / x2)) |
493 | end |
494 | |
495 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key .. ".state1", key .. ".state") -- FS19 to FS21 |
496 | |
497 | for state=1, spec.numStates do |
498 | local stateKey = key..string.format(".state(%d)", state - 1) |
499 | entry.states[state] = {} |
500 | |
501 | local x, y, z = xmlFile:getValue(stateKey.."#translation", {getTranslation(node)}) |
502 | if state == 1 then |
503 | setTranslation(node, x, y, z) |
504 | end |
505 | entry.states[state].translation = {x, y, z} |
506 | |
507 | x, y, z = xmlFile:getValue(stateKey.."#rotation", {getRotation(node)}) |
508 | if state == 1 then |
509 | setRotation(node, x, y, z) |
510 | end |
511 | entry.states[state].rotation = {x, y, z} |
512 | end |
513 | |
514 | local x, y, z = xmlFile:getValue(key.."#translationSpeeds") |
515 | if x ~= nil and y ~= nil and z ~= nil then |
516 | x, y, z = x * 0.001, y * 0.001, z * 0.001 |
517 | if x ~= 0 or y ~= 0 or z ~= 0 then |
518 | entry.translationSpeeds = {x, y, z} |
519 | end |
520 | end |
521 | x, y, z = xmlFile:getValue(key.."#rotationSpeeds") |
522 | if x ~= nil and y ~= nil and z ~= nil then |
523 | x, y, z = x * 0.001, y * 0.001, z *0.001 |
524 | if x ~= 0 or y ~= 0 or z ~= 0 then |
525 | entry.rotationSpeeds = {x, y, z} |
526 | end |
527 | end |
528 | |
529 | x, y, z = string.getVector(xmlFile:getValue(key.."#minRotationLimits")) |
530 | if x ~= nil or y ~= nil or z ~= nil then |
531 | x = (x ~= nil and math.rad(x)) or nil |
532 | y = (y ~= nil and math.rad(y)) or nil |
533 | z = (z ~= nil and math.rad(z)) or nil |
534 | entry.minRotationLimits = {x, y, z} |
535 | end |
536 | x, y, z = string.getVector(xmlFile:getValue(key.."#maxRotationLimits")) |
537 | if x ~= nil or y ~= nil or z ~= nil then |
538 | x = (x ~= nil and math.rad(x)) or nil |
539 | y = (y ~= nil and math.rad(y)) or nil |
540 | z = (z ~= nil and math.rad(z)) or nil |
541 | entry.maxRotationLimits = {x, y, z} |
542 | end |
543 | |
544 | entry.foldPriority = xmlFile:getValue(key.."#foldPriority", 0) |
545 | maxPriority = math.max(entry.foldPriority, maxPriority) |
546 | |
547 | x, y, z = getTranslation(node) |
548 | entry.curTranslation = {x, y, z} |
549 | |
550 | x, y, z = getRotation(node) |
551 | entry.curRotation = {x, y, z} |
552 | entry.lastTargetRotation = {x, y, z} |
553 | |
554 | entry.bendingRegulation = xmlFile:getValue(key.."#bendingRegulation", 0) |
555 | |
556 | entry.regulationNodes = {} |
557 | |
558 | local j = 0 |
559 | while true do |
560 | local regKey = string.format("%s.bendingRegulationNode(%d)", key, j) |
561 | if not xmlFile:hasProperty(regKey) then |
562 | break |
563 | end |
564 | |
565 | local regulationNode = {} |
566 | regulationNode.node = xmlFile:getValue(regKey.."#node", nil, self.components, self.i3dMappings) |
567 | if regulationNode.node ~= nil then |
568 | regulationNode.startRotation = {getRotation(regulationNode.node)} |
569 | |
570 | local axis = xmlFile:getValue(regKey.."#axis", 1) |
571 | local direction = xmlFile:getValue(regKey.."#direction", 1) |
572 | |
573 | regulationNode.weights = {0, 0, 0} |
574 | regulationNode.weights[MathUtil.clamp(axis, 1, 3)] = direction |
575 | |
576 | table.insert(entry.regulationNodes, regulationNode) |
577 | else |
578 | Logging.xmlWarning(self.xmlFile, "Failed to load bendingRegulationNode '%s'", regKey) |
579 | end |
580 | |
581 | j = j + 1 |
582 | end |
583 | |
584 | table.insert(pipeNodes, entry) |
585 | end |
586 | i = i + 1 |
587 | end |
588 | |
589 | for _, pipeNode in ipairs(pipeNodes) do |
590 | pipeNode.inverseFoldPriority = maxPriority-pipeNode.foldPriority |
591 | end |
592 | end |
loadUnloadingTriggers
DescriptionDefinitionloadUnloadingTriggers()Code
445 | function Pipe:loadUnloadingTriggers(unloadingTriggers, xmlFile, baseKey) |
446 | local i = 0 |
447 | while true do |
448 | local key = string.format("%s(%d)", baseKey, i) |
449 | if not xmlFile:hasProperty(key) then |
450 | break |
451 | end |
452 | |
453 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key.."#index", key.."#node") --FS17 to FS19 |
454 | |
455 | local node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
456 | if node ~= nil then |
457 | if CollisionFlag.getHasFlagSet(node, CollisionFlag.FILLABLE) then |
458 | table.insert(unloadingTriggers, {node=node}) |
459 | else |
460 | Logging.xmlWarning(self.xmlFile, "Missing collision mask bit '%d'. Please add this bit to unload trigger node '%s' in '%s'", CollisionFlag.getBit(CollisionFlag.FILLABLE), getName(node), key) |
461 | end |
462 | end |
463 | i = i + 1 |
464 | end |
465 | end |
onAIImplementPrepare
DescriptionDefinitiononAIImplementPrepare()Code
1352 | function Pipe:onAIImplementPrepare() |
1353 | local spec = self.spec_pipe |
1354 | if spec.hasMovablePipe then |
1355 | if self:getIsPipeStateChangeAllowed(1) then |
1356 | self:setPipeState(1) |
1357 | end |
1358 | end |
1359 | end |
onDelete
DescriptionDefinitiononDelete()Code
314 | function Pipe:onDelete() |
315 | local spec = self.spec_pipe |
316 | |
317 | if spec.unloadingTriggers ~= nil then |
318 | for _, unloadingTrigger in pairs(spec.unloadingTriggers) do |
319 | removeTrigger(unloadingTrigger.node) |
320 | end |
321 | end |
322 | |
323 | g_animationManager:deleteAnimations(spec.animationNodes) |
324 | end |
onDeletePipeObject
DescriptionDefinitiononDeletePipeObject()Code
1215 | function Pipe:onDeletePipeObject(object) |
1216 | local spec = self.spec_pipe |
1217 | if spec.objectsInTriggers[object] ~= nil then |
1218 | spec.objectsInTriggers[object] = nil |
1219 | spec.numObjectsInTriggers = spec.numObjectsInTriggers - 1 |
1220 | end |
1221 | |
1222 | if spec.unloadTriggersInTriggers[object] ~= nil then |
1223 | spec.unloadTriggersInTriggers[object] = nil |
1224 | spec.numUnloadTriggersInTriggers = spec.numUnloadTriggersInTriggers - 1 |
1225 | end |
1226 | end |
onDischargeStateChanged
DescriptionCalled on discharge state changeDefinition
onDischargeStateChanged()Code
1331 | function Pipe:onDischargeStateChanged(state) |
1332 | if self.isClient then |
1333 | local spec = self.spec_pipe |
1334 | local dischargeNode = self:getCurrentDischargeNode() |
1335 | local dischargeNodeIndex = nil |
1336 | if dischargeNode ~= nil then |
1337 | dischargeNodeIndex = dischargeNode.index |
1338 | end |
1339 | if dischargeNodeIndex == self:getPipeDischargeNodeIndex() then |
1340 | if state == Dischargeable.DISCHARGE_STATE_OFF then |
1341 | g_animationManager:stopAnimations(spec.animationNodes) |
1342 | else |
1343 | g_animationManager:startAnimations(spec.animationNodes) |
1344 | g_animationManager:setFillType(spec.animationNodes, self:getFillUnitLastValidFillType(dischargeNode.fillUnitIndex)) |
1345 | end |
1346 | end |
1347 | end |
1348 | end |
onLoad
DescriptionDefinitiononLoad()Code
158 | function Pipe:onLoad(savegame) |
159 | local spec = self.spec_pipe |
160 | |
161 | local pipeConfigurationId = Utils.getNoNil(self.configurations["pipe"], 1) |
162 | local baseKey = string.format("vehicle.pipe.pipeConfigurations.pipeConfiguration(%d)", pipeConfigurationId -1) |
163 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.pipe.pipeConfigurations.pipeConfiguration", pipeConfigurationId , self.components, self) |
164 | |
165 | -- fallback key |
166 | if not self.xmlFile:hasProperty(baseKey) then |
167 | baseKey = "vehicle.pipe" |
168 | end |
169 | |
170 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipeEffect.effectNode", baseKey..".pipeEffect.effectNode") --FS17 to FS19 |
171 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.overloading.trailerTriggers.trailerTrigger(0)#index", baseKey..".unloadingTriggers.unloadingTrigger(0)#node") --FS17 to FS19 |
172 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#raycastNodeIndex", baseKey..".raycast#node") --FS17 to FS19 |
173 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#raycastDistance", baseKey..".raycast#maxDistance") --FS17 to FS19 |
174 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#effectExtraDistanceOnTrailer", baseKey..".raycast#extraDistance") --FS17 to FS19 |
175 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#animName", baseKey..".animation#name") --FS17 to FS19 |
176 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#animSpeedScale", baseKey..".animation#speedScale") --FS17 to FS19 |
177 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#animSpeedScale", baseKey..".animation#speedScale") --FS17 to FS19 |
178 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe.node#node", baseKey..".node#node") --FS17 to FS19 |
179 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#numStates", baseKey..".states#num") --FS17 to FS19 |
180 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#unloadingStates", baseKey..".states#unloading") --FS17 to FS19 |
181 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#autoAimingStates", baseKey..".states#autoAiming") --FS17 to FS19 |
182 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#turnOnAllowed", baseKey..".states#turnOnAllowed") --FS17 to FS19 |
183 | |
184 | spec.turnOnStateWarning = string.format(self.xmlFile:getValue(baseKey.."#turnOnStateWarning", "warning_firstSetPipeState", self.customEnvironment), self.typeDesc) |
185 | |
186 | spec.dischargeNodeIndex = self.xmlFile:getValue(baseKey .. "#dischargeNodeIndex", 1) |
187 | spec.forceDischargeNodeIndex = self.xmlFile:getValue(baseKey .. "#forceDischargeNodeIndex", true) |
188 | if spec.forceDischargeNodeIndex then |
189 | self:setCurrentDischargeNodeIndex(spec.dischargeNodeIndex) |
190 | end |
191 | |
192 | spec.automaticDischarge = self.xmlFile:getValue(baseKey .. "#automaticDischarge", true) |
193 | spec.toggleableDischargeToGround = self.xmlFile:getValue(baseKey .. "#toggleableDischargeToGround", false) |
194 | spec.dischargeToGroundState = false |
195 | |
196 | spec.unloadingTriggers = {} |
197 | spec.objectsInTriggers = {} |
198 | spec.unloadTriggersInTriggers = {} |
199 | spec.numObjectsInTriggers = 0 |
200 | spec.numUnloadTriggersInTriggers = 0 |
201 | spec.nearestObjectInTriggers = {objectId=nil, fillUnitIndex=0} |
202 | spec.nearestObjectInTriggersSent = {objectId=nil, fillUnitIndex=0} |
203 | |
204 | self:loadUnloadingTriggers(spec.unloadingTriggers, self.xmlFile, baseKey .. ".unloadingTriggers.unloadingTrigger") |
205 | if #spec.unloadingTriggers == 0 then |
206 | Logging.xmlWarning(self.xmlFile, "No 'unloadingTriggers' defined for pipe 'vehicle.pipe'!") |
207 | else |
208 | for _,trigger in pairs(spec.unloadingTriggers) do |
209 | addTrigger(trigger.node, "unloadingTriggerCallback", self) |
210 | end |
211 | end |
212 | |
213 | spec.animation = {} |
214 | spec.animation.name = self.xmlFile:getValue(baseKey .. ".animation#name") |
215 | spec.animation.speedScale = self.xmlFile:getValue(baseKey .. ".animation#speedScale", 1) |
216 | |
217 | spec.currentState = 1 |
218 | spec.targetState = 1 |
219 | spec.numStates = self.xmlFile:getValue(baseKey .. ".states#num", 0) |
220 | |
221 | spec.nodes = {} |
222 | self:loadPipeNodes(spec.nodes, self.xmlFile, baseKey .. ".pipeNodes.pipeNode") |
223 | spec.hasMovablePipe = #spec.nodes > 0 or spec.animation.name ~= nil |
224 | |
225 | local function loadState(target, xmlFile, key) |
226 | local i = 0 |
227 | local states = xmlFile:getValue(key, nil, true) |
228 | if states ~= nil then |
229 | for _, state in ipairs(states) do |
230 | target[state] = true |
231 | i = i + 1 |
232 | end |
233 | end |
234 | |
235 | return i |
236 | end |
237 | |
238 | spec.unloadingStates = {} |
239 | spec.autoAimingStates = {} |
240 | spec.turnOnAllowedStates = {} |
241 | spec.numUnloadingStates = loadState(spec.unloadingStates, self.xmlFile, baseKey .. ".states#unloading") |
242 | spec.numAutoAimingStates = loadState(spec.autoAimingStates, self.xmlFile, baseKey .. ".states#autoAiming") |
243 | spec.numTurnOnAllowedStates = loadState(spec.turnOnAllowedStates, self.xmlFile, baseKey .. ".states#turnOnAllowed") |
244 | |
245 | spec.dischargeNodeMapping = {} |
246 | local i = 0 |
247 | while true do |
248 | local stateKey = string.format("%s.states.state(%d)", baseKey, i) |
249 | if not self.xmlFile:hasProperty(stateKey) then |
250 | break |
251 | end |
252 | |
253 | local stateIndex = self.xmlFile:getValue(stateKey .. "#stateIndex") |
254 | local dischargeNodeIndex = self.xmlFile:getValue(stateKey .. "#dischargeNodeIndex") |
255 | |
256 | if stateIndex ~= nil and dischargeNodeIndex ~= nil then |
257 | spec.dischargeNodeMapping[stateIndex] = dischargeNodeIndex |
258 | end |
259 | |
260 | i = i + 1 |
261 | end |
262 | |
263 | if self.isClient then |
264 | spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.pipe.animationNodes", self.components, self, self.i3dMappings) |
265 | end |
266 | |
267 | spec.foldMinTime = self.xmlFile:getValue(baseKey .. "#foldMinLimit", 0.0) |
268 | spec.foldMaxTime = self.xmlFile:getValue(baseKey .. "#foldMaxLimit", 1.0) |
269 | spec.foldMinState = self.xmlFile:getValue(baseKey .. "#foldMinState", 1) |
270 | spec.foldMaxState = self.xmlFile:getValue(baseKey .. "#foldMaxState", spec.numStates) |
271 | |
272 | spec.aiFoldedPipeUsesTrailerSpace = self.xmlFile:getValue(baseKey .. "#aiFoldedPipeUsesTrailerSpace", false) |
273 | |
274 | spec.texts = {} |
275 | spec.texts.warningFoldingPipe = g_i18n:getText("warning_foldingNotWhilePipeExtended") |
276 | spec.texts.pipeIn = g_i18n:getText("action_pipeIn") |
277 | spec.texts.pipeOut = g_i18n:getText("action_pipeOut") |
278 | spec.texts.startTipToGround = g_i18n:getText("action_startTipToGround") |
279 | spec.texts.stopTipToGround = g_i18n:getText("action_stopTipToGround") |
280 | |
281 | spec.dirtyFlag = self:getNextDirtyFlag() |
282 | |
283 | spec.lastFillTime = -1000 |
284 | spec.lastEmptyTime = -1000 |
285 | |
286 | if not self.isServer then |
287 | SpecializationUtil.removeEventListener(self, "onUpdateTick", Pipe) |
288 | end |
289 | end |
onMovingToolChanged
DescriptionDefinitiononMovingToolChanged()Code
1298 | function Pipe:onMovingToolChanged(tool, transSpeed, dt) |
1299 | local spec = self.spec_pipe |
1300 | for _, pipeNode in ipairs(spec.nodes) do |
1301 | if pipeNode.node == tool.node then |
1302 | pipeNode.curTranslation = {tool.curTrans[1], tool.curTrans[2], tool.curTrans[3]} |
1303 | pipeNode.curRotation = {tool.curRot[1], tool.curRot[2], tool.curRot[3]} |
1304 | end |
1305 | end |
1306 | end |
onPostLoad
DescriptionDefinitiononPostLoad()Code
293 | function Pipe:onPostLoad(savegame) |
294 | local spec = self.spec_pipe |
295 | |
296 | if savegame ~= nil and not savegame.resetVehicles then |
297 | local pipeState = savegame.xmlFile:getValue(savegame.key..".pipe#state", spec.currentState) |
298 | self:setPipeState(pipeState, true) |
299 | self:updatePipeNodes(999999, nil) |
300 | |
301 | if spec.animation.name ~= nil then |
302 | local targetTime = 0 |
303 | if pipeState ~= 1 then |
304 | targetTime = 1 |
305 | end |
306 | |
307 | self:setAnimationTime(spec.animation.name, targetTime, true) |
308 | end |
309 | end |
310 | end |
onReadStream
DescriptionDefinitiononReadStream()Code
335 | function Pipe:onReadStream(streamId, connection) |
336 | local spec = self.spec_pipe |
337 | |
338 | local pipeState = streamReadUIntN(streamId, 2) |
339 | self:setPipeState(pipeState, true) |
340 | |
341 | if streamReadBool(streamId) then |
342 | spec.nearestObjectInTriggers.objectId = NetworkUtil.readNodeObjectId(streamId) |
343 | spec.nearestObjectInTriggers.fillUnitIndex = streamReadUIntN(streamId, 4) |
344 | end |
345 | end |
onReadUpdateStream
DescriptionDefinitiononReadUpdateStream()Code
362 | function Pipe:onReadUpdateStream(streamId, timestamp, connection) |
363 | if connection:getIsServer() then |
364 | if streamReadBool(streamId) then |
365 | local spec = self.spec_pipe |
366 | if streamReadBool(streamId) then |
367 | spec.nearestObjectInTriggers.objectId = NetworkUtil.readNodeObjectId(streamId) |
368 | spec.nearestObjectInTriggers.fillUnitIndex = streamReadUIntN(streamId, 4) |
369 | else |
370 | spec.nearestObjectInTriggers.objectId = nil |
371 | spec.nearestObjectInTriggers.fillUnitIndex = 0 |
372 | end |
373 | end |
374 | end |
375 | end |
onRegisterActionEvents
DescriptionDefinitiononRegisterActionEvents()Code
1310 | function Pipe:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
1311 | if self.isClient then |
1312 | local spec = self.spec_pipe |
1313 | self:clearActionEventsTable(spec.actionEvents) |
1314 | |
1315 | if isActiveForInputIgnoreSelection and spec.hasMovablePipe then |
1316 | local _, actionEventId = self:addPoweredActionEvent(spec.actionEvents, InputAction.TOGGLE_PIPE, self, Pipe.actionEventTogglePipe, false, true, false, true, nil) |
1317 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH) |
1318 | self:updateActionEventText() |
1319 | |
1320 | if spec.toggleableDischargeToGround then |
1321 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_TIPSTATE_GROUND, self, Pipe.actionEventToggleDischargeToGround, false, true, false, true, nil) |
1322 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL) |
1323 | g_inputBinding:setActionEventText(actionEventId, spec.dischargeToGroundState and spec.texts.stopTipToGround or spec.texts.startTipToGround) |
1324 | end |
1325 | end |
1326 | end |
1327 | end |
onUpdate
DescriptionDefinitiononUpdate()Code
393 | function Pipe:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
394 | local spec = self.spec_pipe |
395 | |
396 | self:updateActionEventText() |
397 | |
398 | if spec.hasMovablePipe then |
399 | self:updatePipeNodes(dt, spec.nearestObjectInTriggers) |
400 | end |
401 | end |
onUpdateTick
DescriptionDefinitiononUpdateTick()Code
405 | function Pipe:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
406 | if self.isServer then |
407 | self:updateNearestObjectInTriggers() |
408 | |
409 | local spec = self.spec_pipe |
410 | local objectChanged = spec.nearestObjectInTriggers.objectId ~= spec.nearestObjectInTriggersSent.objectId |
411 | local fillUnitChanged = spec.nearestObjectInTriggers.fillUnitIndex ~= spec.nearestObjectInTriggersSent.fillUnitIndex |
412 | if objectChanged or fillUnitChanged then |
413 | spec.nearestObjectInTriggersSent.objectId = spec.nearestObjectInTriggers.objectId |
414 | spec.nearestObjectInTriggersSent.fillUnitIndex = spec.nearestObjectInTriggers.fillUnitIndex |
415 | self:raiseDirtyFlags(spec.dirtyFlag) |
416 | end |
417 | |
418 | -- automatic unfold pipe if trailer is in trigger |
419 | if Platform.gameplay.automaticPipeUnfolding and not self:getIsAIActive() then |
420 | local unfoldPipe = spec.nearestObjectInTriggers.objectId ~= nil or spec.numUnloadTriggersInTriggers > 0 |
421 | |
422 | -- only unfold if the vehicle is filled |
423 | local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex()) |
424 | if dischargeNode ~= nil then |
425 | local capacity = self:getFillUnitCapacity(dischargeNode.fillUnitIndex) |
426 | local fillLevel =self:getFillUnitFillLevel(dischargeNode.fillUnitIndex) |
427 | unfoldPipe = unfoldPipe and ((capacity == math.huge and (self.getIsTurnedOn == nil or self:getIsTurnedOn())) or fillLevel > 0) |
428 | end |
429 | |
430 | if unfoldPipe then |
431 | if spec.targetState == 1 then |
432 | self:setPipeState(next(spec.unloadingStates)) |
433 | end |
434 | else |
435 | if spec.targetState > 1 then |
436 | self:setPipeState(1) |
437 | end |
438 | end |
439 | end |
440 | end |
441 | end |
onWriteStream
DescriptionDefinitiononWriteStream()Code
349 | function Pipe:onWriteStream(streamId, connection) |
350 | local spec = self.spec_pipe |
351 | |
352 | streamWriteUIntN(streamId, spec.targetState, 2) |
353 | |
354 | if streamWriteBool(streamId, spec.nearestObjectInTriggersSent.objectId ~= nil) then |
355 | NetworkUtil.writeNodeObjectId(streamId, spec.nearestObjectInTriggersSent.objectId) |
356 | streamWriteUIntN(streamId, spec.nearestObjectInTriggersSent.fillUnitIndex, 4) |
357 | end |
358 | end |
onWriteUpdateStream
DescriptionDefinitiononWriteUpdateStream()Code
379 | function Pipe:onWriteUpdateStream(streamId, connection, dirtyMask) |
380 | if not connection:getIsServer() then |
381 | local spec = self.spec_pipe |
382 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then |
383 | if streamWriteBool(streamId, spec.nearestObjectInTriggersSent.objectId ~= nil) then |
384 | NetworkUtil.writeNodeObjectId(streamId, spec.nearestObjectInTriggersSent.objectId) |
385 | streamWriteUIntN(streamId, spec.nearestObjectInTriggersSent.fillUnitIndex, 4) |
386 | end |
387 | end |
388 | end |
389 | end |
prerequisitesPresent
DescriptionDefinitionprerequisitesPresent()Code
18 | function Pipe.prerequisitesPresent(specializations) |
19 | return SpecializationUtil.hasSpecialization(FillUnit, specializations) and SpecializationUtil.hasSpecialization(Dischargeable, specializations) |
20 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
140 | function Pipe.registerEventListeners(vehicleType) |
141 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Pipe) |
142 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Pipe) |
143 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Pipe) |
144 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Pipe) |
145 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Pipe) |
146 | SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Pipe) |
147 | SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Pipe) |
148 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Pipe) |
149 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Pipe) |
150 | SpecializationUtil.registerEventListener(vehicleType, "onMovingToolChanged", Pipe) |
151 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Pipe) |
152 | SpecializationUtil.registerEventListener(vehicleType, "onDischargeStateChanged", Pipe) |
153 | SpecializationUtil.registerEventListener(vehicleType, "onAIImplementPrepare", Pipe) |
154 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
102 | function Pipe.registerFunctions(vehicleType) |
103 | SpecializationUtil.registerFunction(vehicleType, "loadUnloadingTriggers", Pipe.loadUnloadingTriggers) |
104 | SpecializationUtil.registerFunction(vehicleType, "loadPipeNodes", Pipe.loadPipeNodes) |
105 | SpecializationUtil.registerFunction(vehicleType, "getIsPipeStateChangeAllowed", Pipe.getIsPipeStateChangeAllowed) |
106 | SpecializationUtil.registerFunction(vehicleType, "setPipeState", Pipe.setPipeState) |
107 | SpecializationUtil.registerFunction(vehicleType, "updatePipeNodes", Pipe.updatePipeNodes) |
108 | SpecializationUtil.registerFunction(vehicleType, "updateBendingRegulationNodes", Pipe.updateBendingRegulationNodes) |
109 | SpecializationUtil.registerFunction(vehicleType, "unloadingTriggerCallback", Pipe.unloadingTriggerCallback) |
110 | SpecializationUtil.registerFunction(vehicleType, "updateNearestObjectInTriggers", Pipe.updateNearestObjectInTriggers) |
111 | SpecializationUtil.registerFunction(vehicleType, "updateActionEventText", Pipe.updateActionEventText) |
112 | SpecializationUtil.registerFunction(vehicleType, "onDeletePipeObject", Pipe.onDeletePipeObject) |
113 | SpecializationUtil.registerFunction(vehicleType, "getPipeDischargeNodeIndex", Pipe.getPipeDischargeNodeIndex) |
114 | SpecializationUtil.registerFunction(vehicleType, "setPipeDischargeToGround", Pipe.setPipeDischargeToGround) |
115 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
119 | function Pipe.registerOverwrittenFunctions(vehicleType) |
120 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDischargeNodeActive", Pipe.getIsDischargeNodeActive) |
121 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", Pipe.getCanBeTurnedOn) |
122 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getTurnedOnNotAllowedWarning", Pipe.getTurnedOnNotAllowedWarning) |
123 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", Pipe.getIsFoldAllowed) |
124 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "handleDischarge", Pipe.handleDischarge) |
125 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "handleDischargeRaycast", Pipe.handleDischargeRaycast) |
126 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "dischargeToGround", Pipe.dischargeToGround) |
127 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleDischargeToObject", Pipe.getCanToggleDischargeToObject) |
128 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleDischargeToGround", Pipe.getCanToggleDischargeToGround) |
129 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadMovingToolFromXML", Pipe.loadMovingToolFromXML) |
130 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsMovingToolActive", Pipe.getIsMovingToolActive) |
131 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadCoverFromXML", Pipe.loadCoverFromXML) |
132 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsNextCoverStateAllowed", Pipe.getIsNextCoverStateAllowed) |
133 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", Pipe.getCanBeSelected) |
134 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAIReadyToDrive", Pipe.getIsAIReadyToDrive) |
135 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAIPreparingToDrive", Pipe.getIsAIPreparingToDrive) |
136 | end |
registers
DescriptionCalled on specialization initializingDefinition
registers()Code
49 | function Pipe.registers(schema, basePath) |
50 | schema:register(XMLValueType.L10N_STRING, basePath .. "#turnOnStateWarning", "Turn on warning", "warning_firstSetPipeState") |
51 | schema:register(XMLValueType.INT, basePath .. "#dischargeNodeIndex", "Discharge node index", 1) |
52 | schema:register(XMLValueType.BOOL, basePath .. "#forceDischargeNodeIndex", "Force discharge node selection while changing pipe state. Can be deactivated e.g. if the selection is done by trailer spec etc.", true) |
53 | schema:register(XMLValueType.BOOL, basePath .. "#automaticDischarge", "Pipe is automatically starting to discharge as soon as it hits the trailer", true) |
54 | schema:register(XMLValueType.BOOL, basePath .. "#toggleableDischargeToGround", "Defines if the discharge to ground can be enabled separatly", false) |
55 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".unloadingTriggers.unloadingTrigger(?)#node", "Unload trigger node") |
56 | |
57 | schema:register(XMLValueType.STRING, basePath .. ".animation#name", "Pipe animation name") |
58 | schema:register(XMLValueType.FLOAT, basePath .. ".animation#speedScale", "Pipe animation speed scale", 1) |
59 | schema:register(XMLValueType.INT, basePath .. ".states#num", "Number of pipe states", 0) |
60 | |
61 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".pipeNodes.pipeNode(?)#node", "Pipe node") |
62 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".pipeNodes.pipeNode(?)#subPipeNode", "Sub pipe node (Target rotation is devided between these two nodes depending on the X rotation ratio between #node and #node parent and #subPipeNode and #node parent)") |
63 | schema:register(XMLValueType.FLOAT, basePath .. ".pipeNodes.pipeNode(?)#subPipeNodeRatio", "Ratio between usage of this pipe node and sub node [0-1]", "Calculated based on rotation in i3d file") |
64 | schema:register(XMLValueType.BOOL, basePath .. ".pipeNodes.pipeNode(?)#autoAimXRotation", "Auto aim X rotation", false) |
65 | schema:register(XMLValueType.BOOL, basePath .. ".pipeNodes.pipeNode(?)#autoAimYRotation", "Auto aim Y rotation", false) |
66 | schema:register(XMLValueType.BOOL, basePath .. ".pipeNodes.pipeNode(?)#autoAimInvertZ", "Auto aim invert Z axis", false) |
67 | |
68 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".pipeNodes.pipeNode(?).state(?)#translation", "State translation") |
69 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".pipeNodes.pipeNode(?).state(?)#rotation", "State translation") |
70 | |
71 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".pipeNodes.pipeNode(?)#translationSpeeds", "Translation speeds") |
72 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".pipeNodes.pipeNode(?)#rotationSpeeds", "Rotation speeds") |
73 | |
74 | schema:register(XMLValueType.STRING, basePath .. ".pipeNodes.pipeNode(?)#minRotationLimits", "Min. rotation limit") |
75 | schema:register(XMLValueType.STRING, basePath .. ".pipeNodes.pipeNode(?)#maxRotationLimits", "Max. rotation limit") |
76 | |
77 | schema:register(XMLValueType.INT, basePath .. ".pipeNodes.pipeNode(?)#foldPriority", "Fold priority", 0) |
78 | schema:register(XMLValueType.FLOAT, basePath .. ".pipeNodes.pipeNode(?)#bendingRegulation", "Bending angle regulation", 0) |
79 | |
80 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".pipeNodes.pipeNode(?).bendingRegulationNode(?)#node", "Bending regulation node", 0) |
81 | schema:register(XMLValueType.INT, basePath .. ".pipeNodes.pipeNode(?).bendingRegulationNode(?)#axis", "Bending regulation axis", 0) |
82 | schema:register(XMLValueType.INT, basePath .. ".pipeNodes.pipeNode(?).bendingRegulationNode(?)#direction", "Bending regulation direction", 0) |
83 | |
84 | schema:register(XMLValueType.VECTOR_N, basePath .. ".states#unloading", "Unloading states") |
85 | schema:register(XMLValueType.VECTOR_N, basePath .. ".states#autoAiming", "Auto aim states") |
86 | schema:register(XMLValueType.VECTOR_N, basePath .. ".states#turnOnAllowed", "Turn on allowed states") |
87 | |
88 | schema:register(XMLValueType.INT, basePath .. ".states.state(?)#stateIndex", "State index") |
89 | schema:register(XMLValueType.INT, basePath .. ".states.state(?)#dischargeNodeIndex", "Discharge node index") |
90 | |
91 | schema:register(XMLValueType.FLOAT, basePath .. "#foldMinLimit", "Fold min. limit", 0) |
92 | schema:register(XMLValueType.FLOAT, basePath .. "#foldMaxLimit", "Fold max. limit", 1) |
93 | |
94 | schema:register(XMLValueType.INT, basePath .. "#foldMinState", "Fold min. state", 1) |
95 | schema:register(XMLValueType.INT, basePath .. "#foldMaxState", "Fold max. state", "Num. of states") |
96 | |
97 | schema:register(XMLValueType.BOOL, basePath .. "#aiFoldedPipeUsesTrailerSpace", "Defines if the folded pipe uses the space of the trailer to discharge", false) |
98 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
328 | function Pipe:saveToXMLFile(xmlFile, key, usedModNames) |
329 | local spec = self.spec_pipe |
330 | xmlFile:setValue(key.."#state", MathUtil.clamp(spec.currentState, 1, spec.numStates)) |
331 | end |
setPipeDischargeToGround
DescriptionDefinitionsetPipeDischargeToGround()Code
1246 | function Pipe:setPipeDischargeToGround(state, noEventSend) |
1247 | local spec = self.spec_pipe |
1248 | if state == nil then |
1249 | state = not spec.dischargeToGroundState |
1250 | end |
1251 | |
1252 | if state ~= spec.dischargeToGroundState then |
1253 | spec.dischargeToGroundState = state |
1254 | |
1255 | local actionEvent = spec.actionEvents[InputAction.TOGGLE_TIPSTATE_GROUND] |
1256 | if actionEvent ~= nil then |
1257 | g_inputBinding:setActionEventText(actionEvent.actionEventId, state and spec.texts.stopTipToGround or spec.texts.startTipToGround) |
1258 | end |
1259 | |
1260 | SetPipeDischargeToGroundEvent.sendEvent(self, state, noEventSend) |
1261 | end |
1262 | end |
setPipeState
DescriptionDefinitionsetPipeState()Code
613 | function Pipe:setPipeState(pipeState, noEventSend) |
614 | local spec = self.spec_pipe |
615 | |
616 | pipeState = math.min(pipeState, spec.numStates) |
617 | if spec.targetState ~= pipeState then |
618 | if noEventSend == nil or noEventSend == false then |
619 | if g_server ~= nil then |
620 | g_server:broadcastEvent(SetPipeStateEvent.new(self, pipeState)) |
621 | else |
622 | g_client:getServerConnection():sendEvent(SetPipeStateEvent.new(self, pipeState), nil, nil, self) |
623 | end |
624 | end |
625 | spec.targetState = pipeState |
626 | spec.currentState = 0 |
627 | |
628 | if spec.animation ~= nil then |
629 | if pipeState == 1 then |
630 | self:playAnimation(spec.animation.name, -spec.animation.speedScale, self:getAnimationTime(spec.animation.name), true) |
631 | else |
632 | self:playAnimation(spec.animation.name, spec.animation.speedScale, self:getAnimationTime(spec.animation.name), true) |
633 | end |
634 | end |
635 | |
636 | if spec.forceDischargeNodeIndex then |
637 | self:setCurrentDischargeNodeIndex(self:getPipeDischargeNodeIndex(pipeState)) |
638 | end |
639 | end |
640 | end |
unloadingTriggerCallback
DescriptionDefinitionunloadingTriggerCallback()Code
847 | function Pipe:unloadingTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId) |
848 | if onEnter or onLeave then |
849 | local object = g_currentMission:getNodeObject(otherId) |
850 | |
851 | if object ~= nil and object ~= self and object:isa(Vehicle) then |
852 | if object.getFillUnitIndexFromNode ~= nil then |
853 | local fillUnitIndex = object:getFillUnitIndexFromNode(otherId) |
854 | if fillUnitIndex ~= nil then |
855 | local spec = self.spec_pipe |
856 | |
857 | local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex()) |
858 | if dischargeNode ~= nil then |
859 | local fillTypes = self:getFillUnitSupportedFillTypes(dischargeNode.fillUnitIndex) |
860 | |
861 | -- objects is only valid if it supports at least one of the harvesters fill types |
862 | local objectSupportsFillType = false |
863 | for fillType, _ in pairs(fillTypes) do |
864 | if object:getFillUnitSupportsFillType(fillUnitIndex, fillType) then |
865 | objectSupportsFillType = true |
866 | break |
867 | end |
868 | end |
869 | |
870 | if objectSupportsFillType then |
871 | if onEnter then |
872 | if spec.objectsInTriggers[object] == nil then |
873 | spec.objectsInTriggers[object] = 0 |
874 | spec.numObjectsInTriggers = spec.numObjectsInTriggers + 1 |
875 | if object.addDeleteListener ~= nil then |
876 | object:addDeleteListener(self, "onDeletePipeObject") |
877 | end |
878 | end |
879 | |
880 | spec.objectsInTriggers[object] = spec.objectsInTriggers[object] + 1 |
881 | else |
882 | spec.objectsInTriggers[object] = spec.objectsInTriggers[object] - 1 |
883 | if spec.objectsInTriggers[object] == 0 then |
884 | spec.objectsInTriggers[object] = nil |
885 | spec.numObjectsInTriggers = spec.numObjectsInTriggers - 1 |
886 | if object.removeDeleteListener ~= nil then |
887 | object:removeDeleteListener(self) |
888 | end |
889 | end |
890 | end |
891 | end |
892 | end |
893 | end |
894 | end |
895 | elseif object ~= nil and object ~= self and object:isa(UnloadTrigger) then |
896 | local spec = self.spec_pipe |
897 | if onEnter then |
898 | if spec.unloadTriggersInTriggers[object] == nil then |
899 | spec.unloadTriggersInTriggers[object] = 0 |
900 | spec.numUnloadTriggersInTriggers = spec.numUnloadTriggersInTriggers + 1 |
901 | if object.addDeleteListener ~= nil then |
902 | object:addDeleteListener(self, "onDeletePipeObject") |
903 | end |
904 | end |
905 | |
906 | spec.unloadTriggersInTriggers[object] = spec.unloadTriggersInTriggers[object] + 1 |
907 | else |
908 | spec.unloadTriggersInTriggers[object] = spec.unloadTriggersInTriggers[object] - 1 |
909 | if spec.unloadTriggersInTriggers[object] == 0 then |
910 | spec.unloadTriggersInTriggers[object] = nil |
911 | spec.numUnloadTriggersInTriggers = spec.numUnloadTriggersInTriggers - 1 |
912 | if object.removeDeleteListener ~= nil then |
913 | object:removeDeleteListener(self) |
914 | end |
915 | end |
916 | end |
917 | end |
918 | end |
919 | end |
updateActionEventText
DescriptionDefinitionupdateActionEventText()Code
969 | function Pipe:updateActionEventText() |
970 | local spec = self.spec_pipe |
971 | |
972 | -- check if action event already exists. Nil on loading |
973 | local actionEvent = spec.actionEvents[InputAction.TOGGLE_PIPE] |
974 | if actionEvent ~= nil then |
975 | local showAction = false |
976 | if spec.targetState == spec.numStates then |
977 | if self:getIsPipeStateChangeAllowed(1) then |
978 | g_inputBinding:setActionEventText(actionEvent.actionEventId, spec.texts.pipeIn) |
979 | showAction = true |
980 | end |
981 | else |
982 | local nextState = spec.targetState + 1 |
983 | if self:getIsPipeStateChangeAllowed(nextState) then |
984 | local pipeStateName = "" |
985 | if spec.numUnloadingStates > 1 and spec.numUnloadingStates ~= spec.numStates then |
986 | pipeStateName = string.format(" [%d]", nextState - 1) |
987 | local dischargeNodeIndex = self:getPipeDischargeNodeIndex(nextState) |
988 | local dischargeNode = self:getDischargeNodeByIndex(dischargeNodeIndex) |
989 | local fillTypeIndex = self:getFillUnitFillType(dischargeNode.fillUnitIndex) |
990 | if fillTypeIndex ~= FillType.UNKNOWN then |
991 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex) |
992 | if fillType ~= nil then |
993 | pipeStateName = string.format(" [%d, %s]", nextState - 1, fillType.title) |
994 | end |
995 | end |
996 | end |
997 | |
998 | g_inputBinding:setActionEventText(actionEvent.actionEventId, string.format(spec.texts.pipeOut, pipeStateName)) |
999 | showAction = true |
1000 | end |
1001 | end |
1002 | |
1003 | g_inputBinding:setActionEventActive(actionEvent.actionEventId, showAction) |
1004 | end |
1005 | end |
updateBendingRegulationNodes
DescriptionDefinitionupdateBendingRegulationNodes()Code
824 | function Pipe:updateBendingRegulationNodes(pipeNode, distance) |
825 | local _, dirY, _ = localDirectionToWorld(pipeNode.node, 0, 1, 0) |
826 | |
827 | for _, regulationNode in ipairs(pipeNode.regulationNodes) do |
828 | local regulationAngle = dirY*pipeNode.bendingRegulation |
829 | local weights = regulationNode.weights |
830 | local startRotation = regulationNode.startRotation |
831 | setRotation(regulationNode.node, startRotation[1]+weights[1]*regulationAngle, |
832 | startRotation[2]+weights[2]*regulationAngle, |
833 | startRotation[3]+weights[3]*regulationAngle) |
834 | |
835 | if VehicleDebug.state == VehicleDebug.DEBUG then |
836 | local x1, y1, z1 = getWorldTranslation(regulationNode.node) |
837 | local x2, y2, z2 = localToWorld(regulationNode.node, 0, -10, 0) |
838 | drawDebugLine(x1, y1, z1, 0, 0, 1, x2, y2, z2, 0, 0, 1) |
839 | end |
840 | end |
841 | |
842 | return math.sin(dirY*pipeNode.bendingRegulation) * distance |
843 | end |
updateNearestObjectInTriggers
DescriptionDefinitionupdateNearestObjectInTriggers()Code
923 | function Pipe:updateNearestObjectInTriggers() |
924 | local spec = self.spec_pipe |
925 | |
926 | spec.nearestObjectInTriggers.objectId = nil |
927 | spec.nearestObjectInTriggers.fillUnitIndex = 0 |
928 | |
929 | local minDistance = math.huge |
930 | local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex()) |
931 | if dischargeNode ~= nil then |
932 | local checkNode = Utils.getNoNil(dischargeNode.node, self.components[1].node) |
933 | |
934 | for object, _ in pairs(spec.objectsInTriggers) do |
935 | local outputFillType = self:getFillUnitLastValidFillType(dischargeNode.fillUnitIndex) |
936 | |
937 | for fillUnitIndex, _ in ipairs(object.spec_fillUnit.fillUnits) do |
938 | local allowedToFillByPipe = object:getFillUnitSupportsToolType(fillUnitIndex, ToolType.DISCHARGEABLE) |
939 | local supportsFillType = object:getFillUnitSupportsFillType(fillUnitIndex, outputFillType) or outputFillType == FillType.UNKNOWN |
940 | local fillLevel = object:getFillUnitFreeCapacity(fillUnitIndex, outputFillType, self:getOwnerFarmId()) |
941 | |
942 | if allowedToFillByPipe and supportsFillType and fillLevel > 0 then |
943 | local targetPoint = object:getFillUnitAutoAimTargetNode(fillUnitIndex) |
944 | local exactFillRootNode = object:getFillUnitExactFillRootNode(fillUnitIndex) |
945 | |
946 | if targetPoint == nil then |
947 | targetPoint = exactFillRootNode |
948 | end |
949 | |
950 | if targetPoint ~= nil then |
951 | local distance = calcDistanceFrom(checkNode, targetPoint) |
952 | if distance < minDistance then |
953 | minDistance = distance |
954 | spec.nearestObjectInTriggers.objectId = NetworkUtil.getObjectId(object) |
955 | spec.nearestObjectInTriggers.fillUnitIndex = fillUnitIndex |
956 | break |
957 | end |
958 | end |
959 | end |
960 | end |
961 | end |
962 | else |
963 | Logging.xmlWarning(self.xmlFile, "Unable to find discharge node index '%d' for pipe", self:getPipeDischargeNodeIndex()) |
964 | end |
965 | end |
updatePipeNodes
DescriptionDefinitionupdatePipeNodes()Code
644 | function Pipe:updatePipeNodes(dt, nearestObjectInTrigger) |
645 | local spec = self.spec_pipe |
646 | local object = nil |
647 | if nearestObjectInTrigger ~= nil then |
648 | object = NetworkUtil.getObject(nearestObjectInTrigger.objectId) |
649 | end |
650 | |
651 | local doAutoAiming = object ~= nil and entityExists(object.components[1].node) and spec.autoAimingStates[spec.currentState] |
652 | |
653 | if spec.currentState ~= spec.targetState or doAutoAiming then |
654 | local priority = spec.targetState ~= spec.numStates and "foldPriority" or "inverseFoldPriority" |
655 | |
656 | local fillAutoAimTargetNode |
657 | local autoAimX, autoAimY, autoAimZ |
658 | if doAutoAiming then |
659 | fillAutoAimTargetNode = object:getFillUnitAutoAimTargetNode(nearestObjectInTrigger.fillUnitIndex) |
660 | if fillAutoAimTargetNode == nil then |
661 | fillAutoAimTargetNode = object:getFillUnitExactFillRootNode(nearestObjectInTrigger.fillUnitIndex) |
662 | end |
663 | |
664 | autoAimX, autoAimY, autoAimZ = getWorldTranslation(fillAutoAimTargetNode) |
665 | |
666 | if VehicleDebug.state == VehicleDebug.DEBUG then |
667 | DebugUtil.drawDebugGizmoAtWorldPos(autoAimX, autoAimY, autoAimZ, 0, 0, 1, 0, 1, 0, getName(fillAutoAimTargetNode), false) |
668 | end |
669 | end |
670 | |
671 | local moved = false |
672 | for i=1, #spec.nodes do |
673 | local nodeMoved = false |
674 | local pipeNode = spec.nodes[i] |
675 | |
676 | local nodeAutoAimY = autoAimY |
677 | if pipeNode.bendingRegulation > 0 then |
678 | if fillAutoAimTargetNode ~= nil then |
679 | local distance = calcDistanceFrom(pipeNode.node, fillAutoAimTargetNode) |
680 | local regulation = self:updateBendingRegulationNodes(pipeNode, distance) |
681 | nodeAutoAimY = autoAimY - regulation |
682 | end |
683 | end |
684 | |
685 | local state = pipeNode.states[spec.targetState] |
686 | if pipeNode.translationSpeeds ~= nil then |
687 | for axis=1, 3 do |
688 | if math.abs(pipeNode.curTranslation[axis] - state.translation[axis]) > 0.000001 then |
689 | nodeMoved = true |
690 | if pipeNode.curTranslation[axis] < state.translation[axis] then |
691 | pipeNode.curTranslation[axis] = math.min(pipeNode.curTranslation[axis] + dt*pipeNode.translationSpeeds[axis], state.translation[axis]) |
692 | else |
693 | pipeNode.curTranslation[axis] = math.max(pipeNode.curTranslation[axis] - dt*pipeNode.translationSpeeds[axis], state.translation[axis]) |
694 | end |
695 | end |
696 | end |
697 | setTranslation(pipeNode.node, pipeNode.curTranslation[1],pipeNode.curTranslation[2],pipeNode.curTranslation[3]) |
698 | end |
699 | if pipeNode.rotationSpeeds ~= nil then |
700 | local changed = false |
701 | for axis=1, 3 do |
702 | local targetRotation = state.rotation[axis] |
703 | if doAutoAiming then |
704 | if pipeNode.autoAimXRotation and axis == 1 then |
705 | local x, y, z = getWorldTranslation(pipeNode.node) |
706 | |
707 | if VehicleDebug.state == VehicleDebug.DEBUG then |
708 | if pipeNode.subPipeNode == nil then |
709 | drawDebugLine(x, y, z, 1, 0, 0, autoAimX, nodeAutoAimY, autoAimZ, 1, 0, 0) |
710 | else |
711 | local x1, y1, z1 = getWorldTranslation(pipeNode.node) |
712 | local x2, y2, z2 = localToWorld(pipeNode.node, 0, 0, 3) |
713 | drawDebugLine(x1, y1, z1, 1, 1, 0, x2, y2, z2, 1, 1, 0) |
714 | |
715 | DebugUtil.drawDebugGizmoAtWorldPos(x2, y2, z2, 0, 0, 1, 0, 1, 0, string.format("ratio: %.2f", pipeNode.subPipeNodeRatio), false) |
716 | end |
717 | end |
718 | |
719 | local _, lDirY, lDirZ = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, nodeAutoAimY-y, autoAimZ-z) |
720 | targetRotation = -math.atan2(lDirY, lDirZ) |
721 | |
722 | if pipeNode.subPipeNode ~= nil then |
723 | targetRotation = targetRotation * pipeNode.subPipeNodeRatio |
724 | end |
725 | |
726 | if pipeNode.autoAimInvertZ then |
727 | targetRotation = targetRotation+math.pi |
728 | end |
729 | targetRotation = MathUtil.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[axis]) |
730 | elseif pipeNode.autoAimYRotation and axis == 2 then |
731 | local x, y, z = getWorldTranslation(pipeNode.node) |
732 | local lDirX, _, lDirZ = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, nodeAutoAimY-y, autoAimZ-z) |
733 | targetRotation = math.atan2(lDirX, lDirZ) |
734 | if pipeNode.autoAimInvertZ then |
735 | targetRotation = targetRotation+math.pi |
736 | end |
737 | targetRotation = MathUtil.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[axis]) |
738 | end |
739 | end |
740 | if pipeNode.minRotationLimits ~= nil and pipeNode.maxRotationLimits ~= nil then |
741 | if math.abs(targetRotation) > (2 * math.pi) then |
742 | targetRotation = targetRotation % (2 * math.pi) |
743 | end |
744 | |
745 | if pipeNode.minRotationLimits[axis] ~= nil then |
746 | targetRotation = math.max(targetRotation, pipeNode.minRotationLimits[axis]) |
747 | end |
748 | if pipeNode.maxRotationLimits[axis] ~= nil then |
749 | targetRotation = math.min(targetRotation, pipeNode.maxRotationLimits[axis]) |
750 | end |
751 | end |
752 | if math.abs(pipeNode.curRotation[axis] - targetRotation) > 0.00001 then |
753 | changed = true |
754 | local rotationAllowed = true |
755 | -- priorities only while folding the pipe, not while auto aiming |
756 | if not doAutoAiming then |
757 | for j=1, #spec.nodes do |
758 | local pipeNodeToCheck = spec.nodes[j] |
759 | if pipeNodeToCheck[priority] > pipeNode[priority] then |
760 | for l=1, 3 do |
761 | if pipeNodeToCheck.curRotation[l] ~= pipeNodeToCheck.lastTargetRotation[l] then |
762 | rotationAllowed = false |
763 | break |
764 | end |
765 | end |
766 | end |
767 | end |
768 | end |
769 | |
770 | if rotationAllowed then |
771 | nodeMoved = true |
772 | if pipeNode.curRotation[axis] < targetRotation then |
773 | pipeNode.curRotation[axis] = math.min(pipeNode.curRotation[axis] + dt*pipeNode.rotationSpeeds[axis], targetRotation) |
774 | else |
775 | pipeNode.curRotation[axis] = math.max(pipeNode.curRotation[axis] - dt*pipeNode.rotationSpeeds[axis], targetRotation) |
776 | end |
777 | if pipeNode.curRotation[axis] > 2*math.pi then |
778 | pipeNode.curRotation[axis] = pipeNode.curRotation[axis] - 2*math.pi |
779 | elseif pipeNode.curRotation[axis] < -2*math.pi then |
780 | pipeNode.curRotation[axis] = pipeNode.curRotation[axis] + 2*math.pi |
781 | end |
782 | |
783 | pipeNode.lastTargetRotation[axis] = targetRotation |
784 | end |
785 | end |
786 | end |
787 | |
788 | if changed then |
789 | setRotation(pipeNode.node, pipeNode.curRotation[1], pipeNode.curRotation[2], pipeNode.curRotation[3]) |
790 | end |
791 | end |
792 | moved = moved or nodeMoved |
793 | |
794 | if nodeMoved and self.setMovingToolDirty ~= nil then |
795 | self:setMovingToolDirty(pipeNode.node) |
796 | end |
797 | end |
798 | |
799 | if #spec.nodes == 0 and spec.animation.name ~= nil then |
800 | if self:getIsAnimationPlaying(spec.animation.name) then |
801 | moved = true |
802 | end |
803 | end |
804 | |
805 | if not moved then |
806 | spec.currentState = spec.targetState |
807 | end |
808 | else |
809 | if self:getDischargeState() == Dischargeable.DISCHARGE_STATE_GROUND then |
810 | local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex()) |
811 | if dischargeNode ~= nil then |
812 | for _,pipeNode in ipairs(spec.nodes) do |
813 | if pipeNode.bendingRegulation > 0 then |
814 | self:updateBendingRegulationNodes(pipeNode, dischargeNode.dischargeDistance) |
815 | end |
816 | end |
817 | end |
818 | end |
819 | end |
820 | end |