Passed
Push — dev ( b851e4...f48036 )
by Janko
48:24 queued 21:52
created

EnergyWeaponPhase::fire()   B

Complexity

Conditions 9
Paths 5

Size

Total Lines 72
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 9.0608

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 9
eloc 42
nc 5
nop 3
dl 0
loc 72
ccs 40
cts 44
cp 0.9091
crap 9.0608
rs 7.6924
c 2
b 0
f 0

How to fix   Long Method   

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\Information\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
            $damage_wrapper->setPirateWrath($attacker->getUser(), $target);
74 1
            $this->setWeaponShieldModificator($target, $weapon, $damage_wrapper);
75
76 1
            $message->addMessageMerge($this->applyDamage->damage($damage_wrapper, $targetWrapper)->getInformations());
77
78 1
            if ($target->isDestroyed()) {
79
80 1
                $this->handleDestruction($attacker, $target, $isAlertRed);
81
82 1
                $targetId = $target->getId();
83 1
                $message->add($this->shipRemover->destroy($targetWrapper));
84
85 1
                unset($targetPool[$targetId]);
86
87 1
                if ($weapon->getFiringMode() === self::FIRINGMODE_FOCUS) {
88
                    break;
89
                }
90
            }
91
        }
92
93 1
        return $messages;
94
    }
95
96
    public function fireAtBuilding(
97
        EnergyAttackerInterface $attacker,
98
        PlanetFieldInterface $target,
99
        bool $isOrbitField
100
    ): InformationWrapper {
101
        $informations = new InformationWrapper();
102
103
        $building = $target->getBuilding();
104
        if ($building === null) {
105
            $informations->addInformation(_("Kein Gebäude vorhanden"));
106
107
            return $informations;
108
        }
109
110
        for ($i = 1; $i <= $attacker->getPhaserVolleys(); $i++) {
111
            if (!$attacker->getPhaserState() || !$attacker->hasSufficientEnergy($this->getEnergyWeaponEnergyCosts())) {
112
                break;
113
            }
114
            $attacker->reduceEps($this->getEnergyWeaponEnergyCosts());
115
116
            $weapon = $attacker->getWeapon();
117
            $informations->addInformation(sprintf(
118
                _("Die %s feuert mit einem %s auf das Gebäude %s auf Feld %d"),
119
                $attacker->getName(),
120
                $weapon->getName(),
121
                $building->getName(),
122
                $target->getFieldId()
123
            ));
124
125
            if (
126
                $attacker->getHitChance() < random_int(1, 100)
127
            ) {
128
                $informations->addInformation(_("Das Gebäude wurde verfehlt"));
129
                continue;
130
            }
131
132
            $isCritical = random_int(1, 100) <= $weapon->getCriticalChance();
133
134
            $damage_wrapper = new DamageWrapper(
135
                $attacker->getWeaponDamage($isCritical)
136
            );
137
            $damage_wrapper->setCrit($isCritical);
138
            $damage_wrapper->setShieldDamageFactor($attacker->getPhaserShieldDamageFactor());
139
            $damage_wrapper->setHullDamageFactor($attacker->getPhaserHullDamageFactor());
140
            $damage_wrapper->setIsPhaserDamage(true);
141
142
143
            $informations->addInformationWrapper($this->applyDamage->damageBuilding($damage_wrapper, $target, $isOrbitField));
144
145
            if ($target->getIntegrity() === 0) {
146
                $this->entryCreator->addEntry(
147
                    sprintf(
148
                        _('Das Gebäude %s auf Kolonie %s wurde von der %s zerstört'),
149
                        $building->getName(),
150
                        $target->getHost()->getName(),
151
                        $attacker->getName()
152
                    ),
153
                    $attacker->getUser()->getId(),
154
                    $target->getHost()
0 ignored issues
show
Bug introduced by
It seems like $target->getHost() can also be of type Stu\Orm\Entity\ColonySandboxInterface; however, parameter $target of Stu\Module\History\Lib\E...orInterface::addEntry() does only seem to accept Stu\Orm\Entity\AllianceI...rm\Entity\ShipInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

154
                    /** @scrutinizer ignore-type */ $target->getHost()
Loading history...
155
                );
156
157
                $this->buildingManager->remove($target);
158
                break;
159
            }
160
            //deactivate if high damage
161
            elseif ($target->hasHighDamage()) {
162
                $this->buildingManager->deactivate($target);
163
            }
164
        }
165
166
        return $informations;
167
    }
168
169 1
    private function isCritical(WeaponInterface $weapon, bool $isTargetCloaked): bool
170
    {
171 1
        $critChance = $isTargetCloaked ? $weapon->getCriticalChance() * 2 : $weapon->getCriticalChance();
172 1
        return $this->stuRandom->rand(1, 100) <= $critChance;
173
    }
174
175 1
    private function setWeaponShieldModificator(
176
        ShipInterface $target,
177
        WeaponInterface $weapon,
178
        DamageWrapper $damageWrapper
179
    ): void {
180
181 1
        $targetShieldModule = $this->getModule($target, ShipModuleTypeEnum::SHIELDS);
182 1
        if ($targetShieldModule === null) {
183 1
            return;
184
        }
185
186
        $weaponShield = $targetShieldModule->getWeaponShield()->get($weapon->getId());
187
188
        if ($weaponShield !== null) {
189
            $damageWrapper->setModificator($weaponShield->getModificator());
190
        }
191
    }
192
193 1
    private function getEnergyWeaponEnergyCosts(): int
194
    {
195
        // @todo
196 1
        return 1;
197
    }
198
}
199