Test Failed
Pull Request — master (#1775)
by Nico
26:52
created

FightLib::canAttackTarget()   B

Complexity

Conditions 11
Paths 8

Size

Total Lines 46
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 11.0176

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
eloc 20
c 1
b 1
f 0
nc 8
nop 3
dl 0
loc 46
ccs 18
cts 19
cp 0.9474
crap 11.0176
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 44
    public function __construct(
26
        ShipSystemManagerInterface $shipSystemManager,
27
        CancelRepairInterface $cancelRepair,
28
        AlertLevelBasedReactionInterface $alertLevelBasedReaction
29
    ) {
30 44
        $this->shipSystemManager = $shipSystemManager;
31 44
        $this->cancelRepair = $cancelRepair;
32 44
        $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 11
    public function canAttackTarget(
102
        ShipInterface $ship,
103
        ShipInterface|ShipNfsItem $target,
104
        bool $checkActiveWeapons = true
105
    ): bool {
106 11
        if ($checkActiveWeapons && !$ship->hasActiveWeapon()) {
107 1
            return false;
108
        }
109
110
        //can't attack itself
111 10
        if ($target === $ship) {
112 1
            return false;
113
        }
114
115
        //can't attack trumfields
116 9
        if ($target->isTrumfield()) {
117 1
            return false;
118
        }
119
120
        //if tractored, can only attack tractoring ship
121 8
        $tractoringShip = $ship->getTractoringShip();
122 8
        if ($tractoringShip !== null) {
123 3
            return $target->getId() === $tractoringShip->getId();
124
        }
125
126
        //can't attack target under warp
127 5
        if ($target->getWarpState()) {
128 1
            return false;
129
        }
130
131
        //can't attack own target under cloak
132 4
        if (
133
            $target->getUserId() === $ship->getUserId()
134
            && $target->getCloakState()
135
        ) {
136
            return false;
137
        }
138 4
139 4
        //can't attack same fleet
140 4
        $ownFleetId = $ship->getFleetId();
141 2
        $targetFleetId = $target->getFleetId();
142
        if ($ownFleetId === null || $targetFleetId === null) {
143
            return true;
144 2
        }
145
146
        return $ownFleetId !== $targetFleetId;
147 8
    }
148
149 8
    public function getAttackersAndDefenders(ShipWrapperInterface $wrapper, ShipWrapperInterface $targetWrapper): array
150 8
    {
151
        $attackers = $this->getAttackers($wrapper);
152 8
        $defenders = $this->getDefenders($targetWrapper);
153 8
154 8
        return [
155 8
            $attackers,
156 8
            $defenders,
157
            count($attackers) + count($defenders) > 2
158
        ];
159
    }
160 8
161
    /** @return array<int, ShipWrapperInterface> */
162 8
    public function getAttackers(ShipWrapperInterface $wrapper): array
163 8
    {
164
        $ship = $wrapper->get();
165 8
        $fleet = $wrapper->getFleetWrapper();
166 1
167
        if ($ship->isFleetLeader() && $fleet !== null) {
168 7
            $attackers = $fleet->getShipWrappers();
169
        } else {
170
            $attackers = [$ship->getId() => $wrapper];
171 8
        }
172
173
        return $attackers;
174
    }
175 8
176
    /** @return array<int, ShipWrapperInterface> */
177 8
    private function getDefenders(ShipWrapperInterface $targetWrapper): array
178 8
    {
179
        $target = $targetWrapper->get();
180 8
        $targetFleet = $targetWrapper->getFleetWrapper();
181 3
182
        if ($targetFleet !== null) {
183
            $defenders = [];
184 3
185
            // only uncloaked defenders fight
186 3
            foreach ($targetFleet->getShipWrappers() as $shipId => $defWrapper) {
187 3
188 3
                $defShip = $defWrapper->get();
189
                if (!$defShip->getCloakState()) {
190 3
                    $defenders[$shipId] = $defWrapper;
191
192
                    $this->addDockedToAsDefender($targetWrapper, $defenders);
193
                }
194
            }
195 3
196
            // if all defenders were cloaked, they obviously were scanned and enter the fight as a whole fleet
197
            if ($defenders === []) {
198
                $defenders = $targetFleet->getShipWrappers();
199 5
            }
200
        } else {
201 5
            $defenders = [$target->getId() => $targetWrapper];
202
203
            $this->addDockedToAsDefender($targetWrapper, $defenders);
204 8
        }
205
206
        return $defenders;
207
    }
208 8
209
    /** @param array<int, ShipWrapperInterface> $defenders */
210 8
    private function addDockedToAsDefender(ShipWrapperInterface $targetWrapper, array &$defenders): void
211
    {
212 8
        $dockedToWrapper = $targetWrapper->getDockedToShipWrapper();
213 8
        if (
214 8
            $dockedToWrapper !== null
215
            && !$dockedToWrapper->get()->getUser()->isNpc()
216 2
            && $dockedToWrapper->get()->hasActiveWeapon()
217
        ) {
218
            $defenders[$dockedToWrapper->get()->getId()] = $dockedToWrapper;
219
        }
220 4
    }
221
222 4
    public function isTargetOutsideFinishedTholianWeb(ShipInterface $ship, ShipInterface $target): bool
223 4
    {
224 1
        $web = $ship->getHoldingWeb();
225
        if ($web === null) {
226
            return false;
227 3
        }
228
229
        return $web->isFinished() && ($target->getHoldingWeb() !== $web);
230 6
    }
231
232 6
    public static function isBoardingPossible(ShipInterface|ShipNfsItem $ship): bool
233 6
    {
234 6
        return !(User::isUserNpc($ship->getUserId())
235 6
            || $ship->isBase()
236 6
            || $ship->isTrumfield()
237 6
            || $ship->getCloakState()
238
            || $ship->getShieldState()
239
            || $ship->getWarpState());
240
    }
241
}
242