Passed
Pull Request — master (#1687)
by Nico
22:43
created

Ship::getReactorOutput()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 3
nop 0
dl 0
loc 15
ccs 0
cts 10
cp 0
crap 20
rs 9.9332
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A Ship::setSensorRange() 0 4 1
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 RuntimeException;
21
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...
22
use Stu\Component\Map\MapEnum;
23
use Stu\Component\Ship\ShipAlertStateEnum;
24
use Stu\Component\Ship\ShipEnum;
25
use Stu\Component\Ship\ShipLSSModeEnum;
26
use Stu\Component\Ship\ShipModuleTypeEnum;
27
use Stu\Component\Ship\ShipRumpEnum;
28
use Stu\Component\Ship\ShipStateEnum;
29
use Stu\Component\Ship\SpacecraftTypeEnum;
30
use Stu\Component\Ship\System\ShipSystemModeEnum;
31
use Stu\Component\Ship\System\ShipSystemTypeEnum;
32
use Stu\Component\Ship\System\Type\TorpedoStorageShipSystem;
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
40
/**
41
 * @Entity(repositoryClass="Stu\Orm\Repository\ShipRepository")
42
 * @Table(
43
 *     name="stu_ships",
44
 *     indexes={
45
 *         @Index(name="ship_fleet_idx", columns={"fleets_id"}),
46
 *         @Index(name="ship_map_idx", columns={"map_id"}),
47
 *         @Index(name="ship_starsystem_map_idx", columns={"starsystem_map_id"}),
48
 *         @Index(name="outer_system_location_idx", columns={"cx", "cy"}),
49
 *         @Index(name="ship_rump_idx", columns={"rumps_id"}),
50
 *         @Index(name="ship_web_idx", columns={"holding_web_id"}),
51
 *         @Index(name="ship_user_idx", columns={"user_id"}),
52
 *         @Index(name="ship_tractored_idx", columns={"tractored_ship_id"}),
53
 *         @Index(name="ship_influence_area_idx", columns={"influence_area_id"})
54
 *     }
55
 * )
56
 **/
57
class Ship implements ShipInterface
58
{
59
    /**
60
     * @Id
61
     * @Column(type="integer")
62
     * @GeneratedValue(strategy="IDENTITY")
63
     *
64
     */
65
    private ?int $id = null;
66
67
    /**
68
     * @Column(type="integer")
69
     *
70
     */
71
    private int $user_id = 0;
72
73
    /**
74
     * @Column(type="integer")
75
     *
76
     */
77
    private int $rumps_id = 0;
78
79
    /**
80
     * @Column(type="integer", nullable=true)
81
     *
82
     */
83
    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...
84
85
    /**
86
     * @Column(type="integer", nullable=true)
87
     *
88
     */
89
    private ?int $fleets_id = null;
90
91
    /**
92
     * @Column(type="integer", length=5)
93
     *
94
     */
95
    private int $layer_id = MapEnum::DEFAULT_LAYER;
96
97
    /**
98
     * @Column(type="integer", length=5)
99
     *
100
     */
101
    private int $cx = 0;
102
103
    /**
104
     * @Column(type="integer", length=5)
105
     *
106
     */
107
    private int $cy = 0;
108
109
    /**
110
     * @Column(type="smallint", length=1)
111
     *
112
     */
113
    private int $direction = 0;
114
115
    /**
116
     * @Column(type="string")
117
     *
118
     */
119
    private string $name = '';
120
121
    /**
122
     * @Column(type="smallint", length=1, enumType=ShipAlertStateEnum::class)
123
     *
124
     */
125
    private ShipAlertStateEnum $alvl = ShipAlertStateEnum::ALERT_GREEN;
126
127
    /**
128
     * @Column(type="smallint", length=1)
129
     *
130
     */
131
    private int $lss_mode = ShipLSSModeEnum::LSS_NORMAL;
132
133
    /**
134
     * @Column(type="integer", length=6)
135
     *
136
     */
137
    private int $huelle = 0;
138
139
    /**
140
     * @Column(type="integer", length=6)
141
     *
142
     */
143
    private int $max_huelle = 0;
144
145
    /**
146
     * @Column(type="integer", length=6)
147
     *
148
     */
149
    private int $schilde = 0;
150
151
    /**
152
     * @Column(type="integer", length=6)
153
     *
154
     */
155
    private int $max_schilde = 0;
156
157
    /**
158
     * @Column(type="integer", nullable=true)
159
     *
160
     */
161
    private ?int $tractored_ship_id = null;
162
163
    /**
164
     * @Column(type="integer", nullable=true)
165
     *
166
     */
167
    private ?int $holding_web_id = null;
168
169
    /**
170
     * @Column(type="integer", nullable=true)
171
     *
172
     */
173
    private ?int $dock = null;
174
175
    /**
176
     * @Column(type="integer")
177
     *
178
     */
179
    private int $former_rumps_id = 0;
180
181
    /**
182
     * @Column(type="smallint", length=1, nullable=true)
183
     *
184
     */
185
    private ?int $type = SpacecraftTypeEnum::SPACECRAFT_TYPE_SHIP;
186
187
    /**
188
     * @Column(type="integer")
189
     *
190
     */
191
    private int $database_id = 0;
192
193
    /**
194
     * @Column(type="boolean")
195
     *
196
     */
197
    private bool $is_destroyed = false;
198
199
    /**
200
     * @Column(type="boolean")
201
     *
202
     */
203
    private bool $disabled = false;
204
205
    /**
206
     * @Column(type="smallint", length=3)
207
     *
208
     */
209
    private int $hit_chance = 0;
210
211
    /**
212
     * @Column(type="smallint", length=3)
213
     *
214
     */
215
    private int $evade_chance = 0;
216
217
    /**
218
     * @Column(type="smallint", length=4)
219
     *
220
     */
221
    private int $base_damage = 0;
222
223
    /**
224
     * @Column(type="smallint", length=3)
225
     *
226
     */
227
    private int $sensor_range = 0;
228
229
    /**
230
     * @Column(type="integer")
231
     *
232
     */
233
    private int $shield_regeneration_timer = 0;
234
235
    /**
236
     * @Column(type="smallint", enumType=ShipStateEnum::class)
237
     *
238
     */
239
    private ShipStateEnum $state = ShipStateEnum::SHIP_STATE_NONE;
240
241
    /**
242
     * @Column(type="integer", nullable=true)
243
     *
244
     */
245
    private ?int $astro_start_turn = null;
246
247
    /**
248
     * @Column(type="boolean")
249
     *
250
     */
251
    private bool $is_fleet_leader = false;
252
253
    /**
254
     * @Column(type="integer", nullable=true) *
255
     *
256
     */
257
    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...
258
259
    /**
260
     * @Column(type="integer", nullable=true) *
261
     *
262
     */
263
    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...
264
265
    /**
266
     * @Column(type="integer", nullable=true) *
267
     *
268
     */
269
    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...
270
271
    /**
272
     * @Column(type="boolean")
273
     *
274
     */
275
    private bool $in_emergency = false;
276
277
    /**
278
     * @ManyToOne(targetEntity="Fleet", inversedBy="ships")
279
     * @JoinColumn(name="fleets_id", referencedColumnName="id")
280
     */
281
    private ?FleetInterface $fleet = null;
282
283
    /**
284
     * @OneToOne(targetEntity="TradePost", mappedBy="ship")
285
     */
286
    private ?TradePostInterface $tradePost = null;
287
288
    /**
289
     * @ManyToOne(targetEntity="Ship", inversedBy="dockedShips")
290
     * @JoinColumn(name="dock", referencedColumnName="id")
291
     */
292
    private ?ShipInterface $dockedTo = null;
293
294
    /**
295
     * @var ArrayCollection<int, ShipInterface>
296
     *
297
     * @OneToMany(targetEntity="Ship", mappedBy="dockedTo", indexBy="id")
298
     * @OrderBy({"fleets_id": "DESC", "is_fleet_leader": "DESC"})
299
     */
300
    private Collection $dockedShips;
301
302
    /**
303
     * @var ArrayCollection<int, DockingPrivilegeInterface>
304
     *
305
     * @OneToMany(targetEntity="DockingPrivilege", mappedBy="ship")
306
     */
307
    private Collection $dockingPrivileges;
308
309
    /**
310
     * @OneToOne(targetEntity="Ship")
311
     * @JoinColumn(name="tractored_ship_id", referencedColumnName="id")
312
     */
313
    private ?ShipInterface $tractoredShip = null;
314
315
    /**
316
     * @OneToOne(targetEntity="Ship", mappedBy="tractoredShip")
317
     */
318
    private ?ShipInterface $tractoringShip = null;
319
320
    /**
321
     * @ManyToOne(targetEntity="TholianWeb")
322
     * @JoinColumn(name="holding_web_id", referencedColumnName="id", onDelete="CASCADE")
323
     */
324
    private ?TholianWebInterface $holdingWeb = null;
325
326
    /**
327
     * @ManyToOne(targetEntity="User")
328
     * @JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
329
     */
330
    private UserInterface $user;
331
332
    /**
333
     * @var ArrayCollection<int, ShipCrewInterface>
334
     *
335
     * @OneToMany(targetEntity="ShipCrew", mappedBy="ship", indexBy="id")
336
     * @OrderBy({"id": "ASC"})
337
     */
338
    private Collection $crew;
339
340
    /**
341
     * @OneToOne(targetEntity="TorpedoStorage", mappedBy="ship")
342
     */
343
    private ?TorpedoStorageInterface $torpedoStorage = null;
344
345
    /**
346
     * @var ArrayCollection<int, ShipSystemInterface>
347
     *
348
     * @OneToMany(targetEntity="ShipSystem", mappedBy="ship", indexBy="system_type")
349
     * @OrderBy({"system_type": "ASC"})
350
     */
351
    private Collection $systems;
352
353
    /**
354
     * @ManyToOne(targetEntity="ShipRump")
355
     * @JoinColumn(name="rumps_id", referencedColumnName="id")
356
     */
357
    private ShipRumpInterface $rump;
358
359
    /**
360
     * @ManyToOne(targetEntity="ShipBuildplan")
361
     * @JoinColumn(name="plans_id", referencedColumnName="id", onDelete="CASCADE")
362
     */
363
    private ?ShipBuildplanInterface $buildplan = null;
364
365
    /**
366
     * @var ArrayCollection<int, StorageInterface>
367
     *
368
     * @OneToMany(targetEntity="Storage", mappedBy="ship", indexBy="commodity_id")
369
     * @OrderBy({"commodity_id": "ASC"})
370
     */
371
    private Collection $storage;
372
373
    /**
374
     * @ManyToOne(targetEntity="Map")
375
     * @JoinColumn(name="map_id", referencedColumnName="id")
376
     */
377
    private ?MapInterface $map = null;
378
379
    /**
380
     * @ManyToOne(targetEntity="StarSystemMap")
381
     * @JoinColumn(name="starsystem_map_id", referencedColumnName="id")
382
     */
383
    private ?StarSystemMapInterface $starsystem_map = null;
384
385
    /**
386
     * @ManyToOne(targetEntity="StarSystem")
387
     * @JoinColumn(name="influence_area_id", referencedColumnName="id")
388
     */
389
    private ?StarSystemInterface $influenceArea = null;
390
391
    /**
392
     * @var ArrayCollection<int, ShipLogInterface>
393
     *
394
     * @OneToMany(targetEntity="ShipLog", mappedBy="ship", fetch="EXTRA_LAZY")
395
     * @OrderBy({"id": "DESC"})
396
     */
397
    private Collection $logbook;
398
399
    /**
400
     * @OneToOne(targetEntity="ShipTakeover", mappedBy="source")
401
     */
402
    private ?ShipTakeoverInterface $takeoverActive = null;
403
404
    /**
405
     * @OneToOne(targetEntity="ShipTakeover", mappedBy="target")
406
     */
407
    private ?ShipTakeoverInterface $takeoverPassive = null;
408
409
    public function __construct()
410
    {
411
        $this->dockedShips = new ArrayCollection();
412
        $this->dockingPrivileges = new ArrayCollection();
413
        $this->crew = new ArrayCollection();
414
        $this->systems = new ArrayCollection();
415
        $this->storage = new ArrayCollection();
416
        $this->logbook = new ArrayCollection();
417
    }
418
419
    public function getId(): int
420
    {
421
        if ($this->id === null) {
422
            throw new RuntimeException('entity not yet persisted');
423
        }
424
425
        return $this->id;
426
    }
427
428
    public function getUserId(): int
429
    {
430
        return $this->user_id;
431
    }
432
433
    public function getUserName(): string
434
    {
435
        return $this->getUser()->getName();
436
    }
437
438
    public function getFleetId(): ?int
439
    {
440
        return $this->fleets_id;
441
    }
442
443
    public function setFleetId(?int $fleetId): ShipInterface
444
    {
445
        $this->fleets_id = $fleetId;
446
        return $this;
447
    }
448
449
    public function getSystemsId(): ?int
450
    {
451
        return $this->getSystem() !== null ? $this->getSystem()->getId() : null;
452
    }
453
454
    public function getLayer(): ?LayerInterface
455
    {
456
        $map = $this->getMap();
457
        if ($map !== null) {
458
            return $map->getLayer();
459
        }
460
461
        return $this->getSystem()->getLayer();
462
    }
463
464
    public function getLayerId(): int
465
    {
466
        return $this->layer_id;
467
    }
468
469
    public function setLayerId(int $layerId): ShipInterface
470
    {
471
        $this->layer_id = $layerId;
472
        return $this;
473
    }
474
475
    public function getCx(): int
476
    {
477
        return $this->cx;
478
    }
479
480
    public function setCx(int $cx): ShipInterface
481
    {
482
        $this->cx = $cx;
483
        return $this;
484
    }
485
486
    public function getCy(): int
487
    {
488
        return $this->cy;
489
    }
490
491
    public function setCy(int $cy): ShipInterface
492
    {
493
        $this->cy = $cy;
494
        return $this;
495
    }
496
497
    public function getSx(): int
498
    {
499
        return $this->getStarsystemMap()->getSx();
500
    }
501
502
    public function getSy(): int
503
    {
504
        return $this->getStarsystemMap()->getSy();
505
    }
506
507
    public function getFlightDirection(): int
508
    {
509
        return $this->direction;
510
    }
511
512
    public function setFlightDirection(int $direction): ShipInterface
513
    {
514
        $this->direction = $direction;
515
        return $this;
516
    }
517
518
    public function getName(): string
519
    {
520
        return $this->name;
521
    }
522
523
    public function setName(string $name): ShipInterface
524
    {
525
        $this->name = $name;
526
        return $this;
527
    }
528
529
    public function getLSSmode(): int
530
    {
531
        return $this->lss_mode;
532
    }
533
534
    public function isLSSModeNormal(): bool
535
    {
536
        return $this->getLSSMode() === ShipLSSModeEnum::LSS_NORMAL;
537
    }
538
539
    public function isLSSModeBorder(): bool
540
    {
541
        return $this->getLSSMode() === ShipLSSModeEnum::LSS_BORDER;
542
    }
543
544
    public function setLSSMode(int $lssMode): ShipInterface
545
    {
546
        $this->lss_mode = $lssMode;
547
        return $this;
548
    }
549
550
    public function getAlertState(): ShipAlertStateEnum
551
    {
552
        return $this->alvl;
553
    }
554
555
    public function setAlertState(ShipAlertStateEnum $state): ShipInterface
556
    {
557
        $this->alvl = $state;
558
        return $this;
559
    }
560
561
    public function setAlertStateGreen(): ShipInterface
562
    {
563
        return $this->setAlertState(ShipAlertStateEnum::ALERT_GREEN);
564
    }
565
566
    public function isSystemHealthy(ShipSystemTypeEnum $type): bool
567
    {
568
        if (!$this->hasShipSystem($type)) {
569
            return false;
570
        }
571
572
        return $this->getShipSystem($type)->getStatus() > 0;
573
    }
574
575
    public function getSystemState(ShipSystemTypeEnum $type): bool
576
    {
577
        if (!$this->hasShipSystem($type)) {
578
            return false;
579
        }
580
581
        return $this->getShipSystem($type)->getMode() === ShipSystemModeEnum::MODE_ON
582
            || $this->getShipSystem($type)->getMode() === ShipSystemModeEnum::MODE_ALWAYS_ON;
583
    }
584
585
    public function getImpulseState(): bool
586
    {
587
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
588
    }
589
590
    public function getWarpState(): bool
591
    {
592
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
593
    }
594
595
    public function getWebState(): bool
596
    {
597
        return $this->getHoldingWeb() !== null;
598
    }
599
600
    public function getCloakState(): bool
601
    {
602
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_CLOAK);
603
    }
604
605
    public function getTachyonState(): bool
606
    {
607
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
608
    }
609
610
    public function getSubspaceState(): bool
611
    {
612
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
613
    }
614
615
    public function getAstroState(): bool
616
    {
617
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY);
618
    }
