GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/inventoryrecv.cpp Lines: 1 203 0.5 %
Date: 2017-11-29 Branches: 0 125 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-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/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::mInventoryItems.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::mInventoryItems.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
    }
374
    BLOCK_END("InventoryRecv::processPlayerInventory")
375
}
376
377
void InventoryRecv::processPlayerEquip(Net::MessageIn &msg)
378
{
379
    BLOCK_START("InventoryRecv::processPlayerEquip")
380
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
381
    const int equipType = msg.readInt16("equip type");
382
    const uint8_t flag = msg.readUInt8("flag");
383
384
    if (flag == 0u)
385
    {
386
        NotifyManager::notify(NotifyTypes::EQUIP_FAILED);
387
    }
388
    else
389
    {
390
        Ea::InventoryRecv::mEquips.setEquipment(
391
            InventoryRecv::getSlot(equipType),
392
            index);
393
    }
394
    BLOCK_END("InventoryRecv::processPlayerEquip")
395
}
396
397
void InventoryRecv::processPlayerUnEquip(Net::MessageIn &msg)
398
{
399
    BLOCK_START("InventoryRecv::processPlayerUnEquip")
400
    msg.readInt16("index");
401
    const int equipType = msg.readInt16("equip type");
402
    const uint8_t flag = msg.readUInt8("flag");
403
404
    if (flag != 0u)
405
    {
406
        Ea::InventoryRecv::mEquips.setEquipment(
407
            InventoryRecv::getSlot(equipType),
408
            -1);
409
    }
410
    if ((equipType & 0x8000) != 0)
411
        ArrowsListener::distributeEvent();
412
    BLOCK_END("InventoryRecv::processPlayerUnEquip")
413
}
414
415
void InventoryRecv::processPlayerStorageEquip(Net::MessageIn &msg)
416
{
417
    BLOCK_START("InventoryRecv::processPlayerStorageEquip")
418
    msg.readInt16("len");
419
    const int number = (msg.getLength() - 4) / 20;
420
421
    for (int loop = 0; loop < number; loop++)
422
    {
423
        int cards[maxCards];
424
        const int index = msg.readInt16("index") - STORAGE_OFFSET;
425
        const int itemId = msg.readInt16("item id");
426
        const ItemTypeT itemType = static_cast<ItemTypeT>(
427
            msg.readUInt8("item type"));
428
        const uint8_t identified = msg.readUInt8("identified");
429
        const int amount = 1;
430
        msg.readInt16("equip point?");
431
        msg.readInt16("another equip point?");
432
        msg.readUInt8("attribute (broken)");
433
        const uint8_t refine = msg.readUInt8("refine");
434
        for (int i = 0; i < maxCards; i++)
435
            cards[i] = msg.readUInt16("card");
436
437
        if (Ea::InventoryRecv::mDebugInventory)
438
        {
439
            logger->log("Index: %d, ID: %d, Type: %d, Identified: %u, "
440
                "Qty: %d, Cards: %d, %d, %d, %d, Refine: %u",
441
                index, itemId, CAST_S32(itemType),
442
                CAST_U32(identified), amount,
443
                cards[0], cards[1], cards[2], cards[3],
444
                CAST_U32(refine));
445
        }
446
447
        Ea::InventoryRecv::mInventoryItems.push_back(Ea::InventoryItem(
448
            index,
449
            itemId,
450
            itemType,
451
            cards,
452
            nullptr,
453
            amount,
454
            refine,
455
            ItemColor_one,
456
            fromBool(identified, Identified),
457
            Damaged_false,
458
            Favorite_false,
459
            Equipm_false));
460
    }
461
    BLOCK_END("InventoryRecv::processPlayerStorageEquip")
462
}
463
464
void InventoryRecv::processPlayerStorageAdd(Net::MessageIn &msg)
465
{
466
    BLOCK_START("InventoryRecv::processPlayerStorageAdd")
467
    // Move an item into storage
468
    const int index = msg.readInt16("index") - STORAGE_OFFSET;
469
    const int amount = msg.readInt32("amount");
470
    const int itemId = msg.readInt16("item id");
471
    const unsigned char identified = msg.readUInt8("identified");
472
    msg.readUInt8("attribute");
473
    const uint8_t refine = msg.readUInt8("refine");
474
    int cards[maxCards];
475
    for (int f = 0; f < maxCards; f++)
476
        cards[f] = msg.readUInt16("card");
477
478
    if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
479
    {
480
        item->setId(itemId, ItemColor_one);
481
        item->increaseQuantity(amount);
482
    }
483
    else
484
    {
485
        if (Ea::InventoryRecv::mStorage != nullptr)
486
        {
487
            Ea::InventoryRecv::mStorage->setItem(index,
488
                itemId,
489
                ItemType::Unknown,
490
                amount,
491
                refine,
492
                ItemColor_one,
493
                fromBool(identified, Identified),
494
                Damaged_false,
495
                Favorite_false,
496
                Equipm_false,
497
                Equipped_false);
498
            Ea::InventoryRecv::mStorage->setCards(index, cards, maxCards);
499
        }
500
    }
501
    BLOCK_END("InventoryRecv::processPlayerStorageAdd")
502
}
503
504
void InventoryRecv::processPlayerStorageRemove(Net::MessageIn &msg)
505
{
506
    BLOCK_START("InventoryRecv::processPlayerStorageRemove")
507
    // Move an item out of storage
508
    const int index = msg.readInt16("index") - STORAGE_OFFSET;
509
    const int amount = msg.readInt32("amount");
510
    if (Ea::InventoryRecv::mStorage != nullptr)
511
    {
512
        if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
513
        {
514
            item->increaseQuantity(-amount);
515
            if (item->getQuantity() == 0)
516
                Ea::InventoryRecv::mStorage->removeItemAt(index);
517
        }
518
    }
519
    BLOCK_END("InventoryRecv::processPlayerStorageRemove")
520
}
521
522
void InventoryRecv::processPlayerInventoryRemove(Net::MessageIn &msg)
523
{
524
    BLOCK_START("InventoryRecv::processPlayerInventoryRemove")
525
    Inventory *const inventory = localPlayer != nullptr
526
        ? PlayerInfo::getInventory() : nullptr;
527
528
    const int index = msg.readInt16("index") - INVENTORY_OFFSET;
529
    const int amount = msg.readInt16("amount");
530
    if (inventory != nullptr)
531
    {
532
        if (Item *const item = inventory->getItem(index))
533
        {
534
            item->increaseQuantity(-amount);
535
            if (item->getQuantity() == 0)
536
                inventory->removeItemAt(index);
537
            ArrowsListener::distributeEvent();
538
        }
539
    }
540
    BLOCK_END("InventoryRecv::processPlayerInventoryRemove")
541
}
542
543
int InventoryRecv::getSlot(const int eAthenaSlot)
544
{
545
    if (eAthenaSlot == 0)
546
        return EquipSlot::VECTOREND;
547
548
    if ((eAthenaSlot & 0x8000) != 0)
549
        return inventoryHandler->getProjectileSlot();
550
551
    unsigned int mask = 1;
552
    int position = 0;
553
    while ((eAthenaSlot & mask) == 0u)
554
    {
555
        mask <<= 1;
556
        position++;
557
    }
558
    if (position >= EquipSlot::VECTOREND)
559
        return EquipSlot::VECTOREND;
560
    return CAST_S32(EQUIP_POINTS[position]);
561
}
562
563
4
}  // namespace TmwAthena