Passed
Pull Request — master (#1846)
by Nico
32:16
created

Ship::hasShipSystem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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\Entity;
11
use Doctrine\ORM\Mapping\GeneratedValue;
12
use Doctrine\ORM\Mapping\Id;
13
use Doctrine\ORM\Mapping\Index;
14
use Doctrine\ORM\Mapping\JoinColumn;
15
use Doctrine\ORM\Mapping\ManyToOne;
16
use Doctrine\ORM\Mapping\OneToMany;
17
use Doctrine\ORM\Mapping\OneToOne;
18
use Doctrine\ORM\Mapping\OrderBy;
19
use Doctrine\ORM\Mapping\Table;
20
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...
21
use RuntimeException;
22
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...
23
use Stu\Component\Ship\ShipAlertStateEnum;
24
use Stu\Component\Ship\ShipLSSModeEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\ShipLSSModeEnum 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\Ship\ShipModuleTypeEnum;
26
use Stu\Component\Ship\ShipRumpEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\ShipRumpEnum 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...
27
use Stu\Component\Ship\ShipStateEnum;
28
use Stu\Component\Ship\SpacecraftTypeEnum;
29
use Stu\Component\Ship\System\ShipSystemModeEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\System\ShipSystemModeEnum 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...
30
use Stu\Component\Ship\System\ShipSystemTypeEnum;
31
use Stu\Component\Ship\System\Type\TorpedoStorageShipSystem;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\Syste...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...
32
use Stu\Component\Ship\System\Type\TractorBeamShipSystem;
33
use Stu\Component\Station\StationUtility;
34
use Stu\Module\Control\GameControllerInterface;
35
use Stu\Module\Logging\LoggerUtilInterface;
36
use Stu\Module\Ship\Lib\Battle\FightLib;
37
use Stu\Orm\Repository\ShipRepository;
38
39
#[Table(name: 'stu_ships')]
40
#[Index(name: 'ship_fleet_idx', columns: ['fleets_id'])]
41
#[Index(name: 'ship_location_idx', columns: ['location_id'])]
42
#[Index(name: 'ship_rump_idx', columns: ['rumps_id'])]
43
#[Index(name: 'ship_web_idx', columns: ['holding_web_id'])]
44
#[Index(name: 'ship_user_idx', columns: ['user_id'])]
45
#[Index(name: 'ship_tractored_idx', columns: ['tractored_ship_id'])]
46
#[Index(name: 'ship_influence_area_idx', columns: ['influence_area_id'])]
47
#[Entity(repositoryClass: ShipRepository::class)]
48
class Ship implements ShipInterface
49
{
50
    #[Id]
51
    #[Column(type: 'integer')]
52
    #[GeneratedValue(strategy: 'IDENTITY')]
53
    private ?int $id = null;
54
55
    #[Column(type: 'integer')]
56
    private int $user_id = 0;
57
58
    #[Column(type: 'integer')]
59
    private int $rumps_id = 0;
0 ignored issues
show
introduced by
The private property $rumps_id is not used, and could be removed.
Loading history...
60
61
    #[Column(type: 'integer', nullable: true)]
62
    private ?int $plans_id = null;
0 ignored issues
show
introduced by
The private property $plans_id is not used, and could be removed.
Loading history...
63
64
    #[Column(type: 'integer', nullable: true)]
65
    private ?int $fleets_id = null;
66
67
    #[Column(type: 'smallint', length: 1)]
68
    private int $direction = 0;
69
70
    #[Column(type: 'string')]
71
    private string $name = '';
72
73
    #[Column(type: 'smallint', length: 1, enumType: ShipAlertStateEnum::class)]
74
    private ShipAlertStateEnum $alvl = ShipAlertStateEnum::ALERT_GREEN;
75
76
    #[Column(type: 'smallint', length: 1)]
77
    private int $lss_mode = ShipLSSModeEnum::LSS_NORMAL;
78
79
    #[Column(type: 'integer', length: 6)]
80
    private int $huelle = 0;
81
82
    #[Column(type: 'integer', length: 6)]
83
    private int $max_huelle = 0;
84
85
    #[Column(type: 'integer', length: 6)]
86
    private int $schilde = 0;
87
88
    #[Column(type: 'integer', length: 6)]
89
    private int $max_schilde = 0;
90
91
    #[Column(type: 'integer', nullable: true)]
92
    private ?int $tractored_ship_id = null;
93
94
    #[Column(type: 'integer', nullable: true)]
95
    private ?int $holding_web_id = null;
96
97
    #[Column(type: 'integer', nullable: true)]
98
    private ?int $dock = null;
99
100
    #[Column(type: 'integer')]
101
    private int $former_rumps_id = 0;
102
103
    #[Column(type: 'smallint', length: 1, enumType: SpacecraftTypeEnum::class)]
104
    private SpacecraftTypeEnum $type = SpacecraftTypeEnum::SPACECRAFT_TYPE_SHIP;
105
106
    #[Column(type: 'integer')]
107
    private int $database_id = 0;
108
109
    #[Column(type: 'boolean')]
110
    private bool $is_destroyed = false;
111
112
    #[Column(type: 'boolean')]
113
    private bool $disabled = false;
114
115
    #[Column(type: 'smallint', length: 3)]
116
    private int $hit_chance = 0;
117
118
    #[Column(type: 'smallint', length: 3)]
119
    private int $evade_chance = 0;
120
121
    #[Column(type: 'smallint', length: 4)]
122
    private int $base_damage = 0;
123
124
    #[Column(type: 'smallint', length: 3)]
125
    private int $sensor_range = 0;
126
127
    #[Column(type: 'integer')]
128
    private int $shield_regeneration_timer = 0;
129
130
    #[Column(type: 'smallint', enumType: ShipStateEnum::class)]
131
    private ShipStateEnum $state = ShipStateEnum::SHIP_STATE_NONE;
132
133
    #[Column(type: 'boolean')]
134
    private bool $is_fleet_leader = false;
135
136
    #[Column(type: 'integer')]
137
    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...
138
139
    #[Column(type: 'integer', nullable: true)]
140
    private ?int $map_id = null;
0 ignored issues
show
introduced by
The private property $map_id is not used, and could be removed.
Loading history...
141
142
    #[Column(type: 'integer', nullable: true)]
143
    private ?int $starsystem_map_id = null;
0 ignored issues
show
introduced by
The private property $starsystem_map_id is not used, and could be removed.
Loading history...
144
145
    #[Column(type: 'integer', nullable: true)]
146
    private ?int $influence_area_id = null;
0 ignored issues
show
introduced by
The private property $influence_area_id is not used, and could be removed.
Loading history...
147
148
    #[Column(type: 'boolean')]
149
    private bool $in_emergency = false;
150
151
    #[ManyToOne(targetEntity: 'Fleet', inversedBy: 'ships')]
152
    #[JoinColumn(name: 'fleets_id', referencedColumnName: 'id')]
153
    private ?FleetInterface $fleet = null;
154
155
    #[OneToOne(targetEntity: 'TradePost', mappedBy: 'ship')]
156
    private ?TradePostInterface $tradePost = null;
157
158
    #[ManyToOne(targetEntity: 'Ship', inversedBy: 'dockedShips')]
159
    #[JoinColumn(name: 'dock', referencedColumnName: 'id')]
160
    private ?ShipInterface $dockedTo = null;
161
162
    /**
163
     * @var ArrayCollection<int, ShipInterface>
164
     */
165
    #[OneToMany(targetEntity: 'Ship', mappedBy: 'dockedTo', indexBy: 'id')]
166
    #[OrderBy(['fleets_id' => 'DESC', 'is_fleet_leader' => 'DESC'])]
167
    private Collection $dockedShips;
168
169
    /**
170
     * @var ArrayCollection<int, DockingPrivilegeInterface>
171
     */
172
    #[OneToMany(targetEntity: 'DockingPrivilege', mappedBy: 'ship')]
173
    private Collection $dockingPrivileges;
174
175
    #[OneToOne(targetEntity: 'Ship')]
176
    #[JoinColumn(name: 'tractored_ship_id', referencedColumnName: 'id')]
177
    private ?ShipInterface $tractoredShip = null;
178
179
    #[OneToOne(targetEntity: 'Ship', mappedBy: 'tractoredShip')]
180
    private ?ShipInterface $tractoringShip = null;
181
182
    #[ManyToOne(targetEntity: 'TholianWeb')]
183
    #[JoinColumn(name: 'holding_web_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
184
    private ?TholianWebInterface $holdingWeb = null;
185
186
    #[ManyToOne(targetEntity: 'User')]
187
    #[JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
188
    private UserInterface $user;
189
190
    /**
191
     * @var ArrayCollection<int, ShipCrewInterface>
192
     */
193
    #[OneToMany(targetEntity: 'ShipCrew', mappedBy: 'ship', indexBy: 'id')]
194
    #[OrderBy(['id' => 'ASC'])]
195
    private Collection $crew;
196
197
    #[OneToOne(targetEntity: 'TorpedoStorage', mappedBy: 'ship')]
198
    private ?TorpedoStorageInterface $torpedoStorage = null;
199
200
    /**
201
     * @var ArrayCollection<int, ShipSystemInterface>
202
     */
203
    #[OneToMany(targetEntity: 'ShipSystem', mappedBy: 'ship', indexBy: 'system_type')]
204
    #[OrderBy(['system_type' => 'ASC'])]
205
    private Collection $systems;
206
207
    #[ManyToOne(targetEntity: 'ShipRump')]
208
    #[JoinColumn(name: 'rumps_id', referencedColumnName: 'id')]
209
    private ShipRumpInterface $rump;
210
211
    #[ManyToOne(targetEntity: 'ShipBuildplan')]
212
    #[JoinColumn(name: 'plans_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
213
    private ?ShipBuildplanInterface $buildplan = null;
214
215
    /**
216
     * @var ArrayCollection<int, StorageInterface>
217
     */
218
    #[OneToMany(targetEntity: 'Storage', mappedBy: 'ship', indexBy: 'commodity_id')]
219
    #[OrderBy(['commodity_id' => 'ASC'])]
220
    private Collection $storage;
221
222
    #[ManyToOne(targetEntity: 'Location')]
223
    #[JoinColumn(name: 'location_id', referencedColumnName: 'id')]
224
    private LocationInterface $location;
225
226
    #[ManyToOne(targetEntity: 'StarSystem')]
227
    #[JoinColumn(name: 'influence_area_id', referencedColumnName: 'id')]
228
    private ?StarSystemInterface $influenceArea = null;
229
230
    /**
231
     * @var ArrayCollection<int, ShipLogInterface>
232
     */
233
    #[OneToMany(targetEntity: 'ShipLog', mappedBy: 'ship', fetch: 'EXTRA_LAZY')]
234
    #[OrderBy(['id' => 'DESC'])]
235
    private Collection $logbook;
236
237
    #[OneToOne(targetEntity: 'ShipTakeover', mappedBy: 'source')]
238
    private ?ShipTakeoverInterface $takeoverActive = null;
239
240
    #[OneToOne(targetEntity: 'ShipTakeover', mappedBy: 'target')]
241
    private ?ShipTakeoverInterface $takeoverPassive = null;
242
243 3
    public function __construct()
244
    {
245 3
        $this->dockedShips = new ArrayCollection();
246 3
        $this->dockingPrivileges = new ArrayCollection();
247 3
        $this->crew = new ArrayCollection();
248 3
        $this->systems = new ArrayCollection();
249 3
        $this->storage = new ArrayCollection();
250 3
        $this->logbook = new ArrayCollection();
251
    }
252
253
    #[Override]
254
    public function getId(): int
255
    {
256
        if ($this->id === null) {
257
            throw new RuntimeException('entity not yet persisted');
258
        }
259
260
        return $this->id;
261
    }
262
263
    #[Override]
264
    public function getUserId(): int
265
    {
266
        return $this->user_id;
267
    }
268
269
    #[Override]
270
    public function getUserName(): string
271
    {
272
        return $this->getUser()->getName();
273
    }
274
275
    #[Override]
276
    public function getFleetId(): ?int
277
    {
278
        return $this->fleets_id;
279
    }
280
281
    #[Override]
282
    public function setFleetId(?int $fleetId): ShipInterface
283
    {
284
        $this->fleets_id = $fleetId;
285
        return $this;
286
    }
287
288
    #[Override]
289
    public function getSystemsId(): ?int
290
    {
291
        return $this->getSystem() !== null ? $this->getSystem()->getId() : null;
292
    }
293
294
    #[Override]
295
    public function getLayer(): ?LayerInterface
296
    {
297
        return $this->getLocation()->getLayer();
298
    }
299
300
    #[Override]
301
    public function getSx(): int
302
    {
303
        return $this->getStarsystemMap()->getSx();
304
    }
305
306
    #[Override]
307
    public function getSy(): int
308
    {
309
        return $this->getStarsystemMap()->getSy();
310
    }
311
312
    #[Override]
313
    public function getFlightDirection(): int
314
    {
315
        return $this->direction;
316
    }
317
318
    #[Override]
319
    public function setFlightDirection(int $direction): ShipInterface
320
    {
321
        $this->direction = $direction;
322
        return $this;
323
    }
324
325
    #[Override]
326
    public function getName(): string
327
    {
328
        return $this->name;
329
    }
330
331
    #[Override]
332
    public function setName(string $name): ShipInterface
333
    {
334
        $this->name = $name;
335
        return $this;
336
    }
337
338
    #[Override]
339
    public function getLSSmode(): int
340
    {
341
        return $this->lss_mode;
342
    }
343
344
    public function isLSSModeNormal(): bool
345
    {
346
        return $this->getLSSMode() === ShipLSSModeEnum::LSS_NORMAL;
347
    }
348
349
    public function isLSSModeBorder(): bool
350
    {
351
        return $this->getLSSMode() === ShipLSSModeEnum::LSS_BORDER;
352
    }
353
354
    #[Override]
355
    public function setLSSMode(int $lssMode): ShipInterface
356
    {
357
        $this->lss_mode = $lssMode;
358
        return $this;
359
    }
360
361
    #[Override]
362
    public function getAlertState(): ShipAlertStateEnum
363
    {
364
        return $this->alvl;
365
    }
366
367
    #[Override]
368
    public function setAlertState(ShipAlertStateEnum $state): ShipInterface
369
    {
370
        $this->alvl = $state;
371
        return $this;
372
    }
373
374
    #[Override]
375
    public function setAlertStateGreen(): ShipInterface
376
    {
377
        return $this->setAlertState(ShipAlertStateEnum::ALERT_GREEN);
378
    }
379
380
    #[Override]
381
    public function isSystemHealthy(ShipSystemTypeEnum $type): bool
382
    {
383
        if (!$this->hasShipSystem($type)) {
384
            return false;
385
        }
386
387
        return $this->getShipSystem($type)->getStatus() > 0;
388
    }
389
390
    #[Override]
391
    public function getSystemState(ShipSystemTypeEnum $type): bool
392
    {
393
        if (!$this->hasShipSystem($type)) {
394
            return false;
395
        }
396
397
        return $this->getShipSystem($type)->getMode() === ShipSystemModeEnum::MODE_ON
398
            || $this->getShipSystem($type)->getMode() === ShipSystemModeEnum::MODE_ALWAYS_ON;
399
    }
400
401
    #[Override]
402
    public function getImpulseState(): bool
403
    {
404
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
405
    }
406
407
    #[Override]
408
    public function getWarpDriveState(): bool
409
    {
410
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
411
    }
412
413
    #[Override]
414
    public function isWarped(): bool
415
    {
416
        $tractoringShip = $this->getTractoringShip();
417
418
        if ($tractoringShip !== null) {
419
            return $tractoringShip->getWarpDriveState();
420
        }
421
422
        return $this->getWarpDriveState();
423
    }
424
425
    #[Override]
426
    public function getWebState(): bool
427
    {
428
        return $this->getHoldingWeb() !== null;
429
    }
430
431
    #[Override]
432
    public function getCloakState(): bool
433
    {
434
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_CLOAK);
435
    }
436
437
    #[Override]
438
    public function getTachyonState(): bool
439
    {
440
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
441
    }
442
443
    #[Override]
444
    public function getSubspaceState(): bool
445
    {
446
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
447
    }
448
449
    #[Override]
450
    public function getAstroState(): bool
451
    {
452
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY);
453
    }
