LUADOC - Farming Simulator 19

Vehicle

Description
This class handles all basic functionality of a vehicle - loading of i3d - syncing of components - handling of specializations
Parent
Object
Functions

actionEventToggleSelection

Description
Definition
actionEventToggleSelection()
Code
2951function Vehicle.actionEventToggleSelection(self, actionName, inputValue, callbackState, isAnalog)
2952 local currentSelection = self.currentSelection
2953 local currentObject = currentSelection.object
2954 local currentObjectIndex = currentSelection.index
2955 local currentSubObjectIndex = currentSelection.subIndex
2956
2957 local numSubSelections = 0
2958 if currentObject ~= nil then
2959 numSubSelections = #currentObject.subSelections
2960 end
2961
2962 local newSelectedSubObjectIndex = currentSubObjectIndex + 1
2963 local newSelectedObjectIndex = currentObjectIndex
2964 local newSelectedObject = currentObject
2965
2966 if newSelectedSubObjectIndex > numSubSelections then
2967 newSelectedSubObjectIndex = 1
2968 newSelectedObjectIndex = currentObjectIndex + 1
2969
2970 if newSelectedObjectIndex > #self.selectableObjects then
2971 newSelectedObjectIndex = 1
2972 end
2973 newSelectedObject = self.selectableObjects[newSelectedObjectIndex]
2974 end
2975
2976 if currentObject ~= newSelectedObject or currentObjectIndex ~= newSelectedObjectIndex or currentSubObjectIndex ~= newSelectedSubObjectIndex then
2977 -- event
2978 self:setSelectedObject(newSelectedObject, newSelectedSubObjectIndex)
2979 end
2980end

activate

Description
Called on activate
Definition
activate()
Code
2257function Vehicle:activate()
2258 SpecializationUtil.raiseEvent(self, "onActivate")
2259end

addNodeObjectMapping

Description
Add component nodes to list
Definition
addNodeObjectMapping(table list)
Arguments
tablelistlist
Code
1462function Vehicle:addNodeObjectMapping(list)
1463 for _,v in pairs(self.components) do
1464 list[v.node] = self
1465 end
1466end

addSubselection

Description
Definition
addSubselection()
Code
2028function Vehicle:addSubselection(subSelection)
2029 table.insert(self.selectionObject.subSelections, subSelection)
2030 return #self.selectionObject.subSelections
2031end

addToPhysics

Description
Add vehicle to physics
Definition
addToPhysics()
Return Values
booleansuccesssuccess
Code
1480function Vehicle:addToPhysics()
1481
1482 if not self.isAddedToPhysics then
1483 local lastMotorizedNode = nil
1484 for _, component in pairs(self.components) do
1485 addToPhysics(component.node)
1486 if component.motorized then
1487 if lastMotorizedNode ~= nil then
1488 if self.isServer then
1489 addVehicleLink(lastMotorizedNode, component.node)
1490 end
1491 end
1492 lastMotorizedNode = component.node
1493 end
1494 end
1495
1496 self.isAddedToPhysics = true
1497
1498 if self.isServer then
1499 for _, jointDesc in pairs(self.componentJoints) do
1500 self:createComponentJoint(self.components[jointDesc.componentIndices[1]], self.components[jointDesc.componentIndices[2]], jointDesc)
1501 end
1502
1503 -- if rootnode is sleeping all other components are sleeping as well
1504 addWakeUpReport(self.rootNode, "onVehicleWakeUpCallback", self)
1505 end
1506
1507 for _, collisionPair in pairs(self.collisionPairs) do
1508 setPairCollision(collisionPair.component1.node, collisionPair.component2.node, collisionPair.enabled)
1509 end
1510
1511 self:setMassDirty()
1512 end
1513
1514 return true
1515end

addToTotalVehicleList

Description
Definition
addToTotalVehicleList()
Code
2783function Vehicle:addToTotalVehicleList(list)
2784 list[self] = self
2785end

addVehicleToAIImplementList

Description
Definition
addVehicleToAIImplementList()
Code
2778function Vehicle:addVehicleToAIImplementList(list)
2779end

createComponentJoint

Description
Create component joint between two components
Definition
createComponentJoint(table component1, table component2, table jointDesc)
Arguments
tablecomponent1component 1
tablecomponent2component 2
tablejointDescjoint desc
Return Values
booleansuccesssuccess
Code
2591function Vehicle:createComponentJoint(component1, component2, jointDesc)
2592 if component1 == nil or component2 == nil or jointDesc == nil then
2593 g_logManager:xmlWarning(self.configFileName, "Could not create component joint. No component1, component2 or jointDesc given!")
2594 return false
2595 end
2596
2597 local constr = JointConstructor:new()
2598 constr:setActors(component1.node, component2.node)
2599
2600 local localPoses1 = jointDesc.jointLocalPoses[1]
2601 local localPoses2 = jointDesc.jointLocalPoses[2]
2602 constr:setJointLocalPositions(localPoses1.trans[1], localPoses1.trans[2], localPoses1.trans[3], localPoses2.trans[1], localPoses2.trans[2], localPoses2.trans[3])
2603 constr:setJointLocalRotations(localPoses1.rot[1], localPoses1.rot[2], localPoses1.rot[3], localPoses2.rot[1], localPoses2.rot[2], localPoses2.rot[3])
2604 --constr:setJointTransforms(jointDesc.jointNode, jointDesc.jointNodeActor1)
2605
2606 constr:setRotationLimitSpring(jointDesc.rotLimitSpring[1], jointDesc.rotLimitDamping[1], jointDesc.rotLimitSpring[2], jointDesc.rotLimitDamping[2], jointDesc.rotLimitSpring[3], jointDesc.rotLimitDamping[3])
2607 constr:setTranslationLimitSpring(jointDesc.transLimitSpring[1], jointDesc.transLimitDamping[1], jointDesc.transLimitSpring[2], jointDesc.transLimitDamping[2], jointDesc.transLimitSpring[3], jointDesc.transLimitDamping[3])
2608 constr:setZRotationXOffset(jointDesc.zRotationXOffset)
2609 for i=1, 3 do
2610 if jointDesc.rotLimit[i] >= jointDesc.rotMinLimit[i] then
2611 constr:setRotationLimit(i-1, jointDesc.rotMinLimit[i], jointDesc.rotLimit[i])
2612 end
2613
2614 if jointDesc.transLimit[i] >= jointDesc.transMinLimit[i] then
2615 constr:setTranslationLimit(i-1, true, jointDesc.transMinLimit[i], jointDesc.transLimit[i])
2616 else
2617 constr:setTranslationLimit(i-1, false, 0, 0)
2618 end
2619 end
2620
2621 constr:setRotationLimitForceLimit(jointDesc.rotLimitForceLimit[1], jointDesc.rotLimitForceLimit[2], jointDesc.rotLimitForceLimit[3])
2622 constr:setTranslationLimitForceLimit(jointDesc.transLimitForceLimit[1], jointDesc.transLimitForceLimit[2], jointDesc.transLimitForceLimit[3])
2623
2624 if jointDesc.isBreakable then
2625 constr:setBreakable(jointDesc.breakForce, jointDesc.breakTorque)
2626 end
2627 constr:setEnableCollision(jointDesc.enableCollision)
2628
2629 for i=1,3 do
2630 if jointDesc.maxRotDriveForce[i] > 0.0001 and (jointDesc.rotDriveVelocity[i] ~= nil or jointDesc.rotDriveRotation[i] ~= nil) then
2631 local pos = Utils.getNoNil(jointDesc.rotDriveRotation[i], 0)
2632 local vel = Utils.getNoNil(jointDesc.rotDriveVelocity[i], 0)
2633 constr:setAngularDrive(i-1, jointDesc.rotDriveRotation[i] ~= nil, jointDesc.rotDriveVelocity[i] ~= nil, jointDesc.rotDriveSpring[i], jointDesc.rotDriveDamping[i], jointDesc.maxRotDriveForce[i], pos, vel)
2634 end
2635 if jointDesc.maxTransDriveForce[i] > 0.0001 and (jointDesc.transDriveVelocity[i] ~= nil or jointDesc.transDrivePosition[i] ~= nil) then
2636 local pos = Utils.getNoNil(jointDesc.transDrivePosition[i], 0)
2637 local vel = Utils.getNoNil(jointDesc.transDriveVelocity[i], 0)
2638 constr:setLinearDrive(i-1, jointDesc.transDrivePosition[i] ~= nil, jointDesc.transDriveVelocity[i] ~= nil, jointDesc.transDriveSpring[i], jointDesc.transDriveDamping[i], jointDesc.maxTransDriveForce[i], pos, vel)
2639 end
2640 end
2641
2642 jointDesc.jointIndex = constr:finalize()
2643
2644 return true
2645end

dayChanged

Description
Called if day changed
Definition
dayChanged()
Code
2721function Vehicle:dayChanged()
2722 self.age = self.age + 1
2723end

deactivate

Description
Called on deactivate
Definition
deactivate()
Code
2263function Vehicle:deactivate()
2264 SpecializationUtil.raiseEvent(self, "onDeactivate")
2265end

delete

Description
Definition
delete()
Code
801function Vehicle:delete()
802 g_messageCenter:unsubscribeAll(self)
803
804 if g_currentMission ~= nil and g_currentMission.environment ~= nil then
805 g_currentMission.environment:removeDayChangeListener(self)
806 end
807
808 local rootVehicle = self:getRootVehicle()
809 if rootVehicle:getIsAIActive() then
810 rootVehicle:stopAIVehicle(AIVehicle.STOP_REASON_REGULAR)
811 end
812
813 g_inputBinding:beginActionEventsModification(Vehicle.INPUT_CONTEXT_NAME)
814 self:removeActionEvents()
815 g_inputBinding:endActionEventsModification()
816
817 SpecializationUtil.raiseEvent(self, "onPreDelete")
818 SpecializationUtil.raiseEvent(self, "onDelete")
819
820 if self.isServer then
821 for _,v in pairs(self.componentJoints) do
822 if v.jointIndex ~= 0 then
823 removeJoint(v.jointIndex)
824 end
825 end
826
827 removeWakeUpReport(self.rootNode)
828 end
829
830 for _,v in pairs(self.components) do
831 delete(v.node)
832 end
833
834 g_i3DManager:releaseSharedI3DFile(self.i3dFilename, self.baseDirectory, true)
835
836 delete(self.xmlFile)
837
838 self.isDeleted = true
839
840 Vehicle:superClass().delete(self)
841end

doCheckSpeedLimit

Description
Definition
doCheckSpeedLimit()
Code
2733function Vehicle:doCheckSpeedLimit()
2734 return false
2735end

doCollisionMaskCheck

Description
Definition
doCollisionMaskCheck()
Code
2804function Vehicle:doCollisionMaskCheck(targetCollisionMask, path, node, str)
2805 local ignoreCheck = false
2806 if path ~= nil then
2807 ignoreCheck = Utils.getNoNil(getXMLBool(self.xmlFile, path), false)
2808 end
2809
2810 if not ignoreCheck then
2811 local hasMask = false
2812 if node == nil then
2813 for _, component in ipairs(self.components) do
2814 hasMask = hasMask or bitAND(getCollisionMask(component.node), targetCollisionMask) == targetCollisionMask
2815 end
2816 else
2817 hasMask = hasMask or bitAND(getCollisionMask(node), targetCollisionMask) == targetCollisionMask
2818 end
2819
2820 if not hasMask then
2821 g_logManager:xmlWarning(self.configFileName, "%s has wrong collision mask! Following bit(s) need to be set '%s' or use '%s'", str or self.typeName, MathUtil.numberToSetBitsStr(targetCollisionMask), path)
2822 return false
2823 end
2824 end
2825
2826 return true
2827end

draw

Description
Definition
draw()
Code
1412function Vehicle:draw()
1413 -- draw root attacher vehicle and the selected implement
1414 if self:getIsSelected() or self:getRootVehicle() == self then
1415 local isActiveForInput = self:getIsActiveForInput()
1416 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1417 SpecializationUtil.raiseEvent(self, "onDraw", isActiveForInput, isActiveForInputIgnoreSelection, true)
1418 end
1419
1420 -- DebugUtil.drawDebugNode(self.rootNode, "farm: " .. tostring(self:getOwnerFarmId()) .. ", controller: " .. tostring(self:getActiveFarm()))
1421
1422-- if self == self:getRootVehicle() and self:getIsActiveForInput() then
1423-- renderText(0.5, 0.95, 0.012, tostring(self:getSelectedVehicle()))
1424-- for k, object in ipairs(self.selectableObjects) do
1425-- renderText(0.5, 0.9-k*0.015, 0.012, tostring(object.vehicle) .. " " .. tostring(object.vehicle.configFileName) .. ": " .. #object.subSelections .. " " .. tostring(object.vehicle:getIsSelected()))
1426-- end
1427-- end
1428
1429 VehicleDebug.drawDebug(self)
1430
1431 if self.showTailwaterDepthWarning then
1432 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_dontDriveIntoWater"), 2000)
1433 end
1434end

drawUIInfo

Description
Draw UI info
Definition
drawUIInfo()
Code
1439function Vehicle:drawUIInfo()
1440 if g_showVehicleDistance then
1441 local dist = calcDistanceFrom(self.rootNode, getCamera())
1442 if dist <= 350 then
1443 Utils.renderTextAtWorldPosition(x,y+1,z, string.format("%.0f", dist), getCorrectTextSize(0.02), 0)
1444 end
1445 end
1446end

getAdditionalComponentMass

Description
Definition
getAdditionalComponentMass()
Code
2227function Vehicle:getAdditionalComponentMass(component)
2228 return 0
2229end

getAdditionalSchemaText

Description
Definition
getAdditionalSchemaText()
Code
2715function Vehicle:getAdditionalSchemaText()
2716 return nil
2717end

getCanBePickedUp

Description
Definition
getCanBePickedUp()
Code
2927function Vehicle:getCanBePickedUp(byPlayer)
2928 return self.supportsPickUp and self:getTotalMass() <= Player.MAX_PICKABLE_OBJECT_MASS and g_currentMission.accessHandler:canPlayerAccess(self, byPlayer)
2929end

getCanBeReset

Description
Definition
getCanBeReset()
Code
2933function Vehicle:getCanBeReset()
2934 return self.canBeReset
2935end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
2035function Vehicle:getCanBeSelected()
2036 return VehicleDebug.state ~= 0 -- allow selection while any debug modes is active to debug any vehicle
2037end

getCanByMounted

Description
Definition
getCanByMounted()
Code
2878function Vehicle:getCanByMounted()
2879 return entityExists(self.components[1].node)
2880end

getCanToggleSelectable

Description
Definition
getCanToggleSelectable()
Code
2041function Vehicle:getCanToggleSelectable()
2042 return false
2043end

getChildVehicles

Description
Definition
getChildVehicles()
Code
2053function Vehicle:getChildVehicles(vehicles)
2054 table.insert(vehicles, self)
2055end

getDailyUpkeep

Description
Get daily up keep
Definition
getDailyUpkeep()
Return Values
floatdailyUpkeepdaily up keep
Code
2885function Vehicle:getDailyUpkeep()
2886 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
2887
2888 local multiplier = 1
2889 if storeItem.lifetime ~= nil and storeItem.lifetime ~= 0 then
2890 local ageMultiplier = 0.3 * math.min(self.age/storeItem.lifetime, 1)
2891 local operatingTime = self.operatingTime / (1000*60*60)
2892 local operatingTimeMultiplier = 0.7 * math.min(operatingTime / (storeItem.lifetime*EconomyManager.LIFETIME_OPERATINGTIME_RATIO), 1)
2893 multiplier = 1 + EconomyManager.MAX_DAILYUPKEEP_MULTIPLIER * (ageMultiplier+operatingTimeMultiplier)
2894 end
2895
2896 return StoreItemUtil.getDailyUpkeep(storeItem, self.configurations) * multiplier
2897end

getDeactivateOnLeave

Description
Definition
getDeactivateOnLeave()
Code
1724function Vehicle:getDeactivateOnLeave()
1725 return true
1726end

getDistanceToNode

Description
Definition
getDistanceToNode()
Code
2758function Vehicle:getDistanceToNode(node)
2759 self.interactionFlag = Vehicle.INTERACTION_FLAG_NONE
2760 return math.huge
2761end

getFillLevelInformation

Description
Get fill level information
Definition
getFillLevelInformation(table fillLevelInformations)
Arguments
tablefillLevelInformationsfill level informations
Code
2252function Vehicle:getFillLevelInformation(fillLevelInformations)
2253end

getFullName

Description
Definition
getFullName()
Code
2908function Vehicle:getFullName()
2909 local name = self:getName()
2910 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
2911 if storeItem ~= nil then
2912 local brand = g_brandManager:getBrandByIndex(storeItem.brandIndex)
2913 if brand ~= nil then
2914 name = brand.title .. " " .. name
2915 end
2916 end
2917
2918 if self:getIsAIActive() then
2919 name = name .. " (" .. g_i18n:getText("ui_helper") .. " " .. self:getCurrentHelper().name .. ")"
2920 end
2921
2922 return name
2923end

getInteractionHelp

Description
Definition
getInteractionHelp()
Code
2752function Vehicle:getInteractionHelp()
2753 return ""
2754end

getIsActive

Description
Definition
getIsActive()
Code
1762function Vehicle:getIsActive()
1763 if self.isBroken then
1764 return false
1765 end
1766
1767 if self.forceIsActive then
1768 return true
1769 end
1770
1771 return false
1772end

getIsActiveForInput

Description
Definition
getIsActiveForInput()
Code
1776function Vehicle:getIsActiveForInput(ignoreSelection, activeForAI)
1777 if not self.allowsInput then
1778 return false
1779 end
1780
1781 if not g_currentMission.isRunning then
1782 return false
1783 end
1784
1785 if (activeForAI == nil or not activeForAI) and self:getIsAIActive() then
1786 return false
1787 end
1788
1789 if not ignoreSelection or ignoreSelection == nil then
1790 local rootVehicle = self:getRootVehicle()
1791 if rootVehicle ~= nil then
1792 local selectedObject = rootVehicle:getSelectedVehicle()
1793 if self ~= selectedObject then
1794 return false
1795 end
1796 else
1797 return false
1798 end
1799 end
1800
1801 local rootAttacherVehicle = self:getRootVehicle()
1802 if rootAttacherVehicle ~= self then
1803 if not rootAttacherVehicle:getIsActiveForInput(true, activeForAI) then
1804 return false
1805 end
1806 else
1807 -- if it is the root vehicle and it is not enterable we check for a attacherVehicle
1808 if self.getIsEntered == nil and self.getAttacherVehicle ~= nil and self:getAttacherVehicle() == nil then
1809 return false
1810 end
1811 end
1812
1813 return true
1814end

getIsActiveForSound

Description
Definition
getIsActiveForSound()
Code
1818function Vehicle:getIsActiveForSound()
1819 print("Warning: Vehicle:getIsActiveForSound() is deprecated")
1820 return false
1821end

getIsAIActive

Description
Definition
getIsAIActive()
Code
2765function Vehicle:getIsAIActive()
2766 if self.getAttacherVehicle ~= nil then
2767 local attacherVehicle = self:getAttacherVehicle()
2768 if attacherVehicle ~= nil then
2769 return attacherVehicle:getIsAIActive()
2770 end
2771 end
2772
2773 return false
2774end

getIsInUse

Description
Definition
getIsInUse()
Code
2939function Vehicle:getIsInUse(connection)
2940 return false
2941end

getIsLowered

Description
Definition
getIsLowered()
Code
1825function Vehicle:getIsLowered(defaultIsLowered)
1826 return false
1827end

getIsOnField

Description
Returns true if vehicle is on a field
Definition
getIsOnField()
Return Values
booleanisOnFieldis on field
Code
1673function Vehicle:getIsOnField()
1674 local densityBits = 0
1675 for _,component in pairs(self.components) do
1676 local wx, wy, wz = localToWorld(component.node, getCenterOfMass(component.node))
1677
1678 local h = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wx, wy, wz)
1679 if h-1 > wy then -- 1m threshold since ground tools are working slightly under the ground
1680 break
1681 end
1682
1683 local bits = getDensityAtWorldPos(g_currentMission.terrainDetailId, wx, wy, wz)
1684 densityBits = bitOR(densityBits, bits)
1685 if densityBits ~= 0 then
1686 return true
1687 end
1688 end
1689
1690 return false
1691end

