Passed
Pull Request — master (#1837)
by Nico
24:51
created

Ship::isUnderRepair()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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

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

filter:
    dependency_paths: ["lib/*"]

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

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

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
23
use Stu\Component\Map\MapEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Map\MapEnum 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...
24
use Stu\Component\Ship\ShipAlertStateEnum;
25
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...
26
use Stu\Component\Ship\ShipModuleTypeEnum;
27
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...
28
use Stu\Component\Ship\ShipStateEnum;
29
use Stu\Component\Ship\SpacecraftTypeEnum;
30
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...
31
use Stu\Component\Ship\System\ShipSystemTypeEnum;
32
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...
33
use Stu\Component\Ship\System\Type\TractorBeamShipSystem;
34
use Stu\Component\Station\StationUtility;
35
use Stu\Lib\Map\Location;
36
use Stu\Module\Control\GameControllerInterface;
37
use Stu\Module\Logging\LoggerUtilInterface;
38
use Stu\Module\Ship\Lib\Battle\FightLib;
39
use Stu\Orm\Repository\ShipRepository;
40
41
#[Table(name: 'stu_ships')]
42
#[Index(name: 'ship_fleet_idx', columns: ['fleets_id'])]
43
#[Index(name: 'ship_map_idx', columns: ['map_id'])]
44
#[Index(name: 'ship_starsystem_map_idx', columns: ['starsystem_map_id'])]
45
#[Index(name: 'ship_rump_idx', columns: ['rumps_id'])]
46
#[Index(name: 'ship_web_idx', columns: ['holding_web_id'])]
47
#[Index(name: 'ship_user_idx', columns: ['user_id'])]
48
#[Index(name: 'ship_tractored_idx', columns: ['tractored_ship_id'])]
49
#[Index(name: 'ship_influence_area_idx', columns: ['influence_area_id'])]
50
#[Entity(repositoryClass: ShipRepository::class)]
51
class Ship implements ShipInterface
52
{
53
    #[Id]
54
    #[Column(type: 'integer')]
55
    #[GeneratedValue(strategy: 'IDENTITY')]
56
    private ?int $id = null;
57
58
    #[Column(type: 'integer')]
59
    private int $user_id = 0;
60
61
    #[Column(type: 'integer')]
62
    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...
63
64
    #[Column(type: 'integer', nullable: true)]
65
    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...
66
67
    #[Column(type: 'integer', nullable: true)]
68
    private ?int $fleets_id = null;
69
70
    #[Column(type: 'smallint', length: 1)]
71
    private int $direction = 0;
72
73
    #[Column(type: 'string')]
74
    private string $name = '';
75
76
    #[Column(type: 'smallint', length: 1, enumType: ShipAlertStateEnum::class)]
77
    private ShipAlertStateEnum $alvl = ShipAlertStateEnum::ALERT_GREEN;
78
79
    #[Column(type: 'smallint', length: 1)]
80
    private int $lss_mode = ShipLSSModeEnum::LSS_NORMAL;
81
82
    #[Column(type: 'integer', length: 6)]
83
    private int $huelle = 0;
84
85
    #[Column(type: 'integer', length: 6)]
86
    private int $max_huelle = 0;
87
88
    #[Column(type: 'integer', length: 6)]
89
    private int $schilde = 0;
90
91
    #[Column(type: 'integer', length: 6)]
92
    private int $max_schilde = 0;
93
94
    #[Column(type: 'integer', nullable: true)]
95
    private ?int $tractored_ship_id = null;
96
97
    #[Column(type: 'integer', nullable: true)]
98
    private ?int $holding_web_id = null;
99
100
    #[Column(type: 'integer', nullable: true)]
101
    private ?int $dock = null;
102
103
    #[Column(type: 'integer')]
104
    private int $former_rumps_id = 0;
105
106
    #[Column(type: 'smallint', length: 1, enumType: SpacecraftTypeEnum::class)]
107
    private SpacecraftTypeEnum $type = SpacecraftTypeEnum::SPACECRAFT_TYPE_SHIP;
108
109
    #[Column(type: 'integer')]
110
    private int $database_id = 0;
111
112
    #[Column(type: 'boolean')]
113
    private bool $is_destroyed = false;
114
115
    #[Column(type: 'boolean')]
116
    private bool $disabled = false;
117
118
    #[Column(type: 'smallint', length: 3)]
119
    private int $hit_chance = 0;
120
121
    #[Column(type: 'smallint', length: 3)]
122
    private int $evade_chance = 0;
123
124
    #[Column(type: 'smallint', length: 4)]
125
    private int $base_damage = 0;
126
127
    #[Column(type: 'smallint', length: 3)]
128
    private int $sensor_range = 0;
129
130
    #[Column(type: 'integer')]
131
    private int $shield_regeneration_timer = 0;
132
133
    #[Column(type: 'smallint', enumType: ShipStateEnum::class)]
134
    private ShipStateEnum $state = ShipStateEnum::SHIP_STATE_NONE;
135
136
    #[Column(type: 'boolean')]
137
    private bool $is_fleet_leader = false;
138
139
    #[Column(type: 'integer', nullable: true)]
140
    private ?int $map_id = null;
0 ignored issues
show
introduced by
The private property $map_id is not used, and could be removed.
Loading history...
141
142
    #[Column(type: 'integer', nullable: true)]
143
    private ?int $starsystem_map_id = null;
0 ignored issues
show
introduced by
The private property $starsystem_map_id is not used, and could be removed.
Loading history...
144
145
    #[Column(type: 'integer', nullable: true)]
146
    private ?int $influence_area_id = null;
0 ignored issues
show
introduced by
The private property $influence_area_id is not used, and could be removed.
Loading history...
147
148
    #[Column(type: 'boolean')]
149
    private bool $in_emergency = false;
150
151
    #[ManyToOne(targetEntity: 'Fleet', inversedBy: 'ships')]
152
    #[JoinColumn(name: 'fleets_id', referencedColumnName: 'id')]
153
    private ?FleetInterface $fleet = null;
154
155
    #[OneToOne(targetEntity: 'TradePost', mappedBy: 'ship')]
156
    private ?TradePostInterface $tradePost = null;
157
158
    #[ManyToOne(targetEntity: 'Ship', inversedBy: 'dockedShips')]
159
    #[JoinColumn(name: 'dock', referencedColumnName: 'id')]
160
    private ?ShipInterface $dockedTo = null;
161
162
    /**
163
     * @var ArrayCollection<int, ShipInterface>
164
     */
165
    #[OneToMany(targetEntity: 'Ship', mappedBy: 'dockedTo', indexBy: 'id')]
166
    #[OrderBy(['fleets_id' => 'DESC', 'is_fleet_leader' => 'DESC'])]
167
    private Collection $dockedShips;
168
169
    /**
170
     * @var ArrayCollection<int, DockingPrivilegeInterface>
171
     */
172
    #[OneToMany(targetEntity: 'DockingPrivilege', mappedBy: 'ship')]
173
    private Collection $dockingPrivileges;
174
175
    #[OneToOne(targetEntity: 'Ship')]
176
    #[JoinColumn(name: 'tractored_ship_id', referencedColumnName: 'id')]
177
    private ?ShipInterface $tractoredShip = null;
178
179
    #[OneToOne(targetEntity: 'Ship', mappedBy: 'tractoredShip')]
180
    private ?ShipInterface $tractoringShip = null;
181
182
    #[ManyToOne(targetEntity: 'TholianWeb')]
183
    #[JoinColumn(name: 'holding_web_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
184
    private ?TholianWebInterface $holdingWeb = null;
185
186
    #[ManyToOne(targetEntity: 'User')]
187
    #[JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
188
    private UserInterface $user;
189
190
    /**
191
     * @var ArrayCollection<int, ShipCrewInterface>
192
     */
193
    #[OneToMany(targetEntity: 'ShipCrew', mappedBy: 'ship', indexBy: 'id')]
194
    #[OrderBy(['id' => 'ASC'])]
195
    private Collection $crew;
196
197
    #[OneToOne(targetEntity: 'TorpedoStorage', mappedBy: 'ship')]
198
    private ?TorpedoStorageInterface $torpedoStorage = null;
199
200
    /**
201
     * @var ArrayCollection<int, ShipSystemInterface>
202
     */
203
    #[OneToMany(targetEntity: 'ShipSystem', mappedBy: 'ship', indexBy: 'system_type')]
204
    #[OrderBy(['system_type' => 'ASC'])]
205
    private Collection $systems;
206
207
    #[ManyToOne(targetEntity: 'ShipRump')]
208
    #[JoinColumn(name: 'rumps_id', referencedColumnName: 'id')]
209
    private ShipRumpInterface $rump;
210
211
    #[ManyToOne(targetEntity: 'ShipBuildplan')]
212
    #[JoinColumn(name: 'plans_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
213
    private ?ShipBuildplanInterface $buildplan = null;
214
215
    /**
216
     * @var ArrayCollection<int, StorageInterface>
217
     */
218
    #[OneToMany(targetEntity: 'Storage', mappedBy: 'ship', indexBy: 'commodity_id')]
219
    #[OrderBy(['commodity_id' => 'ASC'])]
220
    private Collection $storage;
221
222
    #[ManyToOne(targetEntity: 'Map')]
223
    #[JoinColumn(name: 'map_id', referencedColumnName: 'id')]
224
    private ?MapInterface $map = null;
225
226
    #[ManyToOne(targetEntity: 'StarSystemMap')]
227
    #[JoinColumn(name: 'starsystem_map_id', referencedColumnName: 'id')]
228
    private ?StarSystemMapInterface $starsystem_map = null;
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 setDatabaseId(int $databaseEntryId): ShipInterface
642
    {
643
        $this->database_id = $databaseEntryId;
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
        $field = $this->getCurrentMapField();
842
843
        if ($field instanceof MapInterface) {
844
            return $field->getCx();
845
        }
846
847
        return $field->getSx();
848
    }
849
850
    #[Override]
851
    public function getPosY(): int
852
    {
853
        $field = $this->getCurrentMapField();
854
855
        if ($field instanceof MapInterface) {
856
            return $field->getCy();
857
        }
858
859
        return $field->getSy();
860
    }
861
862
    #[Override]
863
    public function getCrewCount(): int
864
    {
865
        return $this->getCrewAssignments()->count();
866
    }
867
868
    #[Override]
869
    public function getNeededCrewCount(): int
870
    {
871
        $buildplan = $this->getBuildplan();
872
        if ($buildplan === null) {
873
            return 0;
874
        }
875
876
        return $buildplan->getCrew();
877
    }
878
879
    #[Override]
880
    public function getExcessCrewCount(): int
881
    {
882
        return $this->getCrewCount() - $this->getNeededCrewCount();
883
    }
884
885
    #[Override]
886
    public function hasEnoughCrew(?GameControllerInterface $game = null): bool
887
    {
888
        $buildplan = $this->getBuildplan();
889
890
        if ($buildplan === null) {
891
            if ($game !== null) {
892
                $game->addInformation(_("Keine Crew vorhanden"));
893
            }
894
            return false;
895
        }
896
897
        $result = $buildplan->getCrew() <= 0
898
            || $this->getCrewCount() >= $buildplan->getCrew();
899
900
        if (!$result && $game !== null) {
901
            $game->addInformationf(
902
                _("Es werden %d Crewmitglieder benötigt"),
903
                $buildplan->getCrew()
904
            );
905
        }
906
907
        return $result;
908
    }
909
910
    #[Override]
911
    public function getFleet(): ?FleetInterface
912
    {
913
        return $this->fleet;
914
    }
915
916
    #[Override]
917
    public function setFleet(?FleetInterface $fleet): ShipInterface
918
    {
919
        $this->fleet = $fleet;
920
        return $this;
921
    }
922
923
    #[Override]
924
    public function isFleetLeader(): bool
925
    {
926
        return $this->getIsFleetLeader();
927
    }
928
929
    #[Override]
930
    public function getUser(): UserInterface
931
    {
932
        return $this->user;
933
    }
934
935
    #[Override]
936
    public function setUser(UserInterface $user): ShipInterface
937
    {
938
        $this->user = $user;
939
        return $this;
940
    }
941
942
    #[Override]
943
    public function getSystem(): ?StarSystemInterface
944
    {
945
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getSystem() : null;
946
    }
947
948
    #[Override]
949
    public function getModules(): array
950
    {
951
        $modules = [];
952
953
        $buildplan = $this->getBuildplan();
954
        if ($buildplan === null) {
955
            return $modules;
956
        }
957
958
        foreach ($buildplan->getModules() as $obj) {
959
            $module = $obj->getModule();
960
            $index = $module->getType() === ShipModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
961
            $modules[$index] = $module;
962
        }
963
964
        if ($this->isBase()) {
965
            foreach ($this->getSystems() as $system) {
966
                $module = $system->getModule();
967
968
                if ($module !== null) {
969
                    $index = $module->getType() === ShipModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
970
                    $modules[$index] = $module;
971
                }
972
            }
973
        }
974
975
        return $modules;
976
    }
977
978
    #[Override]
979
    public function isDeflectorHealthy(): bool
980
    {
981
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_DEFLECTOR);
982
    }
983
984
    #[Override]
985
    public function isTroopQuartersHealthy(): bool
986
    {
987
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS);
988
    }
