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

EnergyWeaponPhase::getEnergyWeaponEnergyCosts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
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