Passed
Pull Request — master (#1833)
by Nico
34:40
created

ShipWrapper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 10
dl 0
loc 14
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use JBBCode\Parser;
10
use RuntimeException;
11
use Stu\Component\Ship\AstronomicalMappingEnum;
12
use Stu\Component\Ship\Repair\RepairUtilInterface;
13
use Stu\Component\Ship\ShipAlertStateEnum;
14
use Stu\Component\Ship\ShipStateEnum;
15
use Stu\Component\Ship\System\Data\AbstractSystemData;
16
use Stu\Component\Ship\System\Data\AstroLaboratorySystemData;
17
use Stu\Component\Ship\System\Data\EpsSystemData;
18
use Stu\Component\Ship\System\Data\FusionCoreSystemData;
19
use Stu\Component\Ship\System\Data\HullSystemData;
20
use Stu\Component\Ship\System\Data\ProjectileLauncherSystemData;
21
use Stu\Component\Ship\System\Data\ShieldSystemData;
22
use Stu\Component\Ship\System\Data\SingularityCoreSystemData;
23
use Stu\Component\Ship\System\Data\TrackerSystemData;
24
use Stu\Component\Ship\System\Data\WarpCoreSystemData;
25
use Stu\Component\Ship\System\Data\WarpDriveSystemData;
26
use Stu\Component\Ship\System\Data\WebEmitterSystemData;
27
use Stu\Component\Ship\System\Exception\SystemNotFoundException;
28
use Stu\Component\Ship\System\ShipSystemManagerInterface;
29
use Stu\Component\Ship\System\ShipSystemTypeEnum;
30
use Stu\Component\Ship\System\SystemDataDeserializerInterface;
31
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
32
use Stu\Module\Commodity\CommodityTypeEnum;
33
use Stu\Module\Control\GameControllerInterface;
34
use Stu\Module\Ship\Lib\Interaction\ShipTakeoverManagerInterface;
35
use Stu\Orm\Entity\ShipInterface;
36
use Stu\Orm\Entity\ShipSystemInterface;
37
use Stu\Orm\Entity\ShipTakeoverInterface;
38
use Stu\Orm\Repository\TorpedoTypeRepositoryInterface;
39
40
//TODO increase coverage
41
final class ShipWrapper implements ShipWrapperInterface
42
{
43
    /**
44
     * @var Collection<int, AbstractSystemData>
45
     */
46
    private Collection $shipSystemDataCache;
47
48
    private ?ReactorWrapperInterface $reactorWrapper = null;
49
50
    private ?int $epsUsage = null;
51
52 15
    public function __construct(
53
        private ShipInterface $ship,
54
        private ShipSystemManagerInterface $shipSystemManager,
55
        private SystemDataDeserializerInterface $systemDataDeserializer,
56
        private ColonyLibFactoryInterface $colonyLibFactory,
57
        private TorpedoTypeRepositoryInterface $torpedoTypeRepository,
58
        private GameControllerInterface $game,
59
        private ShipWrapperFactoryInterface $shipWrapperFactory,
60
        private ShipStateChangerInterface $shipStateChanger,
61
        private RepairUtilInterface $repairUtil,
62
        private Parser $bbCodeParser
63
    ) {
64
65 15
        $this->shipSystemDataCache = new ArrayCollection();
66
    }
67
68 15
    public function get(): ShipInterface
69
    {
70 15
        return $this->ship;
71
    }
72
73
    public function getShipWrapperFactory(): ShipWrapperFactoryInterface
74
    {
75
        return $this->shipWrapperFactory;
76
    }
77
78
    public function getShipSystemManager(): ShipSystemManagerInterface
79
    {
80
        return $this->shipSystemManager;
81
    }
82
83
    public function getFleetWrapper(): ?FleetWrapperInterface
84
    {
85
        if ($this->get()->getFleet() === null) {
86
            return null;
87
        }
88
89
        return $this->shipWrapperFactory->wrapFleet($this->get()->getFleet());
90
    }
91
92
    public function getEpsUsage(): int
93
    {
94
        if ($this->epsUsage === null) {
95
            $this->epsUsage = $this->reloadEpsUsage();
96
        }
97
        return $this->epsUsage;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->epsUsage could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
98
    }
99
100
    public function lowerEpsUsage(int $value): void
101
    {
102
        $this->epsUsage -= $value;
103
    }
104
105
    private function reloadEpsUsage(): int
106
    {
107
        $result = 0;
108
109
        foreach ($this->shipSystemManager->getActiveSystems($this->get()) as $shipSystem) {
110
            $result += $this->shipSystemManager->getEnergyConsumption($shipSystem->getSystemType());
111
        }
112
113
        if ($this->get()->getAlertState() == ShipAlertStateEnum::ALERT_YELLOW) {
114
            $result += ShipStateChangerInterface::ALERT_YELLOW_EPS_USAGE;
115
        }
116
        if ($this->get()->getAlertState() == ShipAlertStateEnum::ALERT_RED) {
117
            $result += ShipStateChangerInterface::ALERT_RED_EPS_USAGE;
118
        }
119
120
        return $result;
121
    }
122
123
    public function getReactorUsage(): int
124
    {
125
        $reactor = $this->reactorWrapper;
126
        if ($reactor === null) {
127
            throw new RuntimeException('this should not happen');
128
        }
129
130
        return $this->getEpsUsage() + $reactor->getUsage();
131
    }
132
133
    public function getReactorWrapper(): ?ReactorWrapperInterface
134
    {
135
        if ($this->reactorWrapper === null) {
136
            $ship = $this->get();
137
            $reactorSystemData = null;
138
139
140
            if ($ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPCORE)) {
141
                $reactorSystemData = $this->getSpecificShipSystem(
142
                    ShipSystemTypeEnum::SYSTEM_WARPCORE,
143
                    WarpCoreSystemData::class
144
                );
145
            }
146
            if ($ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SINGULARITY_REACTOR)) {
147
                $reactorSystemData = $this->getSpecificShipSystem(
148
                    ShipSystemTypeEnum::SYSTEM_SINGULARITY_REACTOR,
149
                    SingularityCoreSystemData::class
150
                );
151
            }
152
            if ($ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_FUSION_REACTOR)) {
153
                $reactorSystemData = $this->getSpecificShipSystem(
154
                    ShipSystemTypeEnum::SYSTEM_FUSION_REACTOR,
155
                    FusionCoreSystemData::class
156
                );
157
            }
158
159
            if ($reactorSystemData === null) {
160
                return null;
161
            }
162
163
            $this->reactorWrapper = new ReactorWrapper($this, $reactorSystemData);
164
        }