989
990
    #[Override]
991
    public function isMatrixScannerHealthy(): bool
992
    {
993
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_MATRIX_SCANNER);
994
    }
995
996
    #[Override]
997
    public function isTorpedoStorageHealthy(): bool
998
    {
999
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE);
1000
    }
1001
1002
    #[Override]
1003
    public function isShuttleRampHealthy(): bool
1004
    {
1005
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
1006
    }
1007
1008
    #[Override]
1009
    public function isWebEmitterHealthy(): bool
1010
    {
1011
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_THOLIAN_WEB);
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 isOverWormhole(): bool
1050
    {
1051
        return $this->getMap() !== null && $this->getMap()->getRandomWormholeEntry() !== null;
1052
    }
1053
1054
    #[Override]
1055
    public function isWarpPossible(): bool
1056
    {
1057
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE) && $this->getSystem() === null;
1058
    }
1059
1060
    #[Override]
1061
    public function getTorpedo(): ?TorpedoTypeInterface
1062
    {
1063
        if ($this->getTorpedoStorage() === null) {
1064
            return null;
1065
        }
1066
1067
        return $this->getTorpedoStorage()->getTorpedo();
1068
    }
1069
1070
    #[Override]
1071
    public function getTorpedoStorage(): ?TorpedoStorageInterface
