Passed
Push — master ( db7b85...c86096 )
by Nico
49:13 queued 24:57
created

RepairActions::repairShipsOnStations()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 4
nop 0
dl 0
loc 13
ccs 0
cts 9
cp 0
crap 20
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Module\Tick\Ship\ManagerComponent;
6
7
use Stu\Component\Building\BuildingEnum;
8
use Stu\Component\Colony\ColonyFunctionManagerInterface;
9
use Stu\Component\Colony\Storage\ColonyStorageManagerInterface;
10
use Stu\Component\Ship\Repair\RepairUtilInterface;
11
use Stu\Component\Ship\ShipStateEnum;
12
use Stu\Component\Ship\System\ShipSystemManagerInterface;
13
use Stu\Module\Message\Lib\PrivateMessageFolderSpecialEnum;
14
use Stu\Module\Message\Lib\PrivateMessageSenderInterface;
15
use Stu\Module\PlayerSetting\Lib\UserEnum;
16
use Stu\Module\Ship\Lib\ShipWrapperFactoryInterface;
17
use Stu\Module\Ship\Lib\ShipWrapperInterface;
18
use Stu\Orm\Entity\ColonyInterface;
19
use Stu\Orm\Entity\ShipInterface;
20
use Stu\Orm\Repository\ColonyShipRepairRepositoryInterface;
21
use Stu\Orm\Repository\ModuleQueueRepositoryInterface;
22
use Stu\Orm\Repository\PlanetFieldRepositoryInterface;
23
use Stu\Orm\Repository\ShipRepositoryInterface;
24
use Stu\Orm\Repository\StationShipRepairRepositoryInterface;
25
26
final class RepairActions implements ManagerComponentInterface
27
{
28
    private ShipRepositoryInterface $shipRepository;
29
30
    private PrivateMessageSenderInterface $privateMessageSender;
31
32
    private ShipSystemManagerInterface $shipSystemManager;
33
34
    private ColonyShipRepairRepositoryInterface $colonyShipRepairRepository;
35
36
    private StationShipRepairRepositoryInterface $stationShipRepairRepository;
37
38
    private ColonyStorageManagerInterface $colonyStorageManager;
39
40
    private ModuleQueueRepositoryInterface $moduleQueueRepository;
41
42
    private RepairUtilInterface $repairUtil;
43
44
    private ShipWrapperFactoryInterface $shipWrapperFactory;
45
46
    private PlanetFieldRepositoryInterface $planetFieldRepository;
47
48
    private ColonyFunctionManagerInterface $colonyFunctionManager;
49
50
    public function __construct(
51
        ShipRepositoryInterface $shipRepository,
52
        PrivateMessageSenderInterface $privateMessageSender,
53
        ShipSystemManagerInterface $shipSystemManager,
54
        ColonyShipRepairRepositoryInterface $colonyShipRepairRepository,
55
        StationShipRepairRepositoryInterface $stationShipRepairRepository,
56
        ColonyStorageManagerInterface $colonyStorageManager,
57
        ModuleQueueRepositoryInterface $moduleQueueRepository,
58
        RepairUtilInterface $repairUtil,
59
        ShipWrapperFactoryInterface $shipWrapperFactory,
60
        PlanetFieldRepositoryInterface $planetFieldRepository,
61
        ColonyFunctionManagerInterface $colonyFunctionManager
62
    ) {
63
        $this->shipRepository = $shipRepository;
64
        $this->privateMessageSender = $privateMessageSender;
65
        $this->shipSystemManager = $shipSystemManager;
66
        $this->colonyShipRepairRepository = $colonyShipRepairRepository;
67
        $this->stationShipRepairRepository = $stationShipRepairRepository;
68
        $this->colonyStorageManager = $colonyStorageManager;
69
        $this->moduleQueueRepository = $moduleQueueRepository;
70
        $this->repairUtil = $repairUtil;
71
        $this->shipWrapperFactory = $shipWrapperFactory;
72
        $this->planetFieldRepository = $planetFieldRepository;
73
        $this->colonyFunctionManager = $colonyFunctionManager;
74
    }
75
76
    public function work(): void
77
    {
78
        //spare parts and system components are generated by ship tick, to avoid dead locks
79
        $this->proceedSpareParts();
80
        $this->repairShipsOnColonies(1);
81
        $this->repairShipsOnStations();
82
    }
83
84
    private function proceedSpareParts(): void
85
    {
86
        foreach ($this->moduleQueueRepository->findAll() as $queue) {
87
            $buildingFunction = $queue->getBuildingFunction();
88
89
            if (
90
                $buildingFunction === BuildingEnum::BUILDING_FUNCTION_FABRICATION_HALL ||
91
                $buildingFunction === BuildingEnum::BUILDING_FUNCTION_TECH_CENTER
92
            ) {
93
                $colony = $queue->getColony();
94
95
                if ($this->colonyFunctionManager->hasActiveFunction($colony, $buildingFunction)) {
96
                    $this->colonyStorageManager->upperStorage(
97
                        $colony,
98
                        $queue->getModule()->getCommodity(),
99
                        $queue->getAmount()
100
                    );
101
102
                    $this->privateMessageSender->send(
103
                        UserEnum::USER_NOONE,
104
                        $colony->getUser()->getId(),
105
                        sprintf(
106
                            _('Es wurden %d %s hergestellt'),
107
                            $queue->getAmount(),
108
                            $queue->getModule()->getName()
109
                        ),
110
                        PrivateMessageFolderSpecialEnum::PM_SPECIAL_COLONY
111
                    );
112
113
                    $this->moduleQueueRepository->delete($queue);
114
                }
115
            }
116
        }
117
    }
118
119
    private function repairShipsOnColonies(int $tickId): void
120
    {
121
        $usedShipyards = [];
122
123
        foreach ($this->colonyShipRepairRepository->getMostRecentJobs($tickId) as $obj) {
124
            $ship = $obj->getShip();
125
            $colony = $obj->getColony();
126
127
            if ($colony->isBlocked()) {
128
                continue;
129
            }
130
131
            $field = $this->planetFieldRepository->getByColonyAndFieldIndex(
132
                $obj->getColonyId(),
133
                $obj->getFieldId()
134
            );
135
136
            if ($field === null) {
137
                continue;
138
            }
139
140
            if (!$field->isActive()) {
141
                continue;
142
            }
143
144
            if (!array_key_exists($colony->getId(), $usedShipyards)) {
145
                $usedShipyards[$colony->getId()] = [];
146
            }
147
148
            $isRepairStationBonus = $this->colonyFunctionManager->hasActiveFunction($colony, BuildingEnum::BUILDING_FUNCTION_REPAIR_SHIPYARD);
149
150
            //already repaired a ship on this colony field, max is one without repair station
151
            if (
152
                !$isRepairStationBonus
153
                && array_key_exists($field->getFieldId(), $usedShipyards[$colony->getId()])
154
            ) {
155
                continue;
156
            }
157
158
            $usedShipyards[$colony->getId()][$field->getFieldId()] = [$field->getFieldId()];
159
160
            if ($this->repairShipOnEntity($ship, $colony, $isRepairStationBonus)) {
161
                $this->colonyShipRepairRepository->delete($obj);
162
                $this->shipRepository->save($ship);
163
            }
164
        }
165
    }
166
167
    private function repairShipsOnStations(): void
168
    {
169
        foreach ($this->stationShipRepairRepository->getMostRecentJobs() as $obj) {
170
            $ship = $obj->getShip();
171
            $station = $obj->getStation();
172
173
            if (!$station->hasEnoughCrew()) {
174
                continue;
175
            }
176
177
            if ($this->repairShipOnEntity($ship, $station, false)) {
178
                $this->stationShipRepairRepository->delete($obj);
179
                $this->shipRepository->save($ship);
180
            }
181
        }
182
    }
183
184
    private function repairShipOnEntity(ShipInterface $ship, ColonyInterface|ShipInterface $entity, bool $isRepairStationBonus): bool
185
    {
186
        // check for U-Mode
187
        if ($entity->getUser()->isVacationRequestOldEnough()) {
188
            return false;
189
        }
190
191
        $wrapper = $this->shipWrapperFactory->wrapShip($ship);
192
        $neededParts = $this->repairUtil->determineSpareParts($wrapper, true);
193
194
        // parts stored?
195
        if (!$this->repairUtil->enoughSparePartsOnEntity($neededParts, $entity, $ship)) {
196
            return false;
197
        }
198
199
        $repairFinished = false;
200
201
        $this->repairHull($ship, $isRepairStationBonus);
202
        $this->repairShipSystems($wrapper, $isRepairStationBonus);
203
204
        // consume spare parts
205
        $this->repairUtil->consumeSpareParts($neededParts, $entity);
206
207
        if (!$wrapper->canBeRepaired()) {
208
            $repairFinished = true;
209
210
            $ship->setHuell($ship->getMaxHull());
211
            $ship->setState(ShipStateEnum::SHIP_STATE_NONE);
212
213
            $this->sendPrivateMessages($ship, $entity);
214
        }
215
        $this->shipRepository->save($ship);
216
217
        return $repairFinished;
218
    }
219
220
    private function repairHull(ShipInterface $ship, bool $isRepairStationBonus): void
221
    {
222
        $hullRepairRate = $isRepairStationBonus ? $ship->getRepairRate() * 2 : $ship->getRepairRate();
223
        $ship->setHuell($ship->getHull() + $hullRepairRate);
224
        if ($ship->getHull() > $ship->getMaxHull()) {
225
            $ship->setHuell($ship->getMaxHull());
226
        }
227
    }
228
229
    private function repairShipSystems(ShipWrapperInterface $wrapper, bool $isRepairStationBonus): void
230
    {
231
        $ship = $wrapper->get();
232
233
        $damagedSystems = $wrapper->getDamagedSystems();
234
        if (!empty($damagedSystems)) {
235
            $firstSystem = $damagedSystems[0];
236
            $firstSystem->setStatus(100);
237
238
            if ($ship->getCrewCount() > 0) {
239
                $firstSystem->setMode($this->shipSystemManager->lookupSystem($firstSystem->getSystemType())->getDefaultMode());
240
            }
241
242
            // maximum of two systems get repaired
243
            if (count($damagedSystems) > 1) {
244
                $secondSystem = $damagedSystems[1];
245
                $secondSystem->setStatus(100);
246
247
                if ($ship->getCrewCount() > 0) {
248
                    $secondSystem->setMode($this->shipSystemManager->lookupSystem($secondSystem->getSystemType())->getDefaultMode());
249
                }
250
            }
251
252
            // maximum of two additional systems get repaired
253
            if ($isRepairStationBonus) {
254
                if (count($damagedSystems) > 2) {
255
                    $thirdSystem = $damagedSystems[2];
256
                    $thirdSystem->setStatus(100);
257
258
                    if ($ship->getCrewCount() > 0) {
259
                        $thirdSystem->setMode($this->shipSystemManager->lookupSystem($thirdSystem->getSystemType())->getDefaultMode());
260
                    }
261
                }
262
                if (count($damagedSystems) > 3) {
263
                    $fourthSystem = $damagedSystems[3];
264
                    $fourthSystem->setStatus(100);
265
266
                    if ($ship->getCrewCount() > 0) {
267
                        $fourthSystem->setMode($this->shipSystemManager->lookupSystem($fourthSystem->getSystemType())->getDefaultMode());
268
                    }
269
                }
270
            }
271
        }
272
    }
273
274
    private function sendPrivateMessages(ShipInterface $ship, ColonyInterface|ShipInterface $entity): void
275
    {
276
        $shipOwnerMessage = $entity instanceof ColonyInterface ? sprintf(
277
            "Die Reparatur der %s wurde in Sektor %s bei der Kolonie %s des Spielers %s fertiggestellt",
278
            $ship->getName(),
279
            $ship->getSectorString(),
280
            $entity->getName(),
281
            $entity->getUser()->getName()
282
        ) : sprintf(
283
            "Die Reparatur der %s wurde in Sektor %s von der %s %s des Spielers %s fertiggestellt",
284
            $ship->getName(),
285
            $ship->getSectorString(),
286
            $entity->getRump()->getName(),
287
            $entity->getName(),
288
            $entity->getUser()->getName()
289
        );
290
291
        $this->privateMessageSender->send(
292
            $entity->getUser()->getId(),
293
            $ship->getUser()->getId(),
294
            $shipOwnerMessage,
295
            PrivateMessageFolderSpecialEnum::PM_SPECIAL_SHIP
296
        );
297
298
        $entityOwnerMessage = $entity instanceof ColonyInterface ? sprintf(
299
            "Die Reparatur der %s von Siedler %s wurde in Sektor %s bei der Kolonie %s fertiggestellt",
300
            $ship->getName(),
301
            $ship->getUser()->getName(),
302
            $ship->getSectorString(),
303
            $entity->getName()
304
        ) : sprintf(
305
            "Die Reparatur der %s von Siedler %s wurde in Sektor %s von der %s %s fertiggestellt",
306
            $ship->getName(),
307
            $ship->getUser()->getName(),
308
            $ship->getSectorString(),
309
            $entity->getRump()->getName(),
310
            $entity->getName()
311
        );
312
313
        $this->privateMessageSender->send(
314
            UserEnum::USER_NOONE,
315
            $entity->getUser()->getId(),
316
            $entityOwnerMessage,
317
            $entity instanceof ColonyInterface ? PrivateMessageFolderSpecialEnum::PM_SPECIAL_COLONY :
318
                PrivateMessageFolderSpecialEnum::PM_SPECIAL_STATION
319
        );
320
    }
321
}
322