619
620
    public function getRPGModuleState(): bool
621
    {
622
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_RPG_MODULE);
623
    }
624
625
    public function getConstructionHubState(): bool
626
    {
627
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_CONSTRUCTION_HUB);
628
    }
629
630
    public function getHull(): int
631
    {
632
        return $this->huelle;
633
    }
634
635
    public function setHuell(int $hull): ShipInterface
636
    {
637
        $this->huelle = $hull;
638
        return $this;
639
    }
640
641
    public function getMaxHull(): int
642
    {
643
        return $this->max_huelle;
644
    }
645
646
    public function setMaxHuell(int $maxHull): ShipInterface
647
    {
648
        $this->max_huelle = $maxHull;
649
        return $this;
650
    }
651
652
    public function getShield(): int
653
    {
654
        return $this->schilde;
655
    }
656
657
    public function setShield(int $schilde): ShipInterface
658
    {
659
        $this->schilde = $schilde;
660
        return $this;
661
    }
662
663
    /**
664
     * proportional to shield system status
665
     */
666
    public function getMaxShield(): int
667
    {
668
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHIELDS)) {
669
            return $this->max_schilde;
670
        }
671
672
        return (int) (ceil($this->max_schilde
673
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_SHIELDS)->getStatus() / 100));
674
    }