1072
    {
1073
        return $this->torpedoStorage;
1074
    }
1075
1076
    #[Override]
1077
    public function setTorpedoStorage(?TorpedoStorageInterface $torpedoStorage): ShipInterface
1078
    {
1079
        $this->torpedoStorage = $torpedoStorage;
1080
        return $this;
1081
    }
1082
1083
    #[Override]
1084
    public function getStorage(): Collection
1085
    {
1086
        return $this->storage;
1087
    }
1088
1089
    #[Override]
1090
    public function getLogbook(): Collection
1091
    {
1092
        return $this->logbook;
1093
    }
1094
1095
    #[Override]
1096
    public function getTakeoverActive(): ?ShipTakeoverInterface
1097
    {
1098
        return $this->takeoverActive;
1099
    }
1100
1101
    #[Override]
1102
    public function setTakeoverActive(?ShipTakeoverInterface $takeover): ShipInterface
1103
    {
1104
        $this->takeoverActive = $takeover;
1105
1106
        return $this;
1107
    }
1108
1109
    #[Override]
1110
    public function getTakeoverPassive(): ?ShipTakeoverInterface
1111
    {
1112
        return $this->takeoverPassive;
1113
    }
1114
1115
    #[Override]
1116
    public function setTakeoverPassive(?ShipTakeoverInterface $takeover): ShipInterface
