649 | function BunkerSilo:getBunkerAreaOffset(updateAtFront, offset, fillType) |
650 | local area = self.bunkerSiloArea |
651 | |
652 | local hx, hz = area.dhx_norm, area.dhz_norm |
653 | local hl = MathUtil.vector3Length(area.dhx, area.dhy, area.dhz) |
654 | |
655 | while offset <= (hl - 1) do |
656 | local pos = offset |
657 | if not updateAtFront then |
658 | pos = hl - offset - 1 |
659 | end |
660 | local d1x,d1z = pos*hx, pos*hz |
661 | local d2x,d2z = (pos+1)*hx, (pos+1)*hz |
662 | |
663 | local a0x, a0z = area.sx + d1x, area.sz + d1z |
664 | local a1x, a1z = area.wx + d1x, area.wz + d1z |
665 | local a2x, a2z = area.sx + d2x, area.sz + d2z |
666 | |
667 | local fillLevel = DensityMapHeightUtil.getFillLevelAtArea(fillType, a0x,a0z, a1x,a1z, a2x,a2z) |
668 | if fillLevel > 0 then |
669 | return offset |
670 | end |
671 | offset = offset + 1 |
672 | end |
673 | |
674 | return math.max(hl - 1, 0) |
675 | end |
854 | function BunkerSilo:interactionTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId) |
855 | if onEnter or onLeave then |
856 | if g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then |
857 | if onEnter then |
858 | self.playerInRange = true |
859 | g_currentMission.activatableObjectsSystem:addActivatable(self.activatable) |
860 | else |
861 | self.playerInRange = false |
862 | if self.numVehiclesInRange == 0 then |
863 | g_currentMission.activatableObjectsSystem:removeActivatable(self.activatable) |
864 | end |
865 | end |
866 | else |
867 | --local vehicle = g_currentMission.nodeToObject[otherId] |
868 | local vehicle = g_currentMission.nodeToObject[otherShapeId] |
869 | if vehicle ~= nil then |
870 | if onEnter then |
871 | if self.vehiclesInRange[vehicle] == nil then |
872 | self.vehiclesInRange[vehicle] = true |
873 | self.numVehiclesInRange = self.numVehiclesInRange + 1 |
874 | |
875 | g_currentMission.activatableObjectsSystem:addActivatable(self.activatable) |
876 | |
877 | -- add callback if shovel |
878 | if vehicle.setBunkerSiloInteractorCallback ~= nil then |
879 | vehicle:setBunkerSiloInteractorCallback(BunkerSilo.onChangedFillLevelCallback, self) |
880 | end |
881 | end |
882 | else |
883 | if self.vehiclesInRange[vehicle] then |
884 | self.vehiclesInRange[vehicle] = nil |
885 | self.numVehiclesInRange = self.numVehiclesInRange - 1 |
886 | |
887 | if self.numVehiclesInRange == 0 and not self.playerInRange then |
888 | g_currentMission.activatableObjectsSystem:removeActivatable(self.activatable) |
889 | end |
890 | |
891 | -- remove callback if shovel |
892 | if vehicle.setBunkerSiloInteractorCallback ~= nil then |
893 | vehicle:setBunkerSiloInteractorCallback(nil) |
894 | end |
895 | end |
896 | end |
897 | end |
898 | end |
899 | end |
900 | end |
86 | function BunkerSilo:load(components, xmlFile, key, i3dMappings) |
87 | self.bunkerSiloArea.start = xmlFile:getValue(key..".area#startNode", nil, components, i3dMappings) |
88 | self.bunkerSiloArea.width = xmlFile:getValue(key..".area#widthNode", nil, components, i3dMappings) |
89 | self.bunkerSiloArea.height = xmlFile:getValue(key..".area#heightNode", nil, components, i3dMappings) |
90 | |
91 | self.bunkerSiloArea.sx, self.bunkerSiloArea.sy, self.bunkerSiloArea.sz = getWorldTranslation(self.bunkerSiloArea.start) |
92 | self.bunkerSiloArea.wx, self.bunkerSiloArea.wy, self.bunkerSiloArea.wz = getWorldTranslation(self.bunkerSiloArea.width) |
93 | self.bunkerSiloArea.hx, self.bunkerSiloArea.hy, self.bunkerSiloArea.hz = getWorldTranslation(self.bunkerSiloArea.height) |
94 | |
95 | self.bunkerSiloArea.dhx = self.bunkerSiloArea.hx - self.bunkerSiloArea.sx |
96 | self.bunkerSiloArea.dhy = self.bunkerSiloArea.hy - self.bunkerSiloArea.sy |
97 | self.bunkerSiloArea.dhz = self.bunkerSiloArea.hz - self.bunkerSiloArea.sz |
98 | self.bunkerSiloArea.dhx_norm, self.bunkerSiloArea.dhy_norm, self.bunkerSiloArea.dhz_norm = MathUtil.vector3Normalize(self.bunkerSiloArea.dhx, self.bunkerSiloArea.dhy, self.bunkerSiloArea.dhz) |
99 | |
100 | self.bunkerSiloArea.dwx = self.bunkerSiloArea.wx - self.bunkerSiloArea.sx |
101 | self.bunkerSiloArea.dwy = self.bunkerSiloArea.wy - self.bunkerSiloArea.sy |
102 | self.bunkerSiloArea.dwz = self.bunkerSiloArea.wz - self.bunkerSiloArea.sz |
103 | self.bunkerSiloArea.dwx_norm, self.bunkerSiloArea.dwy_norm, self.bunkerSiloArea.dwz_norm = MathUtil.vector3Normalize(self.bunkerSiloArea.dwx, self.bunkerSiloArea.dwy, self.bunkerSiloArea.dwz) |
104 | |
105 | self.bunkerSiloArea.inner = {} |
106 | self.bunkerSiloArea.inner.start = xmlFile:getValue(key..".innerArea#startNode", self.bunkerSiloArea.start, components, i3dMappings) |
107 | self.bunkerSiloArea.inner.width = xmlFile:getValue(key..".innerArea#widthNode", self.bunkerSiloArea.width, components, i3dMappings) |
108 | self.bunkerSiloArea.inner.height = xmlFile:getValue(key..".innerArea#heightNode", self.bunkerSiloArea.height, components, i3dMappings) |
109 | |
110 | self.bunkerSiloArea.inner.sx, self.bunkerSiloArea.inner.sy, self.bunkerSiloArea.inner.sz = getWorldTranslation(self.bunkerSiloArea.inner.start) |
111 | self.bunkerSiloArea.inner.wx, self.bunkerSiloArea.inner.wy, self.bunkerSiloArea.inner.wz = getWorldTranslation(self.bunkerSiloArea.inner.width) |
112 | self.bunkerSiloArea.inner.hx, self.bunkerSiloArea.inner.hy, self.bunkerSiloArea.inner.hz = getWorldTranslation(self.bunkerSiloArea.inner.height) |
113 | |
114 | self.interactionTriggerNode = xmlFile:getValue(key..".interactionTrigger#node", nil, components, i3dMappings) |
115 | if self.interactionTriggerNode ~= nil then |
116 | addTrigger(self.interactionTriggerNode, "interactionTriggerCallback", self) |
117 | end |
118 | |
119 | self.acceptedFillTypes = {} |
120 | local data = xmlFile:getValue(key.."#acceptedFillTypes", "chaff grass_windrow dryGrass_windrow"):split(" ") |
121 | for i=1, table.getn(data) do |
122 | local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(data[i]) |
123 | if fillTypeIndex ~= nil then |
124 | self.acceptedFillTypes[fillTypeIndex] = true |
125 | else |
126 | Logging.warning("'%s' is an invalid fillType for bunkerSilo '%s'!", tostring(data[i]), key.."#acceptedFillTypes") |
127 | end |
128 | end |
129 | |
130 | local inputFillTypeName = xmlFile:getValue(key.."#inputFillType", "chaff") |
131 | local inputFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(inputFillTypeName) |
132 | if inputFillTypeIndex ~= nil then |
133 | self.inputFillType = inputFillTypeIndex |
134 | else |
135 | Logging.warning("'%s' is an invalid input fillType for bunkerSilo '%s'!", tostring(inputFillTypeName), key.."#inputFillType") |
136 | end |
137 | |
138 | local outputFillTypeName = xmlFile:getValue(key.."#outputFillType", "silage") |
139 | local outputFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(outputFillTypeName) |
140 | if outputFillTypeIndex ~= nil then |
141 | self.outputFillType = outputFillTypeIndex |
142 | else |
143 | Logging.warning("'%s' is an invalid output fillType for bunkerSilo '%s'!", tostring(outputFillTypeName), key.."#outputFillType") |
144 | end |
145 | |
146 | g_densityMapHeightManager:setConvertingFillTypeAreas(self.bunkerSiloArea, self.acceptedFillTypes, self.inputFillType) |
147 | |
148 | self.distanceToCompactedFillLevel = xmlFile:getValue(key.."#distanceToCompactedFillLevel", self.distanceToCompactedFillLevel) |
149 | self.openingLength = xmlFile:getValue(key.."#openingLength", 5) |
150 | |
151 | local leftWallNode = xmlFile:getValue(key .. ".wallLeft#node", nil, components, i3dMappings) |
152 | if leftWallNode ~= nil then |
153 | self.wallLeft = {} |
154 | self.wallLeft.node = leftWallNode |
155 | self.wallLeft.visible = true |
156 | self.wallLeft.collision = xmlFile:getValue(key .. ".wallLeft#collision", nil, components, i3dMappings) |
157 | end |
158 | |
159 | local rightWallNode = xmlFile:getValue(key .. ".wallRight#node", nil, components, i3dMappings) |
160 | if rightWallNode ~= nil then |
161 | self.wallRight = {} |
162 | self.wallRight.node = rightWallNode |
163 | self.wallRight.visible = true |
164 | self.wallRight.collision = xmlFile:getValue(key .. ".wallRight#collision", nil, components, i3dMappings) |
165 | end |
166 | |
167 | self.fillLevel = 0 |
168 | |
169 | -- adjust timings to difficulty |
170 | local difficultyMultiplier = g_currentMission.missionInfo.economicDifficulty |
171 | self.distanceToCompactedFillLevel = self.distanceToCompactedFillLevel/difficultyMultiplier |
172 | |
173 | self:setState(BunkerSilo.STATE_FILL) |
174 | |
175 | return true |
176 | end |
284 | function BunkerSilo:loadFromXMLFile(xmlFile, key) |
285 | |
286 | local state = xmlFile:getValue(key.."#state") |
287 | if state ~= nil then |
288 | if state >= 0 and state < BunkerSilo.NUM_STATES then |
289 | self:setState(state) |
290 | end |
291 | end |
292 | |
293 | local fillLevel = xmlFile:getValue(key.."#fillLevel") |
294 | if fillLevel ~= nil then |
295 | self.fillLevel = fillLevel |
296 | end |
297 | local compactedFillLevel = xmlFile:getValue(key.."#compactedFillLevel") |
298 | if compactedFillLevel ~= nil then |
299 | self.compactedFillLevel = MathUtil.clamp(compactedFillLevel, 0, self.fillLevel) |
300 | end |
301 | self.compactedPercent = MathUtil.getFlooredPercent(math.min(self.compactedFillLevel, self.fillLevel), self.fillLevel) |
302 | |
303 | local fermentingTime = xmlFile:getValue(key.."#fermentingTime") |
304 | if fermentingTime ~= nil then |
305 | -- Convert to percent |
306 | self.fermentingPercent = fermentingTime / (BunkerSilo.MILLISECONDS_PER_DAY * g_currentMission.environment.daysPerPeriod) |
307 | end |
308 | |
309 | self.isOpenedAtFront = xmlFile:getValue(key.."#openedAtFront", false) |
310 | self.isOpenedAtBack = xmlFile:getValue(key.."#openedAtBack", false) |
311 | |
312 | if self.isOpenedAtFront then |
313 | self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.outputFillType) |
314 | else |
315 | self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.fermentingFillType) |
316 | end |
317 | if self.isOpenedAtBack then |
318 | self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.outputFillType) |
319 | else |
320 | self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.fermentingFillType) |
321 | end |
322 | |
323 | if self.fillLevel > 0 and self.state == BunkerSilo.STATE_DRAIN then |
324 | local area = self.bunkerSiloArea |
325 | local offWx = area.wx - area.sx |
326 | local offWz = area.wz - area.sz |
327 | local offW = math.sqrt(offWx*offWx + offWz*offWz) |
328 | |
329 | local offHx = area.hx - area.sx |
330 | local offHz = area.hz - area.sz |
331 | local offH = math.sqrt(offHx*offHx + offHz*offHz) |
332 | |
333 | if offW > 0.001 and offH > 0.001 then |
334 | -- offset by 0.9m in each direction (and max 45%) |
335 | local offWScale = math.min(0.45, 0.9 / offW) |
336 | offWx = offWx * offWScale |
337 | offWz = offWz * offWScale |
338 | |
339 | local offHScale = math.min(0.45, 0.9 / offH) |
340 | offHx = offHx * offHScale |
341 | offHz = offHz * offHScale |
342 | |
343 | local innerFillLevel1 = DensityMapHeightUtil.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) |
344 | local innerFillLevel2 = DensityMapHeightUtil.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) |
345 | local innerFillLevel = innerFillLevel1 + innerFillLevel2 |
346 | if innerFillLevel < self.emptyThreshold*0.5 then |
347 | DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.fermentingFillType) |
348 | DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.outputFillType) |
349 | self:setState(BunkerSilo.STATE_FILL, false) |
350 | end |
351 | end |
352 | |
353 | DensityMapHeightUtil.changeFillTypeAtArea(area.sx, area.sz, area.wx, area.wz, area.hx, area.hz, self.inputFillType, self.outputFillType) |
354 | elseif self.fillLevel > 0 and (self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED) then |
355 | local area = self.bunkerSiloArea |
356 | DensityMapHeightUtil.changeFillTypeAtArea(area.sx, area.sz, area.wx, area.wz, area.hx, area.hz, self.inputFillType, self.fermentingFillType) |
357 | elseif self.state == BunkerSilo.STATE_FILL then |
358 | local area = self.bunkerSiloArea |
359 | local fermentingFillLevel, fermentingPixels, totalFermentingPixels = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
360 | -- Set to fermented state if more than 50% of the area is filled with fermenting fill type |
361 | if fermentingFillLevel > self.emptyThreshold and fermentingPixels > 0.5 * totalFermentingPixels then |
362 | local inputFillLevel, inputPixels, totalInputPixels = DensityMapHeightUtil.getFillLevelAtArea(self.inputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
363 | -- Only change if less than 10% is filled with input type (chaff) (ie. the silo is not being filled) |
364 | if inputPixels < 0.1*totalInputPixels then |
365 | self:setState(BunkerSilo.STATE_FERMENTED, false) |
366 | end |
367 | end |
368 | end |
369 | |
370 | return true |
371 | end |
33 | function BunkerSilo.new(isServer, isClient, customMt) |
34 | local self = Object.new(isServer, isClient, customMt or BunkerSilo_mt) |
35 | |
36 | self.interactionTriggerNode = nil |
37 | |
38 | self.bunkerSiloArea = {} |
39 | self.bunkerSiloArea.offsetFront = 0 |
40 | self.bunkerSiloArea.offsetBack = 0 |
41 | |
42 | self.acceptedFillTypes = {} |
43 | |
44 | self.inputFillType = FillType.CHAFF |
45 | self.outputFillType = FillType.SILAGE |
46 | self.fermentingFillType = FillType.TARP |
47 | |
48 | self.isOpenedAtFront = false |
49 | self.isOpenedAtBack = false |
50 | self.distanceToCompactedFillLevel = 100 |
51 | |
52 | self.fermentingPercent = 0 |
53 | |
54 | self.fillLevel = 0 |
55 | self.compactedFillLevel = 0 |
56 | self.compactedPercent = 0 |
57 | self.emptyThreshold = 100 |
58 | |
59 | self.playerInRange = false |
60 | self.vehiclesInRange = {} |
61 | self.numVehiclesInRange = 0 |
62 | |
63 | self.siloIsFullWarningTimer = 0 |
64 | self.siloIsFullWarningDuration = 2000 |
65 | |
66 | self.updateTimer = 0 |
67 | |
68 | self.activatable = BunkerSiloActivatable.new(self) |
69 | |
70 | self.state = BunkerSilo.STATE_FILL |
71 | |
72 | self.bunkerSiloDirtyFlag = self:getNextDirtyFlag() |
73 | |
74 | g_messageCenter:subscribe(MessageType.HOUR_CHANGED, self.onHourChanged, self) |
75 | |
76 | return self |
77 | end |
907 | function BunkerSilo.onChangedFillLevelCallback(self, vehicle, fillDelta, fillType, x, y, z) |
908 | if fillDelta >= 0 then |
909 | return |
910 | end |
911 | |
912 | local area = self.bunkerSiloArea |
913 | if x == nil or y == nil or z == nil then |
914 | x, y, z = getWorldTranslation(vehicle.components[1].node) |
915 | end |
916 | |
917 | local closerToFront = self:getIsCloserToFront(x, y, z) |
918 | local length = self.openingLength |
919 | |
920 | if closerToFront then |
921 | if self.isOpenedAtFront then |
922 | local p1 = MathUtil.getProjectOnLineParameter(x,z, area.sx,area.sz, area.dhx_norm,area.dhz_norm) |
923 | if p1 > area.offsetFront - length then |
924 | local offset = self:getBunkerAreaOffset(true, area.offsetFront, self.fermentingFillType) |
925 | local targetOffset = math.max(p1, offset) + length |
926 | |
927 | self:switchFillTypeAtOffset(true, area.offsetFront, targetOffset - area.offsetFront) |
928 | area.offsetFront = targetOffset |
929 | end |
930 | end |
931 | else |
932 | if self.isOpenedAtBack then |
933 | local p1 = MathUtil.getProjectOnLineParameter(x,z, area.hx,area.hz, -area.dhx_norm,-area.dhz_norm) |
934 | if p1 > area.offsetBack - length then |
935 | local offset = self:getBunkerAreaOffset(false, area.offsetBack, self.fermentingFillType) |
936 | local targetOffset = math.max(p1, offset) + length |
937 | |
938 | self:switchFillTypeAtOffset(false, area.offsetBack, targetOffset - area.offsetBack) |
939 | area.offsetBack = targetOffset |
940 | end |
941 | end |
942 | end |
943 | end |
947 | function BunkerSilo.registerXMLPaths(schema, basePath) |
948 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".area#startNode", "Area start node (placed in the middle of the walls)") |
949 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".area#widthNode", "Area width node (placed in the middle of the walls)") |
950 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".area#heightNode", "Area height node (placed in the middle of the walls)") |
951 | |
952 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".innerArea#startNode", "Inner area start node (Used to detect fill level - placed 25cm from inner walls)") |
953 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".innerArea#widthNode", "Inner area width node (Used to detect fill level - placed 25cm from inner walls)") |
954 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".innerArea#heightNode", "Inner area height node (Used to detect fill level - placed 25cm from inner walls)") |
955 | |
956 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".wallLeft#node", "Left wall node") |
957 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".wallLeft#collision", "Left wall collision") |
958 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".wallRight#node", "Right wall node") |
959 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".wallRight#collision", "Right wall collision") |
960 | |
961 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".interactionTrigger#node", "Interaction trigger node") |
962 | schema:register(XMLValueType.STRING, basePath .. "#acceptedFillTypes", "Accepted fill types", "chaff grass_windrow dryGrass_windrow") |
963 | schema:register(XMLValueType.STRING, basePath .. "#inputFillType", "Input fill type", "chaff") |
964 | schema:register(XMLValueType.STRING, basePath .. "#outputFillType", "Output fill type", "silage") |
965 | |
966 | schema:register(XMLValueType.FLOAT, basePath .. "#distanceToCompactedFillLevel", "Distance to drive on bunker silo for full compaction", 100) |
967 | schema:register(XMLValueType.FLOAT, basePath .. "#openingLength", "Opening length", 5) |
968 | end |
537 | function BunkerSilo:setState(state, showNotification) |
538 | if state ~= self.state then |
539 | if state == BunkerSilo.STATE_FILL then |
540 | self.fermentingPercent = 0 |
541 | self.compactedFillLevel = 0 |
542 | self.compactedPercent = 0 |
543 | self.isOpenedAtFront = false |
544 | self.isOpenedAtBack = false |
545 | self.bunkerSiloArea.offsetFront = 0 |
546 | self.bunkerSiloArea.offsetBack = 0 |
547 | |
548 | if showNotification then |
549 | self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloIsEmpty")) |
550 | end |
551 | |
552 | if self.isServer then |
553 | g_densityMapHeightManager:removeFixedFillTypesArea(self.bunkerSiloArea) |
554 | g_densityMapHeightManager:setConvertingFillTypeAreas(self.bunkerSiloArea, self.acceptedFillTypes, self.inputFillType) |
555 | end |
556 | |
557 | elseif state == BunkerSilo.STATE_CLOSED then |
558 | |
559 | if self.isServer then |
560 | -- change fillType |
561 | local area = self.bunkerSiloArea |
562 | local offsetFront = self:getBunkerAreaOffset(true, 0, self.inputFillType) |
563 | local offsetBack = self:getBunkerAreaOffset(false, 0, self.inputFillType) |
564 | |
565 | local x0 = area.sx + (offsetFront * area.dhx_norm) |
566 | local z0 = area.sz + (offsetFront * area.dhz_norm) |
567 | local x1 = x0 + area.dwx |
568 | local z1 = z0 + area.dwz |
569 | local x2 = area.sx + area.dhx - (offsetBack * area.dhx_norm) |
570 | local z2 = area.sz + area.dhz - (offsetBack * area.dhz_norm) |
571 | |
572 | local changed = DensityMapHeightUtil.changeFillTypeAtArea(x0,z0, x1,z1, x2,z2, self.inputFillType, self.fermentingFillType) |
573 | |
574 | g_densityMapHeightManager:removeFixedFillTypesArea(self.bunkerSiloArea) |
575 | g_densityMapHeightManager:removeConvertingFillTypeAreas(self.bunkerSiloArea) |
576 | end |
577 | |
578 | if showNotification then |
579 | self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloCovered")) |
580 | end |
581 | |
582 | elseif state == BunkerSilo.STATE_FERMENTED then |
583 | |
584 | if showNotification then |
585 | self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloDoneFermenting")) |
586 | end |
587 | |
588 | elseif state == BunkerSilo.STATE_DRAIN then |
589 | |
590 | self.bunkerSiloArea.offsetFront = 0 |
591 | self.bunkerSiloArea.offsetBack = 0 |
592 | |
593 | if showNotification then |
594 | self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloOpened")) |
595 | end |
596 | |
597 | if self.isServer then |
598 | g_densityMapHeightManager:removeConvertingFillTypeAreas(self.bunkerSiloArea) |
599 | local fillTypes = {} |
600 | fillTypes[self.outputFillType] = true |
601 | g_densityMapHeightManager:setFixedFillTypesArea(self.bunkerSiloArea, fillTypes) |
602 | end |
603 | |
604 | end |
605 | |
606 | self.state = state |
607 | if self.isServer then |
608 | self:raiseDirtyFlags(self.bunkerSiloDirtyFlag) |
609 | end |
610 | end |
611 | end |
682 | function BunkerSilo:switchFillTypeAtOffset(switchAtFront, offset, length) |
683 | |
684 | local fillType = self.fermentingFillType |
685 | local newFillType = self.outputFillType |
686 | |
687 | local a0x, a0z |
688 | local a1x, a1z |
689 | local a2x, a2z |
690 | |
691 | local area = self.bunkerSiloArea |
692 | |
693 | if switchAtFront then |
694 | a0x, a0z = area.sx + (offset * area.dhx_norm), area.sz + (offset * area.dhz_norm) |
695 | a1x, a1z = a0x + area.dwx, a0z + area.dwz |
696 | a2x, a2z = area.sx + ((offset + length) * area.dhx_norm), area.sz + ((offset + length) * area.dhz_norm) |
697 | else |
698 | a0x, a0z = area.hx - (offset * area.dhx_norm), area.hz - (offset * area.dhz_norm) |
699 | a1x, a1z = a0x + area.dwx, a0z + area.dwz |
700 | a2x, a2z = area.hx - ((offset + length) * area.dhx_norm), area.hz - ((offset + length) * area.dhz_norm) |
701 | end |
702 | |
703 | DensityMapHeightUtil.changeFillTypeAtArea(a0x,a0z, a1x,a1z, a2x,a2z, fillType, newFillType) |
704 | |
705 | end |
390 | function BunkerSilo:update(dt) |
391 | if self:getCanInteract(true) then |
392 | local fillTypeIndex = self.inputFillType |
393 | if self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED or self.state == BunkerSilo.STATE_DRAIN then |
394 | fillTypeIndex = self.outputFillType |
395 | end |
396 | local fillTypeName = "" |
397 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex) |
398 | if fillType ~= nil then |
399 | fillTypeName = fillType.title |
400 | end |
401 | if self.state == BunkerSilo.STATE_FILL then |
402 | g_currentMission:addExtraPrintText(g_i18n:getText("info_fillLevel")..string.format(" %s: %d", fillTypeName, self.fillLevel)) |
403 | g_currentMission:addExtraPrintText(g_i18n:getText("info_compacting")..string.format(" %d%%", self.compactedPercent)) |
404 | elseif self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED then |
405 | g_currentMission:addExtraPrintText(g_i18n:getText("info_fermenting")..string.format(" %s: %d%%", fillTypeName, math.ceil(self.fermentingPercent * 100))) |
406 | elseif self.state == BunkerSilo.STATE_DRAIN then |
407 | g_currentMission:addExtraPrintText(g_i18n:getText("info_fillLevel")..string.format(" %s: %d", fillTypeName, self.fillLevel)) |
408 | end |
409 | end |
410 | |
411 | if self.isServer then |
412 | if self.state == BunkerSilo.STATE_FILL then |
413 | for vehicle,state in pairs(self.vehiclesInRange) do |
414 | if state then |
415 | if vehicle:getIsActive() then |
416 | local distance = vehicle.lastMovedDistance |
417 | if distance > 0 then |
418 | local mass = vehicle:getTotalMass(false) |
419 | |
420 | local compactingFactor = (mass / BunkerSilo.COMPACTING_BASE_MASS) |
421 | |
422 | local compactingScale = 1 |
423 | if vehicle.getBunkerSiloCompacterScale ~= nil then |
424 | compactingScale = vehicle:getBunkerSiloCompacterScale() or compactingScale |
425 | end |
426 | compactingFactor = compactingFactor * compactingScale |
427 | |
428 | local deltaCompact = distance*compactingFactor*self.distanceToCompactedFillLevel |
429 | |
430 | if vehicle.getWheels ~= nil then |
431 | local wheels = vehicle:getWheels() |
432 | local numWheels = #wheels |
433 | if numWheels > 0 then |
434 | local wheelsOnSilo = 0 |
435 | local wheelsInAir = 0 |
436 | for _, wheel in ipairs(wheels) do |
437 | if wheel.contact == Wheels.WHEEL_GROUND_HEIGHT_CONTACT then |
438 | wheelsOnSilo = wheelsOnSilo + 1 |
439 | elseif wheel.contact == Wheels.WHEEL_NO_CONTACT then |
440 | wheelsInAir = wheelsInAir + 1 |
441 | end |
442 | end |
443 | if wheelsOnSilo > 0 then |
444 | deltaCompact = deltaCompact * ((wheelsOnSilo + wheelsInAir) / numWheels) |
445 | else |
446 | deltaCompact = 0 |
447 | end |
448 | end |
449 | end |
450 | |
451 | if deltaCompact > 0 then |
452 | local compactedFillLevel = math.min(self.compactedFillLevel + deltaCompact, self.fillLevel) |
453 | if compactedFillLevel ~= self.compactedFillLevel then |
454 | self:updateCompacting(compactedFillLevel) |
455 | end |
456 | end |
457 | end |
458 | end |
459 | end |
460 | end |
461 | end |
462 | end |
463 | |
464 | -- for chaff tutorial: always take the highest fill level of all bunker silos |
465 | if g_currentMission ~= nil and g_currentMission.bunkerScore ~= nil then |
466 | if g_currentMission.bunkerScore < self.fillLevel then |
467 | g_currentMission.bunkerScore = self.fillLevel |
468 | end |
469 | end |
470 | |
471 | self:raiseActive() |
472 | end |
504 | function BunkerSilo:updateFillLevel() |
505 | local area = self.bunkerSiloArea.inner |
506 | local fillLevel = self.fillLevel |
507 | local fillType = self.inputFillType |
508 | |
509 | if fillType ~= FillType.UNKNOWN then |
510 | if self.state == BunkerSilo.STATE_FILL then |
511 | fillLevel = DensityMapHeightUtil.getFillLevelAtArea(fillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
512 | elseif self.state == BunkerSilo.STATE_CLOSED then |
513 | fillLevel = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
514 | elseif self.state == BunkerSilo.STATE_FERMENTED then |
515 | local fillLevel1 = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
516 | local fillLevel2 = DensityMapHeightUtil.getFillLevelAtArea(self.outputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
517 | fillLevel = fillLevel1 + fillLevel2 |
518 | elseif self.state == BunkerSilo.STATE_DRAIN then |
519 | local fillLevel1 = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
520 | local fillLevel2 = DensityMapHeightUtil.getFillLevelAtArea(self.outputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz) |
521 | fillLevel = fillLevel1 + fillLevel2 |
522 | if fillLevel < self.emptyThreshold then |
523 | DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.fermentingFillType) |
524 | DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.outputFillType) |
525 | self:setState(BunkerSilo.STATE_FILL, true) |
526 | end |
527 | end |
528 | end |
529 | |
530 | self.fillLevel = fillLevel |
531 | end |