Passed
Pull Request — master (#1976)
by Janko
21:47 queued 12:50
created

Spacecraft   F

Complexity

Total Complexity 234

Size/Duplication

Total Lines 1412
Duplicated Lines 0 %

Test Coverage

Coverage 60%

Importance

Changes 0
Metric Value
eloc 585
dl 0
loc 1412
ccs 297
cts 495
cp 0.6
rs 2
c 0
b 0
f 0
wmc 234

161 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 4 1
A __construct() 0 6 1
A setName() 0 5 1
A getAlertState() 0 4 1
A isSystemHealthy() 0 8 2
A getSystemsId() 0 4 2
A getUserName() 0 4 1
A getFlightDirection() 0 4 1
A getId() 0 8 2
A getUserId() 0 4 1
A getLssMode() 0 4 1
A setLssMode() 0 5 1
A setAlertStateGreen() 0 4 1
A setFlightDirection() 0 5 1
A setAlertState() 0 5 1
A getLayer() 0 4 1
A hasEnoughCrew() 0 23 6
A isMatrixScannerHealthy() 0 4 1
A isOverSystem() 0 9 2
A getSectorString() 0 4 1
A canMan() 0 8 3
A hasCrewmanOfUser() 0 10 3
A setLocation() 0 6 1
A isAlertGreen() 0 4 1
A getCloakState() 0 4 1
A setSensorRange() 0 5 1
A getRumpName() 0 4 1
A getPosX() 0 4 1
A setHoldingWeb() 0 10 2
A isWarpPossible() 0 4 2
A hasSubspaceScanner() 0 4 1
A setIsInEmergency() 0 5 1
A getWarpDriveState() 0 4 1
A getLogbook() 0 4 1
A setTakeoverPassive() 0 6 1
A getTakeoverActive() 0 4 1
A getColorStyle() 0 24 5
A getTachyonState() 0 4 1
A getHitChance() 0 9 2
A getTorpedo() 0 8 2
A getNbs() 0 4 1
A getModules() 0 17 4
A getSensorRange() 0 9 2
A isShuttle() 0 4 1
A isTractorbeamPossible() 0 4 1
A hasShipSystem() 0 4 1
A getShieldRegenerationRate() 0 4 1
A getStoredShuttles() 0 12 3
A getExcessCrewCount() 0 4 1
A canIntercept() 0 6 4
A getShield() 0 4 1
A canMove() 0 5 2
A getRump() 0 4 1
A getCrewCount() 0 4 1
A getLss() 0 4 1
A getState() 0 4 1
A getShieldRegenerationPercentage() 0 3 2
A isShuttleRampHealthy() 0 4 1
A hasStoredBuoy() 0 4 1
A getBeamableStorage() 0 4 1
A setHitChance() 0 5 1
A setTakeoverActive() 0 6 1
A setShieldRegenerationTimer() 0 5 1
A isDisabled() 0 4 1
A getStorageSum() 0 7 1
A getSystemState() 0 8 2
A hasPhaser() 0 4 1
A getRepairRate() 0 5 1
A setBuildplan() 0 5 1
A getTractoredShip() 0 4 1
A isInterceptable() 0 5 1
A getStorage() 0 4 1
A hasTranswarp() 0 4 1
A isWarpAble() 0 4 1
A setTractoredShip() 0 5 1
A setShield() 0 5 1
A __toString() 0 8 2
A getBuildplan() 0 4 1
A isTroopQuartersHealthy() 0 4 1
A isOverColony() 0 4 2
A hasUplink() 0 4 1
A setHuell() 0 5 1
A hasWarpdrive() 0 4 1
A getUser() 0 4 1
A getShieldRegenerationTimer() 0 4 1
A hasFreeShuttleSpace() 0 9 3
A getRumpId() 0 4 1
A getTakeoverPassive() 0 4 1
A getCrewAssignments() 0 4 1
A hasEscapePods() 0 4 2
A getImpulseState() 0 4 1
A isBoardingPossible() 0 4 1
A getTranswarpCooldown() 0 6 2
A hasCloak() 0 4 1
A setTractoredShipId() 0 5 1
A getTorpedoCount() 0 8 2
A setIsDestroyed() 0 5 1
A getStoredShuttleCount() 0 12 3
A isConstruction() 0 4 1
A isDeflectorHealthy() 0 4 1
A setDisabled() 0 5 1
A getHealthySystems() 0 10 3
A setEvadeChance() 0 5 1
A getHull() 0 4 1
A getShieldState() 0 4 1
A hasTorpedo() 0 4 1
A getDatabaseId() 0 4 1
A getLocation() 0 11 3
A getIsInEmergency() 0 4 1
A setMaxHuell() 0 5 1
A getHullColorStyle() 0 4 1
A getRPGModuleState() 0 4 1
A isWarped() 0 4 1
A getMaxStorage() 0 4 1
A getMap() 0 11 3
A isUnderRepair() 0 5 2
A getHoldingWebBackgroundStyle() 0 16 4
A getHealthPercentage() 0 5 1
A setBaseDamage() 0 5 1
A getPhaserState() 0 4 1
A setTorpedoStorage() 0 5 1
A setUser() 0 5 1
A getMapRegion() 0 14 3
A getSystem() 0 4 2
A hasTachyonScanner() 0 4 1
A getSubspaceState() 0 4 1
A isDestroyed() 0 4 1
A setDatabaseId() 0 5 1
A getNeededCrewCount() 0 9 2
A hasNbsLss() 0 4 1
A getPosY() 0 4 1
A hasAstroLaboratory() 0 4 1
A getMaxShield() 0 9 3
A getHref() 0 8 1
A getMaxHull() 0 4 1
A setState() 0 5 1
A isTorpedoStorageHealthy() 0 4 1
A getMaxTorpedos() 0 6 2
A getStoredBuoy() 0 12 3
A getBeamFactor() 0 4 1
A setMaxShield() 0 5 1
A getTorpedoStorage() 0 4 1
A getBaseDamage() 0 9 2
A getEvadeChance() 0 9 2
A getStarsystemMap() 0 8 2
A displayNbsActions() 0 5 2
A setRump() 0 5 1
A getTractorPayload() 0 9 2
A getHoldingWebImageStyle() 0 15 4
A getHoldingWeb() 0 4 1
A getWebState() 0 4 1
A isWebEmitterHealthy() 0 4 1
A hasActiveWeapon() 0 4 2
A hasReactor() 0 6 3
A isStation() 0 4 1
A getTorpedoState() 0 4 1
A hasShuttleRamp() 0 4 1
A getShipSystem() 0 9 2
A hasRPGModule() 0 4 1
A isTractoring() 0 4 1
A getSystems() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Spacecraft often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Spacecraft, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Orm\Entity;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Doctrine\ORM\Mapping\Column;
10
use Doctrine\ORM\Mapping\DiscriminatorColumn;
11
use Doctrine\ORM\Mapping\DiscriminatorMap;
12
use Doctrine\ORM\Mapping\Entity;
13
use Doctrine\ORM\Mapping\GeneratedValue;
14
use Doctrine\ORM\Mapping\Id;
15
use Doctrine\ORM\Mapping\InheritanceType;
16
use Doctrine\ORM\Mapping\JoinColumn;
17
use Doctrine\ORM\Mapping\ManyToOne;
18
use Doctrine\ORM\Mapping\OneToMany;
19
use Doctrine\ORM\Mapping\OneToOne;
20
use Doctrine\ORM\Mapping\OrderBy;
21
use Doctrine\ORM\Mapping\Table;
22
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...
23
use RuntimeException;
24
use Stu\Component\Game\TimeConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Game\TimeConstants 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...
25
use Stu\Component\Map\DirectionEnum;
26
use Stu\Component\Spacecraft\SpacecraftAlertStateEnum;
27
use Stu\Component\Spacecraft\SpacecraftModuleTypeEnum;
28
use Stu\Component\Spacecraft\SpacecraftRumpEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Spacecraft\SpacecraftRumpEnum 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\Component\Spacecraft\SpacecraftStateEnum;
30
use Stu\Component\Spacecraft\SpacecraftLssModeEnum;
31
use Stu\Component\Spacecraft\SpacecraftTypeEnum;
32
use Stu\Component\Spacecraft\System\SpacecraftSystemModeEnum;
33
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
34
use Stu\Component\Spacecraft\System\Type\TorpedoStorageShipSystem;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Spacecraft...orpedoStorageShipSystem 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...
35
use Stu\Component\Spacecraft\System\Type\TractorBeamShipSystem;
36
use Stu\Lib\Transfer\CommodityTransfer;
37
use Stu\Module\Control\GameControllerInterface;
38
use Stu\Module\Logging\LoggerUtilInterface;
39
use Stu\Module\Spacecraft\Lib\Battle\FightLib;
40
use Stu\Orm\Repository\SpacecraftRepository;
41
42
#[Table(name: 'stu_spacecraft')]
43
#[Entity(repositoryClass: SpacecraftRepository::class)]
44
#[InheritanceType('JOINED')]
45
#[DiscriminatorColumn(name: 'type', type: 'string')]
46
#[DiscriminatorMap([
47
    SpacecraftTypeEnum::SHIP->value => Ship::class,
48
    SpacecraftTypeEnum::STATION->value => Station::class
49
])]
50
abstract class Spacecraft implements SpacecraftInterface
51
{
52
    #[Id]
53
    #[Column(type: 'integer')]
54
    #[GeneratedValue(strategy: 'IDENTITY')]
55
    private ?int $id = null;
56
57
    #[Column(type: 'integer')]
58
    private int $user_id = 0;
59
60
    #[Column(type: 'integer')]
61
    private int $rump_id = 0;
0 ignored issues
show
introduced by
The private property $rump_id is not used, and could be removed.
Loading history...
62
63
    #[Column(type: 'integer', nullable: true)]
64
    private ?int $plan_id = null;
0 ignored issues
show
introduced by
The private property $plan_id is not used, and could be removed.
Loading history...
65
66
    #[Column(type: 'smallint', length: 1, enumType: DirectionEnum::class, nullable: true)]
67
    private ?DirectionEnum $direction = null;
68
69
    #[Column(type: 'string')]
70
    private string $name = '';
71
72
    #[Column(type: 'smallint', length: 1, enumType: SpacecraftAlertStateEnum::class)]
73
    private SpacecraftAlertStateEnum $alvl = SpacecraftAlertStateEnum::ALERT_GREEN;
74
75
    #[Column(type: 'smallint', length: 1, enumType: SpacecraftLssModeEnum::class)]
76
    private SpacecraftLssModeEnum $lss_mode = SpacecraftLssModeEnum::LSS_NORMAL;
77
78
    #[Column(type: 'integer', length: 6)]
79
    private int $huelle = 0;
80
81
    #[Column(type: 'integer', length: 6)]
82
    private int $max_huelle = 0;
83
84
    #[Column(type: 'integer', length: 6)]
85
    private int $schilde = 0;
86
87
    #[Column(type: 'integer', length: 6)]
88
    private int $max_schilde = 0;
89
90
    #[Column(type: 'integer', nullable: true)]
91
    private ?int $tractored_ship_id = null;
92
93
    #[Column(type: 'integer', nullable: true)]
94
    private ?int $holding_web_id = null;
95
96
    #[Column(type: 'integer', nullable: true)]
97
    private ?int $database_id = null;
98
99
    private bool $is_destroyed = false;
100
101
    #[Column(type: 'boolean')]
102
    private bool $disabled = false;
103
104
    #[Column(type: 'smallint', length: 3)]
105
    private int $hit_chance = 0;
106
107
    #[Column(type: 'smallint', length: 3)]
108
    private int $evade_chance = 0;
109
110
    #[Column(type: 'smallint', length: 4)]
111
    private int $base_damage = 0;
112
113
    #[Column(type: 'smallint', length: 3)]
114
    private int $sensor_range = 0;
115
116
    #[Column(type: 'integer')]
117
    private int $shield_regeneration_timer = 0;
118
119
    #[Column(type: 'smallint', enumType: SpacecraftStateEnum::class)]
120
    private SpacecraftStateEnum $state = SpacecraftStateEnum::SHIP_STATE_NONE;
121
122
    #[Column(type: 'integer')]
123
    private int $location_id = 0;
0 ignored issues
show
introduced by
The private property $location_id is not used, and could be removed.
Loading history...
124
125
    #[Column(type: 'boolean')]
126
    private bool $in_emergency = false;
127
128
    #[OneToOne(targetEntity: 'Ship')]
129
    #[JoinColumn(name: 'tractored_ship_id', referencedColumnName: 'id')]
130
    private ?ShipInterface $tractoredShip = null;
131
132
    #[ManyToOne(targetEntity: 'TholianWeb')]
133
    #[JoinColumn(name: 'holding_web_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
134
    private ?TholianWebInterface $holdingWeb = null;
135
136
    #[ManyToOne(targetEntity: 'User')]
137
    #[JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
138
    private UserInterface $user;
139
140
    /**
141
     * @var ArrayCollection<int, CrewAssignmentInterface>
142
     */
143
    #[OneToMany(targetEntity: 'CrewAssignment', mappedBy: 'spacecraft', indexBy: 'id')]
144
    #[OrderBy(['id' => 'ASC'])]
145
    private Collection $crew;
146
147
    #[OneToOne(targetEntity: 'TorpedoStorage', mappedBy: 'spacecraft')]
148
    private ?TorpedoStorageInterface $torpedoStorage = null;
149
150
    /**
151
     * @var ArrayCollection<int, SpacecraftSystemInterface>
152
     */
153
    #[OneToMany(targetEntity: 'SpacecraftSystem', mappedBy: 'spacecraft', indexBy: 'system_type')]
154
    #[OrderBy(['system_type' => 'ASC'])]
155
    private Collection $systems;
156
157
    #[ManyToOne(targetEntity: 'SpacecraftRump')]
158
    #[JoinColumn(name: 'rump_id', referencedColumnName: 'id')]
159
    private SpacecraftRumpInterface $rump;
160
161
    #[ManyToOne(targetEntity: 'SpacecraftBuildplan')]
162
    #[JoinColumn(name: 'plan_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
163
    private ?SpacecraftBuildplanInterface $buildplan = null;
164
165
    /**
166
     * @var ArrayCollection<int, StorageInterface>
167
     */
168
    #[OneToMany(targetEntity: 'Storage', mappedBy: 'spacecraft', indexBy: 'commodity_id')]
169
    #[OrderBy(['commodity_id' => 'ASC'])]
170
    private Collection $storage;
171
172
    #[ManyToOne(targetEntity: 'Location')]
173
    #[JoinColumn(name: 'location_id', referencedColumnName: 'id')]
174
    private LocationInterface $location;
175
176
    /**
177
     * @var ArrayCollection<int, ShipLogInterface>
178
     */
179
    #[OneToMany(targetEntity: 'ShipLog', mappedBy: 'spacecraft', fetch: 'EXTRA_LAZY')]
180
    #[OrderBy(['id' => 'DESC'])]
181
    private Collection $logbook;
182
183
    #[OneToOne(targetEntity: 'ShipTakeover', mappedBy: 'source')]
184
    private ?ShipTakeoverInterface $takeoverActive = null;
185
186
    #[OneToOne(targetEntity: 'ShipTakeover', mappedBy: 'target')]
187
    private ?ShipTakeoverInterface $takeoverPassive = null;
188
189 3
    public function __construct()
190
    {
191 3
        $this->crew = new ArrayCollection();
192 3
        $this->systems = new ArrayCollection();
193 3
        $this->storage = new ArrayCollection();
194 3
        $this->logbook = new ArrayCollection();
195
    }
196
197 38
    #[Override]
198
    public function getId(): int
199
    {
200 38
        if ($this->id === null) {
201
            throw new RuntimeException('entity not yet persisted');
202
        }
203
204 38
        return $this->id;
205
    }
206
207 1
    #[Override]
208
    public function getUserId(): int
209
    {
210 1
        return $this->user_id;
211
    }
212
213 6
    #[Override]
214
    public function getUserName(): string
215
    {
216 6
        return $this->getUser()->getName();
217
    }
218
219
    #[Override]
220
    public function getSystemsId(): ?int
221
    {
222
        return $this->getSystem() !== null ? $this->getSystem()->getId() : null;
223
    }
224
225 3
    #[Override]
226
    public function getLayer(): ?LayerInterface
227
    {
228 3
        return $this->getLocation()->getLayer();
229
    }
230
231
    #[Override]
232
    public function getFlightDirection(): ?DirectionEnum
233
    {
234
        return $this->direction;
235
    }
236
237
    #[Override]
238
    public function setFlightDirection(DirectionEnum $direction): SpacecraftInterface
239
    {
240
        $this->direction = $direction;
241
        return $this;
242
    }
243
244 32
    #[Override]
245
    public function getName(): string
246
    {
247 32
        return $this->name;
248
    }
249
250
    #[Override]
251
    public function setName(string $name): SpacecraftInterface
252
    {
253
        $this->name = $name;
254
        return $this;
255
    }
256
257 2
    #[Override]
258
    public function getLssMode(): SpacecraftLssModeEnum
259
    {
260 2
        return $this->lss_mode;
261
    }
262
263
    #[Override]
264
    public function setLssMode(SpacecraftLssModeEnum $lssMode): SpacecraftInterface
265
    {
266
        $this->lss_mode = $lssMode;
267
        return $this;
268
    }
269
270 6
    #[Override]
271
    public function getAlertState(): SpacecraftAlertStateEnum
272
    {
273 6
        return $this->alvl;
274
    }
275
276
    #[Override]
277
    public function setAlertState(SpacecraftAlertStateEnum $state): SpacecraftInterface
278
    {
279
        $this->alvl = $state;
280
        return $this;
281
    }
282
283
    #[Override]
284
    public function setAlertStateGreen(): SpacecraftInterface
285
    {
286
        return $this->setAlertState(SpacecraftAlertStateEnum::ALERT_GREEN);
287
    }
288
289 17
    #[Override]
290
    public function isSystemHealthy(SpacecraftSystemTypeEnum $type): bool
291
    {
292 17
        if (!$this->hasShipSystem($type)) {
293 17
            return false;
294
        }
295
296 4
        return $this->getShipSystem($type)->getStatus() > 0;
297
    }
298
299 31
    #[Override]
300
    public function getSystemState(SpacecraftSystemTypeEnum $type): bool
301
    {
302 31
        if (!$this->hasShipSystem($type)) {
303 29
            return false;
304
        }
305
306 12
        return $this->getShipSystem($type)->getMode()->isActivated();
307
    }
308
309 4
    #[Override]
310
    public function getImpulseState(): bool
311
    {
312 4
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
313
    }
314
315 5
    #[Override]
316
    public function getWarpDriveState(): bool
317
    {
318 5
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE);
319
    }