1117
    {
1118
        $this->takeoverPassive = $takeover;
1119
1120
        return $this;
1121
    }
1122
1123
    #[Override]
1124
    public function getStorageSum(): int
1125
    {
1126
        return array_reduce(
1127
            $this->getStorage()->getValues(),
1128
            fn (int $sum, StorageInterface $storage): int => $sum + $storage->getAmount(),
1129
            0
1130
        );
1131
    }
1132
1133
    #[Override]
1134
    public function getMaxStorage(): int
1135
    {
1136
        return $this->getRump()->getStorage();
1137
    }
1138
1139
    #[Override]
1140
    public function getBeamableStorage(): array
1141
    {
1142
        return array_filter(
1143
            $this->getStorage()->getValues(),
1144
            fn (StorageInterface $storage): bool => $storage->getCommodity()->isBeamable() === true
1145
        );
1146
    }
1147
1148
    #[Override]
1149
    public function getTradePost(): ?TradePostInterface
1150
    {
1151
        return $this->tradePost;
1152
    }
1153
1154
    #[Override]
1155
    public function setTradePost(?TradePostInterface $tradePost): ShipInterface
1156
    {
1157
        $this->tradePost = $tradePost;
1158
1159
        return $this;
1160
    }
1161
1162 3
    #[Override]
1163
    public function getMap(): ?MapInterface
1164
    {
1165 3
        return $this->map;
1166
    }
1167
1168
    #[Override]
1169
    public function getMapRegion(): ?MapRegionInterface
1170
    {
1171
        $systemMap = $this->getStarsystemMap();
1172
        if ($systemMap !== null) {
1173
            return null;
1174
        }
1175
1176
        $map = $this->getMap();
1177
        if ($map === null) {
1178
            return null;
1179
        }
1180
1181
        return $map->getMapRegion();
1182
    }
1183
1184 3
    #[Override]
1185
    public function setLocation(MapInterface|StarSystemMapInterface|Location $location): ShipInterface
1186
    {
1187 3
        if ($location instanceof MapInterface) {
1188 2
            $this->setMap($location);
1189 2
            $this->setStarsystemMap(null);
1190 2
        } elseif ($location instanceof StarSystemMapInterface) {
1191 2
            $this->setMap($location->getSystem()->getMap());
1192 2
            $this->setStarsystemMap($location);
1193
        } else {
1194
            $this->setLocation($location->get());
1195
        }
1196
1197 3
        return $this;
1198
    }