675
676
    public function setMaxShield(int $maxShields): ShipInterface
677
    {
678
        $this->max_schilde = $maxShields;
679
        return $this;
680
    }
681
682
    public function getShieldState(): bool
683
    {
684
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_SHIELDS);
685
    }
686
687
    public function getNbs(): bool
688
    {
689
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_NBS);
690
    }
691
692
    public function getLss(): bool
693
    {
694
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_LSS);
695
    }
696
697
    public function getPhaserState(): bool
698
    {
699
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_PHASER);
700
    }
701
702
    public function isAlertGreen(): bool
703
    {
704
        return $this->getAlertState() === ShipAlertStateEnum::ALERT_GREEN;
705
    }
706
707
    public function getTorpedoState(): bool
708
    {
709
        return $this->getSystemState(ShipSystemTypeEnum::SYSTEM_TORPEDO);
710
    }
711
712
    public function getFormerRumpId(): int
713
    {
714
        return $this->former_rumps_id;
715
    }
716
717
    public function setFormerRumpId(int $formerShipRumpId): ShipInterface
718
    {
719
        $this->former_rumps_id = $formerShipRumpId;
720
        return $this;
721
    }
722
723
    public function getTorpedoCount(): int
724
    {
725
        if ($this->getTorpedoStorage() === null) {
726
            return 0;
727
        }
728
729
        return $this->getTorpedoStorage()->getStorage()->getAmount();
730
    }
