Test Failed
Pull Request — master (#1771)
by Nico
21:05 queued 10:28
created

BuildOnField::performSessionCheck()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Colony\Action\BuildOnField;
6
7
use request;
8
use Stu\Component\Building\BuildingManagerInterface;
9
use Stu\Component\Colony\Storage\ColonyStorageManagerInterface;
10
use Stu\Lib\Colony\PlanetFieldHostProviderInterface;
11
use Stu\Module\Colony\Lib\BuildingActionInterface;
12
use Stu\Module\Colony\Lib\PlanetFieldTypeRetrieverInterface;
13
use Stu\Module\Colony\View\ShowInformation\ShowInformation;
14
use Stu\Module\Control\ActionControllerInterface;
15
use Stu\Module\Control\GameControllerInterface;
16
use Stu\Module\PlayerSetting\Lib\UserEnum;
17
use Stu\Orm\Entity\BuildingCostInterface;
18
use Stu\Orm\Entity\BuildingInterface;
19
use Stu\Orm\Entity\ColonyInterface;
20
use Stu\Orm\Entity\ColonySandboxInterface;
21
use Stu\Orm\Entity\PlanetFieldInterface;
22
use Stu\Orm\Repository\BuildingFieldAlternativeRepositoryInterface;
23
use Stu\Orm\Repository\BuildingRepositoryInterface;
24
use Stu\Orm\Repository\ColonyRepositoryInterface;
25
use Stu\Orm\Repository\PlanetFieldRepositoryInterface;
26
use Stu\Orm\Repository\ResearchedRepositoryInterface;
27
28
final class BuildOnField implements ActionControllerInterface
29
{
30
    public const ACTION_IDENTIFIER = 'B_BUILD';
31
32
    private PlanetFieldHostProviderInterface $planetFieldHostProvider;
33
34
    private BuildingFieldAlternativeRepositoryInterface $buildingFieldAlternativeRepository;
35
36
    private ResearchedRepositoryInterface $researchedRepository;
37
38
    private BuildingRepositoryInterface $buildingRepository;
39
40
    private PlanetFieldRepositoryInterface $planetFieldRepository;
41
42
    private ColonyStorageManagerInterface $colonyStorageManager;
43
44
    private ColonyRepositoryInterface $colonyRepository;
45
46
    private BuildingActionInterface $buildingAction;
47
48
    private PlanetFieldTypeRetrieverInterface $planetFieldTypeRetriever;
49
50
    private BuildingManagerInterface $buildingManager;
51
52
    public function __construct(
53
        PlanetFieldHostProviderInterface $planetFieldHostProvider,
54
        BuildingFieldAlternativeRepositoryInterface $buildingFieldAlternativeRepository,
55
        ResearchedRepositoryInterface $researchedRepository,
56
        BuildingRepositoryInterface $buildingRepository,
57
        PlanetFieldRepositoryInterface $planetFieldRepository,
58
        ColonyStorageManagerInterface $colonyStorageManager,
59
        ColonyRepositoryInterface $colonyRepository,
60
        BuildingActionInterface $buildingAction,
61
        PlanetFieldTypeRetrieverInterface $planetFieldTypeRetriever,
62
        BuildingManagerInterface $buildingManager
63
    ) {
64
        $this->planetFieldHostProvider = $planetFieldHostProvider;
65
        $this->buildingFieldAlternativeRepository = $buildingFieldAlternativeRepository;
66
        $this->researchedRepository = $researchedRepository;
67
        $this->buildingRepository = $buildingRepository;
68
        $this->planetFieldRepository = $planetFieldRepository;
69
        $this->colonyStorageManager = $colonyStorageManager;
70
        $this->colonyRepository = $colonyRepository;
71
        $this->buildingAction = $buildingAction;
72
        $this->planetFieldTypeRetriever = $planetFieldTypeRetriever;
73
        $this->buildingManager = $buildingManager;
74
    }
75
76
    public function handle(GameControllerInterface $game): void
77
    {
78
        $game->setView(ShowInformation::VIEW_IDENTIFIER);
79
80
        $user = $game->getUser();
81
        $userId = $user->getId();
82
83
        $field = $this->planetFieldHostProvider->loadFieldViaRequestParameter($game->getUser());
84
        $host = $field->getHost();
85
86
        if ($field->getTerraformingId() > 0) {
87
            return;
88
        }
89
        $building = $this->buildingRepository->find(request::indInt('bid'));
90
        if ($building === null) {
91
            return;
92
        }
93
94
        $buildingId = $building->getId();
95
        $researchId = $building->getResearchId();
96
97
        if ($building->getBuildableFields()->containsKey($field->getFieldType()) === false) {
98
            return;
99
        }
100
101
        if ($userId !== UserEnum::USER_NOONE) {
102
            if ($researchId > 0 && $this->researchedRepository->hasUserFinishedResearch($user, [$researchId]) === false) {
103
                return;
104
            }
105
106
            $researchId = $building->getBuildableFields()->get($field->getFieldType())->getResearchId();
107
            if ($researchId != null && $this->researchedRepository->hasUserFinishedResearch($user, [$researchId]) === false) {
108
                return;
109
            }
110
        }
111
112
        if (
113
            $building->hasLimitColony() &&
114
            $this->planetFieldRepository->getCountByHostAndBuilding($host, $buildingId) >= $building->getLimitColony()
115
        ) {
116
            $game->addInformationf(
117
                _('Dieses Gebäude kann auf dieser Kolonie nur %d mal gebaut werden'),
118
                $building->getLimitColony()
119
            );
120
            return;
121
        }
122
        if (
123
            $host instanceof ColonyInterface
124
            && $building->hasLimit()
125
            && $this->planetFieldRepository->getCountByBuildingAndUser($buildingId, $userId) >= $building->getLimit()
126
        ) {
127
            $game->addInformationf(
128
                _('Dieses Gebäude kann insgesamt nur %d mal gebaut werden'),
129
                $building->getLimit()
130
            );
131
            return;
132
        }
133
134
        // Check for alternative building
135
        $alt_building = $this->buildingFieldAlternativeRepository->getByBuildingAndFieldType(
136
            $buildingId,
137
            $field->getFieldType()
138
        );
139
        if ($alt_building !== null) {
140
            $building = $alt_building->getAlternativeBuilding();
141
        }
142
143
        if ($field->hasBuilding()) {
144
            if ($host instanceof ColonyInterface) {
145
                if (!$this->checkBuildingCosts($host, $building, $field, $game)) {
146
                    return;
147
                } elseif ($host->getEps() < $building->getEpsCost()) {
148
                    $game->addInformationf(
149
                        _('Zum Bau wird %d Energie benötigt - Vorhanden ist nur %d'),
150
                        $building->getEpsCost(),
151
                        $host->getEps()
152
                    );
153
                    return;
154
                } elseif ($host->getEps() > $host->getMaxEps() - $field->getBuilding()->getEpsStorage() && $host->getMaxEps() - $field->getBuilding()->getEpsStorage() < $building->getEpsCost()) {
155
                    $game->addInformation(_('Nach der Demontage steht nicht mehr genügend Energie zum Bau zur Verfügung'));
156
                    return;
157
                } else {
158
                    $this->buildingAction->remove($field, $game);
159
                }
160
            }
161
        }
162
163
        if ($host instanceof ColonyInterface) {
164
            if (!$this->doColonyChecksAndConsume($field, $building, $host, $game)) {
165
                return;
166
            }
167
        }
168
169
        $field->setBuilding($building);
170
        $field->setActivateAfterBuild(true);
171
172
        $game->addExecuteJS('refreshHost();');
173
174
        if ($host instanceof ColonySandboxInterface) {
175
            $this->buildingManager->finish($field);
176
177
            $game->addInformationf(
178
                _('%s wurde gebaut'),
179
                $building->getName()
180
            );
181
        } else {
182
            $this->planetFieldRepository->save($field);
183
184
            $game->addInformationf(
185
                _('%s wird gebaut - Fertigstellung: %s'),
186
                $building->getName(),
187
                date('d.m.Y H:i', $field->getActive())
188
            );
189
        }
190
    }
191
192
    private function doColonyChecksAndConsume(
193
        PlanetFieldInterface $field,
194
        BuildingInterface $building,
195
        ColonyInterface $colony,
196
        GameControllerInterface $game
197
    ): bool {
198
        if (
199
            $this->planetFieldTypeRetriever->isOrbitField($field)
200
            && $colony->isBlocked()
201
        ) {
202
            $game->addInformation(_('Der Orbit kann nicht bebaut werden während die Kolonie blockiert wird'));
203
            return false;
204
        }
205
206
        //check for sufficient commodities
207
        if (!$this->checkBuildingCosts($colony, $building, $field, $game)) {
208
            return false;
209
        }
210
211
        if ($colony->getEps() < $building->getEpsCost()) {
212
            $game->addInformationf(
213
                _('Zum Bau wird %d Energie benötigt - Vorhanden ist nur %d'),
214
                $building->getEpsCost(),
215
                $colony->getEps()
216
            );
217
            return false;
218
        }
219
220
        foreach ($building->getCosts() as $cost) {
221
            $this->colonyStorageManager->lowerStorage($colony, $cost->getCommodity(), $cost->getAmount());
222
        }
223
224
        $colony->lowerEps($building->getEpsCost());
225
        $field->setActive(time() + $building->getBuildtime());
226
227
        $this->colonyRepository->save($colony);
228
229
        return true;
230
    }
231
232
    private function checkBuildingCosts(
233
        ColonyInterface $colony,
234
        BuildingInterface $building,
235
        PlanetFieldInterface $field,
236
        GameControllerInterface $game
237
    ): bool {
238
        $isEnoughAvailable = true;
239
        $storage = $colony->getStorage();
240
241
        foreach ($building->getCosts() as $cost) {
242
            $commodityId = $cost->getCommodityId();
243
244
            $currentBuildingCost = [];
245
246
            if ($field->hasBuilding()) {
247
                $currentBuildingCost = $field->getBuilding()->getCosts()->toArray();
248
                $result = array_filter(
249
                    $currentBuildingCost,
250
                    fn (BuildingCostInterface $buildingCost): bool => $commodityId === $buildingCost->getCommodityId()
251
                );
252
                if (
253
                    !$storage->containsKey($commodityId) &&
254
                    $result === []
255
                ) {
256
                    $game->addInformationf(
257
                        _('Es werden %d %s benötigt - Es ist jedoch keines vorhanden'),
258
                        $cost->getAmount(),
259
                        $cost->getCommodity()->getName()
260
                    );
261
                    $isEnoughAvailable = false;
262
                    continue;
263
                }
264
            } elseif (!$storage->containsKey($commodityId)) {
265
                $game->addInformationf(
266
                    _('Es werden %s %s benötigt - Es ist jedoch keines vorhanden'),
267
                    $cost->getAmount(),
268
                    $cost->getCommodity()->getName()
269
                );
270
                $isEnoughAvailable = false;
271
                continue;
272
            }
273
            $amount = $storage->containsKey($commodityId) ? $storage[$commodityId]->getAmount() : 0;
274
            if ($field->hasBuilding()) {
275
                $result = array_filter(
276
                    $currentBuildingCost,
277
                    fn (BuildingCostInterface $buildingCost): bool => $commodityId === $buildingCost->getCommodityId()
278
                );
279
                if ($result !== []) {
280
                    $amount += current($result)->getHalfAmount();
281
                }
282
            }
283
            if ($cost->getAmount() > $amount) {
284
                $game->addInformationf(
285
                    _('Es werden %d %s benötigt - Vorhanden sind nur %d'),
286
                    $cost->getAmount(),
287
                    $cost->getCommodity()->getName(),
288
                    $amount
289
                );
290
                $isEnoughAvailable = false;
291
                continue;
292
            }
293
        }
294
295
        return $isEnoughAvailable;
296
    }
297
298
    public function performSessionCheck(): bool
299
    {
300
        return true;
301
    }
302
}
303