140 | function Attachable.initSpecialization() |
141 | g_configurationManager:addConfigurationType("inputAttacherJoint", g_i18n:getText("configuration_inputAttacherJoint"), "attachable", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION) |
142 | |
143 | local schema = Vehicle.xmlSchema |
144 | schema:setXMLSpecializationType("Attachable") |
145 | |
146 | Attachable.registerInputAttacherJointXMLPaths(schema, Attachable.INPUT_ATTACHERJOINT_XML_KEY) |
147 | Attachable.registerInputAttacherJointXMLPaths(schema, Attachable.INPUT_ATTACHERJOINT_CONFIG_XML_KEY) |
148 | |
149 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.attachable.inputAttacherJointConfigurations.inputAttacherJointConfiguration(?)") |
150 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, Attachable.INPUT_ATTACHERJOINT_XML_KEY) |
151 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, Attachable.INPUT_ATTACHERJOINT_CONFIG_XML_KEY) |
152 | |
153 | schema:register(XMLValueType.INT, "vehicle.attachable#connectionHoseConfigId", "Connection hose configuration index to use") |
154 | schema:register(XMLValueType.INT, "vehicle.attachable#powerTakeOffConfigId", "Power take off configuration index to use") |
155 | schema:register(XMLValueType.INT, "vehicle.attachable.inputAttacherJointConfigurations.inputAttacherJointConfiguration(?)#connectionHoseConfigId", "Connection hose configuration index to use") |
156 | schema:register(XMLValueType.INT, "vehicle.attachable.inputAttacherJointConfigurations.inputAttacherJointConfiguration(?)#powerTakeOffConfigId", "Power take off configuration index to use") |
157 | |
158 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.brakeForce#force", "Brake force", 0) |
159 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.brakeForce#maxForce", "Brake force when vehicle reached mass of #maxForceMass", 0) |
160 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.brakeForce#maxForceMass", "When this mass is reached the vehicle will brake with #maxForce", 0) |
161 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.brakeForce#loweredForce", "Brake force while the tool is lowered") |
162 | |
163 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.airConsumer#usage", "Air consumption while fully braking", 0) |
164 | schema:register(XMLValueType.BOOL, "vehicle.attachable#allowFoldingWhileAttached", "Allow folding while attached", true) |
165 | schema:register(XMLValueType.BOOL, "vehicle.attachable#allowFoldingWhileLowered", "Allow folding while lowered", true) |
166 | schema:register(XMLValueType.BOOL, "vehicle.attachable#blockFoliageDestruction", "If active the vehicle will block the complete foliage destruction of the vehicle chain", false) |
167 | |
168 | schema:register(XMLValueType.BOOL, "vehicle.attachable.power#requiresExternalPower", "Tool requires external power from a vehicle with motor to work", true) |
169 | schema:register(XMLValueType.L10N_STRING, "vehicle.attachable.power#attachToPowerWarning", "Warning to be displayed if no vehicle with motor is attached", "warning_attachToPower") |
170 | |
171 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.steeringAxleAngleScale#startSpeed", "Start speed", 10) |
172 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.steeringAxleAngleScale#endSpeed", "End speed", 30) |
173 | schema:register(XMLValueType.BOOL, "vehicle.attachable.steeringAxleAngleScale#backwards", "Is active backwards", false) |
174 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.steeringAxleAngleScale#speed", "Speed", 0.001) |
175 | schema:register(XMLValueType.BOOL, "vehicle.attachable.steeringAxleAngleScale#useSuperAttachable", "Use super attachable", false) |
176 | schema:register(XMLValueType.NODE_INDEX, "vehicle.attachable.steeringAxleAngleScale.targetNode#node", "Target node") |
177 | schema:register(XMLValueType.ANGLE, "vehicle.attachable.steeringAxleAngleScale.targetNode#refAngle", "Reference angle to transfer from angle between vehicles to defined min. and max. rot for target node") |
178 | schema:register(XMLValueType.ANGLE, "vehicle.attachable.steeringAxleAngleScale#minRot", "Min Rotation", 0) |
179 | schema:register(XMLValueType.ANGLE, "vehicle.attachable.steeringAxleAngleScale#maxRot", "Max Rotation", 0) |
180 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.steeringAxleAngleScale#direction", "Direction", 1) |
181 | schema:register(XMLValueType.BOOL, "vehicle.attachable.steeringAxleAngleScale#forceUsage", "Force usage of steering axle, even if attacher vehicle does not have steering bar nodes", false) |
182 | schema:register(XMLValueType.BOOL, "vehicle.attachable.steeringAxleAngleScale#speedDependent", "Steering axle angle is scaled based on speed with #startSpeed and #endSpeed", true) |
183 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.steeringAxleAngleScale#distanceDelay", "The steering angle is updated delayed after vehicle has been moved this distance", 0) |
184 | schema:register(XMLValueType.INT, "vehicle.attachable.steeringAxleAngleScale#referenceComponentIndex", "If defined the given component is used for steering angle reference. Y between root component and this component will result in steering angle.") |
185 | |
186 | schema:register(XMLValueType.NODE_INDEX, Attachable.STEERING_ANGLE_NODE_XML_KEY .. "#node", "Steering angle node") |
187 | schema:register(XMLValueType.ANGLE, Attachable.STEERING_ANGLE_NODE_XML_KEY .. "#speed", "Change speed (degree per second)", 25) |
188 | schema:register(XMLValueType.FLOAT, Attachable.STEERING_ANGLE_NODE_XML_KEY .. "#scale", "Scale of vehicle to vehicle angle that is applied", 1) |
189 | schema:register(XMLValueType.ANGLE, Attachable.STEERING_ANGLE_NODE_XML_KEY .. "#offset", "Angle offset", 0) |
190 | schema:register(XMLValueType.FLOAT, Attachable.STEERING_ANGLE_NODE_XML_KEY .. "#minSpeed", "Min. speed of vehicle to update", 0) |
191 | |
192 | schema:register(XMLValueType.STRING, "vehicle.attachable.support(?)#animationName", "Animation name") |
193 | schema:register(XMLValueType.BOOL, "vehicle.attachable.support(?)#delayedOnLoad", "Defines if the animation is played onPostLoad or onLoadFinished -> useful if the animation collides e.g. with the folding animation", false) |
194 | schema:register(XMLValueType.BOOL, "vehicle.attachable.support(?)#delayedOnAttach", "Defines if the animation is played before or after the attaching process", true) |
195 | schema:register(XMLValueType.BOOL, "vehicle.attachable.support(?)#detachAfterAnimation", "Defines if the vehicle is detached after the animation has played", true) |
196 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.support(?)#detachAnimationTime", "Defines when in the support animation the vehicle is detached (detachAfterAnimation needs to be true)", 1) |
197 | |
198 | schema:register(XMLValueType.STRING, "vehicle.attachable.lowerAnimation#name", "Animation name") |
199 | schema:register(XMLValueType.FLOAT, "vehicle.attachable.lowerAnimation#speed", "Animation speed", 1) |
200 | schema:register(XMLValueType.INT, "vehicle.attachable.lowerAnimation#directionOnDetach", "Direction on detach", 0) |
201 | schema:register(XMLValueType.BOOL, "vehicle.attachable.lowerAnimation#defaultLowered", "Is default lowered", false) |
202 | |
203 | VehicleCamera.registerCameraXMLPaths(schema, "vehicle.attachable.toolCameras.toolCamera(?)") |
204 | |
205 | for i=1, #Lights.ADDITIONAL_LIGHT_ATTRIBUTES_KEYS do |
206 | local key = Lights.ADDITIONAL_LIGHT_ATTRIBUTES_KEYS[i] |
207 | schema:register(XMLValueType.INT, key .. "#inputAttacherJointIndex", "Index of input attacher joint that needs to be active to activate light") |
208 | end |
209 | |
210 | schema:register(XMLValueType.BOOL, Dashboard.GROUP_XML_KEY .. "#isAttached", "Tool is attached") |
211 | |
212 | schema:addDelayedRegistrationFunc("AnimatedVehicle:part", function(cSchema, cKey) |
213 | cSchema:register(XMLValueType.INT, cKey .. "#inputAttacherJointIndex", "Input Attacher Joint Index [1..n]") |
214 | |
215 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#lowerRotLimitScaleStart", "Lower rotaton limit start") |
216 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#lowerRotLimitScaleEnd", "Lower rotaton limit end") |
217 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#upperRotLimitScaleStart", "Upper rotaton limit start") |
218 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#upperRotLimitScaleEnd", "Upper rotaton limit end") |
219 | |
220 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#lowerTransLimitScaleStart", "Lower translation limit start") |
221 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#lowerTransLimitScaleEnd", "Lower translation limit end") |
222 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#upperTransLimitScaleStart", "Upper translation limit start") |
223 | cSchema:register(XMLValueType.VECTOR_3, cKey .. "#upperTransLimitScaleEnd", "Upper translation limit end") |
224 | |
225 | cSchema:register(XMLValueType.ANGLE, cKey .. "#lowerRotationOffsetStart", "Lower rotation offset start") |
226 | cSchema:register(XMLValueType.ANGLE, cKey .. "#lowerRotationOffsetEnd", "Lower rotation offset end") |
227 | cSchema:register(XMLValueType.ANGLE, cKey .. "#upperRotationOffsetStart", "Upper rotation offset start") |
228 | cSchema:register(XMLValueType.ANGLE, cKey .. "#upperRotationOffsetEnd", "Upper rotation offset end") |
229 | |
230 | cSchema:register(XMLValueType.FLOAT, cKey .. "#lowerDistanceToGroundStart", "Lower distance to ground start") |
231 | cSchema:register(XMLValueType.FLOAT, cKey .. "#lowerDistanceToGroundEnd", "Lower distance to ground end") |
232 | cSchema:register(XMLValueType.FLOAT, cKey .. "#upperDistanceToGroundStart", "Upper distance to ground start") |
233 | cSchema:register(XMLValueType.FLOAT, cKey .. "#upperDistanceToGroundEnd", "Upper distance to ground end") |
234 | end) |
235 | |
236 | schema:setXMLSpecializationType() |
237 | |
238 | local schemaSavegame = Vehicle.xmlSchemaSavegame |
239 | schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?).attachable#lowerAnimTime", "Lower animation time") |
240 | end |
780 | function Attachable:loadInputAttacherJoint(xmlFile, key, inputAttacherJoint, index) |
781 | XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. "#index", key .. "#node") -- FS17 to FS19 |
782 | XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. "#indexVisual", key .. "#nodeVisual") -- FS17 to FS19 |
783 | XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. "#ptoInputNode", "vehicle.powerTakeOffs.input") -- FS17 to FS19 |
784 | XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. "#lowerDistanceToGround", key..".distanceToGround#lower") -- FS17 to FS19 |
785 | XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. "#upperDistanceToGround", key..".distanceToGround#upper") -- FS17 to FS19 |
786 | |
787 | local node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
788 | if node ~= nil then |
789 | inputAttacherJoint.node = node |
790 | |
791 | inputAttacherJoint.heightNodes = {} |
792 | xmlFile:iterate(key .. ".heightNode", function(_, heightNodeKey) |
793 | local heightNode = {} |
794 | if self:loadAttacherJointHeightNode(xmlFile, heightNodeKey, heightNode, node) then |
795 | table.insert(inputAttacherJoint.heightNodes, heightNode) |
796 | end |
797 | end) |
798 | |
799 | local jointTypeStr = xmlFile:getValue(key .. "#jointType") |
800 | local jointType |
801 | if jointTypeStr ~= nil then |
802 | jointType = AttacherJoints.jointTypeNameToInt[jointTypeStr] |
803 | if jointType == nil then |
804 | Logging.xmlWarning(self.xmlFile, "Invalid jointType '%s' for inputAttacherJoint '%s'!", tostring(jointTypeStr), key) |
805 | end |
806 | else |
807 | Logging.xmlWarning(self.xmlFile, "Missing jointType for inputAttacherJoint '%s'!", key) |
808 | end |
809 | if jointType == nil then |
810 | local needsTrailerJoint = xmlFile:getValue(key .. "#needsTrailerJoint", false) |
811 | local needsLowTrailerJoint = xmlFile:getValue(key .. "#needsLowJoint", false) |
812 | if needsTrailerJoint then |
813 | if needsLowTrailerJoint then |
814 | jointType = AttacherJoints.JOINTTYPE_TRAILERLOW |
815 | else |
816 | jointType = AttacherJoints.JOINTTYPE_TRAILER |
817 | end |
818 | else |
819 | jointType = AttacherJoints.JOINTTYPE_IMPLEMENT |
820 | end |
821 | end |
822 | inputAttacherJoint.jointType = jointType |
823 | |
824 | local subTypeStr = xmlFile:getValue(key.. ".subType#name") |
825 | inputAttacherJoint.subTypes = string.split(subTypeStr, " ") |
826 | if #inputAttacherJoint.subTypes == 0 then |
827 | inputAttacherJoint.subTypes = nil |
828 | end |
829 | inputAttacherJoint.subTypeShowWarning = xmlFile:getValue(key.. ".subType#showWarning", true) |
830 | |
831 | inputAttacherJoint.jointOrigTrans = { getTranslation(inputAttacherJoint.node) } |
832 | inputAttacherJoint.jointOrigOffsetComponent = { localToLocal(self:getParentComponent(inputAttacherJoint.node), inputAttacherJoint.node, 0, 0, 0) } |
833 | inputAttacherJoint.jointOrigDirOffsetComponent = { localDirectionToLocal(self:getParentComponent(inputAttacherJoint.node), inputAttacherJoint.node, 0, 0, 1) } |
834 | inputAttacherJoint.topReferenceNode = xmlFile:getValue(key .. "#topReferenceNode", nil, self.components, self.i3dMappings) |
835 | inputAttacherJoint.rootNode = xmlFile:getValue(key .. "#rootNode", self.components[1].node, self.components, self.i3dMappings) |
836 | inputAttacherJoint.rootNodeBackup = inputAttacherJoint.rootNode |
837 | inputAttacherJoint.allowsDetaching = xmlFile:getValue(key .. "#allowsDetaching", true) |
838 | inputAttacherJoint.fixedRotation = xmlFile:getValue(key .. "#fixedRotation", false) |
839 | inputAttacherJoint.hardAttach = xmlFile:getValue(key .. "#hardAttach", false) |
840 | if inputAttacherJoint.hardAttach and #self.components > 1 then |
841 | Logging.xmlWarning(self.xmlFile, "hardAttach only available for single component vehicles! InputAttacherJoint '%s'!", key) |
842 | inputAttacherJoint.hardAttach = false |
843 | end |
844 | inputAttacherJoint.visualNode = xmlFile:getValue(key .. "#nodeVisual", nil, self.components, self.i3dMappings) |
845 | if inputAttacherJoint.hardAttach and inputAttacherJoint.visualNode ~= nil then |
846 | inputAttacherJoint.visualNodeData = { |
847 | parent = getParent(inputAttacherJoint.visualNode), |
848 | translation = { getTranslation(inputAttacherJoint.visualNode) }, |
849 | rotation = { getRotation(inputAttacherJoint.visualNode) }, |
850 | index = getChildIndex(inputAttacherJoint.visualNode) |
851 | } |
852 | end |
853 | |
854 | |
855 | if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT |
856 | or jointType == AttacherJoints.JOINTTYPE_CUTTER |
857 | or jointType == AttacherJoints.JOINTTYPE_CUTTERHARVESTER then |
858 | if xmlFile:getValue(key .. ".distanceToGround#lower") == nil then |
859 | Logging.xmlWarning(self.xmlFile, "Missing '.distanceToGround#lower' for inputAttacherJoint '%s'!", key) |
860 | end |
861 | if xmlFile:getValue(key .. ".distanceToGround#upper") == nil then |
862 | Logging.xmlWarning(self.xmlFile, "Missing '.distanceToGround#upper' for inputAttacherJoint '%s'!", key) |
863 | end |
864 | end |
865 | |
866 | inputAttacherJoint.lowerDistanceToGround = xmlFile:getValue(key .. ".distanceToGround#lower", 0.7) |
867 | inputAttacherJoint.upperDistanceToGround = xmlFile:getValue(key .. ".distanceToGround#upper", 1.0) |
868 | if inputAttacherJoint.lowerDistanceToGround > inputAttacherJoint.upperDistanceToGround then |
869 | Logging.xmlWarning(self.xmlFile, "distanceToGround#lower may not be larger than distanceToGround#upper for inputAttacherJoint '%s'. Switching values!", key) |
870 | local copy = inputAttacherJoint.lowerDistanceToGround |
871 | inputAttacherJoint.lowerDistanceToGround = inputAttacherJoint.upperDistanceToGround |
872 | inputAttacherJoint.upperDistanceToGround = copy |
873 | end |
874 | |
875 | inputAttacherJoint.distanceToGroundByVehicle = {} |
876 | xmlFile:iterate(key .. ".distanceToGround.vehicle", function(_, vehicleKey) |
877 | local entry = {} |
878 | entry.filename = xmlFile:getValue(vehicleKey .. "#filename") |
879 | if entry.filename ~= nil then |
880 | entry.filename = entry.filename:lower() |
881 | entry.lower = xmlFile:getValue(vehicleKey .. "#lower", inputAttacherJoint.lowerDistanceToGround) |
882 | entry.upper = xmlFile:getValue(vehicleKey .. "#upper", inputAttacherJoint.upperDistanceToGround) |
883 | |
884 | table.insert(inputAttacherJoint.distanceToGroundByVehicle, entry) |
885 | end |
886 | end) |
887 | |
888 | inputAttacherJoint.lowerDistanceToGroundOriginal = inputAttacherJoint.lowerDistanceToGround |
889 | inputAttacherJoint.upperDistanceToGroundOriginal = inputAttacherJoint.upperDistanceToGround |
890 | |
891 | inputAttacherJoint.lowerRotationOffset = xmlFile:getValue(key .. "#lowerRotationOffset", 0) |
892 | |
893 | local defaultUpperRotationOffset = 0 |
894 | if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT then |
895 | defaultUpperRotationOffset = 8 |
896 | end |
897 | |
898 | inputAttacherJoint.upperRotationOffset = xmlFile:getValue(key .. "#upperRotationOffset", defaultUpperRotationOffset) |
899 | |
900 | inputAttacherJoint.allowsJointRotLimitMovement = xmlFile:getValue(key .. "#allowsJointRotLimitMovement", true) |
901 | inputAttacherJoint.allowsJointTransLimitMovement = xmlFile:getValue(key .. "#allowsJointTransLimitMovement", true) |
902 | |
903 | inputAttacherJoint.needsToolbar = xmlFile:getValue(key .. "#needsToolbar", false) |
904 | if inputAttacherJoint.needsToolbar and jointType ~= AttacherJoints.JOINTTYPE_IMPLEMENT then |
905 | Logging.xmlWarning(self.xmlFile, "'needsToolbar' requires jointType 'implement' for inputAttacherJoint '%s'!", key) |
906 | inputAttacherJoint.needsToolbar = false |
907 | end |
908 | |
909 | inputAttacherJoint.steeringBarLeftNode = xmlFile:getValue(key .. "#steeringBarLeftNode", nil, self.components, self.i3dMappings) |
910 | inputAttacherJoint.steeringBarRightNode = xmlFile:getValue(key .. "#steeringBarRightNode", nil, self.components, self.i3dMappings) |
911 | |
912 | --load joint limit scales |
913 | inputAttacherJoint.upperRotLimitScale = xmlFile:getValue( key .. "#upperRotLimitScale", "0 0 0", true) |
914 | local x, y, z = xmlFile:getValue( key .. "#lowerRotLimitScale") |
915 | if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT then |
916 | inputAttacherJoint.lowerRotLimitScale = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 1) } |
917 | else |
918 | inputAttacherJoint.lowerRotLimitScale = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) } |
919 | end |
920 | inputAttacherJoint.rotLimitThreshold = xmlFile:getValue( key .. "#rotLimitThreshold", 0) |
921 | |
922 | inputAttacherJoint.upperTransLimitScale = xmlFile:getValue( key .. "#upperTransLimitScale", "0 0 0", true) |
923 | inputAttacherJoint.lowerTransLimitScale = xmlFile:getValue( key .. "#lowerTransLimitScale", "0 1 0", true) |
924 | inputAttacherJoint.transLimitThreshold = xmlFile:getValue( key .. "#transLimitThreshold", 0) |
925 | |
926 | inputAttacherJoint.rotLimitSpring = xmlFile:getValue( key.."#rotLimitSpring", "0 0 0", true) |
927 | inputAttacherJoint.rotLimitDamping = xmlFile:getValue( key.."#rotLimitDamping", "1 1 1", true) |
928 | inputAttacherJoint.rotLimitForceLimit = xmlFile:getValue( key.."#rotLimitForceLimit", "-1 -1 -1", true) |
929 | |
930 | inputAttacherJoint.transLimitSpring = xmlFile:getValue( key.."#transLimitSpring", "0 0 0", true) |
931 | inputAttacherJoint.transLimitDamping = xmlFile:getValue( key.."#transLimitDamping", "1 1 1", true) |
932 | inputAttacherJoint.transLimitForceLimit = xmlFile:getValue( key.."#transLimitForceLimit", "-1 -1 -1", true) |
933 | |
934 | inputAttacherJoint.attachAngleLimitAxis = xmlFile:getValue(key .. "#attachAngleLimitAxis", 1) |
935 | |
936 | inputAttacherJoint.attacherHeight = xmlFile:getValue(key .. "#attacherHeight") |
937 | if inputAttacherJoint.attacherHeight == nil then |
938 | if jointType == AttacherJoints.JOINTTYPE_TRAILER then |
939 | inputAttacherJoint.attacherHeight = 0.9 |
940 | elseif jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then |
941 | inputAttacherJoint.attacherHeight = 0.55 |
942 | end |
943 | end |
944 | |
945 | local defaultNeedsLowering = true |
946 | local defaultAllowsLowering = false |
947 | if inputAttacherJoint.jointType == AttacherJoints.JOINTTYPE_TRAILER or inputAttacherJoint.jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then |
948 | defaultNeedsLowering = false |
949 | end |
950 | if inputAttacherJoint.jointType ~= AttacherJoints.JOINTTYPE_TRAILER and inputAttacherJoint.jointType ~= AttacherJoints.JOINTTYPE_TRAILERLOW then |
951 | defaultAllowsLowering = true |
952 | end |
953 | inputAttacherJoint.needsLowering = xmlFile:getValue(key.. "#needsLowering", defaultNeedsLowering) |
954 | inputAttacherJoint.allowsLowering = xmlFile:getValue(key.. "#allowsLowering", defaultAllowsLowering) |
955 | inputAttacherJoint.isDefaultLowered = xmlFile:getValue(key.. "#isDefaultLowered", false) |
956 | inputAttacherJoint.useFoldingLoweredState = xmlFile:getValue(key.. "#useFoldingLoweredState", false) |
957 | inputAttacherJoint.forceSelection = xmlFile:getValue(key.."#forceSelectionOnAttach", true) |
958 | inputAttacherJoint.forceAllowDetachWhileLifted = xmlFile:getValue(key.."#forceAllowDetachWhileLifted", false) |
959 | inputAttacherJoint.forcedAttachingDirection = xmlFile:getValue(key.."#forcedAttachingDirection", 0) |
960 | |
961 | inputAttacherJoint.allowFolding = xmlFile:getValue(key.."#allowFolding", true) |
962 | inputAttacherJoint.allowTurnOn = xmlFile:getValue(key.."#allowTurnOn", true) |
963 | inputAttacherJoint.allowAI = xmlFile:getValue(key.."#allowAI", true) |
964 | inputAttacherJoint.allowDetachWhileParentLifted = xmlFile:getValue(key.."#allowDetachWhileParentLifted", true) |
965 | |
966 | inputAttacherJoint.dependentAttacherJoints = {} |
967 | local k = 0 |
968 | while true do |
969 | local dependentKey = string.format(key .. ".dependentAttacherJoint(%d)", k) |
970 | if not xmlFile:hasProperty(dependentKey) then |
971 | break |
972 | end |
973 | local attacherJointIndex = xmlFile:getValue(dependentKey.."#attacherJointIndex") |
974 | if attacherJointIndex ~= nil then |
975 | table.insert(inputAttacherJoint.dependentAttacherJoints, attacherJointIndex) |
976 | end |
977 | k = k + 1 |
978 | end |
979 | |
980 | -- reset values if hardAttach is active |
981 | if inputAttacherJoint.hardAttach then |
982 | inputAttacherJoint.needsLowering = false |
983 | inputAttacherJoint.allowsLowering = false |
984 | inputAttacherJoint.isDefaultLowered = false |
985 | inputAttacherJoint.upperRotationOffset = 0 |
986 | end |
987 | |
988 | inputAttacherJoint.changeObjects = {} |
989 | ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, key, inputAttacherJoint.changeObjects, self.components, self) |
990 | |
991 | inputAttacherJoint.additionalObjects = {} |
992 | local i = 0 |
993 | while true do |
994 | local baseKey = string.format("%s.additionalObjects.additionalObject(%d)", key, i) |
995 | if not xmlFile:hasProperty(baseKey) then |
996 | break |
997 | end |
998 | |
999 | local entry = {} |
1000 | entry.node = xmlFile:getValue(baseKey .. "#node", nil, self.components, self.i3dMappings) |
1001 | entry.attacherVehiclePath = xmlFile:getValue(baseKey.."#attacherVehiclePath") |
1002 | |
1003 | if entry.node ~= nil and entry.attacherVehiclePath ~= nil then |
1004 | entry.attacherVehiclePath = NetworkUtil.convertToNetworkFilename(entry.attacherVehiclePath) |
1005 | table.insert(inputAttacherJoint.additionalObjects, entry) |
1006 | end |
1007 | |
1008 | i = i + 1 |
1009 | end |
1010 | |
1011 | inputAttacherJoint.additionalAttachment = {} |
1012 | local filename = xmlFile:getValue(key..".additionalAttachment#filename") |
1013 | if filename ~= nil then |
1014 | inputAttacherJoint.additionalAttachment.filename = Utils.getFilename(filename, self.customEnvironment) |
1015 | end |
1016 | inputAttacherJoint.additionalAttachment.inputAttacherJointIndex = xmlFile:getValue(key..".additionalAttachment#inputAttacherJointIndex", 1) |
1017 | inputAttacherJoint.additionalAttachment.needsLowering = xmlFile:getValue(key..".additionalAttachment#needsLowering", false) |
1018 | |
1019 | local additionalJointTypeStr = xmlFile:getValue(key..".additionalAttachment#jointType") |
1020 | local additionalJointType |
1021 | if additionalJointTypeStr ~= nil then |
1022 | additionalJointType = AttacherJoints.jointTypeNameToInt[additionalJointTypeStr] |
1023 | if additionalJointType == nil then |
1024 | Logging.xmlWarning(self.xmlFile, "Invalid jointType '%s' for additonal implement '%s'!", tostring(additionalJointTypeStr), inputAttacherJoint.additionalAttachment.filename) |
1025 | end |
1026 | end |
1027 | |
1028 | inputAttacherJoint.additionalAttachment.jointType = additionalJointType or AttacherJoints.JOINTTYPE_IMPLEMENT |
1029 | |
1030 | return true |
1031 | end |
1032 | |
1033 | return false |
1034 | end |
323 | function Attachable:onLoad(savegame) |
324 | local spec = self.spec_attachable |
325 | |
326 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attacherJoint", "vehicle.inputAttacherJoints.inputAttacherJoint") -- FS15 to FS17 |
327 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.needsLowering", "vehicle.inputAttacherJoints.inputAttacherJoint#needsLowering") -- FS15 to FS17 |
328 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.allowsLowering", "vehicle.inputAttacherJoints.inputAttacherJoint#allowsLowering") -- FS15 to FS17 |
329 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.isDefaultLowered", "vehicle.inputAttacherJoints.inputAttacherJoint#isDefaultLowered") -- FS15 to FS17 |
330 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.forceSelectionOnAttach#value", "vehicle.inputAttacherJoints.inputAttacherJoint#forceSelectionOnAttach") -- FS15 to FS17 |
331 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.topReferenceNode#index", "vehicle.attacherJoint#topReferenceNode") -- FS15 to FS17 |
332 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachRootNode#index", "vehicle.attacherJoint#rootNode") -- FS15 to FS17 |
333 | |
334 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.inputAttacherJoints", "vehicle.attachable.inputAttacherJoints") -- FS17 to FS19 |
335 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.inputAttacherJointConfigurations", "vehicle.attachable.inputAttacherJointConfigurations") -- FS17 to FS19 |
336 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.brakeForce", "vehicle.attachable.brakeForce#force") -- FS17 to FS22 |
337 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachable.brakeForce", "vehicle.attachable.brakeForce#force", nil, true) -- FS19 to FS22 |
338 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.steeringAxleAngleScale", "vehicle.attachable.steeringAxleAngleScale") -- FS17 to FS19 |
339 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.support", "vehicle.attachable.support") -- FS17 to FS19 |
340 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.lowerAnimation", "vehicle.attachable.lowerAnimation") -- FS17 to FS19 |
341 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.toolCameras", "vehicle.attachable.toolCameras") -- FS17 to FS19 |
342 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachable.toolCameras#count", "vehicle.attachable.toolCameras") -- FS17 to FS19 |
343 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachable.toolCameras.toolCamera1", "vehicle.attachable.toolCamera") -- FS17 to FS19 |
344 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachable.toolCameras.toolCamera2", "vehicle.attachable.toolCamera") -- FS17 to FS19 |
345 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachable.toolCameras.toolCamera3", "vehicle.attachable.toolCamera") -- FS17 to FS19 |
346 | |
347 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.foldable.foldingParts#onlyFoldOnDetach", "vehicle.attachable#allowFoldingWhileAttached") -- FS17 to FS19 |
348 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.maximalAirConsumptionPerFullStop", "vehicle.attachable.airConsumer#usage (is now in usage per second at full brake power)") --FS17 to FS19 |
349 | |
350 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.attachable.steeringAxleAngleScale#targetNode", "vehicle.attachable.steeringAxleAngleScale.targetNode#node") --FS19 to FS22 |
351 | |
352 | spec.attacherJoint = nil |
353 | |
354 | spec.inputAttacherJoints = {} |
355 | self.xmlFile:iterate("vehicle.attachable.inputAttacherJoints.inputAttacherJoint", function(i, key) |
356 | local inputAttacherJoint = {} |
357 | if self:loadInputAttacherJoint(self.xmlFile, key, inputAttacherJoint, i - 1) then |
358 | table.insert(spec.inputAttacherJoints, inputAttacherJoint) |
359 | |
360 | inputAttacherJoint.jointInfo = g_currentMission:registerInputAttacherJoint(self, #spec.inputAttacherJoints, inputAttacherJoint) |
361 | end |
362 | end) |
363 | |
364 | if self.configurations["inputAttacherJoint"] ~= nil then |
365 | local attacherConfigs = string.format("vehicle.attachable.inputAttacherJointConfigurations.inputAttacherJointConfiguration(%d)", self.configurations["inputAttacherJoint"]-1) |
366 | self.xmlFile:iterate(attacherConfigs..".inputAttacherJoint", function(i, baseName) |
367 | local inputAttacherJoint = {} |
368 | if self:loadInputAttacherJoint(self.xmlFile, baseName, inputAttacherJoint, i - 1) then |
369 | table.insert(spec.inputAttacherJoints, inputAttacherJoint) |
370 | |
371 | inputAttacherJoint.jointInfo = g_currentMission:registerInputAttacherJoint(self, #spec.inputAttacherJoints, inputAttacherJoint) |
372 | end |
373 | end) |
374 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.attachable.inputAttacherJointConfigurations.inputAttacherJointConfiguration", self.configurations["inputAttacherJoint"], self.components, self) |
375 | end |
376 | |
377 | spec.brakeForce = self.xmlFile:getValue("vehicle.attachable.brakeForce#force", 0) * 10 |
378 | spec.maxBrakeForce = self.xmlFile:getValue("vehicle.attachable.brakeForce#maxForce", 0) * 10 |
379 | spec.loweredBrakeForce = self.xmlFile:getValue("vehicle.attachable.brakeForce#loweredForce", -1) * 10 |
380 | spec.maxBrakeForceMass = self.xmlFile:getValue("vehicle.attachable.brakeForce#maxForceMass", 0) / 1000 |
381 | |
382 | spec.airConsumerUsage = self.xmlFile:getValue("vehicle.attachable.airConsumer#usage", 0) |
383 | |
384 | spec.allowFoldingWhileAttached = self.xmlFile:getValue("vehicle.attachable#allowFoldingWhileAttached", true) |
385 | spec.allowFoldingWhileLowered = self.xmlFile:getValue("vehicle.attachable#allowFoldingWhileLowered", true) |
386 | spec.blockFoliageDestruction = self.xmlFile:getValue("vehicle.attachable#blockFoliageDestruction", false) |
387 | |
388 | spec.requiresExternalPower = self.xmlFile:getValue("vehicle.attachable.power#requiresExternalPower", true) |
389 | spec.attachToPowerWarning = self.xmlFile:getValue("vehicle.attachable.power#attachToPowerWarning", "warning_attachToPower", self.customEnvironment) |
390 | |
391 | spec.updateWheels = true |
392 | spec.updateSteeringAxleAngle = true |
393 | |
394 | spec.isSelected = false |
395 | spec.attachTime = 0 |
396 | |
397 | spec.steeringAxleAngle = 0 |
398 | spec.steeringAxleTargetAngle = 0 |
399 | |
400 | self:loadSteeringAxleFromXML(spec, self.xmlFile, "vehicle.attachable.steeringAxleAngleScale") |
401 | |
402 | if spec.steeringAxleDistanceDelay > 0 then |
403 | spec.steeringAxleTargetAngleHistory = {} |
404 | for i=1, math.floor(spec.steeringAxleDistanceDelay / 0.1) do |
405 | spec.steeringAxleTargetAngleHistory[i] = 0 |
406 | end |
407 | spec.steeringAxleTargetAngleHistoryIndex = 1 |
408 | spec.steeringAxleTargetAngleHistoryMoved = 1 |
409 | end |
410 | |
411 | spec.steeringAngleNodes = {} |
412 | self.xmlFile:iterate("vehicle.attachable.steeringAngleNodes.steeringAngleNode", function(_, key) |
413 | local entry = {} |
414 | if self:loadSteeringAngleNodeFromXML(entry, self.xmlFile, key) then |
415 | table.insert(spec.steeringAngleNodes, entry) |
416 | end |
417 | end) |
418 | |
419 | spec.detachingInProgress = false |
420 | |
421 | spec.supportAnimations = {} |
422 | self.xmlFile:iterate("vehicle.attachable.support", function(_, baseKey) |
423 | local entry = {} |
424 | if self:loadSupportAnimationFromXML(entry, self.xmlFile, baseKey) then |
425 | table.insert(spec.supportAnimations, entry) |
426 | end |
427 | end) |
428 | |
429 | spec.lowerAnimation = self.xmlFile:getValue("vehicle.attachable.lowerAnimation#name") |
430 | spec.lowerAnimationSpeed = self.xmlFile:getValue("vehicle.attachable.lowerAnimation#speed", 1) |
431 | spec.lowerAnimationDirectionOnDetach = self.xmlFile:getValue("vehicle.attachable.lowerAnimation#directionOnDetach", 0) |
432 | spec.lowerAnimationDefaultLowered = self.xmlFile:getValue("vehicle.attachable.lowerAnimation#defaultLowered", false) |
433 | |
434 | spec.toolCameras = {} |
435 | self.xmlFile:iterate("vehicle.attachable.toolCameras.toolCamera", function(_, cameraKey) |
436 | local camera = VehicleCamera.new(self) |
437 | if camera:loadFromXML(self.xmlFile, cameraKey) then |
438 | table.insert(spec.toolCameras, camera) |
439 | end |
440 | end) |
441 | |
442 | spec.isHardAttached = false |
443 | spec.isAdditionalAttachment = false |
444 | |
445 | spec.texts = {} |
446 | spec.texts.liftObject = g_i18n:getText("action_liftOBJECT") |
447 | spec.texts.lowerObject = g_i18n:getText("action_lowerOBJECT") |
448 | spec.texts.warningFoldingAttached = g_i18n:getText("warning_foldingNotWhileAttached") |
449 | spec.texts.warningFoldingLowered = g_i18n:getText("warning_foldingNotWhileLowered") |
450 | spec.texts.warningFoldingAttacherJoint = g_i18n:getText("warning_foldingNotWhileAttachedToAttacherJoint") |
451 | spec.texts.lowerImplementFirst = g_i18n:getText("warning_lowerImplementFirst") |
452 | end |
457 | function Attachable:onPostLoad(savegame) |
458 | local spec = self.spec_attachable |
459 | |
460 | for _, supportAnimation in ipairs(spec.supportAnimations) do |
461 | if not supportAnimation.delayedOnLoad then |
462 | if self:getIsSupportAnimationAllowed(supportAnimation) then |
463 | self:playAnimation(supportAnimation.animationName, 1, nil, true, false) |
464 | AnimatedVehicle.updateAnimationByName(self, supportAnimation.animationName, 9999999, true) |
465 | end |
466 | end |
467 | end |
468 | |
469 | if savegame ~= nil and not savegame.resetVehicles then |
470 | if spec.lowerAnimation ~= nil and self.playAnimation ~= nil then |
471 | local lowerAnimTime = savegame.xmlFile:getValue(savegame.key..".attachable#lowerAnimTime") |
472 | if lowerAnimTime ~= nil then |
473 | local speed = 1 |
474 | if lowerAnimTime < 0.5 then |
475 | speed = -1 |
476 | end |
477 | self:playAnimation(spec.lowerAnimation, speed, nil, true, false) |
478 | self:setAnimationTime(spec.lowerAnimation, lowerAnimTime) |
479 | AnimatedVehicle.updateAnimationByName(self, spec.lowerAnimation, 9999999, true) |
480 | |
481 | if self.updateCylinderedInitial ~= nil then |
482 | self:updateCylinderedInitial(false) |
483 | end |
484 | end |
485 | end |
486 | else |
487 | if spec.lowerAnimationDefaultLowered then |
488 | self:playAnimation(spec.lowerAnimation, 1, nil, true, false) |
489 | AnimatedVehicle.updateAnimationByName(self, spec.lowerAnimation, 9999999, true) |
490 | end |
491 | end |
492 | |
493 | for _, inputAttacherJoint in pairs(spec.inputAttacherJoints) do |
494 | if self.getMovingPartByNode ~= nil then |
495 | if inputAttacherJoint.steeringBarLeftNode ~= nil then |
496 | local movingPart = self:getMovingPartByNode(inputAttacherJoint.steeringBarLeftNode) |
497 | if movingPart ~= nil then |
498 | inputAttacherJoint.steeringBarLeftMovingPart = movingPart |
499 | else |
500 | inputAttacherJoint.steeringBarLeftNode = nil |
501 | end |
502 | end |
503 | if inputAttacherJoint.steeringBarRightNode ~= nil then |
504 | local movingPart = self:getMovingPartByNode(inputAttacherJoint.steeringBarRightNode) |
505 | if movingPart ~= nil then |
506 | inputAttacherJoint.steeringBarRightMovingPart = movingPart |
507 | else |
508 | inputAttacherJoint.steeringBarRightNode = nil |
509 | end |
510 | end |
511 | else |
512 | inputAttacherJoint.steeringBarLeftNode = nil |
513 | inputAttacherJoint.steeringBarRightNode = nil |
514 | end |
515 | end |
516 | |
517 | if self.brake ~= nil then |
518 | local brakeForce = self:getBrakeForce() |
519 | if brakeForce > 0 then |
520 | self:brake(brakeForce, true) |
521 | end |
522 | end |
523 | |
524 | spec.updateSteeringAxleAngle = #spec.steeringAngleNodes > 0 or spec.steeringAxleTargetNode ~= nil or (self.getWheels ~= nil and #self:getWheels() > 0) |
525 | |
526 | if #spec.inputAttacherJoints > 0 then |
527 | g_currentMission:addAttachableVehicle(self) |
528 | else |
529 | SpecializationUtil.removeEventListener(self, "onUpdate", Attachable) |
530 | end |
531 | end |
2216 | function Attachable:onRegisterAnimationValueTypes() |
2217 | local loadInputAttacherJoint = function(value, xmlFile, xmlKey) |
2218 | value.inputAttacherJointIndex = xmlFile:getValue(xmlKey .. "#inputAttacherJointIndex") |
2219 | |
2220 | if value.inputAttacherJointIndex ~= nil then |
2221 | value:setWarningInformation("inputAttacherJointIndex: " .. value.inputAttacherJointIndex) |
2222 | value:addCompareParameters("inputAttacherJointIndex") |
2223 | |
2224 | return true |
2225 | end |
2226 | |
2227 | return false |
2228 | end |
2229 | |
2230 | local resolveAttacherJoint = function(value) |
2231 | if value.inputAttacherJoint == nil then |
2232 | value.inputAttacherJoint = self:getInputAttacherJointByJointDescIndex(value.inputAttacherJointIndex) |
2233 | if value.inputAttacherJoint == nil then |
2234 | Logging.xmlWarning(self.xmlFile, "Unknown inputAttacherJointIndex '%s' for animation part.", value.inputAttacherJointIndex) |
2235 | value.inputAttacherJointIndex = nil |
2236 | return 0 |
2237 | end |
2238 | end |
2239 | end |
2240 | |
2241 | local updateJointSettings = function(...) |
2242 | local attacherVehicle = self:getAttacherVehicle() |
2243 | if attacherVehicle ~= nil then |
2244 | attacherVehicle:updateAttacherJointSettingsByObject(self, ...) |
2245 | end |
2246 | end |
2247 | |
2248 | self:registerAnimationValueType("lowerRotLimitScale", "lowerRotLimitScaleStart", "lowerRotLimitScaleEnd", false, AnimationValueFloat, |
2249 | loadInputAttacherJoint, |
2250 | |
2251 | function(value) |
2252 | if value.inputAttacherJointIndex ~= nil then |
2253 | resolveAttacherJoint(value) |
2254 | end |
2255 | |
2256 | if value.inputAttacherJoint ~= nil then |
2257 | return unpack(value.inputAttacherJoint.lowerRotLimitScale) |
2258 | else |
2259 | return 0, 0, 0 |
2260 | end |
2261 | end, |
2262 | |
2263 | function(value, x, y, z) |
2264 | if value.inputAttacherJoint ~= nil then |
2265 | value.inputAttacherJoint.lowerRotLimitScale[1] = x |
2266 | value.inputAttacherJoint.lowerRotLimitScale[2] = y |
2267 | value.inputAttacherJoint.lowerRotLimitScale[3] = z |
2268 | updateJointSettings(true) |
2269 | end |
2270 | end) |
2271 | |
2272 | self:registerAnimationValueType("upperRotLimitScale", "upperRotLimitScaleStart", "upperRotLimitScaleEnd", false, AnimationValueFloat, |
2273 | loadInputAttacherJoint, |
2274 | |
2275 | function(value) |
2276 | if value.inputAttacherJointIndex ~= nil then |
2277 | resolveAttacherJoint(value) |
2278 | end |
2279 | |
2280 | if value.inputAttacherJoint ~= nil then |
2281 | return unpack(value.inputAttacherJoint.upperRotLimitScale) |
2282 | else |
2283 | return 0, 0, 0 |
2284 | end |
2285 | end, |
2286 | |
2287 | function(value, x, y, z) |
2288 | if value.inputAttacherJoint ~= nil then |
2289 | value.inputAttacherJoint.upperRotLimitScale[1] = x |
2290 | value.inputAttacherJoint.upperRotLimitScale[2] = y |
2291 | value.inputAttacherJoint.upperRotLimitScale[3] = z |
2292 | updateJointSettings(true) |
2293 | end |
2294 | end) |
2295 | |
2296 | self:registerAnimationValueType("lowerTransLimitScale", "lowerTransLimitScaleStart", "lowerTransLimitScaleEnd", false, AnimationValueFloat, |
2297 | loadInputAttacherJoint, |
2298 | |
2299 | function(value) |
2300 | if value.inputAttacherJointIndex ~= nil then |
2301 | resolveAttacherJoint(value) |
2302 | end |
2303 | |
2304 | if value.inputAttacherJoint ~= nil then |
2305 | return unpack(value.inputAttacherJoint.lowerTransLimitScale) |
2306 | else |
2307 | return 0, 0, 0 |
2308 | end |
2309 | end, |
2310 | |
2311 | function(value, x, y, z) |
2312 | if value.inputAttacherJoint ~= nil then |
2313 | value.inputAttacherJoint.lowerTransLimitScale[1] = x |
2314 | value.inputAttacherJoint.lowerTransLimitScale[2] = y |
2315 | value.inputAttacherJoint.lowerTransLimitScale[3] = z |
2316 | updateJointSettings(true) |
2317 | end |
2318 | end) |
2319 | |
2320 | self:registerAnimationValueType("upperTransLimitScale", "upperTransLimitScaleStart", "upperTransLimitScaleEnd", false, AnimationValueFloat, |
2321 | loadInputAttacherJoint, |
2322 | |
2323 | function(value) |
2324 | if value.inputAttacherJointIndex ~= nil then |
2325 | resolveAttacherJoint(value) |
2326 | end |
2327 | |
2328 | if value.inputAttacherJoint ~= nil then |
2329 | return unpack(value.inputAttacherJoint.upperTransLimitScale) |
2330 | else |
2331 | return 0, 0, 0 |
2332 | end |
2333 | end, |
2334 | |
2335 | function(value, x, y, z) |
2336 | if value.inputAttacherJoint ~= nil then |
2337 | value.inputAttacherJoint.upperTransLimitScale[1] = x |
2338 | value.inputAttacherJoint.upperTransLimitScale[2] = y |
2339 | value.inputAttacherJoint.upperTransLimitScale[3] = z |
2340 | updateJointSettings(true) |
2341 | end |
2342 | end) |
2343 | |
2344 | self:registerAnimationValueType("lowerRotationOffset", "lowerRotationOffsetStart", "lowerRotationOffsetEnd", false, AnimationValueFloat, |
2345 | loadInputAttacherJoint, |
2346 | |
2347 | function(value) |
2348 | if value.inputAttacherJointIndex ~= nil then |
2349 | resolveAttacherJoint(value) |
2350 | end |
2351 | |
2352 | if value.inputAttacherJoint ~= nil then |
2353 | return value.inputAttacherJoint.lowerRotationOffset |
2354 | else |
2355 | return 0 |
2356 | end |
2357 | end, |
2358 | |
2359 | function(value, lowerRotationOffset) |
2360 | if value.inputAttacherJoint ~= nil then |
2361 | value.inputAttacherJoint.lowerRotationOffset = lowerRotationOffset |
2362 | updateJointSettings(false, true) |
2363 | end |
2364 | end) |
2365 | |
2366 | self:registerAnimationValueType("upperRotationOffset", "upperRotationOffsetStart", "upperRotationOffsetEnd", false, AnimationValueFloat, |
2367 | loadInputAttacherJoint, |
2368 | |
2369 | function(value) |
2370 | if value.inputAttacherJointIndex ~= nil then |
2371 | resolveAttacherJoint(value) |
2372 | end |
2373 | |
2374 | if value.inputAttacherJoint ~= nil then |
2375 | return value.inputAttacherJoint.upperRotationOffset |
2376 | else |
2377 | return 0 |
2378 | end |
2379 | end, |
2380 | |
2381 | function(value, upperRotationOffset) |
2382 | if value.inputAttacherJoint ~= nil then |
2383 | value.inputAttacherJoint.upperRotationOffset = upperRotationOffset |
2384 | updateJointSettings(false, true) |
2385 | end |
2386 | end) |
2387 | |
2388 | self:registerAnimationValueType("lowerDistanceToGround", "lowerDistanceToGroundStart", "lowerDistanceToGroundEnd", false, AnimationValueFloat, |
2389 | loadInputAttacherJoint, |
2390 | |
2391 | function(value) |
2392 | if value.inputAttacherJointIndex ~= nil then |
2393 | resolveAttacherJoint(value) |
2394 | end |
2395 | |
2396 | if value.inputAttacherJoint ~= nil then |
2397 | return value.inputAttacherJoint.lowerDistanceToGround |
2398 | else |
2399 | return 0 |
2400 | end |
2401 | end, |
2402 | |
2403 | function(value, lowerDistanceToGround) |
2404 | if value.inputAttacherJoint ~= nil then |
2405 | value.inputAttacherJoint.lowerDistanceToGround = lowerDistanceToGround |
2406 | updateJointSettings(false, false, true) |
2407 | end |
2408 | end) |
2409 | |
2410 | self:registerAnimationValueType("upperDistanceToGround", "upperDistanceToGroundStart", "upperDistanceToGroundEnd", false, AnimationValueFloat, |
2411 | loadInputAttacherJoint, |
2412 | |
2413 | function(value) |
2414 | if value.inputAttacherJointIndex ~= nil then |
2415 | resolveAttacherJoint(value) |
2416 | end |
2417 | |
2418 | if value.inputAttacherJoint ~= nil then |
2419 | return value.inputAttacherJoint.upperDistanceToGround |
2420 | else |
2421 | return 0 |
2422 | end |
2423 | end, |
2424 | |
2425 | function(value, upperDistanceToGround) |
2426 | if value.inputAttacherJoint ~= nil then |
2427 | value.inputAttacherJoint.upperDistanceToGround = upperDistanceToGround |
2428 | updateJointSettings(false, false, true) |
2429 | end |
2430 | end) |
2431 | end |
637 | function Attachable:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
638 | local spec = self.spec_attachable |
639 | |
640 | local yRot |
641 | if spec.updateSteeringAxleAngle then |
642 | if self:getLastSpeed() > 0.25 or not self.finishedFirstUpdate then |
643 | local steeringAngle = 0 |
644 | local baseVehicle = self:getSteeringAxleBaseVehicle() |
645 | if (baseVehicle ~= nil or spec.steeringAxleReferenceComponentNode ~= nil) and (self.movingDirection >= 0 or spec.steeringAxleUpdateBackwards) then |
646 | yRot = Utils.getYRotationBetweenNodes(self.steeringAxleNode, spec.steeringAxleReferenceComponentNode or baseVehicle.steeringAxleNode) |
647 | |
648 | local scale = 1 |
649 | if spec.steeringAxleAngleScaleSpeedDependent then |
650 | local startSpeed = spec.steeringAxleAngleScaleStart |
651 | local endSpeed = spec.steeringAxleAngleScaleEnd |
652 | scale = MathUtil.clamp(1 + (self:getLastSpeed()-startSpeed) * 1.0/(startSpeed-endSpeed), 0, 1) |
653 | end |
654 | steeringAngle = yRot * scale |
655 | elseif self:getLastSpeed() > 0.2 then |
656 | steeringAngle = 0 |
657 | end |
658 | |
659 | if not self:getIsSteeringAxleAllowed() then |
660 | steeringAngle = 0 |
661 | end |
662 | |
663 | if spec.steeringAxleDistanceDelay > 0 then |
664 | spec.steeringAxleTargetAngleHistoryMoved = spec.steeringAxleTargetAngleHistoryMoved + self.lastMovedDistance |
665 | if spec.steeringAxleTargetAngleHistoryMoved > 0.1 then |
666 | spec.steeringAxleTargetAngleHistory[spec.steeringAxleTargetAngleHistoryIndex] = steeringAngle |
667 | |
668 | spec.steeringAxleTargetAngleHistoryIndex = spec.steeringAxleTargetAngleHistoryIndex + 1 |
669 | if spec.steeringAxleTargetAngleHistoryIndex > #spec.steeringAxleTargetAngleHistory then |
670 | spec.steeringAxleTargetAngleHistoryIndex = 1 |
671 | end |
672 | end |
673 | |
674 | local lastIndex = spec.steeringAxleTargetAngleHistoryIndex + 1 |
675 | if lastIndex > #spec.steeringAxleTargetAngleHistory then |
676 | lastIndex = 1 |
677 | end |
678 | spec.steeringAxleTargetAngle = spec.steeringAxleTargetAngleHistory[lastIndex] |
679 | else |
680 | spec.steeringAxleTargetAngle = steeringAngle |
681 | end |
682 | |
683 | local dir = MathUtil.sign(spec.steeringAxleTargetAngle - spec.steeringAxleAngle) |
684 | local speed = spec.steeringAxleAngleSpeed |
685 | if not self.finishedFirstUpdate then |
686 | speed = 9999 |
687 | end |
688 | if dir == 1 then |
689 | spec.steeringAxleAngle = math.min(spec.steeringAxleAngle + dir*dt*speed, spec.steeringAxleTargetAngle) |
690 | else |
691 | spec.steeringAxleAngle = math.max(spec.steeringAxleAngle + dir*dt*speed, spec.steeringAxleTargetAngle) |
692 | end |
693 | |
694 | if spec.steeringAxleTargetNode ~= nil then |
695 | local angle |
696 | if spec.steeringAxleTargetNodeRefAngle ~= nil then |
697 | local alpha = MathUtil.clamp(spec.steeringAxleAngle / spec.steeringAxleTargetNodeRefAngle, -1, 1) |
698 | if alpha >= 0 then |
699 | angle = spec.steeringAxleAngleMaxRot * alpha |
700 | else |
701 | angle = spec.steeringAxleAngleMinRot * -alpha |
702 | end |
703 | else |
704 | angle = MathUtil.clamp(spec.steeringAxleAngle, spec.steeringAxleAngleMinRot, spec.steeringAxleAngleMaxRot) |
705 | end |
706 | |
707 | setRotation(spec.steeringAxleTargetNode, 0, angle * spec.steeringAxleDirection, 0) |
708 | self:setMovingToolDirty(spec.steeringAxleTargetNode) |
709 | end |
710 | end |
711 | end |
712 | |
713 | local numSteeringAngleNodes = #spec.steeringAngleNodes |
714 | if numSteeringAngleNodes > 0 and yRot == nil then |
715 | local baseVehicle = self:getSteeringAxleBaseVehicle() |
716 | if baseVehicle ~= nil then |
717 | yRot = Utils.getYRotationBetweenNodes(self.steeringAxleNode, baseVehicle.steeringAxleNode) |
718 | end |
719 | end |
720 | if yRot ~= nil then |
721 | for i=1, numSteeringAngleNodes do |
722 | self:updateSteeringAngleNode(spec.steeringAngleNodes[i], yRot, dt) |
723 | end |
724 | end |
725 | |
726 | local attacherVehicle = self:getAttacherVehicle() |
727 | |
728 | if spec.detachingInProgress then |
729 | local doDetach = false |
730 | for i=1, #spec.supportAnimations do |
731 | local animation = spec.supportAnimations[i] |
732 | if animation.detachAfterAnimation then |
733 | if not self:getIsAnimationPlaying(animation.animationName) then |
734 | doDetach = true |
735 | elseif animation.detachAnimationTime < 1 then |
736 | if self:getAnimationTime(animation.animationName) > animation.detachAnimationTime then |
737 | doDetach = true |
738 | end |
739 | end |
740 | end |
741 | end |
742 | |
743 | if doDetach then |
744 | if attacherVehicle ~= nil then |
745 | attacherVehicle:detachImplementByObject(self) |
746 | end |
747 | |
748 | spec.detachingInProgress = false |
749 | end |
750 | end |
751 | |
752 | if attacherVehicle ~= nil then |
753 | if self.currentUpdateDistance < attacherVehicle.spec_attacherJoints.maxUpdateDistance then |
754 | if self.updateLoopIndex == attacherVehicle.updateLoopIndex then |
755 | local implement = attacherVehicle:getImplementByObject(self) |
756 | if implement ~= nil then |
757 | attacherVehicle:updateAttacherJointGraphics(implement, dt, true) |
758 | end |
759 | end |
760 | end |
761 | end |
762 | end |
1459 | function Attachable:postAttach(attacherVehicle, inputJointDescIndex, jointDescIndex, loadFromSavegame) |
1460 | local spec = self.spec_attachable |
1461 | |
1462 | -- only activate tool if root vehicle is controlled (activated). We don't want to activate a tool that is attached during loading |
1463 | local rootVehicle = self.rootVehicle |
1464 | if rootVehicle ~= nil and rootVehicle.getIsControlled ~= nil and rootVehicle:getIsControlled() then |
1465 | self:activate() |
1466 | end |
1467 | |
1468 | if self.setLightsTypesMask ~= nil then |
1469 | local lightsSpecAttacherVehicle = attacherVehicle.spec_lights |
1470 | if lightsSpecAttacherVehicle ~= nil then |
1471 | self:setLightsTypesMask(lightsSpecAttacherVehicle.lightsTypesMask, true, true) |
1472 | self:setBeaconLightsVisibility(lightsSpecAttacherVehicle.beaconLightsActive, true, true) |
1473 | self:setTurnLightState(lightsSpecAttacherVehicle.turnLightState, true, true) |
1474 | end |
1475 | end |
1476 | |
1477 | spec.attachTime = g_currentMission.time |
1478 | |
1479 | for _, supportAnimation in ipairs(spec.supportAnimations) do |
1480 | if self:getIsSupportAnimationAllowed(supportAnimation) then |
1481 | if supportAnimation.delayedOnAttach then |
1482 | local skipAnimation = self.propertyState == Vehicle.PROPERTY_STATE_SHOP_CONFIG or loadFromSavegame |
1483 | |
1484 | self:playAnimation(supportAnimation.animationName, -1, nil, true, not skipAnimation) |
1485 | if skipAnimation then |
1486 | AnimatedVehicle.updateAnimationByName(self, supportAnimation.animationName, 9999999, true) |
1487 | end |
1488 | end |
1489 | end |
1490 | end |
1491 | |
1492 | self:attachableAddToolCameras() |
1493 | |
1494 | ObjectChangeUtil.setObjectChanges(spec.attacherJoint.changeObjects, true, self, self.setMovingToolDirty) |
1495 | |
1496 | local jointDesc = attacherVehicle:getAttacherJointByJointDescIndex(jointDescIndex) |
1497 | if jointDesc.steeringBarLeftNode ~= nil and spec.attacherJoint.steeringBarLeftMovingPart ~= nil then |
1498 | for _,movingPart in pairs(self.spec_cylindered.movingParts) do |
1499 | if movingPart.referencePoint == spec.attacherJoint.steeringBarLeftMovingPart.referencePoint and movingPart ~= spec.attacherJoint.steeringBarLeftMovingPart then |
1500 | movingPart.referencePoint = jointDesc.steeringBarLeftNode |
1501 | end |
1502 | end |
1503 | spec.attacherJoint.steeringBarLeftMovingPart.referencePoint = jointDesc.steeringBarLeftNode |
1504 | end |
1505 | if jointDesc.steeringBarRightNode ~= nil and spec.attacherJoint.steeringBarRightMovingPart ~= nil then |
1506 | for _,movingPart in pairs(self.spec_cylindered.movingParts) do |
1507 | if movingPart.referencePoint == spec.attacherJoint.steeringBarRightMovingPart.referencePoint and movingPart ~= spec.attacherJoint.steeringBarRightMovingPart then |
1508 | movingPart.referencePoint = jointDesc.steeringBarRightNode |
1509 | end |
1510 | end |
1511 | spec.attacherJoint.steeringBarRightMovingPart.referencePoint = jointDesc.steeringBarRightNode |
1512 | end |
1513 | |
1514 | local actionController = self.rootVehicle.actionController |
1515 | if actionController ~= nil then |
1516 | local inputJointDesc = self:getActiveInputAttacherJoint() |
1517 | if inputJointDesc ~= nil then |
1518 | if inputJointDesc.needsLowering and inputJointDesc.allowsLowering and jointDesc.allowsLowering then |
1519 | spec.controlledAction = actionController:registerAction("lower", InputAction.LOWER_IMPLEMENT, 2) |
1520 | spec.controlledAction:setCallback(self, Attachable.actionControllerLowerImplementEvent) |
1521 | spec.controlledAction:setFinishedFunctions(self, self.getIsLowered, true, false) |
1522 | spec.controlledAction:setIsSaved(true) |
1523 | if self:getAINeedsLowering() then |
1524 | spec.controlledAction:addAIEventListener(self, "onAIImplementStartLine", 1, true) |
1525 | spec.controlledAction:addAIEventListener(self, "onAIImplementEndLine", -1) |
1526 | spec.controlledAction:addAIEventListener(self, "onAIImplementPrepare", -1) |
1527 | end |
1528 | end |
1529 | end |
1530 | end |
1531 | |
1532 | SpecializationUtil.raiseEvent(self, "onPostAttach", attacherVehicle, inputJointDescIndex, jointDescIndex, loadFromSavegame) |
1533 | end |
41 | function Attachable.registerFunctions(vehicleType) |
42 | SpecializationUtil.registerFunction(vehicleType, "loadInputAttacherJoint", Attachable.loadInputAttacherJoint) |
43 | SpecializationUtil.registerFunction(vehicleType, "loadAttacherJointHeightNode", Attachable.loadAttacherJointHeightNode) |
44 | SpecializationUtil.registerFunction(vehicleType, "getIsAttacherJointHeightNodeActive", Attachable.getIsAttacherJointHeightNodeActive) |
45 | SpecializationUtil.registerFunction(vehicleType, "getInputAttacherJointByJointDescIndex", Attachable.getInputAttacherJointByJointDescIndex) |
46 | SpecializationUtil.registerFunction(vehicleType, "getInputAttacherJointIndexByNode", Attachable.getInputAttacherJointIndexByNode) |
47 | SpecializationUtil.registerFunction(vehicleType, "getAttacherVehicle", Attachable.getAttacherVehicle) |
48 | SpecializationUtil.registerFunction(vehicleType, "getInputAttacherJoints", Attachable.getInputAttacherJoints) |
49 | SpecializationUtil.registerFunction(vehicleType, "getIsAttachedTo", Attachable.getIsAttachedTo) |
50 | SpecializationUtil.registerFunction(vehicleType, "getActiveInputAttacherJointDescIndex", Attachable.getActiveInputAttacherJointDescIndex) |
51 | SpecializationUtil.registerFunction(vehicleType, "getActiveInputAttacherJoint", Attachable.getActiveInputAttacherJoint) |
52 | SpecializationUtil.registerFunction(vehicleType, "getAllowsLowering", Attachable.getAllowsLowering) |
53 | SpecializationUtil.registerFunction(vehicleType, "loadSupportAnimationFromXML", Attachable.loadSupportAnimationFromXML) |
54 | SpecializationUtil.registerFunction(vehicleType, "getIsSupportAnimationAllowed", Attachable.getIsSupportAnimationAllowed) |
55 | SpecializationUtil.registerFunction(vehicleType, "startDetachProcess", Attachable.startDetachProcess) |
56 | SpecializationUtil.registerFunction(vehicleType, "getIsImplementChainLowered", Attachable.getIsImplementChainLowered) |
57 | SpecializationUtil.registerFunction(vehicleType, "getIsInWorkPosition", Attachable.getIsInWorkPosition) |
58 | SpecializationUtil.registerFunction(vehicleType, "getAttachbleAirConsumerUsage", Attachable.getAttachbleAirConsumerUsage) |
59 | SpecializationUtil.registerFunction(vehicleType, "isDetachAllowed", Attachable.isDetachAllowed) |
60 | SpecializationUtil.registerFunction(vehicleType, "isAttachAllowed", Attachable.isAttachAllowed) |
61 | SpecializationUtil.registerFunction(vehicleType, "getIsInputAttacherActive", Attachable.getIsInputAttacherActive) |
62 | SpecializationUtil.registerFunction(vehicleType, "getSteeringAxleBaseVehicle", Attachable.getSteeringAxleBaseVehicle) |
63 | SpecializationUtil.registerFunction(vehicleType, "loadSteeringAxleFromXML", Attachable.loadSteeringAxleFromXML) |
64 | SpecializationUtil.registerFunction(vehicleType, "getIsSteeringAxleAllowed", Attachable.getIsSteeringAxleAllowed) |
65 | SpecializationUtil.registerFunction(vehicleType, "loadSteeringAngleNodeFromXML", Attachable.loadSteeringAngleNodeFromXML) |
66 | SpecializationUtil.registerFunction(vehicleType, "updateSteeringAngleNode", Attachable.updateSteeringAngleNode) |
67 | SpecializationUtil.registerFunction(vehicleType, "attachableAddToolCameras", Attachable.attachableAddToolCameras) |
68 | SpecializationUtil.registerFunction(vehicleType, "attachableRemoveToolCameras", Attachable.attachableRemoveToolCameras) |
69 | SpecializationUtil.registerFunction(vehicleType, "preAttach", Attachable.preAttach) |
70 | SpecializationUtil.registerFunction(vehicleType, "postAttach", Attachable.postAttach) |
71 | SpecializationUtil.registerFunction(vehicleType, "preDetach", Attachable.preDetach) |
72 | SpecializationUtil.registerFunction(vehicleType, "postDetach", Attachable.postDetach) |
73 | SpecializationUtil.registerFunction(vehicleType, "setLowered", Attachable.setLowered) |
74 | SpecializationUtil.registerFunction(vehicleType, "setLoweredAll", Attachable.setLoweredAll) |
75 | SpecializationUtil.registerFunction(vehicleType, "setIsAdditionalAttachment", Attachable.setIsAdditionalAttachment) |
76 | SpecializationUtil.registerFunction(vehicleType, "getIsAdditionalAttachment", Attachable.getIsAdditionalAttachment) |
77 | SpecializationUtil.registerFunction(vehicleType, "setIsSupportVehicle", Attachable.setIsSupportVehicle) |
78 | SpecializationUtil.registerFunction(vehicleType, "getIsSupportVehicle", Attachable.getIsSupportVehicle) |
79 | SpecializationUtil.registerFunction(vehicleType, "registerLoweringActionEvent", Attachable.registerLoweringActionEvent) |
80 | SpecializationUtil.registerFunction(vehicleType, "getLoweringActionEventState", Attachable.getLoweringActionEventState) |
81 | SpecializationUtil.registerFunction(vehicleType, "getAllowMultipleAttachments", Attachable.getAllowMultipleAttachments) |
82 | SpecializationUtil.registerFunction(vehicleType, "resolveMultipleAttachments", Attachable.resolveMultipleAttachments) |
83 | SpecializationUtil.registerFunction(vehicleType, "getBlockFoliageDestruction", Attachable.getBlockFoliageDestruction) |
84 | end |
244 | function Attachable.registerInputAttacherJointXMLPaths(schema, baseName) |
245 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#node", "Joint Node") |
246 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".heightNode(?)#node", "Height Node") |
247 | |
248 | schema:register(XMLValueType.STRING, baseName .. "#jointType", "Joint type") |
249 | schema:register(XMLValueType.STRING, baseName .. ".subType#name", "If defined this type needs to match with the sub type in the attacher vehicle") |
250 | schema:register(XMLValueType.BOOL, baseName .. ".subType#showWarning", "Show warning if user tries to attach with a different sub type", true) |
251 | |
252 | schema:register(XMLValueType.BOOL, baseName .. "#needsTrailerJoint", "Needs trailer joint (only if no joint type is given)", false) |
253 | schema:register(XMLValueType.BOOL, baseName .. "#needsLowJoint", "Needs low trailer joint (only if no joint type is given)", false) |
254 | |
255 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#topReferenceNode", "Top Reference Node") |
256 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#rootNode", "Root node", "first component") |
257 | |
258 | schema:register(XMLValueType.BOOL, baseName .. "#allowsDetaching", "Allows detaching", true) |
259 | schema:register(XMLValueType.BOOL, baseName .. "#fixedRotation", "Fixed rotation (Rot limit is freezed)", false) |
260 | schema:register(XMLValueType.BOOL, baseName .. "#hardAttach", "Implement is hard attached", false) |
261 | |
262 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#nodeVisual", "Visual joint node") |
263 | schema:register(XMLValueType.FLOAT, baseName .. ".distanceToGround#lower", "Lower distance to ground") |
264 | schema:register(XMLValueType.FLOAT, baseName .. ".distanceToGround#upper", "Upper distance to ground") |
265 | schema:register(XMLValueType.STRING, baseName .. ".distanceToGround.vehicle(?)#filename", "Vehicle filename to activate these distances") |
266 | schema:register(XMLValueType.FLOAT, baseName .. ".distanceToGround.vehicle(?)#lower", "Lower distance to ground while attached to this vehicle") |
267 | schema:register(XMLValueType.FLOAT, baseName .. ".distanceToGround.vehicle(?)#upper", "Upper distance to ground while attached to this vehicle") |
268 | schema:register(XMLValueType.ANGLE, baseName .. "#lowerRotationOffset", "Rotation offset if lowered") |
269 | schema:register(XMLValueType.ANGLE, baseName .. "#upperRotationOffset", "Rotation offset if lifted", "8 degrees for implements") |
270 | schema:register(XMLValueType.BOOL, baseName .. "#allowsJointRotLimitMovement", "Rotation limit is changed during lifting/lowering", true) |
271 | schema:register(XMLValueType.BOOL, baseName .. "#allowsJointTransLimitMovement", "Translation limit is changed during lifting/lowering", true) |
272 | schema:register(XMLValueType.BOOL, baseName .. "#needsToolbar", "Needs toolbar", false) |
273 | |
274 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#steeringBarLeftNode", "Left steering bar node") |
275 | schema:register(XMLValueType.NODE_INDEX, baseName .. "#steeringBarRightNode", "Right steering bar node") |
276 | |
277 | schema:register(XMLValueType.VECTOR_3, baseName .. "#upperRotLimitScale", "Upper rot limit scale", "0 0 0") |
278 | schema:register(XMLValueType.VECTOR_3, baseName .. "#lowerRotLimitScale", "Lower rot limit scale", "0 0 0") |
279 | schema:register(XMLValueType.FLOAT, baseName .. "#rotLimitThreshold", "Defines when the transition from upper to lower rot limit starts (0: directly, 0.9: after 90% of lowering)", 0) |
280 | |
281 | schema:register(XMLValueType.VECTOR_3, baseName .. "#upperTransLimitScale", "Upper trans limit scale", "0 0 0") |
282 | schema:register(XMLValueType.VECTOR_3, baseName .. "#lowerTransLimitScale", "Lower trans limit scale", "0 0 0") |
283 | schema:register(XMLValueType.FLOAT, baseName .. "#transLimitThreshold", "Defines when the transition from upper to lower trans limit starts (0: directly, 0.9: after 90% of lowering)", 0) |
284 | |
285 | schema:register(XMLValueType.VECTOR_3, baseName .. "#rotLimitSpring", "Rotation limit spring", "0 0 0") |
286 | schema:register(XMLValueType.VECTOR_3, baseName .. "#rotLimitDamping", "Rotation limit damping", "1 1 1") |
287 | schema:register(XMLValueType.VECTOR_3, baseName .. "#rotLimitForceLimit", "Rotation limit force limit", "-1 -1 -1") |
288 | |
289 | schema:register(XMLValueType.VECTOR_3, baseName .. "#transLimitSpring", "Translation limit spring", "0 0 0") |
290 | schema:register(XMLValueType.VECTOR_3, baseName .. "#transLimitDamping", "Translation limit damping", "1 1 1") |
291 | schema:register(XMLValueType.VECTOR_3, baseName .. "#transLimitForceLimit", "Translation limit force limit", "-1 -1 -1") |
292 | |
293 | schema:register(XMLValueType.INT, baseName .. "#attachAngleLimitAxis", "Direction axis which is used to calculate angle to enable attach", 1) |
294 | |
295 | schema:register(XMLValueType.FLOAT, baseName .. "#attacherHeight", "Height of attacher", "0.9 for trailer, 0.55 for trailer low") |
296 | |
297 | schema:register(XMLValueType.BOOL, baseName .. "#needsLowering", "Needs lowering") |
298 | schema:register(XMLValueType.BOOL, baseName .. "#allowsLowering", "Allows lowering") |
299 | schema:register(XMLValueType.BOOL, baseName .. "#isDefaultLowered", "Is default lowered", false) |
300 | schema:register(XMLValueType.BOOL, baseName .. "#useFoldingLoweredState", "Use folding lowered state", false) |
301 | schema:register(XMLValueType.BOOL, baseName .. "#forceSelectionOnAttach", "Is selected on attach", true) |
302 | schema:register(XMLValueType.BOOL, baseName .. "#forceAllowDetachWhileLifted", "Attacher vehicle can be always detached no matter if we are lifted or not", false) |
303 | schema:register(XMLValueType.INT, baseName .. "#forcedAttachingDirection", "Tool can be only attached in this direction", 0) |
304 | schema:register(XMLValueType.BOOL, baseName .. "#allowFolding", "Folding is allowed while attached to this attacher joint", true) |
305 | schema:register(XMLValueType.BOOL, baseName .. "#allowTurnOn", "Turn on is allowed while attached to this attacher joint", true) |
306 | schema:register(XMLValueType.BOOL, baseName .. "#allowAI", "Toggeling of AI is allowed while attached to this attacher joint", true) |
307 | schema:register(XMLValueType.BOOL, baseName .. "#allowDetachWhileParentLifted", "If set to false the parent vehicle needs to be lowered to be able to detach this implement", true) |
308 | |
309 | schema:register(XMLValueType.INT, baseName .. ".dependentAttacherJoint(?)#attacherJointIndex", "Dependent attacher joint index") |
310 | |
311 | schema:register(XMLValueType.NODE_INDEX, baseName .. ".additionalObjects.additionalObject(?)#node", "Additional object node") |
312 | schema:register(XMLValueType.STRING, baseName .. ".additionalObjects.additionalObject(?)#attacherVehiclePath", "Path to vehicle for object activation") |
313 | |
314 | schema:register(XMLValueType.STRING, baseName .. ".additionalAttachment#filename", "Path to additional attachment") |
315 | schema:register(XMLValueType.INT, baseName .. ".additionalAttachment#inputAttacherJointIndex", "Input attacher joint index of additional attachment") |
316 | schema:register(XMLValueType.BOOL, baseName .. ".additionalAttachment#needsLowering", "Additional implements needs lowering") |
317 | schema:register(XMLValueType.STRING, baseName .. ".additionalAttachment#jointType", "Additional implement joint type") |
318 | end |