Passed
Push — master ( f4068b...77f637 )
by Nico
40:27 queued 14:09
created

RepairUtil::getRepairDuration()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 15
ccs 9
cts 9
cp 1
crap 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Component\Ship\Repair;
6
7
use Stu\Component\Building\BuildingEnum;
8
use Stu\Component\Colony\ColonyFunctionManagerInterface;
9
use Stu\Component\Colony\Storage\ColonyStorageManagerInterface;
10
use Stu\Component\Crew\CrewEnum;
11
use Stu\Component\Ship\RepairTaskEnum;
12
use Stu\Component\Ship\ShipStateEnum;
13
use Stu\Component\Ship\Storage\ShipStorageManagerInterface;
14
use Stu\Component\Ship\System\ShipSystemTypeEnum;
15
use Stu\Module\Commodity\CommodityTypeEnum;
16
use Stu\Module\Message\Lib\PrivateMessageFolderSpecialEnum;
17
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
18
use Stu\Module\PlayerSetting\Lib\UserEnum;
19
use Stu\Module\Ship\Lib\ShipWrapperInterface;
20
use Stu\Orm\Entity\RepairTaskInterface;
21
use Stu\Orm\Entity\ShipInterface;
22
use Stu\Orm\Repository\ColonyShipRepairRepositoryInterface;
23
use Stu\Orm\Repository\RepairTaskRepositoryInterface;
24
use Stu\Orm\Repository\ShipSystemRepositoryInterface;
25
26
//TODO unit tests
27
final class RepairUtil implements RepairUtilInterface
28
{
29
    private ShipSystemRepositoryInterface $shipSystemRepository;
30
31
    private RepairTaskRepositoryInterface $repairTaskRepository;
32
33
    private ColonyShipRepairRepositoryInterface $colonyShipRepairRepository;
34
35
    private ShipStorageManagerInterface $shipStorageManager;
36
37
    private ColonyStorageManagerInterface $colonyStorageManager;
38
39
    private ColonyFunctionManagerInterface $colonyFunctionManager;
40
41
    private PrivateMessageSenderInterface $privateMessageSender;
42
43 9
    public function __construct(
44
        ShipSystemRepositoryInterface $shipSystemRepository,
45
        RepairTaskRepositoryInterface $repairTaskRepository,
46
        ColonyShipRepairRepositoryInterface $colonyShipRepairRepository,
47
        ShipStorageManagerInterface $shipStorageManager,
48
        ColonyStorageManagerInterface $colonyStorageManager,
49
        ColonyFunctionManagerInterface $colonyFunctionManager,
50
        PrivateMessageSenderInterface $privateMessageSender
51
    ) {
52 9
        $this->shipSystemRepository = $shipSystemRepository;
53 9
        $this->repairTaskRepository = $repairTaskRepository;
54 9
        $this->colonyShipRepairRepository = $colonyShipRepairRepository;
55 9
        $this->shipStorageManager = $shipStorageManager;
56 9
        $this->colonyStorageManager = $colonyStorageManager;
57 9
        $this->colonyFunctionManager = $colonyFunctionManager;
58 9
        $this->privateMessageSender = $privateMessageSender;
59
    }
60
61
    //REPAIR STUFF
62
    public function determineSpareParts(ShipWrapperInterface $wrapper): array
63
    {
64
        $neededSpareParts = 0;
65
        $neededSystemComponents = 0;
66
67
        $ship = $wrapper->get();
68
69
        $hull = $ship->getHull();
70
        $maxHull = $ship->getMaxHull();
71
72
        if ($hull < $maxHull) {
73
            $neededSpareParts += (int)($ship->getRepairRate() / RepairTaskEnum::HULL_HITPOINTS_PER_SPARE_PART);
74
        }
75
76
        $damagedSystems = $wrapper->getDamagedSystems();
77
        if (!empty($damagedSystems)) {
78
            $firstSystem = $damagedSystems[0];
79
            $firstSystemLvl = $firstSystem->determineSystemLevel();
80
            $healingPercentage = (100 - $firstSystem->getStatus()) / 100;
81
82
            $neededSpareParts += (int)ceil($healingPercentage * RepairTaskEnum::SHIPYARD_PARTS_USAGE[$firstSystemLvl][RepairTaskEnum::SPARE_PARTS_ONLY]);
83
            $neededSystemComponents += (int)ceil($healingPercentage * RepairTaskEnum::SHIPYARD_PARTS_USAGE[$firstSystemLvl][RepairTaskEnum::SYSTEM_COMPONENTS_ONLY]);
84
85
            // maximum of two systems get repaired
86
            if (count($damagedSystems) > 1) {
87
                $secondSystem = $damagedSystems[1];
88
                $secondSystemLvl = $secondSystem->determineSystemLevel();
89
                $healingPercentage = (100 - $secondSystem->getStatus()) / 100;
90
91
                $neededSpareParts += (int)ceil($healingPercentage * RepairTaskEnum::SHIPYARD_PARTS_USAGE[$secondSystemLvl][RepairTaskEnum::SPARE_PARTS_ONLY]);
92
                $neededSystemComponents += (int)ceil($healingPercentage * RepairTaskEnum::SHIPYARD_PARTS_USAGE[$secondSystemLvl][RepairTaskEnum::SYSTEM_COMPONENTS_ONLY]);
93
            }
94
        }
95
96
        return [
97
            CommodityTypeEnum::COMMODITY_SPARE_PART => $neededSpareParts,
98
            CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT => $neededSystemComponents
99
        ];
100
    }
101
102
    public function enoughSparePartsOnEntity(array $neededParts, $entity, bool $isColony, ShipInterface $ship): bool
103
    {
104
        $neededSpareParts = $neededParts[CommodityTypeEnum::COMMODITY_SPARE_PART];
105
        $neededSystemComponents = $neededParts[CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT];
106
107
        if ($neededSpareParts > 0) {
108
            $spareParts = $entity->getStorage()->get(CommodityTypeEnum::COMMODITY_SPARE_PART);
109
110
            if ($spareParts === null || $spareParts->getAmount() < $neededSpareParts) {
111
                $this->sendNeededAmountMessage($neededSpareParts, $neededSystemComponents, $ship, $entity, $isColony);
112
                return false;
113
            }
114
        }
115
116
        if ($neededSystemComponents > 0) {
117
            $systemComponents = $entity->getStorage()->get(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT);
118
119
            if ($systemComponents === null || $systemComponents->getAmount() < $neededSystemComponents) {
120
                $this->sendNeededAmountMessage($neededSpareParts, $neededSystemComponents, $ship, $entity, $isColony);
121
                return false;
122
            }
123
        }
124
125
        return true;
126
    }
127
128
    private function sendNeededAmountMessage(int $neededSpareParts, int $neededSystemComponents, ShipInterface $ship, $entity, bool $isColony): void
129
    {
130
        $neededPartsString = sprintf(
131
            "%d %s%s",
132
            $neededSpareParts,
133
            CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SPARE_PART),
134
            ($neededSystemComponents > 0 ? sprintf(
135
                "\n%d %s",
136
                $neededSystemComponents,
137
                CommodityTypeEnum::getDescription(CommodityTypeEnum::COMMODITY_SYSTEM_COMPONENT)
138
            ) : '')
139
        );
140
141
        //PASSIVE REPAIR OF STATION BY WORKBEES
142
        if ($entity === $ship) {
143
            $entityOwnerMessage = sprintf(
144
                "Die Reparatur der %s %s wurde in Sektor %s angehalten.\nEs werden folgende Waren benötigt:\n%s",
145
                $entity->getRump()->getName(),
146
                $ship->getName(),
147
                $ship->getSectorString(),
148
                $neededPartsString
149
            );
150
        } else {
151
            $entityOwnerMessage = $isColony ? sprintf(
152
                "Die Reparatur der %s von Siedler %s wurde in Sektor %s bei der Kolonie %s angehalten.\nEs werden folgende Waren benötigt:\n%s",
153
                $ship->getName(),
154
                $ship->getUser()->getName(),
155
                $ship->getSectorString(),
156
                $entity->getName(),
157
                $neededPartsString
158
            ) : sprintf(
159
                "Die Reparatur der %s von Siedler %s wurde in Sektor %s bei der %s %s angehalten.\nEs werden folgende Waren benötigt:\n%s",
160
                $ship->getName(),
161
                $ship->getUser()->getName(),
162
                $ship->getSectorString(),
163
                $entity->getRump()->getName(),
164
                $entity->getName(),
165
                $neededPartsString
166
            );
167
        }
168
        $this->privateMessageSender->send(
169
            UserEnum::USER_NOONE,
170
            $entity->getUserId(),
171
            $entityOwnerMessage,
172
            $isColony ? PrivateMessageFolderSpecialEnum::PM_SPECIAL_COLONY : PrivateMessageFolderSpecialEnum::PM_SPECIAL_STATION
173
        );
174
    }