getIsOperating

Description
Returns true if is operating
Definition
getIsOperating()
Return Values
booleanisOperatingis operating
Code
1756function Vehicle:getIsOperating()
1757 return false
1758end

getIsReadyForAutomatedTrainTravel

Description
Definition
getIsReadyForAutomatedTrainTravel()
Code
2831function Vehicle:getIsReadyForAutomatedTrainTravel()
2832 return true
2833end

getIsSelected

Description
Definition
getIsSelected()
Code
2161function Vehicle:getIsSelected()
2162 return self.selectionObject.isSelected
2163end

getIsVehicleNode

Description
Returns true if node is from vehicle
Definition
getIsVehicleNode(Integer nodeId)
Arguments
IntegernodeIdnode id
Return Values
booleanisFromVehicleis from vehicle
Code
1749function Vehicle:getIsVehicleNode(nodeId)
1750 return self.vehicleNodes[nodeId] ~= nil
1751end

getLastSpeed

Description
Returns last speed in kph
Definition
getLastSpeed(boolean useAttacherVehicleSpeed)
Arguments
booleanuseAttacherVehicleSpeeduse speed of attacher vehicle
Return Values
floatlastSpeedlast speed
Code
1711function Vehicle:getLastSpeed(useAttacherVehicleSpeed)
1712 if useAttacherVehicleSpeed then
1713 if self.attacherVehicle ~= nil then
1714 return self.attacherVehicle:getLastSpeed(true)
1715 end
1716 end
1717
1718 return self.lastSpeed * 3600
1719end

getLimitedVehicleYPosition

Description
Definition
getLimitedVehicleYPosition()
Code
1574function Vehicle:getLimitedVehicleYPosition(position)
1575 if position.posY == nil then
1576 -- vehicle position based on yOffset
1577 local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, position.posX, 300, position.posZ)
1578 return terrainHeight + Utils.getNoNil(position.yOffset, 0)
1579 end
1580
1581 return position.posY
1582end

getName

Description
Definition
getName()
Code
2901function Vehicle:getName()
2902 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
2903 return storeItem.name
2904end

getOperatingTime

Description
Definition
getOperatingTime()
Code
2798function Vehicle:getOperatingTime()
2799 return self.operatingTime
2800end

getOwner

Description
Get owner of vehicle
Definition
getOwner()
Return Values
tableownerowner
Code
1731function Vehicle:getOwner()
1732 if self.owner ~= nil then
1733 return self.owner
1734 end
1735
1736 return nil
1737end

getParentComponent

Description
Get parent component of node
Definition
getParentComponent(Integer node)
Arguments
Integernodeid of node
Return Values
IntegerparentComponentid of parent component node
Code
1697function Vehicle:getParentComponent(node)
1698 while node ~= 0 do
1699 if self:getIsVehicleNode(node) then
1700 return node
1701 end
1702 node = getParent(node)
1703 end
1704 return 0
1705end

getPrice

Description
Returns price
Definition
getPrice(float price)
Arguments
floatpriceprice
Code
1648function Vehicle:getPrice()
1649 return self.price
1650end

getPropertyState

Description
Definition
getPropertyState()
Code
2945function Vehicle:getPropertyState()
2946 return self.propertyState
2947end

getReloadXML

Description
Get reload xml
Definition
getReloadXML(table vehicle)
Arguments
tablevehiclevehicle
Return Values
stringxmlxml
Code
2987function Vehicle.getReloadXML(vehicle)
2988
2989 local vehicleXMLFile = createXMLFile("vehicleXMLFile", "", "vehicles")
2990 if vehicleXMLFile ~= nil then
2991 local key = string.format("vehicles.vehicle(%d)", 0)
2992
2993 setXMLInt(vehicleXMLFile, key.."#id", 1)
2994 setXMLString(vehicleXMLFile, key.."#filename", HTMLUtil.encodeToHTML(NetworkUtil.convertToNetworkFilename(vehicle.configFileName)))
2995
2996 vehicle:saveToXMLFile(vehicleXMLFile, key, {})
2997
2998 return vehicleXMLFile
2999 end
3000
3001 return nil
3002end

getRepairPrice

Description
Definition
getRepairPrice()
Code
1859function Vehicle:getRepairPrice(atSellingPoint)
1860 return 0
1861end

getRootVehicle

Description
Definition
getRootVehicle()
Code
2047function Vehicle:getRootVehicle()
2048 return self
2049end

getSelectedObject

Description
Definition
getSelectedObject()
Code
2167function Vehicle:getSelectedObject()
2168 local rootVehicle = self:getRootVehicle()
2169 if rootVehicle == self then
2170 return self.currentSelection.object
2171 end
2172
2173 return rootVehicle:getSelectedObject()
2174end

getSelectedVehicle

Description
Definition
getSelectedVehicle()
Code
2178function Vehicle:getSelectedVehicle()
2179 local selectedObject = self:getSelectedObject()
2180 if selectedObject ~= nil then
2181 return selectedObject.vehicle
2182 end
2183 return nil
2184end

getSellPrice

Description
Get sell price
Definition
getSellPrice()
Return Values
floatsellPricesell price
Code
1655function Vehicle:getSellPrice()
1656 local priceMultiplier = 0.75
1657 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
1658 local maxVehicleAge = storeItem.lifetime
1659
1660 if maxVehicleAge ~= nil and maxVehicleAge ~= 0 then
1661 local ageMultiplier = 0.5 * math.min(self.age/maxVehicleAge, 1)
1662 local operatingTime = self.operatingTime / (1000*60*60)
1663 local operatingTimeMultiplier = 0.5 * math.min(operatingTime / (maxVehicleAge*EconomyManager.LIFETIME_OPERATINGTIME_RATIO), 1)
1664 priceMultiplier = priceMultiplier * math.exp(-3.5 * (ageMultiplier+operatingTimeMultiplier))
1665 end
1666
1667 return math.max(math.floor(self:getPrice() * math.max(priceMultiplier, 0.05)) - self:getRepairPrice(true), 0)
1668end

getSpecValueCombinations

Description
Definition
getSpecValueCombinations()
Code
3081function Vehicle.getSpecValueCombinations(storeItem, realItem)
3082 return storeItem.specs.combination
3083end

getSpecValueDailyUpkeep

Description
Definition
getSpecValueDailyUpkeep()
Code
3017function Vehicle.getSpecValueDailyUpkeep(storeItem, realItem)
3018 local dailyUpkeep = storeItem.dailyUpkeep
3019 if realItem ~= nil and realItem.getDailyUpkeep ~= nil then
3020 dailyUpkeep = realItem:getDailyUpkeep()
3021 end
3022
3023 -- Hide when no upkeep
3024 if dailyUpkeep == 0 then
3025 return nil
3026 end
3027
3028 return string.format(g_i18n:getText("shop_maintenanceValue"), g_i18n:formatMoney(dailyUpkeep, 2))
3029end

getSpecValueOperatingTime

Description
Definition
getSpecValueOperatingTime()
Code
3033function Vehicle.getSpecValueOperatingTime(storeItem, realItem)
3034 if realItem ~= nil and realItem.operatingTime ~= nil then
3035 local minutes = realItem.operatingTime / (1000 * 60)
3036 local hours = math.floor(minutes / 60)
3037 minutes = math.floor((minutes - hours * 60) / 6)
3038 return string.format(g_i18n:getText("shop_operatingTime"), hours, minutes)
3039 end
3040 return nil
3041end

getSpecValueSlots

Description
Definition
getSpecValueSlots()
Code
3087function Vehicle.getSpecValueSlots(storeItem, realItem, isGarage)
3088 local numOwned = g_currentMission:getNumOfItems(storeItem)
3089 local valueText = ""
3090 if isGarage then
3091 local sellSlotUsage = g_currentMission:getStoreItemSlotUsage(storeItem, numOwned == 1)
3092 if sellSlotUsage ~= 0 then
3093 valueText = "+"..sellSlotUsage
3094 end
3095 else
3096 local buySlotUsage = g_currentMission:getStoreItemSlotUsage(storeItem, numOwned == 0)
3097 if buySlotUsage ~= 0 then
3098 valueText = "-"..buySlotUsage
3099 end
3100 end
3101
3102 if valueText ~= "" then
3103 return valueText
3104 else
3105 return nil
3106 end
3107end

getSpecValueSpeedLimit

Description
Definition
getSpecValueSpeedLimit()
Code
3066function Vehicle.getSpecValueSpeedLimit(storeItem, realItem)
3067 if storeItem.specs.speedLimit ~= nil then
3068 return string.format(g_i18n:getText("shop_maxSpeed"), string.format("%1d", g_i18n:getSpeed(storeItem.specs.speedLimit)), g_i18n:getSpeedMeasuringUnit())
3069 end
3070 return nil
3071end

getSpecValueWorkingWidth

Description
Definition
getSpecValueWorkingWidth()
Code
3051function Vehicle.getSpecValueWorkingWidth(storeItem, realItem)
3052 if storeItem.specs.workingWidth ~= nil then
3053 return string.format(g_i18n:getText("shop_workingWidthValue"), g_i18n:formatNumber(storeItem.specs.workingWidth, 1, true))
3054 end
3055 return nil
3056end

getSpeedLimit

Description
Get speed limit
Definition
getSpeedLimit(boolean onlyIfWorking)
Arguments
booleanonlyIfWorkingonly if working
Return Values
floatlimitlimit
booleandoCheckSpeedLimitdo check speed limit
Code
2840function Vehicle:getSpeedLimit(onlyIfWorking)
2841 local limit = math.huge
2842 local doCheckSpeedLimit = self:doCheckSpeedLimit()
2843 if onlyIfWorking == nil or (onlyIfWorking and doCheckSpeedLimit) then
2844 limit = self.speedLimit
2845
2846 local damage = self:getVehicleDamage()
2847 if damage > 0 then
2848 limit = limit * (1 - damage * Vehicle.DAMAGED_SPEEDLIMIT_REDUCTION)
2849 end
2850 end
2851
2852 local attachedImplements
2853 if self.getAttachedImplements ~= nil then
2854 attachedImplements = self:getAttachedImplements()
2855 end
2856 if attachedImplements ~= nil then
2857 for _, implement in pairs(attachedImplements) do
2858 if implement.object ~= nil then
2859 local speed, implementDoCheckSpeedLimit = implement.object:getSpeedLimit(onlyIfWorking)
2860 if onlyIfWorking == nil or (onlyIfWorking and implementDoCheckSpeedLimit) then
2861 limit = math.min(limit, speed)
2862 end
2863 doCheckSpeedLimit = doCheckSpeedLimit or implementDoCheckSpeedLimit
2864 end
2865 end
2866 end
2867 return limit, doCheckSpeedLimit
2868end

getTailwaterDepth

Description
Definition
getTailwaterDepth()
Code
1831function Vehicle:getTailwaterDepth()
1832 local tailwaterDepth = 0
1833 for _,component in pairs(self.components) do
1834 local _,yt,_ = getWorldTranslation(component.node)
1835 tailwaterDepth = math.max(0, g_currentMission.waterY - yt)
1836 end
1837 return tailwaterDepth
1838end

getTotalMass

Description
Returns total mass of vehicle (optional including attached vehicles)
Definition
getTotalMass(boolean onlyGivenVehicle)
Arguments
booleanonlyGivenVehicleuse only the given vehicle, if false or nil it includes all attachables
Return Values
floattotalMasstotal mass
Code
2235function Vehicle:getTotalMass(onlyGivenVehicle)
2236 if self.isServer then
2237 local mass = 0
2238
2239 for _, component in ipairs(self.components) do
2240 mass = mass + component.mass
2241 end
2242
2243 return mass
2244 end
2245
2246 return 0
2247end

getVehicleDamage

Description
Definition
getVehicleDamage()
Code
1853function Vehicle:getVehicleDamage()
1854 return 0
1855end

getWorkLoad

Description
Definition
getWorkLoad()
Code
2740function Vehicle:getWorkLoad()
2741 return 0, 0
2742end

hasInputConflictWithSelection

Description
Definition
hasInputConflictWithSelection()
Code
2188function Vehicle:hasInputConflictWithSelection(inputs)
2189 printCallstack()
2190 g_logManager:xmlWarning(self.configFileName, "Vehicle:hasInputConflictWithSelection() is deprecated!")
2191 return false
2192end

init