454
455
    #[Override]
456
    public function getRPGModuleState(): bool
457
    {
458
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_RPG_MODULE);
459
    }
460
461
    #[Override]
462
    public function getConstructionHubState(): bool
463
    {
464
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_CONSTRUCTION_HUB);
465
    }
466
467
    #[Override]
468
    public function getHull(): int
469
    {
470
        return $this->huelle;
471
    }
472
473
    #[Override]
474
    public function setHuell(int $hull): ShipInterface
475
    {
476
        $this->huelle = $hull;
477
        return $this;
478
    }
479
480
    #[Override]
481
    public function getMaxHull(): int
482
    {
483
        return $this->max_huelle;
484
    }
485
486
    #[Override]
487
    public function setMaxHuell(int $maxHull): ShipInterface
488
    {
489
        $this->max_huelle = $maxHull;
490
        return $this;
491
    }
492
493
    #[Override]
494
    public function getShield(): int
495
    {
496
        return $this->schilde;
497
    }
498
499
    #[Override]
500
    public function setShield(int $schilde): ShipInterface
501
    {
502
        $this->schilde = $schilde;
503
        return $this;
504
    }
505
506
    /**
507
     * proportional to shield system status
508
     */
509
    #[Override]
510
    public function getMaxShield(bool $isTheoretical = false): int