320
321 1
    #[Override]
322
    public function isWarped(): bool
323
    {
324 1
        return $this->getWarpDriveState();
325
    }
326
327 4
    #[Override]
328
    public function getWebState(): bool
329
    {
330 4
        return $this->getHoldingWeb() !== null;
331
    }
332
333 29
    #[Override]
334
    public function getCloakState(): bool
335
    {
336 29
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_CLOAK);
337
    }
338
339 2
    #[Override]
340
    public function getTachyonState(): bool
341
    {
342 2
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
343
    }
344
345 1
    #[Override]
346
    public function getSubspaceState(): bool
347
    {
348 1
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
349
    }
350
351
    #[Override]
352
    public function getRPGModuleState(): bool
353
    {
354
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_RPG_MODULE);
355
    }
356
357 14
    #[Override]
358
    public function getHull(): int
359
    {
360 14
        return $this->huelle;
361
    }
362
363
    #[Override]
364
    public function setHuell(int $hull): SpacecraftInterface
365
    {
366
        $this->huelle = $hull;
367
        return $this;
368
    }
369
370 14
    #[Override]
371
    public function getMaxHull(): int
372
    {
373 14
        return $this->max_huelle;
374
    }
375
376
    #[Override]
377
    public function setMaxHuell(int $maxHull): SpacecraftInterface
