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

EnergyWeaponPhase   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Test Coverage

Coverage 49.04%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 97
c 3
b 1
f 0
dl 0
loc 181
ccs 51
cts 104
cp 0.4904
rs 10
wmc 23

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setWeaponShieldModificator() 0 15 3
A isCritical() 0 4 2
A getEnergyWeaponEnergyCosts() 0 4 1
B fireAtBuilding() 0 71 8
B fire() 0 73 9
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