511
    {
512
        if ($isTheoretical || !$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHIELDS)) {
513
            return $this->max_schilde;
514
        }
515
516
        return (int) (ceil($this->max_schilde
517
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_SHIELDS)->getStatus() / 100));
518
    }
519
520
    #[Override]
521
    public function setMaxShield(int $maxShields): ShipInterface
522
    {
523
        $this->max_schilde = $maxShields;
524
        return $this;
525
    }
526
527
    #[Override]
528
    public function getHealthPercentage(): float
529
    {
530
        return ($this->getHull() + $this->getShield())
531
            / ($this->getMaxHull() + $this->getMaxShield(true)) * 100;
532
    }
533
534
    #[Override]
535
    public function getShieldState(): bool
536
    {
537
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_SHIELDS);
538
    }
539
540
    #[Override]
541
    public function getNbs(): bool
542
    {
543
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_NBS);
544
    }
545
546
    #[Override]
547
    public function getLss(): bool
548
    {
549
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_LSS);
550
    }
551
552
    #[Override]
553
    public function getPhaserState(): bool
554
    {
555
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_PHASER);
556
    }
557
558
    #[Override]
559
    public function isAlertGreen(): bool
560
    {
561
        return $this->getAlertState() === ShipAlertStateEnum::ALERT_GREEN;
562
    }
563
564
    #[Override]
565
    public function getTorpedoState(): bool
566
    {
567
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_TORPEDO);
568
    }
569
570
    #[Override]
571
    public function getFormerRumpId(): int
572
    {
573
        return $this->former_rumps_id;
574
    }
575
576
    #[Override]
