SpacecraftWrapper::__toString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 12
ccs 9
cts 9
cp 1
crap 1
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Spacecraft\Lib;
6
7
use BadMethodCallException;
8
use Doctrine\Common\Collections\ArrayCollection;
9
use Doctrine\Common\Collections\Collection;
10
use Stu\Component\Spacecraft\Repair\RepairUtilInterface;
11
use Stu\Component\Spacecraft\SpacecraftAlertStateEnum;
12
use Stu\Component\Spacecraft\System\Data\AbstractSystemData;
13
use Stu\Component\Spacecraft\System\SpacecraftSystemManagerInterface;
14
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
15
use Stu\Component\Spacecraft\System\SystemDataDeserializerInterface;
16
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
17
use Stu\Module\Commodity\CommodityTypeConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Module\Commodity\CommodityTypeConstants 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...
18
use Stu\Module\Control\GameControllerInterface;
19
use Stu\Module\Spacecraft\Lib\Interaction\ShipTakeoverManagerInterface;
20
use Stu\Module\Spacecraft\Lib\ReactorWrapperInterface;
21
use Stu\Module\Spacecraft\Lib\ShipRepairCost;
22
use Stu\Module\Spacecraft\Lib\SpacecraftStateChangerInterface;
23
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
24
use Stu\Module\Ship\Lib\ShipWrapperInterface;
25
use Stu\Module\Spacecraft\Lib\Reactor\ReactorWrapperFactoryInterface;
26
use Stu\Module\Spacecraft\Lib\Ui\StateIconAndTitle;
27
use Stu\Orm\Entity\SpacecraftSystem;
28
use Stu\Orm\Entity\ShipTakeover;
29
use Stu\Orm\Entity\Spacecraft;
30
use Stu\Orm\Repository\TorpedoTypeRepositoryInterface;
31
32
//TODO increase coverage
33
/**
34
 * @template T of Spacecraft
35
 */
36
abstract class SpacecraftWrapper implements SpacecraftWrapperInterface
37
{
38
    use SpacecraftWrapperSystemDataTrait;
39
40
    /** @var Collection<int, AbstractSystemData> */
41
    private Collection $shipSystemDataCache;
42
43
    private ?ReactorWrapperInterface $reactorWrapper = null;
44
45
    private ?int $epsUsage = null;
46
47
    /**
48
     * @param T $spacecraft
49
     */
50 183
    public function __construct(
51
        protected readonly Spacecraft $spacecraft,
52
        private readonly SpacecraftSystemManagerInterface $spacecraftSystemManager,
53
        private readonly SystemDataDeserializerInterface $systemDataDeserializer,
54
        private readonly TorpedoTypeRepositoryInterface $torpedoTypeRepository,
55
        protected readonly GameControllerInterface $game,
56
        protected readonly SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
57
        private readonly ReactorWrapperFactoryInterface $reactorWrapperFactory,
58
        private readonly SpacecraftStateChangerInterface $spacecraftStateChanger,
59
        private readonly RepairUtilInterface $repairUtil,
60
        private readonly StateIconAndTitle $stateIconAndTitle,
61
        protected readonly ColonyLibFactoryInterface $colonyLibFactory
62
    ) {
63 183
        $this->shipSystemDataCache = new ArrayCollection();
64
    }
65
66
    #[\Override]
67
    public function get(): Spacecraft
68
    {
69
        return $this->spacecraft;
70
    }
71
72 2
    #[\Override]
73
    public function getSpacecraftWrapperFactory(): SpacecraftWrapperFactoryInterface
74
    {
75 2
        return $this->spacecraftWrapperFactory;
76
    }
77
78 2
    #[\Override]
79
    public function getSpacecraftSystemManager(): SpacecraftSystemManagerInterface
80
    {
81 2
        return $this->spacecraftSystemManager;
82
    }
83
84 8
    #[\Override]
85
    public function getEpsUsage(): int
86
    {
87 8
        if ($this->epsUsage === null) {
88 8
            $this->epsUsage = $this->reloadEpsUsage();
89
        }
90 8
        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...
91
    }
92
93
    #[\Override]
94
    public function lowerEpsUsage(int $value): void
95
    {
96
        $this->epsUsage -= $value;
97
    }
98
99 15
    private function reloadEpsUsage(): int
100
    {
101 15
        $result = 0;
102
103 15
        foreach ($this->spacecraftSystemManager->getActiveSystems($this->spacecraft) as $shipSystem) {
104 15
            $result += $this->spacecraftSystemManager->getEnergyConsumption($shipSystem->getSystemType());
105
        }
106
107 15
        return $this->get()->hasComputer()
108 15
            ? $result + $this->getComputerSystemDataMandatory()->getAlertState()->getEpsUsage()
109 15
            : $result;
110
    }
111
112 4
    public function getReactorUsage(): int
113
    {
114 4
        $reactor = $this->reactorWrapper;
115 4
        if ($reactor === null) {
116
            throw new BadMethodCallException('this should not happen');
117
        }
118
119 4
        return $this->getEpsUsage() + $reactor->getUsage();
120
    }
121
122 18
    #[\Override]
123
    public function getReactorWrapper(): ?ReactorWrapperInterface
124
    {
125 18
        if ($this->reactorWrapper === null) {
126 18
            $this->reactorWrapper = $this->reactorWrapperFactory->createReactorWrapper($this);
127
        }
128
129 18
        return $this->reactorWrapper;
130
    }
131
132 21
    #[\Override]
133
    public function getAlertState(): SpacecraftAlertStateEnum
134
    {
135 21
        return $this->getComputerSystemDataMandatory()->getAlertState();
136
    }
137
138 8
    #[\Override]
139
    public function setAlertState(SpacecraftAlertStateEnum $alertState): ?string
140
    {
141 8
        $msg = $this->spacecraftStateChanger->changeAlertState($this, $alertState);
142 8
        $this->epsUsage = $this->reloadEpsUsage();
143
144 8
        return $msg;
145
    }
146
147 8
    #[\Override]
148
    public function isUnalerted(): bool
149
    {
150 8
        return !$this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::COMPUTER)
151 8
            || $this->getComputerSystemDataMandatory()->isAlertGreen();
152
    }