1199
1200 3
    private function setMap(?MapInterface $map): ShipInterface
1201
    {
1202 3
        $this->map = $map;
1203
1204 3
        return $this;
1205
    }
1206
1207 3
    #[Override]
1208
    public function getStarsystemMap(): ?StarSystemMapInterface
1209
    {
1210 3
        return $this->starsystem_map;
1211
    }
1212
1213 3
    private function setStarsystemMap(?StarSystemMapInterface $systemMap): ShipInterface
1214
    {
1215 3
        $this->starsystem_map = $systemMap;
1216
1217 3
        return $this;
1218
    }
1219
1220
    #[Override]
1221
    public function getLocation(): Location
1222
    {
1223
        return new Location($this->getMap(), $this->getStarsystemMap());
1224
    }
1225
1226
    #[Override]
1227
    public function getInfluenceArea(): ?StarSystemInterface
1228
    {
1229
        return $this->influenceArea;
1230
    }
1231
1232
    #[Override]
1233
    public function setInfluenceArea(?StarSystemInterface $influenceArea): ShipInterface
1234
    {
1235
        $this->influenceArea = $influenceArea;
1236
        return $this;
1237
    }
1238
1239
    #[Override]
1240
    public function getBeamFactor(): int
1241
    {
1242
        return $this->getRump()->getBeamFactor();
1243
    }
1244
1245
    #[Override]
1246
    public function getSectorString(): string
1247
    {
1248
        return $this->getCurrentMapField()->getSectorString();
1249
    }
1250
1251
    #[Override]
1252
    public function getSectorId(): ?int
1253
    {
1254
        $layer = $this->getLayer();
1255
        if ($layer === null) {
1256
            return null;
1257
        }
1258
1259
        $location = $this->getLocation();
1260
1261
        $cx = $location->getCx();
1262
        $cy = $location->getCy();
1263
        if ($cx === null || $cy === null) {
1264
            return null;
1265
        }
1266
1267
        return $layer->getSectorId($this->getMapCX($cx), $this->getMapCY($cy));
1268
    }
1269
1270
1271
    private function getMapCX(int $cx): int
1272
    {
1273
        return (int) ceil($cx / MapEnum::FIELDS_PER_SECTION);
1274
    }
1275
1276
    private function getMapCY(int $cy): int
1277
    {
1278
        return (int) ceil($cy / MapEnum::FIELDS_PER_SECTION);
1279
    }
1280
1281
    #[Override]
1282
    public function getBuildplan(): ?ShipBuildplanInterface
1283
    {
1284
        return $this->buildplan;
1285
    }
1286
1287
    #[Override]
1288
    public function setBuildplan(?ShipBuildplanInterface $shipBuildplan): ShipInterface
1289
    {
1290
        $this->buildplan = $shipBuildplan;
1291
        return $this;
1292
    }
1293
1294
    #[Override]
1295
    public function getSystems(): Collection
1296
    {
1297
        return $this->systems;
1298
    }
1299
1300
    #[Override]
1301
    public function hasShipSystem(ShipSystemTypeEnum $type): bool
1302
    {
1303
        return $this->getSystems()->containsKey($type->value);
1304
    }
1305
1306
    #[Override]
1307
    public function getShipSystem(ShipSystemTypeEnum $type): ShipSystemInterface
1308
    {
1309
        $system = $this->getSystems()->get($type->value);
1310
        if ($system === null) {
1311
            throw new RuntimeException(sprintf('system type %d does not exist on ship', $type->value));
1312
        }
1313
1314
        return $system;
1315
    }
1316
1317
    #[Override]
1318
    public function getHealthySystems(): array
1319
    {
1320
        $healthySystems = [];
1321
        foreach ($this->getSystems() as $system) {
1322
            if ($system->getStatus() > 0) {
1323
                $healthySystems[] = $system;
1324
            }
1325
        }
1326
        return $healthySystems;
1327
    }
1328
1329
    #[Override]
1330
    public function displayNbsActions(): bool
1331
    {
1332
        return !$this->getCloakState()
1333
            && !$this->isWarped();
1334
    }
1335
1336
    #[Override]
1337
    public function isTractorbeamPossible(): bool
1338
    {
1339
        return TractorBeamShipSystem::isTractorBeamPossible($this);
1340
    }
1341
1342
    #[Override]
1343
    public function isBoardingPossible(): bool
1344
    {
1345
        return FightLib::isBoardingPossible($this);
1346
    }
1347
1348
    #[Override]
