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