577
    public function setFormerRumpId(int $formerShipRumpId): ShipInterface
578
    {
579
        $this->former_rumps_id = $formerShipRumpId;
580
        return $this;
581
    }
582
583
    #[Override]
584
    public function getTorpedoCount(): int
585
    {
586
        if ($this->getTorpedoStorage() === null) {
587
            return 0;
588
        }
589
590
        return $this->getTorpedoStorage()->getStorage()->getAmount();
591
    }
592
593
    #[Override]
594
    public function isBase(): bool
595
    {
596
        return $this->type === SpacecraftTypeEnum::SPACECRAFT_TYPE_STATION;
597
    }
598
599
    #[Override]
600
    public function isTrumfield(): bool
601
    {
602
        return $this->getRump()->isTrumfield();
603
    }
604
605
    #[Override]
606
    public function isShuttle(): bool
607
    {
608
        return $this->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_SHUTTLE;
609
    }
610
611
    #[Override]
612
    public function isConstruction(): bool
613
    {
614
        return $this->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_CONSTRUCTION;
615
    }
616
617
    #[Override]
618
    public function getSpacecraftType(): SpacecraftTypeEnum
619
    {
620
        return $this->type;
621
    }
622
623
    #[Override]
624
    public function setSpacecraftType(SpacecraftTypeEnum $type): ShipInterface
625
    {
626
        $this->type = $type;
627
        return $this;
628
    }
629
630
    #[Override]
631
    public function getDatabaseId(): int
632
    {
633
        return $this->database_id;
634
    }
635
636
    #[Override]
637
    public function setDatabaseId(int $databaseEntryId): ShipInterface
638
    {
639
        $this->database_id = $databaseEntryId;
640
        return $this;
641
    }
642
643
    #[Override]
644
    public function isDestroyed(): bool
645
    {
646
        return $this->is_destroyed;
647
    }
648
649
    #[Override]
650
    public function setIsDestroyed(bool $isDestroyed): ShipInterface
651
    {
652
        $this->is_destroyed = $isDestroyed;
653
        return $this;
654
    }
655
656
    #[Override]
657
    public function isDisabled(): bool
658
    {
659
        return $this->disabled;
660
    }
661
662
    #[Override]
663
    public function setDisabled(bool $isDisabled): ShipInterface
664
    {
665
        $this->disabled = $isDisabled;
666
        return $this;
667
    }
668
669
670
671
    /**
672
     * proportional to computer system status
673
     */
674
    #[Override]
675
    public function getHitChance(): int
676
    {
677
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_COMPUTER)) {
678
            return $this->hit_chance;
679
        }
680
681
        return (int) (ceil($this->hit_chance
682
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_COMPUTER)->getStatus() / 100));
683
    }
684
685
    #[Override]
686
    public function setHitChance(int $hitChance): ShipInterface
687
    {
688
        $this->hit_chance = $hitChance;
689
        return $this;
690
    }
691
692
    /**
693
     * proportional to impulsedrive system status
694
     */
695
    #[Override]
696
    public function getEvadeChance(): int
697
    {
698
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE)) {
699
            return $this->evade_chance;
700
        }
701
702
        return (int) (ceil($this->evade_chance
703
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE)->getStatus() / 100));
704
    }
705
706
    #[Override]
707
    public function setEvadeChance(int $evadeChance): ShipInterface
708
    {
709
        $this->evade_chance = $evadeChance;
710
        return $this;
711
    }
712
713
    /**
714
     * proportional to energy weapon system status
715
     */
716
    #[Override]
717
    public function getBaseDamage(): int
718
    {
719
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER)) {
720
            return $this->base_damage;
721
        }
722
723
        return (int) (ceil($this->base_damage
724
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER)->getStatus() / 100));
725
    }
726
727
    #[Override]
728
    public function setBaseDamage(int $baseDamage): ShipInterface
729
    {
730
        $this->base_damage = $baseDamage;
731
        return $this;
732
    }
733
734
    /**
735
     * proportional to sensor system status
736
     */
737
    #[Override]
738
    public function getSensorRange(): int
739
    {
740
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LSS)) {
741
            return $this->sensor_range;
742
        }
743
744
        return (int) (ceil($this->sensor_range
745
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_LSS)->getStatus() / 100));
746
    }
747
748
    #[Override]
749
    public function setSensorRange(int $sensorRange): ShipInterface
750
    {
751
        $this->sensor_range = $sensorRange;
752
        return $this;
753
    }
754
755
    /**
756
     * proportional to tractor beam system status
757
     */
758
    #[Override]
759
    public function getTractorPayload(): int
760
    {
761
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM)) {
762
            return 0;
763
        }
764
765
        return (int) (ceil($this->getRump()->getTractorPayload()
766
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM)->getStatus() / 100));
767
    }
768
769
    #[Override]
770
    public function getShieldRegenerationTimer(): int
771
    {
772
        return $this->shield_regeneration_timer;
773
    }
774
775
    #[Override]
776
    public function setShieldRegenerationTimer(int $shieldRegenerationTimer): ShipInterface
777
    {
778
        $this->shield_regeneration_timer = $shieldRegenerationTimer;
779
        return $this;
780
    }
781
782
    #[Override]
783
    public function getState(): ShipStateEnum
784
    {
785
        return $this->state;
786
    }
787
788
    #[Override]
789
    public function setState(ShipStateEnum $state): ShipInterface
790
    {
791
        $this->state = $state;
792
        return $this;
793
    }
794
795
    #[Override]
796
    public function getIsInEmergency(): bool
797
    {
798
        return $this->in_emergency;
799
    }
800
801
    #[Override]
802
    public function setIsInEmergency(bool $inEmergency): ShipInterface
803
    {
804
        $this->in_emergency = $inEmergency;
805
        return $this;
806
    }
807
808
    #[Override]
809
    public function isUnderRepair(): bool
810
    {
811
        return $this->getState() === ShipStateEnum::SHIP_STATE_REPAIR_ACTIVE
812
            || $this->getState() === ShipStateEnum::SHIP_STATE_REPAIR_PASSIVE;
813
    }
814
815
    #[Override]
816
    public function getIsFleetLeader(): bool
817
    {
818
        return $this->getFleet() !== null && $this->is_fleet_leader;
819
    }
820
821
    #[Override]
822
    public function setIsFleetLeader(bool $isFleetLeader): ShipInterface
823
    {
824
        $this->is_fleet_leader = $isFleetLeader;
825
        return $this;
826
    }
827
828
    #[Override]
829
    public function getCrewAssignments(): Collection