165
166
        return $this->reactorWrapper;
167
    }
168
169
    public function setAlertState(ShipAlertStateEnum $alertState): ?string
170
    {
171
        $msg = $this->shipStateChanger->changeAlertState($this, $alertState);
172
        $this->epsUsage = $this->reloadEpsUsage();
173
174
        return $msg;
175
    }
176
177
    /**
178
     * highest damage first, then prio
179
     *
180
     * @return ShipSystemInterface[]
181
     */
182
    public function getDamagedSystems(): array
183
    {
184
        $damagedSystems = [];
185
        $prioArray = [];
186
        foreach ($this->get()->getSystems() as $system) {
187
            if ($system->getStatus() < 100) {
188
                $damagedSystems[] = $system;
189
                $prioArray[$system->getSystemType()->value] = $this->shipSystemManager->lookupSystem($system->getSystemType())->getPriority();
190
            }
191
        }
192
193
        // sort by damage and priority
194
        usort(
195
            $damagedSystems,
196
            function (ShipSystemInterface $a, ShipSystemInterface $b) use ($prioArray): int {
197
                if ($a->getStatus() === $b->getStatus()) {
198
                    return $prioArray[$b->getSystemType()->value] <=> $prioArray[$a->getSystemType()->value];
199
                }
200
                return ($a->getStatus() < $b->getStatus()) ? -1 : 1;
201
            }
202
        );
203
204
        return $damagedSystems;
205
    }
206
207
    public function isOwnedByCurrentUser(): bool
208
    {
209
        return $this->game->getUser() === $this->get()->getUser();
210
    }
211
212
    public function canLandOnCurrentColony(): bool
213
    {
214
        if ($this->get()->getRump()->getCommodity() === null) {
215
            return false;
216
        }
217
        if ($this->get()->isShuttle()) {
218
            return false;
219
        }
220
221
        $currentColony = $this->get()->getStarsystemMap() !== null ? $this->get()->getStarsystemMap()->getColony() : null;
222
223
        if ($currentColony === null) {
224
            return false;
225
        }
226
        if ($currentColony->getUser() !== $this->get()->getUser()) {
227
            return false;
228
        }
229
230
        return $this->colonyLibFactory
231
            ->createColonySurface($currentColony)
232
            ->hasAirfield();
233
    }
234
235
    public function canBeRepaired(): bool
236
    {
237
        if ($this->get()->getAlertState() !== ShipAlertStateEnum::ALERT_GREEN) {
238
            return false;
239
        }
240
241
        if ($this->get()->getShieldState()) {
242
            return false;
243
        }
244
245
        if ($this->get()->getCloakState()) {
246
            return false;
247
        }
248
249
        if (!empty($this->getDamagedSystems())) {
250
            return true;
251
        }
252
253
        return $this->get()->getHull() < $this->get()->getMaxHull();
254
    }
