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-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/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 bool packets_zero;
52 extern int itemIdLen;
53 
54 namespace EAthena
55 {
56 
58  Ea::NpcHandler()
59 {
60  npcHandler = this;
61 }
62 
64 {
65  npcHandler = nullptr;
66 }
67 
68 void NpcHandler::talk(const Being *const being) const
69 {
70  if (being == nullptr)
71  return;
73  outMsg.writeBeingId(being->getId(), "npc id");
74  outMsg.writeInt8(0, "unused");
76 }
77 
78 void NpcHandler::nextDialog(const BeingId npcId) const
79 {
81  outMsg.writeBeingId(npcId, "npc id");
82 }
83 
85 {
87  outMsg.writeBeingId(npcId, "npc id");
88 
89  const NpcDialogs::iterator it = NpcDialog::mNpcDialogs.find(npcId);
90  if (it != NpcDialog::mNpcDialogs.end())
91  {
92  NpcDialog *const dialog = (*it).second;
93  if (dialog != nullptr)
94  dialog->close();
95  if (dialog == Ea::NpcRecv::mDialog)
96  Ea::NpcRecv::mDialog = nullptr;
97  NpcDialog::mNpcDialogs.erase(it);
98  }
99 }
100 
102  const unsigned char value) const
103 {
105  outMsg.writeBeingId(npcId, "npc id");
106  outMsg.writeInt8(value, "value");
107 }
108 
110  const int value) const
111 {
113  outMsg.writeBeingId(npcId, "npc id");
114  outMsg.writeInt32(value, "value");
115 }
116 
118  const std::string &value) const
119 {
121  if (packetVersion >= 20151029)
122  {
123  outMsg.writeInt16(CAST_S16(value.length() + 8), "len");
124  outMsg.writeBeingId(npcId, "npc id");
125  outMsg.writeString(value, CAST_S32(value.length()), "value");
126  }
127  else
128  {
129  outMsg.writeInt16(CAST_S16(value.length() + 9), "len");
130  outMsg.writeBeingId(npcId, "npc id");
131  outMsg.writeString(value, CAST_S32(value.length()), "value");
132  outMsg.writeInt8(0, "null byte");
133  }
134 }
135 
136 void NpcHandler::buy(const Being *const being) const
137 {
138  if (being == nullptr)
139  return;
141  outMsg.writeBeingId(being->getId(), "npc id");
142  outMsg.writeInt8(0, "action");
144 }
145 
146 void NpcHandler::buy(const BeingId beingId) const
147 {
149  outMsg.writeBeingId(beingId, "npc id");
150  outMsg.writeInt8(0, "action");
152 }
153 
154 void NpcHandler::sell(const BeingId beingId) const
155 {
157  outMsg.writeBeingId(beingId, "npc id");
158  outMsg.writeInt8(1, "action");
159 }
160 
162  const int itemId,
163  const ItemColor color A_UNUSED,
164  const int amount) const
165 {
167  outMsg.writeInt16(8, "len");
168  outMsg.writeInt16(CAST_S16(amount), "amount");
169  outMsg.writeItemId(itemId, "item id");
170 }
171 
172 void NpcHandler::buyItems(STD_VECTOR<ShopItem*> &items) const
173 {
174  int cnt = 0;
175  const int pairSize = 2 + itemIdLen;
176 
177  FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
178  {
179  ShopItem *const item = *it;
180  const int usedQuantity = item->getUsedQuantity();
181  const ItemTypeT type = item->getType();
182  if (usedQuantity == 0)
183  continue;
184  if (type == ItemType::Weapon ||
185  type == ItemType::Armor ||
186  type == ItemType::PetEgg ||
187  type == ItemType::PetArmor)
188  {
189  cnt += item->getUsedQuantity();
190  }
191  else
192  {
193  cnt ++;
194  }
195  }
196 
197  if (cnt > 100)
198  return;
199 
201  outMsg.writeInt16(CAST_S16(4 + pairSize * cnt), "len");
202  FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
203  {
204  ShopItem *const item = *it;
205  const int usedQuantity = item->getUsedQuantity();
206  if (usedQuantity == 0)
207  continue;
208  item->increaseUsedQuantity(-usedQuantity);
209  item->update();
210  const ItemTypeT type = item->getType();
211  if (type == ItemType::Weapon ||
212  type == ItemType::Armor ||
213  type == ItemType::PetEgg ||
214  type == ItemType::PetArmor)
215  {
216  for (int f = 0; f < usedQuantity; f ++)
217  {
218  outMsg.writeInt16(CAST_S16(1), "amount");
219  outMsg.writeItemId(item->getId(),
220  "item id");
221  }
222  }
223  else
224  {
225  outMsg.writeInt16(CAST_S16(usedQuantity), "amount");
226  outMsg.writeItemId(item->getId(), "item id");
227  }
228  }
229 }
230 
232  const int itemId, const int amount) const
233 {
235  outMsg.writeInt16(8, "len");
236  outMsg.writeInt16(CAST_S16(itemId + INVENTORY_OFFSET),
237  "item index");
238  outMsg.writeInt16(CAST_S16(amount), "amount");
239 }
240 
241 void NpcHandler::sellItems(STD_VECTOR<ShopItem*> &items) const
242 {
243  const int pairSize = 4;
244  int cnt = 0;
245 
246  FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
247  {
248  ShopItem *const item = *it;
249  const int usedQuantity = item->getUsedQuantity();
250  if (usedQuantity == 0)
251  continue;
252  cnt ++;
253  }
254 
256  outMsg.writeInt16(CAST_S16(4 + pairSize * cnt), "len");
257  FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, items)
258  {
259  ShopItem *const item = *it;
260  const int usedQuantity = item->getUsedQuantity();
261  if (usedQuantity == 0)
262  continue;
263  item->increaseUsedQuantity(-usedQuantity);
264  item->update();
265  outMsg.writeInt16(CAST_S16(
267  "item index");
268  outMsg.writeInt16(CAST_S16(usedQuantity), "amount");
269  }
270 }
271 
273 {
275 }
276 
277 void NpcHandler::produceMix(const int nameId,
278  const int materialId1,
279  const int materialId2,
280  const int materialId3) const
281 {
283  outMsg.writeItemId(nameId, "item id");
284  outMsg.writeItemId(materialId1, "material 1");
285  outMsg.writeItemId(materialId2, "material 2");
286  outMsg.writeItemId(materialId3, "material 3");
287 }
288 
290  const int nameId) const
291 {
293  outMsg.writeInt16(CAST_S16(type), "type");
294  outMsg.writeItemId(nameId, "item id");
295 }
296 
297 void NpcHandler::repair(const int index) const
298 {
300  outMsg.writeInt16(CAST_S16(index), "index");
301  // unused fields.
302  outMsg.writeItemId(0, "item id");
303  outMsg.writeInt8(0, "refine");
304  for (int f = 0; f < maxCards; f ++)
305  outMsg.writeItemId(0, "card");
306 }
307 
308 void NpcHandler::refine(const int index) const
309 {
311  outMsg.writeInt32(index, "index");
312 }
313 
314 void NpcHandler::identify(const int index) const
315 {
317  outMsg.writeInt16(CAST_S16(index), "index");
318 }
319 
320 void NpcHandler::selectArrow(const int nameId) const
321 {
323  outMsg.writeItemId(nameId, "item id");
324 }
325 
326 void NpcHandler::selectAutoSpell(const int skillId) const
327 {
329  outMsg.writeInt32(CAST_S16(skillId), "skill id");
330 }
331 
333  const NpcActionT action)
334 {
335  const BeingId npcId = msg.readBeingId("npc id");
336 
337  const NpcDialogs::const_iterator diag = NpcDialog::mNpcDialogs.find(npcId);
338 
339  if (diag == NpcDialog::mNpcDialogs.end())
340  {
341  Ea::NpcRecv::mDialog = nullptr;
342  // Empty dialogs don't help
343  if (action == NpcAction::Close)
344  {
345  closeDialog(npcId);
346  return npcId;
347  }
348  else if (action == NpcAction::Next)
349  {
350  nextDialog(npcId);
351  return npcId;
352  }
353  else
354  {
357  if (localPlayer != nullptr)
358  localPlayer->stopWalking(false);
360  }
361  }
362  else
363  {
364  NpcDialog *const dialog = diag->second;
365  if (Ea::NpcRecv::mDialog != nullptr && Ea::NpcRecv::mDialog != dialog)
367  Ea::NpcRecv::mDialog = dialog;
368  if (Ea::NpcRecv::mDialog != nullptr)
370  }
371  return npcId;
372 }
373 
374 void NpcHandler::requestAirship(const std::string &mapName,
375  const int itemId) const
376 {
377  if (packetVersionRe < 20180321 &&
378  packetVersionMain < 20180620 &&
379  packets_zero == false)
380  {
381  return;
382  }
384  outMsg.writeString(mapName, 16, "map name");
385  outMsg.writeItemId(itemId, "item");
386 }
387 
388 } // 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:277
NpcAction ::T NpcActionT
Definition: npcaction.h:32
void cooking(const CookingTypeT type, const int nameId) const
Definition: npchandler.cpp:289
BeingId readBeingId(const char *const str)
Definition: messagein.cpp:223
void selectArrow(const int nameId) const
Definition: npchandler.cpp:320
int CMSG_NPC_INT_RESPONSE
int CMSG_NPC_REFINE
void selectAutoSpell(const int skillId) const
Definition: npchandler.cpp:326
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:101
BeingId getNpc(Net::MessageIn &msg, const NpcActionT action)
Definition: npchandler.cpp:332
void sellItem(const BeingId beingId, const int itemId, const int amount) const
Definition: npchandler.cpp:231
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:374
int CMSG_NPC_REPAIR
void talk(const Being *const being) const
Definition: npchandler.cpp:68
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:161
int CMSG_NPC_TALK
#define CREATEWIDGETV(var, type,...)
Definition: createwidget.h:24
void repair(const int index) const
Definition: npchandler.cpp:297
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:901
void stringInput(const BeingId npcId, const std::string &value) const
Definition: npchandler.cpp:117
int packetVersionRe
Definition: client.cpp:126
void buy(const Being *const being) const
Definition: npchandler.cpp:136
#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:314
LocalPlayer * localPlayer
void refine(const int index) const
Definition: npchandler.cpp:308
int CMSG_NPC_SELECT_ARROW
void buyItems(std::vector< ShopItem *> &items) const
Definition: npchandler.cpp:172
void closeDialog(const BeingId npcId)
Definition: npchandler.cpp:84
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:159
int packetVersion
Definition: client.cpp:124
void integerInput(const BeingId npcId, const int value) const
Definition: npchandler.cpp:109
void sell(const BeingId beingId) const
Definition: npchandler.cpp:154
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:91
#define CAST_S16
Definition: cast.h:27
int CMSG_NPC_LIST_CHOICE
int CMSG_NPC_SELL_REQUEST
bool packets_zero
Definition: client.cpp:132
Definition: being.h:93
int CMSG_NPC_BUY_REQUEST
void nextDialog(const BeingId npcId) const
Definition: npchandler.cpp:78
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:272
void sellItems(std::vector< ShopItem *> &items) const
Definition: npchandler.cpp:241