Passed
Push — dev ( 3fd410...aa33df )
by Janko
13:32
created

SpacecraftWrapper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
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 9
dl 0
loc 13
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\Spacecraft\Lib;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use RuntimeException;
11
use Stu\Component\Spacecraft\Repair\RepairUtilInterface;
12
use Stu\Component\Spacecraft\SpacecraftAlertStateEnum;
13
use Stu\Component\Spacecraft\System\Data\AbstractSystemData;
14
use Stu\Component\Spacecraft\System\Data\ComputerSystemData;
15
use Stu\Component\Spacecraft\System\Data\EnergyWeaponSystemData;
16
use Stu\Component\Spacecraft\System\Data\EpsSystemData;
17
use Stu\Component\Spacecraft\System\Data\FusionCoreSystemData;
18
use Stu\Component\Spacecraft\System\Data\HullSystemData;
19
use Stu\Component\Spacecraft\System\Data\LssSystemData;
20
use Stu\Component\Spacecraft\System\Data\ProjectileLauncherSystemData;
21
use Stu\Component\Spacecraft\System\Data\ShieldSystemData;
22
use Stu\Component\Spacecraft\System\Data\SingularityCoreSystemData;
23
use Stu\Component\Spacecraft\System\Data\WarpCoreSystemData;
24
use Stu\Component\Spacecraft\System\Data\WarpDriveSystemData;
25
use Stu\Component\Spacecraft\System\Exception\SystemNotFoundException;
26
use Stu\Component\Spacecraft\System\SpacecraftSystemManagerInterface;
27
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
28
use Stu\Component\Spacecraft\System\SystemDataDeserializerInterface;
29
use Stu\Module\Commodity\CommodityTypeEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Module\Commodity\CommodityTypeEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use Stu\Module\Control\GameControllerInterface;
31
use Stu\Module\Spacecraft\Lib\Interaction\ShipTakeoverManagerInterface;
32
use Stu\Module\Spacecraft\Lib\ReactorWrapper;
33
use Stu\Module\Spacecraft\Lib\ReactorWrapperInterface;
34
use Stu\Module\Spacecraft\Lib\ShipRepairCost;
35
use Stu\Module\Spacecraft\Lib\SpacecraftStateChangerInterface;
36
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
37
use Stu\Module\Ship\Lib\ShipWrapperInterface;
38
use Stu\Module\Spacecraft\Lib\Ui\StateIconAndTitle;
39
use Stu\Orm\Entity\SpacecraftSystemInterface;
40
use Stu\Orm\Entity\ShipTakeoverInterface;
41
use Stu\Orm\Entity\SpacecraftInterface;
42
use Stu\Orm\Repository\TorpedoTypeRepositoryInterface;
43
44
//TODO increase coverage
45
/**
46
 * @template T of SpacecraftInterface
47
 */
