Passed
Push — master ( 3d0840...13d157 )
by Nico
48:12 queued 22:32
created

ActivatorDeactivatorHelper::setWarpSplitFleet()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 40
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 6
eloc 21
c 1
b 1
f 0
nc 8
nop 2
dl 0
loc 40
ccs 0
cts 23
cp 0
crap 42
rs 8.9617
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib;
6
7
use RuntimeException;
8
use Stu\Component\Ship\ShipAlertStateEnum;
9
use Stu\Component\Ship\ShipLSSModeEnum;
10
use Stu\Component\Ship\System\Exception\ActivationConditionsNotMetException;
11
use Stu\Component\Ship\System\Exception\AlreadyActiveException;
12
use Stu\Component\Ship\System\Exception\AlreadyOffException;
13
use Stu\Component\Ship\System\Exception\DeactivationConditionsNotMetException;
14
use Stu\Component\Ship\System\Exception\InsufficientCrewException;
15
use Stu\Component\Ship\System\Exception\InsufficientEnergyException;
16
use Stu\Component\Ship\System\Exception\ShipSystemException;
17
use Stu\Component\Ship\System\Exception\SystemCooldownException;
18
use Stu\Component\Ship\System\Exception\SystemDamagedException;
19
use Stu\Component\Ship\System\Exception\SystemNotActivatableException;
20
use Stu\Component\Ship\System\Exception\SystemNotDeactivatableException;
21
use Stu\Component\Ship\System\Exception\SystemNotFoundException;
22
use Stu\Component\Ship\System\ShipSystemManagerInterface;
23
use Stu\Component\Ship\System\ShipSystemTypeEnum;
24
use Stu\Module\Control\GameControllerInterface;
25
use Stu\Module\Ship\Lib\Movement\Component\PreFlight\ConditionCheckResult;
26
use Stu\Module\Tal\TalHelper;
27
use Stu\Orm\Entity\ShipInterface;
28
use Stu\Orm\Repository\ShipRepositoryInterface;
29
30
final class ActivatorDeactivatorHelper implements ActivatorDeactivatorHelperInterface
31
{
32
    private ShipLoaderInterface $shipLoader;
33
34
    private ShipRepositoryInterface $shipRepository;
35
36
    private ShipSystemManagerInterface $shipSystemManager;
37
38 1
    public function __construct(
39
        ShipLoaderInterface $shipLoader,
40
        ShipRepositoryInterface $shipRepository,
41
        ShipSystemManagerInterface $shipSystemManager
42
    ) {
43 1
        $this->shipLoader = $shipLoader;
44 1
        $this->shipRepository = $shipRepository;
45 1
        $this->shipSystemManager = $shipSystemManager;
46
    }
47
48
    public function activate(
49
        ShipWrapperInterface|int $target,
50
        shipSystemTypeEnum $type,
51
        ConditionCheckResult|GameControllerInterface $logger,
52
        bool $allowUplink = false,
53
        bool $isDryRun = false
54
    ): bool {
55
        $wrapper = $this->getTargetWrapper(
56
            $target,
57
            $logger,
58
            $allowUplink
59
        );
60
61
        return $this->activateIntern($wrapper, $type, $logger, $isDryRun);
62
    }
63
64
    private function getTargetWrapper(
65
        ShipWrapperInterface|int $target,
66
        ConditionCheckResult|GameControllerInterface $logger,
67
        bool $allowUplink
68
    ): ShipWrapperInterface {
69
        if ($target instanceof ShipWrapperInterface) {
70
            return $target;
71
        }
72
73
        if ($logger instanceof ConditionCheckResult) {
74
            throw new RuntimeException('game needs to be present when target is shipId only');
75
        }
76
77
        return $this->shipLoader->getWrapperByIdAndUser(
78
            $target,
79
            $logger->getUser()->getId(),
80
            $allowUplink
81
        );
82
    }
83
84
    private function activateIntern(
85
        ShipWrapperInterface $wrapper,
86
        shipSystemTypeEnum $type,
87
        ConditionCheckResult|GameControllerInterface $logger,
88
        bool $isDryRun
89
    ): bool {
90
        $systemName = $type->getDescription();
91
        $ship = $wrapper->get();
92
93
        try {
94
            $this->shipSystemManager->activate($wrapper, $type, false, $isDryRun);
95
            $this->shipRepository->save($ship);
96
            if ($logger instanceof GameControllerInterface) {
97
                $logger->addInformation(sprintf(_('%s: System %s aktiviert'), $ship->getName(), $systemName));
98
            }
99
            return true;
100
        } catch (AlreadyActiveException $e) {
101
            if ($logger instanceof GameControllerInterface) {
102
                $logger->addInformation(sprintf(_('%s: System %s ist bereits aktiviert'), $ship->getName(), $systemName));
103
            }
104
        } catch (SystemNotActivatableException $e) {
105
            $this->logError($ship, sprintf(_('%s: [b][color=#ff2626]System %s besitzt keinen Aktivierungsmodus[/color][/b]'), $ship->getName(), $systemName), $logger);
106
        } catch (InsufficientEnergyException $e) {
107
            $this->logError($ship, sprintf(
108
                _('%s: [b][color=#ff2626]System %s kann aufgrund Energiemangels (%d benötigt) nicht aktiviert werden[/color][/b]'),
109
                $ship->getName(),
110
                $systemName,
111
                $e->getNeededEnergy()
112
            ), $logger);
113
        } catch (SystemCooldownException $e) {
114
            $this->logError($ship, sprintf(
115
                _('%s: [b][color=#ff2626]System %s kann nicht aktiviert werden, Cooldown noch %s[/color][/b]'),
116
                $ship->getName(),
117
                $systemName,
118
                TalHelper::formatSeconds((string) $e->getRemainingSeconds())
119
            ), $logger);
120
        } catch (SystemDamagedException $e) {
121
            $this->logError($ship, sprintf(_('%s: [b][color=#ff2626]System %s ist beschädigt und kann daher nicht aktiviert werden[/color][/b]'), $ship->getName(), $systemName), $logger);
122
        } catch (ActivationConditionsNotMetException $e) {
123
            $this->logError($ship, sprintf(_('%s: [b][color=#ff2626]System %s konnte nicht aktiviert werden, weil %s[/color][/b]'), $ship->getName(), $systemName, $e->getMessage()), $logger);
124
        } catch (SystemNotFoundException $e) {
125
            $this->logError($ship, sprintf(_('%s: [b][color=#ff2626]System %s nicht vorhanden[/color][/b]'), $ship->getName(), $systemName), $logger);
126
        } catch (InsufficientCrewException $e) {
127
            $this->logError($ship, sprintf(_('%s: [b][color=#ff2626]System %s konnte wegen Mangel an Crew nicht aktiviert werden[/color][/b]'), $ship->getName(), $systemName), $logger);
128
        } catch (ShipSystemException $e) {
129
            $this->logError($ship, sprintf(_('%s: [b][color=#ff2626]System %s konnte nicht aktiviert werden[/color][/b]'), $ship->getName(), $systemName), $logger);
130
        }
131
132
        return false;
133
    }
134
135
    private function logError(ShipInterface $ship, string $message, ConditionCheckResult|GameControllerInterface $logger): void
136
    {
137
        if ($logger instanceof GameControllerInterface) {
138
            $logger->addInformation($message);
139
        } else {
140
            $logger->addBlockedShip($ship, $message);
141
        }
142
    }
143
144
    public function activateFleet(
145
        int $shipId,
146
        shipSystemTypeEnum $type,
147
        GameControllerInterface $game
148
    ): void {
149
        $userId = $game->getUser()->getId();
150
151
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
152
            $shipId,
153
            $userId
154
        );
155
156
        $fleetWrapper = $wrapper->getFleetWrapper();
157
        if ($fleetWrapper === null) {
158
            throw new RuntimeException('ship not in fleet');
159
        }
160
161
        $success = false;
162
        foreach ($fleetWrapper->getShipWrappers() as $wrapper) {
163
            if ($this->activateIntern($wrapper, $type, $game, false)) {
164
                $success = true;
165
            }
166
        }
167
168
        // only show info if at least one ship was able to change
169
        if (!$success) {
170
            return;
171
        }
172
173
        $game->addInformation(sprintf(
174
            _('Flottenbefehl ausgeführt: System %s aktiviert'),
175
            $type->getDescription()
176
        ));
177
    }
