Test Failed
Push — dev ( cc891d...2da33f )
by Janko
09:11
created

SpacecraftWrapper::getSensorRange()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 8
ccs 2
cts 2
cp 1
crap 2
rs 10
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 63
     */
58
    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 63
70
        $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 3
91
    #[Override]
92
    public function getEpsUsage(): int
93 3
    {
94 3
        if ($this->epsUsage === null) {
95
            $this->epsUsage = $this->reloadEpsUsage();
96 3
        }
97
        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 3
106
    private function reloadEpsUsage(): int
107 3
    {
108
        $result = 0;
109 3
110 3
        foreach ($this->spacecraftSystemManager->getActiveSystems($this->spacecraft) as $shipSystem) {
111
            $result += $this->spacecraftSystemManager->getEnergyConsumption($shipSystem->getSystemType());
112
        }
113 3
114
        if ($this->spacecraft->getAlertState() == SpacecraftAlertStateEnum::ALERT_YELLOW) {
115
            $result += SpacecraftStateChangerInterface::ALERT_YELLOW_EPS_USAGE;
116 3
        }
117
        if ($this->spacecraft->getAlertState() == SpacecraftAlertStateEnum::ALERT_RED) {
118
            $result += SpacecraftStateChangerInterface::ALERT_RED_EPS_USAGE;
119
        }
120 3
121
        return $result;
122
    }
123 2
124
    public function getReactorUsage(): int
125 2
    {
126 2
        $reactor = $this->reactorWrapper;
127
        if ($reactor === null) {
128
            throw new RuntimeException('this should not happen');
129
        }
130 2
131
        return $this->getEpsUsage() + $reactor->getUsage();
132
    }
133 9
134
    #[Override]
135
    public function getReactorWrapper(): ?ReactorWrapperInterface
136 9
    {
137 9
        if ($this->reactorWrapper === null) {
138 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...
139
            $reactorSystemData = null;
140
141 9
142 5
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPCORE)) {
143 5
                $reactorSystemData = $this->getSpecificShipSystem(
144 5
                    SpacecraftSystemTypeEnum::WARPCORE,
145 5
                    WarpCoreSystemData::class
146
                );
147 9
            }
148
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::SINGULARITY_REACTOR)) {
149
                $reactorSystemData = $this->getSpecificShipSystem(
150
                    SpacecraftSystemTypeEnum::SINGULARITY_REACTOR,
151
                    SingularityCoreSystemData::class
152
                );
153 9
            }
154
            if ($ship->hasSpacecraftSystem(SpacecraftSystemTypeEnum::FUSION_REACTOR)) {
155
                $reactorSystemData = $this->getSpecificShipSystem(
156
                    SpacecraftSystemTypeEnum::FUSION_REACTOR,
157
                    FusionCoreSystemData::class
158
                );
159
            }
160 9
161 6
            if ($reactorSystemData === null) {
162
                return null;
163
            }
164 5
165
            $this->reactorWrapper = new ReactorWrapper($this, $reactorSystemData);
166
        }
167 5
168
        return $this->reactorWrapper;
169
    }
170
171
    #[Override]
172
    public function setAlertState(SpacecraftAlertStateEnum $alertState): ?string
173
    {
174
        $msg = $this->spacecraftStateChanger->changeAlertState($this, $alertState);
175
        $this->epsUsage = $this->reloadEpsUsage();
176
177
        return $msg;
178
    }
179
180
    #[Override]
181
    public function getSensorRange(): int
182
    {
183
        $lssSystemData = $this->getLssSystemData();
184 3
185
        return $lssSystemData !== null
186
            ? $lssSystemData->getSensorRange()
187 3
            : 0;
188 3
    }
189 3
190 2
191
    #[Override]
192
    public function getShieldRegenerationRate(): int
193
    {
194
        $regenerationPercentage = $this->get()->isSystemHealthy(SpacecraftSystemTypeEnum::SHIELDS) ? 10 : 0;
195
196
        return (int) ceil(($this->get()->getMaxShield() / 100) * $regenerationPercentage);
197 3
    }
