Passed
Pull Request — master (#1676)
by Nico
24:49
created

ShipMover::getTractoredShips()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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