153
154 3
    #[\Override]
155
    public function getShieldRegenerationRate(): int
156
    {
157 3
        $regenerationPercentage = $this->get()->isSystemHealthy(SpacecraftSystemTypeEnum::SHIELDS) ? 10 : 0;
158
159 3
        $shield = $this->get()->getCondition()->getShield();
160 3
        $maxshield = $this->get()->getMaxShield();
161
162 3
        $result = (int) ceil(($maxshield / 100) * $regenerationPercentage);
163
164 3
        if ($result > $maxshield - $shield) {
165 1
            $result = $maxshield - $shield;
166
        }
167
168 3
        return $result;
169
    }
170
171
    /**
172
     * highest damage first, then prio
173
     *
174
     * @return SpacecraftSystem[]
175
     */
176 1
    #[\Override]
177
    public function getDamagedSystems(): array
178
    {
179 1
        $damagedSystems = [];
180 1
        $prioArray = [];
181 1
        foreach ($this->spacecraft->getSystems() as $system) {
182 1
            if ($system->getStatus() < 100) {
183
                $damagedSystems[] = $system;
184
                $prioArray[$system->getSystemType()->value] = $system->getSystemType()->getPriority();
185
            }
186
        }
187
188
        // sort by damage and priority
189 1
        usort(
190 1
            $damagedSystems,
191 1
            function (SpacecraftSystem $a, SpacecraftSystem $b) use ($prioArray): int {
192
                if ($a->getStatus() === $b->getStatus()) {
193
                    return $prioArray[$b->getSystemType()->value] <=> $prioArray[$a->getSystemType()->value];
194
                }
195
                return ($a->getStatus() < $b->getStatus()) ? -1 : 1;
196 1
            }
197 1
        );
198
199 1
        return $damagedSystems;
200
    }
201
202 10
    #[\Override]
203
    public function isSelectable(): bool
204
    {
205 10
        return $this->game->getUser()->getId() === $this->spacecraft->getUser()->getId()
206 10
            && $this->spacecraft->getType()->getModuleView() !== null;
207
    }
208
209 3
    #[\Override]
210
    public function canBeRepaired(): bool
211
    {
212 3
        if (!$this->isUnalerted()) {
213 3
            return false;
214
        }
215
216
        if ($this->spacecraft->isShielded()) {
217
            return false;
218
        }
219
220
        if ($this->spacecraft->isCloaked()) {
221
            return false;
222
        }
223
224
        if ($this->getDamagedSystems() !== []) {
225
            return true;
226
        }
227
228
        return $this->spacecraft->getCondition()->getHull() < $this->spacecraft->getMaxHull();
229
    }
230
231 7
    #[\Override]
232
    public function canFire(): bool
233
    {
234 7
        $ship = $this->spacecraft;
235 7
        if (!$ship->getNbs()) {
236 4
            return false;
237
        }
238 4
        if (!$ship->hasActiveWeapon()) {
239 1
            return false;
240
        }
241
242 3
        $epsSystem = $this->getEpsSystemData();
243 3
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
244
    }
