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