Description
Definition
init()
Code
192function Vehicle.init()
193 g_configurationManager:addConfigurationType("baseColor", g_i18n:getText("configuration_baseColor"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_COLOR)
194 g_configurationManager:addConfigurationType("design", g_i18n:getText("configuration_design"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_MULTIOPTION)
195 g_configurationManager:addConfigurationType("designColor", g_i18n:getText("configuration_designColor"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_COLOR)
196 g_configurationManager:addConfigurationType("vehicleType", g_i18n:getText("configuration_design"), nil, nil, ConfigurationUtil.getStoreAddtionalConfigData, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
197
198 g_storeManager:addSpecType("age", "shopListAttributeIconLifeTime", nil, Vehicle.getSpecValueAge)
199 g_storeManager:addSpecType("operatingTime", "shopListAttributeIconOperatingHours", nil, Vehicle.getSpecValueOperatingTime)
200 g_storeManager:addSpecType("dailyUpkeep", "shopListAttributeIconMaintenanceCosts", nil, Vehicle.getSpecValueDailyUpkeep)
201 g_storeManager:addSpecType("workingWidth", "shopListAttributeIconWorkingWidth", Vehicle.loadSpecValueWorkingWidth, Vehicle.getSpecValueWorkingWidth)
202 g_storeManager:addSpecType("speedLimit", "shopListAttributeIconWorkSpeed", Vehicle.loadSpecValueSpeedLimit, Vehicle.getSpecValueSpeedLimit)
203 g_storeManager:addSpecType("combination", "shopListAttributeIconCombinations", Vehicle.loadSpecValueCombinations, Vehicle.getSpecValueCombinations)
204 g_storeManager:addSpecType("slots", "shopListAttributeIconSlots", nil, Vehicle.getSpecValueSlots)
205end

interact

Description
Definition
interact()
Code
2747function Vehicle:interact()
2748end

load

Description
Definition
load()
Code
223function Vehicle:load(vehicleData, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments)
224 local modName, baseDirectory = Utils.getModNameAndBaseDirectory(vehicleData.filename)
225
226 self.configFileName = vehicleData.filename
227 self.baseDirectory = baseDirectory
228 self.customEnvironment = modName
229 self.typeName = vehicleData.typeName
230 self.isVehicleSaved = Utils.getNoNil(vehicleData.isVehicleSaved, true)
231 self.configurations = Utils.getNoNil(vehicleData.configurations, {})
232 self.boughtConfigurations = Utils.getNoNil(vehicleData.boughtConfigurations, {})
233
234 local typeDef = g_vehicleTypeManager:getVehicleTypeByName(self.typeName)
235 if typeDef == nil then
236 g_logManager:xmlWarning(self.configFileName, "Unable to find vehicleType '%s'", self.typeName)
237 self:setLoadingState(BaseMission.VEHICLE_LOAD_ERROR)
238 return self.loadingState
239 end
240
241 self.vehicleType = typeDef
242 self.specializations = typeDef.specializations
243 self.specializationNames = typeDef.specializationNames
244 self.specializationsByName = typeDef.specializationsByName
245 self.eventListeners = typeDef.eventListeners
246 self.actionEvents = {}
247 self.xmlFile = loadXMLFile("TempConfig", vehicleData.filename)
248 self.isAddedToPhysics = false
249
250 -- pass function pointers from specializations to 'self'
251 for funcName, func in pairs(typeDef.functions) do
252 self[funcName] = func
253 end
254
255 local data = {}
256 data[1] = {posX=vehicleData.posX, posY=vehicleData.posY, posZ=vehicleData.posZ, yOffset=vehicleData.yOffset, isAbsolute=vehicleData.isAbsolute}
257 data[2] = {rotX=vehicleData.rotX, rotY=vehicleData.rotY, rotZ=vehicleData.rotZ}
258 data[3] = vehicleData.isVehicleSaved
259 data[4] = vehicleData.propertyState
260 data[5] = vehicleData.ownerFarmId
261 data[6] = vehicleData.price
262 data[7] = vehicleData.savegame
263 data[8] = asyncCallbackFunction
264 data[9] = asyncCallbackObject
265 data[10] = asyncCallbackArguments
266 data[11] = vehicleData.componentPositions
267
268 -- check if one of the configurations is not set - e.g. if new configurations are available but not in savegame
269 local item = g_storeManager:getItemByXMLFilename(self.configFileName)
270 if item ~= nil and item.configurations ~= nil then
271 for configName, _ in pairs(item.configurations) do
272 local defaultConfigId = StoreItemUtil.getDefaultConfigId(item, configName)
273 if self.configurations[configName] == nil then
274 ConfigurationUtil.setConfiguration(self, configName, defaultConfigId)
275 end
276 -- base configuration is always included
277 ConfigurationUtil.addBoughtConfiguration(self, configName, defaultConfigId)
278 end
279 -- check if currently used configurations are still available
280 for configName, value in pairs(self.configurations) do
281 if item.configurations[configName] == nil then
282 g_logManager:xmlWarning(self.configFileName, "Configurations are not present anymore. Ignoring this configuration (%s)!", configName)
283 self.configurations[configName] = nil
284 self.boughtConfigurations[configName] = nil
285 else
286 local defaultConfigId = StoreItemUtil.getDefaultConfigId(item, configName)
287 if #item.configurations[configName] < value then
288 g_logManager:xmlWarning(self.configFileName, "Configuration with index '%d' is not present anymore. Using default configuration instead!", value)
289
290 if self.boughtConfigurations[configName] ~= nil then
291 self.boughtConfigurations[configName][value] = nil
292 if next(self.boughtConfigurations[configName]) == nil then
293 self.boughtConfigurations[configName] = nil
294 end
295 end
296 ConfigurationUtil.setConfiguration(self, configName, defaultConfigId)
297 else
298 ConfigurationUtil.addBoughtConfiguration(self, configName, value)
299 end
300 end
301 end
302 end
303
304 for i=1, table.getn(self.specializations) do
305 local specEntryName = "spec_" .. self.specializationNames[i]
306 if self[specEntryName] ~= nil then
307 g_logManager:xmlError(self.configFileName, "The vehicle specialization '%s' could not be added because variable '%s' already exists!", self.specializationNames[i], specEntryName)
308 self:setLoadingState(BaseMission.VEHICLE_LOAD_ERROR)
309 end
310
311 local env = {}
312 setmetatable(env, { __index = self } )
313 env.actionEvents = {}
314 self[specEntryName] = env
315 end
316
317 SpecializationUtil.raiseEvent(self, "onPreLoad", vehicleData.savegame)
318 if self.loadingState ~= BaseMission.VEHICLE_LOAD_OK then
319 g_logManager:xmlError(self.configFileName, "Vehicle pre-loading failed!")
320 if asyncCallbackFunction ~= nil then
321 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
322 end
323
324 return self.loadingState
325 end
326
327 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.filename", "vehicle.base.filename") --FS17 to FS19
328
329 self.i3dFilename = getXMLString(self.xmlFile, "vehicle.base.filename")
330
331 if asyncCallbackFunction ~= nil then
332 g_i3DManager:loadSharedI3DFile(self.i3dFilename, baseDirectory, true, false, true, self.loadFinished, self, data)
333 else
334 local i3dNode = g_i3DManager:loadSharedI3DFile(self.i3dFilename, baseDirectory, true, false, true)
335 return self:loadFinished(i3dNode, data)
336 end
337end

loadComponentFromXML

Description
Load component from xml
Definition
loadComponentFromXML(table component, integer xmlFile, string key, table rootPosition, Integer i)
Arguments
tablecomponentcomponent
integerxmlFileid of xml object
stringkeykey
tablerootPositionroot position (x, y, z)
Integericomponent index
Return Values
booleansuccesssuccess
Code
2344function Vehicle:loadComponentFromXML(component, xmlFile, key, rootPosition, i)
2345 if not self.isServer then
2346 if getRigidBodyType(component.node) == "Dynamic" then
2347 setRigidBodyType(component.node, "Kinematic")
2348 end
2349 end
2350 link(getRootNode(), component.node)
2351 if i == 1 then
2352 rootPosition[1], rootPosition[2], rootPosition[3] = getTranslation(component.node)
2353 if rootPosition[2] ~= 0 then
2354 g_logManager:xmlWarning(self.configFileName, "Y-Translation of component 1 (node 0>) has to be 0. Current value is: %.5f", rootPosition[2])
2355 end
2356 end
2357
2358 if getRigidBodyType(component.node) == "Static" then
2359 component.isStatic = true
2360 elseif getRigidBodyType(component.node) == "Kinematic" then
2361 component.isKinematic = true
2362 elseif getRigidBodyType(component.node) == "Dynamic" then
2363 component.isDynamic = true
2364 end
2365
2366 -- the position of the first component is the zero
2367 translate(component.node, -rootPosition[1], -rootPosition[2], -rootPosition[3])
2368 local x,y,z = getTranslation(component.node)
2369 local rx,ry,rz = getRotation(component.node)
2370 component.originalTranslation = {x,y,z}
2371 component.originalRotation = {rx,ry,rz}
2372
2373 component.sentTranslation = {x,y,z}
2374 component.sentRotation = {rx,ry,rz}
2375
2376 component.defaultMass = nil
2377 component.mass = nil
2378
2379 local mass = getXMLFloat(xmlFile, key.."#mass")
2380 if mass ~= nil then
2381 if mass < 10 then
2382 g_logManager:xmlDevWarning(self.configFileName, "Mass is lower than 10kg for '%s'. Mass unit is kilogramms. Is this correct?", key)
2383 end
2384 if component.isDynamic then
2385 setMass(component.node, mass/1000)
2386 end
2387
2388 component.defaultMass = mass/1000
2389 component.mass = component.defaultMass
2390 component.lastMass = component.mass
2391 else
2392 g_logManager:xmlWarning(self.configFileName, "Missing 'mass' for '%s'. Using default mass 500kg instead!", key)
2393 component.defaultMass = 0.5
2394 component.mass = 0.5
2395 component.lastMass = component.mass
2396 end
2397
2398 local comStr = getXMLString(xmlFile, key .. "#centerOfMass");
2399 if comStr ~= nil then
2400 local com = StringUtil.getVectorNFromString(comStr, 3)
2401 if com ~= nil then
2402 setCenterOfMass(component.node, com[1], com[2], com[3])
2403 else
2404 g_logManager:xmlWarning(self.configFileName, "Invalid center of mass given for '%s'. Ignoring this definition", key)
2405 end
2406 end
2407 local count = getXMLInt(xmlFile, key .. "#solverIterationCount")
2408 if count ~= nil then
2409 setSolverIterationCount(component.node, count)
2410 component.solverIterationCount = count
2411 end
2412 component.motorized = getXMLBool(xmlFile, key .. "#motorized") -- Note: motorized is nil if not set in the xml, and can be set by the wheels
2413 self.vehicleNodes[component.node] = {component=component}
2414 local clipDistance = getClipDistance(component.node)
2415 if clipDistance >= 1000000 and getVisibility(component.node) then
2416 local defaultClipdistance = 300
2417 g_logManager:xmlWarning(self.configFileName, "No clipdistance is set to component node '%s' (%s>). Set default clipdistance '%d'", getName(component.node), i-1, defaultClipdistance)
2418 setClipDistance(component.node, defaultClipdistance)
2419 end
2420
2421 component.collideWithAttachables = Utils.getNoNil(getXMLBool(xmlFile, key.."#collideWithAttachables"), false)
2422
2423 if getRigidBodyType(component.node) ~= "NoRigidBody" then
2424 if getLinearDamping(component.node) > 0.01 then
2425 g_logManager:xmlDevWarning(self.configFileName, "Non-zero linear damping (%.4f) for component node '%s' (%s>). Is this correct?", getLinearDamping(component.node), getName(component.node), i-1)
2426 elseif getAngularDamping(component.node) > 0.05 then
2427 g_logManager:xmlDevWarning(self.configFileName, "Large angular damping (%.4f) for component node '%s' (%s>). Is this correct?", getAngularDamping(component.node), getName(component.node), i-1)
2428 elseif getAngularDamping(component.node) < 0.0001 then
2429 g_logManager:xmlDevWarning(self.configFileName, "Zero damping for component node '%s' (%s>). Is this correct?", getName(component.node), i-1)
2430 end
2431 end
2432
2433 local name = getName(component.node)
2434 if not StringUtil.endsWith(name, "component"..i) then
2435 g_logManager:xmlDevWarning(self.configFileName, "Name of component '%d' ('%s') does not correpond with the component naming convention! (vehicleName_componentName_component%d)", i, name, i)
2436 end
2437
2438 return true
2439end

loadComponentJointFromXML

Description
Load component joints from xml
Definition
loadComponentJointFromXML(table jointDesc, integer xmlFile, string key, Integer componentJointI, Integer jointNode, Integer index1, Integer index2)
Arguments
tablejointDescjoint desc
integerxmlFileid of xml object
stringkeykey
IntegercomponentJointIcomponent joint index
IntegerjointNodeid of joint node
Integerindex1index of component 1
Integerindex2index of component 2
Return Values
booleansuccesssuccess
Code
2451function Vehicle:loadComponentJointFromXML(jointDesc, xmlFile, key, componentJointI, jointNode, index1, index2)
2452 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key .. "#indexActor1", key .. "#nodeActor1") --FS17 to FS19
2453
2454 jointDesc.componentIndices = {index1, index2}
2455 jointDesc.jointNode = jointNode
2456 jointDesc.jointNodeActor1 = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#nodeActor1"), self.i3dMappings), jointNode)
2457 if self.isServer then
2458 if self.components[index1] == nil or self.components[index2] == nil then
2459 g_logManager:xmlWarning(self.configFileName, "Invalid component indices (component1: %d, component2: %d) for component joint %d. Indices start with 1!", index1, index2, componentJointI)
2460 return false
2461 end
2462
2463 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotLimit"))
2464 local rotLimits = { math.rad(Utils.getNoNil(x, 0)), math.rad(Utils.getNoNil(y, 0)), math.rad(Utils.getNoNil(z, 0)) }
2465 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transLimit"))
2466 local transLimits = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2467 jointDesc.rotLimit = rotLimits
2468 jointDesc.transLimit = transLimits
2469
2470 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotMinLimit"))
2471 local rotMinLimits = { Utils.getNoNilRad(x, nil), Utils.getNoNilRad(y, nil), Utils.getNoNilRad(z, nil) }
2472
2473 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transMinLimit"))
2474 local transMinLimits = { x,y,z }
2475
2476 for i=1,3 do
2477 if rotMinLimits[i] == nil then
2478 if rotLimits[i] >= 0 then
2479 rotMinLimits[i] = -rotLimits[i]
2480 else
2481 rotMinLimits[i] = rotLimits[i]+1
2482 end
2483 end
2484 if transMinLimits[i] == nil then
2485 if transLimits[i] >= 0 then
2486 transMinLimits[i] = -transLimits[i]
2487 else
2488 transMinLimits[i] = transLimits[i]+1
2489 end
2490 end
2491 end
2492
2493 jointDesc.jointLocalPoses = {}
2494 local trans = {localToLocal(jointDesc.jointNode, self.components[index1].node, 0, 0, 0)}
2495 local rot = {localRotationToLocal(jointDesc.jointNode, self.components[index1].node, 0, 0, 0)}
2496 jointDesc.jointLocalPoses[1] = {trans=trans, rot=rot}
2497
2498 local trans = {localToLocal(jointDesc.jointNodeActor1, self.components[index2].node, 0, 0, 0)}
2499 local rot = {localRotationToLocal(jointDesc.jointNodeActor1, self.components[index2].node, 0, 0, 0)}
2500 jointDesc.jointLocalPoses[2] = {trans=trans, rot=rot}
2501
2502 jointDesc.rotMinLimit = rotMinLimits
2503 jointDesc.transMinLimit = transMinLimits
2504
2505 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotLimitSpring"))
2506 local rotLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2507 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotLimitDamping"))
2508 local rotLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }
2509 jointDesc.rotLimitSpring = rotLimitSpring
2510 jointDesc.rotLimitDamping = rotLimitDamping
2511
2512 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotLimitForceLimit"))
2513 local rotLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) }
2514 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transLimitForceLimit"))
2515 local transLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) }
2516 jointDesc.rotLimitForceLimit = rotLimitForceLimit
2517 jointDesc.transLimitForceLimit = transLimitForceLimit
2518
2519 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transLimitSpring"))
2520 local transLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2521 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transLimitDamping"))
2522 local transLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }
2523 jointDesc.transLimitSpring = transLimitSpring
2524 jointDesc.transLimitDamping = transLimitDamping
2525
2526 jointDesc.zRotationXOffset = 0
2527 local zRotationNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#zRotationNode"), self.i3dMappings)
2528 if zRotationNode ~= nil then
2529 jointDesc.zRotationXOffset,_,_ = localToLocal(zRotationNode, jointNode, 0,0,0)
2530 end
2531
2532 jointDesc.isBreakable = Utils.getNoNil(getXMLBool(xmlFile, key.."#breakable"), false)
2533 if jointDesc.isBreakable then
2534 jointDesc.breakForce = Utils.getNoNil(getXMLFloat(xmlFile, key.."#breakForce"), 10)
2535 jointDesc.breakTorque = Utils.getNoNil(getXMLFloat(xmlFile, key.."#breakTorque"), 10)
2536 end
2537 jointDesc.enableCollision = Utils.getNoNil(getXMLBool(xmlFile, key.."#enableCollision"), false)
2538
2539 -- Rotational drive
2540 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#maxRotDriveForce"))
2541 local maxRotDriveForce = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2542 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotDriveVelocity"))
2543 local rotDriveVelocity = { Utils.getNoNilRad(x, nil), Utils.getNoNilRad(y, nil), Utils.getNoNilRad(z, nil) } -- convert from deg/s to rad/s
2544 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotDriveRotation"))
2545 local rotDriveRotation = { Utils.getNoNilRad(x, nil), Utils.getNoNilRad(y, nil), Utils.getNoNilRad(z, nil) } -- convert from deg to rad
2546 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotDriveSpring"))
2547 local rotDriveSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2548 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotDriveDamping"))
2549 local rotDriveDamping = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2550
2551 jointDesc.rotDriveVelocity = rotDriveVelocity
2552 jointDesc.rotDriveRotation = rotDriveRotation
2553 jointDesc.rotDriveSpring = rotDriveSpring
2554 jointDesc.rotDriveDamping = rotDriveDamping
2555 jointDesc.maxRotDriveForce = maxRotDriveForce
2556
2557 -- Translational drive
2558 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transDriveVelocity"))
2559 local transDriveVelocity = { x,y,z }
2560
2561 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transDrivePosition"))
2562 local transDrivePosition = { x,y,z }
2563
2564 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transDriveSpring"))
2565 local transDriveSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2566
2567 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#transDriveDamping"))
2568 local transDriveDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }
2569
2570 local x, y, z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#maxTransDriveForce"))
2571 local maxTransDriveForce = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
2572
2573 jointDesc.transDriveVelocity = transDriveVelocity
2574 jointDesc.transDrivePosition = transDrivePosition
2575 jointDesc.transDriveSpring = transDriveSpring
2576 jointDesc.transDriveDamping = transDriveDamping
2577 jointDesc.maxTransDriveForce = maxTransDriveForce
2578
2579 jointDesc.jointIndex = 0
2580 end
2581
2582 return true
2583end

