Passed
Push — master ( f544cb...b3a3d9 )
by Nico
36:43 queued 09:10
created

BuildOnField   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 143
c 0
b 0
f 0
dl 0
loc 256
ccs 0
cts 143
cp 0
rs 9.36
wmc 38

5 Methods

Rating   Name   Duplication   Size   Complexity  
B checkBuildingCosts() 0 64 10
B doColonyChecksAndConsume() 0 46 9
A performSessionCheck() 0 3 1
A __construct() 0 22 1
C handle() 0 87 17
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
        $game->addExecuteJS('refreshHost();');
80
81
        $user = $game->getUser();
82
        $userId = $user->getId();
83
84
        $field = $this->planetFieldHostProvider->loadFieldViaRequestParameter($game->getUser());
85
        $host = $field->getHost();
86
87
        if ($field->getTerraformingId() > 0) {
88
            return;
89
        }
90
        $building = $this->buildingRepository->find(request::indInt('bid'));
91
        if ($building === null) {
92
            return;
93
        }
94
95
        $buildingId = $building->getId();
96
        $researchId = $building->getResearchId();
97
98
        if ($building->getBuildableFields()->containsKey($field->getFieldType()) === false) {
99
            return;
100
        }
101
102
        if ($userId !== UserEnum::USER_NOONE) {
103
            if ($researchId > 0 && $this->researchedRepository->hasUserFinishedResearch($user, [$researchId]) === false) {
104
                return;
105
            }
106
107
            $researchId = $building->getBuildableFields()->get($field->getFieldType())->getResearchId();
108
            if ($researchId != null && $this->researchedRepository->hasUserFinishedResearch($user, [$researchId]) === false) {
109
                return;
110
            }
111
        }
112
113
        if (
114
            $building->hasLimitColony() &&
115
            $this->planetFieldRepository->getCountByHostAndBuilding($host, $buildingId) >= $building->getLimitColony()
116
        ) {
117
            $game->addInformationf(
118
                _('Dieses Gebäude kann auf dieser Kolonie nur %d mal gebaut werden'),
119
                $building->getLimitColony()
120
            );
121
            return;
122
        }
123
        if ($building->hasLimit() && $this->planetFieldRepository->getCountByBuildingAndUser($buildingId, $userId) >= $building->getLimit()) {
124
            $game->addInformationf(
125
                _('Dieses Gebäude kann insgesamt nur %d mal gebaut werden'),
126
                $building->getLimit()
127
            );
128
            return;
129
        }
130
131
        // Check for alternative building
132
        $alt_building = $this->buildingFieldAlternativeRepository->getByBuildingAndFieldType(
133
            $buildingId,
134
            $field->getFieldType()
135
        );
136
        if ($alt_building !== null) {
137
            $building = $alt_building->getAlternativeBuilding();
138
        }
139
140
        if ($host instanceof ColonyInterface) {
141
            if (!$this->doColonyChecksAndConsume($field, $building, $host, $game)) {
142
                return;
143
            }
144
        }
145
146
        $field->setBuilding($building);
147
        $field->setActivateAfterBuild(true);
148
149
        if ($host instanceof ColonySandboxInterface) {
150
            $this->buildingManager->finish($field);
151
152
            $game->addInformationf(
153
                _('%s wurde gebaut'),
154
                $building->getName()
155
            );
156
        } else {
157
            $this->planetFieldRepository->save($field);
158
159
            $game->addInformationf(
160
                _('%s wird gebaut - Fertigstellung: %s'),
161
                $building->getName(),
162
                date('d.m.Y H:i', $field->getActive())
163
            );
164
        }
165
    }