378
    {
379
        $this->max_huelle = $maxHull;
380
        return $this;
381
    }
382
383 9
    #[Override]
384
    public function getShield(): int
385
    {
386 9
        return $this->schilde;
387
    }
388
389
    #[Override]
390
    public function setShield(int $schilde): SpacecraftInterface
391
    {
392
        $this->schilde = $schilde;
393
        return $this;
394
    }
395
396
    /**
397
     * proportional to shield system status
398
     */
399 9
    #[Override]
400
    public function getMaxShield(bool $isTheoretical = false): int
401
    {
402 9
        if ($isTheoretical || !$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS)) {
403 5
            return $this->max_schilde;
404
        }
405
406 7
        return (int) (ceil($this->max_schilde
407 7
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS)->getStatus() / 100));
408
    }
409
410
    #[Override]
411
    public function setMaxShield(int $maxShields): SpacecraftInterface
412
    {
413
        $this->max_schilde = $maxShields;
414
        return $this;
415
    }
416
417
    #[Override]
418
    public function getHealthPercentage(): float
419
    {
420
        return ($this->getHull() + $this->getShield())
421
            / ($this->getMaxHull() + $this->getMaxShield(true)) * 100;
422
    }
423
424 20
    #[Override]
425
    public function getShieldState(): bool