loadFinished

Description
Definition
loadFinished()
Code
341function Vehicle:loadFinished(i3dNode, arguments)
342 self:setLoadingState(BaseMission.VEHICLE_LOAD_OK)
343
344 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.forcedMapHotspotType", "vehicle.base.mapHotspot#type") --FS17 to FS19
345 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.speedLimit#value", "vehicle.base.speedLimit#value") --FS17 to FS19
346 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.steeringAxleNode#index", "vehicle.base.steeringAxle#node") --FS17 to FS19
347 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.size#width", "vehicle.base.size#width") --FS17 to FS19
348 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.size#length", "vehicle.base.size#length") --FS17 to FS19
349 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.size#widthOffset", "vehicle.base.size#widthOffset") --FS17 to FS19
350 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.size#lengthOffset", "vehicle.base.size#lengthOffset") --FS17 to FS19
351 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.typeDesc", "vehicle.base.typeDesc") --FS17 to FS19
352 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.components", "vehicle.base.components") --FS17 to FS19
353 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.components.component", "vehicle.base.components.component") --FS17 to FS19
354 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.base.components.component1", "vehicle.base.components.component") --FS17 to FS19
355
356 local position, rotation, isSave, propertyState, ownerFarmId, price, savegame, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments, componentPositions = unpack(arguments)
357
358 if i3dNode == 0 then
359 self:setLoadingState(BaseMission.VEHICLE_LOAD_ERROR)
360 if asyncCallbackFunction ~= nil then
361 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
362 end
363 return self.loadingState
364 end
365
366 if savegame ~= nil then
367 local i = 0
368 while true do
369 local key = string.format(savegame.key..".boughtConfiguration(%d)", i)
370 if not hasXMLProperty(savegame.xmlFile, key) then
371 break
372 end
373 local name = getXMLString(savegame.xmlFile, key.."#name")
374 local id = getXMLInt(savegame.xmlFile, key.."#id")
375 ConfigurationUtil.addBoughtConfiguration(self, name, id)
376 i = i + 1
377 end
378
379 self.tourId = nil
380 local tourId = getXMLString(savegame.xmlFile, savegame.key.."#tourId")
381 if tourId ~= nil then
382 self.tourId = tourId
383 if g_currentMission ~= nil then
384 g_currentMission.tourVehicles[self.tourId] = self
385 end
386 end
387 end
388
389 self.age = 0
390 self.propertyState = propertyState
391 self:setOwnerFarmId(ownerFarmId, true)
392
393 if savegame ~= nil then
394 -- Load this early: it used by the vehicle load functions already
395 local farmId = Utils.getNoNil(getXMLInt(savegame.xmlFile, savegame.key .. "#farmId"), AccessHandler.EVERYONE)
396 if g_farmManager.spFarmWasMerged and farmId ~= AccessHandler.EVERYONE then
397 farmId = FarmManager.SINGLEPLAYER_FARM_ID
398 end
399 self:setOwnerFarmId(farmId, true)
400 end
401
402 self.price = price
403 if self.price == 0 or self.price == nil then
404 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
405 self.price = StoreItemUtil.getDefaultPrice(storeItem, self.configurations)
406 end
407 self.typeDesc = XMLUtil.getXMLI18NValue(self.xmlFile, "vehicle.base.typeDesc", getXMLString, "", "TypeDescription", self.customEnvironment, true)
408 self.synchronizePosition = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.base.synchronizePosition"), true)
409 self.highPrecisionPositionSynchronization = false
410 self.supportsPickUp = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.base.supportsPickUp"), true)
411 self.canBeReset = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.base.canBeReset"), true)
412
413 self.rootNode = getChildAt(i3dNode, 0)
414 self.serverMass = 0
415 self.isMassDirty = false
416
417
418 self.components = {}
419 self.vehicleNodes = {}
420
421 local numComponents = getNumOfChildren(i3dNode)
422 local rootPosition = {0,0,0}
423 local i = 1
424
425 numComponents = getXMLInt(self.xmlFile, "vehicle.base.components#numComponents") or numComponents
426
427 while true do
428 local namei = string.format("vehicle.base.components.component(%d)", i - 1)
429 if not hasXMLProperty(self.xmlFile, namei) then
430 break
431 end
432 if i > numComponents then
433 g_logManager:xmlWarning(self.configFileName, "Invalid components count. I3D file has '%d' components, but tried to load component no. '%d'!", numComponents, i+1)
434 break
435 end
436
437 local component = {node = getChildAt(i3dNode, 0)}
438
439 if self:loadComponentFromXML(component, self.xmlFile, namei, rootPosition, i) then
440 local x,y,z = getWorldTranslation(component.node)
441 local qx,qy,qz,qw = getWorldQuaternion(component.node)
442 component.networkInterpolators = {}
443 component.networkInterpolators.position = InterpolatorPosition:new(x, y, z)
444 component.networkInterpolators.quaternion = InterpolatorQuaternion:new(qx, qy, qz, qw)
445 table.insert(self.components, component)
446 end
447 i = i + 1
448 end
449 delete(i3dNode)
450
451 self.numComponents = table.getn(self.components)
452 if numComponents ~= self.numComponents then
453 g_logManager:xmlWarning(self.configFileName, "I3D file offers '%d' objects, but '%d' components have been loaded!", numComponents, self.numComponents)
454 end
455
456 if self.numComponents == 0 then
457 g_logManager:xmlWarning(self.configFileName, "No components defined for vehicle!")
458
459 self:setLoadingState(BaseMission.VEHICLE_LOAD_ERROR)
460 if asyncCallbackFunction ~= nil then
461 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
462 end
463 return self.loadingState
464 end
465
466 -- load i3d mappings
467 self.i3dMappings = {}
468 local i = 0
469 while true do
470 local key = string.format("vehicle.i3dMappings.i3dMapping(%d)", i)
471 if not hasXMLProperty(self.xmlFile, key) then
472 break
473 end
474 local id = getXMLString(self.xmlFile, key.."#id")
475 local node = getXMLString(self.xmlFile, key.."#node")
476 if id ~= nil and node ~= nil then
477 self.i3dMappings[id] = node
478 end
479 i = i + 1
480 end
481
482 -- need to be defined in vehicle because all vehicles can define a steering axle ref node
483 self.steeringAxleNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.base.steeringAxle#node"), self.i3dMappings)
484 if self.steeringAxleNode == nil then
485 self.steeringAxleNode = self.components[1].node
486 end
487
488 self:loadSchemaOverlay(self.xmlFile)
489
490 -- load component joints
491 self.componentJoints = {}
492
493 local componentJointI = 0
494 while true do
495 local key = string.format("vehicle.base.components.joint(%d)", componentJointI)
496 local index1 = getXMLInt(self.xmlFile, key.."#component1")
497 local index2 = getXMLInt(self.xmlFile, key.."#component2")
498
499 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key .. "#index", key .. "#node") --FS17 to FS19
500
501 local jointIndexStr = getXMLString(self.xmlFile, key.."#node")
502 if index1 == nil or index2 == nil or jointIndexStr == nil then
503 break
504 end
505 local jointNode = I3DUtil.indexToObject(self.components, jointIndexStr, self.i3dMappings)
506 if jointNode ~= nil and jointNode ~= 0 then
507 local jointDesc = {}
508 if self:loadComponentJointFromXML(jointDesc, self.xmlFile, key, componentJointI, jointNode, index1, index2) then
509 table.insert(self.componentJoints, jointDesc)
510 end
511 end
512 componentJointI = componentJointI +1
513 end
514
515 local collisionPairI = 0
516 self.collisionPairs = {}
517 while true do
518 local key = string.format("vehicle.base.components.collisionPair(%d)", collisionPairI)
519 if not hasXMLProperty(self.xmlFile, key) then
520 break
521 end
522 local enabled = getXMLBool(self.xmlFile, key.."#enabled")
523 local index1 = getXMLInt(self.xmlFile, key.."#component1")
524 local index2 = getXMLInt(self.xmlFile, key.."#component2")
525 if index1 ~= nil and index2 ~= nil and enabled ~= nil then
526 local component1 = self.components[index1]
527 local component2 = self.components[index2]
528 if component1 ~= nil and component2 ~= nil then
529 if not enabled then
530 table.insert(self.collisionPairs, {component1=component1, component2=component2, enabled=enabled})
531 end
532 else
533 g_logManager:xmlWarning(self.configFileName, "Failed to load collision pair '%s'. Unknown component indices. Indices start with 1.", key)
534 end
535 end
536 collisionPairI = collisionPairI +1
537 end
538
539 self.supportsRadio = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.base.supportsRadio"), true)
540 self.allowsInput = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.base.input#allowed"), true)
541 self.sizeWidth, self.sizeLength, self.widthOffset, self.lengthOffset = StoreItemUtil.getSizeValuesFromXML(self.xmlFile, "vehicle", 0, self.configurations)
542 self.showTailwaterDepthWarning = false
543 self.thresholdTailwaterDepthWarning = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.base.tailwaterDepth#warning"), 1.0)
544 self.thresholdTailwaterDepth = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.base.tailwaterDepth#threshold"), 2.5)
545 self.networkTimeInterpolator = InterpolationTime:new(1.2)
546 self.movingDirection = 0
547 self.requiredDriveMode = 1
548 self.rotatedTime = 0
549 self.isBroken = false
550 self.forceIsActive = false
551 self.operatingTime = 0
552 self.firstTimeRun = false
553 self.lastPosition = nil
554 self.lastSpeed = 0
555 self.lastSpeedReal = 0
556 self.lastSignedSpeed = 0
557 self.lastSignedSpeedReal = 0
558 self.lastMovedDistance = 0
559 self.lastSpeedAcceleration = 0
560 self.lastMoveTime = -10000
561 self.operatingTime = 0
562 self.isSelectable = true
563
564
565 self.selectionObjects = {}
566 self.currentSelection = {object=nil, index=0, subIndex=1}
567 self.selectionObject = {index=0, isSelected=false, vehicle=self, subSelections={}}
568
569 self.registeredActionEvents = {}
570 self.actionEventUpdateRequested = false
571 self.vehicleDirtyFlag = self:getNextDirtyFlag()
572
573 if g_currentMission ~= nil and g_currentMission.environment ~= nil then
574 g_currentMission.environment:addDayChangeListener(self)
575 end
576
577 -- load optional forcedMapHotspotType
578 self.forcedMapHotspotType = nil
579 local forcedMapHotspotType = getXMLString(self.xmlFile, "vehicle.base.mapHotspot#type")
580 if forcedMapHotspotType ~= nil then
581 if forcedMapHotspotType == "Tool" then
582 self.forcedMapHotspotType = MapHotspot.CATEGORY_VEHICLE_TOOL
583 elseif forcedMapHotspotType == "Trailer" then
584 self.forcedMapHotspotType = MapHotspot.CATEGORY_VEHICLE_TRAILER
585 elseif forcedMapHotspotType == "Combine" then
586 self.forcedMapHotspotType = MapHotspot.CATEGORY_VEHICLE_COMBINE
587 elseif forcedMapHotspotType == "Steerable" then
588 self.forcedMapHotspotType = MapHotspot.CATEGORY_VEHICLE_STEERABLE
589 else
590 g_logManager:xmlWarning(self.configFileName, "Unsupported forcedMapHotspotType '%s'!", forcedMapHotspotType)
591 end
592 end
593
594 local speedLimit = math.huge
595 for i=1, table.getn(self.specializations) do
596 if self.specializations[i].getDefaultSpeedLimit ~= nil then
597 local limit = self.specializations[i].getDefaultSpeedLimit(self)
598 speedLimit = math.min(limit, speedLimit)
599 end
600 end
601
602 self.checkSpeedLimit = speedLimit == math.huge
603 self.speedLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.base.speedLimit#value"), speedLimit)
604
605 --
606 local objectChanges = {}
607 ObjectChangeUtil.loadObjectChangeFromXML(self.xmlFile, "vehicle.base.objectChanges", objectChanges, self.components, self)
608 ObjectChangeUtil.setObjectChanges(objectChanges, true)
609
610 if self.configurations["vehicleType"] ~= nil then
611 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.vehicleTypeConfigurations.vehicleTypeConfiguration", self.configurations["vehicleType"], self.components, self)
612 end
613
614 SpecializationUtil.raiseEvent(self, "onLoad", savegame)
615 if self.loadingState ~= BaseMission.VEHICLE_LOAD_OK then
616 g_logManager:xmlError(self.configFileName, "Vehicle loading failed!")
617 if asyncCallbackFunction ~= nil then
618 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
619 end
620
621 return self.loadingState
622 end
623
624 -- apply design
625 if self.configurations["design"] ~= nil then
626 ConfigurationUtil.applyDesign(self, self.xmlFile, self.configurations["design"])
627 end
628
629 -- do coloring
630 if self.configurations["baseColor"] ~= nil then
631 ConfigurationUtil.setColor(self, self.xmlFile, "baseColor", self.configurations["baseColor"])
632 end
633
634 -- do coloring
635 if self.configurations["designColor"] ~= nil then
636 ConfigurationUtil.setColor(self, self.xmlFile, "designColor", self.configurations["designColor"])
637 end
638
639
640 -- move all components that are joint to other components to the joint node, so all specializations can move them in there postLoad
641 if self.isServer then
642 for _, jointDesc in pairs(self.componentJoints) do
643 local component2 = self.components[jointDesc.componentIndices[2]].node
644 local jointNode = jointDesc.jointNode
645
646 if self:getParentComponent(jointNode) == component2 then
647 jointNode = jointDesc.jointNodeActor1
648 end
649
650 if self:getParentComponent(jointNode) ~= component2 then
651 setTranslation(component2, localToLocal(component2, jointNode, 0, 0, 0))
652 setRotation(component2, localRotationToLocal(component2, jointNode, 0, 0, 0))
653 link(jointNode, component2)
654 end
655 end
656 end
657
658 SpecializationUtil.raiseEvent(self, "onPostLoad", savegame)
659 if self.loadingState ~= BaseMission.VEHICLE_LOAD_OK then
660 g_logManager:xmlError(self.configFileName, "Vehicle post-loading failed!")
661 if asyncCallbackFunction ~= nil then
662 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
663 end
664
665 return self.loadingState
666 end
667
668 -- move all components that are joint to other components back to the world, so the changes from the specs post load is applied to the world trans/rot
669 if self.isServer then
670 for _, jointDesc in pairs(self.componentJoints) do
671 local component2 = self.components[jointDesc.componentIndices[2]]
672 local jointNode = jointDesc.jointNode
673
674 if self:getParentComponent(jointNode) == component2.node then
675 jointNode = jointDesc.jointNodeActor1
676 end
677
678 if self:getParentComponent(jointNode) ~= component2.node then
679 local ox, oy, oz = 0, 0, 0
680 if jointDesc.jointNodeActor1 ~= jointDesc.jointNode then
681 local x1, y1, z1 = localToLocal(jointDesc.jointNode, component2.node, 0, 0, 0)
682 local x2, y2, z2 = localToLocal(jointDesc.jointNodeActor1, component2.node, 0, 0, 0)
683 ox, oy, oz = x1-x2, y1-y2, z1-z2
684 end
685
686 local x, y, z = localToWorld(component2.node, ox, oy, oz)
687 local rx, ry, rz = localRotationToWorld(component2.node, 0, 0, 0)
688
689 link(getRootNode(), component2.node)
690 setWorldTranslation(component2.node, x, y, z)
691 setWorldRotation(component2.node, rx, ry, rz)
692
693 component2.originalTranslation = {x, y, z}
694 component2.originalRotation = {rx, ry, rz}
695
696 component2.sentTranslation = {x, y, z}
697 component2.sentRotation = {rx, ry, rz}
698 end
699 end
700
701 for _, jointDesc in pairs(self.componentJoints) do
702 self:setComponentJointFrame(jointDesc, 0)
703 self:setComponentJointFrame(jointDesc, 1)
704 end
705 end
706
707 if savegame ~= nil then
708 self.age = Utils.getNoNil(getXMLFloat(savegame.xmlFile, savegame.key.."#age"), 0)
709 self.price = Utils.getNoNil(getXMLInt(savegame.xmlFile, savegame.key.."#price"), self.price)
710 self.propertyState = Utils.getNoNil(getXMLInt(savegame.xmlFile, savegame.key.."#propertyState"), self.propertyState)
711 self.activeMissionId = getXMLInt(savegame.xmlFile, savegame.key .. "#activeMissionId")
712
713 local operatingTime = Utils.getNoNil(getXMLFloat(savegame.xmlFile, savegame.key .. "#operatingTime"), self.operatingTime) * 1000
714 self:setOperatingTime(operatingTime, true)
715 local findPlace = savegame.resetVehicles and not savegame.keepPosition
716 if not findPlace then
717 local isAbsolute = Utils.getNoNil(getXMLBool(savegame.xmlFile, savegame.key.."#isAbsolute"), false)
718 if isAbsolute then
719 local componentPosition = {}
720 local i = 1
721 while true do
722 local componentKey = string.format(savegame.key..".component%d", i)
723 if not hasXMLProperty(savegame.xmlFile, componentKey) then
724 break
725 end
726 local x,y,z = StringUtil.getVectorFromString(getXMLString(savegame.xmlFile, componentKey.."#position"))
727 local xRot,yRot,zRot = StringUtil.getVectorFromString(getXMLString(savegame.xmlFile, componentKey.."#rotation"))
728 if x == nil or y == nil or z == nil or xRot == nil or yRot == nil or zRot == nil then
729 findPlace = true
730 break
731 end
732 xRot = math.rad(xRot)
733 yRot = math.rad(yRot)
734 zRot = math.rad(zRot)
735 table.insert(componentPosition, {x=x, y=y, z=z, xRot=xRot, yRot=yRot, zRot=zRot})
736 i = i + 1
737 end
738 if #componentPosition == #self.components then
739 for i=1, #self.components do
740 local p = componentPosition[i]
741 self:setWorldPosition(p.x,p.y,p.z, p.xRot,p.yRot,p.zRot, i, true)
742 end
743 else
744 findPlace = true
745 g_logManager:xmlWarning(self.configFileName, "Invalid savegame component count. Ignoring savegame position!")
746 end
747 else
748 local yOffset = getXMLFloat(savegame.xmlFile, savegame.key.."#yOffset")
749 local xPosition = getXMLFloat(savegame.xmlFile, savegame.key.."#xPosition")
750 local zPosition = getXMLFloat(savegame.xmlFile, savegame.key.."#zPosition")
751 local yRotation = getXMLFloat(savegame.xmlFile, savegame.key.."#yRotation")
752 if yOffset == nil or xPosition == nil or zPosition == nil or yRotation == nil then
753 findPlace = true
754 else
755 self:setRelativePosition(xPosition, yOffset, zPosition, math.rad(yRotation))
756 end
757 end
758 end
759 if findPlace then
760 if savegame.resetVehicles and not savegame.keepPosition then
761 local x, _, z, place, width, offset = PlacementUtil.getPlace(g_currentMission:getResetPlaces(), self.sizeWidth, self.sizeLength, self.widthOffset, self.lengthOffset, g_currentMission.usedLoadPlaces, true, false, true)
762 if x ~= nil then
763 local yRot = MathUtil.getYRotationFromDirection(place.dirPerpX, place.dirPerpZ)
764 PlacementUtil.markPlaceUsed(g_currentMission.usedLoadPlaces, place, width)
765 self:setRelativePosition(x, offset, z, yRot)
766 else
767 self:setLoadingState(BaseMission.VEHICLE_LOAD_NO_SPACE)
768 if asyncCallbackFunction ~= nil then
769 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
770 end
771 return self.loadingState
772 end
773 else
774 self:setLoadingState(BaseMission.VEHICLE_LOAD_DELAYED)
775 end
776 end
777 else
778 self:setAbsolutePosition(position.posX, self:getLimitedVehicleYPosition(position), position.posZ, rotation.rotX, rotation.rotY, rotation.rotZ, componentPositions)
779 end
780
781 self:addToPhysics()
782
783 self:updateSelectableObjects()
784 self:setSelectedVehicle(self, nil, true)
785
786 SpecializationUtil.raiseEvent(self, "onLoadFinished", savegame)
787
788 if componentPositions ~= nil and savegame == nil then
789 self:setAbsolutePosition(position.posX, self:getLimitedVehicleYPosition(position), position.posZ, rotation.rotX, rotation.rotY, rotation.rotZ, componentPositions)
790 end
791
792 if asyncCallbackFunction ~= nil then
793 asyncCallbackFunction(asyncCallbackObject, self, self.loadingState, asyncCallbackArguments)
794 else
795 return self.loadingState
796 end
797end