731
732
    public function isBase(): bool
733
    {
734
        return $this->type === SpacecraftTypeEnum::SPACECRAFT_TYPE_STATION;
735
    }
736
737
    public function isTrumfield(): bool
738
    {
739
        return $this->getRump()->isTrumfield();
740
    }
741
742
    public function isShuttle(): bool
743
    {
744
        return $this->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_SHUTTLE;
745
    }
746
747
    public function isConstruction(): bool
748
    {
749
        return $this->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_CONSTRUCTION;
750
    }
751
752
    public function getSpacecraftType(): int
753
    {
754
        return $this->type;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->type could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
755
    }
756
757
    public function setSpacecraftType(int $type): ShipInterface
758
    {
759
        $this->type = $type;
760
        return $this;
761
    }
762
763
    public function getDatabaseId(): int
764
    {
765
        return $this->database_id;
766
    }
767
768
    public function setDatabaseId(int $databaseEntryId): ShipInterface
769
    {
770
        $this->database_id = $databaseEntryId;
771
        return $this;
772
    }
773
774
    public function isDestroyed(): bool
775
    {
776
        return $this->is_destroyed;
777
    }
778
779
    public function setIsDestroyed(bool $isDestroyed): ShipInterface
780
    {
781
        $this->is_destroyed = $isDestroyed;
782
        return $this;
783
    }
784
785
    public function isDisabled(): bool
786
    {
787
        return $this->disabled;
788
    }
789
790
    public function setDisabled(bool $isDisabled): ShipInterface
791
    {
792
        $this->disabled = $isDisabled;
793
        return $this;
794
    }
795
796
797
798
    /**
799
     * proportional to computer system status
800
     */
801
    public function getHitChance(): int
802
    {
803
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_COMPUTER)) {
804
            return $this->hit_chance;
805
        }
806
807
        return (int) (ceil($this->hit_chance
808
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_COMPUTER)->getStatus() / 100));
809
    }
810
811
    public function setHitChance(int $hitChance): ShipInterface
812
    {
813
        $this->hit_chance = $hitChance;
814
        return $this;
815
    }
816
817
    /**
818
     * proportional to impulsedrive system status
819
     */
820
    public function getEvadeChance(): int
821
    {
822
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE)) {
823
            return $this->evade_chance;
824
        }
825
826
        return (int) (ceil($this->evade_chance
827
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE)->getStatus() / 100));
828
    }
829
830
    public function setEvadeChance(int $evadeChance): ShipInterface
831
    {
832
        $this->evade_chance = $evadeChance;
833
        return $this;
834
    }
835
836
    /**
837
     * proportional to energy weapon system status
838
     */
839
    public function getBaseDamage(): int
840
    {
841
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER)) {
842
            return $this->base_damage;
843
        }
844
845
        return (int) (ceil($this->base_damage
846
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER)->getStatus() / 100));
847
    }
848
849
    public function setBaseDamage(int $baseDamage): ShipInterface
850
    {
851
        $this->base_damage = $baseDamage;
852
        return $this;
853
    }
854
855
    /**
856
     * proportional to sensor system status
857
     */
858
    public function getSensorRange(): int
859
    {
860
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LSS)) {
861
            return $this->sensor_range;
862
        }
863
864
        return (int) (ceil($this->sensor_range
865
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_LSS)->getStatus() / 100));
866
    }
867
868
    public function setSensorRange(int $sensorRange): ShipInterface
869
    {
870
        $this->sensor_range = $sensorRange;
871
        return $this;
872
    }
873
874
    /**
875
     * proportional to tractor beam system status
876
     */
877
    public function getTractorPayload(): int
878
    {
879
        if (!$this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM)) {
880
            return 0;
881
        }
882
883
        return (int) (ceil($this->getRump()->getTractorPayload()
884
            * $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_TRACTOR_BEAM)->getStatus() / 100));
885
    }
886
887
    public function getShieldRegenerationTimer(): int
888
    {
889
        return $this->shield_regeneration_timer;
890
    }
891
892
    public function setShieldRegenerationTimer(int $shieldRegenerationTimer): ShipInterface
893
    {
894
        $this->shield_regeneration_timer = $shieldRegenerationTimer;
895
        return $this;
896
    }
897
898
    public function getState(): ShipStateEnum
899
    {
900
        return $this->state;
901
    }
902
903
    public function setState(ShipStateEnum $state): ShipInterface
904
    {
905
        $this->state = $state;
906
        return $this;
907
    }
908
909
    public function getIsInEmergency(): bool
910
    {
911
        return $this->in_emergency;
912
    }
913
914
    public function setIsInEmergency(bool $inEmergency): ShipInterface
915
    {
916
        $this->in_emergency = $inEmergency;
917
        return $this;
918
    }
919
920
    public function isUnderRepair(): bool
921
    {
922
        return $this->getState() === ShipStateEnum::SHIP_STATE_REPAIR_ACTIVE
923
            || $this->getState() === ShipStateEnum::SHIP_STATE_REPAIR_PASSIVE;
924
    }
925
926
    public function getAstroStartTurn(): ?int
927
    {
928
        return $this->astro_start_turn;
929
    }
930
931
    public function setAstroStartTurn(?int $turn): ShipInterface
