Passed
Push — dev ( 996fbb...25004f )
by Janko
16:40
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 3
    #[Override]
191
    public function getShieldRegenerationRate(): int
192
    {
193 3
        $regenerationPercentage = $this->get()->isSystemHealthy(SpacecraftSystemTypeEnum::SHIELDS) ? 10 : 0;
194
195 3
        $shield = $this->get()->getCondition()->getShield();
196 3
        $maxshield = $this->get()->getMaxShield();
197
198 3
        $result = (int) ceil(($maxshield / 100) * $regenerationPercentage);
199
200 3
        if ($result > $maxshield - $shield) {
201 1
            $result = $maxshield - $shield;
202
        }
203
204 3
        return $result;
205
    }
206
207
    /**
208
     * highest damage first, then prio
209
     *
210
     * @return SpacecraftSystemInterface[]
211
     */
212 3
    #[Override]
213
    public function getDamagedSystems(): array
214
    {
215 3
        $damagedSystems = [];
216 3
        $prioArray = [];
217 3
        foreach ($this->spacecraft->getSystems() as $system) {
218 2
            if ($system->getStatus() < 100) {
219
                $damagedSystems[] = $system;
220
                $prioArray[$system->getSystemType()->value] = $this->spacecraftSystemManager->lookupSystem($system->getSystemType())->getPriority();
221
            }
222
        }
223
224
        // sort by damage and priority
225 3
        usort(
226 3
            $damagedSystems,
227 3
            function (SpacecraftSystemInterface $a, SpacecraftSystemInterface $b) use ($prioArray): int {
228
                if ($a->getStatus() === $b->getStatus()) {
229
                    return $prioArray[$b->getSystemType()->value] <=> $prioArray[$a->getSystemType()->value];
230
                }
231
                return ($a->getStatus() < $b->getStatus()) ? -1 : 1;
232 3
            }
233 3
        );
234
235 3
        return $damagedSystems;
236
    }
237
238 10
    #[Override]
239
    public function isSelectable(): bool
240
    {
241 10
        return $this->game->getUser() === $this->spacecraft->getUser()
242 10
            && $this->spacecraft->getType()->getModuleView() !== null;
243
    }
244
245 2
    #[Override]
246
    public function canBeRepaired(): bool
247
    {
248 2
        if (!$this->isUnalerted()) {
249
            return false;
250
        }
251
252 2
        if ($this->spacecraft->isShielded()) {
253
            return false;
254
        }
255
256 2
        if ($this->spacecraft->isCloaked()) {
257
            return false;
258
        }
259
260 2
        if ($this->getDamagedSystems() !== []) {
261
            return true;
262
        }
263
264 2
        return $this->spacecraft->getCondition()->getHull() < $this->spacecraft->getMaxHull();
265
    }
266
267 4
    #[Override]
268
    public function canFire(): bool
269
    {
270 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...
271 4
        if (!$ship->getNbs()) {
272 1
            return false;
273
        }
274 3
        if (!$ship->hasActiveWeapon()) {
275 1
            return false;
276
        }
277
278 2
        $epsSystem = $this->getEpsSystemData();
279 2
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
280
    }
281
282 2
    #[Override]
283
    public function canMan(): bool
284
    {
285 2
        $buildplan = $this->spacecraft->getBuildplan();
286
287 2
        return $buildplan !== null
288 2
            && $buildplan->getCrew() > 0
289 2
            && $this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::LIFE_SUPPORT);
290
    }
291
292
    #[Override]
293
    public function getRepairDuration(): int
294
    {
295
        return $this->repairUtil->getRepairDuration($this);
296
    }
297
298
    #[Override]
299
    public function getRepairDurationPreview(): int
300
    {
301
        return $this->repairUtil->getRepairDurationPreview($this);
302
    }
303
304
    #[Override]
305
    public function getRepairCosts(): array
306
    {
307
        $neededParts = $this->repairUtil->determineSpareParts($this, false);
308
309
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
310
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
311
312
        return [
313
            new ShipRepairCost($neededSpareParts, CommodityTypeEnum::COMMODITY_SPARE_PART, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART)),
314
            new ShipRepairCost($neededSystemComponents, CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT))
315
        ];
316
    }
317
318
    #[Override]
319
    public function getPossibleTorpedoTypes(): array
320
    {
321
        if ($this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TORPEDO_STORAGE)) {
322
            return $this->torpedoTypeRepository->getAll();
323
        }
324
325
        return $this->torpedoTypeRepository->getByLevel($this->spacecraft->getRump()->getTorpedoLevel());
326
    }
327
328
    #[Override]
329
    public function getTractoredShipWrapper(): ?ShipWrapperInterface
330
    {
331
        $tractoredShip = $this->spacecraft->getTractoredShip();
332
        if ($tractoredShip === null) {
333
            return null;
334
        }
335
336
        return $this->spacecraftWrapperFactory->wrapShip($tractoredShip);
337
    }
338
339 4
    #[Override]
