Passed
Push — dev ( 03e8c2...8cc6aa )
by Nico
07:39
created

ProjectileWeaponPhase::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib\Battle\Weapon;
6
7
use Stu\Lib\DamageWrapper;
8
use Stu\Module\Ship\Lib\Battle\Message\FightMessage;
9
use Stu\Module\Ship\Lib\Battle\Provider\ProjectileAttackerInterface;
10
use Stu\Orm\Entity\PlanetFieldInterface;
11
use Stu\Orm\Entity\TorpedoTypeInterface;
12
use Stu\Orm\Repository\TorpedoHullRepositoryInterface;
13
14
//TODO unit tests
15
final class ProjectileWeaponPhase extends AbstractWeaponPhase implements ProjectileWeaponPhaseInterface
16
{
17
    private TorpedoHullRepositoryInterface $torpedoHullRepository;
18
19
    public function __construct(
20
        TorpedoHullRepositoryInterface $torpedoHullRepository
21
    ) {
22
        $this->torpedoHullRepository = $torpedoHullRepository;
23
    }
24
25
    public function fire(
26
        ProjectileAttackerInterface $attacker,
27
        array $targetPool,
28
        bool $isAlertRed = false
29
    ): array {
30
        $fightMessages = [];
31
32
        for ($i = 1; $i <= $attacker->getTorpedoVolleys(); $i++) {
33
            if (count($targetPool) === 0) {
34
                break;
35
            }
36
37
            $torpedo = $attacker->getTorpedo();
38
            $targetWrapper = $targetPool[array_rand($targetPool)];
39
            $target = $targetWrapper->get();
40
41
            if (
42
                $torpedo === null
43
                || !$attacker->getTorpedoState()
44
                || !$attacker->hasSufficientEnergy($this->getProjectileWeaponEnergyCosts())
45
                || $attacker->getTorpedoCount() === 0
46
            ) {
47
                break;
48
            }
49
50
            $torpedoName =  $torpedo->getName();
51
52
            $attacker->lowerTorpedoCount(1);
53
            $attacker->reduceEps($this->getProjectileWeaponEnergyCosts());
54
55
            $fightMessage = new FightMessage($attacker->getUser()->getId(), $target->getUser()->getId());
56
            $fightMessages[] = $fightMessage;
57
58
            $fightMessage->add("Die " . $attacker->getName() . " feuert einen " . $torpedoName . " auf die " . $target->getName());
59
60
            $hitchance = $attacker->getHitChance();
61
            if ($hitchance * (100 - $target->getEvadeChance()) < rand(1, 10000)) {
62
                $fightMessage->add("Die " . $target->getName() . " wurde verfehlt");
63
                continue;
64
            }
65
66
            $isCritical = $this->isCritical($torpedo, $target->getCloakState());
67
68
            $damage_wrapper = new DamageWrapper(
69
                $attacker->getProjectileWeaponDamage($isCritical),
70
                $attacker
71
            );
72
            $damage_wrapper->setCrit($isCritical);
73
            $damage_wrapper->setShieldDamageFactor($torpedo->getShieldDamageFactor());
74
            $damage_wrapper->setHullDamageFactor($torpedo->getHullDamageFactor());
75
            $damage_wrapper->setIsTorpedoDamage(true);
76
            $damage_wrapper->setModificator($this->torpedoHullRepository->getByModuleAndTorpedo((int)implode($target->getBuildplan()->getModulesByType(1)), $torpedo->getId())->getModificator());
77
78
            $fightMessage->addMessageMerge($this->applyDamage->damage($damage_wrapper, $targetWrapper));
79
80
            if ($target->isDestroyed()) {
81
                unset($targetPool[$target->getId()]);
82
83
                if ($isAlertRed) {
84
                    $this->entryCreator->addShipEntry(
85
                        '[b][color=red]Alarm-Rot:[/color][/b] Die ' . $target->getName() . ' (' . $target->getRump()->getName() . ') wurde in Sektor ' . $target->getSectorString() . ' von der ' . $attacker->getName() . ' zerstört',
86
                        $attacker->getUser()->getId()
87
                    );
88
                } else {
89
                    $entryMsg = sprintf(
90
                        'Die %s (%s) wurde in Sektor %s von der %s zerstört',
91
                        $target->getName(),
92
                        $target->getRump()->getName(),
93
                        $target->getSectorString(),
94
                        $attacker->getName()
95
                    );
96
                    if ($target->isBase()) {
97
                        $this->entryCreator->addStationEntry(
98
                            $entryMsg,
99
                            $attacker->getUser()->getId()
100
                        );
101
                    } else {
102
                        $this->entryCreator->addShipEntry(
103
                            $entryMsg,
104
                            $attacker->getUser()->getId()
105
                        );
106
                    }
107
                }
108
                $this->checkForPrestige($attacker->getUser(), $target);
109
                $fightMessage->add($this->shipRemover->destroy($targetWrapper));
110
            }
111
        }
112
113
        return $fightMessages;
114
    }
115
116
    public function fireAtBuilding(
117
        ProjectileAttackerInterface $attacker,
118
        PlanetFieldInterface $target,
119
        bool $isOrbitField,
120
        int &$antiParticleCount
121
    ): array {
122
        $building = $target->getBuilding();
123
        if ($building === null) {
124
            return [];
125
        }
126
127
        $msg = [];
128
        for ($i = 1; $i <= $attacker->getTorpedoVolleys(); $i++) {
129
            $torpedo = $attacker->getTorpedo();
130
131
            if (
132
                $torpedo === null
133
                || !$attacker->getTorpedoState()
134
                || !$attacker->hasSufficientEnergy($this->getProjectileWeaponEnergyCosts())
135
            ) {
136
                break;
137
            }
138
139
            $attacker->lowerTorpedoCount(1);
140
            $attacker->reduceEps($this->getProjectileWeaponEnergyCosts());
141
142
            $msg[] = sprintf(
143
                _("Die %s feuert einen %s auf das Gebäude %s auf Feld %d"),
144
                $attacker->getName(),
145
                $torpedo->getName(),
146
                $building->getName(),
147
                $target->getFieldId()
148
            );
149
150
            if ($antiParticleCount > 0) {
151
                $antiParticleCount--;
152
                $msg[] = "Der Torpedo wurde vom orbitalem Torpedoabwehrsystem abgefangen";
153
                continue;
154
            }
155
            if ($attacker->getHitChance() < rand(1, 100)) {
156
                $msg[] = "Das Gebäude wurde verfehlt";
157
                continue;
158
            }
159
            $isCritical = rand(1, 100) <= $torpedo->getCriticalChance();
160
            $damage_wrapper = new DamageWrapper(
161
                $attacker->getProjectileWeaponDamage($isCritical),
162
                $attacker
163
            );
164
            $damage_wrapper->setCrit($isCritical);
165
            $damage_wrapper->setShieldDamageFactor($torpedo->getShieldDamageFactor());
166
            $damage_wrapper->setHullDamageFactor($torpedo->getHullDamageFactor());
167
            $damage_wrapper->setIsTorpedoDamage(true);
168
169
            $msg = array_merge($msg, $this->applyDamage->damageBuilding($damage_wrapper, $target, $isOrbitField));
170
171
            if ($target->getIntegrity() === 0) {
172
                $this->entryCreator->addColonyEntry(
173
                    sprintf(
174
                        _('Das Gebäude %s auf Kolonie %s wurde von der %s zerstört'),
175
                        $building->getName(),
176
                        $target->getColony()->getName(),
177
                        $attacker->getName()
178
                    )
179
                );
180
181
                $this->buildingManager->remove($target);
182
                break;
183
            }
184
            //deactivate if high damage
185
            elseif ($target->hasHighDamage()) {
186
                $this->buildingManager->deactivate($target);
187
            }
188
        }
189
190
        return $msg;
191
    }
192
193
    private function getProjectileWeaponEnergyCosts(): int
194
    {
195
        // @todo
196
        return 1;
197
    }
198
199
    private function isCritical(TorpedoTypeInterface $torpedo, bool $isTargetCloaked): bool
200
    {
201
        $critChance = $isTargetCloaked ? $torpedo->getCriticalChance() * 2 : $torpedo->getCriticalChance();
202
        if (rand(1, 100) <= $critChance) {
203
            return true;
204
        }
205
        return false;
206
    }
207
}
208