GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/npchandler.cpp Lines: 1 179 0.6 %
Date: 2018-05-23 22:10:27 Branches: 0 204 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-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/npchandler.h"
24
25
#include "being/localplayer.h"
26
27
#include "const/net/inventory.h"
28
29
#include "gui/windows/npcdialog.h"
30
31
#include "gui/widgets/createwidget.h"
32
33
#include "net/messagein.h"
34
35
#include "net/ea/npcrecv.h"
36
37
#include "net/eathena/messageout.h"
38
#include "net/eathena/npcrecv.h"
39
40
#include "net/eathena/protocolout.h"
41
42
#include "utils/foreach.h"
43
44
#include "resources/item/shopitem.h"
45
46
#include "debug.h"
47
48
extern int packetVersion;
49
extern int packetVersionRe;
50
51
namespace EAthena
52
{
53
54
NpcHandler::NpcHandler() :
55
    Ea::NpcHandler()
56
{
57
    npcHandler = this;
58
}
59
60
NpcHandler::~NpcHandler()
61
{
62
    npcHandler = nullptr;
63
}
64
65
void NpcHandler::talk(const Being *const being) const
66
{
67
    if (being == nullptr)
68
        return;
69
    createOutPacket(CMSG_NPC_TALK);
70
    outMsg.writeBeingId(being->getId(), "npc id");
71
    outMsg.writeInt8(0, "unused");
72
    EAthena::NpcRecv::mNpcTypeId = being->getSubType();
73
}
74
75
void NpcHandler::nextDialog(const BeingId npcId) const
76
{
77
    createOutPacket(CMSG_NPC_NEXT_REQUEST);
78
    outMsg.writeBeingId(npcId, "npc id");
79
}
80
81
void NpcHandler::closeDialog(const BeingId npcId)
82
{
83
    createOutPacket(CMSG_NPC_CLOSE);
84
    outMsg.writeBeingId(npcId, "npc id");
85
86
    const NpcDialogs::iterator it = NpcDialog::mNpcDialogs.find(npcId);
87
    if (it != NpcDialog::mNpcDialogs.end())
88
    {
89
        NpcDialog *const dialog = (*it).second;
90
        if (dialog != nullptr)
91
            dialog->close();
92
        if (dialog == Ea::NpcRecv::mDialog)
93
            Ea::NpcRecv::mDialog = nullptr;
94
        NpcDialog::mNpcDialogs.erase(it);
95
    }
96
}
97
98
void NpcHandler::listInput(const BeingId npcId,
99
                           const unsigned char value) const
100
{
101
    createOutPacket(CMSG_NPC_LIST_CHOICE);
102
    outMsg.writeBeingId(npcId, "npc id");
103
    outMsg.writeInt8(value, "value");
104
}
105
106
void NpcHandler::integerInput(const BeingId npcId,
107
                              const int value) const
108
{
109
    createOutPacket(CMSG_NPC_INT_RESPONSE);
110
    outMsg.writeBeingId(npcId, "npc id");
111
    outMsg.writeInt32(value, "value");
112
}
113
114
void NpcHandler::stringInput(const BeingId npcId,
115
                             const std::string &value) const
116
{
117
    createOutPacket(CMSG_NPC_STR_RESPONSE);
118
    if (packetVersion >= 20151029)
119
    {
120
        outMsg.writeInt16(CAST_S16(value.length() + 8), "len");
121
        outMsg.writeBeingId(npcId, "npc id");
122
        outMsg.writeString(value, CAST_S32(value.length()), "value");
123
    }
124
    else
125
    {
126
        outMsg.writeInt16(CAST_S16(value.length() + 9), "len");
127
        outMsg.writeBeingId(npcId, "npc id");
128
        outMsg.writeString(value, CAST_S32(value.length()), "value");
129
        outMsg.writeInt8(0, "null byte");
130
    }
131
}
132
133
void NpcHandler::buy(const Being *const being) const
134
{
135
    if (being == nullptr)
136
        return;
137
    createOutPacket(CMSG_NPC_BUY_SELL_REQUEST);
138
    outMsg.writeBeingId(being->getId(), "npc id");
139
    outMsg.writeInt8(0, "action");
140
    EAthena::NpcRecv::mNpcTypeId = being->getSubType();
141
}
142
143
void NpcHandler::buy(const BeingId beingId) const
144
{
145
    createOutPacket(CMSG_NPC_BUY_SELL_REQUEST);
146
    outMsg.writeBeingId(beingId, "npc id");
147
    outMsg.writeInt8(0, "action");
148
    EAthena::NpcRecv::mNpcTypeId = BeingTypeId_zero;
149
}
150
151
void NpcHandler::sell(const BeingId beingId) const
152
{
153
    createOutPacket(CMSG_NPC_BUY_SELL_REQUEST);
154
    outMsg.writeBeingId(beingId, "npc id");
155
    outMsg.writeInt8(1, "action");
156
}
157
158
void NpcHandler::buyItem(const BeingId beingId A_UNUSED,
159
                         const int itemId,
160
                         const ItemColor color A_UNUSED,
161
                         const int amount) const
162
{
163
    createOutPacket(CMSG_NPC_BUY_REQUEST);
164
    outMsg.writeInt16(8, "len");
165
    outMsg.writeInt16(CAST_S16(amount), "amount");
166
    outMsg.writeInt16(CAST_S16(itemId), "item id");
167
}
168
169
void NpcHandler::buyItems(STD_VECTOR<ShopItem*> &items) const
170
{
171
    int cnt = 0;
172
    const int pairSize = 4;
173
174
    FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
175
    {
176
        ShopItem *const item = *it;
177
        const int usedQuantity = item->getUsedQuantity();
178
        const ItemTypeT type = item->getType();
179
        if (usedQuantity == 0)
180
            continue;
181
        if (type == ItemType::Weapon ||
182
            type == ItemType::Armor ||
183
            type == ItemType::PetEgg ||
184
            type == ItemType::PetArmor)
185
        {
186
            cnt += item->getUsedQuantity();
187
        }
188
        else
189
        {
190
            cnt ++;
191
        }
192
    }
193
194
    if (cnt > 100)
195
        return;
196
197
    createOutPacket(CMSG_NPC_BUY_REQUEST);
198
    outMsg.writeInt16(CAST_S16(4 + pairSize * cnt), "len");
199
    FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
200
    {
201
        ShopItem *const item = *it;
202
        const int usedQuantity = item->getUsedQuantity();
203
        if (usedQuantity == 0)
204
            continue;
205
        item->increaseUsedQuantity(-usedQuantity);
206
        item->update();
207
        const ItemTypeT type = item->getType();
208
        if (type == ItemType::Weapon ||
209
            type == ItemType::Armor ||
210
            type == ItemType::PetEgg ||
211
            type == ItemType::PetArmor)
212
        {
213
            for (int f = 0; f < usedQuantity; f ++)
214
            {
215
                outMsg.writeInt16(CAST_S16(1), "amount");
216
                outMsg.writeInt16(CAST_S16(item->getId()),
217
                    "item id");
218
            }
219
        }
220
        else
221
        {
222
            outMsg.writeInt16(CAST_S16(usedQuantity), "amount");
223
            outMsg.writeInt16(CAST_S16(item->getId()), "item id");
224
        }
225
    }
226
}
227
228
void NpcHandler::sellItem(const BeingId beingId A_UNUSED,
229
                          const int itemId, const int amount) const
230
{
231
    createOutPacket(CMSG_NPC_SELL_REQUEST);
232
    outMsg.writeInt16(8, "len");
233
    outMsg.writeInt16(CAST_S16(itemId + INVENTORY_OFFSET),
234
        "item index");
235
    outMsg.writeInt16(CAST_S16(amount), "amount");
236
}
237
238
void NpcHandler::sellItems(STD_VECTOR<ShopItem*> &items) const
239
{
240
    const int pairSize = 4;
241
    int cnt = 0;
242
243
    FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
244
    {
245
        ShopItem *const item = *it;
246
        const int usedQuantity = item->getUsedQuantity();
247
        if (usedQuantity == 0)
248
            continue;
249
        cnt ++;
250
    }
251
252
    createOutPacket(CMSG_NPC_SELL_REQUEST);
253
    outMsg.writeInt16(CAST_S16(4 + pairSize * cnt), "len");
254
    FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
255
    {
256
        ShopItem *const item = *it;
257
        const int usedQuantity = item->getUsedQuantity();
258
        if (usedQuantity == 0)
259
            continue;
260
        item->increaseUsedQuantity(-usedQuantity);
261
        item->update();
262
        outMsg.writeInt16(CAST_S16(
263
            item->getCurrentInvIndex() + INVENTORY_OFFSET),
264
            "item index");
265
        outMsg.writeInt16(CAST_S16(usedQuantity), "amount");
266
    }
267
}
268
269
void NpcHandler::completeProgressBar() const
270
{
271
    createOutPacket(CMSG_NPC_COMPLETE_PROGRESS_BAR);
272
}
273
274
void NpcHandler::produceMix(const int nameId,
275
                            const int materialId1,
276
                            const int materialId2,
277
                            const int materialId3) const
278
{
279
    createOutPacket(CMSG_NPC_PRODUCE_MIX);
280
    outMsg.writeInt16(CAST_S16(nameId), "name id");
281
    outMsg.writeInt16(CAST_S16(materialId1), "material 1");
282
    outMsg.writeInt16(CAST_S16(materialId2), "material 2");
283
    outMsg.writeInt16(CAST_S16(materialId3), "material 3");
284
}
285
286
void NpcHandler::cooking(const CookingTypeT type,
287
                         const int nameId) const
288
{
289
    createOutPacket(CMSG_NPC_COOKING);
290
    outMsg.writeInt16(CAST_S16(type), "type");
291
    outMsg.writeInt16(CAST_S16(nameId), "name id");
292
}
293
294
void NpcHandler::repair(const int index) const
295
{
296
    createOutPacket(CMSG_NPC_REPAIR);
297
    outMsg.writeInt16(CAST_S16(index), "index");
298
}
299
300
void NpcHandler::refine(const int index) const
301
{
302
    createOutPacket(CMSG_NPC_REFINE);
303
    outMsg.writeInt32(index, "index");
304
}
305
306
void NpcHandler::identify(const int index) const
307
{
308
    createOutPacket(CMSG_NPC_IDENTIFY);
309
    outMsg.writeInt16(CAST_S16(index), "index");
310
}
311
312
void NpcHandler::selectArrow(const int nameId) const
313
{
314
    createOutPacket(CMSG_NPC_SELECT_ARROW);
315
    outMsg.writeInt16(CAST_S16(nameId), "name id");
316
}
317
318
void NpcHandler::selectAutoSpell(const int skillId) const
319
{
320
    createOutPacket(CMSG_NPC_SELECT_AUTO_SPELL);
321
    outMsg.writeInt32(CAST_S16(skillId), "skill id");
322
}
323
324
BeingId NpcHandler::getNpc(Net::MessageIn &msg,
325
                           const NpcActionT action)
326
{
327
    const BeingId npcId = msg.readBeingId("npc id");
328
329
    const NpcDialogs::const_iterator diag = NpcDialog::mNpcDialogs.find(npcId);
330
    Ea::NpcRecv::mDialog = nullptr;
331
332
    if (diag == NpcDialog::mNpcDialogs.end())
333
    {
334
        // Empty dialogs don't help
335
        if (action == NpcAction::Close)
336
        {
337
            closeDialog(npcId);
338
            return npcId;
339
        }
340
        else if (action == NpcAction::Next)
341
        {
342
            nextDialog(npcId);
343
            return npcId;
344
        }
345
        else
346
        {
347
            CREATEWIDGETV(Ea::NpcRecv::mDialog, NpcDialog, npcId);
348
            Ea::NpcRecv::mDialog->saveCamera();
349
            if (localPlayer != nullptr)
350
                localPlayer->stopWalking(false);
351
            NpcDialog::mNpcDialogs[npcId] = Ea::NpcRecv::mDialog;
352
        }
353
    }
354
    else
355
    {
356
        NpcDialog *const dialog = diag->second;
357
        if (Ea::NpcRecv::mDialog != nullptr && Ea::NpcRecv::mDialog != dialog)
358
            Ea::NpcRecv::mDialog->restoreCamera();
359
        Ea::NpcRecv::mDialog = dialog;
360
        if (Ea::NpcRecv::mDialog != nullptr)
361
            Ea::NpcRecv::mDialog->saveCamera();
362
    }
363
    return npcId;
364
}
365
366
void NpcHandler::requestAirship(const std::string &mapName,
367
                                const int itemId) const
368
{
369
    if (packetVersionRe < 20180321)
370
        return;
371
    createOutPacket(CMSG_PRIVATE_AIRSHIP_REQUEST);
372
    outMsg.writeString(mapName, 16, "map name");
373
    outMsg.writeInt16(CAST_S16(itemId), "item");
374
}
375
376
4
}  // namespace EAthena