Sprache Deutsch Language English

Script Dokumentation LS 2015 - SowingMachine (Patch 1.3)

Script Dokumentation Übersicht

scripts/vehicles/specializations/SowingMachine.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1--
2-- SowingMachine
3-- Class for all sowing machines
4--
5-- @author Stefan Geiger
6-- @date 25/02/08
7--
8-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
9
10source("dataS/scripts/vehicles/specializations/SetTurnedOnEvent.lua");
11source("dataS/scripts/vehicles/specializations/SowingMachineAreaEvent.lua");
12source("dataS/scripts/vehicles/specializations/SowingMachineSetSeedIndex.lua");
13
14source("dataS/scripts/vehicles/specializations/SetIsFillingEvent.lua");
15
16SowingMachine = {};
17
18function SowingMachine.initSpecialization()
19 WorkArea.registerAreaType("sowingMachine");
20end;
21
22function SowingMachine.prerequisitesPresent(specializations)
23 return SpecializationUtil.hasSpecialization(Fillable, specializations) and SpecializationUtil.hasSpecialization(WorkArea, specializations) and SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations);
24end;
25
26function SowingMachine:preLoad(xmlFile)
27 self.supportsFillTriggers = true;
28 self.loadWorkAreaFromXML = Utils.overwrittenFunction(self.loadWorkAreaFromXML, SowingMachine.loadWorkAreaFromXML);
29end
30
31function SowingMachine:load(xmlFile)
32
33 self.getIsTurnedOnAllowed = Utils.overwrittenFunction(self.getIsTurnedOnAllowed, SowingMachine.getIsTurnedOnAllowed);
34 self.setSeedFruitType = SpecializationUtil.callSpecializationsFunction("setSeedFruitType");
35 self.setSeedIndex = SpecializationUtil.callSpecializationsFunction("setSeedIndex");
36
37 self.getAllowFillFromAir = Utils.overwrittenFunction(self.getAllowFillFromAir, SowingMachine.getAllowFillFromAir);
38 self.getDirectionSnapAngle = Utils.overwrittenFunction(self.getDirectionSnapAngle, SowingMachine.getDirectionSnapAngle);
39 self.allowFillType = Utils.overwrittenFunction(self.allowFillType, SowingMachine.allowFillType);
40 self.setFillLevel = Utils.overwrittenFunction(self.setFillLevel, SowingMachine.setFillLevel);
41 self.getFillLevel = Utils.overwrittenFunction(self.getFillLevel, SowingMachine.getFillLevel);
42 self.resetFillLevelIfNeeded = Utils.overwrittenFunction(self.resetFillLevelIfNeeded, SowingMachine.resetFillLevelIfNeeded);
43 self.getDirtMultiplier = Utils.overwrittenFunction(self.getDirtMultiplier, SowingMachine.getDirtMultiplier);
44 self.doCheckSpeedLimit = Utils.overwrittenFunction(self.doCheckSpeedLimit, SowingMachine.doCheckSpeedLimit);
45
46 if hasXMLProperty(xmlFile, "vehicle.drum#index") then
47 print("Warning: vehicle.drum is no longer used, use vehicle.speedRotatingParts.speedRotatingPart\n");
48 end;
49
50 if next(self.groundReferenceNodes) == nil then
51 print("Warning: No ground reference nodes in "..self.configFileName);
52 end
53
54 self.turnOnAnimation = getXMLString(xmlFile, "vehicle.turnOnAnimation#name");
55 self.turnOnAnimationSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.turnOnAnimation#speed"), 1);
56
57 self.allowFillFromAirWhileTurnedOn = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.allowFillFromAirWhileTurnedOn#value"), true);
58
59 self.sowingDirectionNode = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.sowingDirectionNode#index")), self.components[1].node);
60
61 self.useDirectPlanting = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.useDirectPlanting"), false);
62
63 self.sowingMachineHasGroundContact = false;
64
65 self.seeds = {};
66 local seedFruitTypes = getXMLString(xmlFile, "vehicle.seedFruitTypes#seedFruitTypes");
67 if seedFruitTypes ~= nil and seedFruitTypes ~= "" then
68 local types = Utils.splitString(" ", seedFruitTypes);
69 for _,v in pairs(types) do
70 local fruitTypeDesc = FruitUtil.fruitTypes[v];
71 if fruitTypeDesc ~= nil and fruitTypeDesc.allowsSeeding then
72 table.insert(self.seeds, fruitTypeDesc.index);
73 else
74 print("Warning: '"..self.configFileName.. "' has invalid seedFruitType '"..v.."'.");
75 end;
76 end;
77 else
78 local useSeedingWidth = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.seedFruitTypes#useSeedingWidth"), false);
79 for k, fruitTypeDesc in pairs(FruitUtil.fruitTypes) do
80 if fruitTypeDesc.allowsSeeding and useSeedingWidth == fruitTypeDesc.useSeedingWidth then
81 table.insert(self.seeds, fruitTypeDesc.index);
82 end;
83 end;
84 end;
85
86 self.needsActivation = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.needsActivation#value"), false);
87
88 self.aiTerrainDetailChannel1 = g_currentMission.cultivatorChannel;
89 self.aiTerrainDetailChannel2 = g_currentMission.ploughChannel;
90 if self.useDirectPlanting then
91 self.aiTerrainDetailChannel3 = g_currentMission.sowingChannel;
92 end
93
94 if self.isClient then
95 self.sampleSowing = Utils.loadSample(xmlFile, {}, "vehicle.sowingSound", nil, self.baseDirectory);
96 self.sampleAirBlower = Utils.loadSample(xmlFile, {}, "vehicle.airBlowerSound", nil, self.baseDirectory);
97
98 local linkNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile, "vehicle.fillSound#linkNode"), "0>"));
99 self.sampleFill = Utils.loadSample(xmlFile, {}, "vehicle.fillSound", nil, self.baseDirectory, linkNode);
100 self.sampleFillEnabled = false;
101 self.sampleFillStopTime = -1;
102 self.lastFillLevel = -1;
103
104 self.sowingMachineTurnedOnRotationNodes = Utils.loadRotationNodes(xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "sowingMachine", self.components);
105 self.turnedOnScrollers = Utils.loadScrollers(self.components, xmlFile, "vehicle.turnedOnScrollers.turnedOnScroller", {}, false)
106
107 local changeSeedInputButtonStr = getXMLString(xmlFile, "vehicle.changeSeedInputButton");
108 if changeSeedInputButtonStr ~= nil then
109 self.changeSeedInputButton = InputBinding[changeSeedInputButtonStr];
110 end;
111 self.changeSeedInputButton = Utils.getNoNil(self.changeSeedInputButton, InputBinding.IMPLEMENT_EXTRA3);
112 end;
113
114 self.fillTypes[Fillable.FILLTYPE_SEEDS] = true;
115 self.lastSowingArea = 0;
116 self.currentSeed = 1;
117 self.allowsSeedChanging = true;
118 self.showFieldNotOwnedWarning = false;
119
120 self.isSowingSpeedLimitActive = false;
121
122 self.forcedFillPlaneType = self.seeds[self.currentSeed];
123
124 self.sowingMachineGroundContactFlag = self:getNextDirtyFlag();
125end;
126
127function SowingMachine:delete()
128 if self.isClient then
129 Utils.deleteSample(self.sampleSowing);
130 Utils.deleteSample(self.sampleAirBlower);
131 Utils.deleteSample(self.sampleFill);
132 end;
133end;
134
135function SowingMachine:readStream(streamId, connection)
136 local seedIndex = streamReadUInt8(streamId);
137 self:setSeedIndex(seedIndex, true);
138end;
139
140function SowingMachine:writeStream(streamId, connection)
141 streamWriteUInt8(streamId, self.currentSeed);
142end;
143
144
145function SowingMachine:readUpdateStream(streamId, timestamp, connection)
146 if connection:getIsServer() then
147 self.sowingMachineHasGroundContact = streamReadBool(streamId);
148 self.showFieldNotOwnedWarning = streamReadBool(streamId);
149 end;
150end;
151
152function SowingMachine:writeUpdateStream(streamId, connection, dirtyMask)
153 if not connection:getIsServer() then
154 streamWriteBool(streamId, self.sowingMachineHasGroundContact);
155 streamWriteBool(streamId, self.showFieldNotOwnedWarning);
156 end;
157end;
158
159function SowingMachine:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
160 local selectedSeedFruitType = getXMLString(xmlFile, key.."#selectedSeedFruitType");
161 if selectedSeedFruitType ~= nil then
162 local fruitTypeDesc = FruitUtil.fruitTypes[selectedSeedFruitType];
163 if fruitTypeDesc ~= nil then
164 self:setSeedFruitType(fruitTypeDesc.index, true);
165 end;
166 end;
167 return BaseMission.VEHICLE_LOAD_OK;
168end;
169
170function SowingMachine:getSaveAttributesAndNodes(nodeIdent)
171 local selectedSeedFruitTypeName = "unknown";
172 local selectedSeedFruitType = self.seeds[self.currentSeed];
173 if selectedSeedFruitType ~= nil and selectedSeedFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
174 selectedSeedFruitTypeName = FruitUtil.fruitIndexToDesc[selectedSeedFruitType].name;
175 end;
176 local attributes = 'selectedSeedFruitType="'..selectedSeedFruitTypeName..'"';
177 return attributes, nil;
178end;
179
180
181function SowingMachine:mouseEvent(posX, posY, isDown, isUp, button)
182end;
183
184function SowingMachine:keyEvent(unicode, sym, modifier, isDown)
185end;
186
187function SowingMachine:update(dt)
188
189 if self:getIsActive() then
190 if self:getIsActiveForInput() then
191 if InputBinding.hasEvent(self.changeSeedInputButton) then
192
193 if self.allowsSeedChanging then
194 local seed = self.currentSeed + 1;
195 if seed > table.getn(self.seeds) then
196 seed = 1;
197 end;
198 self:setSeedIndex(seed);
199 end;
200 end;
201 end;
202 end
203 if self.isClient then
204 Utils.updateRotationNodes(self, self.sowingMachineTurnedOnRotationNodes, dt, self:getIsActive() and self:getIsTurnedOn());
205 Utils.updateScrollers(self.turnedOnScrollers, dt, self:getIsActive() and self:getIsTurnedOn());
206 end;
207end;
208
209function SowingMachine:updateTick(dt)
210 self.isSowingSpeedLimitActive = false;
211 if self:getIsActive() then
212
213 self.lastSowingArea = 0;
214 local showFieldNotOwnedWarning = false;
215 if self.isServer then
216 local hasGroundContact = self:getIsTypedWorkAreaActive(WorkArea.AREATYPE_SOWINGMACHINE);
217
218 if self.sowingMachineHasGroundContact ~= hasGroundContact then
219 self:raiseDirtyFlags(self.sowingMachineGroundContactFlag);
220
221 self.sowingMachineHasGroundContact = hasGroundContact;
222 end;
223 end;
224 local hasGroundContact = self.sowingMachineHasGroundContact;
225
226 local doGroundManipulation = (self.movingDirection > 0 and hasGroundContact and (not self.needsActivation or self:getIsTurnedOn()));
227
228 local foldAnimTime = self.foldAnimTime;
229 if doGroundManipulation then
230 self.isSowingSpeedLimitActive = true;
231 if self.isServer then
232 local hasSeeds = (self.fillLevel > 0);
233 local useFillLevel = true;
234 if self:getCapacity() == 0 or self:getIsHired() then
235 useFillLevel = hasSeeds;
236 hasSeeds = true;
237 end;
238 if hasSeeds then
239 local workAreasSend, showWarning, _ = self:getTypedNetworkAreas(WorkArea.AREATYPE_SOWINGMACHINE, true);
240 showFieldNotOwnedWarning = showWarning;
241
242 if (table.getn(workAreasSend) > 0) then
243 local seedsFruitType = self.seeds[self.currentSeed];
244 local dx,dy,dz = localDirectionToWorld(self.sowingDirectionNode, 0, 0, 1);
245
246 local angleRad = Utils.getYRotationFromDirection(dx, dz)
247 local desc = FruitUtil.fruitIndexToDesc[seedsFruitType];
248 if desc ~= nil and desc.directionSnapAngle ~= 0 then
249 angleRad = math.floor(angleRad / desc.directionSnapAngle + 0.5) * desc.directionSnapAngle;
250 end
251
252 local angle = Utils.convertToDensityMapAngle(angleRad, g_currentMission.terrainDetailAngleMaxValue);
253
254 local area, detailArea = SowingMachineAreaEvent.runLocally(workAreasSend, seedsFruitType, angle, self.useDirectPlanting)
255 if area > 0 or detailArea > 0 then
256 if area > 0 then
257 local fruitDesc = FruitUtil.fruitIndexToDesc[seedsFruitType];
258 self.lastSowingArea = Utils.areaToHa(area, g_currentMission:getFruitPixelsToSqm());
259 local usage = fruitDesc.seedUsagePerSqm * self.lastSowingArea * 10000;
260
261 g_currentMission.missionStats:updateStats("seedUsage", usage);
262 g_currentMission.missionStats:updateStats("hectaresSeeded", self.lastSowingArea);
263
264 if useFillLevel then
265 self:setFillLevel(self.fillLevel - usage, self.currentFillType);
266 else
267 local fillTypeDesc = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_SEEDS]
268 if fillTypeDesc ~= nil then
269 local price = usage*fillTypeDesc.pricePerLiter*1.5; -- increase price if AI is active to reward the player's manual work
270 g_currentMission.missionStats:updateStats("expenses", price);
271 g_currentMission:addSharedMoney(-price, "other");
272 end
273 end
274 end
275 g_server:broadcastEvent(SowingMachineAreaEvent:new(workAreasSend, seedsFruitType, angle, self.useDirectPlanting));
276 end;
277 end;
278 end;
279 end;
280 g_currentMission.missionStats:updateStats("seedingDuration", dt/(1000*60));
281 end;
282
283 if self.isClient then
284 if doGroundManipulation and self:getLastSpeed() > 3 then
285 if self:getIsActiveForSound() then
286 Utils.playSample(self.sampleSowing, 0, 0, nil);
287 end
288 else
289 Utils.stopSample(self.sampleSowing);
290 end
291
292 if self:getIsTurnedOn() and self:getIsActiveForSound() then
293 Utils.playSample(self.sampleAirBlower, 0, 0, nil);
294 end
295 end
296
297 if self.isServer then
298 if showFieldNotOwnedWarning ~= self.showFieldNotOwnedWarning then
299 self.showFieldNotOwnedWarning = showFieldNotOwnedWarning;
300 self:raiseDirtyFlags(self.sowingMachineGroundContactFlag);
301 end
302 end
303 end;
304
305 if self.isClient then
306 if self.lastFillLevel ~= self.fillLevel and self.fillLevel > 0 then
307 if self.lastFillLevel < self.fillLevel and self.lastFillLevel ~= -1 then
308 self.sampleFillStopTime = g_currentMission.time + 150;
309 end;
310 self.lastFillLevel = self.fillLevel;
311 end;
312
313 if self.sampleFillStopTime > g_currentMission.time then
314 if self:getIsActiveForSound(true) then
315 Utils.playSample(self.sampleFill, 0, 0, nil);
316 Utils.stop3DSample(self.sampleFill);
317 else
318 Utils.stopSample(self.sampleFill);
319 Utils.play3DSample(self.sampleFill);
320 end;
321 else
322 Utils.stopSample(self.sampleFill);
323 Utils.stop3DSample(self.sampleFill);
324 end;
325 end;
326end;
327
328function SowingMachine:draw()
329
330 if self.isClient then
331 if self:getIsActiveForInput(true) then
332 if self.fillLevel <= 0 and self:getCapacity() ~= 0 then
333 g_currentMission:addExtraPrintText(g_i18n:getText("FirstFillTheTool"));
334 end;
335
336 if self.allowsSeedChanging and table.getn(self.seeds) > 1 then
337 g_currentMission:addHelpButtonText(g_i18n:getText("ChooseSeed"), self.changeSeedInputButton);
338 end;
339 end
340
341 g_currentMission:setFruitOverlayFruitType(self.seeds[self.currentSeed]);
342
343 if self.showFieldNotOwnedWarning then
344 g_currentMission:showBlinkingWarning(g_i18n:getText("You_dont_own_this_field"));
345 end;
346 end;
347end;
348
349function SowingMachine:onAttach(attacherVehicle)
350 SowingMachine.onActivate(self);
351end;
352
353function SowingMachine:onEnter(isControlling)
354 if isControlling then
355 SowingMachine.onActivate(self);
356 end;
357end;
358
359function SowingMachine:onActivate()
360end;
361
362function SowingMachine:onDeactivate()
363 self.showFieldNotOwnedWarning = false;
364end;
365
366function SowingMachine:getIsTurnedOnAllowed(superFunc, isTurnedOn)
367 if not self.needsActivation then
368 return false;
369 end;
370
371 if isTurnedOn and self.fillLevel <= 0 then
372 if self:getCapacity() > 0 and not self:getIsHired() then
373 return false;
374 end;
375 end;
376
377 if superFunc ~= nil then
378 return superFunc(self, isTurnedOn);
379 end
380
381 return true;
382end;
383
384function SowingMachine:onTurnedOn(noEventSend)
385 if self.turnOnAnimation ~= nil and self.playAnimation ~= nil then
386 self:playAnimation(self.turnOnAnimation, self.turnOnAnimationSpeed, nil, true);
387 end;
388end;
389
390function SowingMachine:onTurnedOff(noEventSend)
391 if self.isClient then
392 Utils.stopSample(self.sampleAirBlower);
393 end;
394 if self.turnOnAnimation ~= nil and self.playAnimation ~= nil then
395 self:playAnimation(self.turnOnAnimation, -self.turnOnAnimationSpeed, nil, true);
396 end;
397end;
398
399function SowingMachine:onDeactivateSounds()
400 if self.isClient then
401 Utils.stopSample(self.sampleSowing, true);
402 Utils.stopSample(self.sampleAirBlower, true);
403 end;
404end;
405
406function SowingMachine:setSeedIndex(seedIndex, noEventSend)
407 SowingMachineSetSeedIndex.sendEvent(self, seedIndex, noEventSend);
408 self.currentSeed = math.min(math.max(seedIndex, 1), table.getn(self.seeds));
409
410 if self.useDirectPlanting then
411 self.aiProhibitedFruitType = self.seeds[self.currentSeed];
412 -- do not allow any of the fruit we are seeding
413 self.aiProhibitedMinGrowthState = 0;
414 self.aiProhibitedMaxGrowthState = FruitUtil.fruitIndexToDesc[self.aiProhibitedFruitType].maxHarvestingGrowthState;
415 else
416 self.aiTerrainDetailProhibitedMask = 2^g_currentMission.sowingChannel;
417 self.aiTerrainDetailProhibitedMask = bitOR(self.aiTerrainDetailProhibitedMask, 2^g_currentMission.sowingWidthChannel);
418 self.aiProhibitedFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
419 end
420end;
421
422function SowingMachine:setSeedFruitType(fruitType, noEventSend)
423 for i,v in ipairs(self.seeds) do
424 if v == fruitType then
425 self:setSeedIndex(i, noEventSend);
426 break;
427 end;
428 end;
429end;
430
431function SowingMachine:aiTurnOn()
432 self:setIsTurnedOn(true, true);
433end;
434
435function SowingMachine:aiTurnOff()
436 self:setIsTurnedOn(false, true);
437end;
438
439function SowingMachine:aiLower()
440 self:setIsTurnedOn(true, true);
441end;
442
443function SowingMachine:aiRaise()
444 self:setIsTurnedOn(false, true);
445end;
446
447function SowingMachine:getAllowFillFromAir(superFunc)
448 if self:getIsTurnedOn() and not self.allowFillFromAirWhileTurnedOn then
449 return false;
450 end
451 return superFunc(self);
452end
453
454function SowingMachine:getDirectionSnapAngle(superFunc)
455 local seedsFruitType = self.seeds[self.currentSeed];
456 local desc = FruitUtil.fruitIndexToDesc[seedsFruitType];
457 local snapAngle = 0;
458 if desc ~= nil then
459 snapAngle = desc.directionSnapAngle;
460 end
461 return math.max(snapAngle, superFunc(self));
462end
463
464-- overwrite Fillable.resetFillLevelIfNeeded
465function SowingMachine:resetFillLevelIfNeeded(superFunc, fillType)
466 -- we convert everything to seeds
467 superFunc(self, Fillable.FILLTYPE_SEEDS);
468end;
469
470-- overwrite Fillable.allowFillType
471function SowingMachine:allowFillType(superFunc, fillType, allowEmptying)
472 return self.fillTypes[fillType] == true;
473end;
474
475-- overwrite Fillable.setFillLevel
476function SowingMachine:setFillLevel(superFunc, fillLevel, fillType, force)
477
478 -- convert everything to seeds if it is accepted
479 if self:allowFillType(fillType, false) then
480 fillType = Fillable.FILLTYPE_SEEDS;
481 end
482
483 self.forcedFillPlaneType = self.seeds[self.currentSeed];
484
485 superFunc(self, fillLevel, fillType, force);
486end
487
488-- overwrite Fillable.getFillLevel
489function SowingMachine:getFillLevel(superFunc, fillType)
490 return self.fillLevel;
491end
492
493function SowingMachine:doCheckSpeedLimit(superFunc)
494 local parent = true;
495 if superFunc ~= nil then
496 parent = superFunc(self);
497 end
498
499 return parent and self.isSowingSpeedLimitActive;
500end;
501
502function SowingMachine:getDirtMultiplier(superFunc)
503 local multiplier = 0;
504 if superFunc ~= nil then
505 multiplier = multiplier + superFunc(self);
506 end;
507
508 if self.movingDirection > 0 and self.sowingMachineHasGroundContact and (not self.needsActivation or self:getIsTurnedOn()) then
509 multiplier = multiplier + self.workMultiplier * self:getLastSpeed() / self.speedLimit;
510 end;
511
512 return multiplier;
513end;
514
515function SowingMachine:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
516 local retValue = true;
517 if superFunc ~= nil then
518 retValue = superFunc(self, workArea, xmlFile, key)
519 end
520
521 if workArea.type == WorkArea.AREATYPE_DEFAULT then
522 workArea.type = WorkArea.AREATYPE_SOWINGMACHINE;
523 end;
524
525 return retValue;
526end;
527
528function SowingMachine.getDefaultSpeedLimit()
529 return 15;
530end;
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht