LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

Combine

Description
Specialization for combines providing threshing, effects, chopper and swath functionality
Functions

actionEventToggleChopper

Description
Definition
actionEventToggleChopper()
Code
1950function Combine.actionEventToggleChopper(self, actionName, inputValue, callbackState, isAnalog)
1951 local spec = self.spec_combine
1952
1953 if spec.swath.isAvailable then
1954 local fillUnitIndex = spec.bufferFillUnitIndex or spec.fillUnitIndex
1955 local fruitType = g_fruitTypeManager:getFruitTypeIndexByFillTypeIndex(self:getFillUnitFillType(fillUnitIndex))
1956 if fruitType ~= nil and fruitType ~= FruitType.UNKNOWN then
1957 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitType)
1958 if fruitDesc.hasWindrow then
1959 self:setIsSwathActive(not spec.isSwathActive)
1960 else
1961 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_couldNotToggleChopper"), 2000)
1962 end
1963 else
1964 self:setIsSwathActive(not spec.isSwathActive)
1965 end
1966 end
1967end

addCutterArea

Description
Definition
addCutterArea()
Code
1264function Combine:addCutterArea(area, realArea, inputFruitType, outputFillType, strawRatio, strawGroundType, farmId, cutterLoad)
1265 local spec = self.spec_combine
1266
1267 if area > 0 and (spec.lastCuttersFruitType == FruitType.UNKNOWN or spec.lastCuttersArea == 0 or spec.lastCuttersOutputFillType == outputFillType) then
1268 spec.lastCuttersArea = spec.lastCuttersArea + area
1269 spec.lastCuttersOutputFillType = outputFillType
1270 spec.lastCuttersInputFruitType = inputFruitType
1271 spec.lastCuttersAreaTime = g_currentMission.time
1272
1273 if not spec.swath.isAvailable then
1274 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(inputFruitType)
1275 spec.isSwathActive = not fruitDesc.hasWindrow
1276 end
1277
1278 local litersPerSqm = 60
1279 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(inputFruitType)
1280 if fruitDesc.windrowLiterPerSqm ~= nil then
1281 litersPerSqm = fruitDesc.windrowLiterPerSqm
1282 end
1283
1284 if self:getIsThreshingDuringRain() and self.propertyState ~= Vehicle.PROPERTY_STATE_MISSION then
1285 realArea = realArea * (1-Combine.RAIN_YIELD_REDUCTION)
1286 end
1287
1288 -- only add straw to buffer if the fill type that is loaded is picked up
1289 if self:getFillUnitLastValidFillType(spec.fillUnitIndex) == outputFillType or self:getFillUnitLastValidFillType(spec.bufferFillUnitIndex) == outputFillType then
1290 local liters = (realArea * g_currentMission:getFruitPixelsToSqm() * litersPerSqm) * strawRatio
1291 if liters > 0 then
1292 local inputBuffer = spec.processing.inputBuffer
1293 local slot = inputBuffer.buffer[inputBuffer.fillIndex]
1294 slot.area = slot.area + area
1295 slot.realArea = slot.realArea + realArea
1296 slot.liters = slot.liters + liters
1297 slot.inputLiters = slot.inputLiters + liters
1298 slot.strawRatio = strawRatio
1299 slot.strawGroundType = strawGroundType
1300 slot.effectDensity = cutterLoad * strawRatio * 0.8 + 0.2
1301 end
1302 end
1303
1304 if spec.fillEnableTime == nil then
1305 spec.fillEnableTime = g_currentMission.time + spec.processing.toggleTime
1306 end
1307
1308 -- 8000/1200 = 6.66 liter/meter
1309 -- 8000/1200 / 6 = 1.111 liter/m^2
1310 -- 8000/1200 / 6 / 2^2 = 0.277777 liter / density pixel (density is 4096^2, on a area of 2048m^2
1311 local pixelToSqm = g_currentMission:getFruitPixelsToSqm() -- 4096px are mapped to 2048m
1312 local literPerSqm = 1
1313 if (inputFruitType ~= FruitType.UNKNOWN) then
1314 fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(inputFruitType)
1315 literPerSqm = fruitDesc.literPerSqm
1316 end
1317 local sqm = realArea*pixelToSqm
1318 local deltaFillLevel = sqm*literPerSqm*spec.threshingScale
1319 local fillType = outputFillType
1320
1321 if spec.additives.available then
1322 local fillTypeSupported = false
1323 for i=1, #spec.additives.fillTypes do
1324 if fillType == spec.additives.fillTypes[i] then
1325 fillTypeSupported = true
1326 break
1327 end
1328 end
1329
1330 if fillTypeSupported then
1331 local additivesFillLevel = self:getFillUnitFillLevel(spec.additives.fillUnitIndex)
1332 if additivesFillLevel > 0 then
1333 local usage = spec.additives.usage * deltaFillLevel
1334 if usage > 0 then
1335 local availableUsage = math.min(additivesFillLevel / usage, 1)
1336
1337 deltaFillLevel = deltaFillLevel * (1 + 0.05 * availableUsage)
1338
1339 self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.additives.fillUnitIndex, -usage, self:getFillUnitFillType(spec.additives.fillUnitIndex), ToolType.UNDEFINED)
1340 end
1341 end
1342 end
1343 end
1344
1345 self:setWorkedHectars(spec.workedHectars + MathUtil.areaToHa(realArea, g_currentMission:getFruitPixelsToSqm()))
1346
1347 if farmId ~= AccessHandler.EVERYONE then
1348 local damage = self:getVehicleDamage()
1349 if damage > 0 then
1350 deltaFillLevel = deltaFillLevel * (1 - damage * Combine.DAMAGED_YIELD_REDUCTION)
1351 end
1352 end
1353
1354 -- buffer only the set time in the xml, after that we do not add more to the fill unit
1355 if self:getFillUnitCapacity(spec.fillUnitIndex) == math.huge and self:getFillUnitFillLevel(spec.fillUnitIndex) > 0.001 then
1356 if spec.lastDischargeTime + spec.fillLevelBufferTime < g_time then
1357 return deltaFillLevel
1358 end
1359 end
1360
1361 local fillUnitIndex = spec.fillUnitIndex
1362 if spec.bufferFillUnitIndex ~= nil then
1363 if self:getFillUnitFreeCapacity(spec.bufferFillUnitIndex) > 0 then
1364 fillUnitIndex = spec.bufferFillUnitIndex
1365 end
1366 end
1367
1368 if spec.loadingDelay > 0 then
1369 for i=1, #spec.loadingDelaySlots do
1370 if not spec.loadingDelaySlots[i].valid then
1371 spec.loadingDelaySlots[i].valid = true
1372 spec.loadingDelaySlots[i].fillLevelDelta = deltaFillLevel
1373 spec.loadingDelaySlots[i].fillType = fillType
1374
1375 if spec.loadingDelaySlotsDelayedInsert then
1376 spec.loadingDelaySlots[i].time = g_time
1377 else
1378 spec.loadingDelaySlots[i].time = g_time + (spec.unloadingDelay - spec.loadingDelay)
1379 end
1380
1381 spec.loadingDelaySlotsDelayedInsert = not spec.loadingDelaySlotsDelayedInsert
1382
1383 break
1384 end
1385 end
1386
1387 return deltaFillLevel
1388 end
1389
1390 local loadInfo = self:getFillVolumeLoadInfo(spec.loadInfoIndex)
1391 return self:addFillUnitFillLevel(self:getOwnerFarmId(), fillUnitIndex, deltaFillLevel, fillType, ToolType.UNDEFINED, loadInfo)
1392 end
1393
1394 return 0
1395end

addCutterToCombine

Description
Definition
addCutterToCombine()
Code
1210function Combine:addCutterToCombine(cutter)
1211 local spec = self.spec_combine
1212
1213 if spec.attachedCutters[cutter] == nil then
1214 spec.attachedCutters[cutter] = cutter
1215 spec.numAttachedCutters = spec.numAttachedCutters + 1
1216
1217 local ladder = self.spec_combine.ladder
1218 if ladder.unfoldWhileCutterAttached and ladder.animName ~= nil then
1219 if self:getAnimationTime(ladder.animName) < 1 then
1220 self:playAnimation(ladder.animName, ladder.animSpeedScale, self:getAnimationTime(ladder.animName), true)
1221 end
1222 end
1223 end
1224end

getAreControlledActionsAllowed

Description
Returns if controlled actions are allowed
Definition
getAreControlledActionsAllowed()
Return Values
booleanallowallow controlled actions
stringwarningnot allowed warning
Code
1594function Combine:getAreControlledActionsAllowed(superFunc)
1595 local spec = self.spec_combine
1596
1597 if spec.numAttachedCutters <= 0 then
1598 return false, spec.texts.warningNoCutter
1599 end
1600
1601 return superFunc(self)
1602end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
1624function Combine:getCanBeSelected(superFunc)
1625 return true
1626end

getCanBeTurnedOn

Description
Returns if turn on is allowed
Definition
getCanBeTurnedOn()
Return Values
booleanallowallow turn on
Code
1545function Combine:getCanBeTurnedOn(superFunc)
1546 local spec = self.spec_combine
1547
1548 if spec.numAttachedCutters <= 0 then
1549 return false
1550 end
1551
1552 for cutter, _ in pairs(spec.attachedCutters) do
1553 if cutter ~= self then
1554 if cutter.getCanBeTurnedOn ~= nil and not cutter:getCanBeTurnedOn() then
1555 return false
1556 end
1557 end
1558 end
1559
1560 return superFunc(self)
1561end

getCombineLastValidFillType

Description
Returns last valid fill type from fill unit or buffer unit
Definition
getCombineLastValidFillType()
Return Values
integerfillUnitIndexfill unit index
Code
1490function Combine:getCombineLastValidFillType()
1491 local spec = self.spec_combine
1492
1493 local fillType = FillType.UNKNOWN
1494 if spec.bufferFillUnitIndex ~= nil then
1495 fillType = self:getFillUnitLastValidFillType(spec.bufferFillUnitIndex)
1496 end
1497
1498 if fillType == FillType.UNKNOWN then
1499 fillType = self:getFillUnitLastValidFillType(spec.fillUnitIndex)
1500 end
1501
1502 if fillType == FillType.UNKNOWN then
1503 if spec.loadingDelay > 0 then
1504 for i=1, #spec.loadingDelaySlots do
1505 if spec.loadingDelaySlots[i].valid then
1506 fillType = spec.loadingDelaySlots[i].fillType
1507 break
1508 end
1509 end
1510 end
1511 end
1512
1513 if fillType == FillType.UNKNOWN then
1514 fillType = spec.lastValidInputFillType
1515 end
1516
1517 return fillType
1518end

getCombineLoadPercentage

Description
Definition
getCombineLoadPercentage()
Code
1522function Combine:getCombineLoadPercentage()
1523 local spec = self.spec_combine
1524 if spec ~= nil then
1525 if spec.numAttachedCutters > 0 then
1526 local loadSum = 0
1527 for cutter, _ in pairs(spec.attachedCutters) do
1528 if cutter.getCutterLoad ~= nil then
1529 loadSum = loadSum + cutter:getCutterLoad()
1530 end
1531 end
1532
1533 return loadSum / spec.numAttachedCutters
1534 end
1535 end
1536
1537 return 0
1538end

getDirtMultiplier

Description
Definition
getDirtMultiplier()
Code
1649function Combine:getDirtMultiplier(superFunc)
1650 local spec = self.spec_combine
1651
1652 for cutter, _ in pairs(spec.attachedCutters) do
1653 if cutter.spec_cutter ~= nil then
1654 if cutter.spec_cutter.isWorking then
1655 return superFunc(self) + self:getWorkDirtMultiplier() * self:getLastSpeed() / cutter.speedLimit
1656 end
1657 end
1658 end
1659
1660 return superFunc(self)
1661end

