Passed
Pull Request — master (#2133)
by Janko
26:05 queued 15:18
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\EnergyWeaponSystemData;
15
use Stu\Component\Spacecraft\System\Data\EpsSystemData;
16
use Stu\Component\Spacecraft\System\Data\FusionCoreSystemData;
17
use Stu\Component\Spacecraft\System\Data\HullSystemData;
18
use Stu\Component\Spacecraft\System\Data\LssSystemData;
19
use Stu\Component\Spacecraft\System\Data\ProjectileLauncherSystemData;
20
use Stu\Component\Spacecraft\System\Data\ShieldSystemData;
21
use Stu\Component\Spacecraft\System\Data\SingularityCoreSystemData;
22
use Stu\Component\Spacecraft\System\Data\WarpCoreSystemData;
23
use Stu\Component\Spacecraft\System\Data\WarpDriveSystemData;
24
use Stu\Component\Spacecraft\System\Exception\SystemNotFoundException;
25
use Stu\Component\Spacecraft\System\SpacecraftSystemManagerInterface;
26
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
27
use Stu\Component\Spacecraft\System\SystemDataDeserializerInterface;
28
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...
29
use Stu\Module\Control\GameControllerInterface;
30
use Stu\Module\Spacecraft\Lib\Interaction\ShipTakeoverManagerInterface;
31
use Stu\Module\Spacecraft\Lib\ReactorWrapper;
32
use Stu\Module\Spacecraft\Lib\ReactorWrapperInterface;
33
use Stu\Module\Spacecraft\Lib\ShipRepairCost;
34
use Stu\Module\Spacecraft\Lib\SpacecraftStateChangerInterface;
35
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
36
use Stu\Module\Ship\Lib\ShipWrapperInterface;
37
use Stu\Module\Spacecraft\Lib\Ui\StateIconAndTitle;
38
use Stu\Orm\Entity\SpacecraftSystemInterface;
39
use Stu\Orm\Entity\ShipTakeoverInterface;
40
use Stu\Orm\Entity\SpacecraftInterface;
41
use Stu\Orm\Repository\TorpedoTypeRepositoryInterface;
42
43
//TODO increase coverage
44
/**
45
 * @template T of SpacecraftInterface
46
 */
47
abstract class SpacecraftWrapper implements SpacecraftWrapperInterface
48
{
49
    /** @var Collection<int, AbstractSystemData> */
50
    private Collection $shipSystemDataCache;
51
52
    private ?ReactorWrapperInterface $reactorWrapper = null;
53
54
    private ?int $epsUsage = null;
55
56
    /**
57
     * @param T $spacecraft
58
     */
59 66
    public function __construct(
60
        protected SpacecraftInterface $spacecraft,
61
        private SpacecraftSystemManagerInterface $spacecraftSystemManager,
62
        private SystemDataDeserializerInterface $systemDataDeserializer,
63
        private TorpedoTypeRepositoryInterface $torpedoTypeRepository,
64
        protected GameControllerInterface $game,
65
        protected SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
66
        private SpacecraftStateChangerInterface $spacecraftStateChanger,
67
        private RepairUtilInterface $repairUtil,
68
        private StateIconAndTitle $stateIconAndTitle
69
    ) {
70
71 66
        $this->shipSystemDataCache = new ArrayCollection();
72
    }
73
74
    #[Override]
75
    public function get(): SpacecraftInterface
76
    {
77
        return $this->spacecraft;
78
    }
79
80
    #[Override]
81
    public function getSpacecraftWrapperFactory(): SpacecraftWrapperFactoryInterface
82
    {
83
        return $this->spacecraftWrapperFactory;
84
    }
85
86
    #[Override]
87
    public function getSpacecraftSystemManager(): SpacecraftSystemManagerInterface
88
    {
89
        return $this->spacecraftSystemManager;
90
    }
91
92 3
    #[Override]
93
    public function getEpsUsage(): int
94
    {
95 3
        if ($this->epsUsage === null) {
96 3
            $this->epsUsage = $this->reloadEpsUsage();
97
        }
98 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...
99
    }
100
101
    #[Override]
102
    public function lowerEpsUsage(int $value): void
103
    {
104
        $this->epsUsage -= $value;
105
    }
106
107 3
    private function reloadEpsUsage(): int
108
    {
109 3
        $result = 0;
110
111 3
        foreach ($this->spacecraftSystemManager->getActiveSystems($this->spacecraft) as $shipSystem) {
112 3
            $result += $this->spacecraftSystemManager->getEnergyConsumption($shipSystem->getSystemType());
113
        }
114
115 3
        return $result + $this->spacecraft->getAlertState()->getEpsUsage();
116
    }
117
118 2
    public function getReactorUsage(): int
119
    {
120 2
        $reactor = $this->reactorWrapper;
121 2
        if ($reactor === null) {
122
            throw new RuntimeException('this should not happen');
123
        }
124
125 2
        return $this->getEpsUsage() + $reactor->getUsage();
126
    }
127
128 9
    #[Override]
129
    public function getReactorWrapper(): ?ReactorWrapperInterface
130
    {
131 9
        if ($this->reactorWrapper === null) {
132 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...
133 9
            $reactorSystemData = null;
134
135
136 9
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPCORE)) {
137 5
                $reactorSystemData = $this->getSpecificShipSystem(
138 5
                    SpacecraftSystemTypeEnum::WARPCORE,
139 5
                    WarpCoreSystemData::class
140 5
                );
141
            }
142 9
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::SINGULARITY_REACTOR)) {
143
                $reactorSystemData = $this->getSpecificShipSystem(
144
                    SpacecraftSystemTypeEnum::SINGULARITY_REACTOR,
145
                    SingularityCoreSystemData::class
146
                );
147
            }
