Passed
Push — master ( f544cb...b3a3d9 )
by Nico
36:43 queued 09:10
created

EnergyWeaponPhase::fire()   C

Complexity

Conditions 11
Paths 9

Size

Total Lines 96
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 52
CRAP Score 11.7975

Importance

Changes 0
Metric Value
cc 11
eloc 60
c 0
b 0
f 0
nc 9
nop 3
dl 0
loc 96
ccs 52
cts 64
cp 0.8125
crap 11.7975
rs 6.726

How to fix   Long Method    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\Weapon;
6
7
use Stu\Component\Ship\ShipModuleTypeEnum;
8
use Stu\Lib\DamageWrapper;
9
use Stu\Lib\InformationWrapper;
10
use Stu\Module\Ship\Lib\Message\Message;
11
use Stu\Module\Ship\Lib\Battle\Provider\EnergyAttackerInterface;
12
use Stu\Orm\Entity\PlanetFieldInterface;
13
use Stu\Orm\Entity\ShipInterface;
14
use Stu\Orm\Entity\WeaponInterface;
15
16
//TODO unit tests
17
final class EnergyWeaponPhase extends AbstractWeaponPhase implements EnergyWeaponPhaseInterface
18
{
19
    public const FIRINGMODE_RANDOM = 1;
20
    public const FIRINGMODE_FOCUS = 2;
21
22 1
    public function fire(
23
        EnergyAttackerInterface $attacker,
24
        array $targetPool,
25
        bool $isAlertRed = false
26
    ): array {
27 1
        $messages = [];
28
29 1
        $targetWrapper = $targetPool[array_rand($targetPool)];
30
31 1
        $phaserVolleys = $attacker->getPhaserVolleys();
32 1
        for ($i = 1; $i <= $phaserVolleys; $i++) {
33 1
            if (empty($targetPool)) {
34 1
                break;
35
            }
36 1
            if (!$attacker->getPhaserState() || !$attacker->hasSufficientEnergy($this->getEnergyWeaponEnergyCosts())) {
37
                break;
38
            }
39
40 1
            $weapon = $attacker->getWeapon();
41
42 1
            $attacker->reduceEps($this->getEnergyWeaponEnergyCosts());
43 1
            if ($attacker->getFiringMode() === self::FIRINGMODE_RANDOM) {
44 1
                $targetWrapper = $targetPool[array_rand($targetPool)];
45
            }
46
47 1
            $target = $targetWrapper->get();
48
49 1
            $message = new Message($attacker->getUser()->getId(), $target->getUser()->getId());
50 1
            $messages[] = $message;
51
52 1
            $message->add(sprintf(
53 1
                "Die %s feuert mit einem %s auf die %s",
54 1
                $attacker->getName(),
55 1
                $weapon->getName(),
56 1
                $target->getName()
57 1
            ));
58
59
            if (
60 1
                $attacker->getHitChance() * (100 - $target->getEvadeChance()) < $this->stuRandom->rand(1, 10000)
61
            ) {
62
                $message->add("Die " . $target->getName() . " wurde verfehlt");
63
                continue;
64
            }
65 1
            $isCritical = $this->isCritical($weapon, $target->getCloakState());
66 1
            $damage_wrapper = new DamageWrapper(
67 1
                $attacker->getWeaponDamage($isCritical)
68 1
            );
69 1
            $damage_wrapper->setCrit($isCritical);
70 1
            $damage_wrapper->setShieldDamageFactor($attacker->getPhaserShieldDamageFactor());
71 1
            $damage_wrapper->setHullDamageFactor($attacker->getPhaserHullDamageFactor());
72 1
            $damage_wrapper->setIsPhaserDamage(true);
73 1
            $this->setWeaponShieldModificator($target, $weapon, $damage_wrapper);
74
75 1
            $message->addMessageMerge($this->applyDamage->damage($damage_wrapper, $targetWrapper)->getInformations());
76
77 1
            if ($target->isDestroyed()) {
78 1
                if ($isAlertRed) {
79
                    $this->entryCreator->addShipEntry(
80
                        '[b][color=red]Alarm-Rot:[/color][/b] Die ' . $target->getName() . ' (' . $target->getRump()->getName() . ') wurde in Sektor ' . $target->getSectorString() . ' von der ' . $attacker->getName() . ' zerstört',
81
                        $attacker->getUser()->getId()
82
                    );
83
                } else {
84 1
                    $entryMsg = sprintf(
85 1
                        'Die %s (%s) wurde in Sektor %s von der %s zerstört',
86 1
                        $target->getName(),
87 1
                        $target->getRump()->getName(),
88 1
                        $target->getSectorString(),
89 1
                        $attacker->getName()
90 1
                    );
91 1
                    if ($target->isBase()) {
92
                        $this->entryCreator->addStationEntry(
93
                            $entryMsg,
94
                            $attacker->getUser()->getId()
95
                        );
96
                    } else {
97 1
                        $this->entryCreator->addShipEntry(
98 1
                            $entryMsg,
99 1
                            $attacker->getUser()->getId()
100 1
                        );
101
                    }
102
                }
103
104 1
                $this->checkForPrestige($attacker->getUser(), $target);
105
106 1
                $targetId = $target->getId();
107 1
                $message->add($this->shipRemover->destroy($targetWrapper));
108
109 1
                unset($targetPool[$targetId]);
110
111 1
                if ($weapon->getFiringMode() === self::FIRINGMODE_FOCUS) {
112
                    break;
113
                }
114
            }
115
        }
116
117 1
        return $messages;
118
    }
119
120
    public function fireAtBuilding(
121
        EnergyAttackerInterface $attacker,
122
        PlanetFieldInterface $target,
123
        bool $isOrbitField
124
    ): InformationWrapper {
125
        $informations = new InformationWrapper();
126
127
        $building = $target->getBuilding();
128
        if ($building === null) {
129
            $informations->addInformation(_("Kein Gebäude vorhanden"));
130
131
            return $informations;
132
        }
133
134
        for ($i = 1; $i <= $attacker->getPhaserVolleys(); $i++) {
135
            if (!$attacker->getPhaserState() || !$attacker->hasSufficientEnergy($this->getEnergyWeaponEnergyCosts())) {
136
                break;
137
            }
138
            $attacker->reduceEps($this->getEnergyWeaponEnergyCosts());
139
140
            $weapon = $attacker->getWeapon();
141
            $informations->addInformation(sprintf(
142
                _("Die %s feuert mit einem %s auf das Gebäude %s auf Feld %d"),
143
                $attacker->getName(),
144
                $weapon->getName(),
145
                $building->getName(),
146
                $target->getFieldId()
147
            ));
148
149
            if (
150
                $attacker->getHitChance() < random_int(1, 100)
151
            ) {
152
                $informations->addInformation(_("Das Gebäude wurde verfehlt"));
153
                continue;
154
            }
155
156
            $isCritical = random_int(1, 100) <= $weapon->getCriticalChance();
157
158
            $damage_wrapper = new DamageWrapper(
159
                $attacker->getWeaponDamage($isCritical)
160
            );
161
            $damage_wrapper->setCrit($isCritical);
162
            $damage_wrapper->setShieldDamageFactor($attacker->getPhaserShieldDamageFactor());
163
            $damage_wrapper->setHullDamageFactor($attacker->getPhaserHullDamageFactor());
164
            $damage_wrapper->setIsPhaserDamage(true);
165
166
167
            $informations->addInformationWrapper($this->applyDamage->damageBuilding($damage_wrapper, $target, $isOrbitField));
168
169
            if ($target->getIntegrity() === 0) {
170
                $this->entryCreator->addColonyEntry(
171
                    sprintf(
172
                        _('Das Gebäude %s auf Kolonie %s wurde von der %s zerstört'),
173
                        $building->getName(),
174
                        $target->getHost()->getName(),
175
                        $attacker->getName()
176
                    )
177
                );
178
179
                $this->buildingManager->remove($target);
180
                break;
181
            }
182
            //deactivate if high damage
183
            elseif ($target->hasHighDamage()) {
184
                $this->buildingManager->deactivate($target);
185
            }
186
        }
187
188
        return $informations;
189
    }
190
191 1
    private function isCritical(WeaponInterface $weapon, bool $isTargetCloaked): bool
192
    {
193 1
        $critChance = $isTargetCloaked ? $weapon->getCriticalChance() * 2 : $weapon->getCriticalChance();
194 1
        return $this->stuRandom->rand(1, 100) <= $critChance;
195
    }
196
197 1
    private function setWeaponShieldModificator(
198
        ShipInterface $target,
199
        WeaponInterface $weapon,
200
        DamageWrapper $damageWrapper
201
    ): void {
202
203 1
        $targetShieldModule = $this->getModule($target, ShipModuleTypeEnum::MODULE_TYPE_SHIELDS);
204 1
        if ($targetShieldModule === null) {
205 1
            return;
206
        }
207
208
        $weaponShield = $targetShieldModule->getWeaponShield()->get($weapon->getId());
209
210
        if ($weaponShield !== null) {
211
            $damageWrapper->setModificator($weaponShield->getModificator());
212
        }
213
    }
214
215 1
    private function getEnergyWeaponEnergyCosts(): int
216
    {
217
        // @todo
218 1
        return 1;
219
    }
220
}
221