Passed
Push — dev ( 00bc98...ea1fa5 )
by Janko
14:47
created

SpacecraftWrapper::isSelectable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 2
rs 10
c 0
b 0
f 0
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