426
    {
427 20
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS);
428
    }
429
430 6
    #[Override]
431
    public function getNbs(): bool
432
    {
433 6
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_NBS);
434
    }
435
436 6
    #[Override]
437
    public function getLss(): bool
438
    {
439 6
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_LSS);
440
    }
441
442 3
    #[Override]
443
    public function getPhaserState(): bool
444
    {
445 3
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_PHASER);
446
    }
447
448 1
    #[Override]
449
    public function isAlertGreen(): bool
450
    {
451 1
        return $this->getAlertState() === SpacecraftAlertStateEnum::ALERT_GREEN;
452
    }
453
454 1
    #[Override]
455
    public function getTorpedoState(): bool
456
    {
457 1
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_TORPEDO);
458
    }
459
460
    #[Override]
461
    public function getTorpedoCount(): int
462
    {
463
        if ($this->getTorpedoStorage() === null) {
464
            return 0;
465
        }
466
467
        return $this->getTorpedoStorage()->getStorage()->getAmount();
468
    }
469
470 7
    #[Override]
471
    public function isStation(): bool
472
    {
473 7
        return $this instanceof StationInterface;
474
    }
475
476 1
    #[Override]
477
    public function isShuttle(): bool
478
    {
479 1
        return $this->getRump()->getCategoryId() === SpacecraftRumpEnum::SHIP_CATEGORY_SHUTTLE;
480
    }
481
482 2
    #[Override]
483
    public function isConstruction(): bool
484
    {
485 2
        return $this->getRump()->getCategoryId() === SpacecraftRumpEnum::SHIP_CATEGORY_CONSTRUCTION;
486
    }
487
488 1
    #[Override]
489
    public function getDatabaseId(): ?int
490
    {
491 1
        return $this->database_id;
492
    }
493
494
    #[Override]
495
    public function setDatabaseId(?int $databaseEntryId): SpacecraftInterface
496
    {
497
        $this->database_id = $databaseEntryId;
498
        return $this;
499
    }
500
501 10
    #[Override]
502
    public function isDestroyed(): bool
503
    {
504 10
        return $this->is_destroyed;
505
    }
506
507
    #[Override]
508
    public function setIsDestroyed(bool $isDestroyed): SpacecraftInterface
509
    {
510
        $this->is_destroyed = $isDestroyed;
511
        return $this;
512
    }
513
514
    #[Override]
515
    public function isDisabled(): bool
516
    {
517
        return $this->disabled;
518
    }
519
520
    #[Override]
521
    public function setDisabled(bool $isDisabled): SpacecraftInterface
522
    {
523
        $this->disabled = $isDisabled;
524
        return $this;
525
    }
526
527
528
529
    /**
530
     * proportional to computer system status
531
     */
532 1
    #[Override]
533
    public function getHitChance(): int
534
    {
535 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_COMPUTER)) {
536
            return $this->hit_chance;
537
        }
538
539 1
        return (int) (ceil($this->hit_chance
540 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_COMPUTER)->getStatus() / 100));
541
    }
542
543
    #[Override]
544
    public function setHitChance(int $hitChance): SpacecraftInterface
545
    {
546
        $this->hit_chance = $hitChance;
547
        return $this;
548
    }
549
550
    /**
551
     * proportional to impulsedrive system status
552
     */
553 1
    #[Override]
554
    public function getEvadeChance(): int
555
    {
556 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE)) {
557
            return $this->evade_chance;
558
        }
559
560 1
        return (int) (ceil($this->evade_chance
561 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE)->getStatus() / 100));
562
    }
563
564
    #[Override]
565
    public function setEvadeChance(int $evadeChance): SpacecraftInterface
566
    {
567
        $this->evade_chance = $evadeChance;
568
        return $this;
569
    }
570
571
    /**
572
     * proportional to energy weapon system status
573
     */
574 1
    #[Override]
575
    public function getBaseDamage(): int
576
    {
577 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_PHASER)) {
578
            return $this->base_damage;
579
        }
580
581 1
        return (int) (ceil($this->base_damage
582 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_PHASER)->getStatus() / 100));
583
    }
