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