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

FightLib::isBoardingPossible()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 6
eloc 6
nc 6
nop 1
dl 0
loc 8
ccs 7
cts 7
cp 1
crap 6
rs 9.2222
c 1
b 1
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib\Battle;
6
7
use Stu\Component\Ship\Repair\CancelRepairInterface;
8
use Stu\Component\Ship\System\Exception\ShipSystemException;
9
use Stu\Component\Ship\System\ShipSystemManagerInterface;
10
use Stu\Component\Ship\System\ShipSystemTypeEnum;
11
use Stu\Lib\Information\InformationWrapper;
12
use Stu\Module\Ship\Lib\ShipNfsItem;
13
use Stu\Module\Ship\Lib\ShipWrapperInterface;
14
use Stu\Orm\Entity\ShipInterface;
15
use Stu\Orm\Entity\User;
16
17
final class FightLib implements FightLibInterface
18
{
19
    private ShipSystemManagerInterface $shipSystemManager;
20
21
    private CancelRepairInterface $cancelRepair;
22
23
    private AlertLevelBasedReactionInterface $alertLevelBasedReaction;
24
25 45
    public function __construct(
26
        ShipSystemManagerInterface $shipSystemManager,
27
        CancelRepairInterface $cancelRepair,
28
        AlertLevelBasedReactionInterface $alertLevelBasedReaction
29
    ) {
30 45
        $this->shipSystemManager = $shipSystemManager;
31 45
        $this->cancelRepair = $cancelRepair;
32 45
        $this->alertLevelBasedReaction = $alertLevelBasedReaction;
33
    }
34
35 6
    public function ready(ShipWrapperInterface $wrapper): InformationWrapper
36
    {
37 6
        $ship = $wrapper->get();
38
39 6
        $informations = new InformationWrapper();
40
41
        if (
42 6
            $ship->isDestroyed()
43 6
            || $ship->getRump()->isEscapePods()
44
        ) {
45 2
            return $informations;
46
        }
47 4
        if ($ship->getBuildplan() === null) {
48 1
            return $informations;
49
        }
50 3
        if (!$ship->hasEnoughCrew()) {
51 1
            return $informations;
52
        }
53
54 2
        if ($ship->getDockedTo() !== null) {
55 1
            $ship->setDockedTo(null);
56 1
            $informations->addInformation("- Das Schiff hat abgedockt");
57
        }
58
59
        try {
60 2
            $this->shipSystemManager->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_WARPDRIVE);
61 1
        } catch (ShipSystemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
62
        }
63
        try {
64 2
            $this->shipSystemManager->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_CLOAK);
65 1
        } catch (ShipSystemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
66
        }
67
68 2
        $this->cancelRepair->cancelRepair($ship);
69
70 2
        $informations->addInformationWrapper($this->alertLevelBasedReaction->react($wrapper));
71
72 2
        if (!$informations->isEmpty()) {
73 1
            $informations->addInformationArray([sprintf(_('Aktionen der %s'), $ship->getName())], true);
74
        }
75
76 2
        return $informations;
77
    }
78
79 1
    public function filterInactiveShips(array $base): array
80
    {
81 1
        return array_filter(
82 1
            $base,
83 1
            fn (ShipWrapperInterface $wrapper): bool => !$wrapper->get()->isDestroyed() && !$wrapper->get()->isDisabled()
84 1
        );
85
    }
86
87 4
    public function canFire(ShipWrapperInterface $wrapper): bool
88
    {
89 4
        $ship = $wrapper->get();
90 4
        if (!$ship->getNbs()) {
91 1
            return false;
92
        }
93 3
        if (!$ship->hasActiveWeapon()) {
94 1
            return false;
95
        }
96
97 2
        $epsSystem = $wrapper->getEpsSystemData();
98 2
        return $epsSystem !== null && $epsSystem->getEps() !== 0;
99
    }