340
    public function getStateIconAndTitle(): ?array
341
    {
342 4
        return $this->stateIconAndTitle->getStateIconAndTitle($this);
343
    }
344
345
    #[Override]
346
    public function getTakeoverTicksLeft(?ShipTakeoverInterface $takeover = null): int
347
    {
348
        $takeover ??= $this->spacecraft->getTakeoverActive();
349
        if ($takeover === null) {
350
            throw new RuntimeException('should not call when active takeover is null');
351
        }
352
353
        $currentTurn = $this->game->getCurrentRound()->getTurn();
354
355
        return $takeover->getStartTurn() + ShipTakeoverManagerInterface::TURNS_TO_TAKEOVER - $currentTurn;
356
    }
357
358 6
    #[Override]
359
    public function getCrewStyle(): string
360
    {
361 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...
362 6
        $excessCrew = $ship->getExcessCrewCount();
363
364 6
        if ($excessCrew === 0) {
365 5
            return "";
366
        }
367
368 3
        return $excessCrew > 0 ? "color: green;" : "color: red;";
369
    }
370
371 10
    #[Override]
372
    public function getHullSystemData(): HullSystemData
373
    {
374 10
        $hullSystemData = $this->getSpecificShipSystem(
375 10
            SpacecraftSystemTypeEnum::HULL,
376 10
            HullSystemData::class
377 10
        );
378
379 10
        if ($hullSystemData === null) {
380
            throw new SystemNotFoundException('no hull installed?');
381
        }
382
383 10
        return $hullSystemData;
384
    }
385
386 9
    #[Override]
387
    public function getShieldSystemData(): ?ShieldSystemData
388
    {
389 9
        return $this->getSpecificShipSystem(
390 9
            SpacecraftSystemTypeEnum::SHIELDS,
391 9
            ShieldSystemData::class
392 9
        );
393
    }
394
395 20
    #[Override]
396
    public function getEpsSystemData(): ?EpsSystemData
397
    {
398 20
        return $this->getSpecificShipSystem(
399 20
            SpacecraftSystemTypeEnum::EPS,
400 20
            EpsSystemData::class
401 20
        );
402
    }
403
404 5
    #[Override]
405
    public function getComputerSystemDataMandatory(): ComputerSystemData
406
    {
407 5
        $computer = $this->getSpecificShipSystem(
408 5
            SpacecraftSystemTypeEnum::COMPUTER,
409 5
            ComputerSystemData::class
410 5
        );
411 5
        if ($computer === null) {
412
            throw new SystemNotFoundException('no computer installed?');
413
        }
414
415 5
        return $computer;
416
    }
417
418 3
    #[Override]
419
    public function getLssSystemData(): ?LssSystemData
420
    {
421 3
        return $this->getSpecificShipSystem(
422 3
            SpacecraftSystemTypeEnum::LSS,
423 3
            LssSystemData::class
424 3
        );
425
    }
426
427 1
    #[Override]
428
    public function getEnergyWeaponSystemData(): ?EnergyWeaponSystemData
429
    {
430 1
        return $this->getSpecificShipSystem(
431 1
            SpacecraftSystemTypeEnum::PHASER,
432 1
            EnergyWeaponSystemData::class
433 1
        );
434
    }
435
436 10
    #[Override]
437
    public function getWarpDriveSystemData(): ?WarpDriveSystemData
438
    {
439 10
        return $this->getSpecificShipSystem(
440 10
            SpacecraftSystemTypeEnum::WARPDRIVE,
441 10
            WarpDriveSystemData::class
442 10
        );
443
    }
444
445 1
    #[Override]
446
    public function getProjectileLauncherSystemData(): ?ProjectileLauncherSystemData
447
    {
448 1
        return $this->getSpecificShipSystem(
449 1
            SpacecraftSystemTypeEnum::TORPEDO,
450 1
            ProjectileLauncherSystemData::class
451 1
        );
452
    }
453
454
    /**
455
     * @template T2
456
     * @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...
457
     *
458
     * @return T2|null
459
     */
460 26
    protected function getSpecificShipSystem(SpacecraftSystemTypeEnum $systemType, string $className)
461
    {
462 26
        return $this->systemDataDeserializer->getSpecificShipSystem(
463 26
            $this->spacecraft,
464 26
            $systemType,
465 26
            $className,
466 26
            $this->shipSystemDataCache,
467 26
            $this->spacecraftWrapperFactory
468 26
        );
469
    }
470
471
    #[Override]
472
    public function __toString(): string
473
    {
474
        $systems = implode(",\n", $this->spacecraft->getSystems()
475
            ->filter(fn($system): bool => $system->getData() !== null)
476
            ->map(fn($system): string => $system->__toString())
477
            ->toArray());
478
479
        return sprintf(
480
            "spacecraft: {%s,\n  systems: [\n%s\n}\n]",
481
            $this->spacecraft->__toString(),
482
            $systems
483
        );
484
    }
485
}
486