GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/inventoryrecv.cpp Lines: 2 726 0.3 %
Date: 2017-11-29 Branches: 2 490 0.4 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "net/eathena/inventoryrecv.h"
24
25
#include "notifymanager.h"
26
#include "itemcolormanager.h"
27
28
#include "being/localplayer.h"
29
30
#include "const/net/inventory.h"
31
32
#include "enums/equipslot.h"
33
34
#include "enums/resources/notifytypes.h"
35
36
#include "enums/net/deleteitemreason.h"
37
38
#include "gui/popups/itempopup.h"
39
40
#include "gui/widgets/createwidget.h"
41
42
#include "gui/windows/insertcarddialog.h"
43
44
#include "listeners/arrowslistener.h"
45
46
#include "net/inventoryhandler.h"
47
#include "net/messagein.h"
48
49
#include "net/eathena/itemflags.h"
50
#include "net/eathena/menu.h"
51
52
#include "net/ea/equipbackend.h"
53
#include "net/ea/inventoryrecv.h"
54
55
#include "resources/iteminfo.h"
56
57
#include "utils/gettext.h"
58
#include "utils/foreach.h"
59
#include "utils/stringutils.h"
60
61
#include "debug.h"
62
63
extern int serverVersion;
64
extern int packetVersion;
65
66
namespace EAthena
67
{
68
69
namespace InventoryRecv
70
{
71
    // EQP_* to EquipSlot
72
    const EquipSlot::Type EQUIP_POINTS[EquipSlot::VECTOREND] =
73
    {
74
        EquipSlot::LEGS_SLOT,               // 0  1       EQP_HEAD_LOW
75
        EquipSlot::FIGHT1_SLOT,             // 1  2       EQP_HAND_R
76
        EquipSlot::GLOVES_SLOT,             // 2  4       EQP_GARMENT
77
        EquipSlot::RING2_SLOT,              // 3  8       EQP_ACC_L
78
        EquipSlot::RING1_SLOT,              // 4  16      EQP_ARMOR
79
        EquipSlot::FIGHT2_SLOT,             // 5  32      EQP_HAND_L
80
        EquipSlot::FEET_SLOT,               // 6  64      EQP_SHOES
81
        EquipSlot::NECK_SLOT,               // 7  128     EQP_ACC_R
82
        EquipSlot::HEAD_SLOT,               // 8  256     EQP_HEAD_TOP
83
        EquipSlot::TORSO_SLOT,              // 9  512     EQP_HEAD_MID
84
        EquipSlot::EVOL_RING1_SLOT,         // 10 1024    EQP_COSTUME_HEAD_TOP
85
        EquipSlot::EVOL_RING2_SLOT,         // 11 2048    EQP_COSTUME_HEAD_MID
86
        EquipSlot::PROJECTILE_SLOT,         // 12 4096    EQP_COSTUME_HEAD_LOW
87
        EquipSlot::COSTUME_ROBE_SLOT,       // 13 8192    EQP_COSTUME_GARMENT
88
        EquipSlot::PROJECTILE_SLOT,         // 14 16384   UNUSED_COSTUME_FLOOR
89
        EquipSlot::PROJECTILE_SLOT,         // 15 32768   EQP_AMMO
90
        EquipSlot::SHADOW_ARMOR_SLOT,       // 16 65536   EQP_SHADOW_ARMOR
91
        EquipSlot::SHADOW_WEAPON_SLOT,      // 17 131072  EQP_SHADOW_WEAPON
92
        EquipSlot::SHADOW_SHIELD_SLOT,      // 18 262144  EQP_SHADOW_SHIELD
93
        EquipSlot::SHADOW_SHOES_SLOT,       // 19 524288  EQP_SHADOW_SHOES
94
        EquipSlot::SHADOW_ACCESSORY2_SLOT,  // 20 1048576 EQP_SHADOW_ACC_R
95
        EquipSlot::SHADOW_ACCESSORY1_SLOT,  // 21 2097152 EQP_SHADOW_ACC_L
96
    };
97
98
2
    Ea::InventoryItems mCartItems;
99
}  // namespace InventoryRecv
100
101
void InventoryRecv::processPlayerEquipment(Net::MessageIn &msg)
102
{
103
    BLOCK_START("InventoryRecv::processPlayerEquipment")
104
    Inventory *const inventory = localPlayer != nullptr
105
        ? PlayerInfo::getInventory() : nullptr;
106
107
    msg.readInt16("len");
108
    Equipment *const equipment = PlayerInfo::getEquipment();
109
    if ((equipment != nullptr) && (equipment->getBackend() == nullptr))
110
    {   // look like SMSG_PLAYER_INVENTORY was not received
111
        Ea::InventoryRecv::mEquips.clear();
112
        equipment->setBackend(&Ea::InventoryRecv::mEquips);
113
    }
114
115
    int packetLen = 2 + 2 + 1 + 1 + 8;
116
    if (msg.getVersion() >= 20120925)
117
        packetLen += 4 + 4 + 1;
118
    else
119
        packetLen += 1 + 2 + 2 + 1;
120
    if (msg.getVersion() >= 20071002)
121
        packetLen += 4;
122
    if (msg.getVersion() >= 20080102)
123
        packetLen += 2;
124
    if (msg.getVersion() >= 20100629)
125
        packetLen += 2;
126
    if (msg.getVersion() >= 20150226)
127
        packetLen += 26;
128
129
    const int number = (msg.getLength() - 4) / packetLen;
130
131
    for (int loop = 0; loop < number; loop++)
132
    {
133
        const int index = msg.readInt16("index") - INVENTORY_OFFSET;
134
        const int itemId = msg.readInt16("item id");
135
        const ItemTypeT itemType = static_cast<ItemTypeT>(
136
            msg.readUInt8("item type"));
137
        int equipType;
138
        if (msg.getVersion() >= 20120925)
139
        {
140
            msg.readInt32("location");
141
            equipType = msg.readInt32("wear state");
142
        }
143
        else
144
        {
145
            msg.readUInt8("identified");
146
            msg.readInt16("location");
147
            equipType = msg.readInt16("wear state");
148
            msg.readUInt8("is damaged");
149
        }
150
        const uint8_t refine = CAST_U8(msg.readInt8("refine"));
151
        int cards[maxCards];
152
        for (int f = 0; f < maxCards; f++)
153
            cards[f] = msg.readUInt16("card");
154
        if (msg.getVersion() >= 20071002)
155
            msg.readInt32("hire expire date (?)");
156
        if (msg.getVersion() >= 20080102)
157
            msg.readInt16("equip type");
158
        if (msg.getVersion() >= 20100629)
159
            msg.readInt16("item sprite number");
160
        ItemOptionsList *options = nullptr;
161
        if (msg.getVersion() >= 20150226)
162
        {
163
            options = new ItemOptionsList(msg.readUInt8("option count"));
164
            for (int f = 0; f < 5; f ++)
165
            {
166
                const uint16_t idx = msg.readInt16("option index");
167
                const uint16_t val = msg.readInt16("option value");
168
                msg.readUInt8("option param");
169
                options->add(idx, val);
170
            }
171
        }
172
        ItemFlags flags;
173
        if (msg.getVersion() >= 20120925)
174
            flags.byte = msg.readUInt8("flags");
175
        else
176
            flags.byte = 0;
177
        if (inventory != nullptr)
178
        {
179
            inventory->setItem(index,
180
                itemId,
181
                itemType,
182
                1,
183
                refine,
184
                ItemColorManager::getColorFromCards(&cards[0]),
185
                fromBool(flags.bits.isIdentified, Identified),
186
                fromBool(flags.bits.isDamaged, Damaged),
187
                fromBool(flags.bits.isFavorite, Favorite),
188
                Equipm_true,
189
                Equipped_false);
190
            inventory->setCards(index, cards, maxCards);
191
            inventory->setOptions(index, options);
192
        }
193
        delete options;
194
195
        if (equipType != 0)
196
        {
197
            Ea::InventoryRecv::mEquips.setEquipment(
198
                InventoryRecv::getSlot(equipType),
199
                index);
200
        }
201
    }
202
    BLOCK_END("InventoryRecv::processPlayerEquipment")
203
}
204
205
void InventoryRecv::processPlayerInventoryAdd(Net::MessageIn &msg)
206
{
207
    BLOCK_START("InventoryRecv::processPlayerInventoryAdd")
208
    Inventory *const inventory = localPlayer != nullptr
209
        ? PlayerInfo::getInventory() : nullptr;
210
211
    if ((PlayerInfo::getEquipment() != nullptr)
212
        && (PlayerInfo::getEquipment()->getBackend() == nullptr))
213
    {   // look like SMSG_PLAYER_INVENTORY was not received
214
        Ea::InventoryRecv::mEquips.clear();
215
        PlayerInfo::getEquipment()->setBackend(&Ea::InventoryRecv::mEquips);
216
    }
217
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
218
    int amount = msg.readInt16("count");
219
    const int itemId = msg.readInt16("item id");
220
    const uint8_t identified = msg.readUInt8("identified");
221
    const uint8_t damaged = msg.readUInt8("is damaged");
222
    const uint8_t refine = msg.readUInt8("refine");
223
    Favorite favorite = Favorite_false;
224
    int cards[maxCards];
225
    for (int f = 0; f < maxCards; f++)
226
        cards[f] = msg.readUInt16("card");
227
    int equipType;
228
    if (msg.getVersion() >= 20120925)
229
        equipType = msg.readInt32("location");
230
    else
231
        equipType = msg.readInt16("location");
232
    const ItemTypeT itemType = static_cast<ItemTypeT>(
233
        msg.readUInt8("item type"));
234
    const unsigned char err = msg.readUInt8("result");
235
    if (msg.getVersion() >= 20061218)
236
        msg.readInt32("hire expire date");
237
    if (msg.getVersion() >= 20071002)
238
        msg.readInt16("bind on equip");
239
    ItemOptionsList *options = nullptr;
240
    if (msg.getVersion() >= 20150226)
241
    {
242
        options = new ItemOptionsList;
243
        for (int f = 0; f < 5; f ++)
244
        {
245
            const uint16_t idx = msg.readInt16("option index");
246
            const uint16_t val = msg.readInt16("option value");
247
            msg.readUInt8("option param");
248
            options->add(idx, val);
249
        }
250
    }
251
    if (msg.getVersion() >= 20160921)
252
    {
253
        favorite = fromBool(msg.readUInt8("favorite"), Favorite);
254
        msg.readInt16("look");
255
    }
256
257
    const ItemColor color = ItemColorManager::getColorFromCards(&cards[0]);
258
    BeingId floorId;
259
    if (Ea::InventoryRecv::mSentPickups.empty())
260
    {
261
        floorId = BeingId_zero;
262
    }
263
    else
264
    {
265
        floorId = Ea::InventoryRecv::mSentPickups.front();
266
        Ea::InventoryRecv::mSentPickups.pop();
267
    }
268
269
    if (err != 0u)
270
    {
271
        PickupT pickup;
272
        switch (err)
273
        {
274
            case 1:
275
                pickup = Pickup::BAD_ITEM;
276
                break;
277
            case 2:
278
                pickup = Pickup::TOO_HEAVY;
279
                break;
280
            case 4:
281
                pickup = Pickup::INV_FULL;
282
                break;
283
            case 5:
284
                pickup = Pickup::MAX_AMOUNT;
285
                break;
286
            case 6:
287
                pickup = Pickup::TOO_FAR;
288
                break;
289
            case 7:
290
                pickup = Pickup::STACK_AMOUNT;
291
                break;
292
            default:
293
                pickup = Pickup::UNKNOWN;
294
                UNIMPLEMENTEDPACKETFIELD(err);
295
                break;
296
        }
297
        if (localPlayer != nullptr)
298
        {
299
            if (itemId == 0)
300
            {
301
                localPlayer->pickedUp(ItemDB::getEmpty(),
302
                    0,
303
                    color,
304
                    floorId,
305
                    pickup);
306
            }
307
            else
308
            {
309
                localPlayer->pickedUp(ItemDB::get(itemId),
310
                    0,
311
                    color,
312
                    floorId,
313
                    pickup);
314
            }
315
        }
316
    }
317
    else
318
    {
319
        if (localPlayer != nullptr)
320
        {
321
            if (itemId == 0)
322
            {
323
                localPlayer->pickedUp(ItemDB::getEmpty(),
324
                    amount,
325
                    color,
326
                    floorId,
327
                    Pickup::OKAY);
328
            }
329
            else
330
            {
331
                localPlayer->pickedUp(ItemDB::get(itemId),
332
                    amount,
333
                    color,
334
                    floorId,
335
                    Pickup::OKAY);
336
            }
337
        }
338
339
        if (inventory != nullptr)
340
        {
341
            const Item *const item = inventory->getItem(index);
342
343
            if ((item != nullptr) && item->getId() == itemId)
344
                amount += item->getQuantity();
345
346
            inventory->setItem(index,
347
                itemId,
348
                itemType,
349
                amount,
350
                refine,
351
                color,
352
                fromBool(identified, Identified),
353
                fromBool(damaged, Damaged),
354
                favorite,
355
                fromBool(equipType, Equipm),
356
                Equipped_false);
357
            inventory->setCards(index, cards, maxCards);
358
            inventory->setOptions(index, options);
359
        }
360
        ArrowsListener::distributeEvent();
361
    }
362
    delete options;
363
    BLOCK_END("InventoryRecv::processPlayerInventoryAdd")
364
}
365
366
void InventoryRecv::processPlayerInventory(Net::MessageIn &msg)
367
{
368
    BLOCK_START("InventoryRecv::processPlayerInventory")
369
    Inventory *const inventory = localPlayer != nullptr
370
        ? PlayerInfo::getInventory() : nullptr;
371
    if (PlayerInfo::getEquipment() != nullptr)
372
    {
373
        // Clear inventory - this will be a complete refresh
374
        Ea::InventoryRecv::mEquips.clear();
375
        PlayerInfo::getEquipment()->setBackend(&Ea::InventoryRecv::mEquips);
376
    }
377
378
    if (inventory != nullptr)
379
        inventory->clear();
380
381
    msg.readInt16("len");
382
383
    int packetLen = 7;
384
    if (msg.getVersion() >= 20120925)
385
        packetLen += 4 + 1;
386
    else
387
        packetLen += 1 + 2;
388
    if (packetVersion >= 5)
389
        packetLen += 8;
390
    if (msg.getVersion() >= 20080102)
391
        packetLen += 4;
392
393
    const int number = (msg.getLength() - 4) / packetLen;
394
395
    for (int loop = 0; loop < number; loop++)
396
    {
397
        const int index = msg.readInt16("item index") - INVENTORY_OFFSET;
398
        const int itemId = msg.readInt16("item id");
399
        const ItemTypeT itemType = static_cast<ItemTypeT>(
400
            msg.readUInt8("item type"));
401
        if (msg.getVersion() < 20120925)
402
            msg.readUInt8("identified");
403
        const int amount = msg.readInt16("count");
404
        if (msg.getVersion() >= 20120925)
405
            msg.readInt32("wear state / equip");
406
        else
407
            msg.readInt16("wear state / equip");
408
        int cards[maxCards];
409
        if (packetVersion >= 5)
410
        {
411
            for (int f = 0; f < maxCards; f++)
412
                cards[f] = msg.readUInt16("card");
413
        }
414
        else
415
        {
416
            for (int f = 0; f < maxCards; f++)
417
                cards[f] = 0;
418
        }
419
        if (msg.getVersion() >= 20080102)
420
            msg.readInt32("hire expire date (?)");
421
        ItemFlags flags;
422
        if (msg.getVersion() >= 20120925)
423
            flags.byte = msg.readUInt8("flags");
424
        else
425
            flags.byte = 0;
426
427
        if (inventory != nullptr)
428
        {
429
            inventory->setItem(index,
430
                itemId,
431
                itemType,
432
                amount,
433
                0,
434
                ItemColorManager::getColorFromCards(&cards[0]),
435
                fromBool(flags.bits.isIdentified, Identified),
436
                fromBool(flags.bits.isDamaged, Damaged),
437
                fromBool(flags.bits.isFavorite, Favorite),
438
                Equipm_false,
439
                Equipped_false);
440
            inventory->setCards(index, cards, maxCards);
441
        }
442
    }
443
    BLOCK_END("InventoryRecv::processPlayerInventory")
444
}
445
446
void InventoryRecv::processPlayerStorage(Net::MessageIn &msg)
447
{
448
    BLOCK_START("InventoryRecv::processPlayerInventory")
449
    Ea::InventoryRecv::mInventoryItems.clear();
450
451
    msg.readInt16("len");
452
453
    int packetLen = 7;
454
    if (msg.getVersion() >= 20120925)
455
        packetLen += 4 + 1;
456
    else
457
        packetLen += 1 + 2;
458
    if (packetVersion >= 5)
459
        packetLen += 8;
460
    if (msg.getVersion() >= 20080102)
461
        packetLen += 4;
462
463
    int number;
464
    if (msg.getVersion() >= 20120925)
465
    {
466
        msg.readString(24, "storage name");
467
        number = (msg.getLength() - 4 - 24) / packetLen;
468
    }
469
    else
470
    {
471
        number = (msg.getLength() - 4) / packetLen;
472
    }
473
474
    for (int loop = 0; loop < number; loop++)
475
    {
476
        const int index = msg.readInt16("item index") - STORAGE_OFFSET;
477
        const int itemId = msg.readInt16("item id");
478
        const ItemTypeT itemType = static_cast<ItemTypeT>(
479
            msg.readUInt8("item type"));
480
        if (msg.getVersion() < 20120925)
481
            msg.readUInt8("identified");
482
        const int amount = msg.readInt16("count");
483
        if (msg.getVersion() >= 20120925)
484
            msg.readInt32("wear state / equip");
485
        else
486
            msg.readInt16("wear state / equip");
487
        int cards[maxCards];
488
        if (msg.getVersion() >= 5)
489
        {
490
            for (int f = 0; f < maxCards; f++)
491
                cards[f] = msg.readUInt16("card");
492
        }
493
        else
494
        {
495
            for (int f = 0; f < maxCards; f++)
496
                cards[f] = 0;
497
        }
498
        if (msg.getVersion() >= 20080102)
499
            msg.readInt32("hire expire date (?)");
500
        ItemFlags flags;
501
        if (msg.getVersion() >= 20120925)
502
            flags.byte = msg.readUInt8("flags");
503
        else
504
            flags.byte = 0;
505
506
        Ea::InventoryRecv::mInventoryItems.push_back(Ea::InventoryItem(
507
            index,
508
            itemId,
509
            itemType,
510
            cards,
511
            nullptr,
512
            amount,
513
            0,
514
            ItemColorManager::getColorFromCards(&cards[0]),
515
            fromBool(flags.bits.isIdentified, Identified),
516
            fromBool(flags.bits.isDamaged, Damaged),
517
            fromBool(flags.bits.isFavorite, Favorite),
518
            Equipm_false));
519
    }
520
    BLOCK_END("InventoryRecv::processPlayerInventory")
521
}
522
523
void InventoryRecv::processPlayerEquip(Net::MessageIn &msg)
524
{
525
    BLOCK_START("InventoryRecv::processPlayerEquip")
526
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
527
    int equipType;
528
    if (msg.getVersion() >= 20120925)
529
        equipType = msg.readInt32("wear location");
530
    else
531
        equipType = msg.readInt16("wear location");
532
    if (msg.getVersion() >= 20100629)
533
        msg.readInt16("sprite");
534
    const uint8_t flag = msg.readUInt8("result");
535
536
    switch (flag)
537
    {
538
        case 0:
539
            Ea::InventoryRecv::mEquips.setEquipment(
540
                InventoryRecv::getSlot(equipType),
541
                index);
542
            break;
543
        case 1:
544
            NotifyManager::notify(NotifyTypes::EQUIP_FAILED_LEVEL);
545
            break;
546
547
        case 2:
548
        default:
549
            NotifyManager::notify(NotifyTypes::EQUIP_FAILED);
550
            break;
551
    }
552
    BLOCK_END("InventoryRecv::processPlayerEquip")
553
}
554
555
void InventoryRecv::processPlayerUnEquip(Net::MessageIn &msg)
556
{
557
    BLOCK_START("InventoryRecv::processPlayerUnEquip")
558
    msg.readInt16("index");
559
    int equipType;
560
    if (msg.getVersion() >= 20120925)
561
        equipType = msg.readInt32("wear location");
562
    else
563
        equipType = msg.readInt16("wear location");
564
    const uint8_t flag = msg.readUInt8("result");
565
566
    if (flag != 0u)
567
    {
568
        NotifyManager::notify(NotifyTypes::UNEQUIP_FAILED);
569
    }
570
    else
571
    {
572
        Ea::InventoryRecv::mEquips.setEquipment(
573
            InventoryRecv::getSlot(equipType),
574
            -1);
575
    }
576
    if ((equipType & 0x8000) != 0)
577
        ArrowsListener::distributeEvent();
578
    BLOCK_END("InventoryRecv::processPlayerUnEquip")
579
}
580
581
void InventoryRecv::processPlayerInventoryRemove2(Net::MessageIn &msg)
582
{
583
    BLOCK_START("InventoryRecv::processPlayerInventoryRemove2")
584
    Inventory *const inventory = localPlayer != nullptr
585
        ? PlayerInfo::getInventory() : nullptr;
586
587
    const DeleteItemReasonT reason = static_cast<DeleteItemReasonT>(
588
        msg.readInt16("reason"));
589
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
590
    const int amount = msg.readInt16("amount");
591
592
    if (inventory != nullptr)
593
    {
594
        if (Item *const item = inventory->getItem(index))
595
        {
596
            switch (reason)
597
            {
598
                case DeleteItemReason::Normal:
599
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_NORMAL,
600
                        item->getName());
601
                    break;
602
                case DeleteItemReason::SkillUse:
603
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_SKILL_USE,
604
                        item->getName());
605
                    break;
606
                case DeleteItemReason::FailRefine:
607
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_FAIL_REFINE,
608
                        item->getName());
609
                    break;
610
                case DeleteItemReason::MaterialChange:
611
                    NotifyManager::notify(
612
                        NotifyTypes::DELETE_ITEM_MATERIAL_CHANGE,
613
                        item->getName());
614
                    break;
615
                case DeleteItemReason::ToStorage:
616
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_TO_STORAGE,
617
                        item->getName());
618
                    break;
619
                case DeleteItemReason::ToCart:
620
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_TO_CART,
621
                        item->getName());
