Passed
Push — master ( 77a570...adeb98 )
by Nico
26:43
created

Ship::isUnderRetrofit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Orm\Entity;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Doctrine\ORM\Mapping\Column;
10
use Doctrine\ORM\Mapping\Entity;
11
use Doctrine\ORM\Mapping\GeneratedValue;
12
use Doctrine\ORM\Mapping\Id;
13
use Doctrine\ORM\Mapping\Index;
14
use Doctrine\ORM\Mapping\JoinColumn;
15
use Doctrine\ORM\Mapping\ManyToOne;
16
use Doctrine\ORM\Mapping\OneToMany;
17
use Doctrine\ORM\Mapping\OneToOne;
18
use Doctrine\ORM\Mapping\OrderBy;
19
use Doctrine\ORM\Mapping\Table;
20
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use RuntimeException;
22
use Stu\Component\Game\TimeConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Game\TimeConstants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Stu\Component\Ship\ShipAlertStateEnum;
24
use Stu\Component\Ship\ShipLSSModeEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\ShipLSSModeEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use Stu\Component\Ship\ShipModuleTypeEnum;
26
use Stu\Component\Ship\ShipRumpEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\ShipRumpEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use Stu\Component\Ship\ShipStateEnum;
28
use Stu\Component\Ship\SpacecraftTypeEnum;
29
use Stu\Component\Ship\System\ShipSystemModeEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\System\ShipSystemModeEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use Stu\Component\Ship\System\ShipSystemTypeEnum;
31
use Stu\Component\Ship\System\Type\TorpedoStorageShipSystem;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\Syste...orpedoStorageShipSystem was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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

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