1349
    public function isInterceptable(): bool
1350
    {
1351
        //TODO can tractored ships be intercepted?!
1352
        return $this->getWarpDriveState();
1353
    }
1354
1355
    #[Override]
1356
    public function dockedOnTradePost(): bool
1357
    {
1358
        return $this->getDockedTo() && $this->getDockedTo()->getTradePost() !== null;
1359
    }
1360
1361
    #[Override]
1362
    public function getDockPrivileges(): Collection
1363
    {
1364
        return $this->dockingPrivileges;
1365
    }
1366
1367
    #[Override]
1368
    public function getDockingSlotCount(): int
1369
    {
1370
        return ($this->getState() === ShipStateEnum::SHIP_STATE_UNDER_CONSTRUCTION)
1371
            || ($this->getState() === ShipStateEnum::SHIP_STATE_UNDER_SCRAPPING)
1372
            ? 50 : $this->getRump()->getDockingSlots();
1373
    }
1374
1375
    #[Override]
1376
    public function hasFreeDockingSlots(): bool
1377
    {
1378
        return $this->getDockingSlotCount() > $this->getDockedShipCount();
1379
    }
1380
1381
    #[Override]
1382
    public function getFreeDockingSlotCount(): int
1383
    {
1384
        return $this->getDockingSlotCount() - $this->getDockedShipCount();
1385
    }
1386
1387
    #[Override]
1388
    public function getDockedShipCount(): int
1389
    {
1390
        return $this->dockedShips->count();
1391
    }
1392
1393
    #[Override]
1394
    public function getTractoredShip(): ?ShipInterface
1395
    {
1396
        return $this->tractoredShip;
1397
    }
1398
1399
    #[Override]
1400
    public function setTractoredShip(?ShipInterface $ship): ShipInterface
1401
    {
1402
        $this->tractoredShip = $ship;
1403
        return $this;
1404
    }
1405
1406
    #[Override]
1407
    public function setTractoredShipId(?int $shipId): ShipInterface
1408
    {
1409
        $this->tractored_ship_id = $shipId;
1410
        return $this;
1411
    }
1412
1413
    #[Override]
1414
    public function getTractoringShip(): ?ShipInterface
1415
    {
1416
        return $this->tractoringShip;
1417
    }
1418
1419
    #[Override]
1420
    public function setTractoringShip(?ShipInterface $ship): ShipInterface
1421
    {
1422
        $this->tractoringShip = $ship;
1423
        return $this;
1424
    }
1425
1426
    #[Override]
1427
    public function getHoldingWeb(): ?TholianWebInterface
1428
    {
1429
        return $this->holdingWeb;
1430
    }
1431
1432
    #[Override]
1433
    public function setHoldingWeb(?TholianWebInterface $web): ShipInterface
1434
    {
1435
        $this->holdingWeb = $web;
1436
1437
        if ($web === null) {
1438
            $this->holding_web_id = null;
1439
        }
1440
1441
        return $this;
1442
    }
1443
1444
    #[Override]
1445
    public function getHoldingWebBackgroundStyle(): string
1446
    {
1447
        if ($this->getHoldingWeb() === null) {
1448
            return '';
1449
        }
1450
1451
        if ($this->getHoldingWeb()->isFinished()) {
1452
            $icon =  'web.png';
1453
        } else {
1454
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1455
1456
            $icon = $closeTofinish ? 'web_u.png' : 'web_u2.png';
1457
        }
1458
1459
        return sprintf('src="assets/buttons/%s"; class="indexedGraphics" style="z-index: 5;"', $icon);
1460
    }
1461
1462
    public function getHoldingWebImageStyle(): string
1463
    {
1464
        if ($this->getHoldingWeb() === null) {
1465
            return '';
1466
        }
1467
1468
        if ($this->getHoldingWeb()->isFinished()) {
1469
            $icon =  'webfill.png';
1470
        } else {
1471
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1472
1473
            $icon = $closeTofinish ? 'web_ufill.png' : 'web_ufill2.png';
1474
        }
1475
1476
        return $icon;
1477
    }
1478
1479
    #[Override]
1480
    public function getCurrentMapField(): StarSystemMapInterface|MapInterface
1481
    {
1482
        return $this->getStarsystemMap() ?? $this->getMap();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getStarsys...ap() ?? $this->getMap() could return the type null which is incompatible with the type-hinted return Stu\Orm\Entity\MapInterf...\StarSystemMapInterface. Consider adding an additional type-check to rule them out.
Loading history...
1483
    }
1484
1485
    private function getShieldRegenerationPercentage(): int
1486
    {
1487
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_SHIELDS) ? 10 : 0;
1488
    }
