47 | function Cultivator.initSpecialization() |
48 | g_workAreaTypeManager:addWorkAreaType("cultivator", true) |
49 | |
50 | local schema = Vehicle.xmlSchema |
51 | schema:setXMLSpecializationType("Cultivator") |
52 | |
53 | schema:register(XMLValueType.NODE_INDEX, "vehicle.cultivator.directionNode#node", "Direction node") |
54 | schema:register(XMLValueType.BOOL, "vehicle.cultivator.onlyActiveWhenLowered#value", "Only active when lowered", true) |
55 | schema:register(XMLValueType.BOOL, "vehicle.cultivator#isSubsoiler", "Is subsoiler", false) |
56 | schema:register(XMLValueType.BOOL, "vehicle.cultivator#useDeepMode", "If true the implement acts like a cultivator. If false it's a discharrow or seedbed combination", true) |
57 | schema:register(XMLValueType.BOOL, "vehicle.cultivator#isPowerHarrow", "If this is set the cultivator works standalone like a cultivator, but as soon as a sowing machine is attached to it, it's only using the sowing machine", false) |
58 | |
59 | SoundManager.registerSampleXMLPaths(schema, "vehicle.cultivator.sounds", "work") |
60 | |
61 | schema:setXMLSpecializationType() |
62 | end |
391 | function Cultivator:onEndWorkAreaProcessing(dt) |
392 | local spec = self.spec_cultivator |
393 | |
394 | if self.isServer then |
395 | local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId()) |
396 | local lastStatsArea = spec.workAreaParameters.lastStatsArea |
397 | |
398 | if lastStatsArea > 0 then |
399 | local ha = MathUtil.areaToHa(lastStatsArea, g_currentMission:getFruitPixelsToSqm()) -- 4096px are mapped to 2048m |
400 | stats:updateStats("cultivatedHectares", ha) |
401 | self:updateLastWorkedArea(lastStatsArea) |
402 | end |
403 | |
404 | if spec.isWorking then |
405 | stats:updateStats("cultivatedTime", dt/(1000*60)) |
406 | end |
407 | end |
408 | |
409 | if self.isClient then |
410 | if spec.isWorking then |
411 | if not spec.isWorkSamplePlaying then |
412 | g_soundManager:playSample(spec.samples.work) |
413 | spec.isWorkSamplePlaying = true |
414 | end |
415 | else |
416 | if spec.isWorkSamplePlaying then |
417 | g_soundManager:stopSample(spec.samples.work) |
418 | spec.isWorkSamplePlaying = false |
419 | end |
420 | end |
421 | end |
422 | end |
108 | function Cultivator:onLoad(savegame) |
109 | |
110 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.cultivator.directionNode#index", "vehicle.cultivator.directionNode#node") --FS17 to FS19 |
111 | |
112 | if self:getGroundReferenceNodeFromIndex(1) == nil then |
113 | print("Warning: No ground reference nodes in "..self.configFileName) |
114 | end |
115 | |
116 | local spec = self.spec_cultivator |
117 | |
118 | if self.isClient then |
119 | spec.samples = {} |
120 | spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.cultivator.sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
121 | spec.isWorkSamplePlaying = false |
122 | end |
123 | |
124 | spec.directionNode = self.xmlFile:getValue("vehicle.cultivator.directionNode#node", self.components[1].node, self.components, self.i3dMappings) |
125 | spec.onlyActiveWhenLowered = self.xmlFile:getValue("vehicle.cultivator.onlyActiveWhenLowered#value", true) |
126 | spec.isSubsoiler = self.xmlFile:getValue("vehicle.cultivator#isSubsoiler", false) |
127 | spec.isPowerHarrow = self.xmlFile:getValue("vehicle.cultivator#isPowerHarrow", false) |
128 | spec.useDeepMode = self.xmlFile:getValue("vehicle.cultivator#useDeepMode", true) |
129 | |
130 | self:updateCultivatorAIRequirements() |
131 | |
132 | spec.isEnabled = true |
133 | spec.startActivationTimeout = 2000 |
134 | spec.startActivationTime = 0 |
135 | spec.hasGroundContact = false |
136 | spec.isWorking = false |
137 | spec.limitToField = true |
138 | |
139 | spec.workAreaParameters = {} |
140 | spec.workAreaParameters.limitToField = self:getCultivatorLimitToField() |
141 | spec.workAreaParameters.angle = 0 |
142 | spec.workAreaParameters.lastChangedArea = 0 |
143 | spec.workAreaParameters.lastStatsArea = 0 |
144 | spec.workAreaParameters.lastTotalArea = 0 |
145 | end |
366 | function Cultivator:onStartWorkAreaProcessing(dt) |
367 | local spec = self.spec_cultivator |
368 | |
369 | spec.isWorking = false |
370 | |
371 | local limitToField = self:getCultivatorLimitToField() |
372 | local limitFruitDestructionToField = limitToField |
373 | if not g_currentMission:getHasPlayerPermission("createFields", self:getOwner()) then |
374 | limitToField = true |
375 | limitFruitDestructionToField = true |
376 | end |
377 | |
378 | local dx,_,dz = localDirectionToWorld(spec.directionNode, 0, 0, 1) |
379 | local angle = FSDensityMapUtil.convertToDensityMapAngle(MathUtil.getYRotationFromDirection(dx, dz), g_currentMission.fieldGroundSystem:getGroundAngleMaxValue()) |
380 | |
381 | spec.workAreaParameters.limitToField = limitToField |
382 | spec.workAreaParameters.limitFruitDestructionToField = limitFruitDestructionToField |
383 | spec.workAreaParameters.angle = angle |
384 | spec.workAreaParameters.lastChangedArea = 0 |
385 | spec.workAreaParameters.lastStatsArea = 0 |
386 | spec.workAreaParameters.lastTotalArea = 0 |
387 | end |
426 | function Cultivator:onStateChange(state, data) |
427 | if state == Vehicle.STATE_CHANGE_ATTACH or state == Vehicle.STATE_CHANGE_DETACH then |
428 | self:updateCultivatorAIRequirements() |
429 | self:updateCultivatorEnabledState() |
430 | end |
431 | |
432 | -- turn on attached sowing machines while we turn on the power harrow and vice versa |
433 | if self.isServer then |
434 | if state == Vehicle.STATE_CHANGE_TURN_ON or state == Vehicle.STATE_CHANGE_TURN_OFF then |
435 | local spec = self.spec_cultivator |
436 | if spec.isPowerHarrow then |
437 | if data == self and self.getAttachedImplements ~= nil then |
438 | for _, implement in pairs(self:getAttachedImplements()) do |
439 | local vehicle = implement.object |
440 | if vehicle ~= nil then |
441 | if state == Vehicle.STATE_CHANGE_TURN_ON then |
442 | vehicle:setIsTurnedOn(true) |
443 | else |
444 | if vehicle:getIsTurnedOn() then |
445 | vehicle:setIsTurnedOn(false) |
446 | end |
447 | end |
448 | end |
449 | end |
450 | elseif data.getAttacherVehicle ~= nil then |
451 | local attacherVehicle = data:getAttacherVehicle() |
452 | if attacherVehicle ~= nil then |
453 | if attacherVehicle == self then |
454 | if state == Vehicle.STATE_CHANGE_TURN_ON then |
455 | self:setIsTurnedOn(true) |
456 | else |
457 | if self:getIsTurnedOn() then |
458 | self:setIsTurnedOn(false) |
459 | end |
460 | end |
461 | end |
462 | end |
463 | end |
464 | end |
465 | end |
466 | end |
467 | end |
156 | function Cultivator:processCultivatorArea(workArea, dt) |
157 | local spec = self.spec_cultivator |
158 | |
159 | local realArea, area = 0, 0 |
160 | local xs,_,zs = getWorldTranslation(workArea.start) |
161 | local xw,_,zw = getWorldTranslation(workArea.width) |
162 | local xh,_,zh = getWorldTranslation(workArea.height) |
163 | |
164 | if spec.isEnabled then |
165 | local params = spec.workAreaParameters |
166 | |
167 | if spec.useDeepMode then |
168 | realArea, area = FSDensityMapUtil.updateCultivatorArea(xs,zs, xw,zw, xh,zh, not params.limitToField, params.limitFruitDestructionToField, params.angle, nil) |
169 | realArea = realArea + FSDensityMapUtil.updateVineCultivatorArea(xs, zs, xw, zw, xh, zh) |
170 | else |
171 | realArea, area = FSDensityMapUtil.updateDiscHarrowArea(xs,zs, xw,zw, xh,zh, not params.limitToField, params.limitFruitDestructionToField, params.angle, nil) |
172 | realArea = realArea + FSDensityMapUtil.updateVineCultivatorArea(xs, zs, xw, zw, xh, zh) |
173 | end |
174 | |
175 | params.lastChangedArea = params.lastChangedArea + realArea |
176 | params.lastStatsArea = params.lastStatsArea + realArea |
177 | params.lastTotalArea = params.lastTotalArea + area |
178 | end |
179 | |
180 | if spec.isSubsoiler then |
181 | FSDensityMapUtil.updateSubsoilerArea(xs, zs, xw, zw, xh, zh) |
182 | end |
183 | |
184 | FSDensityMapUtil.eraseTireTrack(xs, zs, xw, zw, xh, zh) |
185 | |
186 | spec.isWorking = self:getLastSpeed() > 0.5 |
187 | |
188 | return realArea, area |
189 | end |
95 | function Cultivator.registerEventListeners(vehicleType) |
96 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Cultivator) |
97 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Cultivator) |
98 | SpecializationUtil.registerEventListener(vehicleType, "onPostAttach", Cultivator) |
99 | SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", Cultivator) |
100 | SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Cultivator) |
101 | SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Cultivator) |
102 | SpecializationUtil.registerEventListener(vehicleType, "onStateChange", Cultivator) |
103 | end |
74 | function Cultivator.registerFunctions(vehicleType) |
75 | SpecializationUtil.registerFunction(vehicleType, "processCultivatorArea", Cultivator.processCultivatorArea) |
76 | SpecializationUtil.registerFunction(vehicleType, "getCultivatorLimitToField", Cultivator.getCultivatorLimitToField) |
77 | SpecializationUtil.registerFunction(vehicleType, "getUseCultivatorAIRequirements", Cultivator.getUseCultivatorAIRequirements) |
78 | SpecializationUtil.registerFunction(vehicleType, "updateCultivatorAIRequirements", Cultivator.updateCultivatorAIRequirements) |
79 | SpecializationUtil.registerFunction(vehicleType, "updateCultivatorEnabledState", Cultivator.updateCultivatorEnabledState) |
80 | SpecializationUtil.registerFunction(vehicleType, "getIsCultivationEnabled", Cultivator.getIsCultivationEnabled) |
81 | end |
85 | function Cultivator.registerOverwrittenFunctions(vehicleType) |
86 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "doCheckSpeedLimit", Cultivator.doCheckSpeedLimit) |
87 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", Cultivator.getDirtMultiplier) |
88 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Cultivator.getWearMultiplier) |
89 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", Cultivator.loadWorkAreaFromXML) |
90 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", Cultivator.getIsWorkAreaActive) |
91 | end |
207 | function Cultivator:updateCultivatorAIRequirements() |
208 | if self:getUseCultivatorAIRequirements() then |
209 | if self.addAITerrainDetailRequiredRange ~= nil then |
210 | local hasSowingMachine = false |
211 | local excludedType1, excludedType2 |
212 | local vehicles = self.rootVehicle:getChildVehicles() |
213 | for i=1, #vehicles do |
214 | if SpecializationUtil.hasSpecialization(SowingMachine, vehicles[i].specializations) then |
215 | if vehicles[i]:getAIRequiresTurnOn() or vehicles[i]:getUseSowingMachineAIRequirements() then |
216 | hasSowingMachine = true |
217 | end |
218 | end |
219 | |
220 | if SpecializationUtil.hasSpecialization(Roller, vehicles[i].specializations) then |
221 | excludedType1 = FieldGroundType.ROLLER_LINES |
222 | excludedType2 = FieldGroundType.ROLLED_SEEDBED |
223 | end |
224 | end |
225 | |
226 | -- if we also have a active sowing machine attached the sowingMachine is fully handling it |
227 | if not hasSowingMachine then |
228 | if self.spec_cultivator.useDeepMode then |
229 | self:addAIGroundTypeRequirements(Cultivator.AI_REQUIRED_GROUND_TYPES_DEEP, excludedType1, excludedType2) |
230 | else |
231 | self:addAIGroundTypeRequirements(Cultivator.AI_REQUIRED_GROUND_TYPES_FLAT, excludedType1, excludedType2) |
232 | end |
233 | else |
234 | self:clearAITerrainDetailRequiredRange() |
235 | end |
236 | end |
237 | end |
238 | end |