Passed
Pull Request — master (#1833)
by Nico
34:40
created

ApplyDamage::damageRandomShipSystem()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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