loadSchemaOverlay

Description
Load schema overlay data from xml file The HUD draws the schema from this information and handles all required visual components.
Definition
loadSchemaOverlay(integer xmlFile)
Arguments
integerxmlFileid of xml object
Code
2665function Vehicle:loadSchemaOverlay(xmlFile)
2666 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#file") --FS17 to FS19
2667 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#width") --FS17 to FS19
2668 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#height") --FS17 to FS19
2669 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#invisibleBorderRight", "vehicle.base.schemaOverlay#invisibleBorderRight") --FS17 to FS19
2670 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#invisibleBorderLeft", "vehicle.base.schemaOverlay#invisibleBorderLeft") --FS17 to FS19
2671 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#attacherJointPosition", "vehicle.base.schemaOverlay#attacherJointPosition") --FS17 to FS19
2672 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#basePosition", "vehicle.base.schemaOverlay#basePosition") --FS17 to FS19
2673 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#fileSelected") --FS17 to FS19
2674 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#fileTurnedOn") --FS17 to FS19
2675 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.schemaOverlay#fileSelectedTurnedOn") --FS17 to FS19
2676
2677 if hasXMLProperty(xmlFile, "vehicle.base.schemaOverlay") then
2678 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, "vehicle.schemaOverlay.attacherJoint", "vehicle.attacherJoints.attacherJoint.schema") -- FS17
2679
2680 local x, y = StringUtil.getVectorFromString(getXMLString(xmlFile, "vehicle.base.schemaOverlay#attacherJointPosition"))
2681 local baseX, baseY = StringUtil.getVectorFromString(getXMLString(xmlFile, "vehicle.base.schemaOverlay#basePosition"))
2682
2683 if baseX == nil then
2684 baseX = x
2685 end
2686
2687 if baseY == nil then
2688 baseY = y
2689 end
2690
2691 local schemaNameDefault = getXMLString(xmlFile, "vehicle.base.schemaOverlay.default#name") or ""
2692 local schemaNameTurnedOn = getXMLString(xmlFile, "vehicle.base.schemaOverlay.turnedOn#name") or ""
2693 local schemaNameSelected = getXMLString(xmlFile, "vehicle.base.schemaOverlay.selected#name") or ""
2694 local schemaNameSelectedTurnedOn = getXMLString(xmlFile, "vehicle.base.schemaOverlay.turnedOnSelected#name") or ""
2695
2696 local modPrefix = self.customEnvironment or ""
2697 schemaNameDefault = Vehicle.prefixSchemaOverlayName(schemaNameDefault, modPrefix)
2698 schemaNameTurnedOn = Vehicle.prefixSchemaOverlayName(schemaNameTurnedOn, modPrefix)
2699 schemaNameSelected = Vehicle.prefixSchemaOverlayName(schemaNameSelected, modPrefix)
2700 schemaNameSelectedTurnedOn = Vehicle.prefixSchemaOverlayName(schemaNameSelectedTurnedOn, modPrefix)
2701
2702 self.schemaOverlay = VehicleSchemaOverlayData.new(
2703 baseX, baseY,
2704 schemaNameDefault,
2705 schemaNameTurnedOn,
2706 schemaNameSelected,
2707 schemaNameSelectedTurnedOn,
2708 getXMLFloat(xmlFile, "vehicle.base.schemaOverlay#invisibleBorderRight"),
2709 getXMLFloat(xmlFile, "vehicle.base.schemaOverlay#invisibleBorderLeft"))
2710 end
2711end

loadSpecValueCombinations

Description
Definition
loadSpecValueCombinations()
Code
3075function Vehicle.loadSpecValueCombinations(xmlFile, customEnvironment)
3076 return XMLUtil.getXMLI18NValue(xmlFile, "vehicle.storeData.specs", getXMLString, "combination", nil, customEnvironment, false)
3077end

loadSpecValueSpeedLimit

Description
Definition
loadSpecValueSpeedLimit()
Code
3060function Vehicle.loadSpecValueSpeedLimit(xmlFile, customEnvironment)
3061 return getXMLString(xmlFile, "vehicle.base.speedLimit#value")
3062end

loadSpecValueWorkingWidth

Description
Definition
loadSpecValueWorkingWidth()
Code
3045function Vehicle.loadSpecValueWorkingWidth(xmlFile, customEnvironment)
3046 return getXMLString(xmlFile, "vehicle.storeData.specs.workingWidth")
3047end

new

Description
Definition
new()
Code
209function Vehicle:new(isServer, isClient, customMt)
210
211 local self = Object:new(isServer, isClient, customMt or Vehicle_mt)
212
213 self.isAddedToMission = false
214 self.isDeleted = false
215 self.updateLoopIndex = -1
216 self.loadingState = BaseMission.VEHICLE_LOAD_OK
217
218 return self
219end

onVehicleWakeUpCallback

Description
Definition
onVehicleWakeUpCallback()
Code
2872function Vehicle:onVehicleWakeUpCallback(id)
2873 self:raiseActive()
2874end

raiseStateChange

Description
Definition
raiseStateChange()
Code
2727function Vehicle:raiseStateChange(state, data)
2728 SpecializationUtil.raiseEvent(self, "onStateChange", state, data)
2729end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
946function Vehicle:readStream(streamId, connection)
947 Vehicle:superClass().readStream(self, streamId)
948 local configFile = NetworkUtil.convertFromNetworkFilename(streamReadString(streamId))
949 local typeName = streamReadString(streamId)
950
951 local configurations = {}
952 local numConfigs = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
953 for i=1, numConfigs do
954 local configNameId = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
955 local configId = streamReadUInt16(streamId)
956
957 local configName = g_configurationManager:getConfigurationNameByIndex(configNameId+1)
958 if configName ~= nil then
959 configurations[configName] = configId+1
960 end
961 end
962
963 local boughtConfigurations = {}
964 local numConfigs = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
965 for i=1, numConfigs do
966 local configNameId = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
967 local configName = g_configurationManager:getConfigurationNameByIndex(configNameId+1)
968 boughtConfigurations[configName] = {}
969 local numBoughtConfigIds = streamReadUInt16(streamId)
970 for j=1, numBoughtConfigIds do
971 local boughtConfigId = streamReadUInt16(streamId)
972 boughtConfigurations[configName][boughtConfigId + 1] = true
973 end
974 end
975
976 if self.configFileName == nil then
977 local vehicleData = {}
978 vehicleData.filename = configFile
979 vehicleData.isAbsolute = false
980 vehicleData.typeName = typeName
981 vehicleData.posX = 0
982 vehicleData.posY = nil
983 vehicleData.posZ = 0
984 vehicleData.yOffset = 0
985 vehicleData.rotX = 0
986 vehicleData.rotY = 0
987 vehicleData.rotZ = 0
988 vehicleData.isVehicleSaved = true
989 vehicleData.price = 0
990 vehicleData.propertyState = Vehicle.PROPERTY_STATE_NONE
991 -- assign parent class Object's ownerFarmId field here to ensure ownership synchronization in MP:
992 vehicleData.ownerFarmId = self.ownerFarmId
993 vehicleData.isLeased = 0
994 vehicleData.configurations = configurations
995 vehicleData.boughtConfigurations = boughtConfigurations
996 self:load(vehicleData)
997 end
998
999 -- remove from physics to set static components correctly
1000 self:removeFromPhysics()
1001
1002 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1003 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1004 for i=1, table.getn(self.components) do
1005 local component = self.components[i]
1006 local x = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1007 local y = NetworkUtil.readCompressedWorldPosition(streamId, paramsY)
1008 local z = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1009 local x_rot = NetworkUtil.readCompressedAngle(streamId)
1010 local y_rot = NetworkUtil.readCompressedAngle(streamId)
1011 local z_rot = NetworkUtil.readCompressedAngle(streamId)
1012
1013 local qx,qy,qz,qw = mathEulerToQuaternion(x_rot,y_rot,z_rot)
1014 self:setWorldPositionQuaternion(x,y,z, qx,qy,qz,qw, i, true)
1015
1016 component.networkInterpolators.position:setPosition(x,y,z)
1017 component.networkInterpolators.quaternion:setQuaternion(qx,qy,qz,qw)
1018 end
1019 self.networkTimeInterpolator:reset()
1020
1021 -- add to physics again
1022 self:addToPhysics()
1023
1024 self.serverMass = streamReadFloat32(streamId)
1025 self.age = streamReadUInt16(streamId)
1026 self:setOperatingTime(streamReadFloat32(streamId), true)
1027 self.price = streamReadInt32(streamId)
1028 self.propertyState = streamReadUIntN(streamId, 2)
1029
1030 SpecializationUtil.raiseEvent(self, "onReadStream", streamId, connection)
1031end

readUpdateStream

Description
Called on client side on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
1101function Vehicle:readUpdateStream(streamId, timestamp, connection)
1102 if connection.isServer then
1103 local hasUpdate = streamReadBool(streamId)
1104 if hasUpdate then
1105 self.networkTimeInterpolator:startNewPhaseNetwork()
1106
1107 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1108 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1109 for i=1, table.getn(self.components) do
1110 local component = self.components[i]
1111 if not component.isStatic then
1112 local x = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1113 local y = NetworkUtil.readCompressedWorldPosition(streamId, paramsY)
1114 local z = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1115 local x_rot = NetworkUtil.readCompressedAngle(streamId)
1116 local y_rot = NetworkUtil.readCompressedAngle(streamId)
1117 local z_rot = NetworkUtil.readCompressedAngle(streamId)
1118 local qx,qy,qz,qw = mathEulerToQuaternion(x_rot,y_rot,z_rot)
1119
1120 component.networkInterpolators.position:setTargetPosition(x,y,z)
1121 component.networkInterpolators.quaternion:setTargetQuaternion(qx,qy,qz,qw)
1122 end
1123 end
1124 SpecializationUtil.raiseEvent(self, "onReadPositionUpdateStream", streamId, connection)
1125 end
1126 end
1127
1128 if Vehicle.debugNetworkUpdate then
1129 print("-------------------------------------------------------------")
1130 print(self.configFileName)
1131 for _, spec in ipairs(self.eventListeners["readUpdateStream"]) do
1132 local className = ClassUtil.getClassName(spec)
1133 local startBits = streamGetReadOffset(streamId)
1134 spec["readUpdateStream"](self, streamId, timestamp, connection)
1135 print(" "..tostring(className).." read " .. streamGetReadOffset(streamId)-startBits .. " bits")
1136 end
1137 else
1138 SpecializationUtil.raiseEvent(self, "onReadUpdateStream", streamId, timestamp, connection)
1139 end
1140end