getFillLevelDependentSpeed

Description
Definition
getFillLevelDependentSpeed()
Code
1453function Combine:getFillLevelDependentSpeed()
1454 local spec = self.spec_combine
1455 if spec.rotationNodesSpeedReverseFillLevel ~= nil then
1456 local fillLevelPct = self:getFillUnitFillLevel(spec.fillUnitIndex) / self:getFillUnitCapacity(spec.fillUnitIndex)
1457 if fillLevelPct > spec.rotationNodesSpeedReverseFillLevel then
1458 return -1
1459 else
1460 return 1
1461 end
1462 else
1463 return 1
1464 end
1465end

getIsCutterCompatible

Description
Returns if given attributes are compatible with combine
Definition
getIsCutterCompatible(table fillTypes)
Arguments
tablefillTypesfill types
Return Values
booleanisCompatibleis compatible with combine
Code
1471function Combine:getIsCutterCompatible(fillTypes)
1472 local spec = self.spec_combine
1473 local supportedTypes = self:getFillUnitSupportedFillTypes(spec.fillUnitIndex)
1474
1475 for i=1, #fillTypes do
1476 local fillType = fillTypes[i]
1477 for supportedType, _ in pairs(supportedTypes) do
1478 if fillType == supportedType then
1479 return true
1480 end
1481 end
1482 end
1483
1484 return false
1485end

getIsFoldAllowed

Description
Returns if fold is allowed
Definition
getIsFoldAllowed()
Return Values
booleanallowsFoldallows folding
Code
1607function Combine:getIsFoldAllowed(superFunc, direction, onAiTurnOn)
1608 local spec = self.spec_combine
1609
1610 if not spec.allowFoldWhileThreshing and self:getIsTurnedOn() then
1611 return false, spec.texts.warningFoldingTurnedOn
1612 end
1613
1614 local fillLevel = self:getFillUnitFillLevel(spec.fillUnitIndex)
1615 if direction == spec.foldDirection and (fillLevel > spec.foldFillLevelThreshold and self:getFillUnitCapacity(spec.fillUnitIndex) ~= math.huge) then
1616 return false, spec.texts.warningFoldingWhileFilled
1617 end
1618
1619 return superFunc(self, direction, onAiTurnOn)
1620end

getIsThreshingDuringRain

Description
Returns if combine is currently threshing during rain
Definition
getIsThreshingDuringRain(boolean earlyWarning)
Arguments
booleanearlyWarningearly warning
Return Values
booleanisThreshingDuringRainis threshing during rain
Code
1401function Combine:getIsThreshingDuringRain(earlyWarning)
1402 local spec = self.spec_combine
1403
1404 if not spec.allowThreshingDuringRain then
1405 local rainScale = g_currentMission.environment.weather:getRainFallScale()
1406 local timeSinceLastRain = g_currentMission.environment.weather:getTimeSinceLastRain()
1407 if earlyWarning ~= nil and earlyWarning == true then
1408 if rainScale >= 0.02 and timeSinceLastRain < 20 then
1409 return true
1410 end
1411 else
1412 if rainScale >= 0.1 and timeSinceLastRain < 20 then
1413 return true
1414 end
1415 end
1416 end
1417
1418 return false
1419end

getIsTurnedOnAnimationActive

Description
Definition
getIsTurnedOnAnimationActive()
Code
1693function Combine:getIsTurnedOnAnimationActive(superFunc, turnedOnAnimation)
1694 local spec = self.spec_combine
1695 if (not turnedOnAnimation.activeChopper and not spec.isSwathActive)
1696 or (not turnedOnAnimation.activeStrawDrop and spec.isSwathActive) then
1697 return false
1698 end
1699
1700 if turnedOnAnimation.waitForStraw then
1701 return superFunc(self, turnedOnAnimation) or spec.workAreaParameters.isChopperEffectEnabled > 0
1702 end
1703
1704 return superFunc(self, turnedOnAnimation)
1705end

getTurnedOnNotAllowedWarning

Description
Returns turn on not allowed warning text
Definition
getTurnedOnNotAllowedWarning()
Return Values
stringwarningTextturn on not allowed warning text
Code
1566function Combine:getTurnedOnNotAllowedWarning(superFunc)
1567 if self:getIsActiveForInput(true) then
1568 local spec = self.spec_combine
1569 if not self:getCanBeTurnedOn() then
1570 if spec.numAttachedCutters == 0 then
1571 return spec.texts.warningNoCutter
1572 else
1573 for cutter, _ in pairs(spec.attachedCutters) do
1574 if cutter ~= self then
1575 if cutter.getTurnedOnNotAllowedWarning ~= nil then
1576 local warning = cutter:getTurnedOnNotAllowedWarning()
1577 if warning ~= nil then
1578 return warning
1579 end
1580 end
1581 end
1582 end
1583 end
1584 end
1585 end
1586
1587 return superFunc(self)
1588end

getWearMultiplier

Description
Definition
getWearMultiplier()
Code
1665function Combine:getWearMultiplier(superFunc)
1666 local spec = self.spec_combine
1667
1668 for cutter, _ in pairs(spec.attachedCutters) do
1669 if cutter.spec_cutter ~= nil then
1670 if cutter.spec_cutter.isWorking then
1671 local stoneMultiplier = cutter:getCutterStoneMultiplier()
1672 return superFunc(self) + self:getWorkWearMultiplier() * self:getLastSpeed() / cutter.speedLimit * stoneMultiplier
1673 end
1674 end
1675 end
1676
1677 return superFunc(self)
1678end

initSpecialization

Description
Definition
initSpecialization()
Code
19function Combine.initSpecialization()
20 g_workAreaTypeManager:addWorkAreaType("combineChopper", false)
21 g_workAreaTypeManager:addWorkAreaType("combineSwath", false)
22
23 local schema = Vehicle.xmlSchema
24 schema:setXMLSpecializationType("Combine")
25
26 schema:register(XMLValueType.L10N_STRING, "vehicle.combine.warning#noCutter", "No cutter warning", "$l10n_warning_noCuttersAttached")
27 schema:register(XMLValueType.FLOAT, "vehicle.combine#fillLevelBufferTime", "Fill level buffer time for forage harvesters", 2000)
28
29 schema:register(XMLValueType.BOOL, "vehicle.combine#allowThreshingDuringRain", "Allow threshing during rain", false)
30 schema:register(XMLValueType.INT, "vehicle.combine#fillUnitIndex", "Fill unit index", 1)
31 schema:register(XMLValueType.INT, "vehicle.combine.buffer#fillUnitIndex", "Buffer fill unit index (This fill unit will be filled first until it's full. Will be emptied if stopped to harvest)")
32 schema:register(XMLValueType.TIME, "vehicle.combine.buffer#unloadingTime", "Buffer unloading speed", 0)
33 schema:register(XMLValueType.INT, "vehicle.combine#loadInfoIndex", "Load info index", 1)
34
35 schema:register(XMLValueType.TIME, "vehicle.combine.buffer#loadingDelay", "Time until the crops from the cutter are added to the tank", 0)
36 schema:register(XMLValueType.TIME, "vehicle.combine.buffer#unloadingDelay", "Time until the crops are not longer added to the tank after the cutting has been stopped", "same as #loadingDelay")
37
38 schema:register(XMLValueType.BOOL, "vehicle.combine.swath#available", "Swath is available", false)
39 schema:register(XMLValueType.BOOL, "vehicle.combine.swath#isDefaultActive", "Swath is default active", "true if available")
40 schema:register(XMLValueType.INT, "vehicle.combine.swath#workAreaIndex", "Swath work area index")
41
42 schema:register(XMLValueType.BOOL, "vehicle.combine.chopper#available", "Chopper is available", false)
43 schema:register(XMLValueType.BOOL, "vehicle.combine.chopper#isPowered", "Vehicle needs to be powered to switch chopper", true)
44 schema:register(XMLValueType.INT, "vehicle.combine.chopper#workAreaIndex", "Chopper work area index")
45 schema:register(XMLValueType.STRING, "vehicle.combine.chopper#animName", "Chopper toggle animation name")
46 schema:register(XMLValueType.FLOAT, "vehicle.combine.chopper#animSpeedScale", "Chopper toggle animation speed", 1)
47
48 schema:register(XMLValueType.STRING, "vehicle.combine.ladder#animName", "Ladder animation name")
49 schema:register(XMLValueType.FLOAT, "vehicle.combine.ladder#animSpeedScale", "Ladder animation speed scale", 1)
50 schema:register(XMLValueType.FLOAT, "vehicle.combine.ladder#foldMinLimit", "Min. folding time to fold ladder", 0.99)
51 schema:register(XMLValueType.FLOAT, "vehicle.combine.ladder#foldMaxLimit", "Max. folding time to fold ladder", 1)
52 schema:register(XMLValueType.INT, "vehicle.combine.ladder#foldDirection", "Fold direction to unfold ladder", "signed animation speed")
53 schema:register(XMLValueType.BOOL, "vehicle.combine.ladder#unfoldWhileCutterAttached", "Unfold ladder while a cutter is attached", false)
54
55 schema:register(XMLValueType.TIME, "vehicle.combine#fillTimeThreshold", "After receiving no input for this threshold time we stop the fill effects", 0.5)
56
57 schema:register(XMLValueType.FLOAT, "vehicle.combine.processing#toggleTime", "Time from crop cutting to dropping straw", 0)
58
59 schema:register(XMLValueType.STRING, "vehicle.combine.threshingStartAnimation#name", "Threshing start animation")
60 schema:register(XMLValueType.FLOAT, "vehicle.combine.threshingStartAnimation#speedScale", "Threshing start animation speed scale")
61 schema:register(XMLValueType.BOOL, "vehicle.combine.threshingStartAnimation#initialIsStarted", "Threshing start animation is initial started")
62
63 schema:register(XMLValueType.INT, "vehicle.combine.additives#fillUnitIndex", "Additives fill unit index")
64 schema:register(XMLValueType.FLOAT, "vehicle.combine.additives#usage", "Usage per picked up liter", 2)
65 schema:register(XMLValueType.STRING, "vehicle.combine.additives#fillTypes", "Fill types to apply additives", "CHAFF GRASS_WINDROW")
66
67 schema:register(XMLValueType.NODE_INDEX, "vehicle.combine.automaticTilt.automaticTiltNode(?)#node", "Automatic tilt node")
68 schema:register(XMLValueType.ANGLE, "vehicle.combine.automaticTilt.automaticTiltNode(?)#minAngle", "Min. angle", -5)
69 schema:register(XMLValueType.ANGLE, "vehicle.combine.automaticTilt.automaticTiltNode(?)#maxAngle", "Max. angle", 5)
70 schema:register(XMLValueType.ANGLE, "vehicle.combine.automaticTilt.automaticTiltNode(?)#maxSpeed", "Max. angle change per second", 2)
71 schema:register(XMLValueType.BOOL, "vehicle.combine.automaticTilt.automaticTiltNode(?)#updateAttacherJoint", "Update cutter attacher joint")
72 schema:register(XMLValueType.STRING, "vehicle.combine.automaticTilt.automaticTiltNode(?)#dependentAnimation", "Animation that is updated depending on tilt state")
73
74 schema:register(XMLValueType.FLOAT, "vehicle.combine.folding#fillLevelThresholdPct", "Max. fill level to be folded (percetange between 0 and 1)", 0.15)
75 schema:register(XMLValueType.INT, "vehicle.combine.folding#direction", "Folding direction", 1)
76 schema:register(XMLValueType.BOOL, "vehicle.combine.folding#allowWhileThreshing", "Allow folding while combine is threshing", false)
77
78 EffectManager.registerEffectXMLPaths(schema, "vehicle.combine.chopperEffect")
79 EffectManager.registerEffectXMLPaths(schema, "vehicle.combine.strawEffect")
80 EffectManager.registerEffectXMLPaths(schema, "vehicle.combine.fillEffect")
81 EffectManager.registerEffectXMLPaths(schema, "vehicle.combine.effect")
82
83 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.combine.animationNodes")
84 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.combine.chopperAnimationNodes")
85 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.combine.strawDropAnimationNodes")
86 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.combine.fillingAnimationNodes")
87 schema:register(XMLValueType.FLOAT, "vehicle.combine.animationNodes#speedReverseFillLevel", "If fill level is above the animation nodes will be reversed (Percent 0-1)")
88
89 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "start")
90 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "stop")
91 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "work")
92
93 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "chopperStart")
94 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "chopperStop")
95 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "chopperWork")
96
97 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "chopStraw")
98 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "dropStraw")
99
100 SoundManager.registerSampleXMLPaths(schema, "vehicle.combine.sounds", "fill")
101
102 Dashboard.registerDashboardXMLPaths(schema, "vehicle.combine.dashboards", "workedHectars")
103
104 schema:register(XMLValueType.BOOL, TurnOnVehicle.TURNED_ON_ANIMATION_XML_PATH .. "#activeChopper", "Animation is active while chopper is active", true)
105 schema:register(XMLValueType.BOOL, TurnOnVehicle.TURNED_ON_ANIMATION_XML_PATH .. "#activeStrawDrop", "Animation is active while straw drop is active", true)
106 schema:register(XMLValueType.BOOL, TurnOnVehicle.TURNED_ON_ANIMATION_XML_PATH .. "#waitForStraw", "Animation is active as long as straw is dropped", true)
107
108 schema:setXMLSpecializationType()
109
110 local schemaSavegame = Vehicle.xmlSchemaSavegame
111 schemaSavegame:register(XMLValueType.BOOL, "vehicles.vehicle(?).combine#isSwathActive", "Swath is active")
112 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?).combine#workedHectars", "Worked hectars")
113 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).combine#numAttachedCutters", "Number of last attached cutters")
114end