584
585
    #[Override]
586
    public function setBaseDamage(int $baseDamage): SpacecraftInterface
587
    {
588
        $this->base_damage = $baseDamage;
589
        return $this;
590
    }
591
592
    /**
593
     * proportional to sensor system status
594
     */
595 2
    #[Override]
596
    public function getSensorRange(): int
597
    {
598 2
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_LSS)) {
599
            return $this->sensor_range;
600
        }
601
602 2
        return (int) (ceil($this->sensor_range
603 2
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_LSS)->getStatus() / 100));
604
    }
605
606
    #[Override]
607
    public function setSensorRange(int $sensorRange): SpacecraftInterface
608
    {
609
        $this->sensor_range = $sensorRange;
610
        return $this;
611
    }
612
613
    /**
614
     * proportional to tractor beam system status
615
     */
616 1
    #[Override]
617
    public function getTractorPayload(): int
618
    {
619 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TRACTOR_BEAM)) {
620
            return 0;
621
        }
622
623 1
        return (int) (ceil($this->getRump()->getTractorPayload()
624 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TRACTOR_BEAM)->getStatus() / 100));
625
    }
626
627
    #[Override]
628
    public function getShieldRegenerationTimer(): int
629
    {
630
        return $this->shield_regeneration_timer;
631
    }
632
633
    #[Override]
634
    public function setShieldRegenerationTimer(int $shieldRegenerationTimer): SpacecraftInterface
635
    {
636
        $this->shield_regeneration_timer = $shieldRegenerationTimer;
637
        return $this;
638
    }
639
640 5
    #[Override]
641
    public function getState(): SpacecraftStateEnum
642
    {
643 5
        return $this->state;
644
    }
645
646
    #[Override]
647
    public function setState(SpacecraftStateEnum $state): SpacecraftInterface
648
    {
649
        $this->state = $state;
650
        return $this;
651
    }
652
653 1
    #[Override]
654
    public function getIsInEmergency(): bool
655
    {
656 1
        return $this->in_emergency;
657
    }
658
659
    #[Override]
660
    public function setIsInEmergency(bool $inEmergency): SpacecraftInterface
661
    {
662
        $this->in_emergency = $inEmergency;
663
        return $this;
664
    }
665
666
    #[Override]
667
    public function isUnderRepair(): bool
668
    {
669
        return $this->getState() === SpacecraftStateEnum::SHIP_STATE_REPAIR_ACTIVE
670
            || $this->getState() === SpacecraftStateEnum::SHIP_STATE_REPAIR_PASSIVE;
671
    }
672
673 13
    #[Override]
674
    public function getCrewAssignments(): Collection
675
    {
676 13
        return $this->crew;
677
    }
678
679 5
    #[Override]
680
    public function getPosX(): int
681
    {
682 5
        return $this->location->getX();
683
    }
684
685 5
    #[Override]
686
    public function getPosY(): int
687
    {
688 5
        return $this->location->getY();
689
    }
690
691 12
    #[Override]
692
    public function getCrewCount(): int
693
    {
694 12
        return $this->getCrewAssignments()->count();
695
    }
696
697 7
    #[Override]
698
    public function getNeededCrewCount(): int
699
    {
700 7
        $buildplan = $this->getBuildplan();
701 7
        if ($buildplan === null) {
702
            return 0;
703
        }
704
705 7
        return $buildplan->getCrew();
706
    }
707
708 6
    #[Override]
709
    public function getExcessCrewCount(): int
710
    {
711 6
        return $this->getCrewCount() - $this->getNeededCrewCount();
712
    }
713
714 3
    #[Override]
715
    public function hasEnoughCrew(?GameControllerInterface $game = null): bool
716
    {
717 3
        $buildplan = $this->getBuildplan();
718
719 3
        if ($buildplan === null) {
720
            if ($game !== null) {
721
                $game->addInformation(_("Keine Crew vorhanden"));
722
            }
723
            return false;
724
        }
725
726 3
        $result = $buildplan->getCrew() <= 0
727 3
            || $this->getCrewCount() >= $buildplan->getCrew();
728
729 3
        if (!$result && $game !== null) {
730
            $game->addInformationf(
731
                _("Es werden %d Crewmitglieder benötigt"),
732
                $buildplan->getCrew()
733
            );
734
        }
735
736 3
        return $result;
737
    }
738
739 40
    #[Override]
740
    public function getUser(): UserInterface
741
    {
742 40
        return $this->user;
743
    }
744
745
    #[Override]
746
    public function setUser(UserInterface $user): SpacecraftInterface
747
    {
748
        $this->user = $user;
749
        return $this;
750
    }
751
752 6
    #[Override]
753
    public function getSystem(): ?StarSystemInterface
754
    {
755 6
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getSystem() : null;
756
    }
757
758 2
    #[Override]
759
    public function getModules(): array
760
    {
761 2
        $modules = [];
762
763 2
        $buildplan = $this->getBuildplan();
764 2
        if ($buildplan === null) {
765
            return $modules;
766
        }
767
768 2
        foreach ($buildplan->getModules() as $obj) {
769 2
            $module = $obj->getModule();
770 2
            $index = $module->getType() === SpacecraftModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
771 2
            $modules[$index] = $module;
772
        }
773
774 2
        return $modules;
775
    }
776
777
    #[Override]
778
    public function isDeflectorHealthy(): bool
779
    {
780
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_DEFLECTOR);
781
    }
782
783 7
    #[Override]
784
    public function isTroopQuartersHealthy(): bool
785
    {
786 7
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_TROOP_QUARTERS);
787
    }
788
789
    #[Override]
790
    public function isMatrixScannerHealthy(): bool
791
    {
792
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_MATRIX_SCANNER);
793
    }
794
795 10
    #[Override]
796
    public function isTorpedoStorageHealthy(): bool
797
    {
798 10
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_TORPEDO_STORAGE);
799
    }
800
801 1
    #[Override]
802
    public function isShuttleRampHealthy(): bool
803
    {
804 1
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
805
    }
806
807 2
    #[Override]
808
    public function isWebEmitterHealthy(): bool
809
    {
810 2
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_THOLIAN_WEB);
811
    }
812
813
    #[Override]
814
    public function isWarpAble(): bool
815
    {
816
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE);
817
    }
818
819 2
    #[Override]
820
    public function isTractoring(): bool
821
    {
822 2
        return $this->getTractoredShip() !== null;
823
    }