registerActionEvents

Description
Definition
registerActionEvents()
Code
1893function Vehicle:registerActionEvents(excludedVehicle)
1894 if not g_gui:getIsGuiVisible() and not g_currentMission.isPlayerFrozen and excludedVehicle ~= self then
1895 self.actionEventUpdateRequested = false
1896
1897 local isActiveForInput = self:getIsActiveForInput()
1898 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1899
1900 if isActiveForInput then
1901 -- reset the action binding enabled state for bindings previously disabled during conflict resolution:
1902 g_inputBinding:resetActiveActionBindings()
1903 end
1904
1905 -- safety: set the input registration context without changing the actual input context in case we're currently
1906 -- not in the vehicle context (e.g. due to network events)
1907 g_inputBinding:beginActionEventsModification(Vehicle.INPUT_CONTEXT_NAME)
1908
1909 SpecializationUtil.raiseEvent(self, "onRegisterActionEvents", isActiveForInput, isActiveForInputIgnoreSelection)
1910
1911 self:clearActionEventsTable(self.actionEvents)
1912 if self:getCanToggleSelectable() then
1913 local numSelectableObjects = 0
1914
1915 for _, object in ipairs(self.selectableObjects) do
1916 numSelectableObjects = numSelectableObjects + 1 + #object.subSelections
1917 end
1918
1919 if numSelectableObjects > 1 then
1920 local _, actionEventId = self:addActionEvent(self.actionEvents, InputAction.SWITCH_IMPLEMENT, self, Vehicle.actionEventToggleSelection, false, true, false, true, nil)
1921 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW)
1922 end
1923 end
1924
1925 g_inputBinding:endActionEventsModification()
1926 end
1927end

registerEvents

Description
Definition
registerEvents()
Code
66function Vehicle.registerEvents(vehicleType)
67 SpecializationUtil.registerEvent(vehicleType, "onPreLoad")
68 SpecializationUtil.registerEvent(vehicleType, "onLoad")
69 SpecializationUtil.registerEvent(vehicleType, "onPostLoad")
70 SpecializationUtil.registerEvent(vehicleType, "onLoadFinished")
71 SpecializationUtil.registerEvent(vehicleType, "onPreDelete")
72 SpecializationUtil.registerEvent(vehicleType, "onDelete")
73 SpecializationUtil.registerEvent(vehicleType, "onSave")
74 SpecializationUtil.registerEvent(vehicleType, "onReadStream")
75 SpecializationUtil.registerEvent(vehicleType, "onWriteStream")
76 SpecializationUtil.registerEvent(vehicleType, "onReadUpdateStream")
77 SpecializationUtil.registerEvent(vehicleType, "onWriteUpdateStream")
78 SpecializationUtil.registerEvent(vehicleType, "onReadPositionUpdateStream")
79 SpecializationUtil.registerEvent(vehicleType, "onWritePositionUpdateStream")
80 SpecializationUtil.registerEvent(vehicleType, "onPreUpdate")
81 SpecializationUtil.registerEvent(vehicleType, "onUpdate")
82 SpecializationUtil.registerEvent(vehicleType, "onUpdateInterpolation")
83 SpecializationUtil.registerEvent(vehicleType, "onUpdateDebug")
84 SpecializationUtil.registerEvent(vehicleType, "onPostUpdate")
85 SpecializationUtil.registerEvent(vehicleType, "onUpdateTick")
86 SpecializationUtil.registerEvent(vehicleType, "onPostUpdateTick")
87 SpecializationUtil.registerEvent(vehicleType, "onUpdateEnd")
88 SpecializationUtil.registerEvent(vehicleType, "onDraw")
89 SpecializationUtil.registerEvent(vehicleType, "onActivate")
90 SpecializationUtil.registerEvent(vehicleType, "onDeactivate")
91 SpecializationUtil.registerEvent(vehicleType, "onStateChange")
92 SpecializationUtil.registerEvent(vehicleType, "onRegisterActionEvents")
93 SpecializationUtil.registerEvent(vehicleType, "onSelect")
94 SpecializationUtil.registerEvent(vehicleType, "onUnselect")
95 SpecializationUtil.registerEvent(vehicleType, "onSetBroken")
96end

registerFunctions

Description
Definition
registerFunctions()
Code
100function Vehicle.registerFunctions(vehicleType)
101 SpecializationUtil.registerFunction(vehicleType, "drawUIInfo", Vehicle.drawUIInfo)
102 SpecializationUtil.registerFunction(vehicleType, "raiseActive", Vehicle.raiseActive)
103 SpecializationUtil.registerFunction(vehicleType, "setLoadingState", Vehicle.setLoadingState)
104 SpecializationUtil.registerFunction(vehicleType, "addNodeObjectMapping", Vehicle.addNodeObjectMapping)
105 SpecializationUtil.registerFunction(vehicleType, "removeNodeObjectMapping", Vehicle.removeNodeObjectMapping)
106 SpecializationUtil.registerFunction(vehicleType, "addToPhysics", Vehicle.addToPhysics)
107 SpecializationUtil.registerFunction(vehicleType, "removeFromPhysics", Vehicle.removeFromPhysics)
108 SpecializationUtil.registerFunction(vehicleType, "setRelativePosition", Vehicle.setRelativePosition)
109 SpecializationUtil.registerFunction(vehicleType, "setAbsolutePosition", Vehicle.setAbsolutePosition)
110 SpecializationUtil.registerFunction(vehicleType, "getLimitedVehicleYPosition", Vehicle.getLimitedVehicleYPosition)
111 SpecializationUtil.registerFunction(vehicleType, "setWorldPosition", Vehicle.setWorldPosition)
112 SpecializationUtil.registerFunction(vehicleType, "setWorldPositionQuaternion", Vehicle.setWorldPositionQuaternion)
113 SpecializationUtil.registerFunction(vehicleType, "updateVehicleSpeed", Vehicle.updateVehicleSpeed)
114 SpecializationUtil.registerFunction(vehicleType, "getUpdatePriority", Vehicle.getUpdatePriority)
115 SpecializationUtil.registerFunction(vehicleType, "getPrice", Vehicle.getPrice)
116 SpecializationUtil.registerFunction(vehicleType, "getSellPrice", Vehicle.getSellPrice)
117 SpecializationUtil.registerFunction(vehicleType, "getDailyUpkeep", Vehicle.getDailyUpkeep)
118 SpecializationUtil.registerFunction(vehicleType, "getIsOnField", Vehicle.getIsOnField)
119 SpecializationUtil.registerFunction(vehicleType, "getParentComponent", Vehicle.getParentComponent)
120 SpecializationUtil.registerFunction(vehicleType, "getLastSpeed", Vehicle.getLastSpeed)
121 SpecializationUtil.registerFunction(vehicleType, "getDeactivateOnLeave", Vehicle.getDeactivateOnLeave)
122 SpecializationUtil.registerFunction(vehicleType, "getOwner", Vehicle.getOwner)
123 SpecializationUtil.registerFunction(vehicleType, "getIsVehicleNode", Vehicle.getIsVehicleNode)
124 SpecializationUtil.registerFunction(vehicleType, "getIsOperating", Vehicle.getIsOperating)
125 SpecializationUtil.registerFunction(vehicleType, "getIsActive", Vehicle.getIsActive)
126 SpecializationUtil.registerFunction(vehicleType, "getIsActiveForInput", Vehicle.getIsActiveForInput)
127 SpecializationUtil.registerFunction(vehicleType, "getIsActiveForSound", Vehicle.getIsActiveForSound)
128 SpecializationUtil.registerFunction(vehicleType, "getIsLowered", Vehicle.getIsLowered)
129 SpecializationUtil.registerFunction(vehicleType, "getTailwaterDepth", Vehicle.getTailwaterDepth)
130 SpecializationUtil.registerFunction(vehicleType, "setBroken", Vehicle.setBroken)
131 SpecializationUtil.registerFunction(vehicleType, "getVehicleDamage", Vehicle.getVehicleDamage)
132 SpecializationUtil.registerFunction(vehicleType, "getRepairPrice", Vehicle.getRepairPrice)
133 SpecializationUtil.registerFunction(vehicleType, "setMassDirty", Vehicle.setMassDirty)
134 SpecializationUtil.registerFunction(vehicleType, "updateMass", Vehicle.updateMass)
135 SpecializationUtil.registerFunction(vehicleType, "getAdditionalComponentMass", Vehicle.getAdditionalComponentMass)
136 SpecializationUtil.registerFunction(vehicleType, "getTotalMass", Vehicle.getTotalMass)
137 SpecializationUtil.registerFunction(vehicleType, "getFillLevelInformation", Vehicle.getFillLevelInformation)
138 SpecializationUtil.registerFunction(vehicleType, "activate", Vehicle.activate)
139 SpecializationUtil.registerFunction(vehicleType, "deactivate", Vehicle.deactivate)
140 SpecializationUtil.registerFunction(vehicleType, "setComponentJointFrame", Vehicle.setComponentJointFrame)
141 SpecializationUtil.registerFunction(vehicleType, "setComponentJointRotLimit", Vehicle.setComponentJointRotLimit)
142 SpecializationUtil.registerFunction(vehicleType, "setComponentJointTransLimit", Vehicle.setComponentJointTransLimit)
143 SpecializationUtil.registerFunction(vehicleType, "loadComponentFromXML", Vehicle.loadComponentFromXML)
144 SpecializationUtil.registerFunction(vehicleType, "loadComponentJointFromXML", Vehicle.loadComponentJointFromXML)
145 SpecializationUtil.registerFunction(vehicleType, "createComponentJoint", Vehicle.createComponentJoint)
146 SpecializationUtil.registerFunction(vehicleType, "loadSchemaOverlay", Vehicle.loadSchemaOverlay)
147 SpecializationUtil.registerFunction(vehicleType, "getAdditionalSchemaText", Vehicle.getAdditionalSchemaText)
148 SpecializationUtil.registerFunction(vehicleType, "dayChanged", Vehicle.dayChanged)
149 SpecializationUtil.registerFunction(vehicleType, "raiseStateChange", Vehicle.raiseStateChange)
150 SpecializationUtil.registerFunction(vehicleType, "doCheckSpeedLimit", Vehicle.doCheckSpeedLimit)
151 SpecializationUtil.registerFunction(vehicleType, "interact", Vehicle.interact)
152 SpecializationUtil.registerFunction(vehicleType, "getInteractionHelp", Vehicle.getInteractionHelp)
153 SpecializationUtil.registerFunction(vehicleType, "getDistanceToNode", Vehicle.getDistanceToNode)
154 SpecializationUtil.registerFunction(vehicleType, "getIsAIActive", Vehicle.getIsAIActive)
155 SpecializationUtil.registerFunction(vehicleType, "addVehicleToAIImplementList", Vehicle.addVehicleToAIImplementList)
156 SpecializationUtil.registerFunction(vehicleType, "addToTotalVehicleList", Vehicle.addToTotalVehicleList)
157 SpecializationUtil.registerFunction(vehicleType, "setOperatingTime", Vehicle.setOperatingTime)
158
159 SpecializationUtil.registerFunction(vehicleType, "requestActionEventUpdate", Vehicle.requestActionEventUpdate)
160 SpecializationUtil.registerFunction(vehicleType, "removeActionEvents", Vehicle.removeActionEvents)
161 SpecializationUtil.registerFunction(vehicleType, "updateActionEvents", Vehicle.updateActionEvents)
162 SpecializationUtil.registerFunction(vehicleType, "registerActionEvents", Vehicle.registerActionEvents)
163
164 SpecializationUtil.registerFunction(vehicleType, "updateSelectableObjects", Vehicle.updateSelectableObjects)
165 SpecializationUtil.registerFunction(vehicleType, "registerSelectableObjects", Vehicle.registerSelectableObjects)
166 SpecializationUtil.registerFunction(vehicleType, "addSubselection", Vehicle.addSubselection)
167 SpecializationUtil.registerFunction(vehicleType, "getRootVehicle", Vehicle.getRootVehicle)
168 SpecializationUtil.registerFunction(vehicleType, "getChildVehicles", Vehicle.getChildVehicles)
169 SpecializationUtil.registerFunction(vehicleType, "getCanBeSelected", Vehicle.getCanBeSelected)
170 SpecializationUtil.registerFunction(vehicleType, "getCanToggleSelectable", Vehicle.getCanToggleSelectable)
171 SpecializationUtil.registerFunction(vehicleType, "unselectVehicle", Vehicle.unselectVehicle)
172 SpecializationUtil.registerFunction(vehicleType, "selectVehicle", Vehicle.selectVehicle)
173 SpecializationUtil.registerFunction(vehicleType, "getIsSelected", Vehicle.getIsSelected)
174 SpecializationUtil.registerFunction(vehicleType, "getSelectedObject", Vehicle.getSelectedObject)
175 SpecializationUtil.registerFunction(vehicleType, "getSelectedVehicle", Vehicle.getSelectedVehicle)
176 SpecializationUtil.registerFunction(vehicleType, "setSelectedVehicle", Vehicle.setSelectedVehicle)
177 SpecializationUtil.registerFunction(vehicleType, "setSelectedObject", Vehicle.setSelectedObject)
178 SpecializationUtil.registerFunction(vehicleType, "getIsReadyForAutomatedTrainTravel", Vehicle.getIsReadyForAutomatedTrainTravel)
179 SpecializationUtil.registerFunction(vehicleType, "getActiveFarm", Vehicle.getActiveFarm)
180 SpecializationUtil.registerFunction(vehicleType, "onVehicleWakeUpCallback", Vehicle.onVehicleWakeUpCallback)
181 SpecializationUtil.registerFunction(vehicleType, "getCanByMounted", Vehicle.getCanByMounted)
182 SpecializationUtil.registerFunction(vehicleType, "getName", Vehicle.getName)
183 SpecializationUtil.registerFunction(vehicleType, "getFullName", Vehicle.getFullName)
184 SpecializationUtil.registerFunction(vehicleType, "getCanBePickedUp", Vehicle.getCanBePickedUp)
185 SpecializationUtil.registerFunction(vehicleType, "getCanBeReset", Vehicle.getCanBeReset)
186 SpecializationUtil.registerFunction(vehicleType, "getIsInUse", Vehicle.getIsInUse)
187 SpecializationUtil.registerFunction(vehicleType, "getPropertyState", Vehicle.getPropertyState)
188end

registerInteractionFlag

Description
Register interaction flag
Definition
registerInteractionFlag(string name)
Arguments
stringnamename of flag
Code
46function Vehicle.registerInteractionFlag(name)
47 local key = "INTERACTION_FLAG_"..string.upper(name)
48 if Vehicle[key] == nil then
49 Vehicle.NUM_INTERACTION_FLAGS = Vehicle.NUM_INTERACTION_FLAGS + 1
50 Vehicle[key] = Vehicle.NUM_INTERACTION_FLAGS
51 end
52end

registerSelectableObjects

Description
Definition
registerSelectableObjects()
Code
2019function Vehicle:registerSelectableObjects(selectableObjects)
2020 if self:getCanBeSelected() then
2021 table.insert(selectableObjects, self.selectionObject)
2022 self.selectionObject.index = #selectableObjects
2023 end
2024end

registerStateChange

Description
Definition
registerStateChange()
Code
56function Vehicle.registerStateChange(name)
57 local key = "STATE_CHANGE_"..string.upper(name)
58 if Vehicle[key] == nil then
59 Vehicle.NUM_STATE_CHANGES = Vehicle.NUM_STATE_CHANGES + 1
60 Vehicle[key] = Vehicle.NUM_STATE_CHANGES
61 end
62end

removeActionEvent

Description
Definition
removeActionEvent()
Code
1995function Vehicle:removeActionEvent(actionEventsTable, inputAction)
1996 if actionEventsTable[inputAction] ~= nil then
1997 g_inputBinding:removeActionEvent(actionEventsTable[inputAction].actionEventId)
1998 actionEventsTable[inputAction] = nil
1999 end
2000end

removeActionEvents

Description
Definition
removeActionEvents()
Code
1880function Vehicle:removeActionEvents()
1881 g_inputBinding:removeActionEventsByTarget(self)
1882end

removeFromPhysics

