Passed
Push — dev ( 00bc98...ea1fa5 )
by Janko
14:47
created

Spacecraft::getStorage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
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\DiscriminatorColumn;
11
use Doctrine\ORM\Mapping\DiscriminatorMap;
12
use Doctrine\ORM\Mapping\Entity;
13
use Doctrine\ORM\Mapping\GeneratedValue;
14
use Doctrine\ORM\Mapping\Id;
15
use Doctrine\ORM\Mapping\InheritanceType;
16
use Doctrine\ORM\Mapping\JoinColumn;
17
use Doctrine\ORM\Mapping\ManyToOne;
18
use Doctrine\ORM\Mapping\OneToMany;
19
use Doctrine\ORM\Mapping\OneToOne;
20
use Doctrine\ORM\Mapping\OrderBy;
21
use Doctrine\ORM\Mapping\Table;
22
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...
23
use RuntimeException;
24
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...
25
use Stu\Component\Map\DirectionEnum;
26
use Stu\Component\Spacecraft\SpacecraftAlertStateEnum;
27
use Stu\Component\Spacecraft\SpacecraftModuleTypeEnum;
28
use Stu\Component\Spacecraft\SpacecraftRumpEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Spacecraft\SpacecraftRumpEnum 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...
29
use Stu\Component\Spacecraft\SpacecraftStateEnum;
30
use Stu\Component\Spacecraft\SpacecraftLssModeEnum;
31
use Stu\Component\Spacecraft\SpacecraftTypeEnum;
32
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
33
use Stu\Component\Spacecraft\System\Type\TorpedoStorageShipSystem;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Spacecraft...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...
34
use Stu\Component\Spacecraft\System\Type\TractorBeamShipSystem;
35
use Stu\Lib\Transfer\CommodityTransfer;
36
use Stu\Module\Control\GameControllerInterface;
37
use Stu\Module\Spacecraft\Lib\Battle\FightLib;
38
use Stu\Orm\Repository\SpacecraftRepository;
39
40
#[Table(name: 'stu_spacecraft')]
41
#[Entity(repositoryClass: SpacecraftRepository::class)]
42
#[InheritanceType('JOINED')]
43
#[DiscriminatorColumn(name: 'type', type: 'string')]
44
#[DiscriminatorMap([
45
    SpacecraftTypeEnum::SHIP->value => Ship::class,
46
    SpacecraftTypeEnum::STATION->value => Station::class,
47
    SpacecraftTypeEnum::THOLIAN_WEB->value => TholianWeb::class
48
])]
49
abstract class Spacecraft implements SpacecraftInterface
50
{
51
    #[Id]
52
    #[Column(type: 'integer')]
53
    #[GeneratedValue(strategy: 'IDENTITY')]
54
    private ?int $id = null;
55
56
    #[Column(type: 'integer')]
57
    private int $user_id = 0;
58
59
    #[Column(type: 'integer')]
60
    private int $rump_id = 0;
0 ignored issues
show
introduced by
The private property $rump_id is not used, and could be removed.
Loading history...
61
62
    #[Column(type: 'integer', nullable: true)]
63
    private ?int $plan_id = null;
0 ignored issues
show
introduced by
The private property $plan_id is not used, and could be removed.
Loading history...
64
65
    #[Column(type: 'smallint', length: 1, enumType: DirectionEnum::class, nullable: true)]
66
    private ?DirectionEnum $direction = null;
67
68
    #[Column(type: 'string')]
69
    private string $name = '';
70
71
    #[Column(type: 'smallint', length: 1, enumType: SpacecraftAlertStateEnum::class)]
72
    private SpacecraftAlertStateEnum $alvl = SpacecraftAlertStateEnum::ALERT_GREEN;
73
74
    #[Column(type: 'smallint', length: 1, enumType: SpacecraftLssModeEnum::class)]
75
    private SpacecraftLssModeEnum $lss_mode = SpacecraftLssModeEnum::NORMAL;
76
77
    #[Column(type: 'integer', length: 6)]
78
    private int $huelle = 0;
79
80
    #[Column(type: 'integer', length: 6)]
81
    private int $max_huelle = 0;
82
83
    #[Column(type: 'integer', length: 6)]
84
    private int $schilde = 0;
85
86
    #[Column(type: 'integer', length: 6)]
87
    private int $max_schilde = 0;
88
89
    #[Column(type: 'integer', nullable: true)]
90
    private ?int $tractored_ship_id = null;
0 ignored issues
show
introduced by
The private property $tractored_ship_id is not used, and could be removed.
Loading history...
91
92
    #[Column(type: 'integer', nullable: true)]
93
    private ?int $holding_web_id = null;
0 ignored issues
show
introduced by
The private property $holding_web_id is not used, and could be removed.
Loading history...
94
95
    #[Column(type: 'integer', nullable: true)]
96
    private ?int $database_id = null;
97
98
    private bool $is_destroyed = false;
99
100
    #[Column(type: 'boolean')]
101
    private bool $disabled = false;
102
103
    #[Column(type: 'smallint', length: 3)]
104
    private int $hit_chance = 0;
105
106
    #[Column(type: 'smallint', length: 3)]
107
    private int $evade_chance = 0;
108
109
    #[Column(type: 'smallint', length: 4)]
110
    private int $base_damage = 0;
111
112
    #[Column(type: 'smallint', enumType: SpacecraftStateEnum::class)]
113
    private SpacecraftStateEnum $state = SpacecraftStateEnum::NONE;
114
115
    #[Column(type: 'integer')]
116
    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...
117
118
    #[Column(type: 'boolean')]
119
    private bool $in_emergency = false;
120
121
    #[OneToOne(targetEntity: 'Ship')]
122
    #[JoinColumn(name: 'tractored_ship_id', referencedColumnName: 'id')]
123
    private ?ShipInterface $tractoredShip = null;
124
125
    #[ManyToOne(targetEntity: 'TholianWeb')]
126
    #[JoinColumn(name: 'holding_web_id', referencedColumnName: 'id')]
127
    private ?TholianWebInterface $holdingWeb = null;
128
129
    #[ManyToOne(targetEntity: 'User')]
130
    #[JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
131
    private UserInterface $user;
132
133
    /**
134
     * @var ArrayCollection<int, CrewAssignmentInterface>
135
     */
136
    #[OneToMany(targetEntity: 'CrewAssignment', mappedBy: 'spacecraft', indexBy: 'id')]
137
    #[OrderBy(['id' => 'ASC'])]
138
    private Collection $crew;
139
140
    #[OneToOne(targetEntity: 'TorpedoStorage', mappedBy: 'spacecraft')]
141
    private ?TorpedoStorageInterface $torpedoStorage = null;
142
143
    /**
144
     * @var ArrayCollection<int, SpacecraftSystemInterface>
145
     */
146
    #[OneToMany(targetEntity: 'SpacecraftSystem', mappedBy: 'spacecraft', indexBy: 'system_type')]
147
    #[OrderBy(['system_type' => 'ASC'])]
148
    private Collection $systems;
149
150
    #[ManyToOne(targetEntity: 'SpacecraftRump')]
151
    #[JoinColumn(name: 'rump_id', referencedColumnName: 'id')]
152
    private SpacecraftRumpInterface $rump;
153
154
    #[ManyToOne(targetEntity: 'SpacecraftBuildplan')]
155
    #[JoinColumn(name: 'plan_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
156
    private ?SpacecraftBuildplanInterface $buildplan = null;
157
158
    /**
159
     * @var ArrayCollection<int, StorageInterface>
160
     */
161
    #[OneToMany(targetEntity: 'Storage', mappedBy: 'spacecraft', indexBy: 'commodity_id')]
162
    #[OrderBy(['commodity_id' => 'ASC'])]
163
    private Collection $storage;
164
165
    #[ManyToOne(targetEntity: 'Location')]
166
    #[JoinColumn(name: 'location_id', referencedColumnName: 'id')]
167
    private LocationInterface $location;
168
169
    /**
170
     * @var ArrayCollection<int, ShipLogInterface>
171
     */
172
    #[OneToMany(targetEntity: 'ShipLog', mappedBy: 'spacecraft', fetch: 'EXTRA_LAZY')]
173
    #[OrderBy(['id' => 'DESC'])]
174
    private Collection $logbook;
175
176
    #[OneToOne(targetEntity: 'ShipTakeover', mappedBy: 'source')]
177
    private ?ShipTakeoverInterface $takeoverActive = null;
178
179
    #[OneToOne(targetEntity: 'ShipTakeover', mappedBy: 'target')]
180
    private ?ShipTakeoverInterface $takeoverPassive = null;
181
182 3
    public function __construct()
183
    {
184 3
        $this->crew = new ArrayCollection();
185 3
        $this->systems = new ArrayCollection();
186 3
        $this->storage = new ArrayCollection();
187 3
        $this->logbook = new ArrayCollection();
188
    }
189
190 43
    #[Override]
191
    public function getId(): int
192
    {
193 43
        if ($this->id === null) {
194
            throw new RuntimeException(sprintf('entity "%s" not yet persisted', $this->getName()));
195
        }
196
197 43
        return $this->id;
198
    }
199
200 1
    #[Override]
201
    public function getUserId(): int
202
    {
203 1
        return $this->user_id;
204
    }
205
206 7
    #[Override]
207
    public function getUserName(): string
208
    {
209 7
        return $this->getUser()->getName();
210
    }
211
212
    #[Override]
213
    public function getSystemsId(): ?int
214
    {
215
        return $this->getSystem() !== null ? $this->getSystem()->getId() : null;
216
    }
217
218 3
    #[Override]
219
    public function getLayer(): ?LayerInterface
220
    {
221 3
        return $this->getLocation()->getLayer();
222
    }
223
224
    #[Override]
225
    public function getFlightDirection(): ?DirectionEnum
226
    {
227
        return $this->direction;
228
    }
229
230
    #[Override]
231
    public function setFlightDirection(DirectionEnum $direction): SpacecraftInterface
232
    {
233
        $this->direction = $direction;
234
        return $this;
235
    }
236
237 35
    #[Override]
238
    public function getName(): string
239
    {
240 35
        return $this->name;
241
    }
242
243
    #[Override]
244
    public function setName(string $name): SpacecraftInterface
245
    {
246
        $this->name = $name;
247
        return $this;
248
    }
249
250 2
    #[Override]
251
    public function getLssMode(): SpacecraftLssModeEnum
252
    {
253 2
        return $this->lss_mode;
254
    }
255
256
    #[Override]
257
    public function setLssMode(SpacecraftLssModeEnum $lssMode): SpacecraftInterface
258
    {
259
        $this->lss_mode = $lssMode;
260
        return $this;
261
    }
262
263 6
    #[Override]
264
    public function getAlertState(): SpacecraftAlertStateEnum
265
    {
266 6
        return $this->alvl;
267
    }
268
269
    #[Override]
270
    public function setAlertState(SpacecraftAlertStateEnum $state): SpacecraftInterface
271
    {
272
        $this->alvl = $state;
273
        return $this;
274
    }
275
276
    #[Override]
277
    public function setAlertStateGreen(): SpacecraftInterface
278
    {
279
        return $this->setAlertState(SpacecraftAlertStateEnum::ALERT_GREEN);
280
    }
281
282 17
    #[Override]
283
    public function isSystemHealthy(SpacecraftSystemTypeEnum $type): bool
284
    {
285 17
        if (!$this->hasSpacecraftSystem($type)) {
286 14
            return false;
287
        }
288
289 5
        return $this->getSpacecraftSystem($type)->isHealthy();
290
    }
291
292 35
    #[Override]
293
    public function getSystemState(SpacecraftSystemTypeEnum $type): bool
294
    {
295 35
        if (!$this->hasSpacecraftSystem($type)) {
296 32
            return false;
297
        }
298
299 13
        return $this->getSpacecraftSystem($type)->getMode()->isActivated();
300
    }
301
302 4
    #[Override]
303
    public function getImpulseState(): bool
304
    {
305 4
        return $this->getSystemState(SpacecraftSystemTypeEnum::IMPULSEDRIVE);
306
    }
307
308 6
    #[Override]
309
    public function getWarpDriveState(): bool
310
    {
311 6
        return $this->getSystemState(SpacecraftSystemTypeEnum::WARPDRIVE);
312
    }
313
314 2
    #[Override]
315
    public function isWarped(): bool
316
    {
317 2
        return $this->getWarpDriveState();
318
    }
319
320 4
    #[Override]
321
    public function isHeldByTholianWeb(): bool
322
    {
323 4
        return $this->getHoldingWeb() !== null;
324
    }
325
326 32
    #[Override]
327
    public function isCloaked(): bool
328
    {
329 32
        return $this->getSystemState(SpacecraftSystemTypeEnum::CLOAK);
330
    }
331
332 2
    #[Override]
333
    public function getTachyonState(): bool
334
    {
335 2
        return $this->getSystemState(SpacecraftSystemTypeEnum::TACHYON_SCANNER);
336
    }
337
338 1
    #[Override]
339
    public function getSubspaceState(): bool
340
    {
341 1
        return $this->getSystemState(SpacecraftSystemTypeEnum::SUBSPACE_SCANNER);
342
    }
343
344
    #[Override]
345
    public function getRPGModuleState(): bool
346
    {
347
        return $this->getSystemState(SpacecraftSystemTypeEnum::RPG_MODULE);
348
    }
349
350 15
    #[Override]
351
    public function getHull(): int
352
    {
353 15
        return $this->huelle;
354
    }
355
356
    #[Override]
357
    public function setHuell(int $hull): SpacecraftInterface
358
    {
359
        $this->huelle = $hull;
360
        return $this;
361
    }
362
363 15
    #[Override]
364
    public function getMaxHull(): int
365
    {
366 15
        return $this->max_huelle;
367
    }
368
369
    #[Override]
370
    public function setMaxHuell(int $maxHull): SpacecraftInterface
371
    {
372
        $this->max_huelle = $maxHull;
373
        return $this;
374
    }
375
376 9
    #[Override]
377
    public function getShield(): int
378
    {
379 9
        return $this->schilde;
380
    }
381
382
    #[Override]
383
    public function setShield(int $schilde): SpacecraftInterface
384
    {
385
        $this->schilde = $schilde;
386
        return $this;
387
    }
388
389
    /**
390
     * proportional to shield system status
391
     */
392 9
    #[Override]
393
    public function getMaxShield(bool $isTheoretical = false): int
394
    {
395 9
        if ($isTheoretical || !$this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::SHIELDS)) {
396 5
            return $this->max_schilde;
397
        }
398
399 7
        return (int) (ceil($this->max_schilde
400 7
            * $this->getSpacecraftSystem(SpacecraftSystemTypeEnum::SHIELDS)->getStatus() / 100));
401
    }
