Passed
Pull Request — master (#1777)
by Nico
22:32 queued 18s
created

ShipMover::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

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