Description
Remove vehicle from physics
Definition
removeFromPhysics()
Code
1519function Vehicle:removeFromPhysics()
1520 for _, component in pairs(self.components) do
1521 removeFromPhysics(component.node)
1522 end
1523 -- invalidate wheel shapes and component joints (removing the components removes the wheels and joints too)
1524 if self.isServer then
1525 for _, jointDesc in pairs(self.componentJoints) do
1526 jointDesc.jointIndex = 0
1527 end
1528 removeWakeUpReport(self.rootNode)
1529 end
1530 self.isAddedToPhysics = false
1531
1532 return true
1533end

removeNodeObjectMapping

Description
Remove component nodes from list
Definition
removeNodeObjectMapping(table list)
Arguments
tablelistlist
Code
1471function Vehicle:removeNodeObjectMapping(list)
1472 for _,v in pairs(self.components) do
1473 list[v.node] = nil
1474 end
1475end

requestActionEventUpdate

Description
Definition
requestActionEventUpdate()
Code
1865function Vehicle:requestActionEventUpdate()
1866 -- pass request to rootVehicle
1867 local vehicle = self:getRootVehicle()
1868 if vehicle == self then
1869 self.actionEventUpdateRequested = true
1870 else
1871 vehicle:requestActionEventUpdate()
1872 end
1873
1874 -- remove all actionEvents
1875 vehicle:removeActionEvents()
1876end

saveStatsToXMLFile

Description
Get xml states attributes
Definition
saveStatsToXMLFile()
Return Values
stringattributesattributes
Code
903function Vehicle:saveStatsToXMLFile(xmlFile, key)
904 local isTabbable = self.getIsTabbable == nil or self:getIsTabbable()
905 if self.isDeleted or not self.isVehicleSaved or not isTabbable then
906 return false
907 end
908 local name = "Unknown"
909 local categoryName = "unknown"
910 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
911 if storeItem ~= nil then
912 if storeItem.name ~= nil then
913 name = tostring(storeItem.name)
914 end
915 if storeItem.categoryName ~= nil and storeItem.categoryName ~= "" then
916 categoryName = tostring(storeItem.categoryName)
917 end
918 end
919
920 setXMLString(xmlFile, key.."#name", HTMLUtil.encodeToHTML(name))
921 setXMLString(xmlFile, key.."#category", HTMLUtil.encodeToHTML(categoryName))
922 setXMLString(xmlFile, key.."#type", HTMLUtil.encodeToHTML(tostring(self.typeName)))
923
924 if self.components[1] ~= nil and self.components[1].node ~= 0 then
925 local x,y,z = getWorldTranslation(self.components[1].node)
926 setXMLFloat(xmlFile, key.."#x", x)
927 setXMLFloat(xmlFile, key.."#y", y)
928 setXMLFloat(xmlFile, key.."#z", z)
929 end
930
931 for id, spec in pairs(self.specializations) do
932 local name = self.specializationNames[id]
933
934 if spec.saveStatsToXMLFile ~= nil then
935 spec.saveStatsToXMLFile(self, xmlFile, key)
936 end
937 end
938
939 return true
940end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
845function Vehicle:saveToXMLFile(xmlFile, key, usedModNames)
846 setXMLBool(xmlFile, key.."#isAbsolute", true)
847 setXMLFloat(xmlFile, key.."#age", self.age)
848 setXMLFloat(xmlFile, key.."#price", self.price)
849 setXMLInt(xmlFile, key.."#farmId", self:getOwnerFarmId())
850 setXMLInt(xmlFile, key.."#propertyState", self.propertyState)
851 setXMLFloat(xmlFile, key.."#operatingTime", self.operatingTime / 1000)
852
853 if self.activeMissionId ~= nil then
854 setXMLInt(xmlFile, key.."#activeMissionId", self.activeMissionId)
855 end
856
857 if self.tourId ~= nil then
858 setXMLString(xmlFile, key.."#tourId", self.tourId)
859 end
860
861 if not self.isBroken then
862 for k, component in ipairs(self.components) do
863 local compKey = string.format("%s.component%d", key, k)
864 local node = component.node
865 local x,y,z = getWorldTranslation(node)
866 local xRot,yRot,zRot = getWorldRotation(node)
867
868 setXMLString(xmlFile, compKey.."#position", string.format("%.4f %.4f %.4f", x, y, z))
869 setXMLString(xmlFile, compKey.."#rotation", string.format("%.4f %.4f %.4f", math.deg(xRot), math.deg(yRot), math.deg(zRot)))
870 end
871 end
872
873 local configIndex = 0
874 for configName, configId in pairs(self.configurations) do
875 local configKey = string.format("%s.configuration(%d)", key, configIndex)
876 setXMLString(xmlFile, configKey.."#name", configName)
877 setXMLInt(xmlFile, configKey.."#id", configId)
878 configIndex = configIndex + 1
879 end
880
881 configIndex = 0
882 for configName, configIds in pairs(self.boughtConfigurations) do
883 for configId,_ in pairs(configIds) do
884 local configKey = string.format("%s.boughtConfiguration(%d)", key, configIndex)
885 setXMLString(xmlFile, configKey.."#name", configName)
886 setXMLInt(xmlFile, configKey.."#id", configId)
887 configIndex = configIndex + 1
888 end
889 end
890
891 for id, spec in pairs(self.specializations) do
892 local name = self.specializationNames[id]
893
894 if spec.saveToXMLFile ~= nil then
895 spec.saveToXMLFile(self, xmlFile, key.."."..name, usedModNames)
896 end
897 end
898end

selectVehicle

Description
Definition
selectVehicle()
Code
2068function Vehicle:selectVehicle(subSelectionIndex, ignoreActionEventUpdate)
2069 self.selectionObject.isSelected = true
2070 SpecializationUtil.raiseEvent(self, "onSelect", subSelectionIndex)
2071
2072 if ignoreActionEventUpdate == nil or not ignoreActionEventUpdate then
2073 self:requestActionEventUpdate()
2074 end
2075end

setAbsolutePosition

Description
Definition
setAbsolutePosition()
Code
1550function Vehicle:setAbsolutePosition(positionX, positionY, positionZ, xRot, yRot, zRot, componentPositions)
1551 local tempRootNode = createTransformGroup("tempRootNode")
1552 setTranslation(tempRootNode, positionX, positionY, positionZ)
1553 setRotation(tempRootNode, xRot, yRot, zRot)
1554
1555 -- now move the objects to the scene root node
1556 for i, component in pairs(self.components) do
1557 local x,y,z = localToWorld(tempRootNode, unpack(component.originalTranslation))
1558 local rx,ry,rz = localRotationToWorld(tempRootNode, unpack(component.originalRotation))
1559
1560 if componentPositions ~= nil and #componentPositions == #self.components then
1561 x,y,z = unpack(componentPositions[i][1])
1562 rx,ry,rz = unpack(componentPositions[i][2])
1563 end
1564
1565 self:setWorldPosition(x, y, z, rx, ry, rz, i, true)
1566 end
1567 delete(tempRootNode)
1568
1569 self.networkTimeInterpolator:reset()
1570end

setBroken

Description
Definition
setBroken()
Code
1842function Vehicle:setBroken()
1843 if self.isServer and not self.isBroken then
1844 g_server:broadcastEvent(VehicleBrokenEvent:new(self), nil, nil, self)
1845 end
1846
1847 self.isBroken = true
1848 SpecializationUtil.raiseEvent(self, "onSetBroken")
1849end

setComponentJointFrame

Description
Set component joint frame
Definition
setComponentJointFrame(Integer jointDesc, Integer anchorActor)
Arguments
IntegerjointDescjoint desc index
IntegeranchorActoranchor actor
Code
2272function Vehicle:setComponentJointFrame(jointDesc, anchorActor)
2273 if anchorActor == 0 then
2274 local localPoses = jointDesc.jointLocalPoses[1]
2275 localPoses.trans[1], localPoses.trans[2], localPoses.trans[3] = localToLocal(jointDesc.jointNode, self.components[jointDesc.componentIndices[1]].node, 0, 0, 0)
2276 localPoses.rot[1], localPoses.rot[2], localPoses.rot[3] = localRotationToLocal(jointDesc.jointNode, self.components[jointDesc.componentIndices[1]].node, 0, 0, 0)
2277 else
2278 local localPoses = jointDesc.jointLocalPoses[2]
2279 localPoses.trans[1], localPoses.trans[2], localPoses.trans[3] = localToLocal(jointDesc.jointNodeActor1, self.components[jointDesc.componentIndices[2]].node, 0, 0, 0)
2280 localPoses.rot[1], localPoses.rot[2], localPoses.rot[3] = localRotationToLocal(jointDesc.jointNodeActor1, self.components[jointDesc.componentIndices[2]].node, 0, 0, 0)
2281 end
2282
2283 local jointNode = jointDesc.jointNode
2284 if anchorActor == 1 then
2285 jointNode = jointDesc.jointNodeActor1
2286 end
2287
2288 if jointDesc.jointIndex ~= 0 then
2289 setJointFrame(jointDesc.jointIndex, anchorActor, jointNode)
2290 end
2291end

setComponentJointRotLimit

Description
Set component joint rot limit
Definition
setComponentJointRotLimit(Integer componentJoint, Integer axis, float minLimit, float maxLimit)
Arguments
IntegercomponentJointindex of component joint
Integeraxisaxis
floatminLimitmin limit
floatmaxLimitmax limit
Code
2300function Vehicle:setComponentJointRotLimit(componentJoint, axis, minLimit, maxLimit)
2301 if self.isServer then
2302 componentJoint.rotLimit[axis] = maxLimit
2303 componentJoint.rotMinLimit[axis] = minLimit
2304
2305 if componentJoint.jointIndex ~= 0 then
2306 if minLimit <= maxLimit then
2307 setJointRotationLimit(componentJoint.jointIndex, axis-1, true, minLimit, maxLimit)
2308 else
2309 setJointRotationLimit(componentJoint.jointIndex, axis-1, false, 0, 0)
2310 end
2311 end
2312 end
2313end

setComponentJointTransLimit

Description
Set component joint trans limit
Definition
setComponentJointTransLimit(Integer componentJoint, Integer axis, float minLimit, float maxLimit)
Arguments
IntegercomponentJointindex of component joint
Integeraxisaxis
floatminLimitmin limit
floatmaxLimitmax limit
Code
2321function Vehicle:setComponentJointTransLimit(componentJoint, axis, minLimit, maxLimit)
2322 if self.isServer then
2323 componentJoint.transLimit[axis] = maxLimit
2324 componentJoint.transMinLimit[axis] = minLimit
2325
2326 if componentJoint.jointIndex ~= 0 then
2327 if minLimit <= maxLimit then
2328 setJointTranslationLimit(componentJoint.jointIndex, axis-1, true, minLimit, maxLimit)
2329 else
2330 setJointTranslationLimit(componentJoint.jointIndex, axis-1, false, 0, 0)
2331 end
2332 end
2333 end
2334end

setLoadingState

Description
Definition
setLoadingState()
Code
1450function Vehicle:setLoadingState(loadingState)
1451 if loadingState == BaseMission.VEHICLE_LOAD_OK or loadingState == BaseMission.VEHICLE_LOAD_ERROR or loadingState == BaseMission.VEHICLE_LOAD_DELAYED or loadingState == BaseMission.VEHICLE_LOAD_NO_SPACE then
1452 self.loadingState = loadingState
1453 else
1454 printCallstack()
1455 g_logManager:xmlError(self.configFileName, "Invalid loading state!")
1456 end
1457end

setMassDirty

Description
Definition
setMassDirty()
Code
2196function Vehicle:setMassDirty()
2197 self.isMassDirty = true
2198end

setOperatingTime

Description
Definition
setOperatingTime()
Code
2789function Vehicle:setOperatingTime(operatingTime, isLoading)
2790 if not isLoading and self.propertyState == Vehicle.PROPERTY_STATE_LEASED and g_currentMission ~= nil and g_currentMission.economyManager ~= nil and math.floor(operatingTime/(1000*60*60)) > math.floor(self.operatingTime/(1000*60*60)) then
2791 g_currentMission.economyManager:vehicleOperatingHourChanged(self)
2792 end
2793 self.operatingTime = math.max(Utils.getNoNil(operatingTime, 0), 0)
2794end

setRelativePosition

Description
Set relative position of vehicle
Definition
setRelativePosition(float positionX, float offsetY, float positionZ, float yRot)
Arguments
floatpositionXx position
floatoffsetYy offset
floatpositionZz position
floatyRoty rotation
Code
1541function Vehicle:setRelativePosition(positionX, offsetY, positionZ, yRot)
1542 -- position the vehicle
1543 local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, positionX, 300, positionZ)
1544
1545 self:setAbsolutePosition(positionX, terrainHeight+offsetY, positionZ, 0, yRot, 0)
1546end

setSelectedObject

Description
Definition
setSelectedObject()
Code
2102function Vehicle:setSelectedObject(object, subSelectionIndex, ignoreActionEventUpdate)
2103 local currentSelection = self.currentSelection
2104
2105 if object == nil then
2106 object = self:getSelectedObject()
2107 end
2108
2109 local found = false
2110 for _, o in ipairs(self.selectableObjects) do
2111 if o == object then
2112 found = true
2113 end
2114 end
2115
2116 if found then
2117 -- if object was found unselect all other vehicles
2118 for _, o in ipairs(self.selectableObjects) do
2119 if o ~= object and o.vehicle:getIsSelected() then
2120 o.vehicle:unselectVehicle()
2121 end
2122 end
2123
2124 if object ~= currentSelection.object or subSelectionIndex ~= currentSelection.subIndex then
2125 currentSelection.object = object
2126 currentSelection.index = object.index
2127 if subSelectionIndex ~= nil then
2128 currentSelection.subIndex = subSelectionIndex
2129 end
2130 if currentSelection.subIndex > #object.subSelections then
2131 currentSelection.subIndex = 1
2132 end
2133
2134 currentSelection.object.vehicle:selectVehicle(currentSelection.subIndex, ignoreActionEventUpdate)
2135
2136 return true
2137 end
2138 else
2139 object = self:getSelectedObject()
2140
2141 found = false
2142 for _, o in ipairs(self.selectableObjects) do
2143 if o == object then
2144 found = true
2145 end
2146 end
2147
2148 -- if the object to select could not be found and the object that was selected is not available anymore we clear the selection
2149 if not found then
2150 currentSelection.object = nil
2151 currentSelection.index = 1
2152 currentSelection.subIndex = 1
2153 end
2154 end
2155
2156 return false
2157end

setSelectedVehicle

Description
Definition
setSelectedVehicle()
Code
2079function Vehicle:setSelectedVehicle(vehicle, subSelectionIndex, ignoreActionEventUpdate)
2080 local object = nil
2081
2082 -- if vehicle could not be selected we select the next possible vehicle
2083 if vehicle == nil or not vehicle:getCanBeSelected() then
2084 vehicle = nil
2085 for _, o in ipairs(self.selectableObjects) do
2086 if o.vehicle:getCanBeSelected() then
2087 vehicle = o.vehicle
2088 break
2089 end
2090 end
2091 end
2092
2093 if vehicle ~= nil then
2094 object = vehicle.selectionObject
2095 end
2096
2097 return self:setSelectedObject(object, subSelectionIndex, ignoreActionEventUpdate)
2098end

setWorldPosition

Description
Set world position and rotation of component
Definition
setWorldPosition(float x, float y, float z, float xRot, float yRot, float zRot, Integer i, boolean changeInterp)
Arguments
floatxx position
floatyy position
floatzz position
floatxRotx rotation
floatyRoty rotation
floatzRotz rotation
Integeriindex if component
booleanchangeInterpchange interpolation
Code
1594function Vehicle:setWorldPosition(x,y,z, xRot,yRot,zRot, i, changeInterp)
1595 local component = self.components[i]
1596 setWorldTranslation(component.node, x,y,z)
1597 setWorldRotation(component.node, xRot,yRot,zRot)
1598 if changeInterp then
1599 local qx, qy, qz, qw = mathEulerToQuaternion(xRot,yRot,zRot)
1600 component.networkInterpolators.quaternion:setQuaternion(qx, qy, qz, qw)
1601 component.networkInterpolators.position:setPosition(x,y,z)
1602 end
1603end

setWorldPositionQuaternion

Description
Set world position and quaternion rotation of component
Definition
setWorldPositionQuaternion(float x, float y, float z, float qx, float qy, float qz, float qw, Integer i, boolean changeInterp)
Arguments
floatxx position
floatyy position
floatzz position
floatqxx rotation
floatqyy rotation
floatqzz rotation
floatqww rotation
Integeriindex if component
booleanchangeInterpchange interpolation
Code
1616function Vehicle:setWorldPositionQuaternion(x,y,z, qx,qy,qz,qw, i, changeInterp)
1617 local component = self.components[i]
1618 setWorldTranslation(component.node, x,y,z)
1619 setWorldQuaternion(component.node, qx,qy,qz,qw)
1620 if changeInterp then
1621 component.networkInterpolators.quaternion:setQuaternion(qx, qy, qz, qw)
1622 component.networkInterpolators.position:setPosition(x,y,z)
1623 end
1624end

