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

3
}  // namespace EAthena