Passed
Pull Request — master (#1969)
by Janko
22:34 queued 10:03
created

Spacecraft   F

Complexity

Total Complexity 235

Size/Duplication

Total Lines 1413
Duplicated Lines 0 %

Test Coverage

Coverage 60.08%

Importance

Changes 0
Metric Value
eloc 586
dl 0
loc 1413
ccs 298
cts 496
cp 0.6008
rs 2
c 0
b 0
f 0
wmc 235

161 Methods

Rating   Name   Duplication   Size   Complexity  
A hasEnoughCrew() 0 23 6
A getName() 0 4 1
A __construct() 0 6 1
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 setName() 0 5 1
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 getAlertState() 0 4 1
A setIsInEmergency() 0 5 1
A getWarpDriveState() 0 4 1
A isSystemHealthy() 0 8 2
A getLogbook() 0 4 1
A setTakeoverPassive() 0 6 1
A getTakeoverActive() 0 4 1
A getTachyonState() 0 4 1
A getHitChance() 0 9 2
A getSystemsId() 0 4 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 getUserName() 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 9 3
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 getFlightDirection() 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 getId() 0 8 2
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 getUserId() 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 getLssMode() 0 4 1
A isDeflectorHealthy() 0 4 1
A setLssMode() 0 5 1
A setDisabled() 0 5 1
A getHealthySystems() 0 10 3
A setEvadeChance() 0 5 1
A setAlertStateGreen() 0 4 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 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 setFlightDirection() 0 5 1
A getMaxHull() 0 4 1
A setAlertState() 0 5 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 getLayer() 0 4 1
A isTractoring() 0 4 1
A getSystems() 0 4 1
A getHref() 0 8 1
A getColorStyle() 0 24 5
A isWarped() 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;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Spacecraft...pacecraftSystemModeEnum 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...
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() === SpacecraftSystemModeEnum::MODE_ON
307 12
            || $this->getShipSystem($type)->getMode() === SpacecraftSystemModeEnum::MODE_ALWAYS_ON;
308
    }
309
310 4
    #[Override]
311
    public function getImpulseState(): bool
312
    {
313 4
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
314
    }
315
316 5
    #[Override]
317
    public function getWarpDriveState(): bool
318
    {
319 5
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE);
320
    }
321
322 1
    #[Override]
323
    public function isWarped(): bool
324
    {
325 1
        return $this->getWarpDriveState();
326
    }
327
328 4
    #[Override]
329
    public function getWebState(): bool
330
    {
331 4
        return $this->getHoldingWeb() !== null;
332
    }
333
334 29
    #[Override]
335
    public function getCloakState(): bool
336
    {
337 29
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_CLOAK);
338
    }
339
340 2
    #[Override]
341
    public function getTachyonState(): bool
342
    {
343 2
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
344
    }
345
346 1
    #[Override]
347
    public function getSubspaceState(): bool
348
    {
349 1
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
350
    }
351
352
    #[Override]
353
    public function getRPGModuleState(): bool
354
    {
355
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_RPG_MODULE);
356
    }
357
358 14
    #[Override]
359
    public function getHull(): int
360
    {
361 14
        return $this->huelle;
362
    }
363
364
    #[Override]
365
    public function setHuell(int $hull): SpacecraftInterface
366
    {
367
        $this->huelle = $hull;
368
        return $this;
369
    }
370
371 14
    #[Override]
372
    public function getMaxHull(): int
373
    {
374 14
        return $this->max_huelle;
375
    }
376
377
    #[Override]
378
    public function setMaxHuell(int $maxHull): SpacecraftInterface
379
    {
380
        $this->max_huelle = $maxHull;
381
        return $this;
382
    }
383
384 9
    #[Override]
385
    public function getShield(): int
386
    {
387 9
        return $this->schilde;
388
    }
389
390
    #[Override]
391
    public function setShield(int $schilde): SpacecraftInterface
392
    {
393
        $this->schilde = $schilde;
394
        return $this;
395
    }
396
397
    /**
398
     * proportional to shield system status
399
     */
400 9
    #[Override]
401
    public function getMaxShield(bool $isTheoretical = false): int
402
    {
403 9
        if ($isTheoretical || !$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS)) {
404 5
            return $this->max_schilde;
405
        }
406
407 7
        return (int) (ceil($this->max_schilde
408 7
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS)->getStatus() / 100));
409
    }
410
411
    #[Override]
412
    public function setMaxShield(int $maxShields): SpacecraftInterface
413
    {
414
        $this->max_schilde = $maxShields;
415
        return $this;
416
    }
417
418
    #[Override]
419
    public function getHealthPercentage(): float
420
    {
421
        return ($this->getHull() + $this->getShield())
422
            / ($this->getMaxHull() + $this->getMaxShield(true)) * 100;
423
    }
