GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/vendingrecv.cpp Lines: 1 139 0.7 %
Date: 2021-03-17 Branches: 2 89 2.2 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "net/eathena/vendingrecv.h"
23
24
#include "actormanager.h"
25
#include "itemcolormanager.h"
26
#include "notifymanager.h"
27
28
#include "const/resources/currency.h"
29
30
#include "being/localplayer.h"
31
#include "being/playerinfo.h"
32
33
#include "const/net/inventory.h"
34
35
#include "enums/resources/notifytypes.h"
36
37
#include "gui/windows/buydialog.h"
38
39
#include "gui/widgets/createwidget.h"
40
41
#include "listeners/vendingmodelistener.h"
42
#include "listeners/vendingslotslistener.h"
43
44
#include "net/messagein.h"
45
46
#include "resources/iteminfo.h"
47
48
#include "resources/db/unitsdb.h"
49
50
#include "resources/inventory/inventory.h"
51
52
#include "resources/item/itemoptionslist.h"
53
#include "resources/item/shopitem.h"
54
55
#include "utils/gettext.h"
56
#include "utils/stringutils.h"
57
58
#include "debug.h"
59
60
extern int packetVersion;
61
extern int serverVersion;
62
extern int itemIdLen;
63
64
namespace EAthena
65
{
66
67
namespace VendingRecv
68
{
69
    BuyDialog *mBuyDialog = nullptr;
70
}  // namespace VendingRecv
71
72
void VendingRecv::processOpenReq(Net::MessageIn &msg)
73
{
74
    VendingSlotsListener::distributeEvent(msg.readInt16("slots allowed"));
75
}
76
77
void VendingRecv::processShowBoard(Net::MessageIn &msg)
78
{
79
    if (actorManager == nullptr)
80
        return;
81
    const BeingId id = msg.readBeingId("owner id");
82
    Being *const dstBeing = actorManager->findBeing(id);
83
    if (dstBeing != nullptr)
84
    {
85
        dstBeing->setSellBoard(msg.readString(80, "shop name"));
86
    }
87
    else
88
    {
89
        msg.readString(80, "shop name");
90
    }
91
}
92
93
void VendingRecv::processHideBoard(Net::MessageIn &msg)
94
{
95
    if (actorManager == nullptr)
96
        return;
97
    const BeingId id = msg.readBeingId("owner id");
98
    Being *const dstBeing = actorManager->findBeing(id);
99
    if (dstBeing != nullptr)
100
        dstBeing->setSellBoard(std::string());
101
    if (dstBeing == localPlayer)
102
    {
103
        PlayerInfo::enableVending(false);
104
        VendingModeListener::distributeEvent(false);
105
    }
106
}
107
108
void VendingRecv::processItemsList(Net::MessageIn &msg)
109
{
110
    if (actorManager == nullptr)
111
        return;
112
    int packetLen = 22;
113
    if (msg.getVersion() >= 20160921)
114
        packetLen = 53;
115
    else if (msg.getVersion() >= 20150226)
116
        packetLen = 47;
117
    if (itemIdLen == 4)
118
        packetLen += 10;
119
    int offset = 8;
120
    if (msg.getVersion() >= 20100105)
121
        offset += 4;
122
123
    const int count = (msg.readInt16("len") - offset) / packetLen;
124
    const BeingId id = msg.readBeingId("id");
125
    const Being *const being = actorManager->findBeing(id);
126
    if (being == nullptr)
127
        return;
128
    int cards[maxCards];
129
    CREATEWIDGETV(mBuyDialog, BuyDialog, being, DEFAULT_CURRENCY);
130
    mBuyDialog->setMoney(PlayerInfo::getAttribute(Attributes::MONEY));
131
    if (msg.getVersion() >= 20100105)
132
        msg.readInt32("vender id");
133
    for (int f = 0; f < count; f ++)
134
    {
135
        const int value = msg.readInt32("price");
136
        const int amount = msg.readInt16("amount");
137
        const int index = msg.readInt16("inv index");
138
        const ItemTypeT type = static_cast<ItemTypeT>(
139
            msg.readUInt8("item type"));
140
        const int itemId = msg.readItemId("item id");
141
        msg.readUInt8("identify");
142
        msg.readUInt8("attribute");
143
        msg.readUInt8("refine");
144
        for (int d = 0; d < maxCards; d ++)
145
            cards[d] = msg.readItemId("card");
146
        ItemOptionsList *options = nullptr;
147
        if (msg.getVersion() >= 20150226)
148
        {
149
            options = new ItemOptionsList;
150
            for (int d = 0; d < 5; d ++)
151
            {
152
                const uint16_t idx = msg.readInt16("option index");
153
                const uint16_t val = msg.readInt16("option value");
154
                msg.readUInt8("option param");
155
                options->add(idx, val);
156
            }
157
        }
158
        if (msg.getVersion() >= 20160921)
159
        {
160
            msg.readInt32("equip type?");
161
            msg.readInt16("look");
162
        }
163
164
        const ItemColor color = ItemColorManager::getColorFromCards(&cards[0]);
165
        ShopItem *const item = mBuyDialog->addItem(itemId, type,
166
            color, amount, value);
167
        if (item != nullptr)
168
        {
169
            item->setInvIndex(index);
170
            item->setOptions(options);
171
        }
172
        delete options;
173
    }
174
    mBuyDialog->sort();
175
}
176
177
void VendingRecv::processBuyAck(Net::MessageIn &msg)
178
{
179
    msg.readInt16("inv index");
180
    msg.readInt16("amount");
181
    const int flag = msg.readUInt8("flag");
182
    switch (flag)
183
    {
184
        case 0:
185
            break;
186
        case 1:
187
            NotifyManager::notify(NotifyTypes::BUY_FAILED_NO_MONEY);
188
            break;
189
        case 2:
190
            NotifyManager::notify(NotifyTypes::BUY_FAILED_OVERWEIGHT);
191
            break;
192
        case 4:
193
            NotifyManager::notify(NotifyTypes::BUY_FAILED_TOO_MANY_ITEMS);
194
            break;
195
        case 5:
196
            NotifyManager::notify(NotifyTypes::BUY_TRADE_FAILED);
197
            break;
198
        case 6:  // +++ probably need show exact error messages?
199
        case 7:
200
            NotifyManager::notify(NotifyTypes::BUY_FAILED);
201
            break;
202
        default:
203
            NotifyManager::notify(NotifyTypes::BUY_FAILED);
204
            UNIMPLEMENTEDPACKETFIELD(flag);
205
            break;
206
    }
207
}
208
209
void VendingRecv::processOpen(Net::MessageIn &msg)
210
{
211
    int packetLen = 22;
212
    if (msg.getVersion() >= 20150226)
213
        packetLen += 25;
214
    if (itemIdLen == 4)
215
        packetLen += 10;
216
217
    const int count = (msg.readInt16("len") - 8) / packetLen;
218
    msg.readInt32("id");
219
    for (int f = 0; f < count; f ++)
220
    {
221
        msg.readInt32("price");
222
        msg.readInt16("inv index");
223
        msg.readInt16("amount");
224
        msg.readUInt8("item type");
225
        msg.readItemId("item id");
226
        msg.readUInt8("identify");
227
        msg.readUInt8("attribute");
228
        msg.readUInt8("refine");
229
        for (int d = 0; d < maxCards; d ++)
230
            msg.readItemId("card");
231
        if (msg.getVersion() >= 20150226)
232
        {
233
            for (int d = 0; d < 5; d ++)
234
            {
235
                msg.readInt16("option index");
236
                msg.readInt16("option value");
237
                msg.readUInt8("option param");
238
            }
239
        }
240
    }
241
    PlayerInfo::enableVending(true);
242
    VendingModeListener::distributeEvent(true);
243
}
244
245
void VendingRecv::processReport(Net::MessageIn &msg)
246
{
247
    const int index = msg.readInt16("inv index") - INVENTORY_OFFSET;
248
    const int amount = msg.readInt16("amount");
249
    int money = 0;
250
    if (msg.getVersion() >= 20141016)
251
    {
252
        msg.readInt32("char id");
253
        msg.readInt32("time");
254
        money = msg.readInt32("zeny");
255
    }
256
    const Inventory *const inventory = PlayerInfo::getCartInventory();
257
    if (inventory == nullptr)
258
        return;
259
    const Item *const item = inventory->getItem(index);
260
    if (item == nullptr)
261
        return;
262
263
    const ItemInfo &info = item->getInfo();
264
    std::string str;
265
    if (money != 0)
266
    {
267
        // TRANSLATORS: vending sold item message
268
        str = strprintf(_("Sold item %s amount %d. You got: %s"),
269
            info.getLink().c_str(),
270
            amount,
271
            UnitsDb::formatCurrency(money).c_str());
272
    }
273
    else
274
    {
275
        // TRANSLATORS: vending sold item message
276
        str = strprintf(_("Sold item %s amount %d"),
277
            info.getLink().c_str(),
278
            amount);
279
    }
280
    NotifyManager::notify(NotifyTypes::VENDING_SOLD_ITEM, str);
281
}
282
283
void VendingRecv::processOpenStatus(Net::MessageIn &msg)
284
{
285
    UNIMPLEMENTEDPACKET;
286
    msg.readUInt8("result");
287
}
288
289

3
}  // namespace EAthena