loadCombineEffects

Description
Definition
loadCombineEffects()
Code
828function Combine:loadCombineEffects(xmlFile, baseKey, entry)
829 if self.isClient then
830 XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. ".chopperParticleSystems", baseKey..".chopperEffect") --FS17 to FS19
831 XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. ".strawParticleSystems", baseKey..".strawEffect") --FS17 to FS19
832 XMLUtil.checkDeprecatedXMLElements(xmlFile, baseKey .. ".threshingFillParticleSystems", baseKey..".fillEffect") --FS17 to FS19
833
834 entry.chopperEffects = g_effectManager:loadEffect(xmlFile, baseKey .. ".chopperEffect", self.components, self, self.i3dMappings)
835 entry.strawEffects = g_effectManager:loadEffect(xmlFile, baseKey .. ".strawEffect", self.components, self, self.i3dMappings)
836 entry.fillEffects = g_effectManager:loadEffect(xmlFile, baseKey .. ".fillEffect", self.components, self, self.i3dMappings)
837 entry.effects = g_effectManager:loadEffect(xmlFile, baseKey .. ".effect", self.components, self, self.i3dMappings)
838
839 entry.strawPSenabled = false
840 entry.chopperPSenabled = false
841 entry.isFilling = false
842
843 entry.fillEnableTime = nil
844 entry.fillDisableTime = nil
845
846 entry.lastEffectFillType = FillType.UNKNOWN
847 end
848end

loadCombineRotationNodes

Description
Definition
loadCombineRotationNodes()
Code
853function Combine:loadCombineRotationNodes(xmlFile, baseKey, entry)
854 if self.isClient then
855 entry.animationNodes = g_animationManager:loadAnimations(xmlFile, baseKey..".animationNodes", self.components, self, self.i3dMappings)
856 entry.chopperAnimationNodes = g_animationManager:loadAnimations(xmlFile, baseKey..".chopperAnimationNodes", self.components, self, self.i3dMappings)
857 entry.strawDropAnimationNodes = g_animationManager:loadAnimations(xmlFile, baseKey..".strawDropAnimationNodes", self.components, self, self.i3dMappings)
858 entry.fillingAnimationNodes = g_animationManager:loadAnimations(xmlFile, baseKey..".fillingAnimationNodes", self.components, self, self.i3dMappings)
859 entry.rotationNodesSpeedReverseFillLevel = xmlFile:getValue(baseKey .. ".animationNodes#speedReverseFillLevel")
860 end
861end

loadCombineSamples

Description
Definition
loadCombineSamples()
Code
866function Combine:loadCombineSamples(xmlFile, key, entry)
867 if self.isClient then
868 entry.samples = {}
869 entry.samples.start = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "start", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
870 entry.samples.stop = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "stop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
871 entry.samples.work = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
872
873 entry.samples.chopperStart = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "chopperStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
874 entry.samples.chopperStop = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "chopperStop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
875 entry.samples.chopperWork = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "chopperWork", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
876
877 entry.samples.chopStraw = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "chopStraw", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
878 entry.samples.dropStraw = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "dropStraw", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
879
880 entry.samples.fill = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "fill", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
881 end
882end

loadCombineSetup

Description
Definition
loadCombineSetup()
Code
699function Combine:loadCombineSetup(xmlFile, baseKey, entry)
700 entry.allowThreshingDuringRain = xmlFile:getValue(baseKey .. "#allowThreshingDuringRain", false)
701
702 entry.fillUnitIndex = xmlFile:getValue(baseKey .. "#fillUnitIndex", 1)
703 entry.bufferFillUnitIndex = xmlFile:getValue(baseKey .. ".buffer#fillUnitIndex")
704 entry.bufferUnloadingTime = xmlFile:getValue(baseKey .. ".buffer#unloadingTime", 0)
705 entry.loadInfoIndex = xmlFile:getValue(baseKey .. "#loadInfoIndex", 1)
706
707 entry.loadingDelay = xmlFile:getValue(baseKey .. ".buffer#loadingDelay", 0)
708 if entry.loadingDelay > 0 then
709 entry.unloadingDelay = xmlFile:getValue(baseKey .. ".buffer#unloadingDelay", entry.loadingDelay / 1000)
710 entry.loadingDelaySlotsDelayedInsert = false
711
712 entry.loadingDelaySlots = {}
713 for i=1, entry.loadingDelay / 1000 * 60 + 1 do -- max if we fill at 60FPS every frame
714 entry.loadingDelaySlots[i] = {time=-math.huge, fillLevelDelta=0, fillType=0, valid=false}
715 end
716 end
717
718 -- swath
719 entry.swath = {}
720 entry.swath.isAvailable = xmlFile:getValue(baseKey .. ".swath#available", false)
721 local isDefaultActive = xmlFile:getValue(baseKey .. ".swath#isDefaultActive", entry.swath.isAvailable)
722 if entry.swath.isAvailable then
723 entry.swath.workAreaIndex = xmlFile:getValue(baseKey .. ".swath#workAreaIndex")
724 if entry.swath.workAreaIndex == nil then
725 entry.swath.isAvailable = false
726 Logging.xmlWarning(xmlFile, "Missing 'swath#workAreaIndex' for combine swath function!")
727 end
728 entry.warningTime = 0
729 end
730
731 -- chopper
732 entry.chopper = {}
733 entry.chopper.isAvailable = xmlFile:getValue(baseKey .. ".chopper#available", false)
734 entry.chopper.isPowered = xmlFile:getValue(baseKey .. ".chopper#isPowered", true)
735 if entry.chopper.isAvailable then
736 entry.chopper.workAreaIndex = xmlFile:getValue(baseKey .. ".chopper#workAreaIndex")
737 if entry.chopper.workAreaIndex == nil then
738 entry.chopper.isAvailable = false
739 Logging.xmlWarning(xmlFile, "Missing 'chopper#workAreaIndex' for combine chopper function!")
740 end
741
742 entry.chopper.animName = xmlFile:getValue(baseKey .. ".chopper#animName")
743 entry.chopper.animSpeedScale = xmlFile:getValue(baseKey .. ".chopper#animSpeedScale", 1)
744 end
745
746 entry.automatedChopperSwitch = GS_IS_MOBILE_VERSION
747
748 entry.isSwathActive = isDefaultActive
749
750 --ladder
751 entry.ladder = {}
752 entry.ladder.animName = xmlFile:getValue(baseKey .. ".ladder#animName")
753 entry.ladder.animSpeedScale = xmlFile:getValue(baseKey .. ".ladder#animSpeedScale", 1)
754 entry.ladder.foldMinLimit = xmlFile:getValue(baseKey .. ".ladder#foldMinLimit", 0.99)
755 entry.ladder.foldMaxLimit = xmlFile:getValue(baseKey .. ".ladder#foldMaxLimit", 1)
756 entry.ladder.foldDirection = xmlFile:getValue(baseKey .. ".ladder#foldDirection", MathUtil.sign(entry.ladder.animSpeedScale))
757 entry.ladder.unfoldWhileCutterAttached = xmlFile:getValue(baseKey .. ".ladder#unfoldWhileCutterAttached", false)
758
759 entry.fillTimeThreshold = xmlFile:getValue(baseKey .. "#fillTimeThreshold", 0.5)
760
761 -- processing buffer
762 entry.processing = {}
763 local toggleTime = xmlFile:getValue(baseKey .. ".processing#toggleTime")
764 if toggleTime == nil and entry.chopper.animName ~= nil then
765 toggleTime = self:getAnimationDurection(entry.chopper.animName)
766 if toggleTime ~= nil then
767 toggleTime = toggleTime / 1000
768 end
769 end
770 entry.processing.toggleTime = Utils.getNoNil(toggleTime, 0) * 1000
771
772 local inputBuffer = {}
773 local slotDuration = 300
774 local slotCount = MathUtil.clamp(math.ceil(entry.processing.toggleTime / slotDuration), 2, 20)
775 inputBuffer.slotCount = slotCount
776 inputBuffer.slotDuration = math.ceil( entry.processing.toggleTime / inputBuffer.slotCount )
777 inputBuffer.fillIndex = 1
778 inputBuffer.dropIndex = inputBuffer.fillIndex + 1
779 inputBuffer.slotTimer = inputBuffer.slotDuration
780 inputBuffer.activeTimeout = inputBuffer.slotDuration * (inputBuffer.slotCount + 2)
781 inputBuffer.activeTimer = inputBuffer.activeTimeout
782 inputBuffer.buffer = {}
783 for _=1, inputBuffer.slotCount do
784 table.insert(inputBuffer.buffer, {realArea = 0, area = 0, liters = 0, inputLiters = 0, strawRatio = 0, effectDensity = 0.2} )
785 end
786 entry.processing.inputBuffer = inputBuffer
787
788 -- threhsing start animation
789 entry.threshingStartAnimation = xmlFile:getValue(baseKey .. ".threshingStartAnimation#name")
790 entry.threshingStartAnimationSpeedScale = xmlFile:getValue(baseKey .. ".threshingStartAnimation#speedScale", 1)
791 entry.threshingStartAnimationInitialIsStarted = xmlFile:getValue(baseKey .. ".threshingStartAnimation#initialIsStarted", false)
792
793 entry.foldFillLevelThreshold = xmlFile:getValue(baseKey .. ".folding#fillLevelThresholdPct", 0.15) * (self:getFillUnitCapacity(entry.fillUnitIndex) or 0.04)
794 entry.foldDirection = xmlFile:getValue(baseKey .. ".folding#direction", 1)
795 entry.allowFoldWhileThreshing = xmlFile:getValue(baseKey .. ".folding#allowWhileThreshing", false)
796
797 entry.additives = {}
798 entry.additives.fillUnitIndex = xmlFile:getValue(baseKey .. ".additives#fillUnitIndex")
799 entry.additives.available = self:getFillUnitByIndex(entry.additives.fillUnitIndex) ~= nil
800 entry.additives.usage = xmlFile:getValue(baseKey .. ".additives#usage", 0.0)
801 local additivesFillTypeNames = xmlFile:getValue(baseKey .. ".additives#fillTypes", "CHAFF GRASS_WINDROW")
802 entry.additives.fillTypes = g_fillTypeManager:getFillTypesByNames(additivesFillTypeNames, "Warning: '"..xmlFile:getFilename().. "' has invalid fillType '%s'.")
803
804 -- automatic tilt
805 entry.automaticTilt = {}
806 entry.automaticTilt.nodes = {}
807 xmlFile:iterate(baseKey .. ".automaticTilt.automaticTiltNode", function(index, key)
808 local automaticTiltNode = {}
809 automaticTiltNode.node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
810 if automaticTiltNode.node ~= nil then
811 automaticTiltNode.minAngle = xmlFile:getValue(key .. "#minAngle", -5)
812 automaticTiltNode.maxAngle = xmlFile:getValue(key .. "#maxAngle", 5)
813
814 automaticTiltNode.maxSpeed = xmlFile:getValue(key .. "#maxSpeed", 2) / 1000
815 automaticTiltNode.updateAttacherJoint = xmlFile:getValue(key .. "#updateAttacherJoint")
816 automaticTiltNode.dependentAnimation = xmlFile:getValue(key .. "#dependentAnimation")
817 automaticTiltNode.lastJointUpdateRot = 0
818
819 table.insert(entry.automaticTilt.nodes, automaticTiltNode)
820 end
821 end)
822
823 entry.automaticTilt.hasNodes = #entry.automaticTilt.nodes > 0
824end