932
    {
933
        $this->astro_start_turn = $turn;
934
        return $this;
935
    }
936
937
    public function getIsFleetLeader(): bool
938
    {
939
        return $this->getFleet() !== null && $this->is_fleet_leader;
940
    }
941
942
    public function setIsFleetLeader(bool $isFleetLeader): ShipInterface
943
    {
944
        $this->is_fleet_leader = $isFleetLeader;
945
        return $this;
946
    }
947
948
    public function getCrewAssignments(): Collection
949
    {
950
        return $this->crew;
951
    }
952
953
    public function getPosX(): int
954
    {
955
        if ($this->getSystem() !== null) {
956
            return $this->getSX();
957
        }
958
        return $this->getCX();
959
    }
960
961
    public function getPosY(): int
962
    {
963
        if ($this->getSystem() !== null) {
964
            return $this->getSY();
965
        }
966
        return $this->getCY();
967
    }
968
969
    public function getCrewCount(): int
970
    {
971
        return $this->getCrewAssignments()->count();
972
    }
973
974
    public function getExcessCrewCount(): int
975
    {
976
        return $this->getCrewCount() - $this->getBuildplan()->getCrew();
977
    }
978
979
    public function hasEnoughCrew(?GameControllerInterface $game = null): bool
980
    {
981
        if ($this->getBuildplan() === null) {
982
            if ($game !== null) {
983
                $game->addInformation(_("Keine Crew vorhanden"));
984
            }
985
            return false;
986
        }
987
988
        $result = $this->getBuildplan()->getCrew() <= 0
989
            || $this->getCrewCount() >= $this->getBuildplan()->getCrew();
990
991
        if (!$result && $game !== null) {
992
            $game->addInformationf(
993
                _("Es werden %d Crewmitglieder benötigt"),
994
                $this->getBuildplan()->getCrew()
995
            );
996
        }
997
998
        return $result;
999
    }
1000
1001
    public function getFleet(): ?FleetInterface
1002
    {
1003
        return $this->fleet;
1004
    }
1005
1006
    public function setFleet(?FleetInterface $fleet): ShipInterface
1007
    {
1008
        $this->fleet = $fleet;
1009
        return $this;
1010
    }
1011
1012
    public function isFleetLeader(): bool
1013
    {
1014
        return $this->getIsFleetLeader();
1015
    }
1016
1017
    public function getUser(): UserInterface
1018
    {
1019
        return $this->user;
1020
    }
1021
1022
    public function setUser(UserInterface $user): ShipInterface
1023
    {
1024
        $this->user = $user;
1025
        return $this;
1026
    }
1027
1028
    public function getSystem(): ?StarSystemInterface
1029
    {
1030
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getSystem() : null;
1031
    }
1032
1033
    public function getModules(): array
1034
    {
1035
        $modules = [];
1036
1037
        foreach ($this->getBuildplan()->getModules() as $obj) {
1038
            $module = $obj->getModule();
1039
            $index = $module->getType() === ShipModuleTypeEnum::MODULE_TYPE_SPECIAL ? $module->getId() : $module->getType();
1040
            $modules[$index] = $module;
1041
        }
1042
1043
        if ($this->isBase()) {
1044
            foreach ($this->getSystems() as $system) {
1045
                $module = $system->getModule();
1046
1047
                if ($module !== null) {
1048
                    $index = $module->getType() === ShipModuleTypeEnum::MODULE_TYPE_SPECIAL ? $module->getId() : $module->getType();
1049
                    $modules[$index] = $module;
1050
                }
1051
            }
1052
        }
1053
1054
        return $modules;
1055
    }
1056
1057
    public function isDeflectorHealthy(): bool
1058
    {
1059
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_DEFLECTOR);
1060
    }
1061
1062
    public function isTroopQuartersHealthy(): bool
1063
    {
1064
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TROOP_QUARTERS);
1065
    }
1066
1067
    public function isMatrixScannerHealthy(): bool
1068
    {
1069
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_MATRIX_SCANNER);
1070
    }
1071
1072
    public function isTorpedoStorageHealthy(): bool
1073
    {
1074
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE);
1075
    }
1076
1077
    public function isShuttleRampHealthy(): bool
1078
    {
1079
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
1080
    }
1081
1082
    public function isWebEmitterHealthy(): bool
1083
    {
1084
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_THOLIAN_WEB);
1085
    }
1086
1087
    public function isWarpAble(): bool
1088
    {
1089
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
1090
    }
1091
1092
    public function isTractoring(): bool
1093
    {
1094
        return $this->getTractoredShip() !== null;
1095
    }
1096
1097
    public function isTractored(): bool
1098
    {
1099
        return $this->getTractoringShip() !== null;
1100
    }
1101
1102
    public function isOverColony(): ?ColonyInterface
1103
    {
1104
        return $this->getStarsystemMap() !== null ? $this->getStarsystemMap()->getColony() : null;
1105
    }
1106
1107
    public function isOverSystem(): ?StarSystemInterface
1108
    {
1109
        if ($this->getSystem() !== null) {
1110
            return null;
1111
        }
1112
1113
        return $this->getMap()->getSystem();
1114
    }
1115
1116
    public function isOverWormhole(): bool
1117
    {
1118
        return $this->getMap() !== null && $this->getMap()->getRandomWormholeEntry() !== null;
1119
    }
1120
1121
    public function isWarpPossible(): bool
1122
    {
1123
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE) && $this->getSystem() === null;
1124
    }
1125
1126
    public function getTorpedo(): ?TorpedoTypeInterface
1127
    {
1128
        if ($this->getTorpedoStorage() === null) {
1129
            return null;
1130
        }
1131
1132
        return $this->getTorpedoStorage()->getTorpedo();
1133
    }
1134
1135
    public function getTorpedoStorage(): ?TorpedoStorageInterface
1136
    {
1137
        return $this->torpedoStorage;
1138
    }
1139
1140
    public function setTorpedoStorage(?TorpedoStorageInterface $torpedoStorage): ShipInterface
1141
    {
1142
        $this->torpedoStorage = $torpedoStorage;
1143
        return $this;
1144
    }
1145
1146
    public function getStorage(): Collection
1147
    {
1148
        return $this->storage;
1149
    }
1150
1151
    public function getLogbook(): Collection
