Passed
Push — dev ( eeaa0f...91a85a )
by Janko
26:10
created

ShipTick::sendMessages()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 3
nop 1
dl 0
loc 21
ccs 0
cts 15
cp 0
crap 20
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
namespace Stu\Module\Tick\Ship;
4
5
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
6
use RuntimeException;
7
use Stu\Component\Ship\AstronomicalMappingEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Component\Ship\AstronomicalMappingEnum 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...
8
use Stu\Component\Ship\Repair\RepairUtilInterface;
9
use Stu\Component\Ship\ShipAlertStateEnum;
10
use Stu\Component\Ship\ShipStateEnum;
11
use Stu\Component\Ship\System\Data\EpsSystemData;
12
use Stu\Component\Ship\System\ShipSystemManagerInterface;
13
use Stu\Component\Ship\System\ShipSystemTypeEnum;
14
use Stu\Component\Station\StationUtilityInterface;
15
use Stu\Module\Control\GameControllerInterface;
16
use Stu\Module\Database\Lib\CreateDatabaseEntryInterface;
17
use Stu\Module\Logging\LoggerUtilFactoryInterface;
18
use Stu\Module\Logging\LoggerUtilInterface;
19
use Stu\Module\Message\Lib\PrivateMessageFolderTypeEnum;
20
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
21
use Stu\Module\PlayerSetting\Lib\UserEnum;
0 ignored issues
show
Bug introduced by
The type Stu\Module\PlayerSetting\Lib\UserEnum 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\Module\Ship\Lib\AstroEntryLibInterface;
23
use Stu\Module\Ship\Lib\Crew\ShipLeaverInterface;
24
use Stu\Module\Ship\Lib\Interaction\ShipTakeoverManagerInterface;
25
use Stu\Module\Ship\Lib\Interaction\TrackerDeviceManagerInterface;
26
use Stu\Module\Ship\Lib\ReactorWrapperInterface;
27
use Stu\Module\Ship\Lib\ShipRemoverInterface;
28
use Stu\Module\Ship\Lib\ShipWrapperFactoryInterface;
29
use Stu\Module\Ship\Lib\ShipWrapperInterface;
30
use Stu\Module\Ship\View\ShowShip\ShowShip;
0 ignored issues
show
Bug introduced by
The type Stu\Module\Ship\View\ShowShip\ShowShip was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
31
use Stu\Module\Tick\Ship\ManagerComponent\ManagerComponentInterface;
32
use Stu\Module\Tick\User\UserTickComponentInterface;
33
use Stu\Orm\Entity\DatabaseEntryInterface;
34
use Stu\Orm\Entity\ShipInterface;
35
use Stu\Orm\Entity\UserInterface;
36
use Stu\Orm\Repository\DatabaseUserRepositoryInterface;
37
use Stu\Orm\Repository\ShipRepositoryInterface;
38
39
final class ShipTick implements ShipTickInterface, ManagerComponentInterface, UserTickComponentInterface
40
{
41
    private LoggerUtilInterface $loggerUtil;
42
43
    /**
44
     * @var array<string>
45
     */
46
    private array $msg = [];
47
48
    public function __construct(
49
        private ShipWrapperFactoryInterface $shipWrapperFactory,
50
        private PrivateMessageSenderInterface $privateMessageSender,
51
        private ShipRepositoryInterface $shipRepository,
52
        private ShipSystemManagerInterface $shipSystemManager,
53
        private ShipLeaverInterface $shipLeaver,
54
        private GameControllerInterface $game,
55
        private AstroEntryLibInterface $astroEntryLib,
56
        private DatabaseUserRepositoryInterface $databaseUserRepository,
57
        private CreateDatabaseEntryInterface $createDatabaseEntry,
58
        private StationUtilityInterface $stationUtility,
59
        private RepairUtilInterface $repairUtil,
60
        private ShipTakeoverManagerInterface $shipTakeoverManager,
61
        private TrackerDeviceManagerInterface $trackerDeviceManager,
62
        private ShipRemoverInterface $shipRemover,
63
        LoggerUtilFactoryInterface $loggerUtilFactory
64
    ) {
65
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil(true);
66
    }
67
68
    #[Override]
69
    public function work(): void
70
    {
71
        foreach ($this->shipRepository->getPlayerShipsForTick() as $ship) {
72
            $this->workShip($this->shipWrapperFactory->wrapShip($ship));
73
        }
74
    }
75
76
    #[Override]
77
    public function processUser(UserInterface $user): void
78
    {
79
        foreach ($this->shipRepository->getByUser($user) as $ship) {
80
            $this->workShip($this->shipWrapperFactory->wrapShip($ship));
81
        }
82
83
        $this->lowerStationConstructionHull($user);
84
    }
85
86
    #[Override]
87
    public function workShip(ShipWrapperInterface $wrapper): void
88
    {
89
        $ship = $wrapper->get();
90
91
        $startTime = microtime(true);
92
93
        // do construction stuff
94
        if ($this->doConstructionStuff($ship)) {
95
            $this->shipRepository->save($ship);
96
            $this->sendMessages($ship);
97
            return;
98
        }
99
100
        $this->potentialLog($ship, "marker0", $startTime);
0 ignored issues
show
Bug introduced by
It seems like $startTime can also be of type string; however, parameter $startTime of Stu\Module\Tick\Ship\ShipTick::potentialLog() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

100
        $this->potentialLog($ship, "marker0", /** @scrutinizer ignore-type */ $startTime);
Loading history...
101
102
103
        $startTime = microtime(true);
104
        // repair station
105
        if ($ship->isBase() && $ship->getState() === ShipStateEnum::SHIP_STATE_REPAIR_PASSIVE) {
106
            $this->doRepairStation($wrapper);
107
        }
108
        $this->potentialLog($ship, "marker1", $startTime);
109
110
        $startTime = microtime(true);
111
        // leave ship
112
        if ($ship->getCrewCount() > 0 && !$ship->isSystemHealthy(ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT)) {
113
            $this->msg[] = _('Die Lebenserhaltung ist ausgefallen:');
114
            $this->msg[] = $this->shipLeaver->evacuate($wrapper);
115
            $this->sendMessages($ship);
116
            $this->potentialLog($ship, "marker2", $startTime);
117
            return;
118
        }
119
120
        $startTime = microtime(true);
121
        $eps = $wrapper->getEpsSystemData();
122
        $reactor = $wrapper->getReactorWrapper();
123
        if ($eps === null) {
124
            $this->potentialLog($ship, "marker3", $startTime);
125
            return;
126
        }
127
128
        $startTime = microtime(true);
129
        $hasEnoughCrew = $ship->hasEnoughCrew();
130
131
        // not enough crew
132
        if (!$hasEnoughCrew) {
133
            $this->msg[] = _('Zu wenig Crew an Bord, Schiff ist nicht voll funktionsfähig! Systeme werden deaktiviert!');
134
135
            //deactivate all systems except life support
136
            foreach ($this->shipSystemManager->getActiveSystems($ship) as $system) {
137
                if ($system->getSystemType() != ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT) {
138
                    $this->shipSystemManager->deactivate($wrapper, $system->getSystemType(), true);
139
                }
140
            }
141
        }
142
        $this->potentialLog($ship, "marker4", $startTime);
143
144
        $startTime = microtime(true);
145
        $reactorUsageForWarpdrive = $this->loadWarpdrive(
146
            $wrapper,
147
            $hasEnoughCrew
148
        );
149
        $this->potentialLog($ship, "marker5", $startTime);
150
151
        $startTime = microtime(true);
152
        $availableEps = $this->getAvailableEps(
153
            $wrapper,
154
            $eps,
155
            $reactor,
156
            $hasEnoughCrew,
157
            $reactorUsageForWarpdrive
158
        );
159
        $this->potentialLog($ship, "marker6", $startTime);
160
161
        $startTime = microtime(true);
162
        //try to save energy by reducing alert state
163
        if ($wrapper->getEpsUsage() > $availableEps) {
164
            $malus = $wrapper->getEpsUsage() - $availableEps;
165
            $alertUsage = $ship->getAlertState()->value - 1;
166
167
            if ($alertUsage > 0) {
168
                $preState = $ship->getAlertState();
169
                $reduce = (int)min($malus, $alertUsage);
170
171
                $ship->setAlertState(ShipAlertStateEnum::from($preState->value - $reduce));
172
                $this->msg[] = sprintf(
173
                    _('Wechsel von %s auf %s wegen Energiemangel'),
174
                    $preState->getDescription(),
175
                    $ship->getAlertState()->getDescription()
176
                );
177
            }
178
        }
179
        $this->potentialLog($ship, "marker7", $startTime);
180
181
        $startTime = microtime(true);
182
        //try to save energy by deactivating systems from low to high priority
183
        if ($wrapper->getEpsUsage() > $availableEps) {
184
            $activeSystems = $this->shipSystemManager->getActiveSystems($ship, true);
185
186
            foreach ($activeSystems as $system) {
187
                $energyConsumption = $this->shipSystemManager->getEnergyConsumption($system->getSystemType());
188
                if ($energyConsumption < 1) {
189
                    continue;
190
                }
191
192
                //echo "- eps: ".$eps." - usage: ".$wrapper->getEpsUsage()."\n";
193
                if ($availableEps - $wrapper->getEpsUsage() - $energyConsumption < 0) {
194
                    //echo "-- hit system: ".$system->getDescription()."\n";
195
196
                    $this->shipSystemManager->deactivate($wrapper, $system->getSystemType(), true);
197
198
                    $wrapper->lowerEpsUsage($energyConsumption);
199
                    $this->msg[] = $system->getSystemType()->getDescription() . ' deaktiviert wegen Energiemangel';
200
201
                    if ($ship->getCrewCount() > 0 && $system->getSystemType() == ShipSystemTypeEnum::SYSTEM_LIFE_SUPPORT) {
202
                        $this->msg[] = _('Die Lebenserhaltung ist ausgefallen:');
203
                        $this->msg[] = $this->shipLeaver->evacuate($wrapper);
204
                        $this->sendMessages($ship);
205
                        return;
206
                    }
207
                }
208
                if ($wrapper->getEpsUsage() <= $availableEps) {
209
                    break;
210
                }
211
            }
212
        }
213
214
        $this->potentialLog($ship, "marker8", $startTime);
215
        $startTime = microtime(true);
216
217
        $newEps = $availableEps - $wrapper->getEpsUsage();
218
        $batteryReload = $ship->isBase()
219
            && $eps->reloadBattery()
220
            && $newEps > $eps->getEps()
221
            ? min(
222
                (int) ceil($eps->getMaxBattery() / 10),
223
                $newEps - $eps->getEps(),
224
                $eps->getMaxBattery() - $eps->getBattery()
225
            ) : 0;
226
227
        $newEps -= $batteryReload;
228
        if ($newEps > $eps->getMaxEps()) {
229
            $newEps = $eps->getMaxEps();
230
        }
231
232
233
        $usedEnergy = $wrapper->getEpsUsage() + $batteryReload + ($newEps - $eps->getEps()) + $reactorUsageForWarpdrive;
234
235
        //echo "--- Generated Id ".$ship->getId()." - eps: ".$eps." - usage: ".$wrapper->getEpsUsage()." - old eps: ".$ship->getEps()." - wk: ".$wkuse."\n";
236
        $eps->setEps($newEps)
237
            ->setBattery($eps->getBattery() + $batteryReload)
238
            ->update();
239
240
        if ($usedEnergy > 0 && $reactor !== null) {
241
            $reactor->changeLoad(-$usedEnergy);
242
        }
243
244
        $this->potentialLog($ship, "marker9", $startTime);
245
246
        $startTime = microtime(true);
247
        $this->checkForFinishedTakeover($ship);
248
        $this->potentialLog($ship, "marker10", $startTime);
249
250
        $startTime = microtime(true);
251
        $this->checkForFinishedAstroMapping($wrapper);
252
        $this->potentialLog($ship, "marker11", $startTime);
253
254
        //update tracker status
255
        $startTime = microtime(true);
256
        $this->doTrackerDeviceStuff($wrapper);
257
        $this->potentialLog($ship, "marker12", $startTime);
258
259
        $startTime = microtime(true);
260
        $this->shipRepository->save($ship);
261
        $this->potentialLog($ship, "marker13", $startTime);
262
263
        $startTime = microtime(true);
264
        $this->sendMessages($ship);
265
        $this->potentialLog($ship, "marker14", $startTime);
266
    }
267
268
    private function potentialLog(ShipInterface $ship, string $marker, float $startTime): void
269
    {
270
        $endTime = microtime(true);
271
272
        if (
273
            $endTime - $startTime > 0.01
274
        ) {
275
            $this->loggerUtil->log(sprintf(
276
                "\t\t\t%s of %d, seconds: %F",
277
                $marker,
278
                $ship->getId(),
279
                $endTime - $startTime
280
            ));
281
        }
282
    }
283
284
    private function getAvailableEps(
285
        ShipWrapperInterface $wrapper,
286
        EpsSystemData $eps,
287
        ?ReactorWrapperInterface $reactor,
288
        bool $hasEnoughCrew,
289
        int $reactorUsageForWarpdrive
290
    ): int {
291
        if ($hasEnoughCrew && $reactor !== null) {
292
293
            return $eps->getEps() + $reactor->getEpsProduction() +  $this->getCarryOver(
294
                $wrapper,
295
                $reactor,
296
                $reactorUsageForWarpdrive
297
            );
298
        }
299
300
        return $eps->getEps();
301
    }
302
303
    private function getCarryOver(
304
        ShipWrapperInterface $wrapper,
305
        ReactorWrapperInterface $reactor,
306
        int $reactorUsageForWarpdrive
307
    ): int {
308
        $warpdrive = $wrapper->getWarpDriveSystemData();
309
        if ($warpdrive === null || !$warpdrive->getAutoCarryOver()) {
310
            return 0;
311
        }
312
313
        return $reactor->getOutputCappedByLoad() - $reactor->getEpsProduction() - $reactorUsageForWarpdrive;
314
    }
315
316
    private function loadWarpdrive(ShipWrapperInterface $wrapper, bool $hasEnoughCrew): int
317
    {
318
        if (!$hasEnoughCrew) {
319
            return 0;
320
        }
321
322
        $reactor = $wrapper->getReactorWrapper();
323
        $warpdrive = $wrapper->getWarpDriveSystemData();
324
        if ($warpdrive === null || $reactor === null) {
325
            return 0;
326
        }
327
328
        $effectiveWarpdriveProduction = $reactor->getEffectiveWarpDriveProduction();
329
        if ($effectiveWarpdriveProduction === 0) {
330
            return 0;
331
        }
332
333
        $currentLoad = $warpdrive->getWarpDrive();
334
335
        $warpdrive->setWarpDrive($currentLoad + $effectiveWarpdriveProduction)->update();
336
337
        return $effectiveWarpdriveProduction * $wrapper->get()->getRump()->getFlightECost();
338
    }
339
340
    private function doConstructionStuff(ShipInterface $ship): bool
341
    {
342
        $progress =  $this->stationUtility->getConstructionProgress($ship);
343
344
        if ($progress === null) {
345
            return false;
346
        }
347
348
        if ($progress->getRemainingTicks() === 0) {
349
            return false;
350
        }
351
352
        $isUnderConstruction = $ship->getState() === ShipStateEnum::SHIP_STATE_UNDER_CONSTRUCTION;
353
354
        if (!$this->stationUtility->hasEnoughDockedWorkbees($ship, $ship->getRump())) {
355
            $neededWorkbees = $isUnderConstruction ? $ship->getRump()->getNeededWorkbees() :
356
                (int)ceil($ship->getRump()->getNeededWorkbees() / 2);
357
358
            $this->msg[] = sprintf(
359
                _('Nicht genügend Workbees (%d/%d) angedockt um %s weiterführen zu können'),
360
                $this->stationUtility->getDockedWorkbeeCount($ship),
361
                $neededWorkbees,
362
                $isUnderConstruction ? 'den Bau' : 'die Demontage'
363
            );
364
            return true;
365
        }
366
367
        if ($progress->getRemainingTicks() === 1) {
368
            if ($isUnderConstruction) {
369
                $this->stationUtility->finishStation($ship, $progress);
370
            } else {
371
                $this->stationUtility->finishScrapping($ship, $progress);
372
            }
373
374
            $this->msg[] = sprintf(
375
                _('%s: %s bei %s fertiggestellt'),
376
                $ship->getRump()->getName(),
377
                $isUnderConstruction ? 'Bau' : 'Demontage',
378
                $ship->getSectorString()
379
            );
380
        } else {
381
            $this->stationUtility->reduceRemainingTicks($progress);
382
383
            if ($isUnderConstruction) {
384
                // raise hull
385
                $increase = intdiv($ship->getMaxHull(), 2 * $ship->getRump()->getBuildtime());
386
                $ship->setHull($ship->getHull() + $increase);
387
            }
388
        }
389
390
        return true;
391
    }
392
393
    private function doRepairStation(ShipWrapperInterface $wrapper): void
394
    {
395
        $station = $wrapper->get();
396
397
        if (!$this->stationUtility->hasEnoughDockedWorkbees($station, $station->getRump())) {
398
            $neededWorkbees = (int)ceil($station->getRump()->getNeededWorkbees() / 5);
399
400
            $this->msg[] = sprintf(
401
                _('Nicht genügend Workbees (%d/%d) angedockt um die Reparatur weiterführen zu können'),
402
                $this->stationUtility->getDockedWorkbeeCount($station),
403
                $neededWorkbees
404
            );
405
            return;
406
        }
407
408
        $neededParts = $this->repairUtil->determineSpareParts($wrapper, true);
409
410
        // parts stored?
411
        if (!$this->repairUtil->enoughSparePartsOnEntity($neededParts, $station, $station)) {
412
            return;
413
        }
414
415
        //repair hull
416
        $station->setHull($station->getHull() + $station->getRepairRate());
417
        if ($station->getHull() > $station->getMaxHull()) {
418
            $station->setHull($station->getMaxHull());
419
        }
420
421
        //repair station systems
422
        $damagedSystems = $wrapper->getDamagedSystems();
423
        if ($damagedSystems !== []) {
424
            $firstSystem = $damagedSystems[0];
425
            $firstSystem->setStatus(100);
426
427
            if ($station->getCrewCount() > 0) {
428
                $firstSystem->setMode($this->shipSystemManager->lookupSystem($firstSystem->getSystemType())->getDefaultMode());
429
            }
430
431
            // maximum of two systems get repaired
432
            if (count($damagedSystems) > 1) {
433
                $secondSystem = $damagedSystems[1];
434
                $secondSystem->setStatus(100);
435
436
                if ($station->getCrewCount() > 0) {
437
                    $secondSystem->setMode($this->shipSystemManager->lookupSystem($secondSystem->getSystemType())->getDefaultMode());
438
                }
439
            }
440
        }
441
442
        // consume spare parts
443
        $this->repairUtil->consumeSpareParts($neededParts, $station);
444
445
        if (!$wrapper->canBeRepaired()) {
446
            $station->setHull($station->getMaxHull());
447
            $station->setState(ShipStateEnum::SHIP_STATE_NONE);
448
449
            $shipOwnerMessage = sprintf(
450
                "Die Reparatur der %s wurde in Sektor %s fertiggestellt",
451
                $station->getName(),
452
                $station->getSectorString()
453
            );
454
455
            $this->privateMessageSender->send(
456
                UserEnum::USER_NOONE,
457
                $station->getUser()->getId(),
458
                $shipOwnerMessage,
459
                PrivateMessageFolderTypeEnum::SPECIAL_STATION
460
            );
461
        }
462
        $this->shipRepository->save($station);
463
    }
464
465
    private function checkForFinishedTakeover(ShipInterface $ship): void
466
    {
467
        $startTime = microtime(true);
468
        $takeover = $ship->getTakeoverActive();
469
        if ($takeover === null) {
470
            return;
471
        }
472
        $this->potentialLog($ship, "marker10.1", $startTime);
0 ignored issues
show
Bug introduced by
It seems like $startTime can also be of type string; however, parameter $startTime of Stu\Module\Tick\Ship\ShipTick::potentialLog() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

472
        $this->potentialLog($ship, "marker10.1", /** @scrutinizer ignore-type */ $startTime);
Loading history...
473
474
        $startTime = microtime(true);
475
        $isTakeoverReady = $this->shipTakeoverManager->isTakeoverReady($takeover);
476
        $this->potentialLog($ship, "marker10.2", $startTime);
477
478
        if ($isTakeoverReady) {
479
            $startTime = microtime(true);
480
            $this->shipTakeoverManager->finishTakeover($takeover);
481
            $this->potentialLog($ship, "marker10.3", $startTime);
482
        }
483
    }
484
485
    private function checkForFinishedAstroMapping(ShipWrapperInterface $wrapper): void
486
    {
487
        $ship = $wrapper->get();
488
489
        /** @var null|DatabaseEntryInterface $databaseEntry */
490
        [$message, $databaseEntry] = $this->getDatabaseEntryForShipLocation($ship);
491
492
        $astroLab = $wrapper->getAstroLaboratorySystemData();
493
494
        if (
495
            $ship->getState() === ShipStateEnum::SHIP_STATE_ASTRO_FINALIZING
496
            && $databaseEntry !== null
497
            && $astroLab !== null
498
            && $this->game->getCurrentRound()->getTurn() >= ($astroLab->getAstroStartTurn() + AstronomicalMappingEnum::TURNS_TO_FINISH)
499
        ) {
500
            $this->astroEntryLib->finish($wrapper);
501
502
            $this->msg[] = sprintf(
503
                _('Die Kartographierung %s wurde vollendet'),
504
                $message
505
            );
506
507
            $userId = $ship->getUser()->getId();
508
            $databaseEntryId = $databaseEntry->getId();
509
510
            if (!$this->databaseUserRepository->exists($userId, $databaseEntryId)) {
511
                $entry = $this->createDatabaseEntry->createDatabaseEntryForUser($ship->getUser(), $databaseEntryId);
512
513
                if ($entry !== null) {
514
                    $this->msg[] = sprintf(
515
                        _('Neuer Datenbankeintrag: %s (+%d Punkte)'),
516
                        $entry->getDescription(),
517
                        $entry->getCategory()->getPoints()
518
                    );
519
                }
520
            }
521
        }
522
    }
523
524
    /**
525
     * @return array{0: string|null, 1: DatabaseEntryInterface|null}
526
     */
527
    private function getDatabaseEntryForShipLocation(ShipInterface $ship): array
528
    {
529
        $system = $ship->getSystem();
530
        if ($system !== null) {
531
            return [
532
                'des Systems ' . $system->getName(),
533
                $system->getDatabaseEntry()
534
            ];
535
        }
536
537
        $mapRegion = $ship->getMapRegion();
538
        if ($mapRegion !== null) {
539
            return [
540
                'der Region ' . $mapRegion->getDescription(),
541
                $mapRegion->getDatabaseEntry()
542
            ];
543
        }
544
545
        return [null, null];
546
    }
547
548
    private function doTrackerDeviceStuff(ShipWrapperInterface $wrapper): void
549
    {
550
        $ship = $wrapper->get();
551
        $tracker = $wrapper->getTrackerSystemData();
552
553
        if ($tracker === null || $tracker->targetId === null) {
554
            return;
555
        }
556
557
        $targetWrapper = $tracker->getTargetWrapper();
558
        if ($targetWrapper === null) {
559
            throw new RuntimeException('should not happen');
560
        }
561
562
        $target = $targetWrapper->get();
563
        $shipLocation = $ship->getLocation();
564
        $targetLocation = $target->getLocation();
565
        $remainingTicks = $tracker->getRemainingTicks();
566
567
        $reduceByTicks = max(1, (int)ceil((abs($shipLocation->getCx() - $targetLocation->getCx())
568
            +  abs($shipLocation->getCy() - $targetLocation->getCy())) / 50));
569
570
        //reduce remaining ticks
571
        if ($remainingTicks > $reduceByTicks) {
572
            $tracker->setRemainingTicks($remainingTicks - $reduceByTicks)->update();
573
        } else {
574
            $this->trackerDeviceManager->deactivateTrackerIfActive($wrapper, true);
575
        }
576
    }
577
578
    private function sendMessages(ShipInterface $ship): void
579
    {
580
        if ($this->msg === []) {
581
            return;
582
        }
583
        $text = "Tickreport der " . $ship->getName() . "\n";
584
        foreach ($this->msg as $msg) {
585
            $text .= $msg . "\n";
586
        }
587
588
        $href = sprintf('ship.php?%s=1&id=%d', ShowShip::VIEW_IDENTIFIER, $ship->getId());
589
590
        $this->privateMessageSender->send(
591
            UserEnum::USER_NOONE,
592
            $ship->getUser()->getId(),
593
            $text,
594
            $ship->isBase() ? PrivateMessageFolderTypeEnum::SPECIAL_STATION : PrivateMessageFolderTypeEnum::SPECIAL_SHIP,
595
            $href
596
        );
597
598
        $this->msg = [];
599
    }
600
601
602
    private function lowerStationConstructionHull(UserInterface $user): void
603
    {
604
        foreach ($this->shipRepository->getStationConstructions($user) as $ship) {
605
            $lower = random_int(5, 15);
606
            if ($ship->getHull() <= $lower) {
607
                $msg = sprintf(_('Dein Konstrukt bei %s war zu lange ungenutzt und ist daher zerfallen'), $ship->getSectorString());
608
                $this->privateMessageSender->send(
609
                    UserEnum::USER_NOONE,
610
                    $ship->getUser()->getId(),
611
                    $msg,
612
                    PrivateMessageFolderTypeEnum::SPECIAL_STATION
613
                );
614
615
                $this->shipRemover->remove($ship);
616
                continue;
617
            }
618
            $ship->setHull($ship->getHull() - $lower);
619
620
            $this->shipRepository->save($ship);
621
        }
622
    }
623
}
624