255
256 4
    public function canFire(): bool
257
    {
258 4
        $ship = $this->get();
259 4
        if (!$ship->getNbs()) {
260 1
            return false;
261
        }
262 3
        if (!$ship->hasActiveWeapon()) {
263 1
            return false;
264
        }
265
266 2
        $epsSystem = $this->getEpsSystemData();
267 2
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
268
    }
269
270 2
    public function getRepairDuration(): int
271
    {
272 2
        return $this->repairUtil->getRepairDuration($this);
273
    }
274
275
    public function getRepairDurationPreview(): int
276
    {
277
        return $this->repairUtil->getRepairDurationPreview($this);
278
    }
279
280
    public function getRepairCosts(): array
281
    {
282
        $neededParts = $this->repairUtil->determineSpareParts($this, false);
283
284
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
285
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
286
287
        return [
288
            new ShipRepairCost($neededSpareParts, CommodityTypeEnum::COMMODITY_SPARE_PART, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART)),
289
            new ShipRepairCost($neededSystemComponents, CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT))
290
        ];
291
    }
292
293
    public function getPossibleTorpedoTypes(): array
294
    {
295
        if ($this->ship->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE)) {
296
            return $this->torpedoTypeRepository->getAll();
297
        }
298
299
        return $this->torpedoTypeRepository->getByLevel($this->ship->getRump()->getTorpedoLevel());
300
    }
301
302
    public function getTractoredShipWrapper(): ?ShipWrapperInterface
303
    {
304
        $tractoredShip = $this->get()->getTractoredShip();
305
        if ($tractoredShip === null) {
306
            return null;
307
        }
308
309
        return $this->shipWrapperFactory->wrapShip($tractoredShip);
310
    }
311
312
    public function getTractoringShipWrapper(): ?ShipWrapperInterface
313
    {
314
        $tractoringShip = $this->get()->getTractoringShip();
315
        if ($tractoringShip === null) {
316
            return null;
317
        }
318
319
        return $this->shipWrapperFactory->wrapShip($tractoringShip);
320
    }
321
322
    public function getDockedToShipWrapper(): ?ShipWrapperInterface
323
    {
324
        $dockedTo = $this->get()->getDockedTo();
325
        if ($dockedTo === null) {
326
            return null;
327
        }
328
329
        return $this->shipWrapperFactory->wrapShip($dockedTo);
330
    }
331
332 7
    public function getStateIconAndTitle(): ?array
333
    {
334 7
        $ship = $this->get();
335
336 7
        $state = $ship->getState();
337
338 7
        if ($state === ShipStateEnum::SHIP_STATE_REPAIR_ACTIVE) {
339 2
            $isBase = $ship->isBase();
340 2
            return ['rep2', sprintf('%s repariert die Station', $isBase ? 'Stationscrew' : 'Schiffscrew')];
341
        }
342
343 5
        if ($state === ShipStateEnum::SHIP_STATE_REPAIR_PASSIVE) {
344 2
            $isBase = $ship->isBase();
345 2
            $repairDuration = $this->getRepairDuration();
346 2
            return ['rep2', sprintf('%s wird repariert (noch %d Runden)', $isBase ? 'Station' : 'Schiff', $repairDuration)];
347
        }
348
349 3
        $currentTurn = $this->game->getCurrentRound()->getTurn();
350 3
        $astroLab = $this->getAstroLaboratorySystemData();
351
        if (
352 3
            $state === ShipStateEnum::SHIP_STATE_ASTRO_FINALIZING
353 3
            && $astroLab !== null
354
        ) {
355 1
            return ['map1', sprintf(
356 1
                'Schiff kartographiert (noch %d Runden)',
357 1
                $astroLab->getAstroStartTurn() + AstronomicalMappingEnum::TURNS_TO_FINISH - $currentTurn
358 1
            )];
359
        }
360
361 2
        $takeover = $ship->getTakeoverActive();
362
        if (
363 2
            $state === ShipStateEnum::SHIP_STATE_ACTIVE_TAKEOVER
364 2
            && $takeover !== null
365
        ) {
366 1
            $targetNamePlainText = $this->bbCodeParser->parse($takeover->getTargetShip()->getName())->getAsText();
367 1
            return ['take2', sprintf(
368 1
                'Schiff übernimmt die "%s" (noch %d Runden)',
369 1
                $targetNamePlainText,
370 1
                $this->getTakeoverTicksLeft($takeover)
371 1
            )];
372
        }
373
374 1
        $takeover = $ship->getTakeoverPassive();
375 1
        if ($takeover !== null) {
376 1
            $sourceUserNamePlainText = $this->bbCodeParser->parse($takeover->getSourceShip()->getUser()->getName())->getAsText();
377 1
            return ['untake2', sprintf(
378 1
                'Schiff wird von Spieler "%s" übernommen (noch %d Runden)',
379 1
                $sourceUserNamePlainText,
380 1
                $this->getTakeoverTicksLeft($takeover)
381 1
            )];
382
        }
383
384
        return null;
385
    }