424
425 20
    #[Override]
426
    public function getShieldState(): bool
427
    {
428 20
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_SHIELDS);
429
    }
430
431 6
    #[Override]
432
    public function getNbs(): bool
433
    {
434 6
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_NBS);
435
    }
436
437 6
    #[Override]
438
    public function getLss(): bool
439
    {
440 6
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_LSS);
441
    }
442
443 3
    #[Override]
444
    public function getPhaserState(): bool
445
    {
446 3
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_PHASER);
447
    }
448
449 1
    #[Override]
450
    public function isAlertGreen(): bool
451
    {
452 1
        return $this->getAlertState() === SpacecraftAlertStateEnum::ALERT_GREEN;
453
    }
454
455 1
    #[Override]
456
    public function getTorpedoState(): bool
457
    {
458 1
        return $this->getSystemState(SpacecraftSystemTypeEnum::SYSTEM_TORPEDO);
459
    }
460
461
    #[Override]
462
    public function getTorpedoCount(): int
463
    {
464
        if ($this->getTorpedoStorage() === null) {
465
            return 0;
466
        }
467
468
        return $this->getTorpedoStorage()->getStorage()->getAmount();
469
    }
470
471 7
    #[Override]
472
    public function isStation(): bool
473
    {
474 7
        return $this instanceof StationInterface;
475
    }
476
477 1
    #[Override]
478
    public function isShuttle(): bool
479
    {
480 1
        return $this->getRump()->getCategoryId() === SpacecraftRumpEnum::SHIP_CATEGORY_SHUTTLE;
481
    }
482
483 2
    #[Override]
484
    public function isConstruction(): bool
485
    {
486 2
        return $this->getRump()->getCategoryId() === SpacecraftRumpEnum::SHIP_CATEGORY_CONSTRUCTION;
487
    }
488
489 1
    #[Override]
490
    public function getDatabaseId(): ?int
491
    {
492 1
        return $this->database_id;
493
    }
494
495
    #[Override]
496
    public function setDatabaseId(?int $databaseEntryId): SpacecraftInterface
497
    {
498
        $this->database_id = $databaseEntryId;
499
        return $this;
500
    }
501
502 26
    #[Override]
503
    public function isDestroyed(): bool
504
    {
505 26
        return $this->is_destroyed;
506
    }
507
508
    #[Override]
509
    public function setIsDestroyed(bool $isDestroyed): SpacecraftInterface
510
    {
511
        $this->is_destroyed = $isDestroyed;
512
        return $this;
513
    }
514
515
    #[Override]
516
    public function isDisabled(): bool
517
    {
518
        return $this->disabled;
519
    }
520
521
    #[Override]
522
    public function setDisabled(bool $isDisabled): SpacecraftInterface
523
    {
524
        $this->disabled = $isDisabled;
525
        return $this;
526
    }
527
528
529
530
    /**
531
     * proportional to computer system status
532
     */
533 1
    #[Override]
534
    public function getHitChance(): int
535
    {
536 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_COMPUTER)) {
537
            return $this->hit_chance;
538
        }
539
540 1
        return (int) (ceil($this->hit_chance
541 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_COMPUTER)->getStatus() / 100));
542
    }
543
544
    #[Override]
545
    public function setHitChance(int $hitChance): SpacecraftInterface
546
    {
547
        $this->hit_chance = $hitChance;
548
        return $this;
549
    }
550
551
    /**
552
     * proportional to impulsedrive system status
553
     */
554 1
    #[Override]
555
    public function getEvadeChance(): int
556
    {
557 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE)) {
558
            return $this->evade_chance;
559
        }
560
561 1
        return (int) (ceil($this->evade_chance
562 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_IMPULSEDRIVE)->getStatus() / 100));
563
    }
564
565
    #[Override]
566
    public function setEvadeChance(int $evadeChance): SpacecraftInterface
567
    {
568
        $this->evade_chance = $evadeChance;
569
        return $this;
570
    }
571
572
    /**
573
     * proportional to energy weapon system status
574
     */
575 1
    #[Override]
576
    public function getBaseDamage(): int
577
    {
578 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_PHASER)) {
579
            return $this->base_damage;
580
        }
581
582 1
        return (int) (ceil($this->base_damage
583 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_PHASER)->getStatus() / 100));
584
    }
585
586
    #[Override]
587
    public function setBaseDamage(int $baseDamage): SpacecraftInterface
588
    {
589
        $this->base_damage = $baseDamage;
590
        return $this;
591
    }
592
593
    /**
594
     * proportional to sensor system status
595
     */
596 2
    #[Override]
597
    public function getSensorRange(): int
598
    {
599 2
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_LSS)) {
600
            return $this->sensor_range;
601
        }