178
179
    public function deactivate(
180
        ShipWrapperInterface|int $target,
181
        shipSystemTypeEnum $type,
182
        GameControllerInterface $game,
183
        bool $allowUplink = false
184
    ): bool {
185
        $wrapper = $this->getTargetWrapper(
186
            $target,
187
            $game,
188
            $allowUplink
189
        );
190
191
        return $this->deactivateIntern($wrapper, $type, $game);
192
    }
193
194
    private function deactivateIntern(
195
        ShipWrapperInterface $wrapper,
196
        shipSystemTypeEnum $type,
197
        GameControllerInterface $game
198
    ): bool {
199
        $systemName = $type->getDescription();
200
        $ship = $wrapper->get();
201
202
        try {
203
            $this->shipSystemManager->deactivate($wrapper, $type);
204
            $this->shipRepository->save($ship);
205
            $game->addInformation(sprintf(_('%s: System %s deaktiviert'), $ship->getName(), $systemName));
206
            return true;
207
        } catch (AlreadyOffException $e) {
208
            $game->addInformation(sprintf(_('%s: System %s ist bereits deaktiviert'), $ship->getName(), $systemName));
209
        } catch (SystemNotDeactivatableException $e) {
210
            $game->addInformation(sprintf(_('%s: [b][color=#ff2626]System %s besitzt keinen Deaktivierungsmodus[/color][/b]'), $ship->getName(), $systemName));
211
        } catch (DeactivationConditionsNotMetException $e) {
212
            $game->addInformation(sprintf(_('%s: [b][color=#ff2626]System %s konnte nicht deaktiviert werden, weil %s[/color][/b]'), $ship->getName(), $systemName, $e->getMessage()));
213
        } catch (SystemNotFoundException $e) {
214
            $game->addInformation(sprintf(_('%s: System %s nicht vorhanden'), $ship->getName(), $systemName));
215
        }
216
217
        return false;
218
    }