loadTurnedOnAnimationFromXML

Description
Definition
loadTurnedOnAnimationFromXML()
Code
1682function Combine:loadTurnedOnAnimationFromXML(superFunc, xmlFile, key, turnedOnAnimation)
1683 turnedOnAnimation.activeChopper = xmlFile:getValue(key.."#activeChopper", true)
1684 turnedOnAnimation.activeStrawDrop = xmlFile:getValue(key.."#activeStrawDrop", true)
1685 turnedOnAnimation.waitForStraw = xmlFile:getValue(key.."#waitForStraw", false)
1686
1687 return superFunc(self, xmlFile, key, turnedOnAnimation)
1688end

loadWorkAreaFromXML

Description
Definition
loadWorkAreaFromXML()
Code
1630function Combine:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
1631 if not superFunc(self, workArea, xmlFile, key) then
1632 return false
1633 end
1634
1635 if workArea.type == WorkAreaType.COMBINECHOPPER or workArea.type == WorkAreaType.COMBINESWATH then
1636 if xmlFile:getValue(key .. "#requiresOwnedFarmland") == nil then
1637 workArea.requiresOwnedFarmland = false
1638 end
1639 if xmlFile:getValue(key .. "#needsSetIsTurnedOn") == nil then
1640 workArea.needsSetIsTurnedOn = false
1641 end
1642 end
1643
1644 return true
1645end

onChangedFillType

Description
Definition
onChangedFillType()
Code
1764function Combine:onChangedFillType(fillUnitIndex, fillTypeIndex)
1765 local spec = self.spec_combine
1766 if spec.bufferFillUnitIndex ~= nil and fillUnitIndex == spec.bufferFillUnitIndex or fillUnitIndex == spec.fillUnitIndex then
1767 if fillTypeIndex ~= FillType.UNKNOWN then
1768 if fillTypeIndex ~= spec.lastEffectFillType then
1769 if spec.chopperPSenabled then
1770 self:setChopperPSEnabled(true, true, 0, true)
1771 end
1772 if spec.strawPSenabled then
1773 self:setStrawPSEnabled(true, true, 0, true)
1774 end
1775 if spec.isFilling then
1776 self:setCombineIsFilling(true, true, true)
1777 end
1778 end
1779
1780 spec.lastEffectFillType = fillTypeIndex
1781 end
1782 end
1783end

onDeactivate

Description
Called on deactivate
Definition
onDeactivate()
Code
1787function Combine:onDeactivate()
1788 local spec = self.spec_combine
1789
1790 self:setChopperPSEnabled(false, false, 0, true)
1791 self:setStrawPSEnabled(false, false, 0, true)
1792 self:setCombineIsFilling(false, false, true)
1793 spec.fillEnableTime = nil
1794 spec.fillDisableTime = nil
1795end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
337function Combine:onDelete()
338 local spec = self.spec_combine
339
340 g_effectManager:deleteEffects(spec.effects)
341 g_effectManager:deleteEffects(spec.fillEffects)
342 g_effectManager:deleteEffects(spec.strawEffects)
343 g_effectManager:deleteEffects(spec.chopperEffects)
344
345 g_animationManager:deleteAnimations(spec.animationNodes)
346 g_animationManager:deleteAnimations(spec.chopperAnimationNodes)
347 g_animationManager:deleteAnimations(spec.strawDropAnimationNodes)
348 g_animationManager:deleteAnimations(spec.fillingAnimationNodes)
349
350 g_soundManager:deleteSamples(spec.samples)
351end

onDraw

Description
Called on draw
Definition
onDraw(boolean isActiveForInput, boolean isSelected)
Arguments
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
685function Combine:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
686 local spec = self.spec_combine
687 if self:getIsTurnedOn() and self:getIsThreshingDuringRain(false) then
688 if not spec.threshingDuringRainWarningDisplayed then
689 g_currentMission:showBlinkingWarning(spec.texts.warningRainReducesYield, 4000)
690 spec.threshingDuringRainWarningDisplayed = true
691 end
692 else
693 spec.threshingDuringRainWarningDisplayed = false
694 end
695end

onEndWorkAreaProcessing

Description
Definition
onEndWorkAreaProcessing()
Code
1756function Combine:onEndWorkAreaProcessing(dt, hasProcessed)
1757 local spec = self.spec_combine
1758 local inputBuffer = spec.processing.inputBuffer
1759 inputBuffer.buffer[inputBuffer.dropIndex].liters = math.max(0, inputBuffer.buffer[inputBuffer.dropIndex].liters - spec.workAreaParameters.droppedLiters)
1760end

onEnterVehicle

Description
Definition
onEnterVehicle()
Code
1870function Combine:onEnterVehicle()
1871 local ladder = self.spec_combine.ladder
1872 if ladder.animName ~= nil then
1873 local fold = true
1874 if self.getFoldAnimTime ~= nil then
1875 local foldAnimTime = self:getFoldAnimTime()
1876 if foldAnimTime > ladder.foldMaxLimit or foldAnimTime < ladder.foldMinLimit then
1877 fold = false
1878 end
1879 end
1880
1881 if ladder.unfoldWhileCutterAttached then
1882 if self.spec_combine.numAttachedCutters > 0 then
1883 fold = false
1884 end
1885 end
1886
1887 if fold then
1888 self:playAnimation(ladder.animName, -ladder.animSpeedScale, self:getAnimationTime(ladder.animName), true)
1889 end
1890 end
1891end

onFillUnitFillLevelChanged

Description
Definition
onFillUnitFillLevelChanged()
Code
1938function Combine:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillTypeIndex, toolType, fillPositionData, appliedDelta)
1939 local spec = self.spec_combine
1940
1941 if fillUnitIndex == spec.fillUnitIndex then
1942 if fillLevelDelta < 0 then
1943 spec.lastDischargeTime = g_time
1944 end
1945 end
1946end

onFoldStateChanged

Description
Definition
onFoldStateChanged()
Code
1920function Combine:onFoldStateChanged(direction, moveToMiddle)
1921 local ladder = self.spec_combine.ladder
1922 if ladder.animName ~= nil and direction ~= 0 and not moveToMiddle then
1923 local fold = true
1924 if ladder.unfoldWhileCutterAttached then
1925 if self.spec_combine.numAttachedCutters > 0 then
1926 fold = false
1927 end
1928 end
1929
1930 if fold then
1931 self:playAnimation(ladder.animName, direction*ladder.animSpeedScale*ladder.foldDirection, self:getAnimationTime(ladder.animName), true)
1932 end
1933 end
1934end

onLeaveVehicle

Description
Definition
onLeaveVehicle()
Code
1895function Combine:onLeaveVehicle()
1896 local ladder = self.spec_combine.ladder
1897 if ladder.animName ~= nil then
1898 local fold = true
1899 if self.getFoldAnimTime ~= nil then
1900 local foldAnimTime = self:getFoldAnimTime()
1901 if foldAnimTime > ladder.foldMaxLimit or foldAnimTime < ladder.foldMinLimit then
1902 fold = false
1903 end
1904 end
1905
1906 if ladder.unfoldWhileCutterAttached then
1907 if self.spec_combine.numAttachedCutters > 0 then
1908 fold = false
1909 end
1910 end
1911
1912 if fold then
1913 self:playAnimation(ladder.animName, ladder.animSpeedScale, self:getAnimationTime(ladder.animName), true)
1914 end
1915 end
1916end

onLoad

Description
Definition
onLoad()
Code
205function Combine:onLoad(savegame)
206 local spec = self.spec_combine
207
208 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.combine.chopperSwitch", "vehicle.combine.swath and vehicle.combine.chopper") --FS17 to FS19
209 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.turnedOnRotationNodes.turnedOnRotationNode#type", "vehicle.combine.rotationNodes.rotationNode", "combine") --FS17 to FS19
210 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.indoorHud.workedHectars", "vehicle.combine.dashboards.dashboard with valueType 'workedHectars'") --FS17 to FS19
211
212 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.combine.folding#fillLevelThreshold", "vehicle.combine.folding#fillLevelThresholdPct") --FS19 to FS22
213
214 self:loadCombineSetup(self.xmlFile, "vehicle.combine", spec)
215 self:loadCombineEffects(self.xmlFile, "vehicle.combine", spec)
216 self:loadCombineRotationNodes(self.xmlFile, "vehicle.combine", spec)
217 self:loadCombineSamples(self.xmlFile, "vehicle.combine", spec)
218
219 spec.attachedCutters = {}
220 spec.numAttachedCutters = 0
221
222 spec.texts = {}
223 spec.texts.warningFoldingTurnedOn = g_i18n:getText("warning_foldingNotWhileTurnedOn")
224 spec.texts.warningFoldingWhileFilled = g_i18n:getText("warning_foldingNotWhileFilled")
225 spec.texts.warningRainReducesYield = g_i18n:getText("warning_rainReducesYield")
226 spec.texts.warningNoCutter = self.xmlFile:getValue("vehicle.combine.warning#noCutter", g_i18n:getText("warning_noCuttersAttached"), self.customEnvironment)
227
228 spec.threshingDuringRainWarningDisplayed = false
229
230 spec.lastArea = 0
231 spec.lastAreaZeroTime = 0
232 spec.lastAreaNonZeroTime = -1000000
233 spec.lastCuttersArea = 0
234 spec.lastCuttersAreaTime = -10000
235 spec.lastInputFruitType = FruitType.UNKNOWN
236 spec.lastValidInputFruitType = FruitType.UNKNOWN
237 spec.lastCuttersFruitType = FruitType.UNKNOWN
238 spec.lastCuttersInputFruitType = FruitType.UNKNOWN
239 spec.lastValidInputFillType = FillType.UNKNOWN
240 spec.lastDischargeTime = 0
241 spec.lastChargeTime = 0
242 spec.fillLevelBufferTime = self.xmlFile:getValue("vehicle.combine#fillLevelBufferTime", 2000) -- time the fill level buffer is filled without unloading
243
244 spec.workedHectars = 0
245 spec.workedHectarsSent = 0
246 if self.loadDashboardsFromXML ~= nil then
247 local dashboardData = {valueTypeToLoad = "workedHectars",
248 valueObject = spec,
249 valueFunc = "workedHectars"}
250
251 self:loadDashboardsFromXML(self.xmlFile, "vehicle.combine.dashboards", dashboardData)
252 end
253
254 spec.threshingScale = 1
255 spec.lastLostFillLevel = 0
256
257 spec.workAreaParameters = {}
258 spec.workAreaParameters.lastRealArea = 0
259 spec.workAreaParameters.lastArea = 0
260 spec.workAreaParameters.litersToDrop = 0
261 spec.workAreaParameters.droppedLiters = 0
262 spec.workAreaParameters.isChopperEffectEnabled = 0
263 spec.workAreaParameters.isStrawEffectEnabled = 0
264 spec.workAreaParameters.effectDensity = 0.2
265 spec.workAreaParameters.effectDensitySent = 0.2
266
267 spec.dirtyFlag = self:getNextDirtyFlag()
268 spec.effectDirtyFlag = self:getNextDirtyFlag()
269end

