Passed
Push — master ( 6b02b9...a180a6 )
by Nico
26:39 queued 18:43
created

ShowShip::createUserLayerIfNecessary()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 13
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 22
ccs 0
cts 14
cp 0
crap 20
rs 9.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\View\ShowShip;
6
7
use NavPanel;
8
use request;
9
use Stu\Component\Player\ColonizationCheckerInterface;
10
use Stu\Component\Ship\AstronomicalMappingEnum;
11
use Stu\Component\Ship\Crew\ShipCrewCalculatorInterface;
12
use Stu\Component\Ship\Nbs\NbsUtilityInterface;
13
use Stu\Component\Ship\ShipModuleTypeEnum;
14
use Stu\Component\Ship\ShipRumpEnum;
15
use Stu\Component\Station\StationUtilityInterface;
16
use Stu\Lib\ColonyStorageCommodityWrapper\ColonyStorageCommodityWrapper;
17
use Stu\Lib\SessionInterface;
18
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
19
use Stu\Module\Control\GameControllerInterface;
20
use Stu\Module\Control\ViewControllerInterface;
21
use Stu\Module\Database\View\Category\Tal\DatabaseCategoryTalFactoryInterface;
22
use Stu\Module\Logging\LoggerUtilFactoryInterface;
23
use Stu\Module\Logging\LoggerUtilInterface;
24
use Stu\Module\Ship\Lib\Battle\FightLibInterface;
25
use Stu\Module\Ship\Lib\ShipLoaderInterface;
26
use Stu\Module\Ship\Lib\ShipRumpSpecialAbilityEnum;
27
use Stu\Module\Ship\Lib\ShipWrapperFactoryInterface;
28
use Stu\Module\Ship\Lib\ShipWrapperInterface;
29
use Stu\Module\Ship\Lib\Ui\ShipUiFactoryInterface;
30
use Stu\Orm\Entity\ColonyInterface;
31
use Stu\Orm\Entity\ShipInterface;
32
use Stu\Orm\Entity\StationShipRepairInterface;
33
use Stu\Orm\Entity\UserInterface;
34
use Stu\Orm\Repository\AstroEntryRepositoryInterface;
35
use Stu\Orm\Repository\DatabaseUserRepositoryInterface;
36
use Stu\Orm\Repository\ShipyardShipQueueRepositoryInterface;
37
use Stu\Orm\Repository\StationShipRepairRepositoryInterface;
38
use Stu\Orm\Repository\UserLayerRepositoryInterface;
39
40
final class ShowShip implements ViewControllerInterface
41
{
42
    public const VIEW_IDENTIFIER = 'SHOW_SHIP';
43
44
    private SessionInterface $session;
45
46
    private LoggerUtilFactoryInterface $loggerUtilFactory;
47
48
    private LoggerUtilInterface $loggerUtil;
49
50
    private ShipLoaderInterface $shipLoader;
51
52
    private ColonizationCheckerInterface $colonizationChecker;
53
54
    private DatabaseCategoryTalFactoryInterface $databaseCategoryTalFactory;
55
56
    private AstroEntryRepositoryInterface $astroEntryRepository;
57
58
    private DatabaseUserRepositoryInterface $databaseUserRepository;
59
60
    private NbsUtilityInterface $nbsUtility;
61
62
    private StationShipRepairRepositoryInterface $stationShipRepairRepository;
63
64
    private ShipyardShipQueueRepositoryInterface $shipyardShipQueueRepository;
65
66
    private UserLayerRepositoryInterface $userLayerRepository;
67
68
    private StationUtilityInterface $stationUtility;
69
70
    private ShipWrapperFactoryInterface $shipWrapperFactory;
71
72
    private ColonyLibFactoryInterface $colonyLibFactory;
73
74
    private ShipUiFactoryInterface $shipUiFactory;
75
76
    private ShipCrewCalculatorInterface $shipCrewCalculator;
77
78
    private FightLibInterface $fightLib;
79
80
    public function __construct(
81
        SessionInterface $session,
82
        ShipLoaderInterface $shipLoader,
83
        ColonizationCheckerInterface $colonizationChecker,
84
        DatabaseCategoryTalFactoryInterface $databaseCategoryTalFactory,
85
        AstroEntryRepositoryInterface $astroEntryRepository,
86
        DatabaseUserRepositoryInterface $databaseUserRepository,
87
        NbsUtilityInterface $nbsUtility,
88
        StationShipRepairRepositoryInterface $stationShipRepairRepository,
89
        ShipyardShipQueueRepositoryInterface $shipyardShipQueueRepository,
90
        UserLayerRepositoryInterface $userLayerRepository,
91
        StationUtilityInterface $stationUtility,
92
        ShipWrapperFactoryInterface $shipWrapperFactory,
93
        ColonyLibFactoryInterface $colonyLibFactory,
94
        ShipUiFactoryInterface $shipUiFactory,
95
        ShipCrewCalculatorInterface $shipCrewCalculator,
96
        FightLibInterface $fightLib,
97
        LoggerUtilFactoryInterface $loggerUtilFactory
98
    ) {
99
        $this->session = $session;
100
        $this->shipLoader = $shipLoader;
101
        $this->colonizationChecker = $colonizationChecker;
102
        $this->databaseCategoryTalFactory = $databaseCategoryTalFactory;
103
        $this->astroEntryRepository = $astroEntryRepository;
104
        $this->databaseUserRepository = $databaseUserRepository;
105
        $this->nbsUtility = $nbsUtility;
106
        $this->stationShipRepairRepository = $stationShipRepairRepository;
107
        $this->shipyardShipQueueRepository = $shipyardShipQueueRepository;
108
        $this->userLayerRepository = $userLayerRepository;
109
        $this->stationUtility = $stationUtility;
110
        $this->shipWrapperFactory = $shipWrapperFactory;
111
        $this->loggerUtilFactory = $loggerUtilFactory;
112
        $this->loggerUtil = $loggerUtilFactory->getLoggerUtil();
113
        $this->colonyLibFactory = $colonyLibFactory;
114
        $this->shipUiFactory = $shipUiFactory;
115
        $this->shipCrewCalculator = $shipCrewCalculator;
116
        $this->fightLib = $fightLib;
117
    }
118
119
    public function handle(GameControllerInterface $game): void
120
    {
121
        $user = $game->getUser();
122
        $userId = $user->getId();
123
        $ownsCurrentColony = false;
124
125
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
126
            request::indInt('id'),
127
            $userId,
128
            true
129
        );
130
        $ship = $wrapper->get();
131
132
        $tachyonFresh = $game->getViewContext()['TACHYON_SCAN_JUST_HAPPENED'] ?? false;
133
        $tachyonActive = $tachyonFresh;
134
135
        // check if tachyon scan still active
136
        if (!$tachyonActive) {
137
            $tachyonActive = $this->nbsUtility->isTachyonActive($ship);
138
        }
139
140
        $rump = $ship->getRump();
141
142
        $colony = $this->getColony($ship);
143
        $canColonize = false;
144
        if ($colony !== null) {
145
            if ($rump->hasSpecialAbility(ShipRumpSpecialAbilityEnum::COLONIZE)) {
146
                $canColonize = $this->colonizationChecker->canColonize($user, $colony);
147
            }
148
            $ownsCurrentColony = $colony->getUser() === $user;
149
        }
150
151
        //Forschungseintrag erstellen, damit System-Link optional erstellt werden kann
152
        $starSystem = $ship->getSystem();
153
        if ($starSystem !== null && $starSystem->getDatabaseEntry() !== null) {
154
            $starSystemEntryTal = $this->databaseCategoryTalFactory->createDatabaseCategoryEntryTal($starSystem->getDatabaseEntry(), $user);
155
            $game->setTemplateVar('STARSYSTEM_ENTRY_TAL', $starSystemEntryTal);
156
        }
157
158
        $isBase = $ship->isBase();
159
        $game->appendNavigationPart(
160
            $isBase ? 'station.php' : 'ship.php',
161
            $isBase ? _('Stationen') : _('Schiffe')
162
        );
163
164
        $game->appendNavigationPart(
165
            sprintf('?%s=1&id=%d', static::VIEW_IDENTIFIER, $ship->getId()),
166
            $ship->getName()
167
        );
168
        $game->setPagetitle($ship->getName());
169
170
        $game->setTemplateFile('html/ship.twig', true);
171
172
        $game->setTemplateVar('WRAPPER', $wrapper);
173
174
        if ($ship->getLss()) {
175
176
            $this->createUserLayerIfNecessary($user, $ship);
177
178
            $game->setTemplateVar('VISUAL_NAV_PANEL', $this->shipUiFactory->createVisualNavPanel(
179
                $ship,
180
                $game->getUser(),
181
                $this->loggerUtilFactory->getLoggerUtil(),
182
                $ship->getTachyonState(),
183
                $tachyonFresh
184
            ));
185
        }
186
        $game->setTemplateVar('NAV_PANEL', new NavPanel($ship));
187
188
        $this->doConstructionStuff($ship, $game);
189
        $this->doStationStuff($ship, $game);
190
191
        $this->nbsUtility->setNbsTemplateVars($ship, $game, $this->session, $tachyonActive);
192
193
        $game->setTemplateVar('ASTRO_STATE', $this->getAstroState($ship, $game));
194
        $game->setTemplateVar('TACHYON_ACTIVE', $tachyonActive);
195
        $game->setTemplateVar('CAN_COLONIZE', $canColonize);
196
        $game->setTemplateVar('OWNS_CURRENT_COLONY', $ownsCurrentColony);
197
        $game->setTemplateVar('CURRENT_COLONY', $colony);
198
        $game->setTemplateVar('FIGHT_LIB', $this->fightLib);
199
200
        $userLayers = $user->getUserLayers();
201
        if ($ship->hasTranswarp()) {
202
            $game->setTemplateVar('USER_LAYERS', $userLayers);
203
        }
204
205
        $layer = $ship->getLayer();
206
        if ($layer !== null && $userLayers->containsKey($layer->getId())) {
207
            $game->setTemplateVar('IS_MAP_BUTTON_VISIBLE', true);
208
        }
209
210
        $crewObj = $this->shipCrewCalculator->getCrewObj($rump);
211
212
        $game->setTemplateVar(
213
            'MAX_CREW_COUNT',
214
            $crewObj === null
215
                ? null
216
                : $this->shipCrewCalculator->getMaxCrewCountByShip($ship)
217
        );
218
219
        $this->addWarpcoreSplitJavascript($wrapper, $game);
220
221
        $this->loggerUtil->log(sprintf('ShowShip.handle-end, timestamp: %F', microtime(true)));
222
    }