219
220
    public function deactivateFleet(
221
        int $shipId,
222
        shipSystemTypeEnum $type,
223
        GameControllerInterface $game
224
    ): void {
225
        $userId = $game->getUser()->getId();
226
227
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
228
            $shipId,
229
            $userId
230
        );
231
232
        $fleetWrapper = $wrapper->getFleetWrapper();
233
        if ($fleetWrapper === null) {
234
            throw new RuntimeException('ship not in fleet');
235
        }
236
237
        $success = false;
238
        foreach ($fleetWrapper->getShipWrappers() as $wrapper) {
239
            if ($this->deactivateIntern($wrapper, $type, $game)) {
240
                $success = true;
241
            }
242
        }
243
244
        // only show info if at least one ship was able to change
245
        if (!$success) {
246
            return;
247
        }
248
249
        $game->addInformation(sprintf(
250
            _('Flottenbefehl ausgeführt: System %s deaktiviert'),
251
            $type->getDescription()
252
        ));
253
    }
254
255
    public function setLSSMode(
256
        int $shipId,
257
        int $lssMode,
258
        GameControllerInterface $game
259
    ): void {
260
        $userId = $game->getUser()->getId();
261
262
        $ship = $this->shipLoader->getByIdAndUser(
263
            $shipId,
264
            $userId
265
        );
266
267
        $ship->setLSSMode($lssMode);
268
        $this->shipRepository->save($ship);
269
270
        if ($lssMode === ShipLSSModeEnum::LSS_NORMAL) {
271
            $game->addInformation("Territoriale Grenzanzeige deaktiviert");
272
        } elseif ($lssMode === ShipLSSModeEnum::LSS_BORDER) {
273
            $game->addInformation("Territoriale Grenzanzeige aktiviert");
274
        }
275
    }
276
277
    public function setAlertState(
278
        int $shipId,
279
        ShipAlertStateEnum $alertState,
280
        GameControllerInterface $game
281
    ): void {
282
        $userId = $game->getUser()->getId();
283
284
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
285
            $shipId,
286
            $userId
287
        );
288
289
        if (!$this->setAlertStateShip($wrapper, $alertState, $game)) {
290
            return;
291
        }
292
293
        if ($alertState === ShipAlertStateEnum::ALERT_RED) {
294
            $game->addInformation("Die Alarmstufe wurde auf [b][color=red]Rot[/color][/b] geändert");
295
        } elseif ($alertState === ShipAlertStateEnum::ALERT_YELLOW) {
296
            $game->addInformation("Die Alarmstufe wurde auf [b][color=yellow]Gelb[/color][/b] geändert");
297
        } elseif ($alertState === ShipAlertStateEnum::ALERT_GREEN) {
298
            $game->addInformation("Die Alarmstufe wurde auf [b][color=green]Grün[/color][/b] geändert");
299
        }
300
    }
301
302
    public function setAlertStateFleet(
303
        int $shipId,
304
        ShipAlertStateEnum $alertState,
305
        GameControllerInterface $game
306
    ): void {
307
        $userId = $game->getUser()->getId();
308
309
        $wrapper = $this->shipLoader->getWrapperByIdAndUser(
310
            $shipId,
311
            $userId
312
        );
313
314
        $fleetWrapper = $wrapper->getFleetWrapper();
315
        if ($fleetWrapper === null) {
316
            throw new RuntimeException('ship not in fleet');
317
        }
318
319
        $success = false;
320
        foreach ($fleetWrapper->getShipWrappers() as $wrapper) {
321
            $success = $this->setAlertStateShip($wrapper, $alertState, $game) || $success;
322
        }
323
324
        // only show info if at least one ship was able to change
325
        if (!$success) {
326
            return;
327
        }
328
329
        if ($alertState === ShipAlertStateEnum::ALERT_RED) {
330
            $game->addInformation(_('Flottenbefehl ausgeführt: Alarmstufe [b][color=red]Rot[/color][/b]'));
331
        } elseif ($alertState === ShipAlertStateEnum::ALERT_YELLOW) {
332
            $game->addInformation(_('Flottenbefehl ausgeführt: Alarmstufe [b][color=yellow]Gelb[/color][/b]'));
333
        } elseif ($alertState === ShipAlertStateEnum::ALERT_GREEN) {
334
            $game->addInformation(_('Flottenbefehl ausgeführt: Alarmstufe [b][color=green]Grün[/color][/b]'));
335
        }
336
    }