622
                    break;
623
                case DeleteItemReason::Sold:
624
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_SOLD,
625
                        item->getName());
626
                    break;
627
                case DeleteItemReason::Analysis:
628
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_ANALYSIS,
629
                        item->getName());
630
                    break;
631
                default:
632
                    NotifyManager::notify(NotifyTypes::DELETE_ITEM_UNKNOWN,
633
                        item->getName());
634
                    break;
635
            }
636
637
            item->increaseQuantity(-amount);
638
            if (item->getQuantity() == 0)
639
                inventory->removeItemAt(index);
640
            ArrowsListener::distributeEvent();
641
        }
642
    }
643
    BLOCK_END("InventoryRecv::processPlayerInventoryRemove2")
644
}
645
646
void InventoryRecv::processPlayerStorageEquip(Net::MessageIn &msg)
647
{
648
    BLOCK_START("InventoryRecv::processPlayerStorageEquip")
649
    msg.readInt16("len");
650
651
    int packetLen = 2 + 2 + 1 + 1 + 8;
652
    if (msg.getVersion() >= 20120925)
653
        packetLen += 4 + 4 + 1;
654
    else
655
        packetLen += 1 + 2 + 2 + 1;
656
    if (msg.getVersion() >= 20071002)
657
        packetLen += 4;
658
    if (msg.getVersion() >= 20080102)
659
        packetLen += 2;
660
    if (msg.getVersion() >= 20100629)
661
        packetLen += 2;
662
    if (msg.getVersion() >= 20150226)
663
        packetLen += 26;
664
665
    int number;
666
    if (msg.getVersion() >= 20120925)
667
    {
668
        msg.readString(24, "storage name");
669
        number = (msg.getLength() - 4 - 24) / packetLen;
670
    }
671
    else
672
    {
673
        number = (msg.getLength() - 4) / packetLen;
674
    }
675
676
    for (int loop = 0; loop < number; loop++)
677
    {
678
        const int index = msg.readInt16("index") - STORAGE_OFFSET;
679
        const int itemId = msg.readInt16("item id");
680
        const ItemTypeT itemType = static_cast<ItemTypeT>(
681
            msg.readUInt8("item type"));
682
        const int amount = 1;
683
        if (msg.getVersion() >= 20120925)
684
        {
685
            msg.readInt32("location");
686
            msg.readInt32("wear state");
687
        }
688
        else
689
        {
690
            msg.readUInt8("identified");
691
            msg.readInt16("location");
692
            msg.readInt16("wear state");
693
            msg.readUInt8("is damaged");
694
        }
695
        const uint8_t refine = msg.readUInt8("refine level");
696
        int cards[maxCards];
697
        for (int f = 0; f < maxCards; f++)
698
            cards[f] = msg.readUInt16("card");
699
        if (msg.getVersion() >= 20071002)
700
            msg.readInt32("hire expire date");
701
        if (msg.getVersion() >= 20080102)
702
            msg.readInt16("bind on equip");
703
        if (msg.getVersion() >= 20100629)
704
            msg.readInt16("sprite");
705
        ItemOptionsList *options = nullptr;
706
        if (msg.getVersion() >= 20150226)
707
        {
708
            options = new ItemOptionsList(msg.readUInt8("option count"));
709
            for (int f = 0; f < 5; f ++)
710
            {
711
                const uint16_t idx = msg.readInt16("option index");
712
                const uint16_t val = msg.readInt16("option value");
713
                msg.readUInt8("option param");
714
                options->add(idx, val);
715
            }
716
        }
717
718
        ItemFlags flags;
719
        if (msg.getVersion() >= 20120925)
720
            flags.byte = msg.readUInt8("flags");
721
        else
722
            flags.byte = 0;
723
724
        Ea::InventoryRecv::mInventoryItems.push_back(Ea::InventoryItem(
725
            index,
726
            itemId,
727
            itemType,
728
            cards,
729
            options,
730
            amount,
731
            refine,
732
            ItemColorManager::getColorFromCards(&cards[0]),
733
            fromBool(flags.bits.isIdentified, Identified),
734
            fromBool(flags.bits.isDamaged, Damaged),
735
            fromBool(flags.bits.isFavorite, Favorite),
736
            Equipm_false));
737
        delete options;
738
    }
739
    BLOCK_END("InventoryRecv::processPlayerStorageEquip")
740
}
741
742
void InventoryRecv::processPlayerStorageAdd(Net::MessageIn &msg)
743
{
744
    BLOCK_START("InventoryRecv::processPlayerStorageAdd")
745
    // Move an item into storage
746
    const int index = msg.readInt16("index") - STORAGE_OFFSET;
747
    const int amount = msg.readInt32("amount");
748
    const int itemId = msg.readInt16("item id");
749
    ItemTypeT itemType;
750
    if (msg.getVersion() >= 5)
751
        itemType = static_cast<ItemTypeT>(msg.readUInt8("type"));
752
    else
753
        itemType = ItemType::Unknown;
754
    const unsigned char identified = msg.readUInt8("identify");
755
    const Damaged damaged = fromBool(msg.readUInt8("attribute"), Damaged);
756
    const uint8_t refine = msg.readUInt8("refine");
757
    int cards[maxCards];
758
    for (int f = 0; f < maxCards; f++)
759
        cards[f] = msg.readUInt16("card");
760
    ItemOptionsList *options = nullptr;
761
    if (msg.getVersion() >= 20150226)
762
    {
763
        options = new ItemOptionsList;
764
        for (int f = 0; f < 5; f ++)
765
        {
766
            const uint16_t idx = msg.readInt16("option index");
767
            const uint16_t val = msg.readInt16("option value");
768
            msg.readUInt8("option param");
769
            options->add(idx, val);
770
        }
771
    }
772
773
    const ItemColor color = ItemColorManager::getColorFromCards(&cards[0]);
774
    if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
775
    {
776
        item->setId(itemId, color);
777
        item->increaseQuantity(amount);
778
    }
779
    else
780
    {
781
        if (Ea::InventoryRecv::mStorage != nullptr)
782
        {
783
            Ea::InventoryRecv::mStorage->setItem(index,
784
                itemId,
785
                itemType,
786
                amount,
787
                refine,
788
                color,
789
                fromBool(identified, Identified),
790
                damaged,
791
                Favorite_false,
792
                Equipm_false,
793
                Equipped_false);
794
            Ea::InventoryRecv::mStorage->setCards(index, cards, maxCards);
795
            Ea::InventoryRecv::mStorage->setOptions(index, options);
796
        }
797
    }
798
    delete options;
799
    BLOCK_END("InventoryRecv::processPlayerStorageAdd")
800
}
801
802
void InventoryRecv::processPlayerUseCard(Net::MessageIn &msg)
803
{
804
    const Inventory *const inv = PlayerInfo::getInventory();
805
    const int index = inventoryHandler->getItemIndex();
806
    const Item *item1 = nullptr;
807
    if (inv != nullptr)
808
        item1 = inv->getItem(index);
809
    SellDialog *const dialog = CREATEWIDGETR(InsertCardDialog,
810
        index, item1);
811
812
    const int count = (msg.readInt16("len") - 4) / 2;
813
    for (int f = 0; f < count; f ++)
814
    {
815
        const int itemIndex = msg.readInt16("item index") - INVENTORY_OFFSET;
816
        if (inv == nullptr)
817
            continue;
818
        const Item *const item = inv->getItem(itemIndex);
819
        if (item == nullptr)
820
            continue;
821
        dialog->addItem(item, 0);
822
    }
823
}
824
825
void InventoryRecv::processPlayerInsertCard(Net::MessageIn &msg)
826
{
827
    const int itemIndex = msg.readInt16("item index") - INVENTORY_OFFSET;
828
    const int cardIndex = msg.readInt16("card index") - INVENTORY_OFFSET;
829
    if (msg.readUInt8("flag") != 0u)
830
    {
831
        NotifyManager::notify(NotifyTypes::CARD_INSERT_FAILED);
832
    }
833
    else
834
    {
835
        NotifyManager::notify(NotifyTypes::CARD_INSERT_SUCCESS);
836
        Inventory *const inv = PlayerInfo::getInventory();
837
        if (inv == nullptr)
838
            return;
839
        Item *const card = inv->getItem(cardIndex);
840
        int cardId = 0;
841
        if (card != nullptr)
842
        {
843
            cardId = card->getId();
844
            card->increaseQuantity(-1);
845
            if (card->getQuantity() == 0)
846
                inv->removeItemAt(cardIndex);
847
        }
848
        Item *const item = inv->getItem(itemIndex);
849
        if (item != nullptr)
850
        {
851
            item->addCard(cardId);
852
            item->updateColor();
853
            itemPopup->resetPopup();
854
        }
855
    }
856
}
857
858
void InventoryRecv::processPlayerItemRentalTime(Net::MessageIn &msg)
859
{
860
    const int id = msg.readInt16("item id");
861
    const int seconds = msg.readInt32("seconds");
862
    const ItemInfo &info = ItemDB::get(id);
863
    const std::string timeStr = timeDiffToString(seconds);
864
    NotifyManager::notify(NotifyTypes::RENTAL_TIME_LEFT,
865
        // TRANSLATORS: notification message
866
        strprintf(_("Left %s rental time for item %s."),
867
        timeStr.c_str(), info.getName().c_str()));
868
}
869
870
void InventoryRecv::processPlayerItemRentalExpired(Net::MessageIn &msg)
871
{
872
    Inventory *const inventory = localPlayer != nullptr
873
        ? PlayerInfo::getInventory() : nullptr;
874
875
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
876
    const int id = msg.readInt16("item id");
877
    const ItemInfo &info = ItemDB::get(id);
878
879
    NotifyManager::notify(NotifyTypes::RENTAL_TIME_EXPIRED,
880
        info.getName());
881
    if (inventory != nullptr)
882
    {
883
        if (Item *const item = inventory->getItem(index))
884
        {
885
            item->increaseQuantity(-item->getQuantity());
886
            inventory->removeItemAt(index);
887
            ArrowsListener::distributeEvent();
888
        }
889
    }
890
}
891
892
void InventoryRecv::processPlayerStorageRemove(Net::MessageIn &msg)
893
{
894
    BLOCK_START("InventoryRecv::processPlayerStorageRemove")
895
    // Move an item out of storage
896
    const int index = msg.readInt16("index") - STORAGE_OFFSET;
897
    const int amount = msg.readInt32("amount");
898
    if (Ea::InventoryRecv::mStorage != nullptr)
899
    {
900
        if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
901
        {
902
            item->increaseQuantity(-amount);
903
            if (item->getQuantity() == 0)
904
                Ea::InventoryRecv::mStorage->removeItemAt(index);
905
        }
906
    }
907
    BLOCK_END("InventoryRecv::processPlayerStorageRemove")
908
}
909
910
void InventoryRecv::processCartInfo(Net::MessageIn &msg)
911
{
912
    msg.readInt16("cart items used");
913
    const int size = msg.readInt16("max cart items");
914
    PlayerInfo::setAttribute(Attributes::CART_TOTAL_WEIGHT,
915
        msg.readInt32("cart weight"));
916
    PlayerInfo::setAttribute(Attributes::CART_MAX_WEIGHT,
917
        msg.readInt32("max cart weight"));
918
    if (mCartItems.empty())
919
        return;
920
921
    Inventory *const inv = PlayerInfo::getCartInventory();
922
    if (inv == nullptr)
923
        return;
924
925
    inv->resize(size);
926
927
    FOR_EACH (Ea::InventoryItems::const_iterator, it, mCartItems)
928
    {
929
        inv->setItem((*it).slot,
930
            (*it).id,
931
            (*it).type,
932
            (*it).quantity,
933
            (*it).refine,
934
            (*it).color,
935
            (*it).identified,
936
            (*it).damaged,
937
            (*it).favorite,
938
            (*it).equip,
939
            Equipped_false);
940
    }
941
    mCartItems.clear();
942
}
943
944
void InventoryRecv::processCartRemove(Net::MessageIn &msg)
945
{
946
    UNIMPLEMENTEDPACKET;
947
    // +++ need close or clear cart?
948
}
949
950
void InventoryRecv::processPlayerCartAdd(Net::MessageIn &msg)
951
{
952
    BLOCK_START("InventoryRecv::processPlayerCartAdd")
953
    Inventory *const inventory = localPlayer != nullptr
954
        ? PlayerInfo::getCartInventory() : nullptr;
955
956
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
957
    int amount = msg.readInt32("count");
958
    const int itemId = msg.readInt16("item id");
959
    ItemTypeT itemType = ItemType::Unknown;
960
    if (msg.getVersion() >= 5)
961
    {
962
        itemType = static_cast<ItemTypeT>(
963
            msg.readUInt8("item type"));
964
    }
965
    const uint8_t identified = msg.readUInt8("identified");
966
    const Damaged damaged = fromBool(msg.readUInt8("attribute"), Damaged);
967
    const uint8_t refine = msg.readUInt8("refine");
968
    int cards[maxCards];
969
    for (int f = 0; f < maxCards; f++)
970
        cards[f] = msg.readUInt16("card");
971
    ItemOptionsList *options = nullptr;
972
    if (msg.getVersion() >= 20150226)
973
    {
974
        options = new ItemOptionsList;
975
        for (int f = 0; f < 5; f ++)
976
        {
977
            const uint16_t idx = msg.readInt16("option index");
978
            const uint16_t val = msg.readInt16("option value");
979
            msg.readUInt8("option param");
980
            options->add(idx, val);
981
        }
982
    }
983
984
    // check what cart was created, if not add delayed items
985
    if ((inventory != nullptr) && inventory->getSize() > 0)
986
    {
987
        const Item *const item = inventory->getItem(index);
988
989
        if ((item != nullptr) && item->getId() == itemId)
990
            amount += item->getQuantity();
991
992
        inventory->setItem(index,
993
            itemId,
994
            itemType,
995
            amount,
996
            refine,
997
            ItemColorManager::getColorFromCards(&cards[0]),
998
            fromBool(identified, Identified),
999
            damaged,
1000
            Favorite_false,
1001
            Equipm_false,
1002
            Equipped_false);
1003
        inventory->setCards(index, cards, maxCards);
1004
        inventory->setOptions(index, options);
1005
    }
1006
    else
1007
    {
1008
        mCartItems.push_back(Ea::InventoryItem(index,
1009
            itemId,
1010
            itemType,
1011
            cards,
1012
            options,
1013
            amount,
1014
            refine,
1015
            ItemColorManager::getColorFromCards(&cards[0]),
1016
            fromBool(identified, Identified),
1017
            damaged,
1018
            Favorite_false,
1019
            Equipm_false));
1020
    }
1021
    delete options;
1022
    BLOCK_END("InventoryRecv::processPlayerCartAdd")
1023
}
1024
1025
void InventoryRecv::processPlayerCartEquip(Net::MessageIn &msg)
1026
{
1027
    BLOCK_START("InventoryRecv::processPlayerCartEquip")
1028
    msg.readInt16("len");
1029
1030
    int packetLen = 2 + 2 + 1 + 1 + 8;
1031
    if (msg.getVersion() >= 20120925)
1032
        packetLen += 4 + 4 + 1;
1033
    else
1034
        packetLen += 1 + 2 + 2 + 1;
1035
    if (msg.getVersion() >= 20071002)
1036
        packetLen += 4;
1037
    if (msg.getVersion() >= 20080102)
1038
        packetLen += 2;
1039
    if (msg.getVersion() >= 20100629)
1040
        packetLen += 2;
1041
    if (msg.getVersion() >= 20150226)
1042
        packetLen += 26;
1043
1044
    const int number = (msg.getLength() - 4) / packetLen;
1045
    for (int loop = 0; loop < number; loop++)
1046
    {
1047
        const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1048
        const int itemId = msg.readInt16("item id");
1049
        const ItemTypeT itemType = static_cast<ItemTypeT>(
1050
            msg.readUInt8("item type"));
1051
        const int amount = 1;
1052
        if (msg.getVersion() >= 20120925)
1053
        {
1054
            msg.readInt32("location");
1055
            msg.readInt32("wear state");
1056
        }
1057
        else
1058
        {
1059
            msg.readUInt8("identified");
1060
            msg.readInt16("location");
1061
            msg.readInt16("wear state");
1062
            msg.readUInt8("is damaged");
1063
        }
1064
        const uint8_t refine = msg.readUInt8("refine level");
1065
        int cards[maxCards];
1066
        for (int f = 0; f < maxCards; f++)
1067
            cards[f] = msg.readUInt16("card");
1068
        if (msg.getVersion() >= 20071002)
1069
            msg.readInt32("hire expire date");
1070
        if (msg.getVersion() >= 20080102)
1071
            msg.readInt16("bind on equip");
1072
        if (msg.getVersion() >= 20100629)
1073
            msg.readInt16("sprite");
1074
        ItemOptionsList *options = nullptr;
1075
        if (msg.getVersion() >= 20150226)
1076
        {
1077
            options = new ItemOptionsList(msg.readUInt8("option count"));
1078
            for (int f = 0; f < 5; f ++)
1079
            {
1080
                const uint16_t idx = msg.readInt16("option index");
1081
                const uint16_t val = msg.readInt16("option value");
1082
                msg.readUInt8("option param");
1083
                options->add(idx, val);
1084
            }
1085
        }
1086
        ItemFlags flags;
1087
        if (msg.getVersion() >= 20120925)
1088
            flags.byte = msg.readUInt8("flags");
1089
        else
1090
            flags.byte = 0;
1091
1092
        mCartItems.push_back(Ea::InventoryItem(index,
1093
            itemId,
1094
            itemType,
1095
            cards,
1096
            options,
1097
            amount,
1098
            refine,
1099
            ItemColorManager::getColorFromCards(&cards[0]),
1100
            fromBool(flags.bits.isIdentified, Identified),
1101
            fromBool(flags.bits.isDamaged, Damaged),
1102
            fromBool(flags.bits.isFavorite, Favorite),
1103
            Equipm_false));
1104
        delete options;
1105
    }
1106
    BLOCK_END("InventoryRecv::processPlayerCartEquip")
1107
}
1108
1109
void InventoryRecv::processPlayerCartItems(Net::MessageIn &msg)
1110
{
1111
    BLOCK_START("InventoryRecv::processPlayerCartItems")
1112
    Ea::InventoryRecv::mInventoryItems.clear();
1113
1114
    msg.readInt16("len");
1115
1116
    int packetLen = 7;
1117
    if (msg.getVersion() >= 20120925)
1118
        packetLen += 4 + 1;
1119
    else
1120
        packetLen += 1 + 2;
1121
    if (packetVersion >= 5)
1122
        packetLen += 8;
1123
    if (msg.getVersion() >= 20080102)
1124
        packetLen += 4;
1125
1126
    const int number = (msg.getLength() - 4) / packetLen;
1127
    for (int loop = 0; loop < number; loop++)
1128
    {
1129
        const int index = msg.readInt16("item index") - INVENTORY_OFFSET;
1130
        const int itemId = msg.readInt16("item id");
1131
        const ItemTypeT itemType = static_cast<ItemTypeT>(
1132
            msg.readUInt8("item type"));
1133
        if (msg.getVersion() < 20120925)
1134
            msg.readUInt8("identified");
1135
        const int amount = msg.readInt16("count");
1136
        if (msg.getVersion() >= 20120925)
1137
            msg.readInt32("wear state / equip");
1138
        int cards[maxCards];
1139
        if (msg.getVersion() >= 5)
1140
        {
1141
            for (int f = 0; f < maxCards; f++)
1142
                cards[f] = msg.readUInt16("card");
1143
        }
1144
        else
1145
        {
1146
            for (int f = 0; f < maxCards; f++)
1147
                cards[f] = 0;
1148
        }
1149
        if (msg.getVersion() >= 20080102)
1150
            msg.readInt32("hire expire date (?)");
1151
        ItemFlags flags;
1152
        if (msg.getVersion() >= 20120925)
1153
            flags.byte = msg.readUInt8("flags");
1154
        else
1155
            flags.byte = 0;
1156
1157
        mCartItems.push_back(Ea::InventoryItem(index,
1158
            itemId,
1159
            itemType,
1160
            cards,
1161
            nullptr,
1162
            amount,
1163
            0,
1164
            ItemColorManager::getColorFromCards(&cards[0]),
1165
            fromBool(flags.bits.isIdentified, Identified),
1166
            fromBool(flags.bits.isDamaged, Damaged),
1167
            fromBool(flags.bits.isFavorite, Favorite),
1168
            Equipm_false));
1169
    }
1170
    BLOCK_END("InventoryRecv::processPlayerCartItems")
1171
}
1172
1173
void InventoryRecv::processPlayerCartRemove(Net::MessageIn &msg)
1174
{
1175
    BLOCK_START("InventoryRecv::processPlayerCartRemove")
1176
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1177
    const int amount = msg.readInt32("amount");
1178
1179
    Inventory *const inv = PlayerInfo::getCartInventory();
1180
    if (inv == nullptr)
1181
        return;
1182
1183
    if (Item *const item = inv->getItem(index))
1184
    {
1185
        item->increaseQuantity(-amount);
1186
        if (item->getQuantity() == 0)
1187
            inv->removeItemAt(index);
1188
    }
1189
    BLOCK_END("InventoryRecv::processPlayerCartRemove")
1190
}
1191
1192
void InventoryRecv::processPlayerIdentifyList(Net::MessageIn &msg)
1193
{
1194
    UNIMPLEMENTEDPACKET;
1195
1196
    menu = MenuType::Identify;
1197
    const int count = msg.readInt16("len") - 4;
1198
    for (int f = 0; f < count; f ++)
1199
        msg.readInt16("inv index");
1200
}
1201
1202
void InventoryRecv::processPlayerIdentified(Net::MessageIn &msg)
1203
{
1204
    UNIMPLEMENTEDPACKET;
1205
1206
    msg.readInt16("inv index");
1207
    msg.readUInt8("flag");
1208
}
1209
1210
void InventoryRecv::processPlayerRefine(Net::MessageIn &msg)
1211
{
1212
    const int flag = msg.readInt16("flag");
1213
    const int index = msg.readInt16("inv index") - INVENTORY_OFFSET;
1214
    msg.readInt16("refine");
1215
    const Inventory *const inv = PlayerInfo::getInventory();
1216
    const Item *item = nullptr;
1217
    int notifyType;
1218
    std::string itemName;
1219
    if (inv != nullptr)
1220
        item = inv->getItem(index);
1221
    if (item != nullptr)
1222
    {
1223
        itemName = item->getName();
1224
    }
1225
    else
1226
    {
1227
        // TRANSLATORS: unknown item
1228
        itemName = _("Unknown item");
1229
    }
1230
    switch (flag)
1231
    {
1232
        case 0:
1233
            notifyType = NotifyTypes::REFINE_SUCCESS;
1234
            break;
1235
        case 1:
1236
            notifyType = NotifyTypes::REFINE_FAILURE;
1237
            break;
1238
        case 2:
1239
            notifyType = NotifyTypes::REFINE_DOWNGRADE;
1240
            break;
1241
        default:
1242
            UNIMPLEMENTEDPACKETFIELD(flag);
1243
            notifyType = NotifyTypes::REFINE_UNKNOWN;
1244
            break;
1245
    }
1246
    NotifyManager::notify(notifyType, itemName);
1247
}
1248
1249
void InventoryRecv::processPlayerRepairList(Net::MessageIn &msg)
1250
{
1251
    UNIMPLEMENTEDPACKET;
1252
1253
    const int count = (msg.readInt16("len") - 4) / 13;
1254
    for (int f = 0; f < count; f ++)
1255
    {
1256
        msg.readInt16("index");
1257
        msg.readInt16("item id");
1258
        msg.readUInt8("refine");
1259
        for (int d = 0; d < maxCards; d ++)
1260
            msg.readUInt16("card");
1261
    }
1262
    menu = MenuType::RepairWespon;
1263
}
1264
1265
void InventoryRecv::processPlayerRepairEffect(Net::MessageIn &msg)
1266
{
1267
    UNIMPLEMENTEDPACKET;
1268
1269
    msg.readInt16("item index");
1270
    msg.readUInt8("flag");
1271
}
1272
1273
void InventoryRecv::processPlayerRefineList(Net::MessageIn &msg)
1274
{
1275
    UNIMPLEMENTEDPACKET;
1276
1277
    const int count = (msg.readInt16("len") - 4) / 13;
1278
1279
    for (int f = 0; f < count; f ++)
1280
    {
1281
        msg.readInt16("item index");
1282
        msg.readInt16("item id");
1283
        msg.readUInt8("refine");
1284
        for (int d = 0; d < maxCards; d ++)
1285
            msg.readUInt16("card");
1286
    }
1287
    menu = MenuType::WeaponeRefine;
1288
}
1289
1290
void InventoryRecv::processPlayerStoragePassword(Net::MessageIn &msg)
1291
{
1292
    UNIMPLEMENTEDPACKET;
1293
1294
    msg.readInt16("info");
1295
}
1296
1297
void InventoryRecv::processPlayerStoragePasswordResult(Net::MessageIn &msg)
1298
{
1299
    UNIMPLEMENTEDPACKET;
1300
1301
    msg.readInt16("result");
1302
    msg.readInt16("error count");
1303
}
1304
1305
void InventoryRecv::processPlayerCookingList(Net::MessageIn &msg)
1306
{
1307
    UNIMPLEMENTEDPACKET;
1308
1309
    const int count = (msg.readInt16("len") - 6) / 2;
1310
    msg.readInt16("list type");
1311
    for (int f = 0; f < count; f ++)
1312
        msg.readInt16("item id");
1313
}
1314
1315
void InventoryRecv::processItemDamaged(Net::MessageIn &msg)
1316
{
1317
    UNIMPLEMENTEDPACKET;
1318
1319
    msg.readInt16("position");
1320
    msg.readBeingId("account id");
1321
}
1322
1323
void InventoryRecv::processFavoriteItem(Net::MessageIn &msg)
1324
{
1325
    UNIMPLEMENTEDPACKET;
1326
1327
    msg.readInt16("item index");
1328
    msg.readUInt8("favorite (0 - favorite)");
1329
}
1330
1331
void InventoryRecv::processCartAddError(Net::MessageIn &msg)
1332
{
1333
    switch (msg.readUInt8("flag"))
1334
    {
1335
        case 0:
1336
            NotifyManager::notify(NotifyTypes::CART_ADD_WEIGHT_ERROR);
1337
            break;
1338
        case 1:
1339
            NotifyManager::notify(NotifyTypes::CART_ADD_COUNT_ERROR);
1340
            break;
1341
        default:
1342
            break;
1343
    }
1344
}
1345
1346
void InventoryRecv::processBindItem(Net::MessageIn &msg)
1347
{
1348
    const int index = msg.readInt16("item index") - INVENTORY_OFFSET;
1349
    const Inventory *const inv = PlayerInfo::getInventory();
1350
    if (inv != nullptr)
1351
    {
1352
        std::string itemName;
1353
        const Item *const item = inv->getItem(index);
1354
        if (item != nullptr)
1355
        {
1356
            itemName = item->getName();
1357
        }
1358
        else
1359
        {
1360
            // TRANSLATORS: unknown item message
1361
            itemName = _("Unknown item");
1362
        }
1363
        NotifyManager::notify(NotifyTypes::BOUND_ITEM, itemName);
1364
    }
1365
}
1366
1367
void InventoryRecv::processPlayerInventoryRemove(Net::MessageIn &msg)
1368
{
1369
    BLOCK_START("InventoryRecv::processPlayerInventoryRemove")
1370
    Inventory *const inventory = localPlayer != nullptr
1371
        ? PlayerInfo::getInventory() : nullptr;
1372
1373
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1374
    const int amount = msg.readInt16("amount");
1375
    if (inventory != nullptr)
1376
    {
1377
        if (Item *const item = inventory->getItem(index))
1378
        {
1379
            if (amount != 0)
1380
            {
1381
                NotifyManager::notify(NotifyTypes::DELETE_ITEM_DROPPED,
1382
                    item->getName());
1383
            }
1384
            item->increaseQuantity(-amount);
1385
            if (item->getQuantity() == 0)
1386
                inventory->removeItemAt(index);
1387
            ArrowsListener::distributeEvent();
1388
        }
1389
    }
1390
    BLOCK_END("InventoryRecv::processPlayerInventoryRemove")
1391
}
1392
1393
void InventoryRecv::processSelectCart(Net::MessageIn &msg)
1394
{
1395
    UNIMPLEMENTEDPACKET;
1396
1397
    const int count = msg.readInt16("len") - 8;
1398
    msg.readBeingId("account id");
1399
    for (int f = 0; f < count; f ++)
1400
        msg.readUInt8("cart type");
1401
}
1402
1403
int InventoryRecv::getSlot(const int eAthenaSlot)
1404
{
1405
    if (eAthenaSlot == 0)
1406
        return EquipSlot::VECTOREND;
1407
1408
    if ((eAthenaSlot & 0x8000) != 0)
1409
        return inventoryHandler->getProjectileSlot();
1410
1411
    unsigned int mask = 1;
1412
    int position = 0;
1413
    while ((eAthenaSlot & mask) == 0u)
1414
    {
1415
        mask <<= 1;
1416
        position++;
1417
    }
1418
    if (position >= EquipSlot::VECTOREND)
1419
        return EquipSlot::VECTOREND;
1420
    return CAST_S32(EQUIP_POINTS[position]);
1421
}
1422
1423
void InventoryRecv::processMergeItem(Net::MessageIn &msg)
1424
{
1425
    UNIMPLEMENTEDPACKET;
1426
1427
    const int count = (msg.readInt16("len") - 4) / 2;
1428
    for (int f = 0; f < count; f ++)
1429
        msg.readInt16("inv index");
1430
}
1431
1432
void InventoryRecv::processMergeItemResponse(Net::MessageIn &msg)
1433
{
1434
    UNIMPLEMENTEDPACKET;
1435
1436
    msg.readInt16("inv index");
1437
    msg.readInt16("amount");
1438
    msg.readUInt8("result");
1439
}
1440
1441

6
}  // namespace EAthena