onPostAttachImplement

Description
Called on attaching a implement
Definition
onPostAttachImplement(table implement)
Arguments
tableimplementimplement to attach
Code
1800function Combine:onPostAttachImplement(attachable, inputJointDescIndex, jointDescIndex)
1801 local attacherJoint = attachable:getActiveInputAttacherJoint()
1802 if attacherJoint ~= nil then
1803 if attacherJoint.jointType == AttacherJoints.JOINTTYPE_CUTTER or attacherJoint.jointType == AttacherJoints.JOINTTYPE_CUTTERHARVESTER then
1804 self:addCutterToCombine(attachable)
1805 end
1806 end
1807end

onPostDetachImplement

Description
Called on detaching a implement
Definition
onPostDetachImplement(integer implementIndex)
Arguments
integerimplementIndexindex of implement to detach
Code
1812function Combine:onPostDetachImplement(implementIndex)
1813 local object = self:getObjectFromImplementIndex(implementIndex)
1814 if object ~= nil then
1815 local attacherJoint = object:getActiveInputAttacherJoint()
1816 if attacherJoint ~= nil then
1817 if attacherJoint.jointType == AttacherJoints.JOINTTYPE_CUTTER or attacherJoint.jointType == AttacherJoints.JOINTTYPE_CUTTERHARVESTER then
1818 self:removeCutterFromCombine(object)
1819 end
1820 end
1821 end
1822end

onPostLoad

Description
Called after loading
Definition
onPostLoad(table savegame)
Arguments
tablesavegamesavegame
Code
274function Combine:onPostLoad(savegame)
275 local spec = self.spec_combine
276
277 if savegame ~= nil then
278 if spec.swath.isAvailable then
279 local isSwathActive = savegame.xmlFile:getValue(savegame.key .. ".combine#isSwathActive", spec.isSwathActive)
280 self:setIsSwathActive(isSwathActive, true, true)
281 end
282 self:setWorkedHectars(savegame.xmlFile:getValue(savegame.key .. ".combine#workedHectars", spec.workedHectars))
283 else
284 self:setIsSwathActive(spec.isSwathActive, true, true)
285 end
286
287 spec.isBufferCombine = self:getFillUnitCapacity(self.spec_combine.fillUnitIndex) == math.huge
288 if spec.isBufferCombine then
289 local fillUnit = self:getFillUnitByIndex(self.spec_combine.fillUnitIndex)
290 if fillUnit.showOnInfoHud then
291 Logging.xmlWarning(self.xmlFile, "Buffer combine fill unit is displayed in info hud! Add showOnInfoHud='false' to the fill unit.")
292 end
293 end
294
295 local ladder = spec.ladder
296 if ladder.animName ~= nil then
297 local time = 0
298 if self.getFoldAnimTime ~= nil then
299 local foldAnimTime = self:getFoldAnimTime()
300 if foldAnimTime > ladder.foldMaxLimit or foldAnimTime < ladder.foldMinLimit then
301 time = 1
302 end
303 end
304
305 if ladder.unfoldWhileCutterAttached then
306 if savegame ~= nil and not savegame.resetVehicles then
307 local numAttachedCutters = savegame.xmlFile:getValue(savegame.key .. ".combine#numAttachedCutters", 0)
308 if numAttachedCutters > 0 then
309 time = 1
310 end
311 end
312 end
313
314 if ladder.foldDirection ~= 1 then
315 time = 1 - time
316 end
317
318 self:setAnimationTime(ladder.animName, time, true)
319 end
320
321 if spec.bufferFillUnitIndex ~= nil then
322 local fillUnit = self:getFillUnitByIndex(spec.fillUnitIndex)
323 local bufferUnit = self:getFillUnitByIndex(spec.bufferFillUnitIndex)
324 if fillUnit ~= nil and bufferUnit ~= nil then
325 bufferUnit.parentUnitOnHud = spec.fillUnitIndex
326 fillUnit.childUnitOnHud = spec.bufferFillUnitIndex
327 end
328 end
329
330 if self:getFillUnitCapacity(spec.fillUnitIndex) == 0 then
331 Logging.xmlWarning(self.xmlFile, "Capacity of fill unit '%d' for combine needs to be set greater 0 or not defined! (not defined = infinity)", spec.fillUnitIndex)
332 end
333end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
370function Combine:onReadStream(streamId, connection)
371 local spec = self.spec_combine
372
373 spec.lastValidInputFruitType = streamReadUIntN(streamId, FruitTypeManager.SEND_NUM_BITS)
374 local combineIsFilling = streamReadBool(streamId)
375 local chopperPSenabled = streamReadBool(streamId)
376 local strawPSenabled = streamReadBool(streamId)
377 spec.lastValidInputFillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
378
379 self:setCombineIsFilling(combineIsFilling, false, true)
380 self:setChopperPSEnabled(chopperPSenabled, false, 1, true)
381 self:setStrawPSEnabled(strawPSenabled, false, 1, true)
382
383 local isSwathActive = streamReadBool(streamId)
384 self:setIsSwathActive(isSwathActive, true)
385
386 local workedHectars = streamReadFloat32(streamId)
387 self:setWorkedHectars(workedHectars)
388end

onReadUpdateStream

Description
Called on on update
Definition
onReadUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
412function Combine:onReadUpdateStream(streamId, timestamp, connection)
413 if connection:getIsServer() then
414 local spec = self.spec_combine
415 if streamReadBool(streamId) then
416 spec.lastValidInputFruitType = streamReadUIntN(streamId, FruitTypeManager.SEND_NUM_BITS)
417
418 local workedHectars = streamReadFloat32(streamId)
419 self:setWorkedHectars(workedHectars)
420 end
421
422 if streamReadBool(streamId) then
423 local combineIsFilling = streamReadBool(streamId)
424 local chopperPSenabled = streamReadBool(streamId)
425 local strawPSenabled = streamReadBool(streamId)
426 local effectDensity = streamReadUIntN(streamId, 5)
427 effectDensity = effectDensity / (2^5 - 1)
428
429 spec.lastValidInputFillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
430
431 self:setCombineIsFilling(combineIsFilling, false, true)
432 self:setChopperPSEnabled(chopperPSenabled, false, effectDensity, true)
433 self:setStrawPSEnabled(strawPSenabled, false, effectDensity, true)
434 end
435 end
436end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
1709function Combine:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
1710 if self.isClient then
1711
1712 local spec = self.spec_combine
1713 self:clearActionEventsTable(spec.actionEvents)
1714
1715 if isActiveForInputIgnoreSelection and spec.swath.isAvailable and spec.chopper.isAvailable then
1716 local func = self.addActionEvent
1717 if spec.chopper.isPowered then
1718 func = self.addPoweredActionEvent
1719 end
1720
1721 local _, actionEventId = func(self, spec.actionEvents, InputAction.TOGGLE_CHOPPER, self, Combine.actionEventToggleChopper, false, true, false, true, nil)
1722 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
1723 Combine.updateToggleStrawText(self)
1724 end
1725 end
1726end

onStartWorkAreaProcessing

Description
Definition
onStartWorkAreaProcessing()
Code
1730function Combine:onStartWorkAreaProcessing(dt)
1731 local spec = self.spec_combine
1732
1733 spec.workAreaParameters.droppedLiters = 0
1734 spec.workAreaParameters.litersToDrop = 0
1735 spec.workAreaParameters.strawRatio = 0
1736 spec.workAreaParameters.dropFillType = FillType.UNKNOWN
1737
1738 local fillUnitIndex = spec.bufferFillUnitIndex or spec.fillUnitIndex
1739 local lastValidFillType = self:getFillUnitLastValidFillType(fillUnitIndex)
1740 if lastValidFillType ~= FillType.UNKNOWN then
1741 local inputBuffer = spec.processing.inputBuffer
1742 local inputLiters = inputBuffer.buffer[inputBuffer.dropIndex].inputLiters
1743 spec.workAreaParameters.litersToDrop = math.min(inputBuffer.buffer[inputBuffer.dropIndex].liters, (dt / inputBuffer.slotDuration) * inputLiters)
1744 spec.workAreaParameters.strawRatio = inputBuffer.buffer[inputBuffer.dropIndex].strawRatio
1745 spec.workAreaParameters.strawGroundType = inputBuffer.buffer[inputBuffer.dropIndex].strawGroundType
1746 spec.workAreaParameters.effectDensity = inputBuffer.buffer[inputBuffer.dropIndex].effectDensity
1747 spec.workAreaParameters.dropFillType = lastValidFillType
1748 end
1749
1750 spec.workAreaParameters.lastRealArea = 0
1751 spec.workAreaParameters.lastArea = 0
1752end

onTurnedOff

