Boost::setMessageBody()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 5
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 2
1
<?php namespace FreedomCore\TrinityCore\Character\Classes;
2
3
use FreedomCore\TrinityCore\Character\Character;
4
use FreedomCore\TrinityCore\Character\Classes\Boost\GearSets;
5
use FreedomCore\TrinityCore\Character\Models\Character as CharacterModel;
6
use FreedomCore\TrinityCore\Character\Models\CharacterInventory;
7
use FreedomCore\TrinityCore\Character\Models\CharacterSkill;
8
use FreedomCore\TrinityCore\Character\Models\ItemInstance;
9
use FreedomCore\TrinityCore\Console\Client as SOAPClient;
10
use FreedomCore\TrinityCore\Support\Classes\Durability;
11
use FreedomCore\TrinityCore\Support\Classes\Item;
12
use FreedomCore\TrinityCore\Support\Classes\Items;
13
use FreedomCore\TrinityCore\Support\Common\Helper;
14
15
/**
16
 * Class Boost
17
 * @package FreedomCore\TrinityCore\Character\Classes
18
 */
19
class Boost
20
{
21
22
    /**
23
     * SOAPClient Instance
24
     * @var SOAPClient|null
25
     */
26
    protected $client = null;
27
28
    /**
29
     * GearSets Instance
30
     * @var GearSets|null
31
     */
32
    protected $gear = null;
33
34
    /**
35
     * Title of the message
36
     * @var null|string
37
     */
38
    protected $messageTitle = null;
39
40
    /**
41
     * Body of the message
42
     * @var null|string
43
     */
44
    protected $messageBody = null;
45
46
    /**
47
     * Character super class reference
48
     * @var Character|null
49
     */
50
    protected $super = null;
51
52
    /**
53
     * Character Instance
54
     * @var null|CharacterModel
55
     */
56
    protected $character = null;
57
58
    /**
59
     * Boost Data Array
60
     * @var array
61
     */
62
    protected $boostData = [
63
        'level' =>  0,
64
        'spec'  =>  0,
65
        'gear'  =>  []
66
    ];
67
68
    /**
69
     * Professions boost for level
70
     * @var array
71
     */
72
    protected $professionsBoost = [
73
        90  =>  600,
74
        100 =>  700
75
    ];
76
77
    /**
78
     * Money boost for level
79
     * @var array
80
     */
81
    protected $moneyBoost = [
82
        90  =>  1500000,
83
        100 =>  5000000
84
    ];
85
86
    /**
87
     * Boost constructor.
88
     * @param Character $character
89
     * @param SOAPClient $client
90
     */
91
    public function __construct(Character $character, SOAPClient $client)
92
    {
93
        $this->super = $character;
94
        $this->character = $character->model();
95
        $this->client = $client;
96
        $this->gear = new GearSets();
97
    }
98
99
    /**
100
     * Get Client Instance
101
     * @return SOAPClient
102
     */
103
    public function getClient() : SOAPClient
104
    {
105
        return $this->client;
106
    }
107
108
    /**
109
     * Get Gear Instance
110
     * @return GearSets
111
     */
112
    public function getGear() : GearSets
113
    {
114
        return $this->gear;
115
    }
116
117
    /**
118
     * Get message title
119
     * @return string
120
     */
121
    public function getMessageTitle() : string
122
    {
123
        return ($this->messageTitle !== null) ? $this->messageTitle : 'undefined';
124
    }
125
126
    /**
127
     * Get message body
128
     * @return string
129
     */
130
    public function getMessageBody() : string
131
    {
132
        return ($this->messageBody !== null) ? $this->messageBody : 'undefined';
133
    }
134
135
    /**
136
     * Set Client Instance
137
     * @param SOAPClient $client
138
     * @return Boost
139
     */
140
    public function setClient(SOAPClient $client) : Boost
141
    {
142
        $this->client = $client;
143
        return $this;
144
    }
145
146
    /**
147
     * Set Gear Instance
148
     * @param GearSets $gearSets
149
     * @return Boost
150
     */
151
    public function setGear(GearSets $gearSets) : Boost
152
    {
153
        $this->gear = $gearSets;
154
        return $this;
155
    }
156
157
    /**
158
     * Set message title
159
     * @param string $title
160
     * @return Boost
161
     */
162
    public function setMessageTitle(string $title) : Boost
163
    {
164
        $this->messageTitle = $title;
165
        return $this;
166
    }
167
168
    /**
169
     * Set message body
170
     * @param string $body
171
     * @return Boost
172
     */
173
    public function setMessageBody(string $body) : Boost
174
    {
175
        $this->messageBody = $body;
176
        return $this;
177
    }
178
179
    /**
180
     * Specify the level we want to boost character to
181
     * @param int $level
182
     * @return Boost
183
     */
184
    public function boostTo(int $level) : Boost
185
    {
186
        $character = $this->character;
187
        if ($this->character->level >= $level) {
188
            throw new \RuntimeException('Character ' . $character->name . ' is already at the level ' . $character->level . ' thus it cannot be boosted to level ' . $level);
189
        }
190
        $this->boostData['level'] = $level;
191
        return $this;
192
    }
193
194
    /**
195
     * Select spec for character
196
     * @param int $spec
197
     * @return Boost
198
     */
199
    public function withSpec(int $spec) : Boost
200
    {
201
        if ($this->boostData['level'] === 0) {
202
            throw new \RuntimeException('You have to specify the level for the character boost first using the boostTo() method!');
203
        }
204
        $character = $this->character;
205
        $this->gear->isGearingStrategyLoaded();
206
        $this->boostData['gear'] = $this->gear->getClassDataByLevel($character->class, $this->boostData['level']);
207
        if (!array_key_exists($spec, $this->boostData['gear'])) {
208
            throw new \RuntimeException('This character does not have a spec with ID #' . $spec . ', please consider using one of the following available specs: ' . implode(', ', array_keys($this->boostData['gear'])));
209
        }
210
        $this->boostData['spec'] = $spec;
211
        return $this;
212
    }
213
214
    /**
215
     * Actually boost character
216
     * @param bool $boostProfessions
217
     * @throws \Exception
218
     * @return bool
219
     */
220
    public function boost(bool $boostProfessions = false) : bool
221
    {
222
        try {
223
            $this->validateMessageStructure();
224
            $this->sendOldItemsToCharacter();
225
            if ($this->character->online) {
226
                $this->client->character()->kick($this->character->name, 'Character boost is in progress!');
227
                $this->character->update(['online' => 0]);
228
            }
229
            if ($boostProfessions && $this->character->level >= 60) {
230
                $this->boostProfessions();
231
            }
232
            $this->character->update([
233
                'level' =>  $this->boostData['level'],
234
                'money' =>  $this->character->money + $this->moneyBoost[$this->boostData['level']]
235
            ]);
236
        } catch (\Exception $exception) {
237
            return false;
238
        }
239
        return true;
240
    }
241
242
    /**
243
     * Validate message structure
244
     */
245
    private function validateMessageStructure()
246
    {
247
        if ($this->messageTitle === null) {
248
            Helper::throwRuntimeException('In order to be able to perform this action, you have to set the message title first using the setMessageTitle() method!');
249
        }
250
        if ($this->messageBody === null) {
251
            Helper::throwRuntimeException('In order to be able to perform this action, you have to set the message body first using the setMessageBody() method!');
252
        }
253
    }
254
255
    /**
256
     * Send old items to the character via in-game mail system
257
     * @param bool $deleteItems
258
     * @throws \Exception
259
     */
260
    private function sendOldItemsToCharacter(bool $deleteItems = true)
261
    {
262
        $mailBack = [];
263
        $super = $this->super;
264
        /**
265
         * @var Item $item
266
         */
267
        foreach ($super->inventory() as $item) {
268
            if (array_key_exists($item->getSlot(), $this->boostData['gear'][$this->boostData['spec']])) {
269
                $newItem = new Item();
270
                $newItem->setItemID($item->getItemID());
271
                $mailBack[] = $newItem;
272
                if ($deleteItems) {
273
                    $this->deleteItemInstance($item->getUpdatedInstance());
274
                }
275
            }
276
        }
277
        $chunks = array_chunk($mailBack, 12);
278
        if (count($chunks) > 1) {
279
            $messageBody = $this->getMessageBody();
280
            $messageBody .= "\n\nThis is the message %s out of " . count($chunks);
281
            $this->setMessageBody($messageBody);
282
        }
283
        foreach ($chunks as $chunk) {
284
            $this->client->send()->items($this->character->name, $this->getMessageTitle(), $this->getMessageBody(), new Items($chunk));
285
        }
286
        /**
287
         * @var int $item
288
         */
289
        foreach ($this->boostData['gear'][$this->boostData['spec']] as $slot => $item) {
290
            if ($super->reader()->isFileOpened()) {
291
                $itemData = new Item();
292
                $itemData->attachReader($super->reader())->autoloadItemData(true);
293
                $itemData->setItemID($item)->setSlot($slot);
294
                $this->createItemInstance($itemData);
295
            } else {
296
                Helper::throwRuntimeException('You have to include DB2Reader reference in order to be able to perform character boost!');
297
            }
298
        }
299
    }
300
301
    /**
302
     * Delete item reference and item inventory entry
303
     * @param ItemInstance $instance
304
     * @throws \Exception
305
     */
306
    protected function deleteItemInstance(ItemInstance $instance)
307
    {
308
        ItemInstance::destroy($instance->guid);
309
        CharacterInventory::destroy($instance->guid);
310
    }
311
312
    /**
313
     * Equip new items on the character
314
     * @param Item $item
315
     * @return int
316
     */
317
    protected function createItemInstance(Item $item)
318
    {
319
        $durability = new Durability($item);
320
        try {
321
            $guid = (int) ItemInstance::incrementID();
322
            $item->setItemGuid($guid);
323
            $item->setOwnerGuid($this->character->guid);
324
            $item->setDurability($durability->getItemDurability());
325
            $item->setInventoryGuid($this->character->guid);
326
            $item->getUpdatedInstance()->save();
327
            $item->getUpdatedInventory()->save();
328
            return $guid;
329
        } catch (\Exception $e) {
330
            dd('Unrecoverable error occurred while tried to create item ' . $item->getItemID() . ' for character ' . $this->character->guid . PHP_EOL . 'Exception occured: ' . $e->getMessage());
331
        }
332
        return 0;
333
    }
334
335
    /**
336
     * Boost characters professions
337
     */
338
    protected function boostProfessions()
339
    {
340
        $super = $this->super;
341
        if (!empty($super->professions())) { // Character has professions, so we are boosting them
342
            $boostProfessionsTo = $this->professionsBoost[$this->boostData['level']];
343
            /**
344
             * @var CharacterSkill $profession
345
             */
346
            foreach ($super->professions() as $profession) {
347
                $profession->value = $boostProfessionsTo;
348
                $profession->save();
349
            }
350
        } else { // Character has no professions, we should provide ones based on the equipped gear type
351
            dd('No professions found!');
352
        }
353
    }
354
}
355