148 9
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::FUSION_REACTOR)) {
149
                $reactorSystemData = $this->getSpecificShipSystem(
150
                    SpacecraftSystemTypeEnum::FUSION_REACTOR,
151
                    FusionCoreSystemData::class
152
                );
153
            }
154
155 9
            if ($reactorSystemData === null) {
156 6
                return null;
157
            }
158
159 5
            $this->reactorWrapper = new ReactorWrapper($this, $reactorSystemData);
160
        }
161
162 5
        return $this->reactorWrapper;
163
    }
164
165
    #[Override]
166
    public function setAlertState(SpacecraftAlertStateEnum $alertState): ?string
167
    {
168
        $msg = $this->spacecraftStateChanger->changeAlertState($this, $alertState);
169
        $this->epsUsage = $this->reloadEpsUsage();
170
171
        return $msg;
172
    }
173
174 1
    #[Override]
175
    public function getSensorRange(): int
176
    {
177 1
        $lssSystemData = $this->getLssSystemData();
178 1
        if ($lssSystemData === null) {
179
            return 0;
180
        }
181
182 1
        return (int) (ceil($lssSystemData->getSensorRange()
183 1
            * $this->get()->getSpacecraftSystem(SpacecraftSystemTypeEnum::LSS)->getStatus() / 100));
184
    }
185
186 3
    #[Override]
187
    public function getShieldRegenerationRate(): int
188
    {
189 3
        $regenerationPercentage = $this->get()->isSystemHealthy(SpacecraftSystemTypeEnum::SHIELDS) ? 10 : 0;
190
191 3
        $shield = $this->get()->getShield();
192 3
        $maxshield = $this->get()->getMaxShield();
193
194 3
        $result = (int) ceil(($maxshield / 100) * $regenerationPercentage);
195
196 3
        if ($result > $maxshield - $shield) {
197 1
            $result = $maxshield - $shield;
198
        }
199
200 3
        return $result;
201
    }
202
203
    /**
204
     * highest damage first, then prio
205
     *
206
     * @return SpacecraftSystemInterface[]
207
     */
208 3
    #[Override]
209
    public function getDamagedSystems(): array