402
403
    #[Override]
404
    public function setMaxShield(int $maxShields): SpacecraftInterface
405
    {
406
        $this->max_schilde = $maxShields;
407
        return $this;
408
    }
409
410
    #[Override]
411
    public function getHealthPercentage(): float
412
    {
413
        return ($this->getHull() + $this->getShield())
414
            / ($this->getMaxHull() + $this->getMaxShield(true)) * 100;
415
    }
416
417 20
    #[Override]
418
    public function isShielded(): bool
419
    {
420 20
        return $this->getSystemState(SpacecraftSystemTypeEnum::SHIELDS);
421
    }
422
423 7
    #[Override]
424
    public function getNbs(): bool
425
    {
426 7
        return $this->getSystemState(SpacecraftSystemTypeEnum::NBS);
427
    }
428
429 6
    #[Override]
430
    public function getLss(): bool
431
    {
432 6
        return $this->getSystemState(SpacecraftSystemTypeEnum::LSS);
433
    }
434
435 3
    #[Override]
436
    public function getPhaserState(): bool
437
    {
438 3
        return $this->getSystemState(SpacecraftSystemTypeEnum::PHASER);
439
    }
440
441 1
    #[Override]
442
    public function isAlertGreen(): bool
443
    {
444 1
        return $this->getAlertState() === SpacecraftAlertStateEnum::ALERT_GREEN;
445
    }