245
246 2
    #[\Override]
247
    public function canMan(): bool
248
    {
249 2
        $buildplan = $this->spacecraft->getBuildplan();
250
251 2
        return $buildplan !== null
252 2
            && $buildplan->getCrew() > 0
253 2
            && $this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::LIFE_SUPPORT);
254
    }
255
256
    #[\Override]
257
    public function getRepairDuration(): int
258
    {
259
        return $this->repairUtil->getRepairDuration($this);
260
    }
261
262
    #[\Override]
263
    public function getRepairDurationPreview(): int
264
    {
265
        return $this->repairUtil->getRepairDurationPreview($this);
266
    }
267
268
    #[\Override]
269
    public function getRepairCosts(): array
270
    {
271
        $neededParts = $this->repairUtil->determineSpareParts($this, false);
272
273
        $neededSpareParts = $neededParts[CommodityTypeConstants::COMMODITY_SPARE_PART];
274
        $neededSystemComponents = $neededParts[CommodityTypeConstants::COMMODITY_SYSTEM_COMPONENT];
275
276
        return [
277
            new ShipRepairCost($neededSpareParts, CommodityTypeConstants::COMMODITY_SPARE_PART, CommodityTypeConstants::getDescription(CommodityTypeConstants::COMMODITY_SPARE_PART)),
278
            new ShipRepairCost($neededSystemComponents, CommodityTypeConstants::COMMODITY_SYSTEM_COMPONENT, CommodityTypeConstants::getDescription(CommodityTypeConstants::COMMODITY_SYSTEM_COMPONENT))
279
        ];
280
    }
281
282
    #[\Override]
283
    public function getPossibleTorpedoTypes(): array
284
    {
285
        if ($this->spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TORPEDO_STORAGE)) {
286
            return $this->torpedoTypeRepository->getAll();
287
        }
288
289
        return $this->torpedoTypeRepository->getByLevel($this->spacecraft->getRump()->getTorpedoLevel());
290
    }
291
292 6
    #[\Override]
293
    public function getTractoredShipWrapper(): ?ShipWrapperInterface
294
    {
295 6
        $tractoredShip = $this->spacecraft->getTractoredShip();
296 6
        if ($tractoredShip === null) {
297 6
            return null;
298
        }
299
300
        return $this->spacecraftWrapperFactory->wrapShip($tractoredShip);
301
    }
302
303 4
    #[\Override]
304
    public function getStateIconAndTitle(): ?array
305
    {
306 4
        return $this->stateIconAndTitle->getStateIconAndTitle($this);
307
    }
308
309
    #[\Override]
310
    public function getTakeoverTicksLeft(?ShipTakeover $takeover = null): int
311
    {
312
        $takeover ??= $this->spacecraft->getTakeoverActive();
313
        if ($takeover === null) {
314
            throw new BadMethodCallException('should not call when active takeover is null');
315
        }
316
317
        $currentTurn = $this->game->getCurrentRound()->getTurn();
318
319
        return $takeover->getStartTurn() + ShipTakeoverManagerInterface::TURNS_TO_TAKEOVER - $currentTurn;
320
    }
321
322 7
    #[\Override]
323
    public function getCrewStyle(): string
324
    {
325 7
        $ship = $this->spacecraft;
326 7
        $excessCrew = $ship->getExcessCrewCount();
327
328 7
        if ($excessCrew === 0) {
329 6
            return "";
330
        }
331
332 3
        return $excessCrew > 0 ? "color: green;" : "color: red;";
333
    }
334
335
    /**
336
     * @template T2
337
     * @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...
338
     *
339
     * @return T2|null
340
     */
341 74
    public function getSpecificShipSystem(SpacecraftSystemTypeEnum $systemType, string $className)
342
    {
343 74
        return $this->systemDataDeserializer->getSpecificShipSystem(
344 74
            $this->spacecraft,
345 74
            $systemType,
346 74
            $className,
347 74
            $this->shipSystemDataCache,
348 74
            $this->spacecraftWrapperFactory
349 74
        );
350
    }
351
352 1
    #[\Override]
353
    public function __toString(): string
354
    {
355 1
        $systems = implode(",\n", $this->spacecraft->getSystems()
356 1
            ->filter(fn($system): bool => $system->getData() !== null)
357 1
            ->map(fn($system): string => $system->__toString())
358 1
            ->toArray());
359
360 1
        return sprintf(
361 1
            "spacecraft: {%s,\n  systems: [\n%s\n}\n]",
362 1
            $this->spacecraft->__toString(),
363 1
            $systems
364 1
        );
365
    }
366
}
367