257 | function Tedder:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
258 | local retValue = superFunc(self, workArea, xmlFile, key) |
259 | |
260 | if workArea.type == WorkAreaType.DEFAULT then |
261 | workArea.type = WorkAreaType.TEDDER |
262 | end |
263 | |
264 | if workArea.type == WorkAreaType.TEDDER then |
265 | workArea.dropWindrowWorkAreaIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. ".tedder#dropWindrowWorkAreaIndex"), 1) |
266 | workArea.litersToDrop = 0 |
267 | workArea.lastPickupLiters = 0 |
268 | workArea.lastDropFillType = FillType.UNKNOWN |
269 | workArea.lastDroppedLiters = 0 |
270 | workArea.tedderParticlesActive = false |
271 | workArea.tedderParticlesActiveSent = false |
272 | |
273 | local spec = self.spec_tedder |
274 | if spec.tedderWorkAreaFillTypes == nil then |
275 | spec.tedderWorkAreaFillTypes = {} |
276 | end |
277 | table.insert(spec.tedderWorkAreaFillTypes, FruitType.UNKNOWN) |
278 | workArea.tedderWorkAreaIndex = #spec.tedderWorkAreaFillTypes |
279 | end |
280 | |
281 | return retValue |
282 | end |
63 | function Tedder:onLoad(savegame) |
64 | local spec = self.spec_tedder |
65 | |
66 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.turnedOnRotationNodes.turnedOnRotationNode#type", "vehicle.tedder.animationNodes.animationNode", "tedder") --FS17 to FS19 |
67 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tedder.sounds", "vehicle.turnOnVehicle.sounds.work") --FS17 to FS19 |
68 | |
69 | spec.fillTypeConverters = {} |
70 | spec.fillTypeConvertersReverse = {} |
71 | local converter = getXMLString(self.xmlFile, "vehicle.tedder#fillTypeConverter") |
72 | if converter ~= nil then |
73 | local data = g_fillTypeManager:getConverterDataByName(converter) |
74 | if data ~= nil then |
75 | for input, converted in pairs(data) do |
76 | spec.fillTypeConverters[input] = converted |
77 | |
78 | if spec.fillTypeConvertersReverse[converted.targetFillTypeIndex] == nil then |
79 | spec.fillTypeConvertersReverse[converted.targetFillTypeIndex] = {} |
80 | end |
81 | table.insert(spec.fillTypeConvertersReverse[converted.targetFillTypeIndex], input) |
82 | end |
83 | end |
84 | else |
85 | print(string.format("Warning: Missing fill type converter in '%s'", self.configFileName)) |
86 | end |
87 | |
88 | if self.isClient then |
89 | spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.tedder.animationNodes", self.components, self, self.i3dMappings) |
90 | |
91 | spec.effects = {} |
92 | spec.workAreaToEffects = {} |
93 | local i = 0 |
94 | while true do |
95 | local key = string.format("vehicle.tedder.effects.effect(%d)", i) |
96 | if not hasXMLProperty(self.xmlFile, key) then |
97 | break |
98 | end |
99 | local effects = g_effectManager:loadEffect(self.xmlFile, key, self.components, self, self.i3dMappings) |
100 | if effects ~= nil then |
101 | local effect = {} |
102 | effect.effects = effects |
103 | effect.workAreaIndex = Utils.getNoNil(getXMLInt(self.xmlFile, key .. "#workAreaIndex"), 1) |
104 | effect.activeTime = -1 |
105 | effect.activeTimeDuration = 250 |
106 | effect.isActive = false |
107 | effect.isActiveSent = false |
108 | table.insert(spec.effects, effect) |
109 | end |
110 | i = i + 1 |
111 | end |
112 | end |
113 | |
114 | spec.lastDroppedLiters = 0 |
115 | |
116 | spec.fillTypesDirtyFlag = self:getNextDirtyFlag() |
117 | spec.effectDirtyFlag = self:getNextDirtyFlag() |
118 | |
119 | if self.addAIFruitRequirement ~= nil then |
120 | self:addAIFruitRequirement(FruitType.GRASS, 0, g_currentMission.terrainDetailHeightTypeNumChannels) |
121 | self:setAIFruitExtraRequirements(true, true) |
122 | end |
123 | end |
127 | function Tedder:onPostLoad(savegame) |
128 | local spec = self.spec_tedder |
129 | for i=#spec.effects, 1, -1 do |
130 | local effect = spec.effects[i] |
131 | local workArea = self:getWorkAreaByIndex(effect.workAreaIndex) |
132 | if workArea ~= nil then |
133 | effect.tedderWorkAreaFillTypeIndex = workArea.tedderWorkAreaIndex |
134 | |
135 | if spec.workAreaToEffects[workArea.index] == nil then |
136 | spec.workAreaToEffects[workArea.index] = {} |
137 | end |
138 | table.insert(spec.workAreaToEffects[workArea.index], effect) |
139 | else |
140 | g_logManager:xmlWarning(self.xmlFileName, "Invalid workAreaIndex '%d' for effect 'vehicle.tedder.effects.effect(%d)'!", effect.workAreaIndex, i) |
141 | table.insert(spec.effects, i) |
142 | end |
143 | end |
144 | end |
161 | function Tedder:onReadStream(streamId, connection) |
162 | local spec = self.spec_tedder |
163 | for index, _ in ipairs(spec.tedderWorkAreaFillTypes) do |
164 | local fillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS) |
165 | spec.tedderWorkAreaFillTypes[index] = fillType |
166 | end |
167 | for _, effect in ipairs(spec.effects) do |
168 | if streamReadBool(streamId) then |
169 | local fillType = spec.tedderWorkAreaFillTypes[effect.tedderWorkAreaFillTypeIndex] |
170 | g_effectManager:setFillType(effect.effects, fillType) |
171 | g_effectManager:startEffects(effect.effects) |
172 | else |
173 | g_effectManager:stopEffects(effect.effects) |
174 | end |
175 | end |
176 | end |
192 | function Tedder:onReadUpdateStream(streamId, timestamp, connection) |
193 | if connection:getIsServer() then |
194 | local spec = self.spec_tedder |
195 | |
196 | if streamReadBool(streamId) then |
197 | for index, _ in ipairs(spec.tedderWorkAreaFillTypes) do |
198 | local fillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS) |
199 | spec.tedderWorkAreaFillTypes[index] = fillType |
200 | end |
201 | end |
202 | |
203 | if streamReadBool(streamId) then |
204 | for _, effect in ipairs(spec.effects) do |
205 | if streamReadBool(streamId) then |
206 | local fillType = spec.tedderWorkAreaFillTypes[effect.tedderWorkAreaFillTypeIndex] |
207 | g_effectManager:setFillType(effect.effects, fillType) |
208 | g_effectManager:startEffects(effect.effects) |
209 | else |
210 | g_effectManager:stopEffects(effect.effects) |
211 | end |
212 | end |
213 | end |
214 | end |
215 | end |
219 | function Tedder:onWriteUpdateStream(streamId, connection, dirtyMask) |
220 | if not connection:getIsServer() then |
221 | local spec = self.spec_tedder |
222 | |
223 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.fillTypesDirtyFlag) ~= 0) then |
224 | for _, fillTypeIndex in ipairs(spec.tedderWorkAreaFillTypes) do |
225 | streamWriteUIntN(streamId, fillTypeIndex, FillTypeManager.SEND_NUM_BITS) |
226 | end |
227 | end |
228 | |
229 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.effectDirtyFlag) ~= 0) then |
230 | for _, effect in ipairs(spec.effects) do |
231 | streamWriteBool(streamId, effect.isActiveSent) |
232 | end |
233 | end |
234 | end |
235 | end |
405 | function Tedder:processDropArea(dropArea, fillType, litersToDrop) |
406 | local lsx, lsy, lsz, lex, ley, lez, lineRadius = DensityMapHeightUtil.getLineByArea(dropArea.start, dropArea.width, dropArea.height, true) |
407 | local dropped, lineOffset = DensityMapHeightUtil.tipToGroundAroundLine(self, litersToDrop, fillType, lsx, lsy, lsz, lex, ley, lez, lineRadius, nil, dropArea.lineOffset, false, nil, false) |
408 | dropArea.lineOffset = lineOffset |
409 | |
410 | return dropped |
411 | end |
327 | function Tedder:processTedderArea(workArea, dt) |
328 | local spec = self.spec_tedder |
329 | local workAreaSpec = self.spec_workArea |
330 | |
331 | -- pick up |
332 | local lsx, lsy, lsz, lex, ley, lez, lineRadius = DensityMapHeightUtil.getLineByArea(workArea.start, workArea.width, workArea.height) |
333 | |
334 | for targetFillType, inputFillTypes in pairs(spec.fillTypeConvertersReverse) do |
335 | local pickedUpLiters = 0 |
336 | for _, inputFillType in ipairs(inputFillTypes) do |
337 | pickedUpLiters = pickedUpLiters + DensityMapHeightUtil.tipToGroundAroundLine(self, -math.huge, inputFillType, lsx, lsy, lsz, lex, ley, lez, lineRadius, nil, nil, false, nil) |
338 | end |
339 | |
340 | if pickedUpLiters == 0 and workArea.lastDropFillType ~= FillType.UNKNOWN then |
341 | targetFillType = workArea.lastDropFillType |
342 | end |
343 | |
344 | workArea.lastPickupLiters = -pickedUpLiters |
345 | workArea.litersToDrop = workArea.litersToDrop + workArea.lastPickupLiters |
346 | |
347 | -- drop |
348 | local dropArea = workAreaSpec.workAreas[workArea.dropWindrowWorkAreaIndex] |
349 | if dropArea ~= nil and workArea.litersToDrop > 0 then |
350 | local dropped = self:processDropArea(dropArea, targetFillType, workArea.litersToDrop) |
351 | |
352 | workArea.lastDropFillType = targetFillType |
353 | workArea.lastDroppedLiters = dropped |
354 | spec.lastDroppedLiters = spec.lastDroppedLiters + dropped |
355 | workArea.litersToDrop = workArea.litersToDrop - dropped |
356 | |
357 | if self.isServer then |
358 | --particles |
359 | if dropped > 0 and self:getLastSpeed(true) > 0.5 then |
360 | local changedFillType = false |
361 | if spec.tedderWorkAreaFillTypes[workArea.tedderWorkAreaIndex] ~= targetFillType then |
362 | spec.tedderWorkAreaFillTypes[workArea.tedderWorkAreaIndex] = targetFillType |
363 | self:raiseDirtyFlags(spec.fillTypesDirtyFlag) |
364 | changedFillType = true |
365 | end |
366 | |
367 | local effects = spec.workAreaToEffects[workArea.index] |
368 | if effects ~= nil then |
369 | for _, effect in ipairs(effects) do |
370 | effect.activeTime = g_currentMission.time + effect.activeTimeDuration |
371 | |
372 | -- sync mp |
373 | if not effect.isActiveSent then |
374 | effect.isActiveSent = true |
375 | self:raiseDirtyFlags(spec.effectDirtyFlag) |
376 | end |
377 | |
378 | if changedFillType then |
379 | g_effectManager:setFillType(effect.effects, targetFillType) |
380 | end |
381 | |
382 | -- enable effect |
383 | if not effect.isActive then |
384 | g_effectManager:setFillType(effect.effects, targetFillType) |
385 | g_effectManager:startEffects(effect.effects) |
386 | end |
387 | |
388 | effect.isActive = true |
389 | end |
390 | end |
391 | end |
392 | end |
393 | end |
394 | end |
395 | |
396 | --calculating area by area width multiplied by last moved distance (not 100% accuracy in corners) |
397 | local areaWidth = MathUtil.vector3Length(lsx-lex, lsy-ley, lsz-lez) |
398 | local area = areaWidth * self.lastMovedDistance |
399 | |
400 | return area, area |
401 | end |
45 | function Tedder.registerEventListeners(vehicleType) |
46 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Tedder) |
47 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Tedder) |
48 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Tedder) |
49 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Tedder) |
50 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Tedder) |
51 | SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Tedder) |
52 | SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Tedder) |
53 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Tedder) |
54 | SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Tedder) |
55 | SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Tedder) |
56 | SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", Tedder) |
57 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", Tedder) |
58 | SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", Tedder) |
59 | end |