446
447 1
    #[Override]
448
    public function getTorpedoState(): bool
449
    {
450 1
        return $this->getSystemState(SpacecraftSystemTypeEnum::TORPEDO);
451
    }
452
453
    #[Override]
454
    public function getTorpedoCount(): int
455
    {
456
        if ($this->getTorpedoStorage() === null) {
457
            return 0;
458
        }
459
460
        return $this->getTorpedoStorage()->getStorage()->getAmount();
461
    }
462
463 7
    #[Override]
464
    public function isStation(): bool
465
    {
466 7
        return $this instanceof StationInterface;
467
    }
468
469 1
    #[Override]
470
    public function isShuttle(): bool
471
    {
472 1
        return $this->getRump()->getCategoryId() === SpacecraftRumpEnum::SHIP_CATEGORY_SHUTTLE;
473
    }
474
475 2
    #[Override]
476
    public function isConstruction(): bool
477
    {
478 2
        return $this->getRump()->getCategoryId() === SpacecraftRumpEnum::SHIP_CATEGORY_CONSTRUCTION;
479
    }
480
481 1
    #[Override]
482
    public function getDatabaseId(): ?int
483
    {
484 1
        return $this->database_id;
485
    }
486
487
    #[Override]
488
    public function setDatabaseId(?int $databaseEntryId): SpacecraftInterface
489
    {
490
        $this->database_id = $databaseEntryId;
491
        return $this;
492
    }
493
494 2
    #[Override]
495
    public function isDestroyed(): bool
496
    {
497 2
        return $this->is_destroyed;
498
    }
499
500
    #[Override]
501
    public function setIsDestroyed(bool $isDestroyed): SpacecraftInterface
502
    {
503
        $this->is_destroyed = $isDestroyed;
504
        return $this;
505
    }
506
507
    #[Override]
508
    public function isDisabled(): bool
509
    {
510
        return $this->disabled;
511
    }
512
513
    #[Override]
514
    public function setDisabled(bool $isDisabled): SpacecraftInterface
515
    {
516
        $this->disabled = $isDisabled;
517
        return $this;
518
    }
519
520
521
522
    /**
523
     * proportional to computer system status
524
     */
525 1
    #[Override]
526
    public function getHitChance(): int
527
    {
528 1
        if (!$this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::COMPUTER)) {
529
            return $this->hit_chance;
530
        }
531
532 1
        return (int) (ceil($this->hit_chance
533 1
            * $this->getSpacecraftSystem(SpacecraftSystemTypeEnum::COMPUTER)->getStatus() / 100));
534
    }
535
536
    #[Override]
537
    public function setHitChance(int $hitChance): SpacecraftInterface
538
    {
539
        $this->hit_chance = $hitChance;
540
        return $this;
541
    }
542
543
    /**
544
     * proportional to impulsedrive system status
545
     */
546 1
    #[Override]
547
    public function getEvadeChance(): int
548
    {
549 1
        if (!$this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::IMPULSEDRIVE)) {
550
            return $this->evade_chance;
551
        }
552
553 1
        return (int) (ceil($this->evade_chance
554 1
            * $this->getSpacecraftSystem(SpacecraftSystemTypeEnum::IMPULSEDRIVE)->getStatus() / 100));
555
    }
556
557
    #[Override]
558
    public function setEvadeChance(int $evadeChance): SpacecraftInterface
559
    {
560
        $this->evade_chance = $evadeChance;
561
        return $this;
562
    }
563
564
    /**
565
     * proportional to energy weapon system status
566
     */
567 1
    #[Override]
568
    public function getBaseDamage(): int
569
    {
570 1
        if (!$this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::PHASER)) {
571
            return $this->base_damage;
572
        }
573
574 1
        return (int) (ceil($this->base_damage
575 1
            * $this->getSpacecraftSystem(SpacecraftSystemTypeEnum::PHASER)->getStatus() / 100));
576
    }
577
578
    #[Override]
579
    public function setBaseDamage(int $baseDamage): SpacecraftInterface
580
    {
581
        $this->base_damage = $baseDamage;
582
        return $this;
583
    }