386
387 2
    public function getTakeoverTicksLeft(ShipTakeoverInterface $takeover = null): int
388
    {
389 2
        $takeover = $takeover ?? $this->get()->getTakeoverActive();
390 2
        if ($takeover === null) {
391
            throw new RuntimeException('should not call when active takeover is null');
392
        }
393
394 2
        $currentTurn = $this->game->getCurrentRound()->getTurn();
395
396 2
        return $takeover->getStartTurn() + ShipTakeoverManagerInterface::TURNS_TO_TAKEOVER - $currentTurn;
397
    }
398
399
    public function canBeScrapped(): bool
400
    {
401
        $ship = $this->get();
402
403
        return $ship->isBase() && $ship->getState() !== ShipStateEnum::SHIP_STATE_UNDER_SCRAPPING;
404
    }
405
406
    public function getCrewStyle(): string
407
    {
408
        $ship = $this->get();
409
        $excessCrew = $ship->getExcessCrewCount();
410
411
        if ($excessCrew === 0) {
412
            return "";
413
        }
414
415
        return $excessCrew > 0 ? "color: green;" : "color: red;";
416
    }
417
418 1
    public function getHullSystemData(): HullSystemData
419
    {
420 1
        $hullSystemData = $this->getSpecificShipSystem(
421 1
            ShipSystemTypeEnum::SYSTEM_HULL,
422 1
            HullSystemData::class
423 1
        );
424
425 1
        if ($hullSystemData === null) {
426
            throw new SystemNotFoundException('no hull installed?');
427
        }
428
429 1
        return $hullSystemData;
430
    }
431
432
    public function getShieldSystemData(): ?ShieldSystemData
433
    {
434
        return $this->getSpecificShipSystem(
435
            ShipSystemTypeEnum::SYSTEM_SHIELDS,
436
            ShieldSystemData::class
437
        );
438
    }
439
440 2
    public function getEpsSystemData(): ?EpsSystemData
441
    {
442 2
        return $this->getSpecificShipSystem(
443 2
            ShipSystemTypeEnum::SYSTEM_EPS,
444 2
            EpsSystemData::class
445 2
        );
446
    }
447
448
    public function getWarpDriveSystemData(): ?WarpDriveSystemData
449
    {
450
        return $this->getSpecificShipSystem(
451
            ShipSystemTypeEnum::SYSTEM_WARPDRIVE,
452
            WarpDriveSystemData::class
453
        );
454
    }
455
456
    public function getTrackerSystemData(): ?TrackerSystemData
457
    {
458
        return $this->getSpecificShipSystem(
459
            ShipSystemTypeEnum::SYSTEM_TRACKER,
460
            TrackerSystemData::class
461
        );
462
    }
463
464
    public function getWebEmitterSystemData(): ?WebEmitterSystemData
465
    {
466
        return $this->getSpecificShipSystem(
467
            ShipSystemTypeEnum::SYSTEM_THOLIAN_WEB,
468
            WebEmitterSystemData::class
469
        );
470
    }
471
472 3
    public function getAstroLaboratorySystemData(): ?AstroLaboratorySystemData
473
    {
474 3
        return $this->getSpecificShipSystem(
475 3
            ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY,
476 3
            AstroLaboratorySystemData::class
477 3
        );
478
    }
479
480
    public function getProjectileLauncherSystemData(): ?ProjectileLauncherSystemData
481
    {
482
        return $this->getSpecificShipSystem(
483
            ShipSystemTypeEnum::SYSTEM_TORPEDO,
484
            ProjectileLauncherSystemData::class
485
        );
486
    }
487
488
    /**
489
     * @template T
490
     * @param class-string<T> $className
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
491
     *
492
     * @return T|null
493
     */
494 6
    private function getSpecificShipSystem(ShipSystemTypeEnum $systemType, string $className)
495
    {
496 6
        return $this->systemDataDeserializer->getSpecificShipSystem(
497 6
            $this->get(),
498 6
            $systemType,
499 6
            $className,
500 6
            $this->shipSystemDataCache,
501 6
            $this->shipWrapperFactory
502 6
        );
503
    }
504
}
505