unselectVehicle

Description
Definition
unselectVehicle()
Code
2059function Vehicle:unselectVehicle()
2060 self.selectionObject.isSelected = false
2061 SpecializationUtil.raiseEvent(self, "onUnselect")
2062
2063 self:requestActionEventUpdate()
2064end

update

Description
Definition
update()
Code
1268function Vehicle:update(dt)
1269 -- states
1270 local isActive = self:getIsActive()
1271 self.isActive = isActive
1272 local isActiveForInput = self:getIsActiveForInput()
1273 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1274 --local isActiveForInput = isActive and not g_gui:getIsGuiVisible() and not g_currentMission.isPlayerFrozen
1275 local isSelected = self:getIsSelected()
1276
1277 self.updateLoopIndex = g_updateLoopIndex
1278
1279 SpecializationUtil.raiseEvent(self, "onPreUpdate", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1280
1281 -- interpolation of position
1282 if not self.isServer and self.synchronizePosition then
1283 self.networkTimeInterpolator:update(dt)
1284 local interpolationAlpha = self.networkTimeInterpolator:getAlpha()
1285 for i, component in pairs(self.components) do
1286 if not component.isStatic then
1287 local posX, posY, posZ = component.networkInterpolators.position:getInterpolatedValues(interpolationAlpha)
1288 local quatX, quatY, quatZ, quatW = component.networkInterpolators.quaternion:getInterpolatedValues(interpolationAlpha)
1289 self:setWorldPositionQuaternion(posX, posY, posZ, quatX, quatY, quatZ, quatW, i, false)
1290 end
1291 end
1292
1293 if self.networkTimeInterpolator:isInterpolating() then
1294 self:raiseActive()
1295 end
1296 end
1297 SpecializationUtil.raiseEvent(self, "onUpdateInterpolation", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1298
1299 self:updateVehicleSpeed(dt)
1300
1301 if self.actionEventUpdateRequested then
1302 self:updateActionEvents()
1303 end
1304
1305 SpecializationUtil.raiseEvent(self, "onUpdate", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1306 if Vehicle.debuggingActive then
1307 SpecializationUtil.raiseEvent(self, "onUpdateDebug", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1308 end
1309 SpecializationUtil.raiseEvent(self, "onPostUpdate", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1310
1311 if self.vehicleCharacter ~= nil then
1312 self.vehicleCharacter:setDirty(true)
1313 end
1314
1315 if self.firstTimeRun and self.isMassDirty then
1316 self.isMassDirty = false
1317 self:updateMass()
1318 end
1319
1320 self.firstTimeRun = true
1321
1322 if self.isServer then
1323 if not getIsSleeping(self.rootNode) then
1324 self:raiseActive()
1325 end
1326 end
1327
1328 VehicleDebug.updateDebug(self)
1329end

updateActionEvents

Description
Definition
updateActionEvents()
Code
1886function Vehicle:updateActionEvents()
1887 local rootVehicle = self:getRootVehicle()
1888 rootVehicle:registerActionEvents()
1889end

updateEnd

Description
Definition
updateEnd()
Code
1402function Vehicle:updateEnd(dt)
1403 local isActiveForInput = self:getIsActiveForInput()
1404 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1405 local isSelected = self:getIsSelected()
1406
1407 SpecializationUtil.raiseEvent(self, "onUpdateEnd", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1408end

updateMass

Description
Definition
updateMass()
Code
2202function Vehicle:updateMass()
2203 self.serverMass = 0
2204
2205 for _, component in ipairs(self.components) do
2206 if component.defaultMass == nil then
2207 if component.isDynamic then
2208 component.defaultMass = getMass(component.node)
2209 end
2210 component.mass = component.defaultMass
2211 end
2212
2213 local mass = self:getAdditionalComponentMass(component)
2214 component.mass = component.defaultMass + mass
2215
2216 -- only update physically mass if difference to last mass is greater 20kg
2217 if self.isServer and component.isDynamic and math.abs(component.lastMass-component.mass) > 0.02 then
2218 setMass(component.node, component.mass)
2219 component.lastMass = component.mass
2220 end
2221 self.serverMass = self.serverMass + component.mass
2222 end
2223end

updateSelectableObjects

Description
Definition
updateSelectableObjects()
Code
2010function Vehicle:updateSelectableObjects()
2011 self.selectableObjects = {}
2012 if self == self:getRootVehicle() then
2013 self:registerSelectableObjects(self.selectableObjects)
2014 end
2015end

updateTick

Description
updateTick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
1334function Vehicle:updateTick(dt)
1335
1336 local isActive = self:getIsActive()
1337 local isActiveForInput = self:getIsActiveForInput()
1338 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1339 local isSelected = self:getIsSelected()
1340
1341 self.wasTooFast = false
1342 if self.isServer then
1343 if self.synchronizePosition then
1344 local hasOwner = self:getOwner() ~= nil
1345 for i=1, table.getn(self.components) do
1346 local component = self.components[i]
1347 if not component.isStatic then
1348 local x,y,z = getWorldTranslation(component.node)
1349 local x_rot,y_rot,z_rot=getWorldRotation(component.node)
1350 local sentTranslation = component.sentTranslation
1351 local sentRotation = component.sentRotation
1352 if hasOwner or
1353 math.abs(x-sentTranslation[1]) > 0.005 or
1354 math.abs(y-sentTranslation[2]) > 0.005 or
1355 math.abs(z-sentTranslation[3]) > 0.005 or
1356 math.abs(x_rot-sentRotation[1]) > 0.1 or
1357 math.abs(y_rot-sentRotation[2]) > 0.1 or
1358 math.abs(z_rot-sentRotation[3]) > 0.1
1359 then
1360 self:raiseDirtyFlags(self.vehicleDirtyFlag)
1361 sentTranslation[1] = x
1362 sentTranslation[2] = y
1363 sentTranslation[3] = z
1364 sentRotation[1] = x_rot
1365 sentRotation[2] = y_rot
1366 sentRotation[3] = z_rot
1367
1368 self.lastMoveTime = g_currentMission.time
1369 end
1370 end
1371 end
1372 end
1373
1374 -- is the vehicle sunken in the water?
1375 self.showTailwaterDepthWarning = false
1376 if not self.isBroken and not g_gui:getIsGuiVisible() then
1377 local tailwaterDepth = self:getTailwaterDepth()
1378 if tailwaterDepth > self.thresholdTailwaterDepthWarning then
1379 self.showTailwaterDepthWarning = true
1380 if tailwaterDepth > self.thresholdTailwaterDepth then
1381 self:setBroken()
1382 end
1383 end
1384 end
1385
1386 local rootAttacherVehicle = self:getRootVehicle()
1387 if rootAttacherVehicle ~= nil and rootAttacherVehicle ~= self then
1388 rootAttacherVehicle.showTailwaterDepthWarning = rootAttacherVehicle.showTailwaterDepthWarning or self.showTailwaterDepthWarning
1389 end
1390 end
1391
1392 if self:getIsOperating() then
1393 self:setOperatingTime(self.operatingTime + dt)
1394 end
1395
1396 SpecializationUtil.raiseEvent(self, "onUpdateTick", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1397 SpecializationUtil.raiseEvent(self, "onPostUpdateTick", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1398end

updateVehicleSpeed

Description
Definition
updateVehicleSpeed()
Code
1186function Vehicle:updateVehicleSpeed(dt)
1187 -- On servers, the physics state is only change
1188 if self.firstTimeRun and not self.components[1].isStatic then
1189 local speedReal = 0
1190 local movedDistance = 0
1191 local movingDirection = 0
1192 local signedSpeedReal = 0
1193 if not self.isServer or self.components[1].isKinematic then
1194 if not self.isServer and self.synchronizePosition then
1195 -- Client code can use the interpolation information that is driving the position change
1196 local interpPos = self.components[1].networkInterpolators.position
1197 local dx, dy, dz = 0, 0, 0
1198 if self.networkTimeInterpolator:isInterpolating() then
1199 dx, dy, dz = worldDirectionToLocal(self.components[1].node, interpPos.targetPositionX-interpPos.lastPositionX, interpPos.targetPositionY-interpPos.lastPositionY, interpPos.targetPositionZ-interpPos.lastPositionZ)
1200 end
1201
1202 if dz > 0.001 then
1203 movingDirection = 1
1204 elseif dz < -0.001 then
1205 movingDirection = -1
1206 end
1207 speedReal = MathUtil.vector3Length(dx, dy, dz) / self.networkTimeInterpolator.interpolationDuration
1208 signedSpeedReal = speedReal * (dz >= 0 and 1 or -1)
1209 movedDistance = speedReal * dt
1210 else
1211 -- Client or kinematic code can't use physics velocity, so calculate based on the position change
1212 local x,y,z = getWorldTranslation(self.components[1].node)
1213 if self.lastPosition == nil then
1214 self.lastPosition = {x,y,z}
1215 end
1216 local dx, dy, dz = worldDirectionToLocal(self.components[1].node, x-self.lastPosition[1], y-self.lastPosition[2], z-self.lastPosition[3])
1217 self.lastPosition[1], self.lastPosition[2], self.lastPosition[3] = x, y, z
1218 if dz > 0.001 then
1219 movingDirection = 1
1220 elseif dz < -0.001 then
1221 movingDirection = -1
1222 end
1223 movedDistance = MathUtil.vector3Length(dx, dy, dz)
1224 speedReal = movedDistance / dt
1225 signedSpeedReal = speedReal * (dz >= 0 and 1 or -1)
1226 end
1227 elseif self.components[1].isDynamic then
1228 -- Dynamic objects on server use velocity provided by the physics engine
1229 local vx, vy, vz = getLocalLinearVelocity(self.components[1].node)
1230 speedReal = MathUtil.vector3Length(vx, vy, vz)*0.001
1231 movedDistance = speedReal*g_physicsDt
1232 signedSpeedReal = speedReal * (vz >= 0 and 1 or -1)
1233 if vz > 0.001 then
1234 movingDirection = 1
1235 elseif vz < -0.001 then
1236 movingDirection = -1
1237 end
1238 end
1239
1240 if self.isServer then
1241 -- On the server, the velocity only changes when a physics simulation step is performed (thus only update the acceleration when something was simulated)
1242 if g_physicsDtNonInterpolated > 0 then
1243 self.lastSpeedAcceleration = (speedReal*movingDirection - self.lastSpeedReal*self.movingDirection) / g_physicsDtNonInterpolated
1244 end
1245 else
1246 -- On the client, the position is driven by the interpolation (updated with dt)
1247 self.lastSpeedAcceleration = (speedReal*movingDirection - self.lastSpeedReal*self.movingDirection) / dt
1248 end
1249
1250 -- Update smooth values (use less smoothing on the server)
1251 if self.isServer then
1252 self.lastSpeed = self.lastSpeed*0.5 + speedReal*0.5
1253 self.lastSignedSpeed = self.lastSignedSpeed*0.5 + signedSpeedReal*0.5
1254 else
1255 self.lastSpeed = self.lastSpeed*0.9 + speedReal*0.1
1256 self.lastSignedSpeed = self.lastSignedSpeed*0.9 + signedSpeedReal*0.1
1257 end
1258
1259 self.lastSpeedReal = speedReal
1260 self.lastSignedSpeedReal = signedSpeedReal
1261 self.movingDirection = movingDirection
1262 self.lastMovedDistance = movedDistance
1263 end
1264end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
1037function Vehicle:writeStream(streamId, connection)
1038 Vehicle:superClass().writeStream(self, streamId)
1039 streamWriteString(streamId, NetworkUtil.convertToNetworkFilename(self.configFileName))
1040 streamWriteString(streamId, self.typeName)
1041
1042 local numConfigs = 0
1043 for _,_ in pairs(self.configurations) do
1044 numConfigs = numConfigs + 1
1045 end
1046
1047 streamWriteUIntN(streamId, numConfigs, ConfigurationUtil.SEND_NUM_BITS)
1048 for configName, configId in pairs(self.configurations) do
1049 local configNameId = g_configurationManager:getConfigurationIndexByName(configName)
1050 streamWriteUIntN(streamId, configNameId-1, ConfigurationUtil.SEND_NUM_BITS)
1051 streamWriteUInt16(streamId, configId-1)
1052 end
1053
1054 local numBoughtConfigs = 0
1055 for _,_ in pairs(self.boughtConfigurations) do
1056 numBoughtConfigs = numBoughtConfigs + 1
1057 end
1058
1059 streamWriteUIntN(streamId, numBoughtConfigs, ConfigurationUtil.SEND_NUM_BITS)
1060 for configName, configIds in pairs(self.boughtConfigurations) do
1061 local numBoughtConfigIds = 0
1062 for _,_ in pairs(configIds) do
1063 numBoughtConfigIds = numBoughtConfigIds + 1
1064 end
1065 local configNameId = g_configurationManager:getConfigurationIndexByName(configName)
1066 streamWriteUIntN(streamId, configNameId-1, ConfigurationUtil.SEND_NUM_BITS)
1067 streamWriteUInt16(streamId, numBoughtConfigIds)
1068 for id, _ in pairs(configIds) do
1069 streamWriteUInt16(streamId, id-1)
1070 end
1071 end
1072
1073 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1074 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1075 for i=1, table.getn(self.components) do
1076 local component = self.components[i]
1077 local x,y,z = getWorldTranslation(component.node)
1078 local x_rot,y_rot,z_rot = getWorldRotation(component.node)
1079 NetworkUtil.writeCompressedWorldPosition(streamId, x, paramsXZ)
1080 NetworkUtil.writeCompressedWorldPosition(streamId, y, paramsY)
1081 NetworkUtil.writeCompressedWorldPosition(streamId, z, paramsXZ)
1082 NetworkUtil.writeCompressedAngle(streamId, x_rot)
1083 NetworkUtil.writeCompressedAngle(streamId, y_rot)
1084 NetworkUtil.writeCompressedAngle(streamId, z_rot)
1085 end
1086
1087 streamWriteFloat32(streamId, self.serverMass)
1088 streamWriteUInt16(streamId, self.age)
1089 streamWriteFloat32(streamId, self.operatingTime)
1090 streamWriteInt32(streamId, self.price)
1091 streamWriteUIntN(streamId, self.propertyState, 2)
1092
1093 SpecializationUtil.raiseEvent(self, "onWriteStream", streamId, connection)
1094end

writeUpdateStream

Description
Called on server side on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
1147function Vehicle:writeUpdateStream(streamId, connection, dirtyMask)
1148 if not connection.isServer then
1149 if streamWriteBool(streamId, bitAND(dirtyMask, self.vehicleDirtyFlag) ~= 0) then
1150
1151 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1152 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1153 for i=1, table.getn(self.components) do
1154 local component = self.components[i]
1155 if not component.isStatic then
1156 local x,y,z = getWorldTranslation(component.node)
1157 local x_rot,y_rot,z_rot = getWorldRotation(component.node)
1158 NetworkUtil.writeCompressedWorldPosition(streamId, x, paramsXZ)
1159 NetworkUtil.writeCompressedWorldPosition(streamId, y, paramsY)
1160 NetworkUtil.writeCompressedWorldPosition(streamId, z, paramsXZ)
1161 NetworkUtil.writeCompressedAngle(streamId, x_rot)
1162 NetworkUtil.writeCompressedAngle(streamId, y_rot)
1163 NetworkUtil.writeCompressedAngle(streamId, z_rot)
1164 end
1165 end
1166 SpecializationUtil.raiseEvent(self, "onWritePositionUpdateStream", streamId, connection, dirtyMask)
1167 end
1168 end
1169
1170 if Vehicle.debugNetworkUpdate then
1171 print("-------------------------------------------------------------")
1172 print(self.configFileName)
1173 for _, spec in ipairs(self.eventListeners["writeUpdateStream"]) do
1174 local className = ClassUtil.getClassName(spec)
1175 local startBits = streamGetWriteOffset(streamId)
1176 spec["writeUpdateStream"](self, streamId, connection, dirtyMask)
1177 print(" "..tostring(className).." Wrote " .. streamGetWriteOffset(streamId)-startBits .. " bits")
1178 end
1179 else
1180 SpecializationUtil.raiseEvent(self, "onWriteUpdateStream", streamId, connection, dirtyMask)
1181 end
1182end