584
585
    /**
586
     * proportional to tractor beam system status
587
     */
588 1
    #[Override]
589
    public function getTractorPayload(): int
590
    {
591 1
        if (!$this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TRACTOR_BEAM)) {
592
            return 0;
593
        }
594
595 1
        return (int) (ceil($this->getRump()->getTractorPayload()
596 1
            * $this->getSpacecraftSystem(SpacecraftSystemTypeEnum::TRACTOR_BEAM)->getStatus() / 100));
597
    }
598
599 5
    #[Override]
600
    public function getState(): SpacecraftStateEnum
601
    {
602 5
        return $this->state;
603
    }
604
605
    #[Override]
606
    public function setState(SpacecraftStateEnum $state): SpacecraftInterface
607
    {
608
        $this->state = $state;
609
        return $this;
610
    }
611
612 1
    #[Override]
613
    public function isInEmergency(): bool
614
    {
615 1
        return $this->in_emergency;
616
    }
617
618
    #[Override]
619
    public function setIsInEmergency(bool $inEmergency): SpacecraftInterface
620
    {
621
        $this->in_emergency = $inEmergency;
622
        return $this;
623
    }
624
625
    #[Override]
626
    public function isUnderRepair(): bool
627
    {
628
        return $this->getState() === SpacecraftStateEnum::REPAIR_ACTIVE
629
            || $this->getState() === SpacecraftStateEnum::REPAIR_PASSIVE;
630
    }
631
632 13
    #[Override]
633
    public function getCrewAssignments(): Collection
634
    {
635 13
        return $this->crew;
636
    }
637
638 5
    #[Override]
639
    public function getPosX(): int
640
    {
641 5
        return $this->location->getX();
642
    }
643
644 5
    #[Override]
645
    public function getPosY(): int
646
    {
647 5
        return $this->location->getY();
648
    }
649
650 12
    #[Override]
651
    public function getCrewCount(): int
652
    {
653 12
        return $this->getCrewAssignments()->count();
654
    }
655
656 7
    #[Override]
657
    public function getNeededCrewCount(): int
658
    {
659 7
        $buildplan = $this->getBuildplan();
660 7
        if ($buildplan === null) {
661
            return 0;
662
        }
663
664 7
        return $buildplan->getCrew();
665
    }
666
667 6
    #[Override]
668
    public function getExcessCrewCount(): int
669
    {
670 6
        return $this->getCrewCount() - $this->getNeededCrewCount();
671
    }
672
673 3
    #[Override]
674
    public function hasEnoughCrew(?GameControllerInterface $game = null): bool
675
    {
676 3
        $buildplan = $this->getBuildplan();
677
678 3
        if ($buildplan === null) {
679
            if ($game !== null) {
680
                $game->addInformation(_("Keine Crew vorhanden"));
681
            }
682
            return false;
683
        }
684
685 3
        $result = $buildplan->getCrew() <= 0
686 3
            || $this->getCrewCount() >= $buildplan->getCrew();
687
688 3
        if (!$result && $game !== null) {
689
            $game->addInformationf(
690
                _("Es werden %d Crewmitglieder benötigt"),
691
                $buildplan->getCrew()
692
            );
693
        }
694
695 3
        return $result;
696
    }
697
698 47
    #[Override]
699
    public function getUser(): UserInterface
700
    {
701 47
        return $this->user;
702
    }
703
704
    #[Override]
705
    public function setUser(UserInterface $user): SpacecraftInterface
706
    {
707
        $this->user = $user;
708
        return $this;
709
    }
710
711 6
    #[Override]
712
    public function getSystem(): ?StarSystemInterface
713
    {
714 6
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getSystem() : null;
715
    }
716
717 2
    #[Override]
718
    public function getModules(): array
719
    {
720 2
        $modules = [];
721
722 2
        $buildplan = $this->getBuildplan();
723 2
        if ($buildplan === null) {
724
            return $modules;
725
        }
726
727 2
        foreach ($buildplan->getModulesOrdered() as $obj) {
728 2
            $module = $obj->getModule();
729 2
            $index = $module->getType() === SpacecraftModuleTypeEnum::SPECIAL ? $module->getId() : $module->getType()->value;
730 2
            $modules[$index] = $module;
731
        }
732
733 2
        return $modules;
734
    }
735
736
    #[Override]
737
    public function isDeflectorHealthy(): bool
738
    {
739
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::DEFLECTOR);
740
    }
741
742
    #[Override]
743
    public function isMatrixScannerHealthy(): bool
744
    {
745
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::MATRIX_SCANNER);
746
    }
747
748 10
    #[Override]
749
    public function isTorpedoStorageHealthy(): bool
750
    {
751 10
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::TORPEDO_STORAGE);
752
    }
753
754 1
    #[Override]
755
    public function isShuttleRampHealthy(): bool
756
    {
757 1
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::SHUTTLE_RAMP);
758
    }
759
760 1
    #[Override]
761
    public function isWebEmitterHealthy(): bool
762
    {
763 1
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::THOLIAN_WEB);
764
    }
765
766 1
    #[Override]
767
    public function isTractoring(): bool
768
    {
769 1
        return $this->getTractoredShip() !== null;
770
    }
