Passed
Pull Request — master (#1821)
by Nico
52:02 queued 25:23
created

EnergyWeaponPhase::fire()   B

Complexity

Conditions 9
Paths 5

Size

Total Lines 73
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 42
CRAP Score 9.0533

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 9
eloc 43
c 3
b 1
f 0
nc 5
nop 3
dl 0
loc 73
ccs 42
cts 46
cp 0.913
crap 9.0533
rs 7.6764

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\Battle\Party\BattlePartyInterface;
11
use Stu\Module\Ship\Lib\Message\Message;
12
use Stu\Module\Ship\Lib\Battle\Provider\EnergyAttackerInterface;
13
use Stu\Module\Ship\Lib\Battle\ShipAttackCauseEnum;
14
use Stu\Orm\Entity\PlanetFieldInterface;
15
use Stu\Orm\Entity\ShipInterface;
16
use Stu\Orm\Entity\WeaponInterface;
17
18
//TODO unit tests
19
final class EnergyWeaponPhase extends AbstractWeaponPhase implements EnergyWeaponPhaseInterface
20
{
21
    public const FIRINGMODE_RANDOM = 1;
22
    public const FIRINGMODE_FOCUS = 2;
23
24 1
    public function fire(
25
        EnergyAttackerInterface $attacker,
26
        BattlePartyInterface $targetPool,
27
        ShipAttackCauseEnum $attackCause
28
    ): array {
29 1
        $messages = [];
30
31
32 1
        $phaserVolleys = $attacker->getPhaserVolleys();
33 1
        for ($i = 1; $i <= $phaserVolleys; $i++) {
34 1
            if ($targetPool->isDefeated()) {
35 1
                break;
36
            }
37 1
            if (!$attacker->getPhaserState() || !$attacker->hasSufficientEnergy($this->getEnergyWeaponEnergyCosts())) {
38
                break;
39
            }
40
41 1
            $weapon = $attacker->getWeapon();
42
43 1
            $attacker->reduceEps($this->getEnergyWeaponEnergyCosts());
44
45 1
            $targetWrapper = $targetPool->getRandomActiveMember();
46 1
            if ($attacker->getFiringMode() === self::FIRINGMODE_RANDOM) {
47 1
                $targetWrapper = $targetPool->getRandomActiveMember();
48
            }
49
50 1
            $target = $targetWrapper->get();
51
52 1
            $message = new Message($attacker->getUser()->getId(), $target->getUser()->getId());
53 1
            $messages[] = $message;
54
55 1
            $message->add(sprintf(
56 1
                "Die %s feuert mit einem %s auf die %s",
57 1
                $attacker->getName(),
58 1
                $weapon->getName(),
59 1
                $target->getName()
60 1
            ));
61
62
            if (
63 1
                $attacker->getHitChance() * (100 - $target->getEvadeChance()) < $this->stuRandom->rand(1, 10000)
64
            ) {
65
                $message->add("Die " . $target->getName() . " wurde verfehlt");
66
                continue;
67
            }
68 1
            $isCritical = $this->isCritical($weapon, $target->getCloakState());
69 1
            $damage_wrapper = new DamageWrapper(
70 1
                $attacker->getWeaponDamage($isCritical)
71 1
            );
72 1
            $damage_wrapper->setCrit($isCritical);
73 1
            $damage_wrapper->setShieldDamageFactor($attacker->getPhaserShieldDamageFactor());
74 1
            $damage_wrapper->setHullDamageFactor($attacker->getPhaserHullDamageFactor());
75 1
            $damage_wrapper->setIsPhaserDamage(true);
76 1
            $damage_wrapper->setPirateWrath($attacker->getUser(), $target);
77 1
            $this->setWeaponShieldModificator($target, $weapon, $damage_wrapper);
78
79 1
            $message->addMessageMerge($this->applyDamage->damage($damage_wrapper, $targetWrapper)->getInformations());
80
81 1
            if ($target->isDestroyed()) {
82
83 1
                $this->checkForShipDestruction(
84 1
                    $attacker,
85 1
                    $targetWrapper,
86 1
                    $attackCause->getDestructionCause(),
87 1
                    $message
88 1
                );
89
90 1
                if ($weapon->getFiringMode() === self::FIRINGMODE_FOCUS) {
91
                    break;
92
                }
93
            }
94
        }
95
96 1
        return $messages;
97
    }
98
99
    public function fireAtBuilding(
100
        EnergyAttackerInterface $attacker,
101
        PlanetFieldInterface $target,
102
        bool $isOrbitField
103
    ): InformationWrapper {
104
        $informations = new InformationWrapper();
105
106
        $building = $target->getBuilding();
107
        if ($building === null) {
108
            $informations->addInformation(_("Kein Gebäude vorhanden"));
109
110
            return $informations;
111
        }
112
113
        for ($i = 1; $i <= $attacker->getPhaserVolleys(); $i++) {
114
            if (!$attacker->getPhaserState() || !$attacker->hasSufficientEnergy($this->getEnergyWeaponEnergyCosts())) {
115
                break;
116
            }
117
            $attacker->reduceEps($this->getEnergyWeaponEnergyCosts());
118
119
            $weapon = $attacker->getWeapon();
120
            $informations->addInformation(sprintf(
121
                _("Die %s feuert mit einem %s auf das Gebäude %s auf Feld %d"),
122
                $attacker->getName(),
123
                $weapon->getName(),
124
                $building->getName(),
125
                $target->getFieldId()
126
            ));
127
128
            if (
129
                $attacker->getHitChance() < random_int(1, 100)
130
            ) {
131
                $informations->addInformation(_("Das Gebäude wurde verfehlt"));
132
                continue;
133
            }
134
135
            $isCritical = random_int(1, 100) <= $weapon->getCriticalChance();
136
137
            $damage_wrapper = new DamageWrapper(
138
                $attacker->getWeaponDamage($isCritical)
139
            );
140
            $damage_wrapper->setCrit($isCritical);
141
            $damage_wrapper->setShieldDamageFactor($attacker->getPhaserShieldDamageFactor());
142
            $damage_wrapper->setHullDamageFactor($attacker->getPhaserHullDamageFactor());
143
            $damage_wrapper->setIsPhaserDamage(true);
144
145
146
            $informations->addInformationWrapper($this->applyDamage->damageBuilding($damage_wrapper, $target, $isOrbitField));
147
148
            if ($target->getIntegrity() === 0) {
149
                $this->entryCreator->addEntry(
150
                    sprintf(
151
                        _('Das Gebäude %s auf Kolonie %s wurde von der %s zerstört'),
152
                        $building->getName(),
153
                        $target->getHost()->getName(),
154
                        $attacker->getName()
155
                    ),
156
                    $attacker->getUser()->getId(),
157
                    $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

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