Passed
Pull Request — master (#1882)
by Janko
28:33
created

Ship::isOverSystem()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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

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