175
176
    public function consumeSpareParts(array $neededParts, $entity, bool $isColony): void
177
    {
178
        foreach ($neededParts as $commodityKey => $amount) {
179
            //$this->loggerUtil->log(sprintf('consume, cid: %d, amount: %d', $commodityKey, $amount));
180
181
            if ($amount < 1) {
182
                continue;
183
            }
184
185
            $commodity = $entity->getStorage()->get($commodityKey)->getCommodity();
186
187
            if ($isColony) {
188
                $this->colonyStorageManager->lowerStorage($entity, $commodity, $amount);
189
            } else {
190
                $this->shipStorageManager->lowerStorage($entity, $commodity, $amount);
191
            }
192
        }
193
    }
194
195
196
    //SELFREPAIR STUFF
197
198
    public function determineFreeEngineerCount(ShipInterface $ship): int
199
    {
200
        $engineerCount = 0;
201
202
        $engineerOptions = [];
203
        $nextNumber = 1;
204
        foreach ($ship->getCrewAssignments() as $shipCrew) {
205
            if (
206
                $shipCrew->getSlot() === CrewEnum::CREW_TYPE_TECHNICAL
207
                //&& $shipCrew->getRepairTask() === null
208
            ) {
209
                $engineerOptions[] = $nextNumber;
210
                $nextNumber++;
211
                $engineerCount++;
212
            }
213
        }
214
215
        return $engineerCount; //$engineerOptions;
216
    }