771
772
    #[Override]
773
    public function isOverColony(): ?ColonyInterface
774
    {
775
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getColony() : null;
776
    }
777
778 2
    #[Override]
779
    public function isOverSystem(): ?StarSystemInterface
780
    {
781 2
        $location = $this->getLocation();
782 2
        if ($location instanceof StarSystemMapInterface) {
783
            return null;
784
        }
785
786 2
        return $location->getSystem();
787
    }
788
789 1
    #[Override]
790
    public function isWarpPossible(): bool
791
    {
792 1
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPDRIVE) && $this->getSystem() === null;
793
    }
794
795 3
    #[Override]
796
    public function getTorpedo(): ?TorpedoTypeInterface
797
    {
798 3
        if ($this->getTorpedoStorage() === null) {
799 3
            return null;
800
        }
801
802
        return $this->getTorpedoStorage()->getTorpedo();
803
    }
804
805 3
    #[Override]
806
    public function getTorpedoStorage(): ?TorpedoStorageInterface
807
    {
808 3
        return $this->torpedoStorage;
809
    }
810
811
    #[Override]
812
    public function setTorpedoStorage(?TorpedoStorageInterface $torpedoStorage): SpacecraftInterface
813
    {
814
        $this->torpedoStorage = $torpedoStorage;
815
        return $this;
816
    }
817
818 15
    #[Override]
819
    public function getStorage(): Collection
820
    {
821 15
        return $this->storage;
822
    }
823
824 1
    #[Override]
825
    public function getLogbook(): Collection
826
    {
827 1
        return $this->logbook;
828
    }
829
830 4
    #[Override]
831
    public function getTakeoverActive(): ?ShipTakeoverInterface
832
    {
833 4
        return $this->takeoverActive;
834
    }
835
836
    #[Override]
837
    public function setTakeoverActive(?ShipTakeoverInterface $takeover): SpacecraftInterface
838
    {
839
        $this->takeoverActive = $takeover;
840
841
        return $this;
842
    }
843
844 4
    #[Override]
845
    public function getTakeoverPassive(): ?ShipTakeoverInterface
846
    {
847 4
        return $this->takeoverPassive;
848
    }
849
850
    #[Override]
851
    public function setTakeoverPassive(?ShipTakeoverInterface $takeover): SpacecraftInterface
852
    {
853
        $this->takeoverPassive = $takeover;
854
855
        return $this;
856
    }
857
858 14
    #[Override]
859
    public function getStorageSum(): int
860
    {
861 14
        return array_reduce(
862 14
            $this->getStorage()->getValues(),
863 14
            fn(int $sum, StorageInterface $storage): int => $sum + $storage->getAmount(),
864 14
            0
865 14
        );
866
    }
867
868 13
    #[Override]
869
    public function getMaxStorage(): int
870
    {
871 13
        return $this->getRump()->getStorage();
872
    }
873
874 8
    #[Override]
875
    public function getBeamableStorage(): Collection
876
    {
877 8
        return CommodityTransfer::excludeNonBeamable($this->storage);
878
    }
879
880 8
    #[Override]
881
    public function getMap(): ?MapInterface
882
    {
883 8
        if ($this->location instanceof MapInterface) {
884 6
            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...
885
        }
886 2
        if ($this->location instanceof StarSystemMapInterface) {
887 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

887
            return $this->location->/** @scrutinizer ignore-call */ getSystem()->getMap();
Loading history...
888
        }
889
890
        return null;
891
    }
892
893 2
    #[Override]
894
    public function getMapRegion(): ?MapRegionInterface
895
    {
896 2
        $systemMap = $this->getStarsystemMap();
897 2
        if ($systemMap !== null) {
898
            return null;
899
        }
900
901 2
        $map = $this->getMap();
902 2
        if ($map === null) {
903
            return null;
904
        }
905
906 2
        return $map->getMapRegion();
907
    }
908
909 3
    #[Override]
910
    public function setLocation(LocationInterface $location): SpacecraftInterface
911
    {
912 3
        $this->location = $location;
913
914 3
        return $this;
915
    }
916
917 9
    #[Override]
918
    public function getStarsystemMap(): ?StarSystemMapInterface
919
    {
920 9
        if ($this->location instanceof StarSystemMapInterface) {
921 5
            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...
922
        }
923
924 6
        return null;
925
    }
926
927 32
    #[Override]
928
    public function getLocation(): MapInterface|StarSystemMapInterface
929
    {
930
        if (
931 32
            $this->location instanceof MapInterface
932 32
            || $this->location instanceof StarSystemMapInterface
933
        ) {
934 32
            return $this->location;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->location returns the type Stu\Orm\Entity\LocationInterface which includes types incompatible with the type-hinted return Stu\Orm\Entity\MapInterf...\StarSystemMapInterface.
Loading history...
935
        }
936
937
        throw new RuntimeException('unknown type');
938
    }
939
940 11
    #[Override]
941
    public function getBeamFactor(): int
942
    {
943 11
        return $this->getRump()->getBeamFactor();
944
    }
945
946 4
    #[Override]
947
    public function getSectorString(): string
