Test Failed
Push — master ( f13730...efaef4 )
by Nico
22:43 queued 11:31
created

Ship   F

Complexity

Total Complexity 292

Size/Duplication

Total Lines 1619
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 563
c 1
b 0
f 0
dl 0
loc 1619
ccs 0
cts 609
cp 0
rs 2
wmc 292

209 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubspaceState() 0 3 1
A getAstroState() 0 3 1
A setFleetId() 0 4 1
A getSystemsId() 0 3 2
A __construct() 0 8 1
A getUserId() 0 3 1
A getUserName() 0 3 1
A getId() 0 7 2
A getFleetId() 0 3 1
A setTractoredShipId() 0 4 1
A hasRPGModule() 0 3 1
A getCurrentMapField() 0 3 1
A getTorpedoCount() 0 7 2
A isFleetLeader() 0 3 1
A hasCloak() 0 3 1
A getWebState() 0 3 1
A setShield() 0 4 1
A hasTranswarp() 0 3 1
A getConstructionHubState() 0 3 1
A getShieldState() 0 3 1
A setAlertState() 0 4 1
A getTractorPayload() 0 8 2
A getTakeoverPassive() 0 3 1
A setMaxHuell() 0 4 1
A getImpulseState() 0 3 1
A getBuildplan() 0 3 1
A setCx() 0 4 1
A isOverSystem() 0 7 2
A getLocation() 0 3 1
A getCrewCount() 0 3 1
A setDisabled() 0 4 1
A canMove() 0 4 2
A isTrumfield() 0 3 1
A isConstruction() 0 3 1
A getMapCX() 0 3 1
A getSystems() 0 3 1
A getSystem() 0 3 2
A setTorpedoStorage() 0 4 1
A isLSSModeBorder() 0 3 1
A isSystemHealthy() 0 7 2
A getSystemState() 0 8 3
A isUnderRepair() 0 4 2
A hasTachyonScanner() 0 3 1
A isTractored() 0 3 1
A setTakeoverPassive() 0 5 1
A getMapRegion() 0 8 2
A getShipSystem() 0 8 2
A getTractoredShip() 0 3 1
A getSy() 0 3 1
A getPosY() 0 6 2
A getLayer() 0 3 1
A isTractoring() 0 3 1
A hasUplink() 0 3 1
A getBeamFactor() 0 3 1
A getDockPrivileges() 0 3 1
A hasFreeDockingSlots() 0 3 1
A getTractoringShip() 0 3 1
A getHoldingWeb() 0 3 1
A isShuttleRampHealthy() 0 3 1
A setDockedTo() 0 4 1
A getName() 0 3 1
A getHoldingWebBackgroundStyle() 0 15 4
A setHitChance() 0 4 1
A getSpacecraftType() 0 3 1
A setName() 0 4 1
A getDockingSlotCount() 0 5 3
A getLSSmode() 0 3 1
A getShieldRegenerationTimer() 0 3 1
A getStoredShuttleCount() 0 11 3
A setEvadeChance() 0 4 1
A getHull() 0 3 1
A setTractoredShip() 0 4 1
A getShieldRegenerationRate() 0 3 1
A isOverWormhole() 0 3 2
A setBuildplan() 0 4 1
A setStarsystemMap() 0 17 3
A updateLocation() 0 13 3
A getTakeoverActive() 0 3 1
A getEvadeChance() 0 8 2
A getPhaserState() 0 3 1
A getLss() 0 3 1
A isMatrixScannerHealthy() 0 3 1
A isDestroyed() 0 3 1
A getSx() 0 3 1
A getMaxStorage() 0 3 1
A hasNbsLss() 0 3 1
A getCy() 0 3 1
A getExcessCrewCount() 0 3 1
A getTranswarpCooldown() 0 5 2
A setUser() 0 4 1
A setSpacecraftType() 0 4 1
A getDockedShips() 0 3 1
A setRump() 0 4 1
A setInfluenceArea() 0 4 1
A setDatabaseId() 0 4 1
A hasEscapePods() 0 3 2
A getMap() 0 3 1
A getUser() 0 3 1
A getIsFleetLeader() 0 3 2
A setAlertStateGreen() 0 3 1
A setFormerRumpId() 0 4 1
A setFlightDirection() 0 4 1
A hasActiveWeapon() 0 3 2
A isOverColony() 0 3 2
A getShield() 0 3 1
A getHoldingWebImageStyle() 0 15 4
A getBaseDamage() 0 8 2
A setFleet() 0 4 1
A setBaseDamage() 0 4 1
A setDockedToId() 0 4 1
A isBoardingPossible() 0 3 1
A hasTorpedo() 0 3 1
A hasWarpdrive() 0 3 1
A dockedOnTradePost() 0 3 2
A getCloakState() 0 3 1
A hasShipSystem() 0 3 1
A getSectorId() 0 8 2
A setMaxShield() 0 4 1
A getFleet() 0 3 1
A isShuttle() 0 3 1
B getModules() 0 27 8
A getHealthySystems() 0 9 3
A setIsFleetLeader() 0 4 1
A setShieldRegenerationTimer() 0 4 1
A getAstroStartTurn() 0 3 1
A getRumpName() 0 3 1
A getHitChance() 0 8 2
A hasFreeShuttleSpace() 0 8 3
A getMapCY() 0 3 1
A getDockedTo() 0 3 1
A getFormerRumpId() 0 3 1
A setHuell() 0 4 1
A getRepairRate() 0 4 1
A hasAstroLaboratory() 0 3 1
A getShieldRegenerationPercentage() 0 3 2
A getTachyonState() 0 3 1
A getMaxTorpedos() 0 5 2
A hasPhaser() 0 3 1
A getRPGModuleState() 0 3 1
A setIsInEmergency() 0 4 1
A getTorpedoState() 0 3 1
A setMap() 0 11 2
A setTradePost() 0 5 1
A getMaxShield() 0 8 2
A getLayerId() 0 3 1
A hasSubspaceScanner() 0 3 1
A isTractorbeamPossible() 0 3 1
A getSectorString() 0 6 2
A setLSSMode() 0 4 1
A setLayerId() 0 4 1
A getRumpId() 0 3 1
A getState() 0 3 1
A getBeamableStorage() 0 5 1
A getLogbook() 0 3 1
A getInfluenceArea() 0 3 1
A getPosX() 0 6 2
A isInterceptAble() 0 3 1
A isAlertGreen() 0 3 1
A getFlightDirection() 0 3 1
A canIntercept() 0 3 2
A hasShuttleRamp() 0 3 1
A setTakeoverActive() 0 5 1
A getTorpedo() 0 7 2
A getDockedShipCount() 0 3 1
A isLSSModeNormal() 0 3 1
A getFreeDockingSlotCount() 0 3 1
A getMaxHull() 0 3 1
A getStorageSum() 0 6 1
A getRump() 0 3 1
A getStoredShuttles() 0 11 3
A setIsDestroyed() 0 4 1
A getDatabaseId() 0 3 1
A hasEnoughCrew() 0 22 6
A isDisabled() 0 3 1
A isWarpPossible() 0 3 2
A setState() 0 4 1
A getTorpedoStorage() 0 3 1
A setAstroStartTurn() 0 4 1
A getCrewAssignments() 0 3 1
A isDeflectorHealthy() 0 3 1
A isTorpedoStorageHealthy() 0 3 1
A getAlertState() 0 3 1
A getNbs() 0 3 1
A getStorage() 0 3 1
A isWarpAble() 0 3 1
A getStarsystemMap() 0 3 1
A setTractoringShip() 0 4 1
A isWebEmitterHealthy() 0 3 1
A isTroopQuartersHealthy() 0 3 1
A getCx() 0 3 1
A getTradePost() 0 3 1
A getNeededCrewCount() 0 8 2
A setSensorRange() 0 4 1
A getSensorRange() 0 8 2
A getWarpState() 0 3 1
A setCy() 0 4 1
A getIsInEmergency() 0 3 1
A isBase() 0 3 1
A setHoldingWeb() 0 9 2
A displayNbsActions() 0 3 2
A getDockedWorkbeeCount() 0 11 3
A getColorStyle() 0 24 5
A getHullColorStyle() 0 3 1
A canMan() 0 7 3
A canBuildConstruction() 0 3 1
A hasCrewmanOfUser() 0 9 3
A hasStoredBuoy() 0 3 1
A __toString() 0 7 2
A getStoredBuoy() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like Ship often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Ship, and based on these observations, apply Extract Interface, too.

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