48
abstract class SpacecraftWrapper implements SpacecraftWrapperInterface
49
{
50
    /** @var Collection<int, AbstractSystemData> */
51
    private Collection $shipSystemDataCache;
52
53
    private ?ReactorWrapperInterface $reactorWrapper = null;
54
55
    private ?int $epsUsage = null;
56
57
    /**
58
     * @param T $spacecraft
59
     */
60 66
    public function __construct(
61
        protected SpacecraftInterface $spacecraft,
62
        private SpacecraftSystemManagerInterface $spacecraftSystemManager,
63
        private SystemDataDeserializerInterface $systemDataDeserializer,
64
        private TorpedoTypeRepositoryInterface $torpedoTypeRepository,
65
        protected GameControllerInterface $game,
66
        protected SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
67
        private SpacecraftStateChangerInterface $spacecraftStateChanger,
68
        private RepairUtilInterface $repairUtil,
69
        private StateIconAndTitle $stateIconAndTitle
70
    ) {
71
72 66
        $this->shipSystemDataCache = new ArrayCollection();
73
    }
74
75
    #[Override]
76
    public function get(): SpacecraftInterface
77
    {
78
        return $this->spacecraft;
79
    }
80
81
    #[Override]
82
    public function getSpacecraftWrapperFactory(): SpacecraftWrapperFactoryInterface
83
    {
84
        return $this->spacecraftWrapperFactory;
85
    }
86
87
    #[Override]
88
    public function getSpacecraftSystemManager(): SpacecraftSystemManagerInterface
89
    {
90
        return $this->spacecraftSystemManager;
91
    }
92
93 3
    #[Override]
94
    public function getEpsUsage(): int
95
    {
96 3
        if ($this->epsUsage === null) {
97 3
            $this->epsUsage = $this->reloadEpsUsage();
98
        }
99 3
        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...
100
    }
101
102
    #[Override]
103
    public function lowerEpsUsage(int $value): void
104
    {
105
        $this->epsUsage -= $value;
106
    }
107
108 3
    private function reloadEpsUsage(): int
109
    {
110 3
        $result = 0;
111
112 3
        foreach ($this->spacecraftSystemManager->getActiveSystems($this->spacecraft) as $shipSystem) {
113 3
            $result += $this->spacecraftSystemManager->getEnergyConsumption($shipSystem->getSystemType());
114
        }
115
116 3
        return $this->get()->hasComputer()
117 3
            ? $result + $this->getComputerSystemDataMandatory()->getAlertState()->getEpsUsage()
118 3
            : $result;
119
    }
120
121 2
    public function getReactorUsage(): int
122
    {
123 2
        $reactor = $this->reactorWrapper;
124 2
        if ($reactor === null) {
125
            throw new RuntimeException('this should not happen');
126
        }
127
128 2
        return $this->getEpsUsage() + $reactor->getUsage();
129
    }
130
131 9
    #[Override]
132
    public function getReactorWrapper(): ?ReactorWrapperInterface
133
    {
134 9
        if ($this->reactorWrapper === null) {
135 9
            $ship = $this->spacecraft;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->spacecraft of type Stu\Orm\Entity\SpacecraftInterface is incompatible with the declared type Stu\Module\Spacecraft\Lib\T of property $spacecraft.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
136 9
            $reactorSystemData = null;
137
138
139 9
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPCORE)) {
140 5
                $reactorSystemData = $this->getSpecificShipSystem(
141 5
                    SpacecraftSystemTypeEnum::WARPCORE,
142 5
                    WarpCoreSystemData::class
143 5
                );
144
            }
145 9
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::SINGULARITY_REACTOR)) {
146
                $reactorSystemData = $this->getSpecificShipSystem(
147
                    SpacecraftSystemTypeEnum::SINGULARITY_REACTOR,
148
                    SingularityCoreSystemData::class
149
                );
150
            }
151 9
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::FUSION_REACTOR)) {
152
                $reactorSystemData = $this->getSpecificShipSystem(
153
                    SpacecraftSystemTypeEnum::FUSION_REACTOR,
154
                    FusionCoreSystemData::class
155
                );
156
            }
157
158 9
            if ($reactorSystemData === null) {
159 6
                return null;
160
            }
161
162 5
            $this->reactorWrapper = new ReactorWrapper($this, $reactorSystemData);
163
        }
164
165 5
        return $this->reactorWrapper;
166
    }
167
168 3
    #[Override]
169
    public function getAlertState(): SpacecraftAlertStateEnum
170
    {
171 3
        return $this->getComputerSystemDataMandatory()->getAlertState();
172
    }
173
174
    #[Override]
175
    public function setAlertState(SpacecraftAlertStateEnum $alertState): ?string
176
    {
177
        $msg = $this->spacecraftStateChanger->changeAlertState($this, $alertState);
178
        $this->epsUsage = $this->reloadEpsUsage();
179
180
        return $msg;
181
    }
182
183 2
    #[Override]
184
    public function isUnalerted(): bool
185
    {
186 2
        return !$this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::COMPUTER)
187 2
            || $this->getComputerSystemDataMandatory()->isAlertGreen();
188
    }
189
190 1
    #[Override]
191
    public function getSensorRange(): int
192
    {
193 1
        $lssSystemData = $this->getLssSystemData();
194 1
        if ($lssSystemData === null) {
195
            return 0;
196
        }
197
198 1
        return (int) (ceil($lssSystemData->getSensorRange()
199 1
            * $this->get()->getSpacecraftSystem(SpacecraftSystemTypeEnum::LSS)->getStatus() / 100));
200
    }
201
202 3
    #[Override]
203
    public function getShieldRegenerationRate(): int
204
    {
205 3
        $regenerationPercentage = $this->get()->isSystemHealthy(SpacecraftSystemTypeEnum::SHIELDS) ? 10 : 0;
206
207 3
        $shield = $this->get()->getShield();
208 3
        $maxshield = $this->get()->getMaxShield();
209
210 3
        $result = (int) ceil(($maxshield / 100) * $regenerationPercentage);
211
212 3
        if ($result > $maxshield - $shield) {
213 1
            $result = $maxshield - $shield;
214
        }
215
216 3
        return $result;
217
    }
218
219
    /**
220
     * highest damage first, then prio
221
     *
222
     * @return SpacecraftSystemInterface[]
223
     */
224 3
    #[Override]
225
    public function getDamagedSystems(): array