210
    {
211 3
        $damagedSystems = [];
212 3
        $prioArray = [];
213 3
        foreach ($this->spacecraft->getSystems() as $system) {
214 2
            if ($system->getStatus() < 100) {
215
                $damagedSystems[] = $system;
216
                $prioArray[$system->getSystemType()->value] = $this->spacecraftSystemManager->lookupSystem($system->getSystemType())->getPriority();
217
            }
218
        }
219
220
        // sort by damage and priority
221 3
        usort(
222 3
            $damagedSystems,
223 3
            function (SpacecraftSystemInterface $a, SpacecraftSystemInterface $b) use ($prioArray): int {
224
                if ($a->getStatus() === $b->getStatus()) {
225
                    return $prioArray[$b->getSystemType()->value] <=> $prioArray[$a->getSystemType()->value];
226
                }
227
                return ($a->getStatus() < $b->getStatus()) ? -1 : 1;
228 3
            }
229 3
        );
230
231 3
        return $damagedSystems;
232
    }
233
234 10
    #[Override]
235
    public function isSelectable(): bool
236
    {
237 10
        return $this->game->getUser() === $this->spacecraft->getUser()
238 10
            && $this->spacecraft->getType()->getModuleView() !== null;
239
    }
240
241 2
    #[Override]
242
    public function canBeRepaired(): bool
243
    {
244 2
        if ($this->spacecraft->getAlertState() !== SpacecraftAlertStateEnum::ALERT_GREEN) {
245
            return false;
246
        }
247
248 2
        if ($this->spacecraft->isShielded()) {
249
            return false;
250
        }
251
252 2
        if ($this->spacecraft->isCloaked()) {
253
            return false;
254
        }
255
256 2
        if ($this->getDamagedSystems() !== []) {
257
            return true;
258
        }
259
260 2
        return $this->spacecraft->getHull() < $this->spacecraft->getMaxHull();
261
    }
262
263 4
    #[Override]
264
    public function canFire(): bool
265
    {
266 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...
267 4
        if (!$ship->getNbs()) {
268 1
            return false;
269
        }
270 3
        if (!$ship->hasActiveWeapon()) {
271 1
            return false;
272
        }
273
274 2
        $epsSystem = $this->getEpsSystemData();
275 2
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
276
    }
277
278 2
    #[Override]
279
    public function canMan(): bool
280
    {
281 2
        $buildplan = $this->spacecraft->getBuildplan();
282
283 2
        return $buildplan !== null
284 2
            && $buildplan->getCrew() > 0
285 2
            && $this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::LIFE_SUPPORT);
286
    }
287
288
    #[Override]
289
    public function getRepairDuration(): int
290
    {
291
        return $this->repairUtil->getRepairDuration($this);
292
    }
293
294
    #[Override]
295
    public function getRepairDurationPreview(): int
296
    {
297
        return $this->repairUtil->getRepairDurationPreview($this);
298
    }
299
300
    #[Override]
301
    public function getRepairCosts(): array
302
    {
303
        $neededParts = $this->repairUtil->determineSpareParts($this, false);
304
305
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
306
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
307
308
        return [
309
            new ShipRepairCost($neededSpareParts, CommodityTypeEnum::COMMODITY_SPARE_PART, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART)),
310
            new ShipRepairCost($neededSystemComponents, CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT))
311
        ];
312
    }
313
314
    #[Override]
315
    public function getPossibleTorpedoTypes(): array
316
    {
317
        if ($this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TORPEDO_STORAGE)) {
318
            return $this->torpedoTypeRepository->getAll();
319
        }
320
321
        return $this->torpedoTypeRepository->getByLevel($this->spacecraft->getRump()->getTorpedoLevel());
322
    }
323
324
    #[Override]
325
    public function getTractoredShipWrapper(): ?ShipWrapperInterface
326
    {
327
        $tractoredShip = $this->spacecraft->getTractoredShip();
328
        if ($tractoredShip === null) {
329
            return null;
330
        }
331
332
        return $this->spacecraftWrapperFactory->wrapShip($tractoredShip);
333
    }
334
335 4
    #[Override]
336
    public function getStateIconAndTitle(): ?array
337
    {
338 4
        return $this->stateIconAndTitle->getStateIconAndTitle($this);
339
    }
340
341
    #[Override]
342
    public function getTakeoverTicksLeft(?ShipTakeoverInterface $takeover = null): int