1489
1490
    #[Override]
1491
    public function getShieldRegenerationRate(): int
1492
    {
1493
        return (int) ceil(($this->getMaxShield() / 100) * $this->getShieldRegenerationPercentage());
1494
    }
1495
1496
    #[Override]
1497
    public function canIntercept(): bool
1498
    {
1499
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_WARPDRIVE)
1500
            && !$this->isTractored() && !$this->isTractoring();
1501
    }
1502
1503
    #[Override]
1504
    public function canMove(): bool
1505
    {
1506
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE)
1507
            || $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
1508
    }
1509
1510
    #[Override]
1511
    public function hasActiveWeapon(): bool
1512
    {
1513
        return $this->getPhaserState() || $this->getTorpedoState();
1514
    }
1515
1516
    #[Override]
1517
    public function hasEscapePods(): bool
1518
    {
1519
        return $this->getRump()->isEscapePods() && $this->getCrewCount() > 0;
1520
    }
1521
1522
    #[Override]
1523
    public function getRepairRate(): int
1524
    {
1525
        // @todo
1526
        return 100;
1527
    }
1528
1529
    #[Override]
1530
    public function getRump(): ShipRumpInterface
1531
    {
1532
        return $this->rump;
1533
    }
1534
1535
    #[Override]
1536
    public function getRumpId(): int
1537
    {
1538
        return $this->getRump()->getId();
1539
    }
1540
1541
    #[Override]
1542
    public function getRumpName(): string
1543
    {
1544
        return $this->getRump()->getName();
1545
    }
1546
1547
    #[Override]
1548
    public function setRump(ShipRumpInterface $shipRump): ShipInterface
1549
    {
1550
        $this->rump = $shipRump;
1551
        return $this;
1552
    }
1553
1554
    #[Override]
1555
    public function hasPhaser(): bool
1556
    {
1557
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER);
1558
    }
1559
1560
    #[Override]
1561
    public function hasTorpedo(): bool
1562
    {
1563
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TORPEDO);
1564
    }
1565
1566
    #[Override]
1567
    public function hasCloak(): bool
1568
    {
1569
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_CLOAK);
1570
    }
1571
1572
    #[Override]
1573
    public function hasTachyonScanner(): bool
1574
    {
1575
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
1576
    }
1577
1578
    #[Override]
1579
    public function hasShuttleRamp(): bool
1580
    {
1581
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
1582
    }
1583
1584
    #[Override]
1585
    public function hasSubspaceScanner(): bool
1586
    {
1587
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
1588
    }
1589
1590
    #[Override]
1591
    public function hasAstroLaboratory(): bool
1592
    {
1593
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY);
1594
    }
1595
1596
    #[Override]
1597
    public function hasWarpdrive(): bool
1598
    {
1599
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
1600
    }
1601
1602
    #[Override]
1603
    public function hasReactor(): bool
1604
    {
1605
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPCORE) ||
1606
            $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_FUSION_REACTOR) ||
1607
            $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SINGULARITY_REACTOR);
1608
    }
1609
1610
    #[Override]
1611
    public function hasRPGModule(): bool
1612
    {
1613
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_RPG_MODULE);
1614
    }
1615
1616
    #[Override]
1617
    public function hasNbsLss(): bool
1618
    {
1619
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LSS);
1620
    }
1621
1622
    #[Override]
1623
    public function hasUplink(): bool
1624
    {
1625
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK);
1626
    }
1627
1628
    #[Override]
1629
    public function hasTranswarp(): bool
1630
    {
1631
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL);
1632
    }
1633
1634
    #[Override]
1635
    public function getTranswarpCooldown(): ?int
1636
    {
1637
        $cooldown = $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL)->getCooldown();
1638
1639
        return $cooldown > time() ? $cooldown : null;
1640
    }
1641
1642
    #[Override]
1643
    public function getMaxTorpedos(): int
1644
    {
1645
        return $this->getRump()->getBaseTorpedoStorage()
1646
            + ($this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE)
1647
                ? TorpedoStorageShipSystem::TORPEDO_CAPACITY : 0);
1648
    }
1649
1650
    #[Override]
1651
    public function getDockedShips(): Collection
1652
    {
1653
        return $this->dockedShips;
1654
    }
1655
1656
    #[Override]
1657
    public function getDockedTo(): ?ShipInterface
1658
    {
1659
        return $this->dockedTo;
1660
    }
1661
1662
    #[Override]
1663
    public function setDockedTo(?ShipInterface $dockedTo): ShipInterface
1664
    {
1665
        $this->dockedTo = $dockedTo;
1666
        return $this;
1667
    }
