FlightRoute::hasEffectOnRoute()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Spacecraft\Lib\Movement\Route;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use RuntimeException;
10
use Stu\Component\Map\Effects\EffectHandlingInterface;
11
use Stu\Lib\Map\FieldTypeEffectEnum;
12
use Stu\Module\Spacecraft\Lib\Message\MessageCollectionInterface;
13
use Stu\Module\Spacecraft\Lib\Movement\Component\Consequence\FlightConsequenceInterface;
14
use Stu\Module\Spacecraft\Lib\Movement\FlightCompany;
15
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperInterface;
16
use Stu\Orm\Entity\Location;
17
use Stu\Orm\Entity\Map;
18
use Stu\Orm\Entity\Spacecraft;
19
use Stu\Orm\Entity\StarSystemMap;
20
use Stu\Orm\Entity\Station;
21
use Stu\Orm\Entity\WormholeEntry;
22
23
final class FlightRoute implements FlightRouteInterface
24
{
25
    //Members
26
    private bool $isTraversing = false;
27
28
    private RouteModeEnum $routeMode = RouteModeEnum::FLIGHT;
29
30
    private Location $current;
31
32
    private ?WormholeEntry $wormholeEntry = null;
33
34
    /**
35
     * @var Collection<int, Location>
36
     */
37
    private Collection $waypoints;
38
39
    /**
40
     * @param array<string, FlightConsequenceInterface> $flightConsequences
41
     * @param array<string, FlightConsequenceInterface> $postFlightConsequences
42
     */
43 27
    public function __construct(
44
        private CheckDestinationInterface $checkDestination,
45
        private LoadWaypointsInterface $loadWaypoints,
46
        private EnterWaypointInterface $enterWaypoint,
47
        private EffectHandlingInterface $effectHandling,
48
        private array $flightConsequences,
49
        private array $postFlightConsequences,
50
    ) {
51 27
        $this->waypoints = new ArrayCollection();
52
    }
53
54 9
    #[\Override]
55
    public function setDestination(
56
        Map|StarSystemMap $destination,
57
        bool $isTranswarp
58
    ): FlightRouteInterface {
59 9
        $this->waypoints->add($destination);
60
61 9
        if ($destination instanceof Map) {
62 6
            if ($isTranswarp) {
63 1
                $this->routeMode = RouteModeEnum::TRANSWARP;
64
            } else {
65 5
                $this->routeMode = RouteModeEnum::SYSTEM_EXIT;
66
            }
67
        } else {
68 3
            $this->routeMode = RouteModeEnum::SYSTEM_ENTRY;
69
        }
70
71 9
        return $this;
72
    }
73
74 2
    #[\Override]
75
    public function setDestinationViaWormhole(WormholeEntry $wormholeEntry, bool $isEntry): FlightRouteInterface
76
    {
77 2
        $this->wormholeEntry = $wormholeEntry;
78 2
        if ($isEntry) {
79 1
            $this->waypoints->add($wormholeEntry->getSystemMap());
80 1
            $this->routeMode = RouteModeEnum::WORMHOLE_ENTRY;
81
        } else {
82 1
            $this->waypoints->add($wormholeEntry->getMap());
83 1
            $this->routeMode = RouteModeEnum::WORMHOLE_EXIT;
84
        }
85
86 2
        return $this;
87
    }
88
89 13
    #[\Override]
90
    public function setDestinationViaCoordinates(Spacecraft $spacecraft, int $x, int $y): FlightRouteInterface
91
    {
92 13
        $start = $spacecraft->getLocation();
93 13
        $this->current = $start;
94 13
        $destination = $this->checkDestination->validate($spacecraft, $x, $y);
95
96 13
        if ($start !== $destination) {
97 10
            $this->waypoints = $this->loadWaypoints->load($start, $destination);
98 10
            $this->isTraversing = true;
99
        }
100
101 13
        return $this;
102
    }
103
104 3
    #[\Override]
105
    public function getCurrentWaypoint(): Location
106
    {
107 3
        return $this->current;
108
    }
109
110 12
    #[\Override]
111
    public function getNextWaypoint(): Location
112
    {
113 12
        if ($this->waypoints->isEmpty()) {
114 1
            throw new RuntimeException('isDestinationArrived has to be called beforehand');
115
        }
116
117 11
        return $this->waypoints->first();
118
    }
119
120 10
    private function stepForward(): void
121
    {
122 10
        $first =  $this->waypoints->first();
123
124 10
        if (!$first) {
125
            return;
126
        }
127
128 10
        $this->current = $first;
129 10
        $this->waypoints->removeElement($this->current);
130
    }
131
132 1
    #[\Override]
133
    public function abortFlight(): void
134
    {
135 1
        $this->waypoints->clear();
136
    }
137
138 10
    #[\Override]
139
    public function enterNextWaypoint(
140
        FlightCompany $flightCompany,
141
        MessageCollectionInterface $messages
142
    ): void {
143
144 10
        $wrappers = $flightCompany->getActiveMembers();
145
146
        // flight consequences
147 10
        $this->walkWrappers(
148 10
            $wrappers,
149 10
            function (SpacecraftWrapperInterface $wrapper) use ($messages): void {
150 10
                $this->walkConsequences($this->flightConsequences, $wrapper, $messages);
151 10
            }
152 10
        );
153
154
        // enter waypoint
155 10
        $this->walkWrappers(
156 10
            $wrappers,
157 10
            function (SpacecraftWrapperInterface $wrapper): void {
158 10
                $this->enterWaypoint->enterNextWaypoint(
159 10
                    $wrapper->get(),
160 10
                    $this->isTraversing,
161 10
                    $this->getNextWaypoint(),
162 10
                    $this->wormholeEntry
163 10
                );
164 10
            }
165 10
        );
166
167 10
        $this->effectHandling->addFlightInformationForActiveEffects($this->getNextWaypoint(), $messages);
168
169
        // post flight consequences
170 10
        $this->walkWrappers(
171 10
            $wrappers,
172 10
            function (SpacecraftWrapperInterface $wrapper) use ($messages): void {
173 10
                $this->walkConsequences($this->postFlightConsequences, $wrapper, $messages);
174 10
            }
175 10
        );
176
177 10
        $this->stepForward();
178
    }
179
180
    /** @param Collection<int, SpacecraftWrapperInterface> $wrappers */
181 10
    private function walkWrappers(Collection $wrappers, callable $func): void
182
    {
183 10
        foreach ($wrappers as $wrapper) {
184 10
            $func($wrapper);
185
        }
186
    }
187
188
    /**
189
     * @param array<string, FlightConsequenceInterface> $consequences
190
     */
191 10
    private function walkConsequences(
192
        array $consequences,
193
        ?SpacecraftWrapperInterface $wrapper,
194
        MessageCollectionInterface $messages
195
    ): void {
196
197 10
        if ($wrapper === null) {
198 10
            return;
199
        }
200
201 10
        array_walk(
202 10
            $consequences,
203 10
            fn(FlightConsequenceInterface $consequence) => $consequence->trigger($wrapper, $this, $messages)
204 10
        );
205
206 10
        $this->walkConsequences($consequences, $wrapper->getTractoredShipWrapper(), $messages);
207
    }
208
209 14
    #[\Override]
210
    public function isDestinationArrived(): bool
211
    {
212 14
        return $this->waypoints->isEmpty();
213
    }
214
215 10
    #[\Override]
216
    public function getRouteMode(): RouteModeEnum
217
    {
218 10
        return $this->routeMode;
219
    }
220
221 4
    #[\Override]
222
    public function isTraversing(): bool
223
    {
224 4
        return $this->isTraversing;
225
    }
226
227 4
    #[\Override]
228
    public function isImpulseDriveNeeded(): bool
229
    {
230 4
        $routeMode = $this->routeMode;
231
232
        if (
233 4
            $routeMode === RouteModeEnum::SYSTEM_ENTRY
234 4
            || $routeMode === RouteModeEnum::WORMHOLE_ENTRY
235
        ) {
236 1
            return true;
237
        }
238
239 3
        return $routeMode === RouteModeEnum::FLIGHT
240 3
            && $this->getNextWaypoint() instanceof StarSystemMap;
241
    }
242
243 4
    #[\Override]
244
    public function isWarpDriveNeeded(): bool
245
    {
246 4
        $routeMode = $this->routeMode;
247
248
        if (
249 4
            $routeMode === RouteModeEnum::SYSTEM_EXIT
250 4
            || $routeMode === RouteModeEnum::TRANSWARP
251
        ) {
252
            return true;
253
        }
254
255 4
        return $routeMode === RouteModeEnum::FLIGHT
256 4
            && $this->getNextWaypoint() instanceof Map;
257
    }
258
259 4
    #[\Override]
260
    public function isTranswarpCoilNeeded(): bool
261
    {
262 4
        return $this->routeMode === RouteModeEnum::TRANSWARP;
263
    }
264
265 2
    #[\Override]
266
    public function hasSpecialDamageOnField(): bool
267
    {
268 2
        foreach ($this->waypoints as $waypoint) {
269 2
            if ($waypoint->getFieldType()->getSpecialDamage() > 0) {
270 1
                return true;
271
            }
272
        }
273
274 1
        return false;
275
    }
276
277 2
    #[\Override]
278
    public function hasEffectOnRoute(FieldTypeEffectEnum $effect): bool
279
    {
280 2
        foreach ($this->waypoints as $waypoint) {
281 2
            if ($waypoint->getFieldType()->hasEffect($effect)) {
282 1
                return true;
283
            }
284
        }
285
286 1
        return false;
287
    }
288
289 2
    #[\Override]
290
    public function isDestinationInAdminRegion(array $regionIds): bool
291
    {
292 2
        $destination = $this->waypoints->last();
293
294 2
        return $destination instanceof Map
295 2
            && in_array($destination->getAdminRegionId(), $regionIds);
296
    }
297
298 4
    #[\Override]
299
    public function isDestinationAtTradepost(): bool
300
    {
301 4
        $destination = $this->waypoints->last();
302
303 4
        return $destination instanceof Map
304 4
            && $destination->getSpacecrafts()->exists(fn(int $key, Spacecraft $spacecraft): bool => $spacecraft instanceof Station && $spacecraft->getTradePost() !== null);
305
    }
306
}
307