343
    {
344
        $takeover ??= $this->spacecraft->getTakeoverActive();
345
        if ($takeover === null) {
346
            throw new RuntimeException('should not call when active takeover is null');
347
        }
348
349
        $currentTurn = $this->game->getCurrentRound()->getTurn();
350
351
        return $takeover->getStartTurn() + ShipTakeoverManagerInterface::TURNS_TO_TAKEOVER - $currentTurn;
352
    }
353
354 6
    #[Override]
355
    public function getCrewStyle(): string
356
    {
357 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...
358 6
        $excessCrew = $ship->getExcessCrewCount();
359
360 6
        if ($excessCrew === 0) {
361 5
            return "";
362
        }
363
364 3
        return $excessCrew > 0 ? "color: green;" : "color: red;";
365
    }
366
367 10
    #[Override]
368
    public function getHullSystemData(): HullSystemData
369
    {
370 10
        $hullSystemData = $this->getSpecificShipSystem(
371 10
            SpacecraftSystemTypeEnum::HULL,
372 10
            HullSystemData::class
373 10
        );
374
375 10
        if ($hullSystemData === null) {
376
            throw new SystemNotFoundException('no hull installed?');
377
        }
378
379 10
        return $hullSystemData;
380
    }
381
382 9
    #[Override]
383
    public function getShieldSystemData(): ?ShieldSystemData
384
    {
385 9
        return $this->getSpecificShipSystem(
386 9
            SpacecraftSystemTypeEnum::SHIELDS,
387 9
            ShieldSystemData::class
388 9
        );
389
    }
390
391 20
    #[Override]
392
    public function getEpsSystemData(): ?EpsSystemData
393
    {
394 20
        return $this->getSpecificShipSystem(
395 20
            SpacecraftSystemTypeEnum::EPS,
396 20
            EpsSystemData::class
397 20
        );
398
    }
399
400 2
    #[Override]
401
    public function getLssSystemData(): ?LssSystemData
402
    {
403 2
        return $this->getSpecificShipSystem(
404 2
            SpacecraftSystemTypeEnum::LSS,
405 2
            LssSystemData::class
406 2
        );
407
    }
408
409 1
    #[Override]
410
    public function getEnergyWeaponSystemData(): ?EnergyWeaponSystemData
411
    {
412 1
        return $this->getSpecificShipSystem(
413 1
            SpacecraftSystemTypeEnum::PHASER,
414 1
            EnergyWeaponSystemData::class
415 1
        );
416
    }
417
418 10
    #[Override]
419
    public function getWarpDriveSystemData(): ?WarpDriveSystemData
420
    {
421 10
        return $this->getSpecificShipSystem(
422 10
            SpacecraftSystemTypeEnum::WARPDRIVE,
423 10
            WarpDriveSystemData::class
424 10
        );
425
    }
426
427 1
    #[Override]
428
    public function getProjectileLauncherSystemData(): ?ProjectileLauncherSystemData
429
    {
430 1
        return $this->getSpecificShipSystem(
431 1
            SpacecraftSystemTypeEnum::TORPEDO,
432 1
            ProjectileLauncherSystemData::class
433 1
        );
434
    }
435
436
    /**
437
     * @template T2
438
     * @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...
439
     *
440
     * @return T2|null
441
     */
442 24
    protected function getSpecificShipSystem(SpacecraftSystemTypeEnum $systemType, string $className)
443
    {
444 24
        return $this->systemDataDeserializer->getSpecificShipSystem(
445 24
            $this->spacecraft,
446 24
            $systemType,
447 24
            $className,
448 24
            $this->shipSystemDataCache,
449 24
            $this->spacecraftWrapperFactory
450 24
        );
451
    }
452
453
    #[Override]
454
    public function __toString(): string
455
    {
456
        $systems = implode(",\n", $this->spacecraft->getSystems()
457
            ->filter(fn($system): bool => $system->getData() !== null)
458
            ->map(fn($system): string => $system->__toString())
459
            ->toArray());
460
461
        return sprintf(
462
            "spacecraft: {%s,\n  systems: [\n%s\n}\n]",
463
            $this->spacecraft->__toString(),
464
            $systems
465
        );
466
    }
467
}
468