166
167
    private function doColonyChecksAndConsume(
168
        PlanetFieldInterface $field,
169
        BuildingInterface $building,
170
        ColonyInterface $colony,
171
        GameControllerInterface $game
172
    ): bool {
173
        if (
174
            $this->planetFieldTypeRetriever->isOrbitField($field)
175
            && $colony->isBlocked()
176
        ) {
177
            $game->addInformation(_('Der Orbit kann nicht bebaut werden während die Kolonie blockiert wird'));
178
            return false;
179
        }
180
181
        //check for sufficient commodities
182
        if (!$this->checkBuildingCosts($colony, $building, $field, $game)) {
183
            return false;
184
        }
185
186
        if ($colony->getEps() < $building->getEpsCost()) {
187
            $game->addInformationf(
188
                _('Zum Bau wird %d Energie benötigt - Vorhanden ist nur %d'),
189
                $building->getEpsCost(),
190
                $colony->getEps()
191
            );
192
            return false;
193
        }
194
195
        if ($field->hasBuilding()) {
196
            if ($colony->getEps() > $colony->getMaxEps() - $field->getBuilding()->getEpsStorage() && $colony->getMaxEps() - $field->getBuilding()->getEpsStorage() < $building->getEpsCost()) {
197
                $game->addInformation(_('Nach der Demontage steht nicht mehr genügend Energie zum Bau zur Verfügung'));
198
                return false;
199
            }
200
            $this->buildingAction->remove($field, $game);
201
        }
202
203
        foreach ($building->getCosts() as $cost) {
204
            $this->colonyStorageManager->lowerStorage($colony, $cost->getCommodity(), $cost->getAmount());
205
        }
206
207
        $colony->lowerEps($building->getEpsCost());
208
        $field->setActive(time() + $building->getBuildtime());
209
210
        $this->colonyRepository->save($colony);
211
212
        return true;
213
    }
214
215
    private function checkBuildingCosts(
216
        ColonyInterface $colony,
217
        BuildingInterface $building,
218
        PlanetFieldInterface $field,
219
        GameControllerInterface $game
220
    ): bool {
221
        $isEnoughAvailable = true;
222
        $storage = $colony->getStorage();
223
224
        foreach ($building->getCosts() as $cost) {
225
            $commodityId = $cost->getCommodityId();
226
227
            $currentBuildingCost = [];
228
229
            if ($field->hasBuilding()) {
230
                $currentBuildingCost = $field->getBuilding()->getCosts()->toArray();
231
                $result = array_filter(
232
                    $currentBuildingCost,
233
                    fn (BuildingCostInterface $buildingCost): bool => $commodityId === $buildingCost->getCommodityId()
234
                );
235
                if (
236
                    !$storage->containsKey($commodityId) &&
237
                    $result === []
238
                ) {
239
                    $game->addInformationf(
240
                        _('Es werden %d %s benötigt - Es ist jedoch keines vorhanden'),
241
                        $cost->getAmount(),
242
                        $cost->getCommodity()->getName()
243
                    );
244
                    $isEnoughAvailable = false;
245
                    continue;
246
                }
247
            } elseif (!$storage->containsKey($commodityId)) {
248
                $game->addInformationf(
249
                    _('Es werden %s %s benötigt - Es ist jedoch keines vorhanden'),
250
                    $cost->getAmount(),
251
                    $cost->getCommodity()->getName()
252
                );
253
                $isEnoughAvailable = false;
254
                continue;
255
            }
256
            $amount = $storage->containsKey($commodityId) ? $storage[$commodityId]->getAmount() : 0;
257
            if ($field->hasBuilding()) {
258
                $result = array_filter(
259
                    $currentBuildingCost,
260
                    fn (BuildingCostInterface $buildingCost): bool => $commodityId === $buildingCost->getCommodityId()
261
                );
262
                if ($result !== []) {
263
                    $amount += current($result)->getHalfAmount();
264
                }
265
            }
266
            if ($cost->getAmount() > $amount) {
267
                $game->addInformationf(
268
                    _('Es werden %d %s benötigt - Vorhanden sind nur %d'),
269
                    $cost->getAmount(),
270
                    $cost->getCommodity()->getName(),
271
                    $amount
272
                );
273
                $isEnoughAvailable = false;
274
                continue;
275
            }
276
        }
277
278
        return $isEnoughAvailable;
279
    }
280
281
    public function performSessionCheck(): bool
282
    {
283
        return true;
284
    }
285
}
286