GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/inventoryrecv.cpp Lines: 1 223 0.4 %
Date: 2019-03-21 Branches: 0 139 0.0 %

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-2019  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/tmwa/inventoryrecv.h"
24
25
#include "notifymanager.h"
26
27
#include "being/localplayer.h"
28
29
#include "const/net/inventory.h"
30
31
#include "enums/equipslot.h"
32
33
#include "enums/resources/notifytypes.h"
34
35
#include "listeners/arrowslistener.h"
36
37
#include "net/inventoryhandler.h"
38
#include "net/messagein.h"
39
40
#include "net/ea/equipbackend.h"
41
#include "net/ea/inventoryrecv.h"
42
43
#include "debug.h"
44
45
namespace TmwAthena
46
{
47
48
namespace InventoryRecv
49
{
50
    const EquipSlot::Type EQUIP_POINTS[EquipSlot::VECTOREND] =
51
    {
52
        EquipSlot::LEGS_SLOT,               // Lower Headgear
53
        EquipSlot::FIGHT1_SLOT,             // Weapon
54
        EquipSlot::GLOVES_SLOT,             // Garment
55
        EquipSlot::RING2_SLOT,              // Accessory 1
56
        EquipSlot::RING1_SLOT,              // Armor
57
        EquipSlot::FIGHT2_SLOT,             // Shield
58
        EquipSlot::FEET_SLOT,               // Footgear
59
        EquipSlot::NECK_SLOT,               // Accessory 2
60
        EquipSlot::HEAD_SLOT,               // Upper Headgear
61
        EquipSlot::TORSO_SLOT,              // Middle Headgear
62
        EquipSlot::EVOL_RING1_SLOT,         // Costume Top Headgear
63
        EquipSlot::EVOL_RING2_SLOT,         // Costume Mid Headgear
64
        EquipSlot::PROJECTILE_SLOT,         // Costume Low Headgear
65
        EquipSlot::COSTUME_ROBE_SLOT,       // Costume Garment/Robe
66
        EquipSlot::MISSING1_SLOT,           // Missing slot 1
67
        EquipSlot::MISSING2_SLOT,           // Missing slot 2
68
        EquipSlot::SHADOW_ARMOR_SLOT,       // Shadow Armor
69
        EquipSlot::SHADOW_WEAPON_SLOT,      // Shadow Weapon
70
        EquipSlot::SHADOW_SHIELD_SLOT,      // Shadow Shield
71
        EquipSlot::SHADOW_SHOES_SLOT,       // Shadow Shoes
72
        EquipSlot::SHADOW_ACCESSORY2_SLOT,  // Shadow Accessory 2
73
        EquipSlot::SHADOW_ACCESSORY1_SLOT,  // Shadow Accessory 1
74
    };
75
}  // namespace InventoryRecv
76
77
void InventoryRecv::processPlayerEquipment(Net::MessageIn &msg)
78
{
79
    BLOCK_START("InventoryRecv::processPlayerEquipment")
80
    Inventory *const inventory = localPlayer != nullptr
81
        ? PlayerInfo::getInventory() : nullptr;
82
83
    msg.readInt16("len");
84
    Equipment *const equipment = PlayerInfo::getEquipment();
85
    if ((equipment != nullptr) && (equipment->getBackend() == nullptr))
86
    {   // look like SMSG_PLAYER_INVENTORY was not received
87
        Ea::InventoryRecv::mEquips.clear();
88
        equipment->setBackend(&Ea::InventoryRecv::mEquips);
89
    }
90
    const int number = (msg.getLength() - 4) / 20;
91
92
    for (int loop = 0; loop < number; loop++)
93
    {
94
        const int index = msg.readInt16("index") - INVENTORY_OFFSET;
95
        const int itemId = msg.readInt16("item id");
96
        const ItemTypeT itemType = static_cast<ItemTypeT>(
97
            msg.readUInt8("item type"));
98
        const uint8_t identified = msg.readUInt8("identify");
99
        msg.readInt16("equip type?");
100
        const int equipType = msg.readInt16("equip type");
101
        msg.readUInt8("attribute");
102
        const uint8_t refine = msg.readUInt8("refine");
103
        int cards[maxCards];
104
        for (int f = 0; f < maxCards; f++)
105
            cards[f] = msg.readUInt16("card");
106
107
        if (Ea::InventoryRecv::mDebugInventory)
108
        {
109
            logger->log("Index: %d, ID: %d, Type: %d, Identified: %d",
110
                        index, itemId, CAST_S32(itemType), identified);
111
        }
112
113
        if (inventory != nullptr)
114
        {
115
            inventory->setItem(index,
116
                itemId,
117
                itemType,
118
                1,
119
                refine,
120
                ItemColor_one,
121
                fromBool(identified, Identified),
122
                Damaged_false,
123
                Favorite_false,
124
                Equipm_true,
125
                Equipped_false);
126
            inventory->setCards(index, cards, maxCards);
127
        }
128
129
        if (equipType != 0)
130
        {
131
            Ea::InventoryRecv::mEquips.setEquipment(
132
                InventoryRecv::getSlot(equipType),
133
                index);
134
        }
135
    }
136
    BLOCK_END("InventoryRecv::processPlayerEquipment")
137
}
138
139
void InventoryRecv::processPlayerInventoryAdd(Net::MessageIn &msg)
140
{
141
    BLOCK_START("InventoryRecv::processPlayerInventoryAdd")
142
    Inventory *const inventory = localPlayer != nullptr
143
        ? PlayerInfo::getInventory() : nullptr;
144
145
    if ((PlayerInfo::getEquipment() != nullptr)
146
        && (PlayerInfo::getEquipment()->getBackend() == nullptr))
147
    {   // look like SMSG_PLAYER_INVENTORY was not received
148
        Ea::InventoryRecv::mEquips.clear();
149
        PlayerInfo::getEquipment()->setBackend(&Ea::InventoryRecv::mEquips);
150
    }
151
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
152
    int amount = msg.readInt16("amount");
153
    const int itemId = msg.readInt16("item id");
154
    const uint8_t identified = msg.readUInt8("identified");
155
    msg.readUInt8("attribute");
156
    const uint8_t refine = msg.readUInt8("refine");
157
    int cards[maxCards];
158
    for (int f = 0; f < maxCards; f++)
159
        cards[f] = msg.readUInt16("card");
160
    const int equipType = msg.readInt16("equip type");
161
    const ItemTypeT type = static_cast<ItemTypeT>(msg.readUInt8("item type"));
162
    const unsigned char err = msg.readUInt8("status");
163
    BeingId floorId;
164
    if (Ea::InventoryRecv::mSentPickups.empty())
165
    {
166
        floorId = BeingId_zero;
167
    }
168
    else
169
    {
170
        floorId = Ea::InventoryRecv::mSentPickups.front();
171
        Ea::InventoryRecv::mSentPickups.pop();
172
    }
173
174
    if (err != 0U)
175
    {
176
        PickupT pickup;
177
        switch (err)
178
        {
179
            case 1:
180
                pickup = Pickup::BAD_ITEM;
181
                break;
182
            case 2:
183
                pickup = Pickup::TOO_HEAVY;
184
                break;
185
            case 3:
186
                pickup = Pickup::TOO_FAR;
187
                break;
188
            case 4:
189
                pickup = Pickup::INV_FULL;
190
                break;
191
            case 5:
192
                pickup = Pickup::STACK_FULL;
193
                break;
194
            case 6:
195
                pickup = Pickup::DROP_STEAL;
196
                break;
197
            default:
198
                pickup = Pickup::UNKNOWN;
199
                UNIMPLEMENTEDPACKETFIELD(err);
200
                break;
201
        }
202
        if (localPlayer != nullptr)
203
        {
204
            if (itemId == 0)
205
            {
206
                localPlayer->pickedUp(ItemDB::getEmpty(),
207
                    0,
208
                    ItemColor_one,
209
                    floorId,
210
                    pickup);
211
            }
212
            else
213
            {
214
                localPlayer->pickedUp(ItemDB::get(itemId),
215
                    0,
216
                    ItemColor_one,
217
                    floorId,
218
                    pickup);
219
            }
220
        }
221
    }
222
    else
223
    {
224
        if (localPlayer != nullptr)
225
        {
226
            if (itemId == 0)
227
            {
228
                localPlayer->pickedUp(ItemDB::getEmpty(),
229
                    amount,
230
                    ItemColor_one,
231
                    floorId,
232
                    Pickup::OKAY);
233
            }
234
            else
235
            {
236
                localPlayer->pickedUp(ItemDB::get(itemId),
237
                    amount,
238
                    ItemColor_one,
239
                    floorId,
240
                    Pickup::OKAY);
241
            }
242
        }
243
244
        if (inventory != nullptr)
245
        {
246
            const Item *const item = inventory->getItem(index);
247
248
            if ((item != nullptr) && item->getId() == itemId)
249
                amount += item->getQuantity();
250
251
            inventory->setItem(index,
252
                itemId,
253
                type,
254
                amount,
255
                refine,
256
                ItemColor_one,
257
                fromBool(identified, Identified),
258
                Damaged_false,
259
                Favorite_false,
260
                fromBool(equipType, Equipm),
261
                Equipped_false);
262
            inventory->setCards(index, cards, maxCards);
263
        }
264
        ArrowsListener::distributeEvent();
265
    }
266
    BLOCK_END("InventoryRecv::processPlayerInventoryAdd")
267
}
268
269
void InventoryRecv::processPlayerInventory(Net::MessageIn &msg)
270
{
271
    BLOCK_START("InventoryRecv::processPlayerInventory")
272
    Inventory *const inventory = localPlayer != nullptr
273
        ? PlayerInfo::getInventory() : nullptr;
274
275
    if (PlayerInfo::getEquipment() != nullptr)
276
    {
277
        // Clear inventory - this will be a complete refresh
278
        Ea::InventoryRecv::mEquips.clear();
279
        PlayerInfo::getEquipment()->setBackend(&Ea::InventoryRecv::mEquips);
280
    }
281
282
    if (inventory != nullptr)
283
        inventory->clear();
284
285
    msg.readInt16("len");
286
    const int number = (msg.getLength() - 4) / 18;
287
288
    for (int loop = 0; loop < number; loop++)
289
    {
290
        int cards[maxCards];
291
        const int index = msg.readInt16("index") - INVENTORY_OFFSET;
292
        const int itemId = msg.readInt16("item id");
293
        const ItemTypeT itemType = static_cast<ItemTypeT>(
294
            msg.readUInt8("item type"));
295
        const uint8_t identified = msg.readUInt8("identified");
296
        const int amount = msg.readInt16("amount");
297
        const int arrow = msg.readInt16("arrow");
298
        for (int i = 0; i < maxCards; i++)
299
            cards[i] = msg.readUInt16("card");
300
301
        if (Ea::InventoryRecv::mDebugInventory)
302
        {
303
            logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, "
304
                        "Qty: %d, Cards: %d, %d, %d, %d",
305
                        index, itemId, CAST_S32(itemType), identified, amount,
306
                        cards[0], cards[1], cards[2], cards[3]);
307
        }
308
309
        // Trick because arrows are not considered equipment
310
        const bool isEquipment = (arrow & 0x8000) != 0;
311
312
        if (inventory != nullptr)
313
        {
314
            inventory->setItem(index,
315
                itemId,
316
                itemType,
317
                amount,
318
                0,
319
                ItemColor_one,
320
                fromBool(identified, Identified),
321
                Damaged_false,
322
                Favorite_false,
323
                fromBool(isEquipment, Equipm),
324
                Equipped_false);
325
            inventory->setCards(index, cards, maxCards);
326
        }
327
    }
328
    BLOCK_END("InventoryRecv::processPlayerInventory")
329
}
330
331
void InventoryRecv::processPlayerStorage(Net::MessageIn &msg)
332
{
333
    BLOCK_START("InventoryRecv::processPlayerInventory")
334
    Ea::InventoryRecv::mStorageItems.clear();
335
336
    msg.readInt16("len");
337
    const int number = (msg.getLength() - 4) / 18;
338
339
    for (int loop = 0; loop < number; loop++)
340
    {
341
        int cards[maxCards];
342
        const int index = msg.readInt16("index") - STORAGE_OFFSET;
343
        const int itemId = msg.readInt16("item id");
344
        const ItemTypeT itemType = static_cast<ItemTypeT>(
345
            msg.readUInt8("item type"));
346
        const uint8_t identified = msg.readUInt8("identified");
347
        const int amount = msg.readInt16("amount");
348
        msg.readInt16("arrow");
349
        for (int i = 0; i < maxCards; i++)
350
            cards[i] = msg.readUInt16("card");
351
352
        if (Ea::InventoryRecv::mDebugInventory)
353
        {
354
            logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, "
355
                        "Qty: %d, Cards: %d, %d, %d, %d",
356
                        index, itemId, CAST_S32(itemType), identified, amount,
357
                        cards[0], cards[1], cards[2], cards[3]);
358
        }
359
360
        Ea::InventoryRecv::mStorageItems.push_back(Ea::InventoryItem(
361
            index,
362
            itemId,
363
            itemType,
364
            cards,
365
            nullptr,
366
            amount,
367
            0,
368
            ItemColor_one,
369
            fromBool(identified, Identified),
370
            Damaged_false,
371
            Favorite_false,
372
            Equipm_false,
373
            -1));
374
    }