Description
Called on turn off
Definition
onTurnedOff(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
1851function Combine:onTurnedOff()
1852 self:stopThreshing()
1853 if self.isClient then
1854 local spec = self.spec_combine
1855 g_animationManager:stopAnimations(spec.animationNodes)
1856 g_animationManager:stopAnimations(spec.chopperAnimationNodes)
1857 g_animationManager:stopAnimations(spec.strawDropAnimationNodes)
1858
1859 g_effectManager:stopEffects(spec.effects)
1860
1861 if g_soundManager:getIsSamplePlaying(spec.samples.chopperWork) then
1862 g_soundManager:stopSample(spec.samples.chopperWork)
1863 g_soundManager:playSample(spec.samples.chopperStop)
1864 end
1865 end
1866end

onTurnedOn

Description
Called on turn on
Definition
onTurnedOn(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
1827function Combine:onTurnedOn()
1828 self:startThreshing()
1829 if self.isClient then
1830 local spec = self.spec_combine
1831 g_animationManager:startAnimations(spec.animationNodes)
1832
1833 if spec.isSwathActive then
1834 g_animationManager:startAnimations(spec.strawDropAnimationNodes)
1835 else
1836 g_animationManager:startAnimations(spec.chopperAnimationNodes)
1837
1838 g_soundManager:stopSample(spec.samples.chopperStop)
1839 g_soundManager:playSample(spec.samples.chopperStart)
1840 g_soundManager:playSample(spec.samples.chopperWork, 0, spec.samples.chopperStart)
1841 end
1842
1843 g_effectManager:setFillType(spec.effects, self:getCombineLastValidFillType())
1844 g_effectManager:startEffects(spec.effects)
1845 end
1846end

onUpdate

Description
Called on update
Definition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
469function Combine:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
470 local spec = self.spec_combine
471
472 local isTurnedOn = self:getIsTurnedOn()
473 if isTurnedOn then
474 if self.isServer and spec.swath.isAvailable then
475 -- check for changes while threshing, e.g. activated straw swath and then start threshing canola (has no windrow)
476 local fillUnitIndex = spec.bufferFillUnitIndex or spec.fillUnitIndex
477 local fruitType = g_fruitTypeManager:getFruitTypeIndexByFillTypeIndex(self:getFillUnitFillType(fillUnitIndex))
478 if spec.isSwathActive and fruitType ~= nil and fruitType ~= FruitType.UNKNOWN then
479 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitType)
480 if not fruitDesc.hasWindrow then
481 self:setIsSwathActive(false)
482 end
483 else
484 -- if the combine does not support chopper but it was forced by the last fill type
485 -- if the new fill type supports swath again we change it back
486 if not spec.chopper.isAvailable or spec.automatedChopperSwitch then
487 if not spec.isSwathActive and fruitType ~= nil and fruitType ~= FruitType.UNKNOWN then
488 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitType)
489 if fruitDesc.hasWindrow then
490 self:setIsSwathActive(true)
491
492 -- empty input buffer to prevent dropping of wrong fill type windrow
493 local inputBuffer = spec.processing.inputBuffer
494 for i=1, #inputBuffer.buffer do
495 inputBuffer.buffer[i].area = 0
496 inputBuffer.buffer[i].realArea = 0
497 inputBuffer.buffer[i].liters = 0
498 inputBuffer.buffer[i].inputLiters = 0
499 end
500 end
501 end
502 end
503 end
504 end
505 end
506
507 if self.isServer then
508 if self:getFillUnitFillLevel(spec.fillUnitIndex) < 0.0001 then
509 spec.lastDischargeTime = g_time
510 end
511 end
512
513 if spec.automaticTilt.hasNodes then
514 local currentDelta, isActive, doReset = 0, false, false
515
516 local _, cutter = next(spec.attachedCutters)
517 if cutter ~= nil and cutter:getCutterTiltIsAvailable() then
518 currentDelta, isActive, doReset = cutter:getCutterTiltDelta()
519 end
520
521 for i=1, #spec.automaticTilt.nodes do
522 local automaticTiltNode = spec.automaticTilt.nodes[i]
523
524 local _, _, curZ = getRotation(automaticTiltNode.node)
525 if not isActive and doReset then
526 currentDelta = -curZ -- return to idle if not active
527 end
528
529 if math.abs(currentDelta) > 0.00001 then
530 local speedScale = math.min(math.pow(math.abs(currentDelta) / 0.01745, 2), 1) * MathUtil.sign(currentDelta)
531 if not isActive and doReset then
532 speedScale = speedScale * 0.5
533 end
534
535 local rotSpeed = speedScale * automaticTiltNode.maxSpeed * dt
536 local newRotZ = MathUtil.clamp(curZ + rotSpeed, automaticTiltNode.minAngle, automaticTiltNode.maxAngle)
537 setRotation(automaticTiltNode.node, 0, 0, newRotZ)
538
539 if automaticTiltNode.dependentAnimation ~= nil then
540 local alpha = MathUtil.inverseLerp(automaticTiltNode.minAngle, automaticTiltNode.maxAngle, newRotZ)
541 self:setAnimationTime(automaticTiltNode.dependentAnimation, alpha, true)
542 end
543
544 if cutter ~= nil and automaticTiltNode.updateAttacherJoint and math.abs(newRotZ-automaticTiltNode.lastJointUpdateRot) > 0.00001 then
545 automaticTiltNode.lastJointUpdateRot = newRotZ
546 local jointDesc = self:getAttacherJointDescFromObject(cutter)
547 if jointDesc.jointIndex ~= 0 then
548 setJointFrame(jointDesc.jointIndex, 0, jointDesc.jointTransform)
549 end
550 end
551
552 if self.setMovingToolDirty ~= nil then
553 self:setMovingToolDirty(automaticTiltNode.node)
554 end
555 end
556 end
557 end
558end

onUpdateTick

Description
Called on update tick
Definition
onUpdateTick(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
565function Combine:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
566 local spec = self.spec_combine
567
568 if self.isServer then
569 spec.lastArea = spec.lastCuttersArea
570 spec.lastAreaZeroTime = spec.lastAreaZeroTime + dt
571 if spec.lastArea > 0 then
572 spec.lastAreaZeroTime = 0
573 spec.lastAreaNonZeroTime = g_currentMission.time
574 end
575 spec.lastInputFruitType = spec.lastCuttersInputFruitType
576 spec.lastCuttersArea = 0
577 spec.lastCuttersInputFruitType = FruitType.UNKNOWN
578 spec.lastCuttersFruitType = FruitType.UNKNOWN
579
580 if spec.lastInputFruitType ~= FruitType.UNKNOWN then
581 spec.lastValidInputFruitType = spec.lastInputFruitType
582 end
583
584 local inputBuffer = spec.processing.inputBuffer
585
586 if spec.lastAreaZeroTime > spec.fillTimeThreshold then
587 if spec.fillDisableTime == nil then
588 spec.fillDisableTime = g_currentMission.time + spec.processing.toggleTime
589 end
590 end
591 if spec.fillEnableTime ~= nil and spec.fillEnableTime <= g_currentMission.time then
592 self:setCombineIsFilling(true, false, false)
593 spec.fillEnableTime = nil
594 end
595 if spec.fillDisableTime ~= nil and spec.fillDisableTime <= g_currentMission.time then
596 self:setCombineIsFilling(false, false, false)
597 spec.fillDisableTime = nil
598 end
599
600 spec.workAreaParameters.isChopperEffectEnabled = math.max(spec.workAreaParameters.isChopperEffectEnabled - dt, 0)
601 spec.workAreaParameters.isStrawEffectEnabled = math.max(spec.workAreaParameters.isStrawEffectEnabled - dt, 0)
602
603 local density = spec.workAreaParameters.effectDensity
604 local chopperPSActive = spec.workAreaParameters.isChopperEffectEnabled > 0
605 local strawPSActive = spec.workAreaParameters.isStrawEffectEnabled > 0
606 self:setChopperPSEnabled(chopperPSActive, false, density, false)
607 self:setStrawPSEnabled(strawPSActive, false, density, false)
608
609 if chopperPSActive or strawPSActive then
610 self:raiseActive()
611 end
612
613 if self:getIsTurnedOn() then
614 local stats = g_currentMission:farmStats(self:getOwnerFarmId())
615 stats:updateStats("threshedTime", dt / (1000 * 60))
616
617 self:updateLastWorkedArea(0) -- mark as working
618 end
619
620 inputBuffer.slotTimer = inputBuffer.slotTimer - dt
621 if inputBuffer.slotTimer < 0 then
622 inputBuffer.slotTimer = inputBuffer.slotDuration
623
624 inputBuffer.fillIndex = inputBuffer.fillIndex + 1
625 if inputBuffer.fillIndex > inputBuffer.slotCount then
626 inputBuffer.fillIndex = 1
627 end
628
629 local lastDropIndex = inputBuffer.dropIndex
630 inputBuffer.dropIndex = inputBuffer.dropIndex + 1
631 if inputBuffer.dropIndex > inputBuffer.slotCount then
632 inputBuffer.dropIndex = 1
633 end
634
635 inputBuffer.buffer[inputBuffer.dropIndex].liters = inputBuffer.buffer[inputBuffer.dropIndex].liters + inputBuffer.buffer[lastDropIndex].liters
636 inputBuffer.buffer[inputBuffer.dropIndex].inputLiters = inputBuffer.buffer[inputBuffer.dropIndex].inputLiters + inputBuffer.buffer[lastDropIndex].liters --inputLiters
637
638 inputBuffer.buffer[lastDropIndex].area = 0
639 inputBuffer.buffer[lastDropIndex].realArea = 0
640 inputBuffer.buffer[lastDropIndex].liters = 0
641 inputBuffer.buffer[lastDropIndex].inputLiters = 0
642 end
643
644 if spec.bufferFillUnitIndex ~= nil then
645 if spec.lastCuttersAreaTime + dt * 10 < g_currentMission.time then
646 if self:getFillUnitFillLevel(spec.bufferFillUnitIndex) > 0 then
647 local deltaFillLevel = dt * (self:getFillUnitCapacity(spec.bufferFillUnitIndex) / spec.bufferUnloadingTime)
648 deltaFillLevel = self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.bufferFillUnitIndex, -deltaFillLevel, self:getFillUnitFillType(spec.bufferFillUnitIndex), ToolType.UNDEFINED)
649
650 self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.fillUnitIndex, -deltaFillLevel, self:getFillUnitFillType(spec.bufferFillUnitIndex), ToolType.UNDEFINED, self:getFillVolumeLoadInfo(spec.loadInfoIndex))
651 end
652 end
653 end
654
655 if spec.loadingDelay > 0 then
656 for i=1, #spec.loadingDelaySlots do
657 local slot = spec.loadingDelaySlots[i]
658 if slot.valid then
659 if slot.time + spec.loadingDelay < g_time then
660 slot.valid = false
661 self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.fillUnitIndex, slot.fillLevelDelta, slot.fillType, ToolType.UNDEFINED, self:getFillVolumeLoadInfo(spec.loadInfoIndex))
662 end
663 end
664 end
665 end
666
667 if spec.isFilling ~= spec.sentIsFilling
668 or spec.chopperPSenabled ~= spec.sentChopperPSenabled
669 or spec.strawPSenabled ~= spec.sentStrawPSenabled
670 or math.abs(spec.workAreaParameters.effectDensity - spec.workAreaParameters.effectDensitySent) > 0.05 then
671 self:raiseDirtyFlags(spec.effectDirtyFlag)
672
673 spec.sentIsFilling = spec.isFilling
674 spec.sentChopperPSenabled = spec.chopperPSenabled
675 spec.sentStrawPSenabled = spec.strawPSenabled
676 spec.workAreaParameters.effectDensitySent = spec.workAreaParameters.effectDensity
677 end
678 end
679end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
394function Combine:onWriteStream(streamId, connection)
395 local spec = self.spec_combine
396
397 streamWriteUIntN(streamId, spec.lastValidInputFruitType, FruitTypeManager.SEND_NUM_BITS)
398 streamWriteBool(streamId, spec.isFilling)
399 streamWriteBool(streamId, spec.chopperPSenabled)
400 streamWriteBool(streamId, spec.strawPSenabled)
401 streamWriteUIntN(streamId, self:getCombineLastValidFillType(), FillTypeManager.SEND_NUM_BITS)
402
403 streamWriteBool(streamId, spec.isSwathActive)
404 streamWriteFloat32(streamId, spec.workedHectars)
405end

onWriteUpdateStream

Description
Called on on update
Definition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
443function Combine:onWriteUpdateStream(streamId, connection, dirtyMask)
444 if not connection:getIsServer() then
445 local spec = self.spec_combine
446
447 if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then
448 streamWriteUIntN(streamId, spec.lastValidInputFruitType, FruitTypeManager.SEND_NUM_BITS)
449 streamWriteFloat32(streamId, spec.workedHectars)
450 end
451
452 if streamWriteBool(streamId, bitAND(dirtyMask, spec.effectDirtyFlag) ~= 0) then
453 streamWriteBool(streamId, spec.isFilling)
454 streamWriteBool(streamId, spec.chopperPSenabled)
455 streamWriteBool(streamId, spec.strawPSenabled)
456
457 streamWriteUIntN(streamId, spec.workAreaParameters.effectDensity * (2^5 - 1), 5)
458
459 streamWriteUIntN(streamId, self:getCombineLastValidFillType(), FillTypeManager.SEND_NUM_BITS)
460 end
461 end
462end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
118function Combine.prerequisitesPresent(specializations)
119 return SpecializationUtil.hasSpecialization(WorkArea, specializations) and
120 SpecializationUtil.hasSpecialization(FillUnit, specializations) and
121 (SpecializationUtil.hasSpecialization(Drivable, specializations) or SpecializationUtil.hasSpecialization(Attachable, specializations)) and
122 SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations) and
123 SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations)
124end

processCombineChopperArea

Description
Definition
processCombineChopperArea()
Code
942function Combine:processCombineChopperArea(workArea)
943 local spec = self.spec_combine
944
945 if not spec.isSwathActive then
946 local litersToDrop = spec.workAreaParameters.litersToDrop
947 local strawRatio = spec.workAreaParameters.strawRatio
948 local strawGroundType = spec.workAreaParameters.strawGroundType
949 spec.workAreaParameters.droppedLiters = litersToDrop
950
951 if litersToDrop > 0 and strawRatio > 0 then
952 if Platform.gameplay.useSprayDiffuseMaps and strawRatio > 0.5 and strawGroundType ~= nil then
953 local xs,_,zs = getWorldTranslation(workArea.start)
954 local xw,_,zw = getWorldTranslation(workArea.width)
955 local xh,_,zh = getWorldTranslation(workArea.height)
956
957 FSDensityMapUtil.setGroundTypeLayerArea(xs, zs, xw, zw, xh, zh, strawGroundType)
958 end
959
960 -- raise active until litersToDrop is 0
961 self:raiseActive()
962 spec.workAreaParameters.isChopperEffectEnabled = 500
963 end
964 end
965
966 return spec.workAreaParameters.lastRealArea, spec.workAreaParameters.lastArea
967end

processCombineSwathArea

Description
Definition
processCombineSwathArea()
Code
971function Combine:processCombineSwathArea(workArea)
972 local spec = self.spec_combine
973 local litersToDrop = spec.workAreaParameters.litersToDrop
974
975 if spec.isSwathActive then
976 if litersToDrop > 0 then
977 local droppedLiters = 0
978 local fruitDesc = g_fruitTypeManager:getFruitTypeByFillTypeIndex(spec.workAreaParameters.dropFillType)
979 if fruitDesc ~= nil and fruitDesc.windrowLiterPerSqm ~= nil then
980 local windrowFillType = g_fruitTypeManager:getWindrowFillTypeIndexByFruitTypeIndex(fruitDesc.index)
981 if windrowFillType ~= nil then
982 local sx,sy,sz,ex,ey,ez = DensityMapHeightUtil.getLineByArea(workArea.start, workArea.width, workArea.height, true)
983 local dropped, lineOffset = DensityMapHeightUtil.tipToGroundAroundLine(self, litersToDrop, windrowFillType, sx, sy, sz, ex, ey, ez, 0, nil, workArea.lineOffset, false, nil, false)
984 droppedLiters = dropped
985 workArea.lineOffset = lineOffset
986 end
987 end
988 if droppedLiters > 0 then
989 spec.workAreaParameters.isStrawEffectEnabled = 500
990 end
991 spec.workAreaParameters.droppedLiters = droppedLiters
992 end
993 end
994
995 return spec.workAreaParameters.lastRealArea, spec.workAreaParameters.lastArea
996end

registerEventListeners

Description
Definition
registerEventListeners()
Code
177function Combine.registerEventListeners(vehicleType)
178 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Combine)
179 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Combine)
180 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Combine)
181 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Combine)
182 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Combine)
183 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Combine)
184 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Combine)
185 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Combine)
186 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Combine)
187 SpecializationUtil.registerEventListener(vehicleType, "onDraw", Combine)
188 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Combine)
189 SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Combine)
190 SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Combine)
191 SpecializationUtil.registerEventListener(vehicleType, "onChangedFillType", Combine)
192 SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", Combine)
193 SpecializationUtil.registerEventListener(vehicleType, "onPostAttachImplement", Combine)
194 SpecializationUtil.registerEventListener(vehicleType, "onPostDetachImplement", Combine)
195 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", Combine)
196 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", Combine)
197 SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", Combine)
198 SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", Combine)
199 SpecializationUtil.registerEventListener(vehicleType, "onFoldStateChanged", Combine)
200 SpecializationUtil.registerEventListener(vehicleType, "onFillUnitFillLevelChanged", Combine)
201end

registerEvents

Description
Definition
registerEvents()
Code
128function Combine.registerEvents(vehicleType)
129 SpecializationUtil.registerEvent(vehicleType, "onStartThreshing")
130 SpecializationUtil.registerEvent(vehicleType, "onStopThreshing")
131end

registerFunctions

Description
Definition
registerFunctions()
Code
135function Combine.registerFunctions(vehicleType)
136 SpecializationUtil.registerFunction(vehicleType, "loadCombineSetup", Combine.loadCombineSetup)
137 SpecializationUtil.registerFunction(vehicleType, "loadCombineEffects", Combine.loadCombineEffects)
138 SpecializationUtil.registerFunction(vehicleType, "loadCombineRotationNodes", Combine.loadCombineRotationNodes)
139 SpecializationUtil.registerFunction(vehicleType, "loadCombineSamples", Combine.loadCombineSamples)
140 SpecializationUtil.registerFunction(vehicleType, "setIsSwathActive", Combine.setIsSwathActive)
141 SpecializationUtil.registerFunction(vehicleType, "processCombineChopperArea", Combine.processCombineChopperArea)
142 SpecializationUtil.registerFunction(vehicleType, "processCombineSwathArea", Combine.processCombineSwathArea)
143 SpecializationUtil.registerFunction(vehicleType, "setChopperPSEnabled", Combine.setChopperPSEnabled)
144 SpecializationUtil.registerFunction(vehicleType, "setStrawPSEnabled", Combine.setStrawPSEnabled)
145 SpecializationUtil.registerFunction(vehicleType, "setCombineIsFilling", Combine.setCombineIsFilling)
146 SpecializationUtil.registerFunction(vehicleType, "startThreshing", Combine.startThreshing)
147 SpecializationUtil.registerFunction(vehicleType, "stopThreshing", Combine.stopThreshing)
148 SpecializationUtil.registerFunction(vehicleType, "setWorkedHectars", Combine.setWorkedHectars)
149 SpecializationUtil.registerFunction(vehicleType, "addCutterToCombine", Combine.addCutterToCombine)
150 SpecializationUtil.registerFunction(vehicleType, "removeCutterFromCombine", Combine.removeCutterFromCombine)
151 SpecializationUtil.registerFunction(vehicleType, "addCutterArea", Combine.addCutterArea)
152 SpecializationUtil.registerFunction(vehicleType, "getIsThreshingDuringRain", Combine.getIsThreshingDuringRain)
153 SpecializationUtil.registerFunction(vehicleType, "verifyCombine", Combine.verifyCombine)
154 SpecializationUtil.registerFunction(vehicleType, "getFillLevelDependentSpeed", Combine.getFillLevelDependentSpeed)
155 SpecializationUtil.registerFunction(vehicleType, "getCombineLastValidFillType", Combine.getCombineLastValidFillType)
156 SpecializationUtil.registerFunction(vehicleType, "getCombineLoadPercentage", Combine.getCombineLoadPercentage)
157 SpecializationUtil.registerFunction(vehicleType, "getIsCutterCompatible", Combine.getIsCutterCompatible)
158end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
162function Combine.registerOverwrittenFunctions(vehicleType)
163 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", Combine.getCanBeTurnedOn)
164 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getTurnedOnNotAllowedWarning", Combine.getTurnedOnNotAllowedWarning)
165 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAreControlledActionsAllowed", Combine.getAreControlledActionsAllowed)
166 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", Combine.getIsFoldAllowed)
167 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", Combine.getCanBeSelected)
168 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", Combine.loadWorkAreaFromXML)
169 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", Combine.getDirtMultiplier)
170 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Combine.getWearMultiplier)
171 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadTurnedOnAnimationFromXML", Combine.loadTurnedOnAnimationFromXML)
172 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsTurnedOnAnimationActive", Combine.getIsTurnedOnAnimationActive)
173end

removeCutterFromCombine

Description
Definition
removeCutterFromCombine()
Code
1228function Combine:removeCutterFromCombine(cutter)
1229 local spec = self.spec_combine
1230
1231 if spec.attachedCutters[cutter] ~= nil then
1232 spec.numAttachedCutters = spec.numAttachedCutters - 1
1233 if spec.numAttachedCutters == 0 then
1234 self:setIsTurnedOn(false, true)
1235 -- if its a buffered combine -> clear the "invisible" tank on cutter detach
1236 if spec.isBufferCombine then
1237 local currentFillType = self:getFillUnitFillType(spec.fillUnitIndex)
1238 if currentFillType ~= FillType.UNKNOWN then
1239 self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.fillUnitIndex, -math.huge, currentFillType, ToolType.UNDEFINED, nil)
1240 end
1241 end
1242 end
1243 spec.attachedCutters[cutter] = nil
1244
1245 local ladder = self.spec_combine.ladder
1246 if ladder.unfoldWhileCutterAttached and ladder.animName ~= nil then
1247 local fold = true
1248 if self.getFoldAnimTime ~= nil then
1249 local foldAnimTime = self:getFoldAnimTime()
1250 if foldAnimTime > ladder.foldMaxLimit or foldAnimTime < ladder.foldMinLimit then
1251 fold = false
1252 end
1253 end
1254
1255 if fold then
1256 self:playAnimation(ladder.animName, -ladder.animSpeedScale, self:getAnimationTime(ladder.animName), true)
1257 end
1258 end
1259 end
1260end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
355function Combine:saveToXMLFile(xmlFile, key, usedModNames)
356 local spec = self.spec_combine
357
358 if spec.swath.isAvailable then
359 xmlFile:setValue(key.."#isSwathActive", spec.isSwathActive)
360 end
361
362 xmlFile:setValue(key.."#workedHectars", spec.workedHectars)
363 xmlFile:setValue(key.."#numAttachedCutters", spec.numAttachedCutters)
364end

setChopperPSEnabled

Description
Set chopper PS enabled
Definition
setChopperPSEnabled(boolean chopperPSenabled, boolean fruitTypeChanged, float density, boolean isSynchronized)
Arguments
booleanchopperPSenabledset enabled
booleanfruitTypeChangedfruit type has changed
floatdensitydensity
booleanisSynchronizedfilling is synchronized
Code
1004function Combine:setChopperPSEnabled(chopperPSenabled, fruitTypeChanged, density, isSynchronized)
1005 local spec = self.spec_combine
1006
1007 if spec.chopperPSenabled ~= chopperPSenabled or fruitTypeChanged then
1008 spec.chopperPSenabled = chopperPSenabled
1009 if self.isServer and isSynchronized then
1010 spec.sentChopperPSenabled = chopperPSenabled
1011 end
1012
1013 if self.isClient then
1014 if not chopperPSenabled or fruitTypeChanged then
1015 g_effectManager:stopEffects(spec.chopperEffects)
1016 end
1017
1018 if chopperPSenabled then
1019 g_effectManager:setFillType(spec.chopperEffects, self:getCombineLastValidFillType())
1020 g_effectManager:startEffects(spec.chopperEffects)
1021
1022 if not g_soundManager:getIsSamplePlaying(spec.samples.chopStraw) then
1023 g_soundManager:playSample(spec.samples.chopStraw)
1024 end
1025 else
1026 if g_soundManager:getIsSamplePlaying(spec.samples.chopStraw) then
1027 g_soundManager:stopSample(spec.samples.chopStraw)
1028 end
1029 end
1030 end
1031 end
1032
1033 if spec.chopperPSenabled and density ~= nil then
1034 g_effectManager:setDensity(spec.chopperEffects, density)
1035 end
1036end