830
    {
831
        return $this->crew;
832
    }
833
834
    #[Override]
835
    public function getPosX(): int
836
    {
837
        return $this->location->getX();
838
    }
839
840
    #[Override]
841
    public function getPosY(): int
842
    {
843
        return $this->location->getY();
844
    }
845
846
    #[Override]
847
    public function getCrewCount(): int
848
    {
849
        return $this->getCrewAssignments()->count();
850
    }
851
852
    #[Override]
853
    public function getNeededCrewCount(): int
854
    {
855
        $buildplan = $this->getBuildplan();
856
        if ($buildplan === null) {
857
            return 0;
858
        }
859
860
        return $buildplan->getCrew();
861
    }
862
863
    #[Override]
864
    public function getExcessCrewCount(): int
865
    {
866
        return $this->getCrewCount() - $this->getNeededCrewCount();
867
    }
868
869
    #[Override]
870
    public function hasEnoughCrew(?GameControllerInterface $game = null): bool
871
    {
872
        $buildplan = $this->getBuildplan();
873
874
        if ($buildplan === null) {
875
            if ($game !== null) {
876
                $game->addInformation(_("Keine Crew vorhanden"));
877
            }
878
            return false;
879
        }
880
881
        $result = $buildplan->getCrew() <= 0
882
            || $this->getCrewCount() >= $buildplan->getCrew();
883
884
        if (!$result && $game !== null) {
885
            $game->addInformationf(
886
                _("Es werden %d Crewmitglieder benötigt"),
887
                $buildplan->getCrew()
888
            );
889
        }
890
891
        return $result;
892
    }
893
894
    #[Override]
895
    public function getFleet(): ?FleetInterface
896
    {
897
        return $this->fleet;
898
    }
899
900
    #[Override]
901
    public function setFleet(?FleetInterface $fleet): ShipInterface
902
    {
903
        $this->fleet = $fleet;
904
        return $this;
905
    }
906
907
    #[Override]
908
    public function isFleetLeader(): bool
909
    {
910
        return $this->getIsFleetLeader();
911
    }
912
913
    #[Override]
914
    public function getUser(): UserInterface
915
    {
916
        return $this->user;
917
    }
918
919
    #[Override]
920
    public function setUser(UserInterface $user): ShipInterface
921
    {
922
        $this->user = $user;
923
        return $this;
924
    }
925
926
    #[Override]
927
    public function getSystem(): ?StarSystemInterface
928
    {
929
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getSystem() : null;
930
    }
931
932
    #[Override]
933
    public function getModules(): array
934
    {
935
        $modules = [];
936
937
        $buildplan = $this->getBuildplan();
938
        if ($buildplan === null) {
939
            return $modules;
940
        }
941
942
        foreach ($buildplan->getModules() as $obj) {
943
            $module = $obj->getModule();
944
            $index = $module->getType() === ShipModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
945
            $modules[$index] = $module;
946
        }
947
948
        if ($this->isBase()) {
949
            foreach ($this->getSystems() as $system) {
950
                $module = $system->getModule();
951
952
                if ($module !== null) {
953
                    $index = $module->getType() === ShipModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
954
                    $modules[$index] = $module;
955
                }
956
            }
957
        }
958
959
        return $modules;
960
    }
961
962
    #[Override]
963
    public function isDeflectorHealthy(): bool
964
    {
965
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_DEFLECTOR);
966
    }
967
968
    #[Override]
969
    public function isTroopQuartersHealthy(): bool
970
    {
971
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS);
972
    }
973
974
    #[Override]
975
    public function isMatrixScannerHealthy(): bool
976
    {
977
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_MATRIX_SCANNER);
978
    }
979
980
    #[Override]
981
    public function isTorpedoStorageHealthy(): bool
982
    {
983
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE);
984
    }
985
986
    #[Override]
987
    public function isShuttleRampHealthy(): bool
988
    {
989
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
990
    }
991
992
    #[Override]
993
    public function isWebEmitterHealthy(): bool
994
    {
995
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_THOLIAN_WEB);
996
    }
997
998
    #[Override]
999
    public function isWarpAble(): bool
1000
    {
1001
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
1002
    }
1003
1004
    #[Override]
1005
    public function isTractoring(): bool
1006
    {
1007
        return $this->getTractoredShip() !== null;
1008
    }
1009
1010
    #[Override]
1011
    public function isTractored(): bool
1012
    {
1013
        return $this->getTractoringShip() !== null;
1014
    }
1015
1016
    #[Override]
1017
    public function isOverColony(): ?ColonyInterface
1018
    {
1019
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getColony() : null;
1020
    }
1021
1022
    #[Override]
1023
    public function isOverSystem(): ?StarSystemInterface
1024
    {
1025
        if ($this->getSystem() !== null) {
1026
            return null;
1027
        }
1028
1029
        return $this->getMap()->getSystem();
1030
    }
1031
1032
    #[Override]
1033
    public function isWarpPossible(): bool
1034
    {
1035
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE) && $this->getSystem() === null;
1036
    }
1037
1038
    #[Override]
1039
    public function getTorpedo(): ?TorpedoTypeInterface
1040
    {
1041
        if ($this->getTorpedoStorage() === null) {
1042
            return null;
1043
        }
1044
1045
        return $this->getTorpedoStorage()->getTorpedo();
1046
    }
1047
1048
    #[Override]
1049
    public function getTorpedoStorage(): ?TorpedoStorageInterface
1050
    {
1051
        return $this->torpedoStorage;
1052
    }
1053
1054
    #[Override]
1055
    public function setTorpedoStorage(?TorpedoStorageInterface $torpedoStorage): ShipInterface
1056
    {
1057
        $this->torpedoStorage = $torpedoStorage;
1058
        return $this;
1059
    }
1060
1061
    #[Override]
1062
    public function getStorage(): Collection
1063
    {
1064
        return $this->storage;
1065
    }
1066
1067
    #[Override]
1068
    public function getLogbook(): Collection
1069
    {
1070
        return $this->logbook;
1071
    }
1072
1073
    #[Override]
1074
    public function getTakeoverActive(): ?ShipTakeoverInterface
1075
    {
1076
        return $this->takeoverActive;
1077
    }
1078
1079
    #[Override]
1080
    public function setTakeoverActive(?ShipTakeoverInterface $takeover): ShipInterface
1081
    {
1082
        $this->takeoverActive = $takeover;
1083
1084
        return $this;
1085
    }
1086
1087
    #[Override]