602
603 2
        return (int) (ceil($this->sensor_range
604 2
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_LSS)->getStatus() / 100));
605
    }
606
607
    #[Override]
608
    public function setSensorRange(int $sensorRange): SpacecraftInterface
609
    {
610
        $this->sensor_range = $sensorRange;
611
        return $this;
612
    }
613
614
    /**
615
     * proportional to tractor beam system status
616
     */
617 1
    #[Override]
618
    public function getTractorPayload(): int
619
    {
620 1
        if (!$this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TRACTOR_BEAM)) {
621
            return 0;
622
        }
623
624 1
        return (int) (ceil($this->getRump()->getTractorPayload()
625 1
            * $this->getShipSystem(SpacecraftSystemTypeEnum::SYSTEM_TRACTOR_BEAM)->getStatus() / 100));
626
    }
627
628
    #[Override]
629
    public function getShieldRegenerationTimer(): int
630
    {
631
        return $this->shield_regeneration_timer;
632
    }
633
634
    #[Override]
635
    public function setShieldRegenerationTimer(int $shieldRegenerationTimer): SpacecraftInterface
636
    {
637
        $this->shield_regeneration_timer = $shieldRegenerationTimer;
638
        return $this;
639
    }
640
641 5
    #[Override]
642
    public function getState(): SpacecraftStateEnum
643
    {
644 5
        return $this->state;
645
    }
646
647
    #[Override]
648
    public function setState(SpacecraftStateEnum $state): SpacecraftInterface
649
    {
650
        $this->state = $state;
651
        return $this;
652
    }
653
654 1
    #[Override]
655
    public function getIsInEmergency(): bool
656
    {
657 1
        return $this->in_emergency;
658
    }
659
660
    #[Override]
661
    public function setIsInEmergency(bool $inEmergency): SpacecraftInterface
662
    {
663
        $this->in_emergency = $inEmergency;
664
        return $this;
665
    }
666
667
    #[Override]
668
    public function isUnderRepair(): bool
669
    {
670
        return $this->getState() === SpacecraftStateEnum::SHIP_STATE_REPAIR_ACTIVE
671
            || $this->getState() === SpacecraftStateEnum::SHIP_STATE_REPAIR_PASSIVE;
672
    }
673
674 13
    #[Override]
675
    public function getCrewAssignments(): Collection
676
    {
677 13
        return $this->crew;
678
    }
679
680 5
    #[Override]
681
    public function getPosX(): int
682
    {
683 5
        return $this->location->getX();
684
    }
685
686 5
    #[Override]
687
    public function getPosY(): int
688
    {
689 5
        return $this->location->getY();
690
    }
691
692 12
    #[Override]
693
    public function getCrewCount(): int
694
    {
695 12
        return $this->getCrewAssignments()->count();
696
    }
697
698 7
    #[Override]
699
    public function getNeededCrewCount(): int
700
    {
701 7
        $buildplan = $this->getBuildplan();
702 7
        if ($buildplan === null) {
703
            return 0;
704
        }
705
706 7
        return $buildplan->getCrew();
707
    }
708
709 6
    #[Override]
710
    public function getExcessCrewCount(): int
711
    {
712 6
        return $this->getCrewCount() - $this->getNeededCrewCount();
713
    }
714
715 3
    #[Override]
716
    public function hasEnoughCrew(?GameControllerInterface $game = null): bool
717
    {
718 3
        $buildplan = $this->getBuildplan();
719
720 3
        if ($buildplan === null) {
721
            if ($game !== null) {
722
                $game->addInformation(_("Keine Crew vorhanden"));
723
            }
724
            return false;
725
        }
726
727 3
        $result = $buildplan->getCrew() <= 0
728 3
            || $this->getCrewCount() >= $buildplan->getCrew();
729
730 3
        if (!$result && $game !== null) {
731
            $game->addInformationf(
732
                _("Es werden %d Crewmitglieder benötigt"),
733
                $buildplan->getCrew()
734
            );
735
        }
736
737 3
        return $result;
738
    }
739
740 40
    #[Override]
741
    public function getUser(): UserInterface
742
    {
743 40
        return $this->user;
744
    }
745
746
    #[Override]
747
    public function setUser(UserInterface $user): SpacecraftInterface
748
    {
749
        $this->user = $user;
750
        return $this;
751
    }
752
753 6
    #[Override]
754
    public function getSystem(): ?StarSystemInterface
755
    {
756 6
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getSystem() : null;
757
    }
758
759 2
    #[Override]
760
    public function getModules(): array
761
    {
762 2
        $modules = [];
763
764 2
        $buildplan = $this->getBuildplan();
765 2
        if ($buildplan === null) {
766
            return $modules;
767
        }
768
769 2
        foreach ($buildplan->getModules() as $obj) {
770 2
            $module = $obj->getModule();
771 2
            $index = $module->getType() === SpacecraftModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
772 2
            $modules[$index] = $module;
773
        }
774
775 2
        return $modules;
776
    }
