handleUndergroundLogisticsRemoval()   B
last analyzed

Complexity

Conditions 7
Paths 8

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 32.088

Importance

Changes 0
Metric Value
cc 7
eloc 22
nc 8
nop 2
dl 0
loc 37
ccs 5
cts 25
cp 0.2
crap 32.088
rs 8.6346
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Component\Building;
6
7
use Stu\Module\Building\Action\BuildingFunctionActionMapperInterface;
8
use Stu\Module\Commodity\CommodityTypeConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Module\Commodity\CommodityTypeConstants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Stu\Orm\Entity\Building;
10
use Stu\Orm\Entity\ColonyChangeable;
11
use Stu\Orm\Entity\Colony;
12
use Stu\Orm\Entity\ColonySandbox;
13
use Stu\Orm\Entity\PlanetField;
14
use Stu\Orm\Repository\ColonyRepositoryInterface;
15
use Stu\Orm\Repository\ColonySandboxRepositoryInterface;
16
use Stu\Orm\Repository\PlanetFieldRepositoryInterface;
17
18
/**
19
 * Manages actions relating to buildings on planets
20
 */
21
final class BuildingManager implements BuildingManagerInterface
22
{
23 19
    public function __construct(
24
        private readonly PlanetFieldRepositoryInterface $planetFieldRepository,
25
        private readonly ColonyRepositoryInterface $colonyRepository,
26
        private readonly ColonySandboxRepositoryInterface $colonySandboxRepository,
27
        private readonly BuildingFunctionActionMapperInterface $buildingFunctionActionMapper,
28
        private readonly BuildingPostActionInterface $buildingPostAction
29 19
    ) {}
30
31 7
    #[\Override]
32
    public function activate(PlanetField $field): bool
33
    {
34 7
        $building = $field->getBuilding();
35
36 7
        if ($building === null) {
37 1
            return false;
38
        }
39
40 6
        if (!$field->isActivateable()) {
41 2
            return false;
42
        }
43
44 4
        if ($field->isActive()) {
45 1
            return true;
46
        }
47
48 3
        if ($field->hasHighDamage()) {
49 1
            return false;
50
        }
51
52 2
        $changeable = $this->getChangeable($field);
53
54 2
        $workerAmount = $building->getWorkers();
55
56 2
        if ($changeable instanceof ColonyChangeable) {
57 2
            $worklessAmount = $changeable->getWorkless();
58 2
            if ($worklessAmount < $workerAmount) {
59 1
                return false;
60
            }
61
62 1
            $changeable->setWorkless($worklessAmount - $workerAmount);
63
        }
64
65 1
        $changeable
66 1
            ->setWorkers($changeable->getWorkers() + $workerAmount)
67 1
            ->setMaxBev($changeable->getMaxBev() + $building->getHousing());
68 1
        $field->setActive(1);
69
70 1
        $this->planetFieldRepository->save($field);
71
72 1
        $this->buildingPostAction->handleActivation($building, $field->getHost());
73
74 1
        $this->saveHost($field->getHost());
75
76 1
        return true;
77
    }
78
79 10
    #[\Override]
80
    public function deactivate(PlanetField $field): void
81
    {
82 10
        $building = $field->getBuilding();
83
84 10
        if ($building === null) {
85 1
            return;
86
        }
87
88 9
        if (!$field->isActivateable()) {
89 2
            return;
90
        }
91
92 7
        if (!$field->isActive()) {
93 1
            return;
94
        }
95
96 6
        $changeable = $this->getChangeable($field);
97
98 6
        $this->updateWorkerAndMaxBev($building, $changeable);
99 6
        $field->setActive(0);
100
101 6
        $this->planetFieldRepository->save($field);
102
103 6
        $this->buildingPostAction->handleDeactivation($building, $field->getHost());
104
105 6
        $this->saveHost($field->getHost());
106
    }
107
108 9
    private function saveHost(Colony|ColonySandbox $host): void
109
    {
110 9
        if ($host instanceof Colony) {
111 9
            $this->colonyRepository->save($host);
112
        } else {
113
            $this->colonySandboxRepository->save($host);
114
        }
115
    }
116
117 6
    private function updateWorkerAndMaxBev(Building $building, ColonyChangeable|ColonySandbox $host): void
118
    {
119 6
        $workerAmount = $building->getWorkers();
120
121 6
        if ($host instanceof ColonyChangeable) {
122 6
            $host->setWorkless($host->getWorkless() + $workerAmount);
123
        }
124 6
        $host->setWorkers($host->getWorkers() - $workerAmount);
125 6
        $host->setMaxBev($host->getMaxBev() - $building->getHousing());
126
    }
127
128 6
    #[\Override]
129
    public function remove(PlanetField $field, bool $isDueToUpgrade = false): void
130
    {
131 6
        $building = $field->getBuilding();
132 6
        if ($building === null) {
133 1
            return;
134
        }
135
136 5
        if (!$isDueToUpgrade && !$building->isRemovable()) {
137 1
            return;
138
        }
139
140 4
        $host = $field->getHost();
141 4
        $changeable = $this->getChangeable($field);
142 4
        $wasActive = $field->isActive();
143
144 4
        if (!$field->isUnderConstruction()) {
145 4
            if ($wasActive && $host instanceof Colony) {
146 3
                $this->handleUndergroundLogisticsRemoval($field, $host);
147 3
                if (!$isDueToUpgrade) {
148 2
                    $this->handleOrbitalMaintenanceRemoval($field, $host);
149
                }
150
            }
151
152 4
            $this->deactivate($field);
153
154 4
            $shouldUpdateStorageAndEps = true;
155 4
            if ($this->buildingRequiresUndergroundLogistics($building)) {
156
                $shouldUpdateStorageAndEps = $this->hasUndergroundLogisticsProduction($host);
157
            }
158
159 4
            if ($shouldUpdateStorageAndEps) {
160 4
                $changeable
161 4
                    ->setMaxStorage($changeable->getMaxStorage() - $building->getStorage())
162 4
                    ->setMaxEps($changeable->getMaxEps() - $building->getEpsStorage());
163
            }
164
        }
165
166 4
        foreach ($building->getFunctions() as $function) {
167 3
            $buildingFunction = $function->getFunction();
168
169 3
            $handler = $this->buildingFunctionActionMapper->map($buildingFunction);
170 3
            if ($handler !== null && $host instanceof Colony) {
171 3
                $handler->destruct($buildingFunction, $host);
172
            }
173
        }
174
175 4
        $field->clearBuilding();
176
177 4
        $this->planetFieldRepository->save($field);
178 4
        $this->saveHost($field->getHost());
179
    }
180
181 2
    #[\Override]
182
    public function finish(PlanetField $field, bool $activate = true): ?string
183
    {
184 2
        $building = $field->getBuilding();
185 2
        if ($building === null) {
186 1
            return null;
187
        }
188
189 1
        $changeable = $this->getChangeable($field);
190
191 1
        $field
192 1
            ->setActive(0)
193 1
            ->setIntegrity($building->getIntegrity());
194
195 1
        $shouldReactivateOthers = $field->getReactivateAfterUpgrade() === $field->getId();
196
197 1
        $activationDetails = null;
198 1
        if ($building->isActivateAble()) {
199 1
            if ($activate) {
200 1
                $activationDetails = $this->activate($field)
201
                    ? '[color=green]Und konnte wunschgemäß aktiviert werden[/color]'
202 1
                    : '[color=red]Konnte allerdings nicht wie gewünscht aktiviert werden[/color]';
203
            } else {
204
                $activationDetails = 'Und wurde wunschgemäß nicht aktiviert';
205
            }
206
        }
207
208 1
        $shouldUpdateStorageAndEps = true;
209 1
        if ($this->buildingRequiresUndergroundLogistics($building)) {
210
            $host = $field->getHost();
211
            if (!$this->hasEnoughUndergroundLogistics($host, $building)) {
212
                $shouldUpdateStorageAndEps = false;
213
            }
214
        }
215
216 1
        if ($shouldUpdateStorageAndEps) {
217 1
            $changeable
218 1
                ->setMaxStorage($changeable->getMaxStorage() + $building->getStorage())
219 1
                ->setMaxEps($changeable->getMaxEps() + $building->getEpsStorage());
220
        }
221
222 1
        $this->saveHost($field->getHost());
223 1
        $this->planetFieldRepository->save($field);
224
225 1
        $reactivatedCount = 0;
226 1
        if ($shouldReactivateOthers) {
227 1
            $host = $field->getHost();
228 1
            if ($host instanceof Colony) {
229 1
                $field->setReactivateAfterUpgrade(null);
230 1
                $this->planetFieldRepository->save($field);
231 1
                $reactivatedCount = $this->reactivateOrbitalBuildingsAfterUpgrade($host, $field->getId());
232
            }
233
        }
234
235 1
        if ($reactivatedCount > 0) {
236
            $activationDetails .= sprintf(' - Es wurden %d Orbitalgebäude reaktiviert', $reactivatedCount);
237
        }
238
239 1
        return $activationDetails;
240
    }
241
242 10
    private function getChangeable(PlanetField $field): ColonyChangeable|ColonySandbox
243
    {
244 10
        $host = $field->getHost();
245
246 10
        return $host instanceof ColonySandbox
247
            ? $host
248 10
            : $host->getChangeable();
249
    }
250
251 5
    private function buildingRequiresUndergroundLogistics(Building $building): bool
252
    {
253 5
        $logisticsCommodityId = CommodityTypeConstants::COMMODITY_EFFECT_UNDERGROUND_LOGISTICS;
254
255 5
        foreach ($building->getCommodities() as $buildingCommodity) {
256
            if ($buildingCommodity->getCommodityId() === $logisticsCommodityId && $buildingCommodity->getAmount() < 0) {
257
                return true;
258
            }
259
        }
260
261 5
        return false;
262
    }
263
264 3
    private function buildingProducesUndergroundLogistics(Building $building): bool
265
    {
266 3
        $logisticsCommodityId = CommodityTypeConstants::COMMODITY_EFFECT_UNDERGROUND_LOGISTICS;
267
268 3
        foreach ($building->getCommodities() as $buildingCommodity) {
269
            if ($buildingCommodity->getCommodityId() === $logisticsCommodityId && $buildingCommodity->getAmount() > 0) {
270
                return true;
271
            }
272
        }
273
274 3
        return false;
275
    }
276
277
    private function hasUndergroundLogisticsProduction(Colony|ColonySandbox $host): bool
278
    {
279
        $logisticsCommodityId = CommodityTypeConstants::COMMODITY_EFFECT_UNDERGROUND_LOGISTICS;
280
281
        $producingFields = $this->planetFieldRepository->getCommodityProducingByHostAndCommodity($host, $logisticsCommodityId);
282
283
        foreach ($producingFields as $field) {
284
            if ($field->isActive()) {
285
                return true;
286
            }
287
        }
288
289
        return false;
290
    }
291
292
    private function hasEnoughUndergroundLogistics(Colony|ColonySandbox $host, Building $building): bool
293
    {
294
        $logisticsCommodityId = CommodityTypeConstants::COMMODITY_EFFECT_UNDERGROUND_LOGISTICS;
295
296
        $production = 0;
297
        $consumption = 0;
298
299
        $producingFields = $this->planetFieldRepository->getCommodityProducingByHostAndCommodity($host, $logisticsCommodityId);
300
        foreach ($producingFields as $field) {
301
            if ($field->isActive() && $field->getBuilding() !== null) {
302
                foreach ($field->getBuilding()->getCommodities() as $commodity) {
303
                    if ($commodity->getCommodityId() === $logisticsCommodityId) {
304
                        $production += $commodity->getAmount();
305
                    }
306
                }
307
            }
308
        }
309
310
        $consumingFields = $this->planetFieldRepository->getCommodityConsumingByHostAndCommodity($host, $logisticsCommodityId, [1]);
311
        foreach ($consumingFields as $field) {
312
            if ($field->getBuilding() !== null) {
313
                foreach ($field->getBuilding()->getCommodities() as $commodity) {
314
                    if ($commodity->getCommodityId() === $logisticsCommodityId) {
315
                        $consumption += $commodity->getAmount();
316
                    }
317
                }
318
            }
319
        }
320
321
        $buildingConsumption = 0;
322
        foreach ($building->getCommodities() as $commodity) {
323
            if ($commodity->getCommodityId() === $logisticsCommodityId) {
324
                $buildingConsumption = $commodity->getAmount();
325
                break;
326
            }
327
        }
328
329
        return ($production + $consumption + $buildingConsumption) >= 0;
330
    }
331
332 3
    private function handleUndergroundLogisticsRemoval(PlanetField $field, Colony $host): void
333
    {
334 3
        $building = $field->getBuilding();
335 3
        if ($building === null) {
336
            return;
337
        }
338
339 3
        if (!$this->buildingProducesUndergroundLogistics($building)) {
340 3
            return;
341
        }
342
343
        $logisticsCommodityId = CommodityTypeConstants::COMMODITY_EFFECT_UNDERGROUND_LOGISTICS;
344
345
        $consumingFields = $this->planetFieldRepository->getCommodityConsumingByHostAndCommodity(
346
            $host,
347
            $logisticsCommodityId,
348
            [0, 1]
349
        );
350
351
        $totalStorage = 0;
352
        $totalEps = 0;
353
354
        foreach ($consumingFields as $consumingField) {
355
            $consumingBuilding = $consumingField->getBuilding();
356
            if ($consumingBuilding === null) {
357
                continue;
358
            }
359
360
            $totalStorage += $consumingBuilding->getStorage();
361
            $totalEps += $consumingBuilding->getEpsStorage();
362
        }
363
364
        if ($totalStorage > 0 || $totalEps > 0) {
365
            $changeable = $host->getChangeable();
366
            $changeable
367
                ->setMaxStorage($changeable->getMaxStorage() - $totalStorage)
368
                ->setMaxEps($changeable->getMaxEps() - $totalEps);
369
        }
370
    }
371
372 1
    private function reactivateOrbitalBuildingsAfterUpgrade(Colony $host, int $upgradedFieldId): int
373
    {
374 1
        $fieldsToReactivate = array_filter(
375 1
            $host->getPlanetFields()->toArray(),
376 1
            fn(PlanetField $f) => $f->getReactivateAfterUpgrade() === $upgradedFieldId
377 1
        );
378
379 1
        $reactivatedCount = 0;
380
381 1
        foreach ($fieldsToReactivate as $fieldToReactivate) {
382
            if ($this->activate($fieldToReactivate)) {
383
                $reactivatedCount++;
384
            }
385
            $fieldToReactivate->setReactivateAfterUpgrade(null);
386
            $this->planetFieldRepository->save($fieldToReactivate);
387
        }
388
389 1
        return $reactivatedCount;
390
    }
391
392 2
    private function handleOrbitalMaintenanceRemoval(PlanetField $field, Colony $host): void
393
    {
394 2
        $building = $field->getBuilding();
395 2
        if ($building === null) {
396
            return;
397
        }
398
399 2
        $maintenanceCommodityId = CommodityTypeConstants::COMMODITY_EFFECT_ORBITAL_MAINTENANCE;
400 2
        $producesMaintenance = false;
401
402 2
        foreach ($building->getCommodities() as $buildingCommodity) {
403
            if ($buildingCommodity->getCommodityId() === $maintenanceCommodityId && $buildingCommodity->getAmount() > 0) {
404
                $producesMaintenance = true;
405
                break;
406
            }
407
        }
408
409 2
        if (!$producesMaintenance) {
410 2
            return;
411
        }
412
413
        $consumingFields = $this->planetFieldRepository->getCommodityConsumingByHostAndCommodity(
414
            $host,
415
            $maintenanceCommodityId,
416
            [1]
417
        );
418
419
        foreach ($consumingFields as $consumingField) {
420
            if ($consumingField->isActive()) {
421
                $this->deactivate($consumingField);
422
            }
423
        }
424
    }
425
}
426