Passed
Push — dev ( fc77d3...501ee6 )
by Janko
33:44
created

ApplyDamage::damageShields()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 3
dl 0
loc 15
ccs 0
cts 10
cp 0
crap 6
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Ship\Lib\Damage;
6
7
use RuntimeException;
8
use Stu\Component\Ship\ShipEnum;
9
use Stu\Component\Ship\System\ShipSystemManagerInterface;
10
use Stu\Component\Ship\System\ShipSystemModeEnum;
11
use Stu\Component\Ship\System\ShipSystemTypeEnum;
12
use Stu\Lib\DamageWrapper;
13
use Stu\Lib\Information\InformationInterface;
14
use Stu\Lib\Information\InformationWrapper;
15
use Stu\Module\Colony\Lib\ColonyLibFactoryInterface;
16
use Stu\Module\Ship\Lib\ShipWrapperInterface;
17
use Stu\Orm\Entity\ColonyInterface;
18
use Stu\Orm\Entity\PlanetFieldInterface;
19
use Stu\Orm\Entity\ShipSystemInterface;
20
21
//TODO unit tests and move to Lib/Damage
22
final class ApplyDamage implements ApplyDamageInterface
23
{
24 2
    public function __construct(
25
        private ColonyLibFactoryInterface $colonyLibFactory,
26
        private ShipSystemManagerInterface $shipSystemManager
27
    ) {
28 2
    }
29
30
    public function damage(
31
        DamageWrapper $damageWrapper,
32
        ShipWrapperInterface $shipWrapper
33
    ): InformationWrapper {
34
        $ship = $shipWrapper->get();
35
        $ship->setShieldRegenerationTimer(time());
36
37
        $informations = new InformationWrapper();
38
        if ($ship->getShieldState()) {
39
40
            if ($damageWrapper->isShieldPenetration()) {
41
                $informations->addInformationf('- Projektil hat Schilde durchdrungen!');
42
            } else {
43
                $this->damageShields($shipWrapper, $damageWrapper, $informations);
44
            }
45
        }
46
        if ($damageWrapper->getNetDamage() <= 0) {
47
            return $informations;
48
        }
49
50
        $disablemessage = false;
51
        $damage = (int) $damageWrapper->getDamageRelative($ship, ShipEnum::DAMAGE_MODE_HULL);
52
        if ($ship->getSystemState(ShipSystemTypeEnum::SYSTEM_RPG_MODULE) && $ship->getHull() - $damage < round($ship->getMaxHull() / 100 * 10)) {
53
            $damage = (int) round($ship->getHull() - $ship->getMaxHull() / 100 * 10);
54
            $disablemessage = _('-- Das Schiff wurde kampfunfähig gemacht');
55
            $ship->setDisabled(true);
56
        }
57
        if ($ship->getHull() > $damage) {
58
            if ($damageWrapper->isCrit()) {
59
                $systemName = $this->destroyRandomShipSystem($shipWrapper);
60
61
                if ($systemName !== null) {
62
                    $informations->addInformation("- Kritischer Hüllen-Treffer zerstört System: " . $systemName);
63
                }
64
            }
65
            $huelleVorher = $ship->getHull();
66
            $ship->setHuell($huelleVorher - $damage);
67
            $informations->addInformation("- Hüllenschaden: " . $damage . " - Status: " . $ship->getHull());
68
69
            if (!$this->checkForDamagedShipSystems(
70
                $shipWrapper,
71
                $huelleVorher,
72
                $informations
73
            )) {
74
                $this->damageRandomShipSystem(
75
                    $shipWrapper,
76
                    $informations,
77
                    (int)ceil((100 * $damage * random_int(1, 5)) / $ship->getMaxHull())
78
                );
79
            }
80
81
            if ($disablemessage) {
82
                $informations->addInformation($disablemessage);
83
            }
84
85
            if ($ship->isDestroyed()) {
86
                $informations->addInformation("-- Das Schiff wurde zerstört!");
87
            }
88
89
            return $informations;
90
        }
91
        $informations->addInformation("- Hüllenschaden: " . $damage);
92
        $informations->addInformation("-- Das Schiff wurde zerstört!");
93
        $ship->setIsDestroyed(true);
94
95
        return $informations;
96
    }
97
98
    private function damageShields(ShipWrapperInterface $wrapper, DamageWrapper $damageWrapper, InformationInterface $informations): void
99
    {
100
        $ship = $wrapper->get();
101
102
        $damage = (int) $damageWrapper->getDamageRelative($ship, ShipEnum::DAMAGE_MODE_SHIELDS);
103
        if ($damage >= $ship->getShield()) {
104
            $informations->addInformation("- Schildschaden: " . $ship->getShield());
105
            $informations->addInformation("-- Schilde brechen zusammen!");
106
107
            $this->shipSystemManager->deactivate($wrapper, ShipSystemTypeEnum::SYSTEM_SHIELDS);
108
109
            $ship->setShield(0);
110
        } else {
111
            $ship->setShield($ship->getShield() - $damage);
112
            $informations->addInformation("- Schildschaden: " . $damage . " - Status: " . $ship->getShield());
113
        }
114
    }
115
116
    public function damageBuilding(
117
        DamageWrapper $damageWrapper,
118
        PlanetFieldInterface $target,
119
        bool $isOrbitField
120
    ): InformationWrapper {
121
        $informations = new InformationWrapper();
122
123
        $colony = $target->getHost();
124
        if (!$colony instanceof ColonyInterface) {
125
            throw new RuntimeException('this should not happen');
126
        }
127
128
        if (!$isOrbitField && $this->colonyLibFactory->createColonyShieldingManager($colony)->isShieldingEnabled()) {
129
            $damage = (int) $damageWrapper->getDamageRelative($colony, ShipEnum::DAMAGE_MODE_SHIELDS);
130
            if ($damage > $colony->getShields()) {
131
                $informations->addInformation("- Schildschaden: " . $colony->getShields());
132
                $informations->addInformation("-- Schilde brechen zusammen!");
133
134
                $colony->setShields(0);
135
            } else {
136
                $colony->setShields($colony->getShields() - $damage);
137
                $informations->addInformation("- Schildschaden: " . $damage . " - Status: " . $colony->getShields());
138
            }
139
        }
140
        if ($damageWrapper->getNetDamage() <= 0) {
141
            return $informations;
142
        }
143
        $damage = (int) $damageWrapper->getDamageRelative($colony, ShipEnum::DAMAGE_MODE_HULL);
144
        if ($target->getIntegrity() > $damage) {
145
            $target->setIntegrity($target->getIntegrity() - $damage);
146
            $informations->addInformation("- Gebäudeschaden: " . $damage . " - Status: " . $target->getIntegrity());
147
148
            return $informations;
149
        }
150
        $informations->addInformation("- Gebäudeschaden: " . $damage);
151
        $informations->addInformation("-- Das Gebäude wurde zerstört!");
152
        $target->setIntegrity(0);
153
154
        return $informations;
155
    }
156
157
    private function checkForDamagedShipSystems(
158
        ShipWrapperInterface $wrapper,
159
        int $huelleVorher,
160
        InformationWrapper $informations
161
    ): bool {
162
        $ship = $wrapper->get();
163
        $systemsToDamage = ceil($huelleVorher * 6 / $ship->getMaxHull()) -
164
            ceil($ship->getHull() * 6 / $ship->getMaxHull());
165
166
        if ($systemsToDamage == 0) {
167
            return false;
168
        }
169
170
        for ($i = 1; $i <= $systemsToDamage; $i++) {
171
            $this->damageRandomShipSystem($wrapper, $informations);
172
        }
173
174
        return true;
175
    }
176
177
    private function destroyRandomShipSystem(ShipWrapperInterface $wrapper): ?string
178
    {
179
        $healthySystems = $wrapper->get()->getHealthySystems();
180
        shuffle($healthySystems);
181
182
        if ($healthySystems === []) {
183
            return null;
184
        }
185
        $system = $healthySystems[0];
186
        $system->setStatus(0);
187
        $system->setMode(ShipSystemModeEnum::MODE_OFF);
188
        $this->shipSystemManager->handleDestroyedSystem($wrapper, $healthySystems[0]->getSystemType());
189
190
        return $healthySystems[0]->getSystemType()->getDescription();
191
    }
192
193
    private function damageRandomShipSystem(
194
        ShipWrapperInterface $wrapper,
195
        InformationWrapper $informations,
196
        int $percent = null
197
    ): void {
198
        $healthySystems = $wrapper->get()->getHealthySystems();
199
        shuffle($healthySystems);
200
201
        if ($healthySystems !== []) {
202
            $system = $healthySystems[0];
203
204
            $this->damageShipSystem($wrapper, $system, $percent ?? random_int(1, 70), $informations);
205
        }
206
    }
207
208
    public function damageShipSystem(
209
        ShipWrapperInterface $wrapper,
210
        ShipSystemInterface $system,
211
        int $dmg,
212
        InformationWrapper $informations
213
    ): bool {
214
        $status = $system->getStatus();
215
        $systemName = $system->getSystemType()->getDescription();
216
217
        if ($status > $dmg) {
218
            $system->setStatus($status - $dmg);
219
            $this->shipSystemManager->handleDamagedSystem($wrapper, $system->getSystemType());
220
            $informations->addInformation("- Folgendes System wurde beschädigt: " . $systemName);
221
222
            return false;
223
        } else {
224
            $system->setStatus(0);
225
            $system->setMode(ShipSystemModeEnum::MODE_OFF);
226
            $this->shipSystemManager->handleDestroyedSystem($wrapper, $system->getSystemType());
227
            $informations->addInformation("- Der Schaden zerstört folgendes System: " . $systemName);
228
229
            return true;
230
        }
231
    }
232
}
233