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