777
778
    #[Override]
779
    public function isDeflectorHealthy(): bool
780
    {
781
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_DEFLECTOR);
782
    }
783
784 7
    #[Override]
785
    public function isTroopQuartersHealthy(): bool
786
    {
787 7
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_TROOP_QUARTERS);
788
    }
789
790
    #[Override]
791
    public function isMatrixScannerHealthy(): bool
792
    {
793
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_MATRIX_SCANNER);
794
    }
795
796 10
    #[Override]
797
    public function isTorpedoStorageHealthy(): bool
798
    {
799 10
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_TORPEDO_STORAGE);
800
    }
801
802 1
    #[Override]
803
    public function isShuttleRampHealthy(): bool
804
    {
805 1
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
806
    }
807
808 2
    #[Override]
809
    public function isWebEmitterHealthy(): bool
810
    {
811 2
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_THOLIAN_WEB);
812
    }
813
814
    #[Override]
815
    public function isWarpAble(): bool
816
    {
817
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE);
818
    }
819
820 2
    #[Override]
821
    public function isTractoring(): bool
822
    {
823 2
        return $this->getTractoredShip() !== null;
824
    }
825
826
    #[Override]
827
    public function isOverColony(): ?ColonyInterface
828
    {
829
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getColony() : null;
830
    }
831
832 2
    #[Override]
833
    public function isOverSystem(): ?StarSystemInterface
834
    {
835 2
        $location = $this->getLocation();
836 2
        if ($location instanceof StarSystemMapInterface) {
837
            return null;
838
        }
839
840 2
        return $location->getSystem();
841
    }
842
843 1
    #[Override]
844
    public function isWarpPossible(): bool
845
    {
846 1
        return $this->hasShipSystem(SpacecraftSystemTypeEnum::SYSTEM_WARPDRIVE) && $this->getSystem() === null;
847
    }
848
849 1
    #[Override]
850
    public function getTorpedo(): ?TorpedoTypeInterface
851
    {
852 1
        if ($this->getTorpedoStorage() === null) {
853 1
            return null;
854
        }
855
856
        return $this->getTorpedoStorage()->getTorpedo();
857
    }
858
859 1
    #[Override]
860
    public function getTorpedoStorage(): ?TorpedoStorageInterface
861
    {
862 1
        return $this->torpedoStorage;
863
    }
864
865
    #[Override]
866
    public function setTorpedoStorage(?TorpedoStorageInterface $torpedoStorage): SpacecraftInterface
867
    {
868
        $this->torpedoStorage = $torpedoStorage;
869
        return $this;
870
    }
871
872 15
    #[Override]
873
    public function getStorage(): Collection
874
    {
875 15
        return $this->storage;
876
    }
877
878 1
    #[Override]
879
    public function getLogbook(): Collection
880
    {
881 1
        return $this->logbook;
882
    }
883
884 4
    #[Override]
885
    public function getTakeoverActive(): ?ShipTakeoverInterface
886
    {
887 4
        return $this->takeoverActive;
888
    }
889
890
    #[Override]
891
    public function setTakeoverActive(?ShipTakeoverInterface $takeover): SpacecraftInterface
892
    {
893
        $this->takeoverActive = $takeover;
894
895
        return $this;
896
    }
897
898 4
    #[Override]
899
    public function getTakeoverPassive(): ?ShipTakeoverInterface
900
    {
901 4
        return $this->takeoverPassive;
902
    }
903
904
    #[Override]
905
    public function setTakeoverPassive(?ShipTakeoverInterface $takeover): SpacecraftInterface
906
    {
907
        $this->takeoverPassive = $takeover;
908
909
        return $this;
910
    }
911
912 14
    #[Override]
913
    public function getStorageSum(): int
914
    {
915 14
        return array_reduce(
916 14
            $this->getStorage()->getValues(),
917 14
            fn(int $sum, StorageInterface $storage): int => $sum + $storage->getAmount(),
918 14
            0
919 14
        );
920
    }
921
922 13
    #[Override]
923
    public function getMaxStorage(): int
924
    {
925 13
        return $this->getRump()->getStorage();
926
    }
927
928 8
    #[Override]
929
    public function getBeamableStorage(): Collection
930
    {
931 8
        return CommodityTransfer::excludeNonBeamable($this->storage);
932
    }
933
934 8
    #[Override]
935
    public function getMap(): ?MapInterface
936
    {
937 8
        if ($this->location instanceof MapInterface) {
938 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...
939
        }
940 2
        if ($this->location instanceof StarSystemMapInterface) {
941 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

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