Passed
Push — master ( 92a2e9...9d73f4 )
by Nico
41:55
created

Ship::getMaxShield()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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

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