217
218
    public function determineRepairOptions(ShipWrapperInterface $wrapper): array
219
    {
220
        $repairOptions = [];
221
222
        $ship = $wrapper->get();
223
224
        //check for hull option
225
        $hullPercentage = (int) ($ship->getHull() * 100 / $ship->getMaxHull());
226
        if ($hullPercentage < RepairTaskEnum::BOTH_MAX) {
227
            $hullSystem = $this->shipSystemRepository->prototype();
228
            $hullSystem->setSystemType(ShipSystemTypeEnum::SYSTEM_HULL);
229
            $hullSystem->setStatus($hullPercentage);
230
231
            $repairOptions[ShipSystemTypeEnum::SYSTEM_HULL] = $hullSystem;
232
        }
233
234
        //check for system options
235
        foreach ($wrapper->getDamagedSystems() as $system) {
236
            if ($system->getStatus() < RepairTaskEnum::BOTH_MAX) {
237
                $repairOptions[$system->getSystemType()] = $system;
238
            }
239
        }
240
241
        return $repairOptions;
242
    }
243
244
    public function createRepairTask(ShipInterface $ship, int $systemType, int $repairType, int $finishTime): void
245
    {
246
        $obj = $this->repairTaskRepository->prototype();
247
248
        $obj->setUser($ship->getUser());
249
        $obj->setShip($ship);
250
        $obj->setSystemType($systemType);
251
        $obj->setHealingPercentage($this->determineHealingPercentage($repairType));
252
        $obj->setFinishTime($finishTime);
253
254
        $this->repairTaskRepository->save($obj);
255
    }
256
257
    public function determineHealingPercentage(int $repairType): int