948
    {
949 4
        return $this->getLocation()->getSectorString();
950
    }
951
952 13
    #[Override]
953
    public function getBuildplan(): ?SpacecraftBuildplanInterface
954
    {
955 13
        return $this->buildplan;
956
    }
957
958
    #[Override]
959
    public function setBuildplan(?SpacecraftBuildplanInterface $spacecraftBuildplan): SpacecraftInterface
960
    {
961
        $this->buildplan = $spacecraftBuildplan;
962
        return $this;
963
    }
964
965 39
    #[Override]
966
    public function getSystems(): Collection
967
    {
968 39
        return $this->systems;
969
    }
970
971 38
    #[Override]
972
    public function hasSpacecraftSystem(SpacecraftSystemTypeEnum $type): bool
973
    {
974 38
        return $this->getSystems()->containsKey($type->value);
975
    }
976
977 20
    #[Override]
978
    public function getSpacecraftSystem(SpacecraftSystemTypeEnum $type): SpacecraftSystemInterface
979
    {
980 20
        $system = $this->getSystems()->get($type->value);
981 20
        if ($system === null) {
982
            throw new RuntimeException(sprintf('system type %d does not exist on ship', $type->value));
983
        }
984
985 20
        return $system;
986
    }
987
988 1
    #[Override]
989
    public function displayNbsActions(): bool
990
    {
991 1
        return !$this->isCloaked()
992 1
            && !$this->isWarped();
993
    }
994
995
    #[Override]
996
    public function isTractorbeamPossible(): bool
997
    {
998
        return TractorBeamShipSystem::isTractorBeamPossible($this);
999
    }
1000
1001
    #[Override]
1002
    public function isBoardingPossible(): bool
1003
    {
1004
        return FightLib::isBoardingPossible($this);
1005
    }
1006
1007
    #[Override]
1008
    public function isInterceptable(): bool
1009
    {
1010
        //TODO can tractored ships be intercepted?!
1011
        return $this->getWarpDriveState();
1012
    }
1013
1014 2
    #[Override]
1015
    public function getTractoredShip(): ?ShipInterface
1016
    {
1017 2
        return $this->tractoredShip;
1018
    }
1019
1020
    #[Override]
1021
    public function setTractoredShip(?ShipInterface $ship): SpacecraftInterface
1022
    {
1023
        $this->tractoredShip = $ship;
1024
        return $this;
1025
    }
1026
1027 8
    #[Override]
1028
    public function getHoldingWeb(): ?TholianWebInterface
1029
    {
1030 8
        return $this->holdingWeb;
1031
    }
1032
1033
    #[Override]
1034
    public function setHoldingWeb(?TholianWebInterface $web): SpacecraftInterface
1035
    {
1036
        $this->holdingWeb = $web;
1037
1038
        return $this;
1039
    }
1040
1041 4
    #[Override]
1042
    public function getHoldingWebBackgroundStyle(): string
1043
    {
1044 4
        if ($this->getHoldingWeb() === null) {
1045 4
            return '';
1046
        }
1047
1048
        if ($this->getHoldingWeb()->isFinished()) {
1049
            $icon =  'web.png';
1050
        } else {
1051
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1052
1053
            $icon = $closeTofinish ? 'web_u.png' : 'web_u2.png';
1054
        }
1055
1056
        return sprintf('src="assets/buttons/%s"; class="indexedGraphics" style="z-index: 5;"', $icon);
1057
    }
1058
1059
    public function getHoldingWebImageStyle(): string
1060
    {
1061
        if ($this->getHoldingWeb() === null) {
1062
            return '';
1063
        }
1064
1065
        if ($this->getHoldingWeb()->isFinished()) {
1066
            $icon =  'webfill.png';
1067
        } else {
1068
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1069
1070
            $icon = $closeTofinish ? 'web_ufill.png' : 'web_ufill2.png';
1071
        }
1072
1073
        return $icon;
1074
    }
1075
1076 1
    #[Override]
1077
    public function canIntercept(): bool
1078
    {
1079 1
        return $this->isSystemHealthy(SpacecraftSystemTypeEnum::WARPDRIVE)
1080 1
            && !$this->isTractoring()
1081 1
            && (!$this instanceof ShipInterface || !$this->isTractored());
1082
    }
1083
1084 3
    #[Override]
1085
    public function canMove(): bool
1086
    {
1087 3
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPDRIVE)
1088 3
            || $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::IMPULSEDRIVE);
1089
    }
1090
1091 1
    #[Override]
1092
    public function hasActiveWeapon(): bool
1093
    {
1094 1
        return $this->getPhaserState() || $this->getTorpedoState();
1095
    }
1096
1097
    #[Override]
1098
    public function hasEscapePods(): bool
1099
    {
1100
        return $this->getRump()->isEscapePods() && $this->getCrewCount() > 0;
1101
    }
1102
1103 1
    #[Override]
1104
    public function getRepairRate(): int
1105
    {
1106
        // @todo
1107 1
        return 100;
1108
    }
1109
1110 36
    #[Override]
1111
    public function getRump(): SpacecraftRumpInterface
1112
    {
1113 36
        return $this->rump;
1114
    }