824
825
    #[Override]
826
    public function isOverColony(): ?ColonyInterface
827
    {
828
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getColony() : null;
829
    }
830
831 2
    #[Override]
832
    public function isOverSystem(): ?StarSystemInterface
833
    {
834 2
        $location = $this->getLocation();
835 2
        if ($location instanceof StarSystemMapInterface) {
836
            return null;
837
        }
838
839 2
        return $location->getSystem();
840
    }
841
842 1
    #[Override]
843
    public function isWarpPossible(): bool
844
    {
845 1
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE) && $this->getSystem() === null;
846
    }
847
848 1
    #[Override]
849
    public function getTorpedo(): ?TorpedoTypeInterface
850
    {
851 1
        if ($this->getTorpedoStorage() === null) {
852 1
            return null;
853
        }
854
855
        return $this->getTorpedoStorage()->getTorpedo();
856
    }
857
858 1
    #[Override]
859
    public function getTorpedoStorage(): ?TorpedoStorageInterface
860
    {
861 1
        return $this->torpedoStorage;
862
    }
863
864
    #[Override]
865
    public function setTorpedoStorage(?TorpedoStorageInterface $torpedoStorage): SpacecraftInterface
866
    {
867
        $this->torpedoStorage = $torpedoStorage;
868
        return $this;
869
    }
870
871 15
    #[Override]
872
    public function getStorage(): Collection
873
    {
874 15
        return $this->storage;
875
    }
876
877 1
    #[Override]
878
    public function getLogbook(): Collection
879
    {
880 1
        return $this->logbook;
881
    }
882
883 4
    #[Override]
884
    public function getTakeoverActive(): ?ShipTakeoverInterface
885
    {
886 4
        return $this->takeoverActive;
887
    }
888
889
    #[Override]
890
    public function setTakeoverActive(?ShipTakeoverInterface $takeover): SpacecraftInterface
891
    {
892
        $this->takeoverActive = $takeover;
893
894
        return $this;
895
    }
896
897 4
    #[Override]
898
    public function getTakeoverPassive(): ?ShipTakeoverInterface
899
    {
900 4
        return $this->takeoverPassive;
901
    }
902
903
    #[Override]
904
    public function setTakeoverPassive(?ShipTakeoverInterface $takeover): SpacecraftInterface
905
    {
906
        $this->takeoverPassive = $takeover;
907
908
        return $this;
909
    }
910
911 14
    #[Override]
912
    public function getStorageSum(): int
913
    {
914 14
        return array_reduce(
915 14
            $this->getStorage()->getValues(),
916 14
            fn(int $sum, StorageInterface $storage): int => $sum + $storage->getAmount(),
917 14
            0
918 14
        );
919
    }
920
921 13
    #[Override]
922
    public function getMaxStorage(): int
923
    {
924 13
        return $this->getRump()->getStorage();
925
    }
926
927 8
    #[Override]
928
    public function getBeamableStorage(): Collection
929
    {
930 8
        return CommodityTransfer::excludeNonBeamable($this->storage);
931
    }
932
933 8
    #[Override]
934
    public function getMap(): ?MapInterface
935
    {
936 8
        if ($this->location instanceof MapInterface) {
937 6
            return $this->location;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->location returns the type Stu\Orm\Entity\LocationInterface which includes types incompatible with the type-hinted return Stu\Orm\Entity\MapInterface|null.
Loading history...
938
        }
939 2
        if ($this->location instanceof StarSystemMapInterface) {
940 2
            return $this->location->getSystem()->getMap();
0 ignored issues
show
Bug introduced by
The method getSystem() does not exist on Stu\Orm\Entity\LocationInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Stu\Orm\Entity\Location. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

940
            return $this->location->/** @scrutinizer ignore-call */ getSystem()->getMap();
Loading history...
941
        }
942
943
        return null;
944
    }
945
946 2
    #[Override]
947
    public function getMapRegion(): ?MapRegionInterface
948
    {
949 2
        $systemMap = $this->getStarsystemMap();
950 2
        if ($systemMap !== null) {
951
            return null;
952
        }
953
954 2
        $map = $this->getMap();
955 2
        if ($map === null) {
956
            return null;
957
        }
958
959 2
        return $map->getMapRegion();
960
    }
961
962 3
    #[Override]
963
    public function setLocation(LocationInterface $location): SpacecraftInterface
964
    {
965 3
        $this->location = $location;
966
967 3
        return $this;
968
    }
969
970 9
    #[Override]
971
    public function getStarsystemMap(): ?StarSystemMapInterface
972
    {
973 9
        if ($this->location instanceof StarSystemMapInterface) {
974 5
            return $this->location;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->location returns the type Stu\Orm\Entity\LocationInterface which includes types incompatible with the type-hinted return Stu\Orm\Entity\StarSystemMapInterface|null.
Loading history...
975
        }
976
977 6
        return null;
978
    }
979
980 28
    #[Override]
981
    public function getLocation(): MapInterface|StarSystemMapInterface
982
    {
983
        if (
984 28
            $this->location instanceof MapInterface
985 28
            || $this->location instanceof StarSystemMapInterface
986
        ) {
987 28
            return $this->location;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->location returns the type Stu\Orm\Entity\LocationInterface which includes types incompatible with the type-hinted return Stu\Orm\Entity\MapInterf...\StarSystemMapInterface.
Loading history...
988
        }
989
990
        throw new RuntimeException('unknown type');
991
    }
992
993 11
    #[Override]
994
    public function getBeamFactor(): int
995
    {
996 11
        return $this->getRump()->getBeamFactor();
997
    }
998
999 4
    #[Override]
1000
    public function getSectorString(): string
1001
    {
1002 4
        return $this->getLocation()->getSectorString();
1003
    }
1004
1005 13
    #[Override]
1006
    public function getBuildplan(): ?SpacecraftBuildplanInterface
1007
    {
1008 13
        return $this->buildplan;
1009
    }
1010
1011
    #[Override]
1012
    public function setBuildplan(?SpacecraftBuildplanInterface $spacecraftBuildplan): SpacecraftInterface
1013
    {
1014
        $this->buildplan = $spacecraftBuildplan;
1015
        return $this;
1016
    }
1017
1018 34
    #[Override]
1019
    public function getSystems(): Collection
1020
    {
1021 34
        return $this->systems;
1022
    }
1023
1024 33
    #[Override]
1025
    public function hasShipSystem(SpacecraftSystemTypeEnum $type): bool
