Passed
Push — master ( 4cbcfa...1ee8de )
by Nico
53:18 queued 29:25
created

FightLib   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Test Coverage

Coverage 98.11%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 103
dl 0
loc 221
ccs 104
cts 106
cp 0.9811
rs 8.4
c 1
b 1
f 0
wmc 50

11 Methods

Rating   Name   Duplication   Size   Complexity  
A filterInactiveShips() 0 5 2
B ready() 0 42 9
A canFire() 0 12 4
A __construct() 0 8 1
A isBoardingPossible() 0 8 6
A addDockedToAsDefender() 0 9 4
A getAttackersAndDefenders() 0 9 1
A getDefenders() 0 30 5
A getAttackers() 0 12 3
C canAttackTarget() 0 44 12
A isTargetOutsideFinishedTholianWeb() 0 8 3

How to fix   Complexity   

Complex Class

Complex classes like FightLib often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FightLib, and based on these observations, apply Extract Interface, too.

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 (method_exists($target, 'isOwnedByCurrentUser') && $target->isOwnedByCurrentUser() && $target->getCloakState()) {
133
            return false;
134
        }
135
136
137
        //can't attack same fleet
138 4
        $ownFleetId = $ship->getFleetId();
139 4
        $targetFleetId = $target->getFleetId();
140 4
        if ($ownFleetId === null || $targetFleetId === null) {
141 2
            return true;
142
        }
143
144 2
        return $ownFleetId !== $targetFleetId;
145
    }
146
147 8
    public function getAttackersAndDefenders(ShipWrapperInterface $wrapper, ShipWrapperInterface $targetWrapper): array
148
    {
149 8
        $attackers = $this->getAttackers($wrapper);
150 8
        $defenders = $this->getDefenders($targetWrapper);
151
152 8
        return [
153 8
            $attackers,
154 8
            $defenders,
155 8
            count($attackers) + count($defenders) > 2
156 8
        ];
157
    }
158
159
    /** @return array<int, ShipWrapperInterface> */
160 8
    public function getAttackers(ShipWrapperInterface $wrapper): array
161
    {
162 8
        $ship = $wrapper->get();
163 8
        $fleet = $wrapper->getFleetWrapper();
164
165 8
        if ($ship->isFleetLeader() && $fleet !== null) {
166 1
            $attackers = $fleet->getShipWrappers();
167
        } else {
168 7
            $attackers = [$ship->getId() => $wrapper];
169
        }
170
171 8
        return $attackers;
172
    }
173
174
    /** @return array<int, ShipWrapperInterface> */
175 8
    private function getDefenders(ShipWrapperInterface $targetWrapper): array
176
    {
177 8
        $target = $targetWrapper->get();
178 8
        $targetFleet = $targetWrapper->getFleetWrapper();
179
180 8
        if ($targetFleet !== null) {
181 3
            $defenders = [];
182
183
            // only uncloaked defenders fight
184 3
            foreach ($targetFleet->getShipWrappers() as $shipId => $defWrapper) {
185
186 3
                $defShip = $defWrapper->get();
187 3
                if (!$defShip->getCloakState()) {
188 3
                    $defenders[$shipId] = $defWrapper;
189
190 3
                    $this->addDockedToAsDefender($targetWrapper, $defenders);
191
                }
192
            }
193
194
            // if all defenders were cloaked, they obviously were scanned and enter the fight as a whole fleet
195 3
            if ($defenders === []) {
196
                $defenders = $targetFleet->getShipWrappers();
197
            }
198
        } else {
199 5
            $defenders = [$target->getId() => $targetWrapper];
200
201 5
            $this->addDockedToAsDefender($targetWrapper, $defenders);
202
        }
203
204 8
        return $defenders;
205
    }
206
207
    /** @param array<int, ShipWrapperInterface> $defenders */
208 8
    private function addDockedToAsDefender(ShipWrapperInterface $targetWrapper, array &$defenders): void
209
    {
210 8
        $dockedToWrapper = $targetWrapper->getDockedToShipWrapper();
211
        if (
212 8
            $dockedToWrapper !== null
213 8
            && !$dockedToWrapper->get()->getUser()->isNpc()
214 8
            && $dockedToWrapper->get()->hasActiveWeapon()
215
        ) {
216 2
            $defenders[$dockedToWrapper->get()->getId()] = $dockedToWrapper;
217
        }
218
    }
219
220 4
    public function isTargetOutsideFinishedTholianWeb(ShipInterface $ship, ShipInterface $target): bool
221
    {
222 4
        $web = $ship->getHoldingWeb();
223 4
        if ($web === null) {
224 1
            return false;
225
        }
226
227 3
        return $web->isFinished() && ($target->getHoldingWeb() !== $web);
228
    }
229
230 6
    public static function isBoardingPossible(ShipInterface|ShipNfsItem $ship): bool
231
    {
232 6
        return !(User::isUserNpc($ship->getUserId())
0 ignored issues
show
Deprecated Code introduced by
The function Stu\Orm\Entity\ShipInterface::getUserId() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

232
        return !(User::isUserNpc(/** @scrutinizer ignore-deprecated */ $ship->getUserId())
Loading history...
233 6
            || $ship->isBase()
234 6
            || $ship->isTrumfield()
235 6
            || $ship->getCloakState()
236 6
            || $ship->getShieldState()
237 6
            || $ship->getWarpState());
238
    }
239
}