1152
    {
1153
        return $this->logbook;
1154
    }
1155
1156
    public function getTakeoverActive(): ?ShipTakeoverInterface
1157
    {
1158
        return $this->takeoverActive;
1159
    }
1160
1161
    public function setTakeoverActive(?ShipTakeoverInterface $takeover): ShipInterface
1162
    {
1163
        $this->takeoverActive = $takeover;
1164
1165
        return $this;
1166
    }
1167
1168
    public function getTakeoverPassive(): ?ShipTakeoverInterface
1169
    {
1170
        return $this->takeoverPassive;
1171
    }
1172
1173
    public function setTakeoverPassive(?ShipTakeoverInterface $takeover): ShipInterface
1174
    {
1175
        $this->takeoverPassive = $takeover;
1176
1177
        return $this;
1178
    }
1179
1180
    public function getStorageSum(): int
1181
    {
1182
        return array_reduce(
1183
            $this->getStorage()->getValues(),
1184
            fn (int $sum, StorageInterface $storage): int => $sum + $storage->getAmount(),
1185
            0
1186
        );
1187
    }
1188
1189
    public function getMaxStorage(): int
1190
    {
1191
        return $this->getRump()->getStorage();
1192
    }
1193
1194
    public function getBeamableStorage(): array
1195
    {
1196
        return array_filter(
1197
            $this->getStorage()->getValues(),
1198
            fn (StorageInterface $storage): bool => $storage->getCommodity()->isBeamable() === true
1199
        );
1200
    }
1201
1202
    public function getTradePost(): ?TradePostInterface
1203
    {
1204
        return $this->tradePost;
1205
    }
1206
1207
    public function setTradePost(?TradePostInterface $tradePost): ShipInterface
1208
    {
1209
        $this->tradePost = $tradePost;
1210
1211
        return $this;
1212
    }
1213
1214
    public function getMap(): ?MapInterface
1215
    {
1216
        return $this->map;
1217
    }
1218
1219
    public function getMapRegion(): ?MapRegionInterface
1220
    {
1221
        $map = $this->getMap();
1222
        if ($map === null) {
1223
            return null;
1224
        }
1225
1226
        return $map->getMapRegion();
1227
    }
1228
1229
    public function updateLocation(?MapInterface $map, ?StarSystemMapInterface $starsystem_map): ShipInterface
1230
    {
1231
        $this->setMap($map);
1232
        $this->setStarsystemMap($starsystem_map);
1233
1234
        return $this;
1235
    }
1236
1237
    public function setMap(?MapInterface $map): ShipInterface
1238
    {
1239
        $this->map = $map;
1240
1241
        if ($map !== null) {
1242
            $this->setLayerId($map->getLayer()->getId());
1243
            $this->setCx($map->getCx());
1244
            $this->setCy($map->getCy());
1245
        }
1246
1247
        return $this;
1248
    }
1249
1250
    public function getStarsystemMap(): ?StarSystemMapInterface
1251
    {
1252
        return $this->starsystem_map;
1253
    }
1254
1255
    public function setStarsystemMap(?StarSystemMapInterface $systemMap): ShipInterface
1256
    {
1257
        $this->starsystem_map = $systemMap;
1258
1259
        if ($systemMap !== null) {
1260
            $system = $systemMap->getSystem();
1261
            $layer = $system->getLayer();
1262
            if ($layer === null) {
1263
                $this->setLayerId(MapEnum::LAYER_ID_WORMHOLES);
1264
            } else {
1265
                $this->setLayerId($layer->getId());
1266
            }
1267
            $this->setCx($systemMap->getSystem()->getCx());
1268
            $this->setCy($systemMap->getSystem()->getCy());
1269
        }
1270
1271
        return $this;
1272
    }
1273
1274
    public function getLocation(): Location
1275
    {
1276
        return new Location($this->getMap(), $this->getStarsystemMap());
1277
    }
1278
1279
    public function getInfluenceArea(): ?StarSystemInterface
1280
    {
1281
        return $this->influenceArea;
1282
    }
1283
1284
    public function setInfluenceArea(?StarSystemInterface $influenceArea): ShipInterface
1285
    {
1286
        $this->influenceArea = $influenceArea;
1287
        return $this;
1288
    }
1289
1290
    public function getBeamFactor(): int
1291
    {
1292
        return $this->getRump()->getBeamFactor();
1293
    }
1294
1295
    public function getSectorString(): string
1296
    {
1297
        if ($this->getStarsystemMap() !== null) {
1298
            return $this->getStarsystemMap()->getSectorString();
1299
        } else {
1300
            return $this->getMap()->getSectorString();
1301
        }
1302
    }
1303
1304
    public function getSectorId(): ?int
1305
    {
1306
        $layer = $this->getLayer();
1307
        if ($layer === null) {
1308
            return null;
1309
        }
1310
1311
        return $layer->getSectorId($this->getMapCX(), $this->getMapCY());
1312
    }
1313
1314
    public function getBuildplan(): ?ShipBuildplanInterface
1315
    {
1316
        return $this->buildplan;
1317
    }
1318
1319
    public function setBuildplan(?ShipBuildplanInterface $shipBuildplan): ShipInterface
1320
    {
1321
        $this->buildplan = $shipBuildplan;
1322
        return $this;
1323
    }
1324
1325
    public function getSystems(): Collection
1326
    {
1327
        return $this->systems;
1328
    }
1329
1330
    public function hasShipSystem(ShipSystemTypeEnum $type): bool
1331
    {
1332
        return $this->getSystems()->containsKey($type->value);
1333
    }
1334
1335
    public function getShipSystem(ShipSystemTypeEnum $type): ShipSystemInterface
1336
    {
1337
        $system = $this->getSystems()->get($type->value);
1338
        if ($system === null) {
1339
            throw new RuntimeException(sprintf('system type %d does not exist on ship', $type->value));
1340
        }
1341
1342
        return $system;
1343
    }
1344
1345
    public function getHealthySystems(): array
1346
    {
1347
        $healthySystems = [];
1348
        foreach ($this->getSystems() as $system) {
1349
            if ($system->getStatus() > 0) {
1350
                $healthySystems[] = $system;
1351
            }
1352
        }
1353
        return $healthySystems;
1354
    }
1355
1356
    public function displayNbsActions(): bool
