Passed
Pull Request — master (#1685)
by Nico
30:06
created

TroopTransfer::transferToShip()   B

Complexity

Conditions 9
Paths 11

Size

Total Lines 44
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
eloc 21
nc 11
nop 6
dl 0
loc 44
ccs 0
cts 22
cp 0
crap 90
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Action\TroopTransfer;
6
7
use request;
8
use Stu\Component\Ship\System\Exception\ShipSystemException;
9
use Stu\Component\Ship\System\Exception\SystemNotActivatableException;
10
use Stu\Component\Ship\System\Exception\SystemNotFoundException;
11
use Stu\Component\Ship\System\ShipSystemManagerInterface;
12
use Stu\Component\Ship\System\ShipSystemModeEnum;
13
use Stu\Component\Ship\System\ShipSystemTypeEnum;
14
use Stu\Component\Ship\System\Type\UplinkShipSystem;
15
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
16
use Stu\Module\Control\ActionControllerInterface;
17
use Stu\Module\Control\GameControllerInterface;
18
use Stu\Module\Logging\LoggerUtilFactoryInterface;
19
use Stu\Module\Logging\LoggerUtilInterface;
20
use Stu\Module\Message\Lib\PrivateMessageFolderSpecialEnum;
21
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
22
use Stu\Module\Ship\Lib\ActivatorDeactivatorHelperInterface;
23
use Stu\Module\Ship\Lib\Auxiliary\ShipShutdownInterface;
24
use Stu\Module\Ship\Lib\Interaction\DockPrivilegeUtilityInterface;
25
use Stu\Module\Ship\Lib\Interaction\InteractionChecker;
26
use Stu\Module\Ship\Lib\ShipLoaderInterface;
27
use Stu\Module\Ship\Lib\ShipWrapperFactoryInterface;
28
use Stu\Module\Ship\Lib\Crew\TroopTransferUtilityInterface;
29
use Stu\Module\Ship\Lib\ShipWrapperInterface;
30
use Stu\Module\Ship\View\ShowShip\ShowShip;
31
use Stu\Orm\Entity\ColonyInterface;
32
use Stu\Orm\Entity\ShipCrewInterface;
33
use Stu\Orm\Entity\ShipInterface;
34
use Stu\Orm\Repository\ColonyRepositoryInterface;
35
use Stu\Orm\Repository\ShipRepositoryInterface;
36
37
final class TroopTransfer implements ActionControllerInterface
38
{
39
    public const ACTION_IDENTIFIER = 'B_TROOP_TRANSFER';
40
41
    private ShipLoaderInterface $shipLoader;
42
43
    private ShipRepositoryInterface $shipRepository;
44
45
    private ColonyRepositoryInterface $colonyRepository;
46
47
    private TroopTransferUtilityInterface $transferUtility;
48
49
    private ActivatorDeactivatorHelperInterface $helper;
50
51
    private ShipSystemManagerInterface $shipSystemManager;
52
53
    private DockPrivilegeUtilityInterface $dockPrivilegeUtility;
54
55
    private ShipWrapperFactoryInterface $shipWrapperFactory;
56
57
    private PrivateMessageSenderInterface $privateMessageSender;
58
59
    private ColonyLibFactoryInterface $colonyLibFactory;
60
61
    private ShipShutdownInterface $shipShutdown;
62
63
    private LoggerUtilInterface $loggerUtil;
64
65
    public function __construct(
66
        ShipLoaderInterface $shipLoader,
67
        ShipRepositoryInterface $shipRepository,
68
        ColonyRepositoryInterface $colonyRepository,
69
        TroopTransferUtilityInterface $transferUtility,
70
        ActivatorDeactivatorHelperInterface $helper,
71
        ShipSystemManagerInterface $shipSystemManager,
72
        DockPrivilegeUtilityInterface $dockPrivilegeUtility,
73
        ShipWrapperFactoryInterface $shipWrapperFactory,
74
        PrivateMessageSenderInterface $privateMessageSender,
75
        ColonyLibFactoryInterface $colonyLibFactory,
76
        ShipShutdownInterface $shipShutdown,
77
        LoggerUtilFactoryInterface $loggerUtilFactory
78
    ) {
79
        $this->shipLoader = $shipLoader;
80
        $this->shipRepository = $shipRepository;
81
        $this->colonyRepository = $colonyRepository;
82
        $this->transferUtility = $transferUtility;
83
        $this->helper = $helper;
84
        $this->shipSystemManager = $shipSystemManager;
85
        $this->dockPrivilegeUtility = $dockPrivilegeUtility;
86
        $this->shipWrapperFactory = $shipWrapperFactory;
87
        $this->privateMessageSender = $privateMessageSender;
88
        $this->colonyLibFactory = $colonyLibFactory;
89
        $this->shipShutdown = $shipShutdown;
90
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil();
91
    }
92
93
    public function handle(GameControllerInterface $game): void
94
    {
95
        //$this->loggerUtil->init('stu', LoggerEnum::LEVEL_ERROR);
96
        $game->setView(ShowShip::VIEW_IDENTIFIER);
97
98
        $user = $game->getUser();
99
        $userId = $user->getId();
100
101
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
102
            request::indInt('id'),
103
            $userId
104
        );
105
        $ship = $wrapper->get();
106
107
        if (!$ship->hasEnoughCrew($game)) {
108
            return;
109
        }
110
111
        $isColony = request::has('isColony');
112
        if ($isColony) {
113
            $target = $this->colonyRepository->find(request::postIntFatal('target'));
114
        } else {
115
            $target = $this->shipRepository->find(request::postIntFatal('target'));
116
        }
117
        if ($target === null) {
118
            return;
119
        }
120
        if (!InteractionChecker::canInteractWith($ship, $target, $game, !$isColony)) {
121
            return;
122
        }
123
124
        if ($ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)) {
125
            if (!$ship->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)) {
126
                $game->addInformation(_("Die Truppenquartiere sind zerstört"));
127
                return;
128
            }
129
        }