198 3
199 3
    /**
200
     * highest damage first, then prio
201
     *
202
     * @return SpacecraftSystemInterface[]
203
     */
204 3
    #[Override]
205 3
    public function getDamagedSystems(): array
206
    {
207 3
        $damagedSystems = [];
208
        $prioArray = [];
209
        foreach ($this->spacecraft->getSystems() as $system) {
210 9
            if ($system->getStatus() < 100) {
211
                $damagedSystems[] = $system;
212
                $prioArray[$system->getSystemType()->value] = $this->spacecraftSystemManager->lookupSystem($system->getSystemType())->getPriority();
213 9
            }
214 9
        }
215
216
        // sort by damage and priority
217 2
        usort(
218
            $damagedSystems,
219
            function (SpacecraftSystemInterface $a, SpacecraftSystemInterface $b) use ($prioArray): int {
220 2
                if ($a->getStatus() === $b->getStatus()) {
221
                    return $prioArray[$b->getSystemType()->value] <=> $prioArray[$a->getSystemType()->value];
222
                }
223
                return ($a->getStatus() < $b->getStatus()) ? -1 : 1;
224 2
            }
225
        );
226
227
        return $damagedSystems;
228 2
    }
229
230
    #[Override]
231
    public function isSelectable(): bool
232 2
    {
233
        return $this->game->getUser() === $this->spacecraft->getUser()
234
            && $this->spacecraft->getType()->getModuleView() !== null;
235
    }
236 2
237
    #[Override]
238
    public function canBeRepaired(): bool
239 4
    {
240
        if ($this->spacecraft->getAlertState() !== SpacecraftAlertStateEnum::ALERT_GREEN) {
241
            return false;
242 4
        }
243 4
244 1
        if ($this->spacecraft->getShieldState()) {
245
            return false;
246 3
        }
247 1
248
        if ($this->spacecraft->isCloaked()) {
249
            return false;
250 2
        }
251 2
252
        if ($this->getDamagedSystems() !== []) {
253
            return true;
254
        }
255
256
        return $this->spacecraft->getHull() < $this->spacecraft->getMaxHull();
257
    }
258
259
    #[Override]
260
    public function canFire(): bool
261
    {
262
        $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...
263
        if (!$ship->getNbs()) {
264
            return false;
265
        }
266
        if (!$ship->hasActiveWeapon()) {
267
            return false;
268
        }
269
270
        $epsSystem = $this->getEpsSystemData();
271
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
272
    }
273
274
    #[Override]
275
    public function getRepairDuration(): int
276
    {
277
        return $this->repairUtil->getRepairDuration($this);
278
    }
279
280
    #[Override]
281
    public function getRepairDurationPreview(): int
282
    {
283
        return $this->repairUtil->getRepairDurationPreview($this);
284
    }
285
286
    #[Override]
287
    public function getRepairCosts(): array
288
    {
289
        $neededParts = $this->repairUtil->determineSpareParts($this, false);
290
291
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
292
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
293
294
        return [
295
            new ShipRepairCost($neededSpareParts, CommodityTypeEnum::COMMODITY_SPARE_PART, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART)),
296
            new ShipRepairCost($neededSystemComponents, CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT, CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT))
297
        ];
298
    }
299
300
    #[Override]
301 4
    public function getPossibleTorpedoTypes(): array
302
    {
303
        if ($this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TORPEDO_STORAGE)) {
304 4
            return $this->torpedoTypeRepository->getAll();
305
        }
306
307
        return $this->torpedoTypeRepository->getByLevel($this->spacecraft->getRump()->getTorpedoLevel());
308
    }
309
310
    #[Override]
311
    public function getTractoredShipWrapper(): ?ShipWrapperInterface
312
    {
313
        $tractoredShip = $this->spacecraft->getTractoredShip();
314
        if ($tractoredShip === null) {
315
            return null;
316
        }
317
318
        return $this->spacecraftWrapperFactory->wrapShip($tractoredShip);
319
    }
320 6
321
    #[Override]
322
    public function getStateIconAndTitle(): ?array
