Passed
Push — master ( bf860f...1dd8f7 )
by Nico
57:55 queued 29:36
created

ShipMover::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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