40 | function BunkerSilo:new(isServer, isClient, customMt) |
41 | local mt = customMt; |
42 | if mt == nil then |
43 | mt = BunkerSilo_mt; |
44 | end; |
45 | |
46 | local self = Object:new(isServer, isClient, mt); |
47 | self.nodeId = 0; |
48 | |
49 | self.acceptedFillTypes = {}; |
50 | self.inputFillType = FillUtil.FILLTYPE_CHAFF; |
51 | self.fermentingFillType = FillUtil.FILLTYPE_TARP; |
52 | self.outputFillType = FillUtil.FILLTYPE_SILAGE; |
53 | |
54 | self.fillLevel = 0; |
55 | self.compactedFillLevel = 0; |
56 | self.compactedPercent = 0; |
57 | |
58 | self.emptyThreshold = 100; |
59 | |
60 | self.fermentingTime = 0; |
61 | self.fermentingDuration = 6*60*60; -- 6hours (ingame) |
62 | self.fermentingPercent = 0; |
63 | |
64 | self.isOpenedAtFront = false; |
65 | self.isOpenedAtBack = false; |
66 | |
67 | self.distanceToCompactedFillLevel = 100; |
68 | |
69 | self.interactionTriggerId = nil; |
70 | |
71 | self.playerInRange = false; |
72 | self.vehiclesInRange = {}; |
73 | self.numVehiclesInRange = 0; |
74 | |
75 | self.bunkerSiloArea = {}; |
76 | self.bunkerSiloArea.offsetFront = 0; |
77 | self.bunkerSiloArea.offsetBack = 0 |
78 | |
79 | self.siloIsFullWarningTimer = 0; |
80 | self.siloIsFullWarningDuration = 2000; |
81 | |
82 | self.updateTimer = 0; |
83 | |
84 | self.activatable = BunkerSiloActivatable:new(self); |
85 | |
86 | self.state = BunkerSilo.STATE_FILL; |
87 | |
88 | self.bunkerSiloDirtyFlag = self:getNextDirtyFlag(); |
89 | return self; |
90 | end; |
194 | function BunkerSilo:load(nodeId) |
195 | |
196 | self.nodeId = nodeId; |
197 | |
198 | local areaNode = Utils.indexToObject(nodeId, getUserAttribute(nodeId, "bunkerSiloArea")); |
199 | if areaNode == nil then |
200 | print("Warning: BunkerSilo, could not resolve attribute 'bunkerSiloArea' into a valid node!"); |
201 | return false; |
202 | end |
203 | self.bunkerSiloArea.start = getChildAt(areaNode, 0); |
204 | self.bunkerSiloArea.width = getChildAt(areaNode, 1); |
205 | self.bunkerSiloArea.height = getChildAt(areaNode, 2); |
206 | |
207 | self.bunkerSiloArea.sx, self.bunkerSiloArea.sy, self.bunkerSiloArea.sz = getWorldTranslation(self.bunkerSiloArea.start); |
208 | self.bunkerSiloArea.wx, self.bunkerSiloArea.wy, self.bunkerSiloArea.wz = getWorldTranslation(self.bunkerSiloArea.width); |
209 | self.bunkerSiloArea.hx, self.bunkerSiloArea.hy, self.bunkerSiloArea.hz = getWorldTranslation(self.bunkerSiloArea.height); |
210 | |
211 | self.bunkerSiloArea.dhx = self.bunkerSiloArea.hx - self.bunkerSiloArea.sx; |
212 | self.bunkerSiloArea.dhy = self.bunkerSiloArea.hy - self.bunkerSiloArea.sy; |
213 | self.bunkerSiloArea.dhz = self.bunkerSiloArea.hz - self.bunkerSiloArea.sz; |
214 | local dhLength = Utils.vector3Length(self.bunkerSiloArea.dhx, self.bunkerSiloArea.dhy, self.bunkerSiloArea.dhz); |
215 | self.bunkerSiloArea.dhx_norm = self.bunkerSiloArea.dhx / dhLength; |
216 | self.bunkerSiloArea.dhy_norm = self.bunkerSiloArea.dhy / dhLength; |
217 | self.bunkerSiloArea.dhz_norm = self.bunkerSiloArea.dhz / dhLength; |
218 | |
219 | self.bunkerSiloArea.dwx = self.bunkerSiloArea.wx - self.bunkerSiloArea.sx; |
220 | self.bunkerSiloArea.dwy = self.bunkerSiloArea.wy - self.bunkerSiloArea.sy; |
221 | self.bunkerSiloArea.dwz = self.bunkerSiloArea.wz - self.bunkerSiloArea.sz; |
222 | local dwLength = Utils.vector3Length(self.bunkerSiloArea.dwx, self.bunkerSiloArea.dwy, self.bunkerSiloArea.dwz); |
223 | self.bunkerSiloArea.dwx_norm = self.bunkerSiloArea.dwx / dwLength; |
224 | self.bunkerSiloArea.dwy_norm = self.bunkerSiloArea.dwy / dwLength; |
225 | self.bunkerSiloArea.dwz_norm = self.bunkerSiloArea.dwz / dwLength; |
226 | |
227 | |
228 | self.acceptedFillTypes = {}; |
229 | local dataString = Utils.getNoNil(getUserAttribute(nodeId, "acceptedFillTypes"), "chaff grass_windrow dryGrass_windrow"); |
230 | local data = Utils.splitString(" ", dataString); |
231 | for i=1,table.getn(data) do |
232 | local fillType = FillUtil.fillTypeNameToInt[data[i] ]; |
233 | if fillType ~= nil then |
234 | self.acceptedFillTypes[fillType] = true; |
235 | else |
236 | print("Warning: BunkerSilo has an invalid fillType (acceptedFillTypes): "..tostring(data[i])); |
237 | end |
238 | end |
239 | |
240 | local dataString = Utils.getNoNil(getUserAttribute(nodeId, "inputFillType"), "chaff"); |
241 | local fillType = FillUtil.fillTypeNameToInt[dataString]; |
242 | if fillType ~= nil then |
243 | self.inputFillType = fillType; |
244 | else |
245 | print("Warning: BunkerSilo has an invalid fillType (inputFillType): "..tostring(dataString)); |
246 | end |
247 | |
248 | local dataString = Utils.getNoNil(getUserAttribute(nodeId, "outputFillType"), "silage"); |
249 | local fillType = FillUtil.fillTypeNameToInt[dataString]; |
250 | if fillType ~= nil then |
251 | self.outputFillType = fillType; |
252 | else |
253 | print("Warning: BunkerSilo has an invalid fillType (outputFillType): "..tostring(dataString)); |
254 | end |
255 | |
256 | if self.isServer then |
257 | TipUtil.setConvertingFillTypeAreas(self.bunkerSiloArea, self.acceptedFillTypes, self.inputFillType); |
258 | end |
259 | |
260 | |
261 | local distanceToCompactedFillLevelStr = getUserAttribute(nodeId, "distanceToCompactedFillLevel"); |
262 | if distanceToCompactedFillLevelStr ~= nil then |
263 | self.distanceToCompactedFillLevel = Utils.getNoNil(tonumber(distanceToCompactedFillLevelStr), self.distanceToCompactedFillLevel); |
264 | end; |
265 | |
266 | local fermentingDurationStr = getUserAttribute(nodeId, "fermentingDuration"); |
267 | if fermentingDurationStr ~= nil then |
268 | self.fermentingDuration = Utils.getNoNil(tonumber(fermentingDurationStr), self.fermentingDuration); |
269 | end; |
270 | |
271 | self.fillLevel = 0; |
272 | |
273 | local interactionTriggerIndex = getUserAttribute(nodeId, "interactionTriggerIndex"); |
274 | if interactionTriggerIndex ~= nil then |
275 | self.interactionTriggerId = Utils.indexToObject(nodeId, interactionTriggerIndex); |
276 | if self.interactionTriggerId ~= nil then |
277 | addTrigger(self.interactionTriggerId, "interactionTriggerCallback", self); |
278 | end; |
279 | end; |
280 | |
281 | self.openingLength = Utils.getNoNil(getUserAttribute(nodeId, "openingLength"), 5); |
282 | |
283 | -- adjust timings to difficulty |
284 | local difficultyMultiplier = g_currentMission.missionInfo.difficulty; |
285 | self.fermentingDuration = self.fermentingDuration*difficultyMultiplier; |
286 | self.distanceToCompactedFillLevel = self.distanceToCompactedFillLevel/difficultyMultiplier; |
287 | |
288 | -- just for tutorial 12 (feeder) |
289 | self.isTutorialSilo = Utils.getNoNil( getUserAttribute(nodeId, "isTutorialSilo"), false ); |
290 | |
291 | self.saveId = Utils.getNoNil( getUserAttribute(nodeId, "saveId"), "BunkerSilo_"..getName(nodeId) ); |
292 | |
293 | g_currentMission:addNodeObject(self.nodeId, self); |
294 | |
295 | self:setState(BunkerSilo.STATE_FILL); |
296 | |
297 | |
298 | return true; |
299 | end; |
306 | function BunkerSilo:loadFromAttributesAndNodes(xmlFile, key) |
307 | |
308 | local state = getXMLInt(xmlFile, key.."#state"); |
309 | if state ~= nil then |
310 | if state >= 0 and state < BunkerSilo.NUM_STATES then |
311 | self:setState(state); |
312 | end; |
313 | end; |
314 | |
315 | local fillLevel = getXMLFloat(xmlFile, key.."#fillLevel"); |
316 | if fillLevel ~= nil then |
317 | self.fillLevel = fillLevel; |
318 | end; |
319 | local compactedFillLevel = getXMLFloat(xmlFile, key.."#compactedFillLevel"); |
320 | if compactedFillLevel ~= nil then |
321 | self.compactedFillLevel = Utils.clamp(compactedFillLevel, 0, self.fillLevel); |
322 | end; |
323 | self.compactedPercent = Utils.getFlooredPercent(math.min(self.compactedFillLevel, self.fillLevel), self.fillLevel); |
324 | |
325 | local fermentingTime = getXMLFloat(xmlFile, key.."#fermentingTime"); |
326 | if fermentingTime ~= nil then |
327 | self.fermentingTime = Utils.clamp(fermentingTime, 0, self.fermentingDuration); |
328 | self.fermentingPercent = Utils.getFlooredPercent(self.fermentingTime, self.fermentingDuration); |
329 | end; |
330 | |
331 | self.isOpenedAtFront = Utils.getNoNil(getXMLBool(xmlFile, key.."#openedAtFront"), false); |
332 | self.isOpenedAtBack = Utils.getNoNil(getXMLBool(xmlFile, key.."#openedAtBack"), false); |
333 | |
334 | if self.isOpenedAtFront then |
335 | self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.outputFillType); |
336 | else |
337 | self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.fermentingFillType); |
338 | end |
339 | if self.isOpenedAtBack then |
340 | self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.outputFillType); |
341 | else |
342 | self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.fermentingFillType); |
343 | end |
344 | |
345 | if self.fillLevel > 0 and self.state == BunkerSilo.STATE_DRAIN then |
346 | local area = self.bunkerSiloArea; |
347 | local offWx = area.wx - area.sx; |
348 | local offWz = area.wz - area.sz; |
349 | local offW = math.sqrt(offWx*offWx + offWz*offWz); |
350 | |
351 | local offHx = area.hx - area.sx; |
352 | local offHz = area.hz - area.sz; |
353 | local offH = math.sqrt(offHx*offHx + offHz*offHz); |
354 | |
355 | if offW > 0.001 and offH > 0.001 then |
356 | -- offset by 0.9m in each direction (and max 45%) |
357 | local offWScale = math.min(0.45, 0.9 / offW); |
358 | offWx = offWx * offWScale; |
359 | offWz = offWz * offWScale; |
360 | |
361 | local offHScale = math.min(0.45, 0.9 / offH); |
362 | offHx = offHx * offHScale; |
363 | offHz = offHz * offHScale; |
364 | |
365 | local innerFillLevel1 = TipUtil.getFillLevelAtArea(self.fermentingFillType, area.sx+offWx+offHx,area.sz+offWz+offHz, area.wx-offWx+offHx,area.wz-offWz+offHz, area.hx+offWx-offHx,area.hz+offWz-offHz) |
366 | local innerFillLevel2 = TipUtil.getFillLevelAtArea(self.outputFillType, area.sx+offWx+offHx,area.sz+offWz+offHz, area.wx-offWx+offHx,area.wz-offWz+offHz, area.hx+offWx-offHx,area.hz+offWz-offHz) |
367 | local innerFillLevel = innerFillLevel1 + innerFillLevel2; |
368 | if innerFillLevel < self.emptyThreshold*0.5 then |
369 | TipUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.fermentingFillType); |
370 | TipUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.outputFillType); |
371 | self:setState(BunkerSilo.STATE_FILL, false); |
372 | end |
373 | end |
374 | elseif self.state == BunkerSilo.STATE_FILL then |
375 | local area = self.bunkerSiloArea; |
376 | local fermentingFillLevel, fermentingPixels, totalFermentingPixels = TipUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz); |
377 | -- Set to fermented state if more than 50% of the area is filled with fermenting fill type |
378 | if fermentingFillLevel > self.emptyThreshold and fermentingPixels > 0.5 * totalFermentingPixels then |
379 | local inputFillLevel, inputPixels, totalInputPixels = TipUtil.getFillLevelAtArea(self.inputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz); |
380 | -- Only change if less than 10% is filled with input type (chaff) (ie. the silo is not being filled) |
381 | if inputPixels < 0.1*totalInputPixels then |
382 | self:setState(BunkerSilo.STATE_FERMENTED, false); |
383 | end |
384 | end |
385 | end |
386 | |
387 | return true; |
388 | end; |
408 | function BunkerSilo:update(dt) |
409 | |
410 | if self:getCanInteract(true) then |
411 | local fillType = self.inputFillType; |
412 | if self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED or self.state == BunkerSilo.STATE_DRAIN then |
413 | fillType = self.outputFillType; |
414 | end |
415 | local fillTypeName = ""; |
416 | if FillUtil.fillTypeIndexToDesc[fillType] ~= nil then |
417 | fillTypeName = FillUtil.fillTypeIndexToDesc[fillType].nameI18N; |
418 | end |
419 | if self.state == BunkerSilo.STATE_FILL then |
420 | g_currentMission:addExtraPrintText(g_i18n:getText("info_fillLevel")..string.format(" %s: %d", fillTypeName, self.fillLevel)); |
421 | g_currentMission:addExtraPrintText(g_i18n:getText("info_compacting")..string.format(" %d%%", self.compactedPercent)); |
422 | elseif self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED then |
423 | g_currentMission:addExtraPrintText(g_i18n:getText("info_fermenting")..string.format(" %s: %d%%", fillTypeName, self.fermentingPercent)); |
424 | elseif self.state == BunkerSilo.STATE_DRAIN then |
425 | g_currentMission:addExtraPrintText(g_i18n:getText("info_fillLevel")..string.format(" %s: %d", fillTypeName, self.fillLevel)); |
426 | end; |
427 | end; |
428 | |
429 | if self.state == BunkerSilo.STATE_CLOSED then |
430 | if self.isServer then |
431 | self.fermentingTime = math.min(self.fermentingDuration, self.fermentingTime + dt*0.001*g_currentMission.missionInfo.timeScale); |
432 | local fermentingPercent = Utils.getFlooredPercent(self.fermentingTime, self.fermentingDuration); |
433 | if fermentingPercent ~= self.fermentingPercent then |
434 | self.fermentingPercent = fermentingPercent; |
435 | self:raiseDirtyFlags(self.bunkerSiloDirtyFlag); |
436 | end |
437 | if self.fermentingTime >= self.fermentingDuration then |
438 | self:setState(BunkerSilo.STATE_FERMENTED, true); |
439 | end; |
440 | end; |
441 | end; |
442 | |
443 | if self.isServer then |
444 | if self.state == BunkerSilo.STATE_FILL then |
445 | for vehicle,state in pairs(self.vehiclesInRange) do |
446 | if state then |
447 | if vehicle:getIsActive() then |
448 | local distance = vehicle.lastMovedDistance; |
449 | if distance > 0 then |
450 | local mass = vehicle:getTotalMass(false); |
451 | |
452 | local refNode = vehicle.bunkerSiloCompactingRefNode; |
453 | if refNode == nil then |
454 | refNode = vehicle.components[1].node; |
455 | end |
456 | local scale = (mass / BunkerSilo.COMPACTING_BASE_MASS) * Utils.getNoNil(vehicle.bunkerSiloCompactingScale, 1); |
457 | |
458 | local deltaCompact = distance*scale*self.distanceToCompactedFillLevel; |
459 | |
460 | local numWheels = table.getn(vehicle.wheels); |
461 | if numWheels > 0 then |
462 | local wheelsOnSilo = 0; |
463 | local wheelsInAir = 0; |
464 | for i=1,numWheels do |
465 | local wheel = vehicle.wheels[i]; |
466 | if wheel.contact == Vehicle.WHEEL_GROUND_HEIGHT_CONTACT then |
467 | wheelsOnSilo = wheelsOnSilo + 1; |
468 | elseif wheel.contact == Vehicle.WHEEL_NO_CONTACT then |
469 | wheelsInAir = wheelsInAir + 1; |
470 | end |
471 | end |
472 | if wheelsOnSilo > 0 then |
473 | deltaCompact = deltaCompact * ((wheelsOnSilo + wheelsInAir) / numWheels); |
474 | else |
475 | deltaCompact = 0; |
476 | end |
477 | end |
478 | |
479 | if deltaCompact > 0 then |
480 | local compactedFillLevel = math.min(self.compactedFillLevel + deltaCompact, self.fillLevel); |
481 | if compactedFillLevel ~= self.compactedFillLevel then |
482 | self.compactedFillLevel = compactedFillLevel; |
483 | self.compactedPercent = Utils.getFlooredPercent(math.min(self.compactedFillLevel, self.fillLevel), self.fillLevel); |
484 | self:raiseDirtyFlags(self.bunkerSiloDirtyFlag); |
485 | end |
486 | end |
487 | end; |
488 | end; |
489 | end |
490 | end; |
491 | end; |
492 | end; |
493 | |
494 | -- for chaff tutorial: always take the highest fill level of all bunker silos |
495 | if g_currentMission ~= nil and g_currentMission.bunkerScore ~= nil then |
496 | if g_currentMission.bunkerScore < self.fillLevel then |
497 | g_currentMission.bunkerScore = self.fillLevel; |
498 | end; |
499 | end; |
500 | end; |
556 | function BunkerSilo:setState(state, showNotification) |
557 | |
558 | if state ~= self.state then |
559 | |
560 | if state == BunkerSilo.STATE_FILL then |
561 | |
562 | self.fermentingTime = 0; |
563 | self.fermentingPercent = 0; |
564 | self.compactedFillLevel = 0; |
565 | self.isOpenedAtFront = false; |
566 | self.isOpenedAtBack = false; |
567 | self.bunkerSiloArea.offsetFront = 0; |
568 | self.bunkerSiloArea.offsetBack = 0; |
569 | |
570 | if showNotification then |
571 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ingameNotification_bunkerSiloIsEmpty")); |
572 | end |
573 | |
574 | if self.isServer then |
575 | TipUtil.removeFixedFillTypesArea(self.bunkerSiloArea); |
576 | TipUtil.setConvertingFillTypeAreas(self.bunkerSiloArea, self.acceptedFillTypes, self.inputFillType); |
577 | end |
578 | |
579 | elseif state == BunkerSilo.STATE_CLOSED then |
580 | |
581 | if self.isServer then |
582 | -- change fillType |
583 | local area = self.bunkerSiloArea; |
584 | local offsetFront = self:getBunkerAreaOffset(true, 0, self.inputFillType); |
585 | local offsetBack = self:getBunkerAreaOffset(false, 0, self.inputFillType); |
586 | |
587 | local x0 = area.sx + (offsetFront * area.dhx_norm); |
588 | local z0 = area.sz + (offsetFront * area.dhz_norm); |
589 | local x1 = x0 + area.dwx; |
590 | local z1 = z0 + area.dwz; |
591 | local x2 = area.sx + area.dhx - (offsetBack * area.dhx_norm); |
592 | local z2 = area.sz + area.dhz - (offsetBack * area.dhz_norm); |
593 | |
594 | local changed = TipUtil.changeFillTypeAtArea(x0,z0, x1,z1, x2,z2, self.inputFillType, self.fermentingFillType); |
595 | |
596 | TipUtil.removeFixedFillTypesArea(self.bunkerSiloArea); |
597 | TipUtil.removeConvertingFillTypeAreas(self.bunkerSiloArea); |
598 | end |
599 | |
600 | if showNotification then |
601 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ingameNotification_bunkerSiloCovered")); |
602 | end |
603 | |
604 | elseif state == BunkerSilo.STATE_FERMENTED then |
605 | |
606 | if showNotification then |
607 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ingameNotification_bunkerSiloDoneFermenting")); |
608 | end |
609 | |
610 | elseif state == BunkerSilo.STATE_DRAIN then |
611 | |
612 | self.bunkerSiloArea.offsetFront = 0; |
613 | self.bunkerSiloArea.offsetBack = 0; |
614 | |
615 | if showNotification then |
616 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ingameNotification_bunkerSiloOpened")); |
617 | end |
618 | |
619 | if self.isServer then |
620 | TipUtil.removeConvertingFillTypeAreas(self.bunkerSiloArea); |
621 | local fillTypes = {}; |
622 | fillTypes[self.outputFillType] = true; |
623 | TipUtil.setFixedFillTypesArea(self.bunkerSiloArea, fillTypes); |
624 | end |
625 | |
626 | end; |
627 | |
628 | self.state = state; |
629 | if self.isServer then |
630 | self:raiseDirtyFlags(self.bunkerSiloDirtyFlag); |
631 | end; |
632 | end; |
633 | end; |
640 | function BunkerSilo:openSilo(px,py,pz) |
641 | self:setState(BunkerSilo.STATE_DRAIN, true); |
642 | |
643 | self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.fermentingFillType); |
644 | self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.fermentingFillType); |
645 | |
646 | -- check which side is closer to player |
647 | local openAtFront = self:getIsCloserToFront(px,py,pz); |
648 | if openAtFront and not self.isOpenedAtFront then |
649 | self:switchFillTypeAtOffset(true, self.bunkerSiloArea.offsetFront, self.openingLength); |
650 | self.isOpenedAtFront = true; |
651 | self:raiseDirtyFlags(self.bunkerSiloDirtyFlag); |
652 | elseif not self.isOpenedAtBack then |
653 | self:switchFillTypeAtOffset(false, self.bunkerSiloArea.offsetBack, self.openingLength); |
654 | self.isOpenedAtBack = true; |
655 | self:raiseDirtyFlags(self.bunkerSiloDirtyFlag); |
656 | end |
657 | end |
665 | function BunkerSilo:getBunkerAreaOffset(updateAtFront, offset, fillType) |
666 | local area = self.bunkerSiloArea; |
667 | |
668 | local hx, hz = area.dhx_norm, area.dhz_norm; |
669 | local hl = Utils.vector3Length(area.dhx, area.dhy, area.dhz); |
670 | |
671 | while offset <= (hl - 1) do |
672 | local pos = offset; |
673 | if not updateAtFront then |
674 | pos = hl - offset - 1; |
675 | end |
676 | local d1x,d1z = pos*hx, pos*hz; |
677 | local d2x,d2z = (pos+1)*hx, (pos+1)*hz; |
678 | |
679 | local a0x, a0z = area.sx + d1x, area.sz + d1z; |
680 | local a1x, a1z = area.wx + d1x, area.wz + d1z; |
681 | local a2x, a2z = area.sx + d2x, area.sz + d2z; |
682 | |
683 | local fillLevel = TipUtil.getFillLevelAtArea(fillType, a0x,a0z, a1x,a1z, a2x,a2z); |
684 | if fillLevel > 0 then |
685 | return offset; |
686 | end |
687 | offset = offset + 1; |
688 | end |
689 | |
690 | return math.max(hl - 1, 0); |
691 | end |
698 | function BunkerSilo:switchFillTypeAtOffset(switchAtFront, offset, length) |
699 | |
700 | local fillType = self.fermentingFillType; |
701 | local newFillType = self.outputFillType; |
702 | |
703 | local a0x, a0z = nil, nil; |
704 | local a1x, a1z = nil, nil; |
705 | local a2x, a2z = nil, nil; |
706 | |
707 | local area = self.bunkerSiloArea; |
708 | |
709 | if switchAtFront then |
710 | a0x, a0z = area.sx + (offset * area.dhx_norm), area.sz + (offset * area.dhz_norm); |
711 | a1x, a1z = a0x + area.dwx, a0z + area.dwz; |
712 | a2x, a2z = area.sx + ((offset + length) * area.dhx_norm), area.sz + ((offset + length) * area.dhz_norm); |
713 | else |
714 | a0x, a0z = area.hx - (offset * area.dhx_norm), area.hz - (offset * area.dhz_norm); |
715 | a1x, a1z = a0x + area.dwx, a0z + area.dwz; |
716 | a2x, a2z = area.hx - ((offset + length) * area.dhx_norm), area.hz - ((offset + length) * area.dhz_norm); |
717 | end |
718 | |
719 | TipUtil.changeFillTypeAtArea(a0x,a0z, a1x,a1z, a2x,a2z, fillType, newFillType); |
720 | |
721 | end |
822 | function BunkerSilo:interactionTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId) |
823 | if onEnter or onLeave then |
824 | if g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then |
825 | if onEnter then |
826 | self.playerInRange = true; |
827 | g_currentMission:removeActivatableObject(self.activatable); -- make sure it is not added twice |
828 | g_currentMission:addActivatableObject(self.activatable); |
829 | else |
830 | self.playerInRange = false; |
831 | if self.numVehiclesInRange == 0 then |
832 | g_currentMission:removeActivatableObject(self.activatable); |
833 | end; |
834 | end; |
835 | else |
836 | --local vehicle = g_currentMission.nodeToVehicle[otherId]; |
837 | local vehicle = g_currentMission.nodeToVehicle[otherShapeId]; |
838 | if vehicle ~= nil then |
839 | if onEnter then |
840 | if self.vehiclesInRange[vehicle] == nil then |
841 | self.vehiclesInRange[vehicle] = true; |
842 | self.numVehiclesInRange = self.numVehiclesInRange + 1; |
843 | |
844 | g_currentMission:removeActivatableObject(self.activatable); -- make sure it is not added twice |
845 | g_currentMission:addActivatableObject(self.activatable); |
846 | |
847 | -- add callback if shovel |
848 | if vehicle.setChangedFillLevelCallback ~= nil then |
849 | vehicle:setChangedFillLevelCallback(BunkerSilo.onChangedFillLevelCallback, self); |
850 | end |
851 | end; |
852 | else |
853 | if self.vehiclesInRange[vehicle] then |
854 | self.vehiclesInRange[vehicle] = nil; |
855 | self.numVehiclesInRange = self.numVehiclesInRange - 1; |
856 | |
857 | if self.numVehiclesInRange == 0 and not self.playerInRange then |
858 | g_currentMission:removeActivatableObject(self.activatable); |
859 | end; |
860 | |
861 | -- remove callback if shovel |
862 | if vehicle.setChangedFillLevelCallback ~= nil then |
863 | vehicle:setChangedFillLevelCallback(nil); |
864 | end |
865 | end; |
866 | end; |
867 | end; |
868 | end; |
869 | end; |
870 | end; |
877 | function BunkerSilo.onChangedFillLevelCallback(self, shovel, fillDelta, fillType) |
878 | if fillDelta >= 0 then |
879 | return; |
880 | end |
881 | |
882 | local area = self.bunkerSiloArea; |
883 | |
884 | local x,y,z = getWorldTranslation(shovel.components[1].node); |
885 | local closerToFront = self:getIsCloserToFront(x,y,z); |
886 | |
887 | if shovel.pickUp ~= nil and shovel.pickUp.node ~= nil then |
888 | x,y,z = localToWorld(shovel.pickUp.node, 0, 0, shovel.pickUp.length); |
889 | end; |
890 | |
891 | local length = self.openingLength; |
892 | |
893 | if closerToFront then |
894 | if self.isOpenedAtFront then |
895 | local p1 = Utils.getProjectOnLineParameter(x,z, area.sx,area.sz, area.dhx_norm,area.dhz_norm); |
896 | if p1 > area.offsetFront - length then |
897 | local offset = self:getBunkerAreaOffset(true, area.offsetFront, self.fermentingFillType); |
898 | local targetOffset = math.max(p1, offset) + length; |
899 | |
900 | self:switchFillTypeAtOffset(true, area.offsetFront, targetOffset - area.offsetFront); |
901 | area.offsetFront = targetOffset; |
902 | end |
903 | end |
904 | else |
905 | if self.isOpenedAtBack then |
906 | local p1 = Utils.getProjectOnLineParameter(x,z, area.hx,area.hz, -area.dhx_norm,-area.dhz_norm); |
907 | if p1 > area.offsetBack - length then |
908 | local offset = self:getBunkerAreaOffset(true, area.offsetBack, self.fermentingFillType); |
909 | local targetOffset = math.max(p1, offset) + length; |
910 | |
911 | self:switchFillTypeAtOffset(false, area.offsetBack, targetOffset - area.offsetBack); |
912 | area.offsetBack = targetOffset; |
913 | end |
914 | end |
915 | end |
916 | end |