Script v1.7.1.0
- AI
- Animals
- Contracts
- Debug
- Economy
- Effects
- Events
- Farms
- GUI
- Handtools
- I3d
- Materials
- Misc
- Objects
- Placeables
- Player
- Shop
- Sounds
- Specializations
- Triggers
- Utils
- Vehicles
- Weather
Engine v1.7.1.0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- XML
- general
Foundation Reference
Cutter
DescriptionSpecialization for cutters providing cutter effects; requires WorkArea specializationFunctions
- doCheckSpeedLimit
- getAllowCutterAIFruitRequirements
- getCombine
- getCutterLoad
- getDefaultSpeedLimit
- getDirtMultiplier
- getIsRandomlyMovingPartActive
- getIsSpeedRotatingPartActive
- getIsTestAreaActive
- getIsWorkAreaActive
- getWearMultiplier
- initSpecialization
- loadRandomlyMovingPartFromXML
- loadSpeedRotatingPartFromXML
- loadTestAreaFromXML
- loadWorkAreaFromXML
- onAIImplementStart
- onDelete
- onEndWorkAreaProcessing
- onLoad
- onPostDetach
- onPostLoad
- onPreAttach
- onReadStream
- onReadUpdateStream
- onStartWorkAreaProcessing
- onTurnedOff
- onTurnedOn
- onUpdateTick
- onWriteStream
- onWriteUpdateStream
- prerequisitesPresent
- processCutterArea
- processPickupCutterArea
- readTestAreasStream
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- updateDebugValues
- updateExtraObjects
- writeTestAreasStream
doCheckSpeedLimit
DescriptionDefinitiondoCheckSpeedLimit()Code
882 | function Cutter:doCheckSpeedLimit(superFunc) |
883 | return superFunc(self) or (self:getIsTurnedOn() and (self.getIsLowered == nil or self:getIsLowered())) |
884 | end |
getAllowCutterAIFruitRequirements
DescriptionDefinitiongetAllowCutterAIFruitRequirements()Code
533 | function Cutter:getAllowCutterAIFruitRequirements() |
534 | return true |
535 | end |
getCombine
DescriptionDefinitiongetCombine()Code
507 | function Cutter:getCombine() |
508 | local spec = self.spec_cutter |
509 | |
510 | local outputFillType = g_fruitTypeManager:getFillTypeIndexByFruitTypeIndex(spec.currentInputFruitType) |
511 | if spec.fruitTypeConverters[spec.currentInputFruitType] ~= nil then |
512 | outputFillType = spec.fruitTypeConverters[spec.currentInputFruitType].fillTypeIndex |
513 | end |
514 | |
515 | if self.verifyCombine ~= nil then |
516 | return self:verifyCombine(spec.currentInputFruitType, outputFillType) |
517 | else |
518 | if self.getAttacherVehicle ~= nil then |
519 | local attacherVehicle = self:getAttacherVehicle() |
520 | if attacherVehicle ~= nil then |
521 | if attacherVehicle.verifyCombine ~= nil then |
522 | return attacherVehicle:verifyCombine(spec.currentInputFruitType, outputFillType) |
523 | end |
524 | end |
525 | end |
526 | end |
527 | |
528 | return nil |
529 | end |
getCutterLoad
DescriptionDefinitiongetCutterLoad()Code
819 | function Cutter:getCutterLoad() |
820 | return self.spec_cutter.cutterLoad |
821 | end |
getDefaultSpeedLimit
DescriptionDefinitiongetDefaultSpeedLimit()Code
1023 | function Cutter.getDefaultSpeedLimit() |
1024 | return 10 |
1025 | end |
getDirtMultiplier
DescriptionDefinitiongetDirtMultiplier()Code
898 | function Cutter:getDirtMultiplier(superFunc) |
899 | local spec = self.spec_cutter |
900 | |
901 | if spec.isWorking then |
902 | return superFunc(self) + self:getWorkDirtMultiplier() * self:getLastSpeed() / self.speedLimit |
903 | end |
904 | |
905 | return superFunc(self) |
906 | end |
getIsRandomlyMovingPartActive
DescriptionDefinitiongetIsRandomlyMovingPartActive()Code
857 | function Cutter:getIsRandomlyMovingPartActive(superFunc, part) |
858 | local retValue = superFunc(self, part) |
859 | |
860 | if part.moveOnlyIfCutted then |
861 | retValue = retValue and (self.spec_cutter.lastAreaBiggerZeroTime >= (g_currentMission.time - 150)) |
862 | end |
863 | |
864 | return retValue |
865 | end |
getIsSpeedRotatingPartActive
DescriptionDefinitiongetIsSpeedRotatingPartActive()Code
836 | function Cutter:getIsSpeedRotatingPartActive(superFunc, speedRotatingPart) |
837 | local spec = self.spec_cutter |
838 | if (not spec.allowCuttingWhileRaised and not self:getIsLowered(true)) or (speedRotatingPart.rotateIfTurnedOn and not self:getIsTurnedOn()) then |
839 | return false |
840 | end |
841 | |
842 | return superFunc(self, speedRotatingPart) |
843 | end |
getIsTestAreaActive
DescriptionDefinitiongetIsTestAreaActive()Code
813 | function Cutter:getIsTestAreaActive(area) |
814 | return true |
815 | end |
getIsWorkAreaActive
DescriptionDefinitiongetIsWorkAreaActive()Code
869 | function Cutter:getIsWorkAreaActive(superFunc, workArea) |
870 | local spec = self.spec_cutter |
871 | if self.getAllowsLowering == nil or self:getAllowsLowering() then |
872 | if not spec.allowCuttingWhileRaised and not self:getIsLowered(true) then |
873 | return false |
874 | end |
875 | end |
876 | |
877 | return superFunc(self, workArea) |
878 | end |
getWearMultiplier
DescriptionDefinitiongetWearMultiplier()Code
910 | function Cutter:getWearMultiplier(superFunc) |
911 | local spec = self.spec_cutter |
912 | |
913 | if spec.isWorking then |
914 | return superFunc(self) + self:getWorkWearMultiplier() * self:getLastSpeed() / self.speedLimit |
915 | end |
916 | |
917 | return superFunc(self) |
918 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
15 | function Cutter.initSpecialization() |
16 | g_workAreaTypeManager:addWorkAreaType("cutter", false) |
17 | end |
loadRandomlyMovingPartFromXML
DescriptionDefinitionloadRandomlyMovingPartFromXML()Code
847 | function Cutter:loadRandomlyMovingPartFromXML(superFunc, part, xmlFile, key) |
848 | local retValue = superFunc(self, part, xmlFile, key) |
849 | |
850 | part.moveOnlyIfCutted = Utils.getNoNil(getXMLBool(xmlFile, key .. "#moveOnlyIfCutted"), false) |
851 | |
852 | return retValue |
853 | end |
loadSpeedRotatingPartFromXML
DescriptionDefinitionloadSpeedRotatingPartFromXML()Code
825 | function Cutter:loadSpeedRotatingPartFromXML(superFunc, speedRotatingPart, xmlFile, key) |
826 | if not superFunc(self, speedRotatingPart, xmlFile, key) then |
827 | return false |
828 | end |
829 | speedRotatingPart.rotateIfTurnedOn = Utils.getNoNil(getXMLBool(xmlFile, key .. "#rotateIfTurnedOn"), false) |
830 | |
831 | return true |
832 | end |
loadTestAreaFromXML
DescriptionDefinitionloadTestAreaFromXML()Code
790 | function Cutter:loadTestAreaFromXML(testArea, xmlFile, key) |
791 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. "#startIndex", key .. "#startNode") --FS17 to FS19 |
792 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. "#widthIndex", key .. "#widthNode") --FS17 to FS19 |
793 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. "#heightIndex", key .. "#heightNode") --FS17 to FS19 |
794 | |
795 | local start = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#startNode"), self.i3dMappings) |
796 | local width = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#widthNode"), self.i3dMappings) |
797 | local height = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#heightNode"), self.i3dMappings) |
798 | |
799 | if start ~= nil and width ~= nil and height ~= nil then |
800 | testArea.start = start |
801 | testArea.width = width |
802 | testArea.height = height |
803 | testArea.hasFruitContact = false |
804 | testArea.hasFruitContactSent = false |
805 | return true |
806 | end |
807 | |
808 | return false |
809 | end |
loadWorkAreaFromXML
DescriptionDefinitionloadWorkAreaFromXML()Code
888 | function Cutter:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
889 | local retValue = superFunc(self, workArea, xmlFile, key) |
890 | |
891 | workArea.chopperAreaIndex = getXMLInt(xmlFile, key..".chopperArea#index") |
892 | |
893 | return retValue |
894 | end |
onAIImplementStart
DescriptionDefinitiononAIImplementStart()Code
966 | function Cutter:onAIImplementStart() |
967 | -- clear ai fruit requirements on start of ai vehicle to get the newest fruit type in front of the cutter |
968 | if self:getAllowCutterAIFruitRequirements() then |
969 | self:clearAIFruitRequirements() |
970 | |
971 | -- default require all fruit types the cutter can handle so we don't get other fruit types |
972 | local spec = self.spec_cutter |
973 | for fruitTypeIndex, _ in pairs(spec.fruitTypes) do |
974 | local fruitType = g_fruitTypeManager:getFruitTypeByIndex(fruitTypeIndex) |
975 | if fruitType ~= nil then |
976 | local minState = spec.allowsForageGrowthState and fruitType.minForageGrowthState or fruitType.minHarvestingGrowthState |
977 | self:addAIFruitRequirement(fruitType.index, minState, fruitType.maxHarvestingGrowthState) |
978 | end |
979 | end |
980 | end |
981 | end |
onDelete
DescriptionDefinitiononDelete()Code
245 | function Cutter:onDelete() |
246 | if self.isClient then |
247 | local spec = self.spec_cutter |
248 | |
249 | for _, effectAttribute in pairs(spec.cutterEffects) do |
250 | g_effectManager:deleteEffects(effectAttribute.effect) |
251 | end |
252 | g_effectManager:deleteEffects(spec.fillEffects) |
253 | g_animationManager:deleteAnimations(spec.animationNodes) |
254 | end |
255 | end |
onEndWorkAreaProcessing
DescriptionDefinitiononEndWorkAreaProcessing()Code
683 | function Cutter:onEndWorkAreaProcessing(dt, hasProcessed) |
684 | if self.isServer then |
685 | local spec = self.spec_cutter |
686 | |
687 | local lastRealArea = spec.workAreaParameters.lastRealArea |
688 | local lastThreshedArea = spec.workAreaParameters.lastThreshedArea |
689 | local lastStatsArea = spec.workAreaParameters.lastStatsArea |
690 | local lastArea = spec.workAreaParameters.lastArea |
691 | |
692 | if lastRealArea > 0 then |
693 | if spec.workAreaParameters.combineVehicle ~= nil then |
694 | local inputFruitType = spec.workAreaParameters.lastFruitType |
695 | |
696 | -- always use the same input fruit type while the ai is active to prevent situations where the combine is unable to unload a different fruit type |
697 | if self:getIsAIActive() then |
698 | local requirements = self:getAIFruitRequirements() |
699 | local requirement = requirements[1] |
700 | if #requirements == 1 and requirement ~= nil and requirement.fruitType ~= FruitType.UNKNOWN then |
701 | inputFruitType = requirement.fruitType |
702 | end |
703 | end |
704 | |
705 | -- take fill type conversion into consideration |
706 | local conversionFactor = 1.0 |
707 | local outputFillType = g_fruitTypeManager:getFillTypeIndexByFruitTypeIndex(inputFruitType) |
708 | |
709 | if spec.fruitTypeConverters[inputFruitType] ~= nil then |
710 | outputFillType = spec.fruitTypeConverters[inputFruitType].fillTypeIndex |
711 | conversionFactor = spec.fruitTypeConverters[inputFruitType].conversionFactor |
712 | end |
713 | |
714 | if spec.lastOutputFillTypes[outputFillType] == nil then |
715 | spec.lastOutputFillTypes[outputFillType] = lastRealArea |
716 | else |
717 | spec.lastOutputFillTypes[outputFillType] = spec.lastOutputFillTypes[outputFillType] + lastRealArea |
718 | end |
719 | |
720 | if spec.lastPrioritizedOutputType ~= FillType.UNKNOWN then |
721 | outputFillType = spec.lastPrioritizedOutputType |
722 | end |
723 | |
724 | lastRealArea = lastRealArea * conversionFactor |
725 | local farmId = self:getLastTouchedFarmlandFarmId() |
726 | local appliedDelta = spec.workAreaParameters.combineVehicle:addCutterArea(lastArea, lastRealArea, inputFruitType, outputFillType, spec.strawRatio, farmId) |
727 | if appliedDelta > 0 then |
728 | spec.lastValidInputFruitType = inputFruitType |
729 | end |
730 | end |
731 | |
732 | local ha = MathUtil.areaToHa(lastStatsArea, g_currentMission:getFruitPixelsToSqm()) -- 4096px are mapped to 2048m |
733 | local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId()) |
734 | stats:updateStats("threshedHectares", ha) |
735 | stats:updateStats("workedHectares", ha) |
736 | |
737 | spec.lastAreaBiggerZero = lastArea > 0 |
738 | if spec.lastAreaBiggerZero then |
739 | spec.lastAreaBiggerZeroTime = g_currentMission.time |
740 | end |
741 | if spec.lastAreaBiggerZero ~= spec.lastAreaBiggerZeroSent then |
742 | self:raiseDirtyFlags(spec.dirtyFlag) |
743 | spec.lastAreaBiggerZeroSent = spec.lastAreaBiggerZero |
744 | end |
745 | |
746 | if spec.currentInputFruitType ~= spec.currentInputFruitTypeSent then |
747 | self:raiseDirtyFlags(spec.effectDirtyFlag) |
748 | spec.currentInputFruitTypeSent = spec.currentInputFruitType |
749 | end |
750 | |
751 | if self:getAllowCutterAIFruitRequirements() then |
752 | if self.setAIFruitRequirements ~= nil then |
753 | -- we do not allow changes of the required type while working, just on ai start (if the cutter has more than one requirement or no requirement -> only one requirement allowed at the time) |
754 | -- prevents fruit type changes on field borders |
755 | local requirements = self:getAIFruitRequirements() |
756 | local requirement = requirements[1] |
757 | if #requirements > 1 or requirement == nil or requirement.fruitType == FruitType.UNKNOWN then |
758 | local fruitType = g_fruitTypeManager:getFruitTypeByIndex(spec.currentInputFruitTypeAI) |
759 | if fruitType ~= nil then |
760 | local minState = spec.allowsForageGrowthState and fruitType.minForageGrowthState or fruitType.minHarvestingGrowthState |
761 | self:setAIFruitRequirements(spec.currentInputFruitTypeAI, minState, fruitType.maxHarvestingGrowthState) |
762 | end |
763 | end |
764 | end |
765 | |
766 | spec.aiNoValidGroundTimer = 0 |
767 | end |
768 | else |
769 | if self:getAllowCutterAIFruitRequirements() then |
770 | if hasProcessed then |
771 | if self:getIsAIActive() and self:getRootVehicle():getAILastAllowedToDrive() then |
772 | spec.aiNoValidGroundTimer = spec.aiNoValidGroundTimer + dt |
773 | if spec.aiNoValidGroundTimer > 5000 then |
774 | local rootVehicle = self:getRootVehicle() |
775 | if rootVehicle.stopAIVehicle ~= nil then |
776 | rootVehicle:stopAIVehicle(AIVehicle.STOP_REASON_UNKOWN) |
777 | end |
778 | end |
779 | else |
780 | spec.aiNoValidGroundTimer = 0 |
781 | end |
782 | end |
783 | end |
784 | end |
785 | end |
786 | end |
onLoad
DescriptionDefinitiononLoad()Code
75 | function Cutter:onLoad(savegame) |
76 | local spec = self.spec_cutter |
77 | |
78 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.turnedOnRotationNodes.turnedOnRotationNode#type", "vehicle.cutter.animationNodes.animationNode", "cutter") --FS17 to FS19 |
79 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.turnedOnScrollers", "vehicle.cutter.animationNodes.animationNode") --FS17 to FS19 |
80 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cutter.turnedOnScrollers", "vehicle.cutter.animationNodes.animationNode") --FS17 to FS19 |
81 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cutter.reelspikes", "vehicle.cutter.rotationNodes.rotationNode or vehicle.turnOnVehicle.turnedOnAnimation") --FS17 to FS19 |
82 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cutter.threshingParticleSystems.threshingParticleSystem", "vehicle.cutter.fillEffect.effectNode") --FS17 to FS19 |
83 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cutter.threshingParticleSystems.emitterShape", "vehicle.cutter.fillEffect.effectNode") --FS17 to FS19 |
84 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cutter#convertedFillTypeCategories", "vehicle.cutter#fruitTypeConverter") --FS17 to FS19 |
85 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cutter#startAnimationName", "vehicle.turnOnVehicle.turnOnAnimation#name") --FS17 to FS19 |
86 | |
87 | -- load fruitTypes |
88 | local fruitTypes = nil |
89 | local fruitTypeNames = getXMLString(self.xmlFile, "vehicle.cutter#fruitTypes") |
90 | local fruitTypeCategories = getXMLString(self.xmlFile, "vehicle.cutter#fruitTypeCategories") |
91 | if fruitTypeCategories ~= nil and fruitTypeNames == nil then |
92 | fruitTypes = g_fruitTypeManager:getFruitTypesByCategoryNames(fruitTypeCategories, "Warning: Cutter has invalid fruitTypeCategory '%s' in '"..self.configFileName.."'") |
93 | elseif fruitTypeCategories == nil and fruitTypeNames ~= nil then |
94 | fruitTypes = g_fruitTypeManager:getFruitTypesByNames(fruitTypeNames, "Warning: Cutter has invalid fruitType '%s' in '"..self.configFileName.."'") |
95 | else |
96 | g_logManager:xmlWarning(self.configFileName, "Cutter needs either the 'fruitTypeCategories' or 'fruitTypes' attribute!") |
97 | end |
98 | |
99 | if fruitTypes ~= nil then |
100 | spec.fruitTypes = {} |
101 | for _,fruitType in pairs(fruitTypes) do |
102 | spec.fruitTypes[fruitType] = true |
103 | end |
104 | end |
105 | |
106 | spec.fruitTypeConverters = {} |
107 | local category = getXMLString(self.xmlFile, "vehicle.cutter#fruitTypeConverter") |
108 | if category ~= nil then |
109 | local data = g_fruitTypeManager:getConverterDataByName(category) |
110 | if data ~= nil then |
111 | for input, converter in pairs(data) do |
112 | spec.fruitTypeConverters[input] = converter |
113 | end |
114 | end |
115 | end |
116 | |
117 | if self.isClient then |
118 | spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.cutter.animationNodes", self.components, self, self.i3dMappings) |
119 | |
120 | spec.fruitExtraObjects = {} |
121 | local i = 0 |
122 | while true do |
123 | local key = string.format("vehicle.cutter.fruitExtraObjects.fruitExtraObject(%d)", i) |
124 | |
125 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key.."#index", key.."#node") |
126 | |
127 | local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node"), self.i3dMappings) |
128 | local anim = getXMLString(self.xmlFile, key.."#anim") |
129 | local isDefault = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#isDefault"), false) |
130 | local fruitType = g_fruitTypeManager:getFruitTypeByName(getXMLString(self.xmlFile, key.."#fruitType")) |
131 | |
132 | if fruitType == nil or (node == nil and anim == nil) then |
133 | break |
134 | end |
135 | |
136 | if node ~= nil then |
137 | setVisibility(node, false) |
138 | end |
139 | |
140 | local extraObject = {node=node, anim=anim} |
141 | spec.fruitExtraObjects[fruitType.index] = extraObject |
142 | if isDefault then |
143 | spec.fruitExtraObjects[FruitType.UNKNOWN] = extraObject |
144 | end |
145 | |
146 | i = i + 1 |
147 | end |
148 | spec.hideExtraObjectsOnDetach = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.cutter.fruitExtraObjects#hideOnDetach"), false) |
149 | |
150 | spec.testAreas = {} |
151 | spec.testAreaBase = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.cutter.testAreas#baseNode"), self.i3dMappings), self.rootNode) |
152 | i = 0 |
153 | while true do |
154 | local key = string.format("vehicle.cutter.testAreas.testArea(%d)", i) |
155 | if not hasXMLProperty(self.xmlFile, key) then |
156 | break |
157 | end |
158 | |
159 | local testArea = {} |
160 | if self:loadTestAreaFromXML(testArea, self.xmlFile, key) then |
161 | table.insert(spec.testAreas, testArea) |
162 | end |
163 | |
164 | i = i + 1 |
165 | end |
166 | |
167 | -- cutter |
168 | spec.cutterEffects = {} |
169 | spec.currentCutterEffect = nil |
170 | if hasXMLProperty(self.xmlFile, "vehicle.cutter.effect") then |
171 | for fruitTypeIndex,_ in pairs(spec.fruitTypes) do |
172 | spec.cutterEffects[fruitTypeIndex] = {} |
173 | i = 0 |
174 | while true do |
175 | local key = string.format("vehicle.cutter.effect.effectNode(%d)", i) |
176 | if not hasXMLProperty(self.xmlFile, key) then |
177 | break |
178 | end |
179 | local effect = CutterEffect:new() |
180 | effect:load(self.xmlFile, key, self.components, self, fruitTypeIndex, self.i3dMappings) |
181 | table.insert(spec.cutterEffects[fruitTypeIndex], effect) |
182 | i = i + 1 |
183 | end |
184 | end |
185 | end |
186 | |
187 | spec.fillEffects = g_effectManager:loadEffect(self.xmlFile, "vehicle.cutter.fillEffect", self.components, self, self.i3dMappings) |
188 | end |
189 | |
190 | spec.allowsForageGrowthState = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.cutter#allowsForageGrowthState"), false) |
191 | spec.allowCuttingWhileRaised = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.cutter#allowCuttingWhileRaised"), false) |
192 | spec.movingDirection = MathUtil.sign(Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.cutter#movingDirection"), 1)) |
193 | spec.strawRatio = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.cutter#strawRatio"), 1) |
194 | |
195 | spec.useWindrow = false |
196 | spec.currentInputFillType = FillType.UNKNOWN |
197 | spec.currentInputFruitType = FruitType.UNKNOWN |
198 | spec.currentInputFruitTypeAI = FruitType.UNKNOWN |
199 | spec.lastValidInputFruitType = FruitType.UNKNOWN |
200 | spec.currentInputFruitTypeSent = FruitType.UNKNOWN |
201 | spec.currentGrowthStateTime = 0 |
202 | spec.currentGrowthStateTimer = 0 |
203 | spec.currentGrowthState = 0 |
204 | |
205 | spec.lastAreaBiggerZero = false |
206 | spec.lastAreaBiggerZeroSent = false |
207 | spec.lastAreaBiggerZeroTime = -1 |
208 | |
209 | spec.workAreaParameters = {} |
210 | spec.workAreaParameters.lastRealArea = 0 |
211 | spec.workAreaParameters.lastArea = 0 |
212 | spec.workAreaParameters.lastGrowthState = 0 |
213 | spec.workAreaParameters.lastGrowthStateArea = 0 |
214 | |
215 | spec.lastOutputFillTypes = {} |
216 | spec.lastPrioritizedOutputType = FillType.UNKNOWN |
217 | spec.lastOutputTime = 0 |
218 | |
219 | spec.cutterLoad = 0 |
220 | spec.isWorking = false |
221 | |
222 | spec.workAreaParameters.countArea = true |
223 | spec.aiNoValidGroundTimer = 0 |
224 | |
225 | spec.dirtyFlag = self:getNextDirtyFlag() |
226 | spec.effectDirtyFlag = self:getNextDirtyFlag() |
227 | |
228 | self:doCollisionMaskCheck(MathUtil.bitsToMask(26), "vehicle.cutter#ignoreCollisionMask") |
229 | end |
onPostDetach
DescriptionCalled if vehicle gets detachedDefinition
onPostDetach(table attacherVehicle, table implement)Arguments
table | attacherVehicle | attacher vehicle |
table | implement | implement |
935 | function Cutter:onPostDetach(attacherVehicle, implement) |
936 | if self.isClient then |
937 | Cutter.updateExtraObjects(self) |
938 | end |
939 | end |
onPostLoad
DescriptionDefinitiononPostLoad()Code
233 | function Cutter:onPostLoad(savegame) |
234 | if self.addCutterToCombine ~= nil then |
235 | self:addCutterToCombine(self) |
236 | end |
237 | |
238 | if self.isClient then |
239 | Cutter.updateExtraObjects(self) |
240 | end |
241 | end |
onPreAttach
DescriptionCalled if vehicle gets attachedDefinition
onPreAttach(table attacherVehicle, integer inputJointDescIndex, integer jointDescIndex)Arguments
table | attacherVehicle | attacher vehicle |
integer | inputJointDescIndex | index of input attacher |
integer | jointDescIndex | index if attacher at the attacher vehicle |
925 | function Cutter:onPreAttach(attacherVehicle, inputJointDescIndex, jointDescIndex) |
926 | if self.isClient then |
927 | Cutter.updateExtraObjects(self) |
928 | end |
929 | end |
onReadStream
DescriptionDefinitiononReadStream()Code
259 | function Cutter:onReadStream(streamId, connection) |
260 | self:readTestAreasStream(streamId, connection) |
261 | |
262 | local spec = self.spec_cutter |
263 | spec.lastAreaBiggerZero = streamReadBool(streamId) |
264 | if spec.lastAreaBiggerZero then |
265 | spec.lastAreaBiggerZeroTime = g_currentMission.time |
266 | end |
267 | end |
onReadUpdateStream
DescriptionDefinitiononReadUpdateStream()Code
280 | function Cutter:onReadUpdateStream(streamId, timestamp, connection) |
281 | if connection:getIsServer() then |
282 | local spec = self.spec_cutter |
283 | |
284 | if streamReadBool(streamId) then |
285 | self:readTestAreasStream(streamId, connection) |
286 | end |
287 | |
288 | spec.lastAreaBiggerZero = streamReadBool(streamId) |
289 | if spec.lastAreaBiggerZero then |
290 | spec.lastAreaBiggerZeroTime = g_currentMission.time |
291 | end |
292 | end |
293 | end |
onStartWorkAreaProcessing
DescriptionDefinitiononStartWorkAreaProcessing()Code
657 | function Cutter:onStartWorkAreaProcessing(dt) |
658 | local spec = self.spec_cutter |
659 | |
660 | local combineVehicle = self:getCombine() |
661 | |
662 | spec.workAreaParameters.combineVehicle = combineVehicle |
663 | spec.workAreaParameters.lastRealArea = 0 |
664 | spec.workAreaParameters.lastThreshedArea = 0 |
665 | spec.workAreaParameters.lastStatsArea = 0 |
666 | spec.workAreaParameters.lastArea = 0 |
667 | spec.workAreaParameters.lastGrowthState = 0 |
668 | spec.workAreaParameters.lastGrowthStateArea = 0 |
669 | |
670 | if spec.workAreaParameters.lastFruitType == nil then |
671 | spec.workAreaParameters.fruitTypesToUse = spec.fruitTypes |
672 | else |
673 | spec.workAreaParameters.fruitTypesToUse = {} |
674 | spec.workAreaParameters.fruitTypesToUse[spec.workAreaParameters.lastFruitType] = true |
675 | end |
676 | |
677 | spec.workAreaParameters.lastFruitType = nil |
678 | spec.isWorking = false |
679 | end |
onTurnedOff
DescriptionDefinitiononTurnedOff()Code
952 | function Cutter:onTurnedOff() |
953 | local spec = self.spec_cutter |
954 | if self.isClient then |
955 | g_animationManager:stopAnimations(spec.animationNodes) |
956 | g_effectManager:resetEffects(spec.currentCutterEffect) |
957 | |
958 | spec.currentInputFruitType = FruitType.UNKNOWN |
959 | spec.currentInputFruitTypeAI = FruitType.UNKNOWN |
960 | spec.currentInputFillType = FillType.UNKNOWN |
961 | end |
962 | end |
onTurnedOn
DescriptionDefinitiononTurnedOn()Code
943 | function Cutter:onTurnedOn() |
944 | if self.isClient then |
945 | local spec = self.spec_cutter |
946 | g_animationManager:startAnimations(spec.animationNodes) |
947 | end |
948 | end |
onUpdateTick
DescriptionDefinitiononUpdateTick()Code
364 | function Cutter:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
365 | local spec = self.spec_cutter |
366 | local isTurnedOn = self:getIsTurnedOn() |
367 | |
368 | local isEffectActive = isTurnedOn and self.movingDirection == spec.movingDirection and self:getLastSpeed() > 0.5 and (spec.allowCuttingWhileRaised or self:getIsLowered(true)) |
369 | |
370 | if isEffectActive then |
371 | local minEffectValue = math.huge |
372 | local maxEffectValue = -math.huge |
373 | |
374 | local chargedAreas = 0 |
375 | for _, area in ipairs(spec.testAreas) do |
376 | local x,y,z = getWorldTranslation(area.start) |
377 | local x1,y1,z1 = getWorldTranslation(area.width) |
378 | local x2,_,z2 = getWorldTranslation(area.height) |
379 | |
380 | if self.isServer and spec.currentInputFruitType ~= nil then |
381 | if self:getIsTestAreaActive(area) then |
382 | local fruitValue, _, _, _ = FSDensityMapUtil.getFruitArea(spec.currentInputFruitType, x, z, x1, z1, x2, z2, nil, spec.allowsForageGrowthState) |
383 | area.hasFruitContact = fruitValue > 0 |
384 | |
385 | if area.hasFruitContactSent ~= area.hasFruitContact then |
386 | self:raiseDirtyFlags(spec.effectDirtyFlag) |
387 | area.hasFruitContactSent = area.hasFruitContact |
388 | end |
389 | end |
390 | end |
391 | |
392 | if area.hasFruitContact then |
393 | local lx1,_,_ = worldToLocal(spec.testAreaBase, x,y,z) |
394 | local lx2,_,_ = worldToLocal(spec.testAreaBase, x1,y1,z1) |
395 | minEffectValue = math.min(minEffectValue, lx1, lx2) |
396 | maxEffectValue = math.max(maxEffectValue, lx1, lx2) |
397 | chargedAreas = chargedAreas + 1 |
398 | end |
399 | end |
400 | |
401 | if not spec.useWindrow and #spec.testAreas > 0 then |
402 | local currentLoad = chargedAreas / #spec.testAreas |
403 | spec.cutterLoad = spec.cutterLoad * 0.95 + currentLoad * 0.05 |
404 | end |
405 | |
406 | local reset = false |
407 | if minEffectValue == math.huge and maxEffectValue == -math.huge then |
408 | minEffectValue = 0 |
409 | maxEffectValue = 0 |
410 | reset = true |
411 | end |
412 | |
413 | if spec.movingDirection > 0 then |
414 | minEffectValue = minEffectValue * -1 |
415 | maxEffectValue = maxEffectValue * -1 |
416 | if maxEffectValue < minEffectValue then |
417 | local t = minEffectValue |
418 | minEffectValue = maxEffectValue |
419 | maxEffectValue = t |
420 | end |
421 | end |
422 | |
423 | local inputFruitType = spec.currentInputFruitType |
424 | if inputFruitType ~= spec.lastValidInputFruitType then |
425 | -- if we pickup a different fruit type than we are able to proceed to the combine we won't display the effect |
426 | inputFruitType = nil |
427 | end |
428 | |
429 | if inputFruitType ~= nil then |
430 | local newEffect = spec.cutterEffects[inputFruitType] |
431 | if newEffect ~= nil then |
432 | if spec.currentCutterEffect ~= newEffect then |
433 | g_effectManager:resetEffects(spec.currentCutterEffect) |
434 | end |
435 | spec.currentCutterEffect = newEffect |
436 | for _, effect in ipairs(spec.currentCutterEffect) do |
437 | if effect.setGrowthState ~= nil then |
438 | effect:setGrowthState(spec.currentGrowthState) |
439 | end |
440 | if effect.setMinMaxWidth ~= nil then |
441 | effect:setMinMaxWidth(minEffectValue, maxEffectValue, reset) |
442 | end |
443 | end |
444 | else |
445 | if spec.currentCutterEffect ~= nil then |
446 | g_effectManager:resetEffects(spec.currentCutterEffect) |
447 | end |
448 | end |
449 | |
450 | Cutter.updateExtraObjects(self) |
451 | end |
452 | |
453 | local isCollecting = spec.lastAreaBiggerZeroTime + 300 > g_currentMission.time |
454 | local fillType = spec.currentInputFillType |
455 | |
456 | if spec.useWindrow then |
457 | if isCollecting then |
458 | spec.cutterLoad = spec.cutterLoad * 0.95 + 0.05 |
459 | else |
460 | spec.cutterLoad = spec.cutterLoad * 0.9 |
461 | end |
462 | end |
463 | |
464 | if fillType ~= FillType.UNKNOWN and isCollecting then |
465 | g_effectManager:setFillType(spec.fillEffects, fillType) |
466 | g_effectManager:setMinMaxWidth(spec.fillEffects, minEffectValue, maxEffectValue, reset) |
467 | g_effectManager:startEffects(spec.fillEffects) |
468 | else |
469 | g_effectManager:stopEffects(spec.fillEffects) |
470 | end |
471 | else |
472 | if spec.currentCutterEffect ~= nil then |
473 | for _, effect in pairs(spec.currentCutterEffect) do |
474 | if effect.setMinMaxWidth ~= nil then |
475 | effect:setMinMaxWidth(0, 0, true) |
476 | end |
477 | end |
478 | end |
479 | g_effectManager:stopEffects(spec.fillEffects) |
480 | |
481 | spec.cutterLoad = spec.cutterLoad * 0.9 |
482 | end |
483 | |
484 | -- lastPrioritizedOutputType is always the fill type that was the most significant fill type of the last 500ms |
485 | -- this fill type is transfered to the combine to avoid quick changes of the fill type if we harvester 2 different fruit types at the same time |
486 | -- e.g. on field borders if can happen that a bit of grass if collected from the cutter |
487 | spec.lastOutputTime = spec.lastOutputTime + dt |
488 | if spec.lastOutputTime > 500 then |
489 | spec.lastPrioritizedOutputType = FillType.UNKNOWN |
490 | |
491 | local max = 0 |
492 | for i, _ in pairs(spec.lastOutputFillTypes) do |
493 | if spec.lastOutputFillTypes[i] > max then |
494 | spec.lastPrioritizedOutputType = i |
495 | max = spec.lastOutputFillTypes[i] |
496 | end |
497 | |
498 | spec.lastOutputFillTypes[i] = 0 |
499 | end |
500 | |
501 | spec.lastOutputTime = 0 |
502 | end |
503 | end |
onWriteStream
DescriptionDefinitiononWriteStream()Code
271 | function Cutter:onWriteStream(streamId, connection) |
272 | self:writeTestAreasStream(streamId, connection) |
273 | |
274 | local spec = self.spec_cutter |
275 | streamWriteBool(streamId, spec.lastAreaBiggerZeroSent) |
276 | end |
onWriteUpdateStream
DescriptionDefinitiononWriteUpdateStream()Code
297 | function Cutter:onWriteUpdateStream(streamId, connection, dirtyMask) |
298 | if not connection:getIsServer() then |
299 | local spec = self.spec_cutter |
300 | |
301 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.effectDirtyFlag) ~= 0) then |
302 | self:writeTestAreasStream(streamId, connection) |
303 | end |
304 | |
305 | streamWriteBool(streamId, spec.lastAreaBiggerZeroSent) |
306 | end |
307 | end |
prerequisitesPresent
DescriptionDefinitionprerequisitesPresent()Code
21 | function Cutter.prerequisitesPresent(specializations) |
22 | return SpecializationUtil.hasSpecialization(WorkArea, specializations) |
23 | end |
processCutterArea
DescriptionDefinitionprocessCutterArea()Code
539 | function Cutter:processCutterArea(workArea, dt) |
540 | local spec = self.spec_cutter |
541 | |
542 | if spec.workAreaParameters.combineVehicle ~= nil then |
543 | local xs,_,zs = getWorldTranslation(workArea.start) |
544 | local xw,_,zw = getWorldTranslation(workArea.width) |
545 | local xh,_,zh = getWorldTranslation(workArea.height) |
546 | |
547 | local lastRealArea = 0 |
548 | local lastThreshedArea = 0 |
549 | local lastArea = 0 |
550 | for fruitType, state in pairs(spec.workAreaParameters.fruitTypesToUse) do |
551 | if state then |
552 | local realArea, area, sprayFactor, plowFactor, limeFactor, weedFactor, growthState, _, terrainDetailPixelsSum = FSDensityMapUtil.cutFruitArea(fruitType, xs,zs, xw,zw, xh,zh, true, true, spec.allowsForageGrowthState, g_currentMission.chopperGroundLayerType) |
553 | |
554 | if realArea > 0 then |
555 | if self.isServer then |
556 | if growthState ~= spec.currentGrowthState then |
557 | spec.currentGrowthStateTimer = spec.currentGrowthStateTimer + dt |
558 | if spec.currentGrowthStateTimer > 500 or spec.currentGrowthStateTime + 1000 < g_time then |
559 | spec.currentGrowthState = growthState |
560 | spec.currentGrowthStateTimer = 0 |
561 | end |
562 | else |
563 | spec.currentGrowthStateTimer = 0 |
564 | spec.currentGrowthStateTime = g_time |
565 | end |
566 | |
567 | spec.currentInputFruitType = fruitType |
568 | |
569 | -- ai only works on terrain detail, so we do not allow the ai to require fruits that are out of a field |
570 | if terrainDetailPixelsSum > 0 then |
571 | spec.currentInputFruitTypeAI = fruitType |
572 | end |
573 | spec.currentInputFillType = g_fruitTypeManager:getFillTypeIndexByFruitTypeIndex(fruitType) |
574 | spec.useWindrow = false |
575 | end |
576 | |
577 | local multiplier = g_currentMission:getHarvestScaleMultiplier(fruitType, sprayFactor, plowFactor, limeFactor, weedFactor) |
578 | lastRealArea = realArea * multiplier |
579 | lastThreshedArea = realArea |
580 | lastArea = area |
581 | |
582 | spec.workAreaParameters.lastFruitType = fruitType |
583 | break |
584 | end |
585 | end |
586 | end |
587 | |
588 | if lastArea > 0 then |
589 | if workArea.chopperAreaIndex ~= nil then |
590 | local workArea = self:getWorkAreaByIndex(workArea.chopperAreaIndex) |
591 | if workArea ~= nil then |
592 | local xs,_,zs = getWorldTranslation(workArea.start) |
593 | local xw,_,zw = getWorldTranslation(workArea.width) |
594 | local xh,_,zh = getWorldTranslation(workArea.height) |
595 | |
596 | FSDensityMapUtil.setGroundTypeLayerArea(xs, zs, xw, zw, xh, zh, g_currentMission.chopperGroundLayerType) |
597 | else |
598 | workArea.chopperAreaIndex = nil |
599 | g_logManager:xmlWarning(self.configFileName, "Invalid chopperAreaIndex '%d' for workArea '%d'!", workArea.chopperAreaIndex, workArea.index) |
600 | end |
601 | end |
602 | |
603 | spec.isWorking = true |
604 | end |
605 | |
606 | spec.workAreaParameters.lastRealArea = spec.workAreaParameters.lastRealArea + lastRealArea |
607 | spec.workAreaParameters.lastThreshedArea = spec.workAreaParameters.lastThreshedArea + lastThreshedArea |
608 | spec.workAreaParameters.lastStatsArea = spec.workAreaParameters.lastStatsArea + lastThreshedArea |
609 | spec.workAreaParameters.lastArea = spec.workAreaParameters.lastArea + lastArea |
610 | end |
611 | |
612 | return spec.workAreaParameters.lastRealArea, spec.workAreaParameters.lastArea |
613 | end |
processPickupCutterArea
DescriptionDefinitionprocessPickupCutterArea()Code
617 | function Cutter:processPickupCutterArea(workArea, dt) |
618 | local spec = self.spec_cutter |
619 | |
620 | if spec.workAreaParameters.combineVehicle ~= nil then |
621 | local lsx, lsy, lsz, lex, ley, lez, lineRadius = DensityMapHeightUtil.getLineByArea(workArea.start, workArea.width, workArea.height) |
622 | |
623 | for fruitType, state in pairs(spec.workAreaParameters.fruitTypesToUse) do |
624 | if state then |
625 | local fillType = g_fruitTypeManager:getWindrowFillTypeIndexByFruitTypeIndex(fruitType) |
626 | if fillType ~= nil then |
627 | local pickedUpLiters = -DensityMapHeightUtil.tipToGroundAroundLine(self, -math.huge, fillType, lsx, lsy, lsz, lex, ley, lez, lineRadius, nil, nil, false, nil) |
628 | |
629 | if self.isServer then |
630 | if pickedUpLiters > 0 then |
631 | local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitType) |
632 | local literPerSqm = fruitDesc.literPerSqm |
633 | local lastCutterArea = pickedUpLiters / (g_currentMission:getFruitPixelsToSqm() * literPerSqm); |
634 | |
635 | spec.currentInputFruitType = fruitType |
636 | spec.useWindrow = true |
637 | spec.currentInputFillType = fillType |
638 | spec.workAreaParameters.lastFruitType = fruitType |
639 | spec.workAreaParameters.lastRealArea = spec.workAreaParameters.lastRealArea + lastCutterArea |
640 | spec.workAreaParameters.lastThreshedArea = spec.workAreaParameters.lastThreshedArea + lastCutterArea |
641 | spec.workAreaParameters.lastStatsArea = spec.workAreaParameters.lastStatsArea + lastCutterArea |
642 | spec.workAreaParameters.lastArea = spec.workAreaParameters.lastArea + lastCutterArea |
643 | spec.isWorking = true |
644 | break |
645 | end |
646 | end |
647 | end |
648 | end |
649 | end |
650 | end |
651 | |
652 | return spec.workAreaParameters.lastRealArea, spec.workAreaParameters.lastArea |
653 | end |
readTestAreasStream
DescriptionDefinitionreadTestAreasStream()Code
311 | function Cutter:readTestAreasStream(streamId, connection) |
312 | local spec = self.spec_cutter |
313 | |
314 | local readGrowthState = false |
315 | for _, testArea in ipairs(spec.testAreas) do |
316 | testArea.hasFruitContact = streamReadBool(streamId) |
317 | if testArea.hasFruitContact then |
318 | readGrowthState = true |
319 | end |
320 | end |
321 | |
322 | if readGrowthState then |
323 | spec.currentGrowthState = streamReadUIntN(streamId, 4) |
324 | end |
325 | |
326 | spec.currentInputFruitType = streamReadUIntN(streamId, 7) |
327 | if streamReadBool(streamId) then |
328 | spec.lastValidInputFruitType = spec.currentInputFruitType |
329 | else |
330 | spec.currentInputFruitType = FillType.UNKNOWN |
331 | end |
332 | |
333 | if streamReadBool(streamId) then |
334 | spec.currentInputFillType = g_fruitTypeManager:getWindrowFillTypeIndexByFruitTypeIndex(spec.currentInputFruitType) |
335 | else |
336 | spec.currentInputFillType = g_fruitTypeManager:getFillTypeIndexByFruitTypeIndex(spec.currentInputFruitType) |
337 | end |
338 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
55 | function Cutter.registerEventListeners(vehicleType) |
56 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Cutter) |
57 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Cutter) |
58 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Cutter) |
59 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Cutter) |
60 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Cutter) |
61 | SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Cutter) |
62 | SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Cutter) |
63 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Cutter) |
64 | SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Cutter) |
65 | SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Cutter) |
66 | SpecializationUtil.registerEventListener(vehicleType, "onPreAttach", Cutter) |
67 | SpecializationUtil.registerEventListener(vehicleType, "onPostDetach", Cutter) |
68 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", Cutter) |
69 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", Cutter) |
70 | SpecializationUtil.registerEventListener(vehicleType, "onAIImplementStart", Cutter) |
71 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
27 | function Cutter.registerFunctions(vehicleType) |
28 | SpecializationUtil.registerFunction(vehicleType, "readTestAreasStream", Cutter.readTestAreasStream) |
29 | SpecializationUtil.registerFunction(vehicleType, "writeTestAreasStream", Cutter.writeTestAreasStream) |
30 | SpecializationUtil.registerFunction(vehicleType, "getCombine", Cutter.getCombine) |
31 | SpecializationUtil.registerFunction(vehicleType, "getAllowCutterAIFruitRequirements", Cutter.getAllowCutterAIFruitRequirements) |
32 | SpecializationUtil.registerFunction(vehicleType, "loadTestAreaFromXML", Cutter.loadTestAreaFromXML) |
33 | SpecializationUtil.registerFunction(vehicleType, "getIsTestAreaActive", Cutter.getIsTestAreaActive) |
34 | SpecializationUtil.registerFunction(vehicleType, "processCutterArea", Cutter.processCutterArea) |
35 | SpecializationUtil.registerFunction(vehicleType, "processPickupCutterArea", Cutter.processPickupCutterArea) |
36 | SpecializationUtil.registerFunction(vehicleType, "getCutterLoad", Cutter.getCutterLoad) |
37 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
41 | function Cutter.registerOverwrittenFunctions(vehicleType) |
42 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadSpeedRotatingPartFromXML", Cutter.loadSpeedRotatingPartFromXML) |
43 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsSpeedRotatingPartActive", Cutter.getIsSpeedRotatingPartActive) |
44 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadRandomlyMovingPartFromXML", Cutter.loadRandomlyMovingPartFromXML) |
45 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsRandomlyMovingPartActive", Cutter.getIsRandomlyMovingPartActive) |
46 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", Cutter.getIsWorkAreaActive) |
47 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "doCheckSpeedLimit", Cutter.doCheckSpeedLimit) |
48 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", Cutter.loadWorkAreaFromXML) |
49 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", Cutter.getDirtMultiplier) |
50 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Cutter.getWearMultiplier) |
51 | end |
updateDebugValues
DescriptionDefinitionupdateDebugValues()Code
1029 | function Cutter:updateDebugValues(values) |
1030 | local spec = self.spec_cutter |
1031 | table.insert(values, {name="lastPrioritizedOutputType", value=string.format("%s", g_fillTypeManager:getFillTypeNameByIndex(spec.lastPrioritizedOutputType))}) |
1032 | |
1033 | local sum = 0 |
1034 | for fillType, value in pairs(spec.lastOutputFillTypes) do |
1035 | sum = sum + value |
1036 | end |
1037 | |
1038 | for fillType, value in pairs(spec.lastOutputFillTypes) do |
1039 | table.insert(values, {name=string.format("buffer (%s)", g_fillTypeManager:getFillTypeNameByIndex(fillType)), value=string.format("%.0f%%", value/sum*100)}) |
1040 | end |
1041 | end |
updateExtraObjects
DescriptionDefinitionupdateExtraObjects()Code
985 | function Cutter.updateExtraObjects(self) |
986 | local spec = self.spec_cutter |
987 | |
988 | if spec.currentInputFruitType ~= nil then |
989 | local extraObject = spec.fruitExtraObjects[spec.currentInputFruitType] |
990 | |
991 | if spec.hideExtraObjectsOnDetach then |
992 | if self.getAttacherVehicle == nil or self:getAttacherVehicle() == nil then |
993 | extraObject = nil |
994 | end |
995 | end |
996 | |
997 | if extraObject ~= spec.currentExtraObject then |
998 | if spec.currentExtraObject ~= nil then |
999 | if spec.currentExtraObject.node ~= nil then |
1000 | setVisibility(spec.currentExtraObject.node, false) |
1001 | end |
1002 | if spec.currentExtraObject.anim ~= nil and self.playAnimation ~= nil then |
1003 | self:playAnimation(spec.currentExtraObject.anim, -1, self:getAnimationTime(spec.currentExtraObject.anim), true) |
1004 | end |
1005 | spec.currentExtraObject = nil |
1006 | end |
1007 | |
1008 | if extraObject ~= nil then |
1009 | if extraObject.node ~= nil then |
1010 | setVisibility(extraObject.node, true) |
1011 | end |
1012 | if extraObject.anim ~= nil and self.playAnimation ~= nil then |
1013 | self:playAnimation(extraObject.anim, 1, self:getAnimationTime(extraObject.anim), true) |
1014 | end |
1015 | spec.currentExtraObject = extraObject |
1016 | end |
1017 | end |
1018 | end |
1019 | end |
writeTestAreasStream
DescriptionDefinitionwriteTestAreasStream()Code
342 | function Cutter:writeTestAreasStream(streamId, connection) |
343 | local spec = self.spec_cutter |
344 | |
345 | local sentGrowthState = false |
346 | for _, testArea in ipairs(spec.testAreas) do |
347 | streamWriteBool(streamId, testArea.hasFruitContact) |
348 | if testArea.hasFruitContact then |
349 | sentGrowthState = true |
350 | end |
351 | end |
352 | |
353 | if sentGrowthState then |
354 | streamWriteUIntN(streamId, spec.currentGrowthState, 4) |
355 | end |
356 | |
357 | streamWriteUIntN(streamId, spec.currentInputFruitType, 7) |
358 | streamWriteBool(streamId, spec.currentInputFruitType == spec.lastValidInputFruitType) |
359 | streamWriteBool(streamId, spec.useWindrow) |
360 | end |