223
224
    private function createUserLayerIfNecessary(UserInterface $user, ShipInterface $ship): void
225
    {
226
        $layer = $ship->getLayer();
227
        if ($layer === null) {
228
            return;
229
        }
230
231
        if ($ship->getMap() === null) {
232
            return;
233
        }
234
235
        $hasSeenLayer = $user->hasSeen($layer->getId());
236
        if ($hasSeenLayer) {
237
            return;
238
        }
239
240
        $userLayer = $this->userLayerRepository->prototype();
241
        $userLayer->setLayer($layer);
242
        $userLayer->setUser($user);
243
        $this->userLayerRepository->save($userLayer);
244
245
        $user->getUserLayers()->set($layer->getId(), $userLayer);
246
    }
247
248
    private function addWarpcoreSplitJavascript(ShipWrapperInterface $wrapper, GameControllerInterface $game): void
249
    {
250
        $warpCoreSystem = $wrapper->getWarpCoreSystemData();
251
        $warpDriveSystem = $wrapper->getWarpDriveSystemData();
252
        $epsSystem = $wrapper->getEpsSystemData();
253
254
        if ($warpCoreSystem !== null && $warpDriveSystem !== null && $epsSystem !== null) {
255
            $ship = $wrapper->get();
256
257
            $game->addExecuteJS(sprintf(
258
                'updateEPSSplitValue(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);',
259
                $warpCoreSystem->getWarpCoreSplit(),
260
                $ship->getReactorOutput(),
261
                $wrapper->getEpsUsage(),
262
                $ship->getRump()->getFlightEcost(),
263
                $wrapper->getEffectiveEpsProduction(),
264
                $epsSystem->getEps(),
265
                $epsSystem->getMaxEps(),
266
                $warpDriveSystem->getWarpDrive(),
267
                $warpDriveSystem->getMaxWarpDrive(),
268
                $ship->getReactorLoad()
269
            ), true);
270
        }
271
    }
