Passed
Push — dev ( 501ee6...82c4ce )
by Janko
28:35
created

ApplyDamage::destroyRandomShipSystem()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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