100
101 12
    public function canAttackTarget(
102
        ShipInterface $ship,
103
        ShipInterface|ShipNfsItem $target,
104
        bool $checkActiveWeapons = true
105
    ): bool {
106 12
        if ($checkActiveWeapons && !$ship->hasActiveWeapon()) {
107 1
            return false;
108
        }
109
110
        //can't attack itself
111 11
        if ($target === $ship) {
112 1
            return false;
113
        }
114
115
        //can't attack trumfields
116 10
        if ($target->isTrumfield()) {
117 1
            return false;
118
        }
119
120
        //if tractored, can only attack tractoring ship
121 9
        $tractoringShip = $ship->getTractoringShip();
122 9
        if ($tractoringShip !== null) {
123 3
            return $target->getId() === $tractoringShip->getId();
124
        }
125
126
        //can't attack target under warp
127 6
        if ($target->getWarpState()) {
128 1
            return false;
129
        }
130
131
        //can't attack own target under cloak
132
        if (
133 5
            $target->getUserId() === $ship->getUserId()
134 5
            && $target->getCloakState()
135
        ) {
136 1
            return false;
137
        }
138
139
        //can't attack same fleet
140 4
        $ownFleetId = $ship->getFleetId();
141 4
        $targetFleetId = $target->getFleetId();
142 4
        if ($ownFleetId === null || $targetFleetId === null) {
143 2
            return true;
144
        }
145
146 2
        return $ownFleetId !== $targetFleetId;
147
    }
148
149 8
    public function getAttackersAndDefenders(ShipWrapperInterface $wrapper, ShipWrapperInterface $targetWrapper): array
150
    {
151 8
        $attackers = $this->getAttackers($wrapper);
152 8
        $defenders = $this->getDefenders($targetWrapper);
153
154 8
        return [
155 8
            $attackers,
156 8
            $defenders,
157 8
            count($attackers) + count($defenders) > 2
158 8
        ];
159
    }
160
161
    /** @return array<int, ShipWrapperInterface> */
162 8
    public function getAttackers(ShipWrapperInterface $wrapper): array
163
    {
164 8
        $ship = $wrapper->get();
165 8
        $fleet = $wrapper->getFleetWrapper();
166
167 8
        if ($ship->isFleetLeader() && $fleet !== null) {
168 1
            $attackers = $fleet->getShipWrappers();
169
        } else {
170 7
            $attackers = [$ship->getId() => $wrapper];
171
        }
172
173 8
        return $attackers;
174
    }
175
176
    /** @return array<int, ShipWrapperInterface> */
177 8
    private function getDefenders(ShipWrapperInterface $targetWrapper): array
178
    {
179 8
        $target = $targetWrapper->get();
180 8
        $targetFleet = $targetWrapper->getFleetWrapper();
181
182 8
        if ($targetFleet !== null) {
183 3
            $defenders = [];
184
185
            // only uncloaked defenders fight
186 3
            foreach ($targetFleet->getShipWrappers() as $shipId => $defWrapper) {
187
188 3
                $defShip = $defWrapper->get();
189 3
                if (!$defShip->getCloakState()) {
190 3
                    $defenders[$shipId] = $defWrapper;
191
192 3
                    $this->addDockedToAsDefender($targetWrapper, $defenders);
193
                }
194
            }
195
196
            // if all defenders were cloaked, they obviously were scanned and enter the fight as a whole fleet
197 3
            if ($defenders === []) {
198
                $defenders = $targetFleet->getShipWrappers();
199
            }
200
        } else {
201 5
            $defenders = [$target->getId() => $targetWrapper];
202
203 5
            $this->addDockedToAsDefender($targetWrapper, $defenders);
204
        }
205
206 8
        return $defenders;
207
    }
208
209
    /** @param array<int, ShipWrapperInterface> $defenders */
210 8
    private function addDockedToAsDefender(ShipWrapperInterface $targetWrapper, array &$defenders): void
211
    {
212 8
        $dockedToWrapper = $targetWrapper->getDockedToShipWrapper();
213
        if (
214 8
            $dockedToWrapper !== null
215 8
            && !$dockedToWrapper->get()->getUser()->isNpc()
216 8
            && $dockedToWrapper->get()->hasActiveWeapon()
217
        ) {
218 2
            $defenders[$dockedToWrapper->get()->getId()] = $dockedToWrapper;
219
        }
220
    }
221
222 4
    public function isTargetOutsideFinishedTholianWeb(ShipInterface $ship, ShipInterface $target): bool
223
    {
224 4
        $web = $ship->getHoldingWeb();
225 4
        if ($web === null) {
226 1
            return false;
227
        }
228
229 3
        return $web->isFinished() && ($target->getHoldingWeb() !== $web);
230
    }
231
232 6
    public static function isBoardingPossible(ShipInterface|ShipNfsItem $ship): bool
233
    {
234 6
        return !(User::isUserNpc($ship->getUserId())
235 6
            || $ship->isBase()
236 6
            || $ship->isTrumfield()
237 6
            || $ship->getCloakState()
238 6
            || $ship->getShieldState()
239 6
            || $ship->getWarpState());
240
    }
241
}
242