1088
    public function getTakeoverPassive(): ?ShipTakeoverInterface
1089
    {
1090
        return $this->takeoverPassive;
1091
    }
1092
1093
    #[Override]
1094
    public function setTakeoverPassive(?ShipTakeoverInterface $takeover): ShipInterface
1095
    {
1096
        $this->takeoverPassive = $takeover;
1097
1098
        return $this;
1099
    }
1100
1101
    #[Override]
1102
    public function getStorageSum(): int
1103
    {
1104
        return array_reduce(
1105
            $this->getStorage()->getValues(),
1106
            fn (int $sum, StorageInterface $storage): int => $sum + $storage->getAmount(),
1107
            0
1108
        );
1109
    }
1110
1111
    #[Override]
1112
    public function getMaxStorage(): int
1113
    {
1114
        return $this->getRump()->getStorage();
1115
    }
1116
1117
    #[Override]
1118
    public function getBeamableStorage(): array
1119
    {
1120
        return array_filter(
1121
            $this->getStorage()->getValues(),
1122
            fn (StorageInterface $storage): bool => $storage->getCommodity()->isBeamable() === true
1123
        );
1124
    }
1125
1126
    #[Override]
1127
    public function getTradePost(): ?TradePostInterface
1128
    {
1129
        return $this->tradePost;
1130
    }
1131
1132
    #[Override]
1133
    public function setTradePost(?TradePostInterface $tradePost): ShipInterface
1134
    {
1135
        $this->tradePost = $tradePost;
1136
1137
        return $this;
1138
    }
1139
1140 3
    #[Override]
1141
    public function getMap(): ?MapInterface
1142
    {
1143 3
        if ($this->location instanceof MapInterface) {
1144 1
            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...
1145
        }
1146 2
        if ($this->location instanceof StarSystemMapInterface) {
1147 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

1147
            return $this->location->/** @scrutinizer ignore-call */ getSystem()->getMap();
Loading history...
1148
        }
1149
1150
        return null;
1151
    }
1152
1153
    #[Override]
1154
    public function getMapRegion(): ?MapRegionInterface
1155
    {
1156
        $systemMap = $this->getStarsystemMap();
1157
        if ($systemMap !== null) {
1158
            return null;
1159
        }
1160
1161
        $map = $this->getMap();
1162
        if ($map === null) {
1163
            return null;
1164
        }
1165
1166
        return $map->getMapRegion();
1167
    }
1168
1169 3
    #[Override]
1170
    public function setLocation(LocationInterface $location): ShipInterface
1171
    {
1172 3
        $this->location = $location;
1173
1174 3
        return $this;
1175
    }
1176
1177 3
    #[Override]
1178
    public function getStarsystemMap(): ?StarSystemMapInterface
1179
    {
1180 3
        if ($this->location instanceof StarSystemMapInterface) {
1181 2
            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...
1182
        }
1183
1184 1
        return null;
1185
    }
1186
1187
    #[Override]
1188
    public function getLocation(): MapInterface|StarSystemMapInterface
1189
    {
1190
        if (
1191
            $this->location instanceof MapInterface
1192
            || $this->location instanceof StarSystemMapInterface
1193
        ) {
1194
            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...
1195
        }
1196
1197
        throw new RuntimeException('unknown type');
1198
    }
1199
1200
    #[Override]
1201
    public function getInfluenceArea(): ?StarSystemInterface
1202
    {
1203
        return $this->influenceArea;
1204
    }
1205
1206
    #[Override]
1207
    public function setInfluenceArea(?StarSystemInterface $influenceArea): ShipInterface
1208
    {
1209
        $this->influenceArea = $influenceArea;
1210
        return $this;
1211
    }
1212
1213
    #[Override]
1214
    public function getBeamFactor(): int
1215
    {
1216
        return $this->getRump()->getBeamFactor();
1217
    }
1218
1219
    #[Override]
1220
    public function getSectorString(): string
1221
    {
1222
        return $this->getCurrentMapField()->getSectorString();
1223
    }
1224
1225
    #[Override]
1226
    public function getBuildplan(): ?ShipBuildplanInterface
1227
    {
1228
        return $this->buildplan;
1229
    }
1230
1231
    #[Override]
1232
    public function setBuildplan(?ShipBuildplanInterface $shipBuildplan): ShipInterface
1233
    {
1234
        $this->buildplan = $shipBuildplan;
1235
        return $this;
1236
    }
1237
1238
    #[Override]
1239
    public function getSystems(): Collection
1240
    {
1241
        return $this->systems;
1242
    }
1243
1244
    #[Override]
1245
    public function hasShipSystem(ShipSystemTypeEnum $type): bool
1246
    {
1247
        return $this->getSystems()->containsKey($type->value);
1248
    }
1249
1250
    #[Override]
1251
    public function getShipSystem(ShipSystemTypeEnum $type): ShipSystemInterface
1252
    {
1253
        $system = $this->getSystems()->get($type->value);
1254
        if ($system === null) {
1255
            throw new RuntimeException(sprintf('system type %d does not exist on ship', $type->value));
1256
        }
1257
1258
        return $system;
1259
    }
1260
1261
    #[Override]
1262
    public function getHealthySystems(): array
1263
    {
1264
        $healthySystems = [];
1265
        foreach ($this->getSystems() as $system) {
1266
            if ($system->getStatus() > 0) {
1267
                $healthySystems[] = $system;
1268
            }
1269
        }
1270
        return $healthySystems;
1271
    }
1272
1273
    #[Override]
1274
    public function displayNbsActions(): bool
1275
    {
1276
        return !$this->getCloakState()
1277
            && !$this->isWarped();
1278
    }
1279
1280
    #[Override]
1281
    public function isTractorbeamPossible(): bool
1282
    {
1283
        return TractorBeamShipSystem::isTractorBeamPossible($this);
1284
    }
1285
1286
    #[Override]
1287
    public function isBoardingPossible(): bool
1288
    {
1289
        return FightLib::isBoardingPossible($this);
1290
    }
1291
1292
    #[Override]
1293
    public function isInterceptable(): bool
1294
    {
1295
        //TODO can tractored ships be intercepted?!
1296
        return $this->getWarpDriveState();
1297
    }
1298
1299
    #[Override]
1300
    public function dockedOnTradePost(): bool
1301
    {
1302
        return $this->getDockedTo() && $this->getDockedTo()->getTradePost() !== null;
1303
    }
1304
1305
    #[Override]
1306
    public function getDockPrivileges(): Collection
1307
    {
1308
        return $this->dockingPrivileges;
1309
    }