258
    {
259
        $percentage = 0;
260
261
        if ($repairType === RepairTaskEnum::SPARE_PARTS_ONLY) {
262
            $percentage += random_int(RepairTaskEnum::SPARE_PARTS_ONLY_MIN, RepairTaskEnum::SPARE_PARTS_ONLY_MAX);
263
        } elseif ($repairType === RepairTaskEnum::SYSTEM_COMPONENTS_ONLY) {
264
            $percentage += random_int(RepairTaskEnum::SYSTEM_COMPONENTS_ONLY_MIN, RepairTaskEnum::SYSTEM_COMPONENTS_ONLY_MAX);
265
        } elseif ($repairType === RepairTaskEnum::BOTH) {
266
            $percentage += random_int(RepairTaskEnum::BOTH_MIN, RepairTaskEnum::BOTH_MAX);
267
        }
268
269
        return $percentage;
270
    }
271
272
    public function instantSelfRepair($ship, $systemType, $healingPercentage): bool
273
    {
274
        return $this->internalSelfRepair(
275
            $ship,
276
            $systemType,
277
            $healingPercentage
278
        );
279
    }
280
281
    public function selfRepair(ShipInterface $ship, RepairTaskInterface $repairTask): bool
282
    {
283
        $systemType = $repairTask->getSystemType();
284
        $percentage = $repairTask->getHealingPercentage();
285
286
        $this->repairTaskRepository->delete($repairTask);
287
288
        return $this->internalSelfRepair($ship, $systemType, $percentage);
289
    }
290
291
    private function internalSelfRepair(ShipInterface $ship, int $systemType, int $percentage): bool
292
    {
293
        $result = true;
294
295
        if ($systemType === ShipSystemTypeEnum::SYSTEM_HULL) {
296
            $hullPercentage = (int) ($ship->getHull() * 100 / $ship->getMaxHull());
297
298
            if ($hullPercentage > $percentage) {
299
                $result = false;
300
            } else {
301
                $ship->setHuell((int)($ship->getMaxHull() * $percentage / 100));
302
            }
303
        } else {
304
            $system = $ship->getShipSystem($systemType);
305
306
            if ($system->getStatus() > $percentage) {
307
                $result = false;
308
            } else {
309
                $system->setStatus($percentage);
310
                $this->shipSystemRepository->save($system);
311
            }
312
        }
313
314
        $ship->setState(ShipStateEnum::SHIP_STATE_NONE);
315
316
        return $result;
317
    }
318
319 5
    public function getRepairDuration(ShipWrapperInterface $wrapper): int
320
    {
321 5
        $ship = $wrapper->get();
322 5
        $ticks = $this->getRepairTicks($wrapper);
323
324
        //check if repair station is active
325 5
        $colonyRepair = $this->colonyShipRepairRepository->getByShip($ship->getId());
326 5
        if ($colonyRepair !== null) {
327 2
            $isRepairStationBonus = $this->colonyFunctionManager->hasActiveFunction($colonyRepair->getColony(), BuildingEnum::BUILDING_FUNCTION_REPAIR_SHIPYARD);
328 2
            if ($isRepairStationBonus) {
329 1
                $ticks = (int)ceil($ticks / 2);
330
            }
331
        }
332
333 5
        return $ticks;
334
    }
335
336 3
    public function getRepairDurationPreview(ShipWrapperInterface $wrapper): int
337
    {
338 3
        $ship = $wrapper->get();
339 3
        $ticks = $this->getRepairTicks($wrapper);
340
341 3
        $colony = $ship->isOverColony();
342 3
        if ($colony !== null) {
343 2
            $isRepairStationBonus = $this->colonyFunctionManager->hasActiveFunction($colony, BuildingEnum::BUILDING_FUNCTION_REPAIR_SHIPYARD);
344 2
            if ($isRepairStationBonus) {
345 1
                $ticks = (int)ceil($ticks / 2);
346
            }
347
        }
348
349 3
        return $ticks;
350
    }
351
352 8
    private function getRepairTicks(ShipWrapperInterface $wrapper): int
353
    {
354 8
        $ship = $wrapper->get();
355 8
        $ticks = (int) ceil(($ship->getMaxHull() - $ship->getHull()) / $ship->getRepairRate());
356
357 8
        return max($ticks, (int) ceil(count($wrapper->getDamagedSystems()) / 2));
358
    }
359
}
360