130
131
        $epsSystem = $wrapper->getEpsSystemData();
132
        if ($epsSystem->getEps() == 0) {
133
            $game->addInformation(_("Keine Energie vorhanden"));
134
            return;
135
        }
136
        if ($ship->getCloakState()) {
137
            $game->addInformation(_("Die Tarnung ist aktiviert"));
138
            return;
139
        }
140
        if ($ship->getWarpState()) {
141
            $game->addInformation(_("Der Warpantrieb ist aktiviert"));
142
            return;
143
        }
144
        if ($ship->getShieldState()) {
145
            $game->addInformation(_("Die Schilde sind aktiviert"));
146
            return;
147
        }
148
149
        $isUnload = request::has('isUnload');
150
151
152
        if (!$isColony && $target->getWarpState()) {
153
            $game->addInformation(sprintf(_('Die %s befindet sich im Warp'), $target->getName()));
154
            return;
155
        }
156
        $requestedTransferCount = request::postInt('tcount');
157
158
        $amount = 0;
159
160
        try {
161
            if ($isColony) {
162
                if ($isUnload) {
163
                    $amount = $this->transferToColony($requestedTransferCount, $ship, $target);
164
                } else {
165
                    $amount = $this->transferFromColony($requestedTransferCount, $wrapper, $target, $game);
166
                }
167
            } else {
168
                $this->loggerUtil->log('A');
169
                $isUplinkSituation = false;
170
                $ownCrewOnTarget = $this->transferUtility->ownCrewOnTarget($user, $target);
171
172
                if ($target->getUser() !== $user) {
173
                    $this->loggerUtil->log('B');
174
                    if ($target->hasUplink()) {
175
                        $this->loggerUtil->log('C');
176
                        $isUplinkSituation = true;
177
                    } else {
178
                        return;
179
                    }
180
                }
181
182
                if ($isUnload) {
183
                    $this->loggerUtil->log('D');
184
                    if ($isUplinkSituation) {
185
                        $this->loggerUtil->log('E');
186
                        if (!$this->dockPrivilegeUtility->checkPrivilegeFor($target->getId(), $user)) {
187
                            $game->addInformation(_("Benötigte Andockerlaubnis wurde verweigert"));
188
                            return;
189
                        }
190
                        $this->loggerUtil->log('F');
191
                        if (!$target->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_UPLINK)) {
192
                            $this->loggerUtil->log('G');
193
                            $game->addInformation(_("Das Ziel verfügt über keinen intakten Uplink"));
194
                            return;
195
                        }
196
197
                        if ($this->transferUtility->foreignerCount($target) >= UplinkShipSystem::MAX_FOREIGNERS) {
198
                            $game->addInformation(_("Maximale Anzahl an fremden Crewman ist bereits erreicht"));
199
                        }
200
                    }
201
202
                    $amount = $this->transferToShip($requestedTransferCount, $ship, $target, $isUplinkSituation, $ownCrewOnTarget, $game);
203
                } else {
204
                    $amount = $this->transferFromShip($requestedTransferCount, $wrapper, $target, $isUplinkSituation, $ownCrewOnTarget, $game);
205
                }
206
            }