1310
1311
    #[Override]
1312
    public function getDockingSlotCount(): int
1313
    {
1314
        return ($this->getState() === ShipStateEnum::SHIP_STATE_UNDER_CONSTRUCTION)
1315
            || ($this->getState() === ShipStateEnum::SHIP_STATE_UNDER_SCRAPPING)
1316
            ? 50 : $this->getRump()->getDockingSlots();
1317
    }
1318
1319
    #[Override]
1320
    public function hasFreeDockingSlots(): bool
1321
    {
1322
        return $this->getDockingSlotCount() > $this->getDockedShipCount();
1323
    }
1324
1325
    #[Override]
1326
    public function getFreeDockingSlotCount(): int
1327
    {
1328
        return $this->getDockingSlotCount() - $this->getDockedShipCount();
1329
    }
1330
1331
    #[Override]
1332
    public function getDockedShipCount(): int
1333
    {
1334
        return $this->dockedShips->count();
1335
    }
1336
1337
    #[Override]
1338
    public function getTractoredShip(): ?ShipInterface
1339
    {
1340
        return $this->tractoredShip;
1341
    }
1342
1343
    #[Override]
1344
    public function setTractoredShip(?ShipInterface $ship): ShipInterface
1345
    {
1346
        $this->tractoredShip = $ship;
1347
        return $this;
1348
    }
1349
1350
    #[Override]
1351
    public function setTractoredShipId(?int $shipId): ShipInterface
1352
    {
1353
        $this->tractored_ship_id = $shipId;
1354
        return $this;
1355
    }
1356
1357
    #[Override]
1358
    public function getTractoringShip(): ?ShipInterface
1359
    {
1360
        return $this->tractoringShip;
1361
    }
1362
1363
    #[Override]
1364
    public function setTractoringShip(?ShipInterface $ship): ShipInterface
1365
    {
1366
        $this->tractoringShip = $ship;
1367
        return $this;
1368
    }
1369
1370
    #[Override]
1371
    public function getHoldingWeb(): ?TholianWebInterface
1372
    {
1373
        return $this->holdingWeb;
1374
    }
1375
1376
    #[Override]
1377
    public function setHoldingWeb(?TholianWebInterface $web): ShipInterface
1378
    {
1379
        $this->holdingWeb = $web;
1380
1381
        if ($web === null) {
1382
            $this->holding_web_id = null;
1383
        }
1384
1385
        return $this;
1386
    }
1387
1388
    #[Override]
1389
    public function getHoldingWebBackgroundStyle(): string
1390
    {
1391
        if ($this->getHoldingWeb() === null) {
1392
            return '';
1393
        }
1394
1395
        if ($this->getHoldingWeb()->isFinished()) {
1396
            $icon =  'web.png';
1397
        } else {
1398
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1399
1400
            $icon = $closeTofinish ? 'web_u.png' : 'web_u2.png';
1401
        }
1402
1403
        return sprintf('src="assets/buttons/%s"; class="indexedGraphics" style="z-index: 5;"', $icon);
1404
    }
1405
1406
    public function getHoldingWebImageStyle(): string
1407
    {
1408
        if ($this->getHoldingWeb() === null) {
1409
            return '';
1410
        }
1411
1412
        if ($this->getHoldingWeb()->isFinished()) {
1413
            $icon =  'webfill.png';
1414
        } else {
1415
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1416
1417
            $icon = $closeTofinish ? 'web_ufill.png' : 'web_ufill2.png';
1418
        }
1419
1420
        return $icon;
1421
    }
1422
1423
    #[Override]
1424
    public function getCurrentMapField(): StarSystemMapInterface|MapInterface
1425
    {
1426
        return $this->getStarsystemMap() ?? $this->getMap();
1427
    }
1428
1429
    private function getShieldRegenerationPercentage(): int
1430
    {
1431
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_SHIELDS) ? 10 : 0;
1432
    }
1433
1434
    #[Override]
1435
    public function getShieldRegenerationRate(): int
1436
    {
1437
        return (int) ceil(($this->getMaxShield() / 100) * $this->getShieldRegenerationPercentage());
1438
    }
1439
1440
    #[Override]
1441
    public function canIntercept(): bool
1442
    {
1443
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_WARPDRIVE)
1444
            && !$this->isTractored() && !$this->isTractoring();
1445
    }
1446
1447
    #[Override]
1448
    public function canMove(): bool
1449
    {
1450
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE)
1451
            || $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
1452
    }
1453
1454
    #[Override]
1455
    public function hasActiveWeapon(): bool
1456
    {
1457
        return $this->getPhaserState() || $this->getTorpedoState();
1458
    }
1459
1460
    #[Override]
1461
    public function hasEscapePods(): bool
1462
    {
1463
        return $this->getRump()->isEscapePods() && $this->getCrewCount() > 0;
1464
    }
1465
1466
    #[Override]
1467
    public function getRepairRate(): int
1468
    {
1469
        // @todo
1470
        return 100;
1471
    }
1472
1473
    #[Override]
1474
    public function getRump(): ShipRumpInterface
1475
    {
1476
        return $this->rump;
1477
    }
1478
1479
    #[Override]
1480
    public function getRumpId(): int
1481
    {
1482
        return $this->getRump()->getId();
1483
    }
1484
1485
    #[Override]
1486
    public function getRumpName(): string
1487
    {
1488
        return $this->getRump()->getName();
1489
    }
1490
1491
    #[Override]
1492
    public function setRump(ShipRumpInterface $shipRump): ShipInterface
1493
    {
1494
        $this->rump = $shipRump;
1495
        return $this;
1496
    }
1497
1498
    #[Override]
1499
    public function hasPhaser(): bool
1500
    {
1501
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER);
1502
    }
1503
1504
    #[Override]
1505
    public function hasTorpedo(): bool
1506
    {
1507
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TORPEDO);
1508
    }
1509
1510
    #[Override]
1511
    public function hasCloak(): bool
1512
    {
1513
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_CLOAK);
1514
    }
1515
1516
    #[Override]
1517
    public function hasTachyonScanner(): bool
1518
    {
1519
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
1520
    }
1521
1522
    #[Override]
1523
    public function hasShuttleRamp(): bool
1524
    {
1525
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
1526
    }
1527
1528
    #[Override]
1529
    public function hasSubspaceScanner(): bool
1530
    {
1531
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
1532
    }
1533
1534
    #[Override]
1535
    public function hasAstroLaboratory(): bool
1536
    {
1537
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY);
1538
    }
