Passed
Push — dev ( 98511f...00baf5 )
by Janko
15:17
created

SpacecraftWrapper::getShieldRegenerationRate()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 0
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 3
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\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