1026
    {
1027 33
        return $this->getSystems()->containsKey($type->value);
1028
    }
1029
1030 14
    #[Override]
1031
    public function getShipSystem(SpacecraftSystemTypeEnum $type): SpacecraftSystemInterface
1032
    {
1033 14
        $system = $this->getSystems()->get($type->value);
1034 14
        if ($system === null) {
1035
            throw new RuntimeException(sprintf('system type %d does not exist on ship', $type->value));
1036
        }
1037
1038 14
        return $system;
1039
    }
1040
1041
    #[Override]
1042
    public function getHealthySystems(): array
1043
    {
1044
        $healthySystems = [];
1045
        foreach ($this->getSystems() as $system) {
1046
            if ($system->getStatus() > 0) {
1047
                $healthySystems[] = $system;
1048
            }
1049
        }
1050
        return $healthySystems;
1051
    }
1052
1053 1
    #[Override]
1054
    public function displayNbsActions(): bool
1055
    {
1056 1
        return !$this->getCloakState()
1057 1
            && !$this->isWarped();
1058
    }
1059
1060
    #[Override]
1061
    public function isTractorbeamPossible(): bool
1062
    {
1063
        return TractorBeamShipSystem::isTractorBeamPossible($this);
1064
    }
1065
1066
    #[Override]
1067
    public function isBoardingPossible(): bool
1068
    {
1069
        return FightLib::isBoardingPossible($this);
1070
    }
1071
1072
    #[Override]
1073
    public function isInterceptable(): bool
1074
    {
1075
        //TODO can tractored ships be intercepted?!
1076
        return $this->getWarpDriveState();
1077
    }
1078
1079 2
    #[Override]
1080
    public function getTractoredShip(): ?ShipInterface
1081
    {
1082 2
        return $this->tractoredShip;
1083
    }
1084
1085
    #[Override]
1086
    public function setTractoredShip(?ShipInterface $ship): SpacecraftInterface
1087
    {
1088
        $this->tractoredShip = $ship;
1089
        return $this;
1090
    }
1091
1092
    #[Override]
1093
    public function setTractoredShipId(?int $shipId): SpacecraftInterface
1094
    {
1095
        $this->tractored_ship_id = $shipId;
1096
        return $this;
1097
    }
1098
1099 7
    #[Override]
1100
    public function getHoldingWeb(): ?TholianWebInterface
1101
    {
1102 7
        return $this->holdingWeb;
1103
    }
1104
1105
    #[Override]
1106
    public function setHoldingWeb(?TholianWebInterface $web): SpacecraftInterface
1107
    {
1108
        $this->holdingWeb = $web;
1109
1110
        if ($web === null) {
1111
            $this->holding_web_id = null;
1112
        }
1113
1114
        return $this;
1115
    }
1116
1117 3
    #[Override]
1118
    public function getHoldingWebBackgroundStyle(): string
1119
    {
1120 3
        if ($this->getHoldingWeb() === null) {
1121 3
            return '';
1122
        }
1123
1124
        if ($this->getHoldingWeb()->isFinished()) {
1125
            $icon =  'web.png';
1126
        } else {
1127
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1128
1129
            $icon = $closeTofinish ? 'web_u.png' : 'web_u2.png';
1130
        }
1131
1132
        return sprintf('src="assets/buttons/%s"; class="indexedGraphics" style="z-index: 5;"', $icon);
1133
    }
1134
1135
    public function getHoldingWebImageStyle(): string
1136
    {
1137
        if ($this->getHoldingWeb() === null) {
1138
            return '';
1139
        }
1140
1141
        if ($this->getHoldingWeb()->isFinished()) {
1142
            $icon =  'webfill.png';
1143
        } else {
1144
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1145
1146
            $icon = $closeTofinish ? 'web_ufill.png' : 'web_ufill2.png';
1147
        }
1148
1149
        return $icon;
1150
    }
1151
1152 7
    private function getShieldRegenerationPercentage(): int
1153
    {
1154 7
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS) ? 10 : 0;
1155
    }
1156
1157 7
    #[Override]
1158
    public function getShieldRegenerationRate(): int
1159
    {
1160 7
        return (int) ceil(($this->getMaxShield() / 100) * $this->getShieldRegenerationPercentage());
1161
    }
1162
1163 1
    #[Override]
1164
    public function canIntercept(): bool
1165
    {
1166 1
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE)
1167 1
            && !$this->isTractoring()
1168 1
            && (!$this instanceof ShipInterface || !$this->isTractored());
1169
    }
1170
1171 3
    #[Override]
1172
    public function canMove(): bool
1173
    {
1174 3
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE)
1175 3
            || $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
1176
    }
1177
1178 1
    #[Override]
1179
    public function hasActiveWeapon(): bool
1180
    {
1181 1
        return $this->getPhaserState() || $this->getTorpedoState();
1182
    }
1183
1184
    #[Override]
1185
    public function hasEscapePods(): bool
1186
    {
1187
        return $this->getRump()->isEscapePods() && $this->getCrewCount() > 0;
1188
    }
1189
1190 1
    #[Override]
1191
    public function getRepairRate(): int
1192
    {
1193
        // @todo
1194 1
        return 100;
1195
    }
1196
1197 34
    #[Override]
1198
    public function getRump(): SpacecraftRumpInterface
1199
    {
1200 34
        return $this->rump;
1201
    }
1202
1203 17
    #[Override]
1204
    public function getRumpId(): int
1205
    {
1206 17
        return $this->getRump()->getId();
1207
    }
1208
1209 17
    #[Override]
1210
    public function getRumpName(): string
1211
    {
1212 17
        return $this->getRump()->getName();
1213
    }
1214
1215
    #[Override]
1216
    public function setRump(SpacecraftRumpInterface $shipRump): SpacecraftInterface
1217
    {
1218
        $this->rump = $shipRump;
1219
        return $this;
1220
    }
1221
1222 6
    #[Override]
1223
    public function hasPhaser(): bool
1224
    {
1225 6
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_PHASER);
1226
    }
1227
1228 6
    #[Override]
1229
    public function hasTorpedo(): bool
1230
    {
1231 6
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TORPEDO);
1232
    }
1233
1234 6
    #[Override]
1235
    public function hasCloak(): bool
1236
    {
1237 6
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_CLOAK);
1238
    }
1239
1240 2
    #[Override]
1241
    public function hasTachyonScanner(): bool
1242
    {
1243 2
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
1244
    }
