41 | function Tedder:load(savegame) |
42 | |
43 | self.getDirtMultiplier = Utils.overwrittenFunction(self.getDirtMultiplier, Tedder.getDirtMultiplier); |
44 | self.doCheckSpeedLimit = Utils.overwrittenFunction(self.doCheckSpeedLimit, Tedder.doCheckSpeedLimit); |
45 | |
46 | self.processTedderAreas = Tedder.processTedderAreas; |
47 | |
48 | self.tedderTurnedOnRotationNodes = Utils.loadRotationNodes(self.xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "tedder", self.components); |
49 | |
50 | if hasXMLProperty(self.xmlFile, "vehicle.rotors") then |
51 | print("Warning: vehicle.rotors are not supported anymore, use vehicle.turnedOnRotationNodes.turnedOnRotationNode (type: tedder) instead"); |
52 | end; |
53 | |
54 | local numTedderDropAreas = table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_TEDDERDROP)); |
55 | if numTedderDropAreas == 0 then |
56 | print("Warning: No drop work areas specified in '"..self.configFileName.."'"); |
57 | else |
58 | if numTedderDropAreas ~= 1 and numTedderDropAreas ~= table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_TEDDER)) then |
59 | print("Warning: Number of work areas and drop work areas should be equal in '"..self.configFileName.."'"); |
60 | end; |
61 | end; |
62 | |
63 | self.tedderParticleSystems = {} |
64 | local i=0; |
65 | while true do |
66 | local key = string.format("vehicle.tedderParticleSystems.emitterShape(%d)", i); |
67 | if not hasXMLProperty(self.xmlFile, key) then |
68 | break |
69 | end |
70 | local emitterShape = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node")); |
71 | local particleType = getXMLString(self.xmlFile, key.."#particleType") |
72 | if emitterShape ~= nil then |
73 | local particleSystem = MaterialUtil.getParticleSystem(FillUtil.FILLTYPE_DRYGRASS_WINDROW, particleType) |
74 | if particleSystem ~= nil then |
75 | local currentPS = ParticleUtil.copyParticleSystem(self.xmlFile, key, particleSystem, emitterShape) |
76 | currentPS.disableTime = 0; |
77 | currentPS.isEnabled = false; |
78 | table.insert(self.tedderParticleSystems, currentPS) |
79 | end |
80 | end |
81 | |
82 | i=i+1; |
83 | end |
84 | |
85 | if self.isClient then |
86 | self.sampleTedder = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.tedderSound", nil, self.baseDirectory); |
87 | end; |
88 | |
89 | self.isTedderSpeedLimitActive = false; |
90 | |
91 | self.showFieldNotOwnedWarning = false |
92 | |
93 | local desc = FruitUtil.fruitTypes["grass"]; |
94 | self.aiRequiredFruitType = desc.index; |
95 | self.aiRequiredMinGrowthState = 0; |
96 | self.aiRequiredMaxGrowthState = g_currentMission.numWindrowChannels; |
97 | self.aiUseDensityHeightMap = true; |
98 | self.aiUseWindrowFruitType = true; |
99 | |
100 | table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.grassValue, g_currentMission.grassValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels}); |
101 | |
102 | self.tedderDirtyFlag = self:getNextDirtyFlag(); |
103 | end; |
185 | function Tedder:updateTick(dt) |
186 | local showFieldNotOwnedWarning = false |
187 | self.isTedderSpeedLimitActive = false; |
188 | self.isWorking = false; |
189 | if self:getIsActive() then |
190 | local hasGroundContact, typedWorkAreas = self:getIsTypedWorkAreaActive(WorkArea.AREATYPE_TEDDER); |
191 | self.hasGroundContact = hasGroundContact; |
192 | |
193 | if self.hasGroundContact then |
194 | if self:getIsTurnedOn() then |
195 | self.isTedderSpeedLimitActive = true; |
196 | if self.isServer then |
197 | local workAreas = {}; |
198 | local typedWorkAreasDrop, showWarning = self:getTypedNetworkAreas(WorkArea.AREATYPE_TEDDERDROP, true); |
199 | showFieldNotOwnedWarning = showWarning; |
200 | |
201 | if not showWarning then |
202 | for k, workArea in pairs(typedWorkAreas) do |
203 | if self:getIsWorkAreaActive(workArea) then |
204 | local x,_,z = getWorldTranslation(workArea.start); |
205 | local x1,_,z1 = getWorldTranslation(workArea.width); |
206 | local x2,_,z2 = getWorldTranslation(workArea.height); |
207 | |
208 | local dropArea = typedWorkAreasDrop[workArea.dropAreaIndex]; |
209 | local dx, dz = dropArea[1], dropArea[2]; |
210 | local dx1, dz1 = dropArea[3], dropArea[4]; |
211 | local dx2, dz2 = dropArea[5], dropArea[6]; |
212 | |
213 | table.insert(workAreas, {x,z, x1,z1, x2,z2, dx,dz, dx1,dz1, dx2,dz2, 0, k}); |
214 | end; |
215 | end; |
216 | if (table.getn(workAreas) > 0) then |
217 | local usedWorkAreas = self:processTedderAreas(workAreas, self.accumulatedWorkAreaValues); |
218 | if (table.getn(usedWorkAreas) > 0) then |
219 | self.isWorking = true; |
220 | if self:getLastSpeed(true) > 0.5 then |
221 | for i=1, table.getn(usedWorkAreas) do |
222 | local workArea = typedWorkAreas[usedWorkAreas[i][14]]; |
223 | if workArea.tedderParticleSystemIndex ~= nil then |
224 | local ps = self.tedderParticleSystems[workArea.tedderParticleSystemIndex+1] |
225 | if ps ~= nil then |
226 | ps.disableTime = g_currentMission.time + 300; |
227 | if not ps.isEnabled then |
228 | ps.isEnabled = true; |
229 | self:raiseDirtyFlags(self.tedderDirtyFlag); |
230 | if self.isClient then |
231 | ParticleUtil.setEmittingState(ps, true); |
232 | end; |
233 | end; |
234 | end; |
235 | end; |
236 | end; |
237 | end; |
238 | end; |
239 | end; |
240 | |
241 | end; |
242 | end; |
243 | end; |
244 | end; |
245 | if self.isServer then |
246 | for _, ps in pairs(self.tedderParticleSystems) do |
247 | if g_currentMission.time > ps.disableTime then |
248 | if ps.isEnabled then |
249 | ps.isEnabled = false; |
250 | self:raiseDirtyFlags(self.tedderDirtyFlag); |
251 | if self.isClient then |
252 | ParticleUtil.setEmittingState(ps, false); |
253 | end; |
254 | end; |
255 | end; |
256 | end; |
257 | end; |
258 | |
259 | if self:getIsTurnedOn() then |
260 | if self.isClient and self:getIsActiveForSound() then |
261 | SoundUtil.playSample(self.sampleTedder, 0, 0, nil); |
262 | end; |
263 | end; |
264 | end; |
265 | |
266 | if self.isServer then |
267 | if showFieldNotOwnedWarning ~= self.showFieldNotOwnedWarning then |
268 | self.showFieldNotOwnedWarning = showFieldNotOwnedWarning |
269 | self:raiseDirtyFlags(self.tedderDirtyFlag); |
270 | end |
271 | end |
272 | end; |
332 | function Tedder:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
333 | local retValue = true; |
334 | if superFunc ~= nil then |
335 | retValue = superFunc(self, workArea, xmlFile, key) |
336 | end |
337 | |
338 | if workArea.type == WorkArea.AREATYPE_DEFAULT then |
339 | workArea.type = WorkArea.AREATYPE_TEDDER; |
340 | end; |
341 | |
342 | if workArea.type == WorkArea.AREATYPE_TEDDER then |
343 | workArea.tedderParticleSystemIndex = getXMLInt(xmlFile, key .. "#particleSystemIndex"); |
344 | workArea.dropAreaIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. "#dropAreaIndex"), 0) + 1; |
345 | |
346 | if self.accumulatedWorkAreaValues == nil then |
347 | self.accumulatedWorkAreaValues = {}; |
348 | end; |
349 | self.accumulatedWorkAreaValues[table.getn(self.accumulatedWorkAreaValues)+1] = 0; |
350 | end; |
351 | |
352 | return retValue; |
353 | end; |
379 | function Tedder:processTedderAreas(workAreas, accumulatedWorkAreaValues) |
380 | |
381 | local numAreas = table.getn(workAreas); |
382 | |
383 | local retWorkAreas = {}; |
384 | for i=1, numAreas do |
385 | local x0 = workAreas[i][1]; |
386 | local z0 = workAreas[i][2]; |
387 | local x1 = workAreas[i][3]; |
388 | local z1 = workAreas[i][4]; |
389 | local x2 = workAreas[i][5]; |
390 | local z2 = workAreas[i][6]; |
391 | local dx0 = workAreas[i][7]; |
392 | local dz0 = workAreas[i][8]; |
393 | local dx1 = workAreas[i][9]; |
394 | local dz1 = workAreas[i][10]; |
395 | local dx2 = workAreas[i][11]; |
396 | local dz2 = workAreas[i][12]; |
397 | |
398 | -- pick up |
399 | local hx = x2 - x0; |
400 | local hz = z2 - z0; |
401 | local hLength = Utils.vector2Length(hx, hz); |
402 | local hLength_2 = 0.5 * hLength; |
403 | |
404 | local wx = x1 - x0; |
405 | local wz = z1 - z0; |
406 | local wLength = Utils.vector2Length(wx, wz); |
407 | |
408 | local sx = x0 + (hx * 0.5) + ((wx/wLength)*hLength_2); |
409 | local sz = z0 + (hz * 0.5) + ((wz/wLength)*hLength_2); |
410 | |
411 | local ex = x1 + (hx * 0.5) - ((wx/wLength)*hLength_2); |
412 | local ez = z1 + (hz * 0.5) - ((wz/wLength)*hLength_2); |
413 | |
414 | local sy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx,0,sz); |
415 | local ey = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, ex,0,ez); |
416 | |
417 | local fillType1 = FruitUtil.fruitTypeToWindrowFillType[FruitUtil.FRUITTYPE_GRASS]; |
418 | local liters1 = TipUtil.tipToGroundAroundLine(self, -math.huge, fillType1, sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil); |
419 | |
420 | local fillType2 = FruitUtil.fruitTypeToWindrowFillType[FruitUtil.FRUITTYPE_DRYGRASS]; |
421 | local liters2 = TipUtil.tipToGroundAroundLine(self, -math.huge, fillType2, sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil); |
422 | |
423 | local liters = -liters1 - liters2; |
424 | |
425 | -- drop |
426 | local hx = dx2 - dx0; |
427 | local hz = dz2 - dz0; |
428 | local hLength = Utils.vector2Length(hx, hz); |
429 | local hLength_2 = 0.5 * hLength; |
430 | |
431 | local wx = dx1 - dx0; |
432 | local wz = dz1 - dz0; |
433 | local wLength = Utils.vector2Length(wx, wz); |
434 | |
435 | local sx = dx0 + (hx * 0.5) + ((wx/wLength)*hLength_2); |
436 | local sz = dz0 + (hz * 0.5) + ((wz/wLength)*hLength_2); |
437 | |
438 | local ex = dx1 + (hx * 0.5) - ((wx/wLength)*hLength_2); |
439 | local ez = dz1 + (hz * 0.5) - ((wz/wLength)*hLength_2); |
440 | |
441 | local sy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx,0,sz); |
442 | local ey = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, ex,0,ez); |
443 | |
444 | local toDrop = accumulatedWorkAreaValues[i] + liters; |
445 | local dropped, lineOffset = TipUtil.tipToGroundAroundLine(self, toDrop, FruitUtil.fruitTypeToWindrowFillType[FruitUtil.FRUITTYPE_DRYGRASS], sx,sy,sz, ex,ey,ez, hLength_2, nil, self.tedderLineOffset, false, nil, false); |
446 | self.tedderLineOffset = lineOffset; |
447 | local remain = toDrop - dropped; |
448 | |
449 | accumulatedWorkAreaValues[i] = remain; |
450 | workAreas[i][13] = remain; |
451 | |
452 | if liters > remain then |
453 | table.insert(retWorkAreas, workAreas[i]); |
454 | end |
455 | |
456 | end; |
457 | return retWorkAreas; |
458 | end |