Passed
Push — master ( 288b46...98b0e3 )
by Nico
31:30 queued 08:00
created

ShipMover::shouldActivateImpulsedrive()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 6
nc 4
nop 2
dl 0
loc 11
ccs 0
cts 6
cp 0
crap 30
rs 9.6111
c 1
b 0
f 0
1
<?php
2
3
namespace Stu\Module\Ship\Lib\Movement;
4
5
use Stu\Module\PlayerSetting\Lib\UserEnum;
6
use Stu\Module\Ship\Lib\Battle\AlertRedHelperInterface;
7
use Stu\Module\Ship\Lib\Message\Message;
8
use Stu\Module\Ship\Lib\Message\MessageCollection;
9
use Stu\Module\Ship\Lib\Message\MessageCollectionInterface;
10
use Stu\Module\Ship\Lib\Movement\Component\PreFlight\PreFlightConditionsCheckInterface;
11
use Stu\Module\Ship\Lib\Movement\Route\FlightRouteInterface;
12
use Stu\Module\Ship\Lib\ShipWrapperInterface;
13
use Stu\Orm\Entity\ShipInterface;
14
use Stu\Orm\Repository\ShipRepositoryInterface;
15
16
//TODO unit tests
17
final class ShipMover implements ShipMoverInterface
18
{
19
    private ShipRepositoryInterface $shipRepository;
20
21
    private ShipMovementInformationAdderInterface $shipMovementInformationAdder;
22
23
    private PreFlightConditionsCheckInterface $preFlightConditionsCheck;
24
25
    private AlertRedHelperInterface $alertRedHelper;
26
27
    /**
28
     * @var array<ShipInterface>
29
     */
30
    private array $tractoredShips = [];
31
32
    private bool $hasTravelled = false;
33
34
    private MessageCollectionInterface $messages;
35
36
    public function __construct(
37
        ShipRepositoryInterface $shipRepository,
38
        ShipMovementInformationAdderInterface $shipMovementInformationAdder,
39
        PreFlightConditionsCheckInterface $preFlightConditionsCheck,
40
        AlertRedHelperInterface $alertRedHelper
41
    ) {
42
        $this->shipRepository = $shipRepository;
43
        $this->shipMovementInformationAdder = $shipMovementInformationAdder;
44
        $this->preFlightConditionsCheck = $preFlightConditionsCheck;
45
        $this->alertRedHelper = $alertRedHelper;
46
47
        $this->messages = new MessageCollection();
48
    }
49
50
    private function addInformation(string $value): void
51
    {
52
        $this->messages->add(new Message(UserEnum::USER_NOONE, null, [$value]));
53
    }
54
55
    /**
56
     * @param array<string> $value
57
     */
58
    private function addInformationMerge(array $value): void
59
    {
60
        $this->messages->add(new Message(UserEnum::USER_NOONE, null, $value));
61
    }
62
63
    public function checkAndMove(
64
        ShipWrapperInterface $leadShipWrapper,
65
        FlightRouteInterface $flightRoute
66
    ): MessageCollectionInterface {
67
68
        $leadShip = $leadShipWrapper->get();
69
        $leadShipName = $leadShip->getName();
70
        $fleet = $leadShip->getFleet();
71
72
        $isFleetMode = $leadShip->isFleetLeader();
73
        $fleetWrapper = $leadShipWrapper->getFleetWrapper();
74
75
        $wrappers = $isFleetMode && $fleetWrapper !== null ? $fleetWrapper->getShipWrappers() : [$leadShipWrapper];
76
77
        $isFixedFleetMode = $isFleetMode
78
            && $fleet !== null
79
            && $fleet->isFleetFixed();
80
81
        $this->initTractoredShips($wrappers);
82
83
        // fly until destination arrived
84
        while (!$flightRoute->isDestinationArrived()) {
85
            $nextWaypoint = $flightRoute->getNextWaypoint();
86
87
            // nächstes Feld nicht passierbar
88
            $nextFieldType = $nextWaypoint->getFieldType();
89
            if (!$nextFieldType->getPassable()) {
90
                $flightRoute->abortFlight();
91
                $this->addInformation(_('Das nächste Feld kann nicht passiert werden'));
92
                break;
93
            }
94
95
            $activeWrappers = array_filter(
96
                $wrappers,
97
                fn (ShipWrapperInterface $wrapper) => !$wrapper->get()->isDestroyed()
98
            );
99
100
            // check all flight pre conditions
101
            $conditionCheckResult = $this->preFlightConditionsCheck->checkPreconditions($activeWrappers, $flightRoute, $isFixedFleetMode);
102
103
            if (!$conditionCheckResult->isFlightPossible()) {
104
                $flightRoute->abortFlight();
105
                $this->addInformation(_('Der Weiterflug wurde aus folgenden Gründen abgebrochen:'));
106
                $this->addInformationMerge($conditionCheckResult->getInformations());
107
                break;
108
            }
109
110
            // move every ship by one field
111
            foreach ($activeWrappers as $wrapper) {
112
113
                if ($conditionCheckResult->isNotBlocked($wrapper->get())) {
114
                    $flightRoute->enterNextWaypoint(
115
                        $wrapper,
116
                        $this->messages
117
                    );
118
119
                    $tractoredShip = $wrapper->getTractoredShipWrapper();
120
                    if ($tractoredShip !== null) {
121
                        $flightRoute->enterNextWaypoint(
122
                            $tractoredShip,
123
                            $this->messages
124
                        );
125
                    }
126
127
                    $this->hasTravelled = true;
128
                }
129
            }
130
131
            $flightRoute->stepForward();
132
133
            // alert red check
134
            $alertRedInformations =
135
                $this->alertRedHelper->doItAll($leadShip);
136
137
            if ($alertRedInformations !== null) {
138
                $this->addInformationMerge($alertRedInformations->getInformations());
139
            }
140
141
            // alert red check for tractored ships
142
            foreach ($this->tractoredShips as [$tractoringShip, $tractoredShip]) {
143
                if (!$tractoredShip->isDestroyed()) {
144
                    $alertRedInformations =
145
                        $this->alertRedHelper->doItAll($tractoredShip, null, $tractoringShip);
146
147
                    if ($alertRedInformations !== null) {
148
                        $this->addInformationMerge($alertRedInformations->getInformations());
149
                    }
150
                }
151
            }
152
153
            if ($this->areAllShipsDestroyed($activeWrappers)) {
154
                $flightRoute->abortFlight();
155
                $this->addInformation(_('Es wurden alle Schiffe zerstört'));
156
            }
157
        }
158
159
        //skip save and log info if flight did not happen
160
        if (!$this->hasTravelled) {
161
            return $this->messages;
162
        }
163
164
        // save all ships
165
        foreach ($wrappers as $wrapper) {
166
            $ship = $wrapper->get();
167
            if (!$ship->isDestroyed()) {
168
                $this->shipRepository->save($ship);
169
            }
170
171
            $tractoredShip = $ship->getTractoredShip();
172
            if ($tractoredShip !== null) {
173
                $this->shipMovementInformationAdder->pulledTractoredShip(
174
                    $ship,
175
                    $tractoredShip,
176
                    $flightRoute->getRouteMode(),
177
                    $this->messages
178
                );
179
            }
180
        }
181
        foreach ($this->tractoredShips as $ship) {
182
            $this->shipRepository->save($ship);
183
        }
184
185
        if ($this->areAllShipsDestroyed($wrappers)) {
186
            $this->shipMovementInformationAdder->reachedDestinationDestroyed(
187
                $leadShip,
188
                $leadShipName,
189
                $isFleetMode,
190
                $flightRoute->getRouteMode(),
191
                $this->messages
192
            );
193
        } else {
194
            $this->shipMovementInformationAdder->reachedDestination(
195
                $leadShip,
196
                $isFleetMode,
197
                $flightRoute->getRouteMode(),
198
                $this->messages
199
            );
200
        }
201
202
        //add info about anomalies
203
        foreach ($leadShipWrapper->get()->getLocation()->getAnomalies() as $anomaly) {
204
            $this->addInformation(sprintf('[b][color=yellow]In diesem Sektor befindet sich eine %s[/color][/b]', $anomaly->getAnomalyType()->getName()));
205
        }
206
207
        return $this->messages;
208
    }
209
210
    /**
211
     * @param ShipWrapperInterface[] $wrappers
212
     */
213
    private function initTractoredShips(array $wrappers): void
214
    {
215
        foreach ($wrappers as $fleetShipWrapper) {
216
            $fleetShip = $fleetShipWrapper->get();
217
218
            $tractoredShip = $fleetShip->getTractoredShip();
219
            if (
220
                $tractoredShip !== null
221
            ) {
222
                $this->tractoredShips[] = $tractoredShip;
223
            }
224
        }
225
    }
226
227
    /**
228
     * @param ShipWrapperInterface[] $wrappers
229
     */
230
    private function areAllShipsDestroyed(array $wrappers): bool
231
    {
232
        foreach ($wrappers as $wrapper) {
233
            if (!$wrapper->get()->isDestroyed()) {
234
                return false;
235
            }
236
        }
237
238
        return true;
239
    }
240
}
241