272
273
    private function getColony(ShipInterface $ship): ?ColonyInterface
274
    {
275
        if ($ship->getStarsystemMap() === null) {
276
            return null;
277
        }
278
279
        return $ship->getStarsystemMap()->getColony();
280
    }
281
282
    private function getAstroState(ShipInterface $ship, GameControllerInterface $game): AstroStateWrapper
283
    {
284
        $system = $ship->getSystem() ?? $ship->isOverSystem();
285
286
        $astroEntry = null;
287
        if ($system === null || $system->getDatabaseEntry() === null) {
288
            $state = AstronomicalMappingEnum::NONE;
289
        } elseif ($this->databaseUserRepository->exists($game->getUser()->getId(), $system->getDatabaseEntry()->getId())) {
290
            $state = AstronomicalMappingEnum::DONE;
291
        } else {
292
            $astroEntry = $this->astroEntryRepository->getByUserAndSystem(
293
                $ship->getUser()->getId(),
294
                $system->getId()
295
            );
296
297
            $state = $astroEntry === null ? AstronomicalMappingEnum::PLANNABLE : $astroEntry->getState();
298
        }
299
        $turnsLeft = null;
300
        if ($state === AstronomicalMappingEnum::FINISHING && $astroEntry !== null) {
301
            $turnsLeft = AstronomicalMappingEnum::TURNS_TO_FINISH - ($game->getCurrentRound()->getTurn() - $astroEntry->getAstroStartTurn());
302
        }
303
        return new AstroStateWrapper($state, $turnsLeft);
304
    }