226
    {
227 3
        $damagedSystems = [];
228 3
        $prioArray = [];
229 3
        foreach ($this->spacecraft->getSystems() as $system) {
230 2
            if ($system->getStatus() < 100) {
231
                $damagedSystems[] = $system;
232
                $prioArray[$system->getSystemType()->value] = $this->spacecraftSystemManager->lookupSystem($system->getSystemType())->getPriority();
233
            }
234
        }
235
236
        // sort by damage and priority
237 3
        usort(
238 3
            $damagedSystems,
239 3
            function (SpacecraftSystemInterface $a, SpacecraftSystemInterface $b) use ($prioArray): int {
240
                if ($a->getStatus() === $b->getStatus()) {
241
                    return $prioArray[$b->getSystemType()->value] <=> $prioArray[$a->getSystemType()->value];
242
                }
243
                return ($a->getStatus() < $b->getStatus()) ? -1 : 1;
244 3
            }
245 3
        );
246
247 3
        return $damagedSystems;
248
    }
249
250 10
    #[Override]
251
    public function isSelectable(): bool
252
    {
253 10
        return $this->game->getUser() === $this->spacecraft->getUser()
254 10
            && $this->spacecraft->getType()->getModuleView() !== null;
255
    }
256
257 2
    #[Override]
258
    public function canBeRepaired(): bool
259
    {
260 2
        if (!$this->isUnalerted()) {
261
            return false;
262
        }
263
264 2
        if ($this->spacecraft->isShielded()) {
265
            return false;
266
        }
267
268 2
        if ($this->spacecraft->isCloaked()) {
269
            return false;
270
        }
271
272 2
        if ($this->getDamagedSystems() !== []) {
273
            return true;
274
        }
275
276 2
        return $this->spacecraft->getHull() < $this->spacecraft->getMaxHull();
277
    }
278
279 4
    #[Override]
280
    public function canFire(): bool
281
    {
282 4
        $ship = $this->spacecraft;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->spacecraft of type Stu\Orm\Entity\SpacecraftInterface is incompatible with the declared type Stu\Module\Spacecraft\Lib\T of property $spacecraft.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
283 4
        if (!$ship->getNbs()) {
284 1
            return false;
285
        }
286 3
        if (!$ship->hasActiveWeapon()) {
287 1
            return false;
288
        }
289
290 2
        $epsSystem = $this->getEpsSystemData();
291 2
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
292
    }
293
294 2
    #[Override]
295
    public function canMan(): bool
296
    {
297 2
        $buildplan = $this->spacecraft->getBuildplan();
298
299 2
        return $buildplan !== null
300 2
            && $buildplan->getCrew() > 0
301 2
            && $this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::LIFE_SUPPORT);
302
    }
303
304
    #[Override]
305
    public function getRepairDuration(): int
306
    {
307
        return $this->repairUtil->getRepairDuration($this);
308
    }
309
310
    #[Override]
311
    public function getRepairDurationPreview(): int
312
    {
313
        return $this->repairUtil->getRepairDurationPreview($this);
314
    }
315
316
    #[Override]
317
    public function getRepairCosts(): array
318
    {
319
        $neededParts = $this->repairUtil->determineSpareParts($this, false);
320
321
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
322
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
323
324
        return [
325
            new ShipRepairCost($neededSpareParts, CommodityTypeEnum::COMMODITY_SPARE_PART, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART)),
326
            new ShipRepairCost($neededSystemComponents, CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT))
327
        ];
328
    }
329
330
    #[Override]
331
    public function getPossibleTorpedoTypes(): array
332
    {
333
        if ($this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TORPEDO_STORAGE)) {
334
            return $this->torpedoTypeRepository->getAll();
335
        }
336
337
        return $this->torpedoTypeRepository->getByLevel($this->spacecraft->getRump()->getTorpedoLevel());
338
    }
339
340
    #[Override]
341
    public function getTractoredShipWrapper(): ?ShipWrapperInterface
342
    {
343
        $tractoredShip = $this->spacecraft->getTractoredShip();
344
        if ($tractoredShip === null) {
345
            return null;
346
        }
347
348
        return $this->spacecraftWrapperFactory->wrapShip($tractoredShip);
349
    }
350
351 4
    #[Override]
352
    public function getStateIconAndTitle(): ?array
353
    {
354 4
        return $this->stateIconAndTitle->getStateIconAndTitle($this);
355
    }
356
357
    #[Override]
358
    public function getTakeoverTicksLeft(?ShipTakeoverInterface $takeover = null): int
359
    {
360
        $takeover ??= $this->spacecraft->getTakeoverActive();
361
        if ($takeover === null) {
362
            throw new RuntimeException('should not call when active takeover is null');
363
        }
364
365
        $currentTurn = $this->game->getCurrentRound()->getTurn();
366
367
        return $takeover->getStartTurn() + ShipTakeoverManagerInterface::TURNS_TO_TAKEOVER - $currentTurn;
368
    }