1245
1246 4
    #[Override]
1247
    public function hasShuttleRamp(): bool
1248
    {
1249 4
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
1250
    }
1251
1252 2
    #[Override]
1253
    public function hasSubspaceScanner(): bool
1254
    {
1255 2
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
1256
    }
1257
1258 2
    #[Override]
1259
    public function hasAstroLaboratory(): bool
1260
    {
1261 2
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_ASTRO_LABORATORY);
1262
    }
1263
1264 6
    #[Override]
1265
    public function hasWarpdrive(): bool
1266
    {
1267 6
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE);
1268
    }
1269
1270 1
    #[Override]
1271
    public function hasReactor(): bool
1272
    {
1273 1
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_WARPCORE) ||
1274 1
            $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_FUSION_REACTOR) ||
1275 1
            $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SINGULARITY_REACTOR);
1276
    }
1277
1278 2
    #[Override]
1279
    public function hasRPGModule(): bool
1280
    {
1281 2
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_RPG_MODULE);
1282
    }
1283
1284 2
    #[Override]
1285
    public function hasNbsLss(): bool
1286
    {
1287 2
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_LSS);
1288
    }
1289
1290 8
    #[Override]
1291
    public function hasUplink(): bool
1292
    {
1293 8
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_UPLINK);
1294
    }
1295
1296 2
    #[Override]
1297
    public function hasTranswarp(): bool
1298
    {
1299 2
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TRANSWARP_COIL);
1300
    }
1301
1302
    #[Override]
1303
    public function getTranswarpCooldown(): ?int
1304
    {
1305
        $cooldown = $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TRANSWARP_COIL)->getCooldown();
1306
1307
        return $cooldown > time() ? $cooldown : null;
1308
    }
1309
1310 3
    #[Override]
1311
    public function getMaxTorpedos(): int
1312
    {
1313 3
        return $this->getRump()->getBaseTorpedoStorage()
1314 3
            + ($this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_TORPEDO_STORAGE)
1315 3
                ? TorpedoStorageShipSystem::TORPEDO_CAPACITY : 0);
1316
    }
1317
1318
    #[Override]
1319
    public function hasFreeShuttleSpace(?LoggerUtilInterface $loggerUtil = null): bool
1320
    {
1321
        if ($loggerUtil !== null) {
1322
            $loggerUtil->log(sprintf('rumpShuttleSlots: %d', $this->getRump()->getShuttleSlots()));
1323
            $loggerUtil->log(sprintf('storedShuttleCount: %d', $this->getStoredShuttleCount()));
1324
        }
1325
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SHUTTLE_RAMP)
1326
            && $this->getRump()->getShuttleSlots() - $this->getStoredShuttleCount() > 0;
1327
    }
1328
1329
    #[Override]
1330
    public function getStoredShuttles(): array
1331
    {
1332
        $shuttles = [];
1333
1334
        foreach ($this->getStorage() as $stor) {
1335
            if ($stor->getCommodity()->isShuttle()) {
1336
                $shuttles[] = $stor->getCommodity();
1337
            }
1338
        }
1339
1340
        return $shuttles;
1341
    }
1342
1343
    #[Override]
1344
    public function getStoredShuttleCount(): int
1345
    {
1346
        $count = 0;
1347
1348
        foreach ($this->getStorage() as $stor) {
1349
            if ($stor->getCommodity()->isShuttle()) {
1350
                $count += $stor->getAmount();
1351
            }
1352
        }
1353
1354
        return $count;
1355
    }
1356
1357
    /**
1358
     * @return CommodityInterface[]
1359
     */
1360 2
    #[Override]
1361
    public function getStoredBuoy(): array
1362
    {
1363 2
        $buoy = [];
1364
1365 2
        foreach ($this->getStorage() as $stor) {
1366 1
            if ($stor->getCommodity()->isBouy()) {
1367
                $buoy[] = $stor->getCommodity();
1368
            }
1369
        }
1370
1371 2
        return $buoy;
1372
    }
1373
1374
1375 2
    #[Override]
1376
    public function hasStoredBuoy(): bool
1377
    {
1378 2
        return $this->getStoredBuoy() !== [];
1379
    }
1380
1381 2
    #[Override]
1382
    public function canMan(): bool
1383
    {
1384 2
        $buildplan = $this->getBuildplan();
1385
1386 2
        return $buildplan !== null
1387 2
            && $buildplan->getCrew() > 0
1388 2
            && $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_LIFE_SUPPORT);
1389
    }
1390
1391
    #[Override]
1392
    public function hasCrewmanOfUser(int $userId): bool
1393
    {
1394
        foreach ($this->getCrewAssignments() as $shipCrew) {
1395
            if ($shipCrew->getCrew()->getUser()->getId() === $userId) {
1396
                return true;
1397
            }
1398
        }
1399
1400
        return false;
1401
    }
1402
1403 4
    #[Override]
1404
    public function getHref(): string
1405
    {
1406 4
        return sprintf(
1407 4
            '%s?%s=1&id=%d',
1408 4
            $this->getType()->getModuleView()->getPhpPage(),
1409 4
            $this->getType()->getViewIdentifier(),
1410 4
            $this->getId()
1411 4
        );
1412
    }
1413
1414
    #[Override]
1415
    public function __toString(): string
1416
    {
1417
        if ($this->id !== null) {
1418
            return sprintf('id: %d, name: %s', $this->getId(), $this->getName());
1419
        }
1420
1421
        return $this->getName();
1422
    }
1423
1424 4
    #[Override]
1425
    public function getHullColorStyle(): string
1426
    {
1427 4
        return $this->getColorStyle($this->getHull(), $this->getMaxHull());
1428
    }
1429
1430 4
    private function getColorStyle(int $actual, int $max): string
1431
    {
1432
        // full
1433 4
        if ($actual === $max) {
1434 3
            return '';
1435
        }
1436
1437
        // less than 100% - green
1438 1
        if ($actual / $max > 0.75) {
1439 1
            return 'color: #19c100;';
1440
        }
1441
1442
        // less than 75% - yellow
1443
        if ($actual / $max > 0.50) {
1444
            return 'color: #f4e932;';
1445
        }
1446
1447
        // less than 50% - orange
1448
        if ($actual / $max > 0.25) {
1449
            return 'color: #f48b28;';
1450
        }
1451
1452
        // less than 25% - red
1453
        return 'color: #ff3c3c;';
1454
    }
1455
}
1456