207
        } catch (ShipSystemException $e) {
208
            return;
209
        }
210
211
        $this->shipLoader->save($ship);
212
213
        $game->addInformation(
214
            sprintf(
215
                _('Die %s hat %d Crewman %s der %s transferiert'),
216
                $ship->getName(),
217
                $amount,
218
                $isUnload ? 'zu' : 'von',
219
                $target->getName()
220
            )
221
        );
222
223
        if ($ship->getCrewCount() <= $ship->getBuildplan()->getCrew()) {
224
            $this->helper->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game);
225
        }
226
    }
227
228
    private function transferToColony(int $requestedTransferCount, ShipInterface $ship, ColonyInterface $colony): int
229
    {
230
        $freeAssignmentCount = $this->colonyLibFactory->createColonyPopulationCalculator(
231
            $colony
232
        )->getFreeAssignmentCount();
233
234
        $amount = min(
235
            $requestedTransferCount,
236
            $this->transferUtility->getBeamableTroopCount($ship),
237
            $freeAssignmentCount
238
        );
239
240
        $assignments = $ship->getCrewAssignments()->getValues();
241
242
        for ($i = 0; $i < $amount; $i++) {
243
            //assign crew to colony
244
            $this->transferUtility->assignCrew($assignments[$i], $colony);
245
        }
246
247
        return $amount;
248
    }
249
250
    private function transferFromColony(int $requestedTransferCount, ShipWrapperInterface $wrapper, ColonyInterface $colony, GameControllerInterface $game): int
251
    {
252
        $ship = $wrapper->get();
253
254
        $amount = min(
255
            $requestedTransferCount,
256
            $colony->getCrewAssignmentAmount(),
257
            $this->transferUtility->getFreeQuarters($ship)
258
        );
259
260
        if ($ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)) {
261
        if (
262
            $amount > 0
263
            && $ship->getShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)->getMode() === ShipSystemModeEnum::MODE_OFF
264
            && !$this->helper->activate($wrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game)
265
        ) {
266
            throw new SystemNotActivatableException();
267
            }
268
        }
269
270
        $crewAssignments = $colony->getCrewAssignments();
271
272
        for ($i = 0; $i < $amount; $i++) {
273
            /** @var ShipCrewInterface $crewAssignment */
274
            $crewAssignment = $crewAssignments->get(array_rand($crewAssignments->toArray()));
0 ignored issues
show
Bug introduced by
It seems like array_rand($crewAssignments->toArray()) can also be of type array; however, parameter $key of Doctrine\Common\Collecti...adableCollection::get() does only seem to accept integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

274
            $crewAssignment = $crewAssignments->get(/** @scrutinizer ignore-type */ array_rand($crewAssignments->toArray()));
Loading history...
275
276
            $this->transferUtility->assignCrew($crewAssignment, $ship);
277
        }
278
279
        return $amount;
280
    }
281
282
    private function transferToShip(
283
        int $requestedTransferCount,
284
        ShipInterface $ship,
285
        ShipInterface $target,
286
        bool $isUplinkSituation,
287
        int $ownCrewOnTarget,
288
        GameControllerInterface $game
289
    ): int {
290
        if (!$target->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)) {
291
            $game->addInformation(sprintf(_('Die %s hat keine Lebenserhaltungssysteme'), $target->getName()));
292
293
            throw new SystemNotFoundException();
294
        }
295
296
        $this->loggerUtil->log(sprintf('ownCrewOnTarget: %d', $ownCrewOnTarget));
297
298
        $amount = min(
299
            $requestedTransferCount,
300
            $this->transferUtility->getBeamableTroopCount($ship),
301
            $this->transferUtility->getFreeQuarters($target),
302
            $isUplinkSituation ? ($ownCrewOnTarget === 0 ? 1 : 0) : PHP_INT_MAX
303
        );