369
370 6
    #[Override]
371
    public function getCrewStyle(): string
372
    {
373 6
        $ship = $this->spacecraft;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->spacecraft of type Stu\Orm\Entity\SpacecraftInterface is incompatible with the declared type Stu\Module\Spacecraft\Lib\T of property $spacecraft.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
374 6
        $excessCrew = $ship->getExcessCrewCount();
375
376 6
        if ($excessCrew === 0) {
377 5
            return "";
378
        }
379
380 3
        return $excessCrew > 0 ? "color: green;" : "color: red;";
381
    }
382
383 10
    #[Override]
384
    public function getHullSystemData(): HullSystemData
385
    {
386 10
        $hullSystemData = $this->getSpecificShipSystem(
387 10
            SpacecraftSystemTypeEnum::HULL,
388 10
            HullSystemData::class
389 10
        );
390
391 10
        if ($hullSystemData === null) {
392
            throw new SystemNotFoundException('no hull installed?');
393
        }
394
395 10
        return $hullSystemData;
396
    }
397
398 9
    #[Override]
399
    public function getShieldSystemData(): ?ShieldSystemData
400
    {
401 9
        return $this->getSpecificShipSystem(
402 9
            SpacecraftSystemTypeEnum::SHIELDS,
403 9
            ShieldSystemData::class
404 9
        );
405
    }
406
407 20
    #[Override]
408
    public function getEpsSystemData(): ?EpsSystemData
409
    {
410 20
        return $this->getSpecificShipSystem(
411 20
            SpacecraftSystemTypeEnum::EPS,
412 20
            EpsSystemData::class
413 20
        );
414
    }
415
416 5
    #[Override]
417
    public function getComputerSystemDataMandatory(): ComputerSystemData
418
    {
419 5
        $computer = $this->getSpecificShipSystem(
420 5
            SpacecraftSystemTypeEnum::COMPUTER,
421 5
            ComputerSystemData::class
422 5
        );
423 5
        if ($computer === null) {
424
            throw new SystemNotFoundException('no computer installed?');
425
        }
426
427 5
        return $computer;
428
    }
429
430 2
    #[Override]
431
    public function getLssSystemData(): ?LssSystemData
432
    {
433 2
        return $this->getSpecificShipSystem(
434 2
            SpacecraftSystemTypeEnum::LSS,
435 2
            LssSystemData::class
436 2
        );
437
    }
438
439 1
    #[Override]
440
    public function getEnergyWeaponSystemData(): ?EnergyWeaponSystemData
441
    {
442 1
        return $this->getSpecificShipSystem(
443 1
            SpacecraftSystemTypeEnum::PHASER,
444 1
            EnergyWeaponSystemData::class
445 1
        );
446
    }
447
448 10
    #[Override]
449
    public function getWarpDriveSystemData(): ?WarpDriveSystemData
450
    {
451 10
        return $this->getSpecificShipSystem(
452 10
            SpacecraftSystemTypeEnum::WARPDRIVE,
453 10
            WarpDriveSystemData::class
454 10
        );
455
    }
456
457 1
    #[Override]
458
    public function getProjectileLauncherSystemData(): ?ProjectileLauncherSystemData
459
    {
460 1
        return $this->getSpecificShipSystem(
461 1
            SpacecraftSystemTypeEnum::TORPEDO,
462 1
            ProjectileLauncherSystemData::class
463 1
        );
464
    }
465
466
    /**
467
     * @template T2
468
     * @param class-string<T2> $className
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T2> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T2>.
Loading history...
469
     *
470
     * @return T2|null
471
     */
472 25
    protected function getSpecificShipSystem(SpacecraftSystemTypeEnum $systemType, string $className)
473
    {
474 25
        return $this->systemDataDeserializer->getSpecificShipSystem(
475 25
            $this->spacecraft,
476 25
            $systemType,
477 25
            $className,
478 25
            $this->shipSystemDataCache,
479 25
            $this->spacecraftWrapperFactory
480 25
        );
481
    }
482
483
    #[Override]
484
    public function __toString(): string
485
    {
486
        $systems = implode(",\n", $this->spacecraft->getSystems()
487
            ->filter(fn($system): bool => $system->getData() !== null)
488
            ->map(fn($system): string => $system->__toString())
489
            ->toArray());
490
491
        return sprintf(
492
            "spacecraft: {%s,\n  systems: [\n%s\n}\n]",
493
            $this->spacecraft->__toString(),
494
            $systems
495
        );
496
    }
497
}
498