Passed
Push — dev ( 70a2b2...33c686 )
by Janko
21:40
created

Ship::getReactorLoadStyle()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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