304
305
        $assignments = $ship->getCrewAssignments()->getValues();
306
307
        for ($i = 0; $i < $amount; $i++) {
308
            $this->transferUtility->assignCrew($assignments[$i], $target);
309
        }
310
311
        if ($amount > 0) {
312
            if (
313
                $target->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)
314
                && $target->getShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)->getMode() == ShipSystemModeEnum::MODE_OFF
315
            ) {
316
                $this->shipSystemManager->activate($this->shipWrapperFactory->wrapShip($target), ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT, true);
317
            }
318
319
            if ($isUplinkSituation) {
320
                $target->getShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK)->setMode(ShipSystemModeEnum::MODE_ON);
321
                $this->sendUplinkMessage(true, true, $ship, $target);
322
            }
323
        }
324
325
        return $amount;
326
    }
327
328
    private function transferFromShip(
329
        int $requestedTransferCount,
330
        ShipWrapperInterface $wrapper,
331
        ShipInterface $target,
332
        bool $isUplinkSituation,
333
        int $ownCrewOnTarget,
334
        GameControllerInterface $game
335
    ): int {
336
        $ship = $wrapper->get();
337
338
        $amount = min(
339
            $requestedTransferCount,
340
            $this->transferUtility->getFreeQuarters($ship),
341
            $ownCrewOnTarget
342
        );
343
344
        if ($ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)) {
345
        if (
346
            $amount > 0
347
            && $ship->getShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)->getMode() === ShipSystemModeEnum::MODE_OFF
348
            && !$this->helper->activate($wrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game)
349
        ) {
350
            throw new SystemNotActivatableException();
351
            }
352
        }
353
354
        $array = $target->getCrewAssignments()->getValues();
355
        $targetCrewCount = $target->getCrewCount();
356
357
        $i = 0;
358
        foreach ($array as $crewAssignment) {
359
            if ($crewAssignment->getCrew()->getUser() !== $ship->getUser()) {
360
                continue;
361
            }
362
363
            $this->transferUtility->assignCrew($crewAssignment, $ship);
364
            $i++;
365
366
            if ($i === $amount) {
367
                break;
368
            }
369
        }
370
371
        if ($amount > 0 && $isUplinkSituation) {
372
            //no foreigners left, shut down uplink
373
            if ($this->transferUtility->foreignerCount($target) === 0) {
374
                $target->getShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK)->setMode(ShipSystemModeEnum::MODE_OFF);
375
                $this->sendUplinkMessage(false, false, $ship, $target);
376
            } else {
377
                $this->sendUplinkMessage(false, true, $ship, $target);
378
            }
379
        }
380
381
        $targetWrapper = $this->shipWrapperFactory->wrapShip($target);
382
383
        // no crew left
384
        if ($amount === $targetCrewCount) {
385
            $this->shipShutdown->shutdown($targetWrapper);
386
        } elseif (
387
            $target->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)
388
            && $target->getSystemState(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS)
389
            && $target->getCrewCount() <= $target->getBuildplan()->getCrew()
390
        ) {
391
            $this->helper->deactivate($targetWrapper, ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS, $game);
392
        }
393
394
        return $amount;
395
    }
396
397
    private function sendUplinkMessage(bool $isUnload, bool $isOn, ShipInterface $ship, ShipInterface $target): void
398
    {
399
        $href = sprintf('ship.php?%s=1&id=%d', ShowShip::VIEW_IDENTIFIER, $target->getId());
400
401
        $msg = sprintf(
402
            _('Die %s von Spieler %s hat 1 Crewman %s deiner Station %s gebeamt. Der Uplink ist %s'),
403
            $ship->getName(),
404
            $ship->getUser()->getName(),
405
            $isUnload ? 'zu' : 'von',
406
            $target->getName(),
407
            $isOn ? 'aktiviert' : 'deaktiviert'
408
        );
409
410
        $this->privateMessageSender->send(
411
            $ship->getUser()->getId(),
412
            $target->getUser()->getId(),
413
            $msg,
414
            PrivateMessageFolderSpecialEnum::PM_SPECIAL_STATION,
415
            $href
416
        );
417
    }
418
419
    public function performSessionCheck(): bool
420
    {
421
        return true;
422
    }
423
}