setCombineIsFilling

Description
Set combine is filling
Definition
setCombineIsFilling(boolean isFilling, boolean fruitTypeChanged, boolean isSynchronized)
Arguments
booleanisFillingcombine is filling
booleanfruitTypeChangedfruit type has changed
booleanisSynchronizedfilling is synchronized
Code
1086function Combine:setCombineIsFilling(isFilling, fruitTypeChanged, isSynchronized)
1087 local spec = self.spec_combine
1088
1089 if spec.isFilling ~= isFilling or fruitTypeChanged then
1090 spec.isFilling = isFilling
1091
1092 if self.isServer and isSynchronized then
1093 spec.sentIsFilling = isFilling
1094 end
1095
1096 if self.isClient then
1097 if isFilling then
1098 g_animationManager:startAnimations(spec.fillingAnimationNodes)
1099 else
1100 g_animationManager:stopAnimations(spec.fillingAnimationNodes)
1101 end
1102 g_animationManager:setFillType(spec.fillingAnimationNodes, self:getCombineLastValidFillType())
1103
1104 g_effectManager:setFillType(spec.effects, self:getCombineLastValidFillType(spec.fillUnitIndex))
1105
1106 if not isFilling or fruitTypeChanged then
1107 g_effectManager:stopEffects(spec.fillEffects)
1108 end
1109
1110 if isFilling then
1111 g_effectManager:setFillType(spec.fillEffects, self:getCombineLastValidFillType())
1112 g_effectManager:startEffects(spec.fillEffects)
1113 end
1114
1115 if isFilling then
1116 if not g_soundManager:getIsSamplePlaying(spec.samples.fill) then
1117 g_soundManager:playSample(spec.samples.fill)
1118 end
1119 else
1120 if g_soundManager:getIsSamplePlaying(spec.samples.fill) then
1121 g_soundManager:stopSample(spec.samples.fill)
1122 end
1123 end
1124 end
1125 end
1126end

setIsSwathActive

Description
Set is straw enabled
Definition
setIsSwathActive(boolean isSwathActive, boolean noEventSend, boolean force)
Arguments
booleanisSwathActivenew state
booleannoEventSendno event send
booleanforceforce action
Code
889function Combine:setIsSwathActive(isSwathActive, noEventSend, force)
890 local spec = self.spec_combine
891
892 if isSwathActive ~= spec.isSwathActive or force then
893 CombineStrawEnableEvent.sendEvent(self, isSwathActive, noEventSend)
894 spec.isSwathActive = isSwathActive
895
896 local anim = spec.chopper.animName
897 if self.playAnimation ~= nil and anim ~= nil then
898 local dir = 1
899 if isSwathActive then
900 dir = -1
901 end
902 self:playAnimation(anim, dir * spec.chopper.animSpeedScale, self:getAnimationTime(anim), true)
903
904 if force then
905 AnimatedVehicle.updateAnimationByName(self, anim, 9999999, true)
906 end
907 end
908
909 -- reset buffer drop slots (may still be some liters that could not be dropped to swath, but then can be chopped)
910 local inputBuffer = spec.processing.inputBuffer
911 for i=1, #inputBuffer.buffer do
912 inputBuffer.buffer[i].liters = 0
913 end
914
915 if self:getIsTurnedOn() then
916 if self.isClient then
917 if spec.isSwathActive then
918 g_animationManager:stopAnimations(spec.chopperAnimationNodes)
919 g_animationManager:startAnimations(spec.strawDropAnimationNodes)
920
921 if g_soundManager:getIsSamplePlaying(spec.samples.chopperWork) then
922 g_soundManager:stopSample(spec.samples.chopperWork)
923 g_soundManager:playSample(spec.samples.chopperStop)
924 end
925 else
926 g_animationManager:stopAnimations(spec.strawDropAnimationNodes)
927 g_animationManager:startAnimations(spec.chopperAnimationNodes)
928
929 g_soundManager:stopSample(spec.samples.chopperStop)
930 g_soundManager:playSample(spec.samples.chopperStart)
931 g_soundManager:playSample(spec.samples.chopperWork, 0, spec.samples.chopperStart)
932 end
933 end
934 end
935
936 Combine.updateToggleStrawText(self)
937 end
938end

setStrawPSEnabled

Description
Set straw PS enabled
Definition
setStrawPSEnabled(boolean strawPSenabled, boolean fruitTypeChanged, float density, boolean isSynchronized)
Arguments
booleanstrawPSenabledset enabled
booleanfruitTypeChangedfruit type has changed
floatdensitydensity
booleanisSynchronizedfilling is synchronized
Code
1044function Combine:setStrawPSEnabled(strawPSenabled, fruitTypeChanged, density, isSynchronized)
1045 local spec = self.spec_combine
1046
1047 if spec.strawPSenabled ~= strawPSenabled or fruitTypeChanged then
1048 spec.strawPSenabled = strawPSenabled
1049 if self.isServer and isSynchronized then
1050 spec.sentStrawPSenabled = strawPSenabled
1051 end
1052 if not strawPSenabled then
1053 spec.strawToDrop = 0
1054 end
1055
1056 if self.isClient then
1057 if not strawPSenabled or fruitTypeChanged then
1058 g_effectManager:stopEffects(spec.strawEffects)
1059 end
1060
1061 if strawPSenabled then
1062 g_effectManager:setFillType(spec.strawEffects, self:getCombineLastValidFillType())
1063 g_effectManager:startEffects(spec.strawEffects)
1064
1065 if not g_soundManager:getIsSamplePlaying(spec.samples.dropStraw) then
1066 g_soundManager:playSample(spec.samples.dropStraw)
1067 end
1068 else
1069 if g_soundManager:getIsSamplePlaying(spec.samples.dropStraw) then
1070 g_soundManager:stopSample(spec.samples.dropStraw)
1071 end
1072 end
1073 end
1074 end
1075
1076 if spec.strawPSenabled and density ~= nil then
1077 g_effectManager:setDensity(spec.strawEffects, density)
1078 end
1079end

setWorkedHectars

Description
Set worked hectars value and updated hud
Definition
setWorkedHectars(float hectars)
Arguments
floathectarsnew hectars value
Code
1195function Combine:setWorkedHectars(hectars)
1196 local spec = self.spec_combine
1197
1198 spec.workedHectars = hectars
1199
1200 if self.isServer then
1201 if math.abs(spec.workedHectars-spec.workedHectarsSent) > 0.01 then
1202 self:raiseDirtyFlags(spec.dirtyFlag)
1203 spec.workedHectarsSent = spec.workedHectars
1204 end
1205 end
1206end

startThreshing

Description
Start threshing
Definition
startThreshing()
Code
1130function Combine:startThreshing()
1131 local spec = self.spec_combine
1132
1133 if spec.numAttachedCutters > 0 then
1134 -- do not lower the cutter if the combine is turned on during headland (happens if ai was blocked during headland)
1135 local allowLowering = not self:getIsAIActive() or not self.rootVehicle:getAIFieldWorkerIsTurning()
1136
1137 for _,cutter in pairs(spec.attachedCutters) do
1138 if allowLowering then
1139 if cutter ~= self then
1140 local jointDescIndex = self:getAttacherJointIndexFromObject(cutter)
1141 self:setJointMoveDown(jointDescIndex, true, true)
1142 end
1143 end
1144
1145 cutter:setIsTurnedOn(true, true)
1146 end
1147
1148 if spec.threshingStartAnimation ~= nil and self.playAnimation ~= nil then
1149 self:playAnimation(spec.threshingStartAnimation, spec.threshingStartAnimationSpeedScale, self:getAnimationTime(spec.threshingStartAnimation), true)
1150 end
1151
1152 if self.isClient then
1153 g_soundManager:stopSample(spec.samples.stop)
1154 g_soundManager:stopSample(spec.samples.work)
1155 g_soundManager:playSample(spec.samples.start)
1156 g_soundManager:playSample(spec.samples.work, 0, spec.samples.start)
1157 end
1158
1159 SpecializationUtil.raiseEvent(self, "onStartThreshing")
1160 end
1161end

stopThreshing

Description
Stop threshing
Definition
stopThreshing()
Code
1165function Combine:stopThreshing()
1166 local spec = self.spec_combine
1167
1168 if self.isClient then
1169 g_soundManager:stopSample(spec.samples.start)
1170 g_soundManager:stopSample(spec.samples.work)
1171 g_soundManager:playSample(spec.samples.stop)
1172 end
1173
1174 self:setCombineIsFilling(false, false, true)
1175
1176 for cutter,_ in pairs(spec.attachedCutters) do
1177 if cutter ~= self then
1178 local jointDescIndex = self:getAttacherJointIndexFromObject(cutter)
1179 self:setJointMoveDown(jointDescIndex, false, true)
1180 end
1181
1182 cutter:setIsTurnedOn(false, true)
1183 end
1184
1185 if spec.threshingStartAnimation ~= nil and spec.playAnimation ~= nil then
1186 self:playAnimation(spec.threshingStartAnimation, -spec.threshingStartAnimationSpeedScale, self:getAnimationTime(spec.threshingStartAnimation), true)
1187 end
1188
1189 SpecializationUtil.raiseEvent(self, "onStopThreshing")
1190end

updateToggleStrawText

Description
Definition
updateToggleStrawText()
Code
1971function Combine.updateToggleStrawText(self)
1972 local spec = self.spec_combine
1973 local actionEvent = spec.actionEvents[InputAction.TOGGLE_CHOPPER]
1974 if actionEvent ~= nil and actionEvent.actionEventId ~= nil then
1975 local text
1976 if spec.isSwathActive then
1977 text = g_i18n:getText("action_disableStrawSwath")
1978 else
1979 text = g_i18n:getText("action_enableStrawSwath")
1980 end
1981
1982 g_inputBinding:setActionEventText(actionEvent.actionEventId, text)
1983 end
1984end

verifyCombine

Description
Definition
verifyCombine()
Code
1423function Combine:verifyCombine(fruitType, outputFillType)
1424 local spec = self.spec_combine
1425 local fillUnitIndex = spec.bufferFillUnitIndex or spec.fillUnitIndex
1426 -- buffer combine can never be over the limit since the capacity is math.huge
1427 if self:getFillUnitFillLevelPercentage(fillUnitIndex) > self:getFillTypeChangeThreshold() or spec.isBufferCombine then
1428 local currentFillType = self:getFillUnitFillType(fillUnitIndex)
1429 if currentFillType ~= FillType.UNKNOWN and fruitType ~= FruitType.UNKNOWN and currentFillType ~= outputFillType then
1430 -- if we are a combine harvester without a "real" fill unit we empty the buffer if a new fill type comes from the cutter
1431 if spec.isBufferCombine then
1432 self:addFillUnitFillLevel(self:getOwnerFarmId(), fillUnitIndex, -math.huge, currentFillType, ToolType.UNDEFINED, nil)
1433 return self
1434 end
1435
1436 return nil, self, currentFillType
1437 end
1438 end
1439
1440 local maxFreeCapacity = 0
1441 if spec.bufferFillUnitIndex ~= nil then
1442 maxFreeCapacity = self:getFillUnitFillLevel(spec.bufferFillUnitIndex)
1443 end
1444 if self:getFillUnitFreeCapacity(spec.fillUnitIndex) <= maxFreeCapacity then
1445 return nil
1446 end
1447
1448 return self
1449end