1668
1669
    #[Override]
1670
    public function setDockedToId(?int $dockedToId): ShipInterface
1671
    {
1672
        $this->dock = $dockedToId;
1673
        return $this;
1674
    }
1675
1676
    #[Override]
1677
    public function hasFreeShuttleSpace(?LoggerUtilInterface $loggerUtil = null): bool
1678
    {
1679
        if ($loggerUtil !== null) {
1680
            $loggerUtil->log(sprintf('rumpShuttleSlots: %d', $this->getRump()->getShuttleSlots()));
1681
            $loggerUtil->log(sprintf('storedShuttleCount: %d', $this->getStoredShuttleCount()));
1682
        }
1683
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP)
1684
            && $this->getRump()->getShuttleSlots() - $this->getStoredShuttleCount() > 0;
1685
    }
1686
1687
    #[Override]
1688
    public function getStoredShuttles(): array
1689
    {
1690
        $shuttles = [];
1691
1692
        foreach ($this->getStorage() as $stor) {
1693
            if ($stor->getCommodity()->isShuttle()) {
1694
                $shuttles[] = $stor->getCommodity();
1695
            }
1696
        }
1697
1698
        return $shuttles;
1699
    }
1700
1701
    #[Override]
1702
    public function getStoredShuttleCount(): int
1703
    {
1704
        $count = 0;
1705
1706
        foreach ($this->getStorage() as $stor) {
1707
            if ($stor->getCommodity()->isShuttle()) {
1708
                $count += $stor->getAmount();
1709
            }
1710
        }
1711
1712
        return $count;
1713
    }
1714
1715
    /**
1716
     * @return CommodityInterface[]
1717
     */
1718
    #[Override]
1719
    public function getStoredBuoy(): array
1720
    {
1721
        $buoy = [];
1722
1723
        foreach ($this->getStorage() as $stor) {
1724
            if ($stor->getCommodity()->isBouy()) {
1725
                $buoy[] = $stor->getCommodity();
1726
            }
1727
        }
1728
1729
        return $buoy;
1730
    }
1731
1732
1733
    #[Override]
1734
    public function hasStoredBuoy(): bool
1735
    {
1736
        return $this->getStoredBuoy() !== [];
1737
    }
1738
1739
1740
    #[Override]
1741
    public function getDockedWorkbeeCount(): int
1742
    {
1743
        $count = 0;
1744
1745
        foreach ($this->getDockedShips() as $ships) {
1746
            if ($ships->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_SHUTTLE) {
1747
                $count += 1;
1748
            }
1749
        }
1750
1751
        return $count;
1752
    }
1753
1754
    #[Override]
1755
    public function canMan(): bool
1756
    {
1757
        $buildplan = $this->getBuildplan();
1758
1759
        return $buildplan !== null
1760
            && $buildplan->getCrew() > 0
1761
            && $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT);
1762
    }
1763
1764
    #[Override]
1765
    public function canBuildConstruction(): bool
1766
    {
1767
        return StationUtility::canShipBuildConstruction($this);
1768
    }
1769
1770
    #[Override]
1771
    public function hasCrewmanOfUser(int $userId): bool
1772
    {
1773
        foreach ($this->getCrewAssignments() as $shipCrew) {
1774
            if ($shipCrew->getCrew()->getUser()->getId() === $userId) {
1775
                return true;
1776
            }
1777
        }
1778
1779
        return false;
1780
    }
1781
1782
    #[Override]
1783
    public function __toString(): string
1784
    {
1785
        if ($this->id !== null) {
1786
            return sprintf('id: %d, name: %s', $this->getId(), $this->getName());
1787
        }
1788
1789
        return $this->getName();
1790
    }
1791
1792
    #[Override]
1793
    public function getHullColorStyle(): string
1794
    {
1795
        return $this->getColorStyle($this->getHull(), $this->getMaxHull());
1796
    }
1797
1798
    private function getColorStyle(int $actual, int $max): string
1799
    {
1800
        // full
1801
        if ($actual === $max) {
1802
            return '';
1803
        }
1804
1805
        // less than 100% - green
1806
        if ($actual / $max > 0.75) {
1807
            return 'color: #19c100;';
1808
        }
1809
1810
        // less than 75% - yellow
1811
        if ($actual / $max > 0.50) {
1812
            return 'color: #f4e932;';
1813
        }
1814
1815
        // less than 50% - orange
1816
        if ($actual / $max > 0.25) {
1817
            return 'color: #f48b28;';
1818
        }
1819
1820
        // less than 25% - red
1821
        return 'color: #ff3c3c;';
1822
    }
1823
}
1824