1539
1540
    #[Override]
1541
    public function hasWarpdrive(): bool
1542
    {
1543
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
1544
    }
1545
1546
    #[Override]
1547
    public function hasReactor(): bool
1548
    {
1549
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPCORE) ||
1550
            $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_FUSION_REACTOR) ||
1551
            $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SINGULARITY_REACTOR);
1552
    }
1553
1554
    #[Override]
1555
    public function hasRPGModule(): bool
1556
    {
1557
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_RPG_MODULE);
1558
    }
1559
1560
    #[Override]
1561
    public function hasNbsLss(): bool
1562
    {
1563
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LSS);
1564
    }
1565
1566
    #[Override]
1567
    public function hasUplink(): bool
1568
    {
1569
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK);
1570
    }
1571
1572
    #[Override]
1573
    public function hasTranswarp(): bool
1574
    {
1575
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL);
1576
    }
1577
1578
    #[Override]
1579
    public function getTranswarpCooldown(): ?int
1580
    {
1581
        $cooldown = $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL)->getCooldown();
1582
1583
        return $cooldown > time() ? $cooldown : null;
1584
    }
1585
1586
    #[Override]
1587
    public function getMaxTorpedos(): int
1588
    {
1589
        return $this->getRump()->getBaseTorpedoStorage()
1590
            + ($this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE)
1591
                ? TorpedoStorageShipSystem::TORPEDO_CAPACITY : 0);
1592
    }
1593
1594
    #[Override]
1595
    public function getDockedShips(): Collection
1596
    {
1597
        return $this->dockedShips;
1598
    }
1599
1600
    #[Override]
1601
    public function getDockedTo(): ?ShipInterface
1602
    {
1603
        return $this->dockedTo;
1604
    }
1605
1606
    #[Override]
1607
    public function setDockedTo(?ShipInterface $dockedTo): ShipInterface
1608
    {
1609
        $this->dockedTo = $dockedTo;
1610
        return $this;
1611
    }
1612
1613
    #[Override]
1614
    public function setDockedToId(?int $dockedToId): ShipInterface
1615
    {
1616
        $this->dock = $dockedToId;
1617
        return $this;
1618
    }
1619
1620
    #[Override]
1621
    public function hasFreeShuttleSpace(?LoggerUtilInterface $loggerUtil = null): bool
1622
    {
1623
        if ($loggerUtil !== null) {
1624
            $loggerUtil->log(sprintf('rumpShuttleSlots: %d', $this->getRump()->getShuttleSlots()));
1625
            $loggerUtil->log(sprintf('storedShuttleCount: %d', $this->getStoredShuttleCount()));
1626
        }
1627
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP)
1628
            && $this->getRump()->getShuttleSlots() - $this->getStoredShuttleCount() > 0;
1629
    }
1630
1631
    #[Override]
1632
    public function getStoredShuttles(): array
1633
    {
1634
        $shuttles = [];
1635
1636
        foreach ($this->getStorage() as $stor) {
1637
            if ($stor->getCommodity()->isShuttle()) {
1638
                $shuttles[] = $stor->getCommodity();
1639
            }
1640
        }
1641
1642
        return $shuttles;
1643
    }
1644
1645
    #[Override]
1646
    public function getStoredShuttleCount(): int
1647
    {
1648
        $count = 0;
1649
1650
        foreach ($this->getStorage() as $stor) {
1651
            if ($stor->getCommodity()->isShuttle()) {
1652
                $count += $stor->getAmount();
1653
            }
1654
        }
1655
1656
        return $count;
1657
    }
1658
1659
    /**
1660
     * @return CommodityInterface[]
1661
     */
1662
    #[Override]
1663
    public function getStoredBuoy(): array
1664
    {
1665
        $buoy = [];
1666
1667
        foreach ($this->getStorage() as $stor) {
1668
            if ($stor->getCommodity()->isBouy()) {
1669
                $buoy[] = $stor->getCommodity();
1670
            }
1671
        }
1672
1673
        return $buoy;
1674
    }
1675
1676
1677
    #[Override]
1678
    public function hasStoredBuoy(): bool
1679
    {
1680
        return $this->getStoredBuoy() !== [];
1681
    }
1682
1683
1684
    #[Override]
1685
    public function getDockedWorkbeeCount(): int
1686
    {
1687
        $count = 0;
1688
1689
        foreach ($this->getDockedShips() as $ships) {
1690
            if ($ships->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_SHUTTLE) {
1691
                $count += 1;
1692
            }
1693
        }
1694
1695
        return $count;
1696
    }
1697
1698
    #[Override]
1699
    public function canMan(): bool
1700
    {
1701
        $buildplan = $this->getBuildplan();
1702
1703
        return $buildplan !== null
1704
            && $buildplan->getCrew() > 0
1705
            && $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT);
1706
    }
1707
1708
    #[Override]
1709
    public function canBuildConstruction(): bool
1710
    {
1711
        return StationUtility::canShipBuildConstruction($this);
1712
    }
1713
1714
    #[Override]
1715
    public function hasCrewmanOfUser(int $userId): bool
1716
    {
1717
        foreach ($this->getCrewAssignments() as $shipCrew) {
1718
            if ($shipCrew->getCrew()->getUser()->getId() === $userId) {
1719
                return true;
1720
            }
1721
        }
1722
1723
        return false;
1724
    }
1725
1726
    #[Override]
1727
    public function __toString(): string
1728
    {
1729
        if ($this->id !== null) {
1730
            return sprintf('id: %d, name: %s', $this->getId(), $this->getName());
1731
        }
1732
1733
        return $this->getName();
1734
    }
1735
1736
    #[Override]
1737
    public function getHullColorStyle(): string
1738
    {
1739
        return $this->getColorStyle($this->getHull(), $this->getMaxHull());
1740
    }
1741
1742
    private function getColorStyle(int $actual, int $max): string
1743
    {
1744
        // full
1745
        if ($actual === $max) {
1746
            return '';
1747
        }
1748
1749
        // less than 100% - green
1750
        if ($actual / $max > 0.75) {
1751
            return 'color: #19c100;';
1752
        }
1753
1754
        // less than 75% - yellow
1755
        if ($actual / $max > 0.50) {
1756
            return 'color: #f4e932;';
1757
        }
1758
1759
        // less than 50% - orange
1760
        if ($actual / $max > 0.25) {
1761
            return 'color: #f48b28;';
1762
        }
1763
1764
        // less than 25% - red
1765
        return 'color: #ff3c3c;';
1766
    }
1767
}
1768