1357
    {
1358
        return $this->getCloakState() == 0 && $this->getWarpstate() == 0;
1359
    }
1360
1361
    public function isTractorbeamPossible(): bool
1362
    {
1363
        return TractorBeamShipSystem::isTractorBeamPossible($this);
1364
    }
1365
1366
    public function isBoardingPossible(): bool
1367
    {
1368
        return FightLib::isBoardingPossible($this);
1369
    }
1370
1371
    public function isInterceptAble(): bool
1372
    {
1373
        return $this->getWarpState();
1374
    }
1375
1376
    public function getMapCX(): int
1377
    {
1378
        return (int) ceil($this->getCX() / MapEnum::FIELDS_PER_SECTION);
1379
    }
1380
1381
    public function getMapCY(): int
1382
    {
1383
        return (int) ceil($this->getCY() / MapEnum::FIELDS_PER_SECTION);
1384
    }
1385
1386
    public function dockedOnTradePost(): bool
1387
    {
1388
        return $this->getDockedTo() && $this->getDockedTo()->getTradePost() !== null;
1389
    }
1390
1391
    public function getDockPrivileges(): Collection
1392
    {
1393
        return $this->dockingPrivileges;
1394
    }
1395
1396
    public function getDockingSlotCount(): int
1397
    {
1398
        return ($this->getState() === ShipStateEnum::SHIP_STATE_UNDER_CONSTRUCTION)
1399
            || ($this->getState() === ShipStateEnum::SHIP_STATE_UNDER_SCRAPPING)
1400
            ? 50 : $this->getRump()->getDockingSlots();
1401
    }
1402
1403
    public function hasFreeDockingSlots(): bool
1404
    {
1405
        return $this->getDockingSlotCount() > $this->getDockedShipCount();
1406
    }
1407
1408
    public function getFreeDockingSlotCount(): int
1409
    {
1410
        return $this->getDockingSlotCount() - $this->getDockedShipCount();
1411
    }
1412
1413
    public function getDockedShipCount(): int
1414
    {
1415
        return $this->dockedShips->count();
1416
    }
1417
1418
    public function getTractoredShip(): ?ShipInterface
1419
    {
1420
        return $this->tractoredShip;
1421
    }
1422
1423
    public function setTractoredShip(?ShipInterface $ship): ShipInterface
1424
    {
1425
        $this->tractoredShip = $ship;
1426
        return $this;
1427
    }
1428
1429
    public function setTractoredShipId(?int $shipId): ShipInterface
1430
    {
1431
        $this->tractored_ship_id = $shipId;
1432
        return $this;
1433
    }
1434
1435
    public function getTractoringShip(): ?ShipInterface
1436
    {
1437
        return $this->tractoringShip;
1438
    }
1439
1440
    public function setTractoringShip(?ShipInterface $ship): ShipInterface
1441
    {
1442
        $this->tractoringShip = $ship;
1443
        return $this;
1444
    }
1445
1446
    public function getHoldingWeb(): ?TholianWebInterface
1447
    {
1448
        return $this->holdingWeb;
1449
    }
1450
1451
    public function setHoldingWeb(?TholianWebInterface $web): ShipInterface
1452
    {
1453
        $this->holdingWeb = $web;
1454
1455
        if ($web === null) {
1456
            $this->holding_web_id = null;
1457
        }
1458
1459
        return $this;
1460
    }
1461
1462
    public function getHoldingWebBackgroundStyle(): string
1463
    {
1464
        if ($this->getHoldingWeb() === null) {
1465
            return '';
1466
        }
1467
1468
        if ($this->getHoldingWeb()->isFinished()) {
1469
            $icon =  'web.png';
1470
        } else {
1471
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1472
1473
            $icon = $closeTofinish ? 'web_u.png' : 'web_u2.png';
1474
        }
1475
1476
        return sprintf('src="assets/buttons/%s"; class="indexedGraphics" style="z-index: 5;"', $icon);
1477
    }
1478
1479
    public function getHoldingWebImageStyle(): string
1480
    {
1481
        if ($this->getHoldingWeb() === null) {
1482
            return '';
1483
        }
1484
1485
        if ($this->getHoldingWeb()->isFinished()) {
1486
            $icon =  'webfill.png';
1487
        } else {
1488
            $closeTofinish = $this->getHoldingWeb()->getFinishedTime() - time() < TimeConstants::ONE_HOUR_IN_SECONDS;
1489
1490
            $icon = $closeTofinish ? 'web_ufill.png' : 'web_ufill2.png';
1491
        }
1492
1493
        return $icon;
1494
    }
1495
1496
    public function getCurrentMapField(): StarSystemMapInterface|MapInterface
1497
    {
1498
        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...
1499
    }
1500
1501
    private function getShieldRegenerationPercentage(): int
1502
    {
1503
        return $this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_SHIELDS) ? 10 : 0;
1504
    }
1505
1506
    public function getShieldRegenerationRate(): int
1507
    {
1508
        return (int) ceil(($this->getMaxShield() / 100) * $this->getShieldRegenerationPercentage());
1509
    }
1510
1511
    public function canIntercept(): bool
1512
    {
1513
        return !$this->isTractored() && !$this->isTractoring();
1514
    }
1515
1516
    public function canMove(): bool
1517
    {
1518
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE)
1519
            || $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_IMPULSEDRIVE);
1520
    }
1521
1522
    public function hasActiveWeapon(): bool
1523
    {
1524
        return $this->getPhaserState() || $this->getTorpedoState();
1525
    }
1526
1527
    public function hasEscapePods(): bool
1528
    {
1529
        return $this->getRump()->isEscapePods() && $this->getCrewCount() > 0;
1530
    }
1531
1532
    public function getRepairRate(): int
1533
    {
1534
        // @todo
1535
        return 100;
1536
    }
1537
1538
    public function getRump(): ShipRumpInterface
1539
    {
1540
        return $this->rump;
1541
    }
1542
1543
    public function getRumpId(): int
1544
    {
1545
        return $this->rumps_id;
1546
    }
1547
1548
    public function getRumpName(): string
1549
    {
1550
        return $this->getRump()->getName();
1551
    }
1552
1553
    public function setRump(ShipRumpInterface $shipRump): ShipInterface
1554
    {
1555
        $this->rump = $shipRump;
1556
        return $this;
1557
    }
