Passed
Push — dev ( dc1a8e...52c71a )
by Nico
05:53
created

AssaultPhalanxBehaviour::getOwnCrewCount()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 9
ccs 0
cts 6
cp 0
crap 12
rs 10
1
<?php
2
3
namespace Stu\Lib\Pirate\Behaviour;
4
5
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use RuntimeException;
7
use Stu\Component\Spacecraft\System\SpacecraftSystemManagerInterface;
8
use Stu\Component\Spacecraft\System\SpacecraftSystemModeEnum;
9
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
10
use Stu\Lib\Information\InformationWrapper;
11
use Stu\Lib\Map\DistanceCalculationInterface;
12
use Stu\Lib\Pirate\Component\PirateNavigationInterface;
13
use Stu\Lib\Pirate\Component\TrapDetectionInterface;
14
use Stu\Lib\Pirate\PirateBehaviourEnum;
15
use Stu\Lib\Pirate\PirateReactionInterface;
16
use Stu\Lib\Pirate\PirateReactionMetadata;
17
use Stu\Module\Logging\LoggerUtilFactoryInterface;
18
use Stu\Module\Logging\PirateLoggerInterface;
19
use Stu\Module\Message\Lib\DistributedMessageSenderInterface;
20
use Stu\Module\Message\Lib\PrivateMessageFolderTypeEnum;
21
use Stu\Module\PlayerSetting\Lib\UserConstants;
0 ignored issues
show
Bug introduced by
The type Stu\Module\PlayerSetting\Lib\UserConstants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use Stu\Module\Ship\Lib\FleetWrapperInterface;
23
use Stu\Module\Ship\Lib\ShipWrapperInterface;
24
use Stu\Module\Spacecraft\Lib\Crew\TroopTransferUtilityInterface;
25
use Stu\Module\Spacecraft\Lib\Battle\SpacecraftAttackCoreInterface;
26
use Stu\Module\Spacecraft\Lib\CloseCombat\BoardShipUtilInterface;
27
use Stu\Module\Spacecraft\Lib\CloseCombat\CloseCombatUtilInterface;
28
use Stu\Module\Spacecraft\Lib\Message\MessageCollectionInterface;
29
use Stu\Module\Spacecraft\Lib\Message\MessageFactoryInterface;
30
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperFactoryInterface;
31
use Stu\Orm\Entity\Spacecraft;
32
use Stu\Orm\Entity\Station;
33
use Stu\Orm\Repository\StationRepositoryInterface;
34
35
class AssaultPhalanxBehaviour implements PirateBehaviourInterface
36
{
37
    private PirateLoggerInterface $logger;
38
39 1
    public function __construct(
40
        private StationRepositoryInterface $stationRepository,
41
        private DistanceCalculationInterface $distanceCalculation,
42
        private PirateNavigationInterface $pirateNavigation,
43
        private SpacecraftAttackCoreInterface $spacecraftAttackCore,
44
        private CloseCombatUtilInterface $closeCombatUtil,
45
        private BoardShipUtilInterface $boardShip,
46
        private SpacecraftSystemManagerInterface $spacecraftSystemManager,
47
        private SpacecraftWrapperFactoryInterface $spacecraftWrapperFactory,
48
        private TrapDetectionInterface $trapDetection,
49
        private MessageFactoryInterface $messageFactory,
50
        private DistributedMessageSenderInterface $distributedMessageSender,
51
        private TroopTransferUtilityInterface $troopTransferUtility,
52
        LoggerUtilFactoryInterface $loggerUtilFactory
53
    ) {
54 1
        $this->logger = $loggerUtilFactory->getPirateLogger();
55
    }
56
57
    #[Override]
58
    public function action(
59
        FleetWrapperInterface $fleet,
60
        PirateReactionInterface $pirateReaction,
61
        PirateReactionMetadata $reactionMetadata,
62
        ?Spacecraft $triggerSpacecraft
63
    ): ?PirateBehaviourEnum {
64
65
        $leadWrapper = $fleet->getLeadWrapper();
66
        $leadShip = $leadWrapper->get();
67
68
        $targets = $this->stationRepository->getPiratePhalanxTargets($leadWrapper);
69
70
        $this->logger->log(sprintf('    %d targets in reach', count($targets)));
71
72
        $filteredTargets = array_filter(
73
            $targets,
74
            fn(Station $target): bool =>
75
            !$this->trapDetection->isAlertTrap($target->getLocation(), $leadShip)
76
        );
77
78
        $this->logger->log(sprintf('    %d filtered targets in reach', count($filteredTargets)));
79
80
        if ($filteredTargets === []) {
81
            return null;
82
        }
83
84
        usort(
85
            $filteredTargets,
86
            fn(Station $a, Station $b): int =>
87
            $this->distanceCalculation->shipToShipDistance($leadShip, $a) - $this->distanceCalculation->shipToShipDistance($leadShip, $b)
88
        );
89
90
        $isFleetFight = false;
91
        $informations = new InformationWrapper();
92
93
        /** @var Station */
94
        $closestPhalanx = current($filteredTargets);
95
        $phalanxWrapper = $this->spacecraftWrapperFactory->wrapStation($closestPhalanx);
96
97
        if (!$this->pirateNavigation->navigateToTarget($fleet, $closestPhalanx->getLocation())) {
98
            return null;
99
        }
100
101
        // take down shields only
102
        while ($closestPhalanx->isShielded()) {
103
            $this->spacecraftAttackCore->attack($leadWrapper, $phalanxWrapper, true, $isFleetFight, $informations);
104
        }
105
106
        if ($closestPhalanx->getCondition()->isDestroyed()) {
107
            return null;
108
        }
109
110
        $boardingWrapper = $this->getBoardingPirateWrapper($fleet);
111
        $boardingShip = $boardingWrapper->get();
112
113
        $this->spacecraftSystemManager->deactivate($boardingWrapper, SpacecraftSystemTypeEnum::SHIELDS, true);
114
115
        $combatGroupAttacker = $this->closeCombatUtil->getCombatGroup($boardingShip);
116
        $combatGroupDefender = $this->closeCombatUtil->getCombatGroup($closestPhalanx);
117
118
        $messages = $this->messageFactory->createMessageCollection();
119
        $message = $this->messageFactory->createMessage(UserConstants::USER_NPC_KAZON, $closestPhalanx->getUser()->getId(), [sprintf(
120
            'Das Piratenschiff %s entsendet ein Enterkommando auf die %s',
121
            $boardingShip->getName(),
122
            $closestPhalanx->getName()
123
        )]);
124
125
        $messages->add($message);
126
127
        while ($combatGroupAttacker !== [] && $combatGroupDefender !== []) {
128
129
            $this->logger->logf('    %d vs %d', count($combatGroupAttacker), count($combatGroupDefender));
130
131
            $this->boardShip->cycleKillRound(
132
                $combatGroupAttacker,
133
                $combatGroupDefender,
134
                $boardingWrapper,
135
                $phalanxWrapper,
136
                $messages
137
            );
138
        }
139
140
        // Check uplink status after combat
141
        $uplinkMessages = $this->checkUplinkStatus($phalanxWrapper);
142
143
        // Füge die Uplink-Meldungen zur Nachrichtensammlung hinzu
144
        if (!empty($uplinkMessages)) {
145
            // Erstelle eine einzige Nachricht mit allen Uplink-Meldungen
146
            $message = $this->messageFactory->createMessage(
147
                UserConstants::USER_NPC_KAZON,
148
                $closestPhalanx->getUser()->getId(),
149
                $uplinkMessages
150
            );
151
            $messages->add($message);
152
        }
153
154
        // Send messages including combat results and uplink status
155
        $this->sendPms(
156
            $closestPhalanx->getSectorString(),
157
            $messages
158
        );
159
160
        return null;
161
    }
162
163
    private function getBoardingPirateWrapper(FleetWrapperInterface $fleetWrapper): ShipWrapperInterface
164
    {
165
166
        $pirateWrapperArray = $fleetWrapper->getShipWrappers()->toArray();
167
168
        usort(
169
            $pirateWrapperArray,
170
            fn(ShipWrapperInterface $a, ShipWrapperInterface $b): int =>
171
            $b->get()->getCrewCount() - $a->get()->getCrewCount()
172
        );
173
174
        $pirateShipWithMostCrew = current($pirateWrapperArray);
175
        if ($pirateShipWithMostCrew === false) {
176
            throw new RuntimeException('this should not happen');
177
        }
178
179
        return $pirateShipWithMostCrew;
180
    }
181
182
    /**
183
     * @return array<string>
184
     */
185
    private function checkUplinkStatus(\Stu\Module\Station\Lib\StationWrapperInterface $wrapper): array
186
    {
187
        $spacecraft = $wrapper->get();
188
        $messages = [];
189
190
        // Check if uplink system exists and is active
191
        if (!$spacecraft->hasSpacecraftSystem(SpacecraftSystemTypeEnum::UPLINK)) {
192
            return $messages;
193
        }
194
195
        $hasForeigners = $this->troopTransferUtility->foreignerCount($spacecraft) > 0;
196
        $ownCrewCount = $this->getOwnCrewCount($spacecraft);
197
        $minOwnCrew = 0;
198
199
        $buildplan = $spacecraft->getBuildplan();
200
        if ($buildplan !== null) {
201
            $minOwnCrew = $buildplan->getCrew();
202
        }
203
204
        // Deactivate uplink if no foreigners left
205
        if (!$hasForeigners && $spacecraft->getSystemState(SpacecraftSystemTypeEnum::UPLINK)) {
206
            $spacecraft->getSpacecraftSystem(SpacecraftSystemTypeEnum::UPLINK)->setMode(SpacecraftSystemModeEnum::MODE_OFF);
207
            $message = sprintf('Der Uplink der %s wurde deaktiviert, da sich keine fremden Crewmitglieder mehr an Bord befinden', $spacecraft->getName());
208
            $this->logger->log($message);
209
            $messages[] = $message;
210
        }
211
212
        // Deactivate uplink if not enough own crew
213
        if ($hasForeigners && $spacecraft->getSystemState(SpacecraftSystemTypeEnum::UPLINK) && $ownCrewCount < $minOwnCrew) {
214
            $spacecraft->getSpacecraftSystem(SpacecraftSystemTypeEnum::UPLINK)->setMode(SpacecraftSystemModeEnum::MODE_OFF);
215
            $message = sprintf(
216
                'Der Uplink der %s wurde deaktiviert, da nicht mehr genügend eigene Crewmitglieder an Bord sind (%d/%d)',
217
                $spacecraft->getName(),
218
                $ownCrewCount,
219
                $minOwnCrew
220
            );
221
            $this->logger->log($message);
222
            $messages[] = $message;
223
        }
224
225
        return $messages;
226
    }
227
228
    private function getOwnCrewCount(Spacecraft $spacecraft): int
229
    {
230
        $count = 0;
231
        foreach ($spacecraft->getCrewAssignments() as $spacecraftCrew) {
232
            if ($spacecraftCrew->getCrew()->getUser()->getId() === $spacecraft->getUser()->getId()) {
233
                $count++;
234
            }
235
        }
236
        return $count;
237
    }
238
239
    private function sendPms(
240
        string $sectorString,
241
        MessageCollectionInterface $messageCollection
242
    ): void {
243
244
        $header = sprintf(
245
            "Plünderung in Sektor %s",
246
            $sectorString
247
        );
248
249
        $this->distributedMessageSender->distributeMessageCollection(
250
            $messageCollection,
251
            UserConstants::USER_NPC_KAZON,
252
            PrivateMessageFolderTypeEnum::SPECIAL_STATION,
253
            $header,
254
            true
255
        );
256
    }
257
}
258