375
    BLOCK_END("InventoryRecv::processPlayerInventory")
376
}
377
378
void InventoryRecv::processPlayerEquip(Net::MessageIn &msg)
379
{
380
    BLOCK_START("InventoryRecv::processPlayerEquip")
381
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
382
    const int equipType = msg.readInt16("equip type");
383
    const uint8_t flag = msg.readUInt8("flag");
384
385
    if (flag == 0U)
386
    {
387
        NotifyManager::notify(NotifyTypes::EQUIP_FAILED);
388
    }
389
    else
390
    {
391
        Ea::InventoryRecv::mEquips.setEquipment(
392
            InventoryRecv::getSlot(equipType),
393
            index);
394
    }
395
    BLOCK_END("InventoryRecv::processPlayerEquip")
396
}
397
398
void InventoryRecv::processPlayerUnEquip(Net::MessageIn &msg)
399
{
400
    BLOCK_START("InventoryRecv::processPlayerUnEquip")
401
    msg.readInt16("index");
402
    const int equipType = msg.readInt16("equip type");
403
    const uint8_t flag = msg.readUInt8("flag");
404
405
    if (flag != 0U)
406
    {
407
        Ea::InventoryRecv::mEquips.setEquipment(
408
            InventoryRecv::getSlot(equipType),
409
            -1);
410
    }
411
    if ((equipType & 0x8000) != 0)
412
        ArrowsListener::distributeEvent();
413
    BLOCK_END("InventoryRecv::processPlayerUnEquip")
414
}
415
416
void InventoryRecv::processPlayerStorageEquip(Net::MessageIn &msg)
417
{
418
    BLOCK_START("InventoryRecv::processPlayerStorageEquip")
419
    msg.readInt16("len");
420
    const int number = (msg.getLength() - 4) / 20;
421
422
    for (int loop = 0; loop < number; loop++)
423
    {
424
        int cards[maxCards];
425
        const int index = msg.readInt16("index") - STORAGE_OFFSET;
426
        const int itemId = msg.readInt16("item id");
427
        const ItemTypeT itemType = static_cast<ItemTypeT>(
428
            msg.readUInt8("item type"));
429
        const uint8_t identified = msg.readUInt8("identified");
430
        const int amount = 1;
431
        msg.readInt16("equip point?");
432
        msg.readInt16("another equip point?");
433
        msg.readUInt8("attribute (broken)");
434
        const uint8_t refine = msg.readUInt8("refine");
435
        for (int i = 0; i < maxCards; i++)
436
            cards[i] = msg.readUInt16("card");
437
438
        if (Ea::InventoryRecv::mDebugInventory)
439
        {
440
            logger->log("Index: %d, ID: %d, Type: %d, Identified: %u, "
441
                "Qty: %d, Cards: %d, %d, %d, %d, Refine: %u",
442
                index, itemId, CAST_S32(itemType),
443
                CAST_U32(identified), amount,
444
                cards[0], cards[1], cards[2], cards[3],
445
                CAST_U32(refine));
446
        }
447
448
        Ea::InventoryRecv::mStorageItems.push_back(Ea::InventoryItem(
449
            index,
450
            itemId,
451
            itemType,
452
            cards,
453
            nullptr,
454
            amount,
455
            refine,
456
            ItemColor_one,
457
            fromBool(identified, Identified),
458
            Damaged_false,
459
            Favorite_false,
460
            Equipm_false,
461
            -1));
462
    }
463
    BLOCK_END("InventoryRecv::processPlayerStorageEquip")
464
}
465
466
void InventoryRecv::processPlayerStorageAdd(Net::MessageIn &msg)
467
{
468
    BLOCK_START("InventoryRecv::processPlayerStorageAdd")
469
    // Move an item into storage
470
    const int index = msg.readInt16("index") - STORAGE_OFFSET;
471
    const int amount = msg.readInt32("amount");
472
    const int itemId = msg.readInt16("item id");
473
    const unsigned char identified = msg.readUInt8("identified");
474
    msg.readUInt8("attribute");
475
    const uint8_t refine = msg.readUInt8("refine");
476
    int cards[maxCards];
477
    for (int f = 0; f < maxCards; f++)
478
        cards[f] = msg.readUInt16("card");
479
480
    if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
481
    {
482
        item->setId(itemId, ItemColor_one);
483
        item->increaseQuantity(amount);
484
    }
485
    else
486
    {
487
        if (Ea::InventoryRecv::mStorage != nullptr)
488
        {
489
            Ea::InventoryRecv::mStorage->setItem(index,
490
                itemId,
491
                ItemType::Unknown,
492
                amount,
493
                refine,
494
                ItemColor_one,
495
                fromBool(identified, Identified),
496
                Damaged_false,
497
                Favorite_false,
498
                Equipm_false,
499
                Equipped_false);
500
            Ea::InventoryRecv::mStorage->setCards(index, cards, maxCards);
501
        }
502
    }
503
    BLOCK_END("InventoryRecv::processPlayerStorageAdd")
504
}
505
506
void InventoryRecv::processPlayerStorageRemove(Net::MessageIn &msg)
507
{
508
    BLOCK_START("InventoryRecv::processPlayerStorageRemove")
509
    // Move an item out of storage
510
    const int index = msg.readInt16("index") - STORAGE_OFFSET;
511
    const int amount = msg.readInt32("amount");
512
    if (Ea::InventoryRecv::mStorage != nullptr)
513
    {
514
        if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
515
        {
516
            item->increaseQuantity(-amount);
517
            if (item->getQuantity() == 0)
518
                Ea::InventoryRecv::mStorage->removeItemAt(index);
519
        }
520
    }
521
    BLOCK_END("InventoryRecv::processPlayerStorageRemove")
522
}
523
524
void InventoryRecv::processPlayerInventoryRemove(Net::MessageIn &msg)
525
{
526
    BLOCK_START("InventoryRecv::processPlayerInventoryRemove")
527
    Inventory *const inventory = localPlayer != nullptr
528
        ? PlayerInfo::getInventory() : nullptr;
529
530
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
531
    const int amount = msg.readInt16("amount");
532
    if (inventory != nullptr)
533
    {
534
        if (Item *const item = inventory->getItem(index))
535
        {
536
            item->increaseQuantity(-amount);
537
            if (item->getQuantity() == 0)
538
                inventory->removeItemAt(index);
539
            ArrowsListener::distributeEvent();
540
        }
541
    }
542
    BLOCK_END("InventoryRecv::processPlayerInventoryRemove")
543
}
544
545
int InventoryRecv::getSlot(const int eAthenaSlot)
546
{
547
    if (eAthenaSlot == 0)
548
        return EquipSlot::VECTOREND;
549
550
    if ((eAthenaSlot & 0x8000) != 0)
551
        return inventoryHandler->getProjectileSlot();
552
553
    unsigned int mask = 1;
554
    int position = 0;
555
    while ((eAthenaSlot & mask) == 0U)
556
    {
557
        mask <<= 1;
558
        position++;
559
    }
560
    if (position >= EquipSlot::VECTOREND)
561
        return EquipSlot::VECTOREND;
562
    return CAST_S32(EQUIP_POINTS[position]);
563
}
564
565
void InventoryRecv::processPlayerInventoryUse(Net::MessageIn &msg)
566
{
567
    BLOCK_START("InventoryRecv::processPlayerInventoryUse")
568
    Inventory *const inventory = localPlayer != nullptr
569
        ? PlayerInfo::getInventory() : nullptr;
570
571
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
572
    msg.readItemId("item id");
573
    msg.readInt32("id?");
574
    const int amount = msg.readInt16("amount");
575
    msg.readUInt8("type");
576
577
    if (inventory != nullptr)
578
    {
579
        if (Item *const item = inventory->getItem(index))
580
        {
581
            if (amount != 0)
582
                item->setQuantity(amount);
583
            else
584
                inventory->removeItemAt(index);
585
        }
586
    }
587
    BLOCK_END("InventoryRecv::processPlayerInventoryUse")
588
}
589
590
2
}  // namespace TmwAthena