1115
1116 19
    #[Override]
1117
    public function getRumpId(): int
1118
    {
1119 19
        return $this->getRump()->getId();
1120
    }
1121
1122 19
    #[Override]
1123
    public function getRumpName(): string
1124
    {
1125 19
        return $this->getRump()->getName();
1126
    }
1127
1128
    #[Override]
1129
    public function setRump(SpacecraftRumpInterface $shipRump): SpacecraftInterface
1130
    {
1131
        $this->rump = $shipRump;
1132
        return $this;
1133
    }
1134
1135 4
    #[Override]
1136
    public function hasPhaser(): bool
1137
    {
1138 4
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::PHASER);
1139
    }
1140
1141 6
    #[Override]
1142
    public function hasTorpedo(): bool
1143
    {
1144 6
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::TORPEDO);
1145
    }
1146
1147 4
    #[Override]
1148
    public function hasCloak(): bool
1149
    {
1150 4
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::CLOAK);
1151
    }
1152
1153 4
    #[Override]
1154
    public function hasShuttleRamp(): bool
1155
    {
1156 4
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::SHUTTLE_RAMP);
1157
    }
1158
1159 6
    #[Override]
1160
    public function hasWarpdrive(): bool
1161
    {
1162 6
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPDRIVE);
1163
    }
1164
1165 1
    #[Override]
1166
    public function hasReactor(): bool
1167
    {
1168 1
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::WARPCORE) ||
1169 1
            $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::FUSION_REACTOR) ||
1170 1
            $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::SINGULARITY_REACTOR);
1171
    }
1172
1173 2
    #[Override]
1174
    public function hasNbsLss(): bool
1175
    {
1176 2
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::LSS);
1177
    }
1178
1179 7
    #[Override]
1180
    public function hasUplink(): bool
1181
    {
1182 7
        return $this->hasSpacecraftSystem(SpacecraftSystemTypeEnum::UPLINK);
1183
    }
1184
1185 3
    #[Override]
1186
    public function getMaxTorpedos(): int
1187
    {
1188 3
        return $this->getRump()->getBaseTorpedoStorage()
1189 3
            + ($this->isSystemHealthy(SpacecraftSystemTypeEnum::TORPEDO_STORAGE)
1190 3
                ? TorpedoStorageShipSystem::TORPEDO_CAPACITY : 0);
1191
    }
1192
1193 2
    #[Override]
1194
    public function getStoredShuttles(): Collection
1195
    {
1196 2
        return $this->getStorage()
1197 2
            ->map(fn(StorageInterface $storage): CommodityInterface => $storage->getCommodity())
1198 2
            ->filter(fn(CommodityInterface $commodity): bool => $commodity->isShuttle());
1199
    }
1200
1201 2
    #[Override]
1202
    public function hasStoredBuoy(): bool
1203
    {
1204 2
        return $this->getStorage()
1205 2
            ->exists(fn(int $key, StorageInterface $storage): bool => $storage->getCommodity()->isBouy());
1206
    }
1207
1208 2
    #[Override]
1209
    public function getHref(): string
1210
    {
1211 2
        $moduleView = $this->getType()->getModuleView();
1212 2
        if ($moduleView === null) {
1213
            return '';
1214
        }
1215
1216 2
        return sprintf(
1217 2
            '%s?%s=1&id=%d',
1218 2
            $moduleView->getPhpPage(),
1219 2
            $this->getType()->getViewIdentifier(),
1220 2
            $this->getId()
1221 2
        );
1222
    }
1223
1224
    #[Override]
1225
    public function __toString(): string
1226
    {
1227
        if ($this->id !== null) {
1228
            return sprintf(
1229
                "id: %d, name: %s,\nhull: %d/%d, shields %d/%d,\nevadeChance: %d, hitChance: %d, baseDamage: %d",
1230
                $this->getId(),
1231
                $this->getName(),
1232
                $this->huelle,
1233
                $this->max_huelle,
1234
                $this->schilde,
1235
                $this->max_schilde,
1236
                $this->evade_chance,
1237
                $this->hit_chance,
1238
                $this->base_damage
1239
            );
1240
        }
1241
1242
        return $this->getName();
1243
    }
1244
1245 4
    #[Override]
1246
    public function getHullColorStyle(): string
1247
    {
1248 4
        return $this->getColorStyle($this->getHull(), $this->getMaxHull());
1249
    }
1250
1251 4
    private function getColorStyle(int $actual, int $max): string
1252
    {
1253
        // full
1254 4
        if ($actual === $max) {
1255 3
            return '';
1256
        }
1257
1258
        // less than 100% - green
1259 1
        if ($actual / $max > 0.75) {
1260 1
            return 'color: #19c100;';
1261
        }
1262
1263
        // less than 75% - yellow
1264
        if ($actual / $max > 0.50) {
1265
            return 'color: #f4e932;';
1266
        }
1267
1268
        // less than 50% - orange
1269
        if ($actual / $max > 0.25) {
1270
            return 'color: #f48b28;';
1271
        }
1272
1273
        // less than 25% - red
1274
        return 'color: #ff3c3c;';
1275
    }
1276
}
1277