1558
1559
    public function hasPhaser(): bool
1560
    {
1561
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_PHASER);
1562
    }
1563
1564
    public function hasTorpedo(): bool
1565
    {
1566
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TORPEDO);
1567
    }
1568
1569
    public function hasCloak(): bool
1570
    {
1571
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_CLOAK);
1572
    }
1573
1574
    public function hasTachyonScanner(): bool
1575
    {
1576
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TACHYON_SCANNER);
1577
    }
1578
1579
    public function hasShuttleRamp(): bool
1580
    {
1581
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP);
1582
    }
1583
1584
    public function hasSubspaceScanner(): bool
1585
    {
1586
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SUBSPACE_SCANNER);
1587
    }
1588
1589
    public function hasAstroLaboratory(): bool
1590
    {
1591
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_ASTRO_LABORATORY);
1592
    }
1593
1594
    public function hasWarpdrive(): bool
1595
    {
1596
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
1597
    }
1598
1599
    public function hasRPGModule(): bool
1600
    {
1601
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_RPG_MODULE);
1602
    }
1603
1604
    public function hasNbsLss(): bool
1605
    {
1606
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LSS);
1607
    }
1608
1609
    public function hasUplink(): bool
1610
    {
1611
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_UPLINK);
1612
    }
1613
1614
    public function hasTranswarp(): bool
1615
    {
1616
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL);
1617
    }
1618
1619
    public function getTranswarpCooldown(): ?int
1620
    {
1621
        $cooldown = $this->getShipSystem(ShipSystemTypeEnum::SYSTEM_TRANSWARP_COIL)->getCooldown();
1622
1623
        return $cooldown > time() ? $cooldown : null;
1624
    }
1625
1626
    public function getMaxTorpedos(): int
1627
    {
1628
        return $this->getRump()->getBaseTorpedoStorage()
1629
            + ($this->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_TORPEDO_STORAGE)
1630
                ? TorpedoStorageShipSystem::TORPEDO_CAPACITY : 0);
1631
    }
1632
1633
    public function getDockedShips(): Collection
1634
    {
1635
        return $this->dockedShips;
1636
    }
1637
1638
    public function getDockedTo(): ?ShipInterface
1639
    {
1640
        return $this->dockedTo;
1641
    }
1642
1643
    public function setDockedTo(?ShipInterface $dockedTo): ShipInterface
1644
    {
1645
        $this->dockedTo = $dockedTo;
1646
        return $this;
1647
    }
1648
1649
    public function setDockedToId(?int $dockedToId): ShipInterface
1650
    {
1651
        $this->dock = $dockedToId;
1652
        return $this;
1653
    }
1654
1655
    public function hasFreeShuttleSpace(?LoggerUtilInterface $loggerUtil = null): bool
1656
    {
1657
        if ($loggerUtil !== null) {
1658
            $loggerUtil->log(sprintf('rumpShuttleSlots: %d', $this->getRump()->getShuttleSlots()));
1659
            $loggerUtil->log(sprintf('storedShuttleCount: %d', $this->getStoredShuttleCount()));
1660
        }
1661
        return $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_SHUTTLE_RAMP)
1662
            && $this->getRump()->getShuttleSlots() - $this->getStoredShuttleCount() > 0;
1663
    }
1664
1665
    public function getStoredShuttles(): array
1666
    {
1667
        $shuttles = [];
1668
1669
        foreach ($this->getStorage() as $stor) {
1670
            if ($stor->getCommodity()->isShuttle()) {
1671
                $shuttles[] = $stor->getCommodity();
1672
            }
1673
        }
1674
1675
        return $shuttles;
1676
    }
1677
1678
    public function getStoredShuttleCount(): int
1679
    {
1680
        $count = 0;
1681
1682
        foreach ($this->getStorage() as $stor) {
1683
            if ($stor->getCommodity()->isShuttle()) {
1684
                $count += $stor->getAmount();
1685
            }
1686
        }
1687
1688
        return $count;
1689
    }
1690
1691
    public function getDockedWorkbeeCount(): int
1692
    {
1693
        $count = 0;
1694
1695
        foreach ($this->getDockedShips() as $ships) {
1696
            if ($ships->getRump()->getCategoryId() === ShipRumpEnum::SHIP_CATEGORY_SHUTTLE) {
1697
                $count += 1;
1698
            }
1699
        }
1700
1701
        return $count;
1702
    }
1703
1704
    public function canMan(): bool
1705
    {
1706
        return $this->getCrewCount() === 0
1707
            && $this->getBuildplan() !== null
1708
            && $this->getBuildplan()->getCrew() > 0
1709
            && $this->hasShipSystem(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT);
1710
    }
1711
1712
    public function canBuildConstruction(): bool
1713
    {
1714
        return StationUtility::canShipBuildConstruction($this);
1715
    }
1716
1717
    public function hasCrewmanOfUser(int $userId): bool
1718
    {
1719
        foreach ($this->getCrewAssignments() as $shipCrew) {
1720
            if ($shipCrew->getCrew()->getUser()->getId() === $userId) {
1721
                return true;
1722
            }
1723
        }
1724
1725
        return false;
1726
    }
1727
1728
    public function __toString(): string
1729
    {
1730
        if ($this->id !== null) {
1731
            return sprintf('id: %d, name: %s', $this->getId(), $this->getName());
1732
        }
1733
1734
        return $this->getName();
1735
    }
1736
1737
    public function getHullColorStyle(): string
1738
    {
1739
        return $this->getColorStyle($this->getHull(), $this->getMaxHull());
1740
    }
1741
1742
    private function getColorStyle(int $actual, int $max): string
1743
    {
1744
        // full
1745
        if ($actual === $max) {
1746
            return '';
1747
        }
1748
1749
        // less than 100% - green
1750
        if ($actual / $max > 0.75) {
1751
            return 'color: #19c100;';
1752
        }
1753
1754
        // less than 75% - yellow
1755
        if ($actual / $max > 0.50) {
1756
            return 'color: #f4e932;';
1757
        }
1758
1759
        // less than 50% - orange
1760
        if ($actual / $max > 0.25) {
1761
            return 'color: #f48b28;';
1762
        }
1763
1764
        // less than 25% - red
1765
        return 'color: #ff3c3c;';
1766
    }
1767
}
1768