Passed
Push — dev ( 923b08...03e2b8 )
by Janko
15:21
created

EnergyConsumeHandler::handleSpacecraftTick()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 43
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 23
nc 9
nop 2
dl 0
loc 43
ccs 0
cts 25
cp 0
crap 42
rs 8.9297
c 1
b 0
f 0
1
<?php
2
3
namespace Stu\Module\Tick\Spacecraft\Handler;
4
5
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Stu\Component\Spacecraft\SpacecraftAlertStateEnum;
7
use Stu\Component\Spacecraft\System\Data\EpsSystemData;
8
use Stu\Component\Spacecraft\System\SpacecraftSystemManagerInterface;
9
use Stu\Component\Spacecraft\System\SpacecraftSystemTypeEnum;
10
use Stu\Lib\Information\InformationInterface;
11
use Stu\Module\Spacecraft\Lib\Crew\SpacecraftLeaverInterface;
12
use Stu\Module\Spacecraft\Lib\ReactorWrapperInterface;
13
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperInterface;
14
use Stu\Module\Tick\Spacecraft\SpacecraftTickFinishedException;
15
use Stu\Orm\Entity\SpacecraftInterface;
16
use Stu\Orm\Entity\SpacecraftSystemInterface;
17
18
class EnergyConsumeHandler implements SpacecraftTickHandlerInterface
19
{
20 1
    public function __construct(
21
        private SpacecraftSystemManagerInterface $spacecraftSystemManager,
22
        private SpacecraftLeaverInterface $spacecraftLeaver
23 1
    ) {}
24
25
    #[Override]
26
    public function handleSpacecraftTick(
27
        SpacecraftWrapperInterface $wrapper,
28
        InformationInterface $information
29
    ): void {
30
31
        $spacecraft = $wrapper->get();
32
        $hasEnoughCrew = $spacecraft->hasEnoughCrew();
33
34
        $reactorUsageForWarpdrive = $this->loadWarpdrive(
35
            $wrapper,
36
            $hasEnoughCrew
37
        );
38
39
        $eps = $wrapper->getEpsSystemData();
40
        if ($eps === null) {
41
            return;
42
        }
43
44
        $reactor = $wrapper->getReactorWrapper();
45
46
        $availableEps = $this->getAvailableEps(
47
            $wrapper,
48
            $eps,
49
            $reactor,
50
            $hasEnoughCrew,
51
            $reactorUsageForWarpdrive
52
        );
53
54
        //try to save energy by reducing alert state
55
        if ($wrapper->getEpsUsage() > $availableEps) {
56
            $this->reduceAlertState($wrapper, $availableEps, $information);
57
        }
58
59
        //try to save energy by deactivating systems from low to high priority
60
        if ($wrapper->getEpsUsage() > $availableEps) {
61
            $this->deactivateSystems($wrapper, $availableEps, $information);
62
        }
63
64
        $usedEnergy = $this->updateEps($wrapper, $eps, $availableEps, $reactorUsageForWarpdrive);
65
66
        if ($usedEnergy > 0 && $reactor !== null) {
67
            $reactor->changeLoad(-$usedEnergy);
68
        }
69
    }
70
71
    private function reduceAlertState(
72
        SpacecraftWrapperInterface $wrapper,
73
        int $availableEps,
74
        InformationInterface $information
75
    ): void {
76
        $spacecraft = $wrapper->get();
77
        $malus = $wrapper->getEpsUsage() - $availableEps;
78
        $alertUsage = $spacecraft->getAlertState()->value - 1;
79
80
        if ($alertUsage > 0) {
81
            $preState = $spacecraft->getAlertState();
82
            $reduce = (int)min($malus, $alertUsage);
83
84
            $spacecraft->setAlertState(SpacecraftAlertStateEnum::from($preState->value - $reduce));
85
            $information->addInformationf(
86
                'Wechsel von %s auf %s wegen Energiemangel',
87
                $preState->getDescription(),
88
                $spacecraft->getAlertState()->getDescription()
89
            );
90
        }
91
    }
92
93
    private function deactivateSystems(SpacecraftWrapperInterface $wrapper, int $availableEps, InformationInterface $information): void
94
    {
95
        $activeSystems = $this->spacecraftSystemManager->getActiveSystems($wrapper->get(), true);
96
97
        foreach ($activeSystems as $system) {
98
            $energyConsumption = $this->spacecraftSystemManager->getEnergyConsumption($system->getSystemType());
99
            if ($energyConsumption < 1) {
100
                continue;
101
            }
102
103
            if ($availableEps - $wrapper->getEpsUsage() - $energyConsumption < 0) {
104
105
                $this->deactivateSystem($wrapper, $system, $energyConsumption, $information);
106
            }
107
            if ($wrapper->getEpsUsage() <= $availableEps) {
108
                break;
109
            }
110
        }
111
    }
112
113
    private function deactivateSystem(
114
        SpacecraftWrapperInterface $wrapper,
115
        SpacecraftSystemInterface $system,
116
        int $energyConsumption,
117
        InformationInterface $information
118
    ): void {
119
        $spacecraft = $wrapper->get();
120
        $this->spacecraftSystemManager->deactivate($wrapper, $system->getSystemType(), true);
121
122
        $wrapper->lowerEpsUsage($energyConsumption);
123
        $information->addInformationf('%s deaktiviert wegen Energiemangel', $system->getSystemType()->getDescription());
124
125
        if ($spacecraft->getCrewCount() > 0 && $system->getSystemType() == SpacecraftSystemTypeEnum::LIFE_SUPPORT) {
126
            $information->addInformation('Die Lebenserhaltung ist ausgefallen:');
127
            $information->addInformation($this->spacecraftLeaver->evacuate($wrapper));
128
129
            throw new SpacecraftTickFinishedException();
130
        }
131
    }
132
133
    private function calculateBatteryReload(SpacecraftInterface $spacecraft, EpsSystemData $eps, int $newEps): int
134
    {
135
        return $spacecraft->isStation()
136
            && $eps->reloadBattery()
137
            && $newEps > $eps->getEps()
138
            ? min(
139
                (int) ceil($eps->getMaxBattery() / 10),
140
                $newEps - $eps->getEps(),
141
                $eps->getMaxBattery() - $eps->getBattery()
142
            ) : 0;
143
    }
144
145
    private function updateEps(SpacecraftWrapperInterface $wrapper, EpsSystemData $eps, int $availableEps, int $reactorUsageForWarpdrive): int
146
    {
147
        $spacecraft = $wrapper->get();
148
149
        $newEps = $availableEps - $wrapper->getEpsUsage();
150
        $batteryReload = $this->calculateBatteryReload($spacecraft, $eps, $newEps);
151
152
        $newEps -= $batteryReload;
153
        if ($newEps > $eps->getMaxEps()) {
154
            $newEps = $eps->getMaxEps();
155
        }
156
157
        $eps->setEps($newEps)
158
            ->setBattery($eps->getBattery() + $batteryReload)
159
            ->update();
160
161
        return $wrapper->getEpsUsage() + $batteryReload + ($newEps - $eps->getEps()) + $reactorUsageForWarpdrive;
162
    }
163
164
    private function loadWarpdrive(SpacecraftWrapperInterface $wrapper, bool $hasEnoughCrew): int
165
    {
166
        if (!$hasEnoughCrew) {
167
            return 0;
168
        }
169
170
        $reactor = $wrapper->getReactorWrapper();
171
        $warpdrive = $wrapper->getWarpDriveSystemData();
172
        if ($warpdrive === null || $reactor === null) {
173
            return 0;
174
        }
175
176
        $effectiveWarpdriveProduction = $reactor->getEffectiveWarpDriveProduction();
177
        if ($effectiveWarpdriveProduction === 0) {
178
            return 0;
179
        }
180
181
        $currentLoad = $warpdrive->getWarpDrive();
182
183
        $warpdrive->setWarpDrive($currentLoad + $effectiveWarpdriveProduction)->update();
184
185
        return $effectiveWarpdriveProduction * $wrapper->get()->getRump()->getFlightECost();
186
    }
187
188
    private function getAvailableEps(
189
        SpacecraftWrapperInterface $wrapper,
190
        EpsSystemData $eps,
191
        ?ReactorWrapperInterface $reactor,
192
        bool $hasEnoughCrew,
193
        int $reactorUsageForWarpdrive
194
    ): int {
195
        if ($hasEnoughCrew && $reactor !== null) {
196
197
            return $eps->getEps() + $reactor->getEpsProduction() +  $this->getCarryOver(
198
                $wrapper,
199
                $reactor,
200
                $reactorUsageForWarpdrive
201
            );
202
        }
203
204
        return $eps->getEps();
205
    }
206
207
    private function getCarryOver(
208
        SpacecraftWrapperInterface $wrapper,
209
        ReactorWrapperInterface $reactor,
210
        int $reactorUsageForWarpdrive
211
    ): int {
212
        $warpdrive = $wrapper->getWarpDriveSystemData();
213
        if ($warpdrive === null || !$warpdrive->getAutoCarryOver()) {
214
            return 0;
215
        }
216
217
        return $reactor->getOutputCappedByLoad() - $reactor->getEpsProduction() - $reactorUsageForWarpdrive;
218
    }
219
}
220