337
338
    private function setAlertStateShip(ShipWrapperInterface $wrapper, ShipAlertStateEnum $alertState, GameControllerInterface $game): bool
339
    {
340
        $ship = $wrapper->get();
341
342
        // station constructions can't change alert state
343
        if ($ship->isConstruction()) {
344
            $game->addInformation(sprintf(_('%s: [b][color=#ff2626]Konstrukte können die Alarmstufe nicht ändern[/color][/b]'), $ship->getName()));
345
            return false;
346
        }
347
348
        // can only change when there is enough crew
349
        if (!$ship->hasEnoughCrew()) {
350
            $game->addInformation(sprintf(_('%s: [b][color=#ff2626]Mangel an Crew verhindert den Wechsel der Alarmstufe[/color][/b]'), $ship->getName()));
351
            return false;
352
        }
353
354
        if ($alertState === ShipAlertStateEnum::ALERT_RED && $ship->getCloakState()) {
355
            $game->addInformation(sprintf(_('%s: [b][color=#ff2626]Tarnung verhindert den Wechsel zu Alarm-Rot[/color][/b]'), $ship->getName()));
356
            return false;
357
        }
358
359
        try {
360
            $alertMsg = $wrapper->setAlertState($alertState);
361
            $this->shipRepository->save($ship);
362
363
            if ($alertMsg !== null) {
364
                $game->addInformation(sprintf(_('%s: [b][color=FAFA03]%s[/color][/b]'), $ship->getName(), $alertMsg));
365
            }
366
        } catch (InsufficientEnergyException $e) {
367
            $game->addInformation(sprintf(_('%s: [b][color=#ff2626]Nicht genügend Energie um die Alarmstufe zu wechseln (%d benötigt)[/color][/b]'), $ship->getName(), $e->getNeededEnergy()));
368
            return false;
369
        }
370
371
        switch ($alertState) {
372
            case ShipAlertStateEnum::ALERT_RED:
373
                $this->setAlertRed($wrapper, $game);
374
                break;
375
            case ShipAlertStateEnum::ALERT_YELLOW:
376
                $this->setAlertYellow($wrapper, $game);
377
                break;
378
            case ShipAlertStateEnum::ALERT_GREEN:
379
                $this->setAlertGreen($wrapper, $game);
380
                break;
381
        }
382
383
        $this->shipRepository->save($ship);
384
385
        return true;
386
    }
387
388
    private function setAlertRed(ShipWrapperInterface $wrapper, GameControllerInterface $game): void
389
    {
390
        $alertSystems = [
391
            ShipSystemTypeEnum::SYSTEM_SHIELDS,
392
            ShipSystemTypeEnum::SYSTEM_NBS,
393
            ShipSystemTypeEnum::SYSTEM_PHASER,
394
            ShipSystemTypeEnum::SYSTEM_TORPEDO
395
        ];
396
397
        foreach ($alertSystems as $type) {
398
            $this->activateIntern($wrapper, $type, $game, false);
399
        }
400
    }
401
402
    private function setAlertYellow(ShipWrapperInterface $wrapper, GameControllerInterface $game): void
403
    {
404
        $alertSystems = [
405
            ShipSystemTypeEnum::SYSTEM_NBS
406
        ];
407
408
        foreach ($alertSystems as $type) {
409
            $this->activateIntern($wrapper, $type, $game, false);
410
        }
411
    }
412
413
    private function setAlertGreen(ShipWrapperInterface $wrapper, GameControllerInterface $game): void
414
    {
415
        $deactivateSystems = [
416
            ShipSystemTypeEnum::SYSTEM_PHASER,
417
            ShipSystemTypeEnum::SYSTEM_TORPEDO,
418
            ShipSystemTypeEnum::SYSTEM_SHIELDS
419
        ];
420
421
        foreach ($deactivateSystems as $type) {
422
            if ($wrapper->get()->hasShipSystem($type)) {
423
                $this->deactivateIntern($wrapper, $type, $game);
424
            }
425
        }
426
    }
427
}
428