305
306
    private function doConstructionStuff(ShipInterface $ship, GameControllerInterface $game): void
307
    {
308
        if (!$ship->isConstruction() && !$ship->isBase()) {
309
            return;
310
        }
311
312
        $progress =  $this->stationUtility->getConstructionProgress($ship);
313
        if ($progress === null || $progress->getRemainingTicks() === 0) {
314
            $game->setTemplateVar('CONSTRUCTION_PROGRESS_WRAPPER', null);
315
        } else {
316
            $dockedWorkbees = $this->stationUtility->getDockedWorkbeeCount($ship);
317
            $neededWorkbees = $this->stationUtility->getNeededWorkbeeCount($ship, $ship->getRump());
318
319
            $game->setTemplateVar('CONSTRUCTION_PROGRESS_WRAPPER', new ConstructionProgressWrapper(
320
                $progress,
321
                $ship,
322
                $dockedWorkbees,
323
                $neededWorkbees
324
            ));
325
        }
326
327
        if ($progress === null) {
328
            $plans = $this->stationUtility->getStationBuildplansByUser($game->getUser()->getId());
329
            $game->setTemplateVar('POSSIBLE_STATIONS', $plans);
330
331
            $moduleSelectors = [];
332
            foreach ($plans as $plan) {
333
                $ms = $this->colonyLibFactory->createModuleSelectorSpecial(
334
                    ShipModuleTypeEnum::MODULE_TYPE_SPECIAL,
335
                    null,
336
                    $ship,
337
                    $plan->getRump(),
338
                    $game->getUser()->getId()
339
                );
340
341
                $ms->setDummyId($plan->getId());
342
                $moduleSelectors[] = $ms;
343
            }
344
345
            $game->setTemplateVar('MODULE_SELECTORS', $moduleSelectors);
346
            $game->setTemplateVar('HAS_STORAGE', new ColonyStorageCommodityWrapper($ship->getStorage()));
347
        }
348
    }
349
350
    private function doStationStuff(ShipInterface $ship, GameControllerInterface $game): void
351
    {
352
        if ($this->stationUtility->canManageShips($ship)) {
353
            $game->setTemplateVar('CAN_MANAGE', true);
354
        }
355
356
        if ($this->stationUtility->canRepairShips($ship)) {
357
            $game->setTemplateVar('CAN_REPAIR', true);
358
359
            $shipRepairProgress = array_map(
360
                fn (StationShipRepairInterface $repair): ShipWrapperInterface => $this->shipWrapperFactory->wrapShip($repair->getShip()),
361
                $this->stationShipRepairRepository->getByStation(
362
                    $ship->getId()
363
                )
364
            );
365
366
            $game->setTemplateVar('SHIP_REPAIR_PROGRESS', $shipRepairProgress);
367
        }
368
369
        if ($ship->getRump()->getRoleId() === ShipRumpEnum::SHIP_ROLE_SHIPYARD) {
370
            $game->setTemplateVar('SHIP_BUILD_PROGRESS', $this->shipyardShipQueueRepository->getByShipyard($ship->getId()));
371
        }
372
373
        $firstOrbitShip = null;
374
375
        /**
376
         * @var ShipInterface[] $shipList
377
         */
378
        $shipList = $ship->getDockedShips()->toArray();
379
        if ($shipList !== []) {
380
            // if selected, return the current target
381
            $target = request::postInt('target');
382
383
            if ($target !== 0) {
384
                foreach ($shipList as $ship) {
385
                    if ($ship->getId() === $target) {
386
                        $firstOrbitShip = $ship;
387
                    }
388
                }
389
            }
390
            if ($firstOrbitShip === null) {
391
                $firstOrbitShip = current($shipList);
392
            }
393
        }
394
395
        $game->setTemplateVar('FIRST_MANAGE_SHIP', $firstOrbitShip !== null ? $this->shipWrapperFactory->wrapShip($firstOrbitShip) : null);
396
        $game->setTemplateVar('CAN_UNDOCK', true);
397
398
        if ($ship->getRump()->isShipyard()) {
399
            $game->setTemplateVar('AVAILABLE_BUILDPLANS', $this->stationUtility->getShipyardBuildplansByUser($game->getUser()->getId()));
400
        }
401
    }
402
}
403