278 | function Cultivator:onEndWorkAreaProcessing(dt) |
279 | local spec = self.spec_cultivator |
280 | |
281 | if self.isServer then |
282 | local lastStatsArea = spec.workAreaParameters.lastStatsArea |
283 | if lastStatsArea > 0 then |
284 | local ha = MathUtil.areaToHa(lastStatsArea, g_currentMission:getFruitPixelsToSqm()) -- 4096px are mapped to 2048m |
285 | local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId()) |
286 | stats:updateStats("workedHectares", ha) |
287 | stats:updateStats("cultivatedHectares", ha) |
288 | |
289 | stats:updateStats("workedTime", dt/(1000*60)) |
290 | stats:updateStats("cultivatedTime", dt/(1000*60)) |
291 | end |
292 | end |
293 | |
294 | if self.isClient then |
295 | if spec.isWorking then |
296 | if not spec.isWorkSamplePlaying then |
297 | g_soundManager:playSample(spec.samples.work) |
298 | spec.isWorkSamplePlaying = true |
299 | end |
300 | else |
301 | if spec.isWorkSamplePlaying then |
302 | g_soundManager:stopSample(spec.samples.work) |
303 | spec.isWorkSamplePlaying = false |
304 | end |
305 | end |
306 | end |
307 | end |
59 | function Cultivator:onLoad(savegame) |
60 | |
61 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cultivator.directionNode#index", "vehicle.cultivator.directionNode#node") --FS17 to FS19 |
62 | |
63 | if self:getGroundReferenceNodeFromIndex(1) == nil then |
64 | print("Warning: No ground reference nodes in "..self.configFileName) |
65 | end |
66 | |
67 | local spec = self.spec_cultivator |
68 | |
69 | if self.isClient then |
70 | spec.samples = {} |
71 | spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.cultivator.sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
72 | spec.isWorkSamplePlaying = false |
73 | end |
74 | |
75 | spec.directionNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.cultivator.directionNode#node"), self.i3dMappings), self.components[1].node) |
76 | spec.onlyActiveWhenLowered = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.cultivator.onlyActiveWhenLowered#value"), true) |
77 | spec.isSubsoiler = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.cultivator#isSubsoiler"), false) |
78 | |
79 | if self.addAITerrainDetailRequiredRange ~= nil then |
80 | self:addAITerrainDetailRequiredRange(g_currentMission.plowValue, g_currentMission.plowValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels) |
81 | self:addAITerrainDetailRequiredRange(g_currentMission.sowingValue, g_currentMission.sowingValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels) |
82 | self:addAITerrainDetailRequiredRange(g_currentMission.sowingWidthValue, g_currentMission.sowingWidthValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels) |
83 | self:addAITerrainDetailRequiredRange(g_currentMission.grassValue, g_currentMission.grassValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels) |
84 | end |
85 | |
86 | spec.startActivationTimeout = 2000 |
87 | spec.startActivationTime = 0 |
88 | spec.hasGroundContact = false |
89 | spec.isWorking = false |
90 | spec.limitToField = false |
91 | spec.forceLimitToField = true |
92 | |
93 | spec.workAreaParameters = {} |
94 | spec.workAreaParameters.limitToField = spec.limitToField |
95 | spec.workAreaParameters.forceLimitToField = spec.forceLimitToField |
96 | spec.workAreaParameters.angle = 0 |
97 | spec.workAreaParameters.lastChangedArea = 0 |
98 | spec.workAreaParameters.lastStatsArea = 0 |
99 | spec.workAreaParameters.lastTotalArea = 0 |
100 | end |
253 | function Cultivator:onStartWorkAreaProcessing(dt) |
254 | local spec = self.spec_cultivator |
255 | |
256 | spec.isWorking = false |
257 | |
258 | local limitToField = spec.limitToField or spec.forceLimitToField |
259 | local limitGrassDestructionToField = spec.limitToField or spec.forceLimitToField |
260 | if not g_currentMission:getHasPlayerPermission("createFields", self:getOwner()) then |
261 | limitToField = true |
262 | limitGrassDestructionToField = true |
263 | end |
264 | |
265 | local dx,_,dz = localDirectionToWorld(spec.directionNode, 0, 0, 1) |
266 | local angle = FSDensityMapUtil.convertToDensityMapAngle(MathUtil.getYRotationFromDirection(dx, dz), g_currentMission.terrainDetailAngleMaxValue) |
267 | |
268 | spec.workAreaParameters.limitToField = limitToField |
269 | spec.workAreaParameters.limitGrassDestructionToField = limitGrassDestructionToField |
270 | spec.workAreaParameters.angle = angle |
271 | spec.workAreaParameters.lastChangedArea = 0 |
272 | spec.workAreaParameters.lastStatsArea = 0 |
273 | spec.workAreaParameters.lastTotalArea = 0 |
274 | end |
113 | function Cultivator:processCultivatorArea(workArea, dt) |
114 | local spec = self.spec_cultivator |
115 | |
116 | local xs,_,zs = getWorldTranslation(workArea.start) |
117 | local xw,_,zw = getWorldTranslation(workArea.width) |
118 | local xh,_,zh = getWorldTranslation(workArea.height) |
119 | |
120 | local params = spec.workAreaParameters |
121 | |
122 | local realArea, area = FSDensityMapUtil.updateCultivatorArea(xs,zs, xw,zw, xh,zh, not params.limitToField, not params.limitGrassDestructionToField, params.angle, nil) |
123 | params.lastChangedArea = params.lastChangedArea + realArea |
124 | params.lastStatsArea = params.lastStatsArea + realArea |
125 | params.lastTotalArea = params.lastTotalArea + area |
126 | |
127 | if spec.isSubsoiler then |
128 | FSDensityMapUtil.updateSubsoilerArea(xs,zs, xw,zw, xh,zh) |
129 | end |
130 | |
131 | FSDensityMapUtil.eraseTireTrack(xs,zs, xw,zw, xh,zh) |
132 | |
133 | spec.isWorking = self:getLastSpeed() > 0.5 |
134 | |
135 | return realArea, area |
136 | end |
46 | function Cultivator.registerEventListeners(vehicleType) |
47 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Cultivator) |
48 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Cultivator) |
49 | SpecializationUtil.registerEventListener(vehicleType, "onPostAttach", Cultivator) |
50 | SpecializationUtil.registerEventListener(vehicleType, "onPreDetach", Cultivator) |
51 | SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", Cultivator) |
52 | SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Cultivator) |
53 | SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Cultivator) |
54 | end |
35 | function Cultivator.registerOverwrittenFunctions(vehicleType) |
36 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "doCheckSpeedLimit", Cultivator.doCheckSpeedLimit) |
37 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDoGroundManipulation", Cultivator.getDoGroundManipulation) |
38 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", Cultivator.getDirtMultiplier) |
39 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Cultivator.getWearMultiplier) |
40 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", Cultivator.loadWorkAreaFromXML) |
41 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", Cultivator.getIsWorkAreaActive) |
42 | end |