323 6
    {
324 6
        return $this->stateIconAndTitle->getStateIconAndTitle($this);
325
    }
326 6
327 5
    #[Override]
328
    public function getTakeoverTicksLeft(?ShipTakeoverInterface $takeover = null): int
329
    {
330 3
        $takeover ??= $this->spacecraft->getTakeoverActive();
331
        if ($takeover === null) {
332
            throw new RuntimeException('should not call when active takeover is null');
333 9
        }
334
335
        $currentTurn = $this->game->getCurrentRound()->getTurn();
336 9
337 9
        return $takeover->getStartTurn() + ShipTakeoverManagerInterface::TURNS_TO_TAKEOVER - $currentTurn;
338 9
    }
339 9
340
    #[Override]
341 9
    public function getCrewStyle(): string
342
    {
343
        $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...
344
        $excessCrew = $ship->getExcessCrewCount();
345 9
346
        if ($excessCrew === 0) {
347
            return "";
348 8
        }
349
350
        return $excessCrew > 0 ? "color: green;" : "color: red;";
351 8
    }
352 8
353 8
    #[Override]
354 8
    public function getHullSystemData(): HullSystemData
355
    {
356
        $hullSystemData = $this->getSpecificShipSystem(
357 18
            SpacecraftSystemTypeEnum::HULL,
358
            HullSystemData::class
359
        );
360 18
361 18
        if ($hullSystemData === null) {
362 18
            throw new SystemNotFoundException('no hull installed?');
363 18
        }
364
365
        return $hullSystemData;
366 4
    }
367
368
    #[Override]
369 4
    public function getShieldSystemData(): ?ShieldSystemData
370 4
    {
371 4
        return $this->getSpecificShipSystem(
372 4
            SpacecraftSystemTypeEnum::SHIELDS,
373
            ShieldSystemData::class
374
        );
375 1
    }
376
377
    #[Override]
378 1
    public function getEpsSystemData(): ?EpsSystemData
379 1
    {
380 1
        return $this->getSpecificShipSystem(
381 1
            SpacecraftSystemTypeEnum::EPS,
382
            EpsSystemData::class
383
        );
384
    }
385
386
    #[Override]
387
    public function getLssSystemData(): ?LssSystemData
388
    {
389
        return $this->getSpecificShipSystem(
390 22
            SpacecraftSystemTypeEnum::LSS,
391
            LssSystemData::class
392 22
        );
393 22
    }
394 22
395 22
    #[Override]
396 22
    public function getWarpDriveSystemData(): ?WarpDriveSystemData
397 22
    {
398 22
        return $this->getSpecificShipSystem(
399
            SpacecraftSystemTypeEnum::WARPDRIVE,
400
            WarpDriveSystemData::class
401
        );
402
    }
403
404
    #[Override]
405
    public function getProjectileLauncherSystemData(): ?ProjectileLauncherSystemData
406
    {
407
        return $this->getSpecificShipSystem(
408
            SpacecraftSystemTypeEnum::TORPEDO,
409
            ProjectileLauncherSystemData::class
410
        );
411
    }
412
413
    /**
414
     * @template T2
415
     * @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...
416
     *
417
     * @return T2|null
418
     */
419
    protected function getSpecificShipSystem(SpacecraftSystemTypeEnum $systemType, string $className)
420
    {
421
        return $this->systemDataDeserializer->getSpecificShipSystem(
422
            $this->spacecraft,
423
            $systemType,
424
            $className,
425
            $this->shipSystemDataCache,
426
            $this->spacecraftWrapperFactory
427
        );
428
    }
429
430
    #[Override]
431
    public function __toString(): string
432
    {
433
        $systems = implode(",\n", $this->spacecraft->getSystems()
434
            ->filter(fn($system): bool => $system->getData() !== null)
435
            ->map(fn($system): string => $system->__toString())
436
            ->toArray());
437
438
        return sprintf(
439
            "spacecraft: {%s,\n  systems: [\n%s\n}\n]",
440
            $this->spacecraft->__toString(),
441
            $systems
442
        );
443
    }
444
}
445