Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / interface_v3 / inventory_manager.cpp
blob0da63f3b681344bae9340807118942d887c3c6be
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2015-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
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 Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "stdpch.h"
24 #include "nel/misc/cdb_leaf.h"
25 #include "nel/misc/cdb_branch.h"
26 #include "inventory_manager.h"
27 #include "interface_manager.h"
28 #include "bot_chat_page_trade.h"
29 #include "bot_chat_page_all.h"
30 #include "nel/gui/group_container.h"
31 #include "nel/gui/group_menu.h"
32 #include "nel/misc/cdb_leaf.h"
33 #include "nel/misc/cdb_branch.h"
34 #include "list_sheet_base.h"
35 #include "../net_manager.h"
36 #include "../user_entity.h"
37 #include "../global.h"
39 #include "nel/misc/algo.h"
41 // TODO: remove this ugly dependence
42 #include "sphrase_manager.h"
44 // For handlers
45 #include "nel/gui/action_handler.h"
46 #include "nel/gui/group_editbox.h"
47 #include "dbctrl_sheet.h"
49 #include "../sheet_manager.h"
50 #include "game_share/slot_equipment.h"
51 #include "game_share/animal_status.h"
52 #include "game_share/bot_chat_types.h"
54 #include "../client_cfg.h"
56 #include "../misc.h"
58 #ifdef DEBUG_NEW
59 #define new DEBUG_NEW
60 #endif
62 using namespace std;
63 using namespace NLMISC;
65 extern TSessionId CharacterHomeSessionId;
67 extern NLMISC::CLog g_log;
68 // Context help
69 extern void contextHelp (const std::string &help);
71 CTempInvManager *CTempInvManager::_Instance = NULL;
72 CInventoryManager *CInventoryManager::_Instance = NULL;
74 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListSheetBag, std::string, "list_sheet_bag");
75 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupIconListBag, std::string, "list_icon_bag");
76 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListSheetFilterCLMSlot, std::string, "list_sheet_filter_clm_slot");
77 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListSheetFilterExchangeable, std::string, "list_sheet_filter_exchangeable");
79 // ***************************************************************************
80 // db path for all the inventories (without the SERVER: prefix)
81 const std::string CInventoryManager::InventoryDBs[]=
83 "INVENTORY:BAG",
84 // MAX_INVENTORY_ANIMAL
85 "INVENTORY:PACK_ANIMAL0",
86 "INVENTORY:PACK_ANIMAL1",
87 "INVENTORY:PACK_ANIMAL2",
88 "INVENTORY:PACK_ANIMAL3",
89 "INVENTORY:PACK_ANIMAL4",
90 "INVENTORY:PACK_ANIMAL5",
91 "INVENTORY:PACK_ANIMAL6",
92 "INVENTORY:TEMP",
93 "EXCHANGE:GIVE",
94 "EXCHANGE:RECEIVE",
95 "TRADING",
96 "INVENTORY:SHARE",
97 "GUILD:INVENTORY",
98 "INVENTORY:ROOM",
101 static void dummyCheck()
103 // if this raise, correct the 2 tables above and below
104 nlctassert(MAX_INVENTORY_ANIMAL==7);
107 const uint CInventoryManager::InventoryIndexes[]=
109 INVENTORIES::bag,
110 // MAX_INVENTORY_ANIMAL
111 INVENTORIES::pet_animal1,
112 INVENTORIES::pet_animal2,
113 INVENTORIES::pet_animal3,
114 INVENTORIES::pet_animal4,
115 INVENTORIES::pet_animal5,
116 INVENTORIES::pet_animal6,
117 INVENTORIES::pet_animal7,
118 INVENTORIES::temporary,
119 INVENTORIES::exchange,
120 INVENTORIES::exchange_proposition,
121 INVENTORIES::trading,
122 INVENTORIES::reward_sharing,
123 INVENTORIES::guild,
124 INVENTORIES::player_room,
127 const uint CInventoryManager::NumInventories= sizeof(CInventoryManager::InventoryDBs)/sizeof(CInventoryManager::InventoryDBs[0]);
130 // *************************************************************************************************
131 CItemImage::CItemImage()
133 Sheet = NULL;
134 Quality = NULL;
135 Quantity = NULL;
136 CreateTime = NULL;
137 Serial = NULL;
138 UserColor = NULL;
139 Price = NULL;
140 Weight= NULL;
141 NameId= NULL;
142 InfoVersion= NULL;
145 // *************************************************************************************************
146 void CItemImage::build(CCDBNodeBranch *branch)
148 if (!branch) return;
149 Sheet = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SHEET"), false));
150 Quality = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUALITY"), false));
151 Quantity = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUANTITY"), false));
152 CreateTime = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("CREATE_TIME"), false));
153 Serial = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SERIAL"), false));
154 UserColor = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("USER_COLOR"), false));
155 Price = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("PRICE"), false));
156 Weight = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("WEIGHT"), false));
157 NameId = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("NAMEID"), false));
158 InfoVersion= dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("INFO_VERSION"), false));
159 ResaleFlag = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false));
161 // Should always have at least those one:(ie all but Price)
162 nlassert(Sheet && Quality && Quantity && CreateTime && Serial && UserColor && Weight && NameId && InfoVersion);
165 uint64 CItemImage::getItemId() const
167 return ((uint64)getSerial() << 32) | getCreateTime();
170 // *************************************************************************************************
171 void CItemInfoCache::load(const std::string &filename)
175 CIFile f;
176 if (f.open(filename))
178 serial(f);
180 } catch(...)
184 void CItemInfoCache::save(const std::string &filename)
188 COFile f;
189 if (f.open(filename))
191 serial(f);
193 }catch(...)
197 void CItemInfoCache::serial(NLMISC::IStream &s)
199 s.serialCheck(NELID("METI"));
200 uint ver = 1;
201 s.serialVersion(ver);
203 uint8 byte = 1;
204 if (s.isReading())
206 _ItemInfoCacheMap.clear();
207 while(true)
209 uint64 key;
211 s.serial(byte);
212 if (byte == 0)
214 break;
216 s.serial(key);
217 s.serial(_ItemInfoCacheMap[key].CacheCycle);
218 _ItemInfoCacheMap[key].serial(s);
220 // these are not used in item info cache
221 _ItemInfoCacheMap[key].InfoVersionFromMsg = 0;
222 _ItemInfoCacheMap[key].InfoVersionFromSlot = 0;
223 _ItemInfoCacheMap[key].InfoVersionSlotServerWaiting = 0;
226 else
228 byte = 1;
229 TItemInfoCacheMap::iterator it = _ItemInfoCacheMap.begin();
230 while (it != _ItemInfoCacheMap.end())
232 // purge item from cache if not encountered in X save
233 if (it->second.CacheCycle < 10000)
235 // 'record exists' byte
236 s.serial(byte);
238 // item id (serial << 32 | createTime)
239 uint64 key = it->first;
240 s.serial(key);
242 uint32 cycle = it->second.CacheCycle+1;
243 s.serial(cycle);
245 // item info
246 it->second.serial(s);
249 ++it;
251 // eof of records byte
252 byte = 0;
253 s.serial(byte);
257 const CClientItemInfo *CItemInfoCache::getItemInfo(uint32 serial, uint32 createTime) const
259 if (serial > 0 && createTime > 0)
261 uint64 itemId = ((uint64)serial << 32) | createTime;
262 return getItemInfo(itemId);
265 return NULL;
268 const CClientItemInfo *CItemInfoCache::getItemInfo(uint64 itemId) const
270 if (itemId > 0)
272 TItemInfoCacheMap::const_iterator it = _ItemInfoCacheMap.find(itemId);
273 if (it != _ItemInfoCacheMap.end())
274 return &(it->second);
277 return NULL;
280 void CItemInfoCache::readFromImpulse(uint64 itemId, CItemInfos itemInfo)
282 if (itemId > 0)
284 _ItemInfoCacheMap[itemId].readFromImpulse(itemInfo);
285 _ItemInfoCacheMap[itemId].CacheCycle = 0;
289 void CItemInfoCache::debugItemInfoCache() const
291 nlinfo("ItemInfoCache: %d entries", _ItemInfoCacheMap.size());
292 uint count = 0;
293 for (TItemInfoCacheMap::const_iterator it = _ItemInfoCacheMap.begin(); it != _ItemInfoCacheMap.end(); ++it)
295 uint32 serial = (it->first >> 32) & 0xFFFFFFFF;
296 uint32 created = it->first & 0xFFFFFFFF;
297 nlinfo("[%-4d] cacheCycle:%d, serial:%d, createTime:%d", count++, it->second.CacheCycle, serial, created);
299 CInterfaceManager *pIM= CInterfaceManager::getInstance();
300 pIM->displaySystemInfo(toString("ItemInfoCache: %d entries written to client.log", _ItemInfoCacheMap.size()));
303 // *************************************************************************************************
304 // CInventoryManager
305 // *************************************************************************************************
307 // *************************************************************************************************
308 CInventoryManager::CInventoryManager()
310 Money = NULL;
311 ServerMoney = NULL;
312 uint i;
313 for (i = 0; i < MAX_HANDINV_ENTRIES; ++i)
315 Hands[i] = ServerHands[i] = 0;
316 UIHands[i] = NULL;
319 for (i = 0; i < MAX_EQUIPINV_ENTRIES; ++i)
321 Equip[i] = ServerEquip[i] = 0;
322 UIEquip[i] = NULL;
323 UIEquip2[i] = NULL;
326 for (i = 0; i < MAX_BAGINV_ENTRIES; i++)
328 BagItemEquipped[i]= false;
331 _ItemInfoCacheFilename = toString("save/item_infos_%d.cache", CharacterHomeSessionId.asInt());
332 _ItemInfoCache.load(_ItemInfoCacheFilename);
334 nlctassert(NumInventories== sizeof(InventoryIndexes)/sizeof(InventoryIndexes[0]));
337 // ***************************************************************************
338 CInventoryManager::~CInventoryManager()
340 _ItemInfoCache.save(_ItemInfoCacheFilename);
343 // *************************************************************************************************
344 CInventoryManager *CInventoryManager::getInstance()
346 if( !_Instance )
347 _Instance = new CInventoryManager();
348 return _Instance;
351 // ***************************************************************************
352 void CInventoryManager::releaseInstance()
354 if( _Instance )
355 delete _Instance;
356 _Instance = NULL;
359 // *************************************************************************************************
360 CItemImage &CInventoryManager::getBagItem(uint index)
362 nlassert(index < MAX_BAGINV_ENTRIES);
363 return Bag[index];
366 // *************************************************************************************************
367 CItemImage &CInventoryManager::getTempItem(uint index)
369 nlassert(index < MAX_TEMPINV_ENTRIES);
370 return TempInv[index];
373 // *************************************************************************************************
374 CItemImage *CInventoryManager::getHandItem(uint index)
376 nlassert(index < MAX_HANDINV_ENTRIES);
377 if (Hands[index] != 0)
378 return &Bag[Hands[index]-1];
379 else
380 return NULL;
383 // *************************************************************************************************
384 CItemImage *CInventoryManager::getEquipItem(uint index)
386 nlassert(index < MAX_EQUIPINV_ENTRIES);
387 if (Equip[index] != 0)
388 return &Bag[Equip[index]];
389 else
390 return NULL;
393 // *************************************************************************************************
394 CDBCtrlSheet *CInventoryManager::getHandSheet(uint index)
396 return UIHands[index];
399 // *************************************************************************************************
400 CDBCtrlSheet *CInventoryManager::getEquipSheet(uint index)
402 return UIEquip[index];
406 // *************************************************************************************************
407 CItemImage &CInventoryManager::getServerBagItem(uint index)
409 nlassert(index < MAX_BAGINV_ENTRIES);
410 return ServerBag[index];
412 const CItemImage &CInventoryManager::getServerBagItem(uint index) const
414 nlassert(index < MAX_BAGINV_ENTRIES);
415 return ServerBag[index];
418 // *************************************************************************************************
419 CItemImage &CInventoryManager::getServerTempItem(uint index)
421 nlassert(index < MAX_TEMPINV_ENTRIES);
422 return ServerTempInv[index];
424 const CItemImage &CInventoryManager::getServerTempItem(uint index) const
426 nlassert(index < MAX_TEMPINV_ENTRIES);
427 return ServerTempInv[index];
430 // *************************************************************************************************
431 CItemImage *CInventoryManager::getServerHandItem(uint index)
433 nlassert(index < MAX_HANDINV_ENTRIES);
434 if (ServerHands[index] != 0)
435 return &ServerBag[ServerHands[index]];
436 else
437 return NULL;
440 // *************************************************************************************************
441 CItemImage *CInventoryManager::getServerEquipItem(uint index)
443 nlassert(index < MAX_EQUIPINV_ENTRIES);
444 if (ServerEquip[index] != 0)
445 return &ServerBag[ServerEquip[index]];
446 else
447 return NULL;
450 // *************************************************************************************************
451 uint64 CInventoryManager::getMoney() const
453 return Money ? Money->getValue64() : 0;
456 // *************************************************************************************************
457 void CInventoryManager::setMoney(uint64 value)
459 if (Money) Money->setValue64(value);
462 // *************************************************************************************************
463 uint64 CInventoryManager::getServerMoney() const
465 return ServerMoney ? ServerMoney->getValue64() : 0;
468 // *************************************************************************************************
469 void CInventoryManager::setServerMoney(uint64 value)
471 if (ServerMoney) ServerMoney->setValue64(value);
473 // *************************************************************************************************
474 void CInventoryManager::init()
476 CInterfaceManager *im = CInterfaceManager::getInstance();
477 // LOCAL DB
478 initItemArray(LOCAL_INVENTORY ":BAG", Bag, MAX_BAGINV_ENTRIES);
479 initItemArray(LOCAL_INVENTORY ":TEMP", TempInv, MAX_TEMPINV_ENTRIES);
480 Money = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":MONEY");
481 initIndirection (LOCAL_INVENTORY ":HAND:", Hands, MAX_HANDINV_ENTRIES, true);
482 initIndirection (LOCAL_INVENTORY ":EQUIP:", Equip, MAX_EQUIPINV_ENTRIES, true);
483 // Init observers for auto equipment
485 for (uint i = 0; i < MAX_BAGINV_ENTRIES; ++i)
487 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(i) + ":SHEET");
488 ICDBNode::CTextId textId;
489 pNL->addObserver(&_DBBagObs, textId);
492 // Init Animals
493 for(uint i=0;i<MAX_INVENTORY_ANIMAL;i++)
494 initItemArray(toString(LOCAL_INVENTORY ":PACK_ANIMAL%d", i), PAInv[i], MAX_ANIMALINV_ENTRIES);
497 // SERVER DB
498 initItemArray(SERVER_INVENTORY ":BAG", ServerBag, MAX_BAGINV_ENTRIES);
499 initItemArray(SERVER_INVENTORY ":TEMP", ServerTempInv, MAX_TEMPINV_ENTRIES);
500 ServerMoney = NLGUI::CDBManager::getInstance()->getDbProp(SERVER_INVENTORY ":MONEY");
501 // Init Animals
502 for(uint i=0;i<MAX_INVENTORY_ANIMAL;i++)
503 initItemArray(toString(SERVER_INVENTORY ":PACK_ANIMAL%d", i), ServerPAInv[i], MAX_ANIMALINV_ENTRIES);
505 // Drag'n'Drop
506 DNDCurrentItem = NULL;
507 DNDFrom = Nowhere;
508 // Initialize interface part
509 UIHands[0] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_RIGHT));
510 UIHands[1] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_LEFT));
512 UIEquip[SLOT_EQUIPMENT::HEADDRESS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_HEADDRESS));
513 UIEquip[SLOT_EQUIPMENT::EARL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_EARING_LEFT));
514 UIEquip[SLOT_EQUIPMENT::EARR] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_EARING_RIGHT));
515 UIEquip[SLOT_EQUIPMENT::NECKLACE] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_NECK));
516 UIEquip[SLOT_EQUIPMENT::WRISTL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_BRACELET_LEFT));
517 UIEquip[SLOT_EQUIPMENT::WRISTR] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_BRACELET_RIGHT));
518 UIEquip[SLOT_EQUIPMENT::FINGERL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_RING_LEFT));
519 UIEquip[SLOT_EQUIPMENT::FINGERR] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_RING_RIGHT));
520 UIEquip[SLOT_EQUIPMENT::ANKLEL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_ANKLET_LEFT));
521 UIEquip[SLOT_EQUIPMENT::ANKLER] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWEL_ANKLET_RIGHT));
523 UIEquip[SLOT_EQUIPMENT::HEAD] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMOR_HEAD));
524 UIEquip[SLOT_EQUIPMENT::CHEST] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMOR_CHEST));
525 UIEquip[SLOT_EQUIPMENT::ARMS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMOR_ARMS));
526 UIEquip[SLOT_EQUIPMENT::FEET] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMOR_FEET));
527 UIEquip[SLOT_EQUIPMENT::LEGS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMOR_LEGS));
528 UIEquip[SLOT_EQUIPMENT::HANDS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMOR_HANDS));
530 UIEquip2[SLOT_EQUIPMENT::HEADDRESS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_HEADDRESS));
531 UIEquip2[SLOT_EQUIPMENT::EARL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_EARING_LEFT));
532 UIEquip2[SLOT_EQUIPMENT::EARR] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_EARING_RIGHT));
533 UIEquip2[SLOT_EQUIPMENT::NECKLACE] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_NECK));
534 UIEquip2[SLOT_EQUIPMENT::WRISTL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_BRACELET_LEFT));
535 UIEquip2[SLOT_EQUIPMENT::WRISTR] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_BRACELET_RIGHT));
536 UIEquip2[SLOT_EQUIPMENT::FINGERL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_RING_LEFT));
537 UIEquip2[SLOT_EQUIPMENT::FINGERR] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_RING_RIGHT));
538 UIEquip2[SLOT_EQUIPMENT::ANKLEL] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_ANKLET_LEFT));
539 UIEquip2[SLOT_EQUIPMENT::ANKLER] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_JEWL2_ANKLET_RIGHT));
541 UIEquip2[SLOT_EQUIPMENT::HEAD] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMR2_HEAD));
542 UIEquip2[SLOT_EQUIPMENT::CHEST] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMR2_CHEST));
543 UIEquip2[SLOT_EQUIPMENT::ARMS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMR2_ARMS));
544 UIEquip2[SLOT_EQUIPMENT::FEET] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMR2_FEET));
545 UIEquip2[SLOT_EQUIPMENT::LEGS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMR2_LEGS));
546 UIEquip2[SLOT_EQUIPMENT::HANDS] = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_ARMR2_HANDS));
549 // Init ItemInfoObservers
551 CCDBNodeLeaf *nodeTS;
553 nodeTS= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:TRADING:SESSION", false);
554 if( nodeTS )
556 ICDBNode::CTextId textId;
557 nodeTS->addObserver(&_DBTradeInfoObs, textId);
560 // Init All Version obs
561 for(uint i=0;i<NumInventories;i++)
563 // Don't do it for TRADING DB
564 if(InventoryIndexes[i]!=INVENTORIES::trading)
566 // since different size per inventory, stop when node not found....
567 for(uint j=0;;j++)
569 CCDBNodeLeaf *nodeIV= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:" + InventoryDBs[i] + ":" + toString(j) + ":INFO_VERSION", false);
570 CCDBNodeLeaf *nodeSH= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:" + InventoryDBs[i] + ":" + toString(j) + ":SHEET", false);
571 if( nodeIV && nodeSH )
573 ICDBNode::CTextId textIdIV, textIdSH;
574 nodeIV->addObserver(&_DBInfoSlotVersionObs, textIdIV);
575 nodeSH->addObserver(&_DBItemSheetObs, textIdSH);
576 // if current value!=0, simulate a receive item info obs
577 if(nodeIV->getValue32())
579 onReceiveItemInfoSlotVersion(nodeIV);
582 else
583 // stop here for this inventory
584 break;
591 // *************************************************************************************************
592 void CInventoryManager::initItemArray(const std::string &dbBranchName, CItemImage *dest, uint numItems)
594 nlassert(dest);
595 CInterfaceManager *im = CInterfaceManager::getInstance();
596 CCDBNodeBranch *branch = NLGUI::CDBManager::getInstance()->getDbBranch(dbBranchName);
597 if (!branch)
599 nlwarning("Can't init inventory image from branch %s.", dbBranchName.c_str());
600 return;
602 for(uint k = 0; k < numItems; ++k)
604 CCDBNodeBranch *itemBranch = dynamic_cast<CCDBNodeBranch *>(branch->getNode((uint16) k));
605 if (!itemBranch)
607 nlwarning("Can't retrieve item %d of branch %s", (int) k, dbBranchName.c_str());
609 else
611 dest[k].build(itemBranch);
616 // ***************************************************************************
617 void CInventoryManager::initIndirection(const std::string &dbbranch, sint32 *indices, sint32 nbIndex, bool putObs)
619 CInterfaceManager *im = CInterfaceManager::getInstance();
620 for (uint i = 0 ; i < (uint)nbIndex; ++i)
622 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(dbbranch + toString(i) + ":INDEX_IN_BAG");
623 if (putObs)
625 ICDBNode::CTextId textId;
626 pNL->addObserver(&_DBEquipObs, textId);
628 if (pNL != NULL)
629 indices[i] = pNL->getValue32();
633 // ***************************************************************************
634 void CInventoryManager::beginDrag(CDBCtrlSheet *pCS, TFrom From)
636 DNDCurrentItem = pCS;
637 if (pCS)
638 CDBCtrlSheet::setCurrSelSheet(pCS);
639 DNDFrom = From;
642 // ***************************************************************************
643 void CInventoryManager::endDrag()
645 DNDCurrentItem = NULL;
646 DNDFrom = Nowhere;
649 // ***************************************************************************
650 // Used for interface objects which are reference in bag (the getSheet() returns INDEX_IN_BAG)
651 std::string CInventoryManager::getDBIndexPath(CDBCtrlSheet *pCS)
653 string sTmp;
654 uint i;
655 for (i = 0; i < MAX_HANDINV_ENTRIES; ++i)
657 if (UIHands[i] == pCS)
659 return string(LOCAL_INVENTORY) + ":HAND:" + toString(i);
663 for (i = 0; i < MAX_EQUIPINV_ENTRIES; ++i)
665 if (UIEquip[i] == pCS)
667 return string(LOCAL_INVENTORY) + ":EQUIP:" + toString(i);
669 if (UIEquip2[i] == pCS)
671 return string(LOCAL_INVENTORY) + ":EQUIP:" + toString(i);
674 return "";
677 // ***************************************************************************
678 bool CInventoryManager::is2HandItem(uint32 sheetID)
680 bool result = false;
681 CEntitySheet *sheet= SheetMngr.get(CSheetId(sheetID));
682 if(sheet && sheet->type()== CEntitySheet::ITEM)
684 CItemSheet *item= (CItemSheet*)sheet;
685 if( item->hasSlot(SLOTTYPE::TWO_HANDS) || item->hasSlot(SLOTTYPE::RIGHT_HAND_EXCLUSIVE) )
686 result = true;
688 return result;
691 // ***************************************************************************
692 bool CInventoryManager::isMeleeWeaponItem(uint32 sheetID)
694 bool result = false;
695 CEntitySheet *sheet= SheetMngr.get(CSheetId(sheetID));
696 if(sheet && sheet->type()== CEntitySheet::ITEM)
698 CItemSheet *item= (CItemSheet*)sheet;
699 if( item->Family == ITEMFAMILY::MELEE_WEAPON )
700 result = true;
702 return result;
705 // ***************************************************************************
706 bool CInventoryManager::isRangeWeaponItem(uint32 sheetID)
708 bool result = false;
709 CEntitySheet *sheet= SheetMngr.get(CSheetId(sheetID));
710 if(sheet && sheet->type()== CEntitySheet::ITEM)
712 CItemSheet *item= (CItemSheet*)sheet;
713 if( item->Family == ITEMFAMILY::RANGE_WEAPON )
714 result = true;
716 return result;
719 // ***************************************************************************
720 bool CInventoryManager::isDagger(uint32 sheetID)
722 bool result = false;
723 CEntitySheet *sheet= SheetMngr.get(CSheetId(sheetID));
724 if(sheet && sheet->type()== CEntitySheet::ITEM)
726 CItemSheet *item= (CItemSheet*)sheet;
727 if( item->ItemType == ITEM_TYPE::DAGGER)
728 result = true;
730 return result;
733 // ***************************************************************************
734 bool CInventoryManager::isSword(uint32 sheetID)
736 bool result = false;
737 CEntitySheet *sheet= SheetMngr.get(CSheetId(sheetID));
738 if(sheet && sheet->type()== CEntitySheet::ITEM)
740 CItemSheet *item= (CItemSheet*)sheet;
741 if( item->ItemType == ITEM_TYPE::SWORD)
742 result = true;
744 return result;
747 // ***************************************************************************
748 bool CInventoryManager::isForageToolItem(uint32 sheetID)
750 bool result = false;
751 CEntitySheet *sheet= SheetMngr.get(CSheetId(sheetID));
752 if(sheet && sheet->type()== CEntitySheet::ITEM)
754 CItemSheet *item= (CItemSheet*)sheet;
755 if( item->Family == ITEMFAMILY::HARVEST_TOOL )
756 result = true;
758 return result;
761 // ***************************************************************************
762 uint32 CInventoryManager::getHandItemSheet( bool rightHand ) const
764 CSheetId item;
765 CInterfaceManager *pIM= CInterfaceManager::getInstance();
766 string dbPropPath = toString("LOCAL:INVENTORY:HAND:%d:INDEX_IN_BAG",rightHand?0:1);
767 // get the RightHand bag index
768 sint32 itemSlot= NLGUI::CDBManager::getInstance()->getDbProp(dbPropPath)->getValue32();
769 // if something in hand
770 if(itemSlot>0)
772 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:BAG:"+toString(itemSlot-1) +":SHEET", false);
773 if(node)
774 item= node->getValue32();
776 return item.asInt();
780 // ***************************************************************************
781 bool CInventoryManager::isLeftHandItemCompatibleWithRightHandItem(uint32 leftHandSheet, uint32 rightHandSheet, uint32 lastRightHandSheet)
783 CEntitySheet *pLastRight = SheetMngr.get (CSheetId(lastRightHandSheet));
784 if (pLastRight != NULL)
786 if (pLastRight->type() != CEntitySheet::ITEM) return false;
787 CItemSheet *pIsLastRight = (CItemSheet *)pLastRight;
789 // Last item in right hand is a 2 hand item and the new item is nothing (unequip)
790 if (pIsLastRight->hasSlot(SLOTTYPE::TWO_HANDS) || pIsLastRight->hasSlot(SLOTTYPE::RIGHT_HAND_EXCLUSIVE))
791 return false;
794 if (leftHandSheet == 0) return true;
796 CEntitySheet *pLeft = SheetMngr.get (CSheetId(leftHandSheet));
797 if (pLeft == NULL) return false;
798 if (pLeft->type() != CEntitySheet::ITEM) return false;
799 CItemSheet *pIsLeft = (CItemSheet *)pLeft;
801 if ((pIsLeft->Family == ITEMFAMILY::AMMO) && (rightHandSheet == 0))
802 return false;
804 if ((pIsLeft->ItemType == ITEM_TYPE::DAGGER) && (rightHandSheet == 0))
805 return false;
807 CEntitySheet *pRight = SheetMngr.get (CSheetId(rightHandSheet));
808 if (pRight == NULL) return true;
809 if (pRight->type() != CEntitySheet::ITEM) return true;
810 CItemSheet *pIsRight = (CItemSheet *)pRight;
812 if (pIsRight->Family == ITEMFAMILY::RANGE_WEAPON)
814 if (pIsLeft->Family == ITEMFAMILY::AMMO)
815 if (pIsRight->RangeWeapon.Skill == pIsLeft->Ammo.Skill)
816 return true;
819 if (pIsLeft->ItemType == ITEM_TYPE::DAGGER)
821 if ((pIsRight->ItemType == ITEM_TYPE::SWORD) || (pIsRight->ItemType == ITEM_TYPE::DAGGER))
822 return true;
823 else
824 return false;
827 if (!pIsRight->hasSlot(SLOTTYPE::TWO_HANDS) && !pIsRight->hasSlot(SLOTTYPE::RIGHT_HAND_EXCLUSIVE))
829 return true;
832 return false;
835 // ***************************************************************************
836 static void grayItem (const std::string &listname, sint32 bagEntryIndex, bool gray)
838 CInterfaceManager *pIM = CInterfaceManager::getInstance();
840 IListSheetBase *pList = dynamic_cast<IListSheetBase*>(CWidgetManager::getInstance()->getElementFromId(listname));
842 if (pList != NULL)
844 pList->invalidateCoords();
846 for(uint i = 0; i < MAX_BAGINV_ENTRIES; ++i)
848 CDBCtrlSheet *pCS = pList->getSheet(i);
849 string sTmp = pCS->getSheet();
850 sTmp = sTmp.substr(sTmp.rfind(':')+1,sTmp.size());
851 sint32 nTmp;
852 fromString(sTmp, nTmp);
853 if (nTmp == bagEntryIndex)
854 pCS->setItemWeared(gray);
859 // ***************************************************************************
860 void CInventoryManager::wearBagItem(sint32 bagEntryIndex)
862 if(bagEntryIndex>=0 && bagEntryIndex<(sint32)MAX_BAGINV_ENTRIES)
864 BagItemEquipped[bagEntryIndex]= true;
865 grayItem (LIST_BAG_TEXT, bagEntryIndex, true);
866 grayItem (LIST_BAG_ICONS, bagEntryIndex, true);
867 sortBag();
871 // ***************************************************************************
872 void CInventoryManager::unwearBagItem(sint32 bagEntryIndex)
874 if(bagEntryIndex>=0 && bagEntryIndex<(sint32)MAX_BAGINV_ENTRIES)
876 BagItemEquipped[bagEntryIndex]= false;
877 grayItem (LIST_BAG_TEXT, bagEntryIndex, false);
878 grayItem (LIST_BAG_ICONS, bagEntryIndex, false);
879 sortBag();
883 // ***************************************************************************
884 bool CInventoryManager::isBagItemWeared(sint32 bagEntryIndex)
886 if(bagEntryIndex>=0 && bagEntryIndex<(sint32)MAX_BAGINV_ENTRIES)
888 return BagItemEquipped[bagEntryIndex];
891 return false;
894 // ----------------------------------------------------------------------------
895 static bool isSwimming()
897 if (UserEntity != NULL)
898 return (UserEntity->mode() == MBEHAV::SWIM || UserEntity->mode() == MBEHAV::MOUNT_SWIM);
899 else
900 return false;
903 static bool isRiding()
905 if (UserEntity)
906 return UserEntity->isRiding();
907 else
908 return false;
911 static bool isStunned()
913 if (UserEntity != NULL)
914 return (UserEntity->behaviour() == MBEHAV::STUNNED);
915 else
916 return false;
919 static bool isDead()
921 if (UserEntity != NULL)
922 return (UserEntity->mode() == MBEHAV::DEATH);
923 else
924 return false;
927 // ----------------------------------------------
928 // equip
930 // ----------------------------------------------
931 void CInventoryManager::equip(const std::string &bagPath, const std::string &invPath)
933 if (isSwimming() || isStunned() || isDead() || isRiding()) return;
935 CInterfaceManager *pIM = CInterfaceManager::getInstance();
937 if (bagPath.empty() || invPath.empty())
939 return;
942 // Get inventory and slot
943 string sIndexInBag = bagPath.substr(bagPath.rfind(':')+1,bagPath.size());
944 uint16 indexInBag;
945 fromString(sIndexInBag, indexInBag);
947 uint16 inventory = INVENTORIES::UNDEFINED;
948 uint16 invSlot = 0xffff;
950 if (strnicmp(invPath.c_str(),"LOCAL:INVENTORY:HAND",20) == 0)
952 inventory = INVENTORIES::handling;
953 fromString(invPath.substr(21,invPath.size()), invSlot);
955 else if (strnicmp(invPath.c_str(),"LOCAL:INVENTORY:EQUIP",21) == 0)
957 inventory = INVENTORIES::equipment;
958 fromString(invPath.substr(22,invPath.size()), invSlot);
961 // Hands management : check if we have to unequip left hand because of incompatibility with right hand item
962 sint16 oldRightIndexInBag = NLGUI::CDBManager::getInstance()->getDbProp(invPath + ":INDEX_IN_BAG")->getValue16();
963 if (inventory == INVENTORIES::handling && invSlot == 0)
965 CDBCtrlSheet *pCSLeftHand = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_LEFT));
966 if (pCSLeftHand == NULL)
968 return;
971 // get sheet of left item
972 uint32 leftSheet = 0;
973 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":HAND:1:INDEX_IN_BAG", false);
974 if (pNL == NULL)
976 return;
978 if (pNL->getValue32() > 0)
980 CCDBNodeLeaf *pNL2 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(pNL->getValue32()-1) + ":SHEET", false);
981 if (pNL2 == NULL)
983 return;
985 leftSheet = pNL2->getValue32();
988 // get sheet of previous right hand item
989 uint32 lastRightSheet = 0;
990 if (oldRightIndexInBag > 0)
992 pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(oldRightIndexInBag-1) + ":SHEET", false);
993 if (pNL == NULL)
995 return;
997 lastRightSheet = pNL->getValue32();
1000 // get sheet of new right hand item
1001 uint32 rightSheet = 0;
1002 if (indexInBag+1 > 0)
1004 pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(indexInBag) + ":SHEET", false);
1005 if (pNL == NULL)
1007 return;
1009 rightSheet = pNL->getValue32();
1012 // If incompatible -> remove
1013 if (!getInventory().isLeftHandItemCompatibleWithRightHandItem(leftSheet, rightSheet, lastRightSheet))
1015 getInventory().unequip(LOCAL_INVENTORY ":HAND:1");
1019 // update the equip DB pointer
1020 NLGUI::CDBManager::getInstance()->getDbProp(invPath + ":INDEX_IN_BAG")->setValue16(indexInBag+1);
1022 // Yoyo add: when the user equip an item, the action are invalid during some time
1023 if(indexInBag < MAX_BAGINV_ENTRIES)
1025 CItemSheet *pIS= dynamic_cast<CItemSheet*>(SheetMngr.get(CSheetId(getBagItem(indexInBag).getSheetID())));
1026 if(pIS)
1028 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1029 pPM->setEquipInvalidation(NetMngr.getCurrentServerTick(), pIS->EquipTime);
1033 // Update trade window if any
1034 if ((BotChatPageAll != NULL) && (BotChatPageAll->Trade != NULL))
1035 BotChatPageAll->Trade->invalidateCoords();
1037 // Send message to the server
1038 if (inventory != INVENTORIES::UNDEFINED)
1040 CBitMemStream out;
1041 const string sMsg = "ITEM:EQUIP";
1042 if (GenericMsgHeaderMngr.pushNameToStream(sMsg, out))
1044 // Fill the message (equipped inventory, equipped inventory slot, bag slot)
1045 out.serial(inventory);
1046 out.serial(invSlot);
1047 out.serial(indexInBag);
1048 NetMngr.push (out);
1050 pIM->incLocalSyncActionCounter();
1052 //nlinfo("impulseCallBack : %s %d %d %d sent", sMsg.c_str(), inventory, invSlot, indexInBag);
1054 else
1056 nlwarning ("don't know message name %s", sMsg.c_str());
1063 // ----------------------------------------------
1064 // unequip
1066 // ----------------------------------------------
1067 void CInventoryManager::unequip(const std::string &invPath)
1069 if (isSwimming() || isStunned() || isDead() ) return;
1071 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1073 sint16 oldIndexInBag = NLGUI::CDBManager::getInstance()->getDbProp(invPath + ":INDEX_IN_BAG")->getValue16();
1074 if( oldIndexInBag == 0 )
1076 return;
1079 // Get inventory and slot
1080 uint16 inventory = INVENTORIES::UNDEFINED;
1081 uint16 invSlot = 0xffff;
1083 if (strnicmp(invPath.c_str(),"LOCAL:INVENTORY:HAND",20) == 0)
1085 inventory = INVENTORIES::handling;
1086 fromString(invPath.substr(21,invPath.size()), invSlot);
1088 else if (strnicmp(invPath.c_str(),"LOCAL:INVENTORY:EQUIP",21) == 0)
1090 inventory = INVENTORIES::equipment;
1091 fromString(invPath.substr(22,invPath.size()), invSlot);
1094 // Hands management : check if we have to unequip left hand because of incompatibility with right hand item
1095 if (inventory == INVENTORIES::handling && invSlot == 0)
1097 CDBCtrlSheet *pCSLeftHand = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_LEFT));
1098 if (pCSLeftHand == NULL)
1100 return;
1103 // get sheet of left item
1104 uint32 leftSheet = 0;
1105 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":HAND:1:INDEX_IN_BAG", false);
1106 if (pNL == NULL)
1108 return;
1110 if (pNL->getValue32() > 0)
1112 CCDBNodeLeaf *pNL2 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(pNL->getValue32()-1) + ":SHEET", false);
1113 if (pNL2 == NULL)
1115 return;
1117 leftSheet = pNL2->getValue32();
1120 // get sheet of previous right hand item
1121 uint32 lastRightSheet = 0;
1122 if (oldIndexInBag > 0)
1124 pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(oldIndexInBag-1) + ":SHEET", false);
1125 if (pNL == NULL)
1127 return;
1129 lastRightSheet = pNL->getValue32();
1132 // sheet of new right hand item
1133 uint32 rightSheet = 0;
1135 // If incompatible -> remove
1136 if (!getInventory().isLeftHandItemCompatibleWithRightHandItem(leftSheet, rightSheet, lastRightSheet))
1138 getInventory().unequip(LOCAL_INVENTORY ":HAND:1");
1142 NLGUI::CDBManager::getInstance()->getDbProp(invPath + ":INDEX_IN_BAG")->setValue16(0);
1144 // Update trade window if any
1145 if ((BotChatPageAll != NULL) && (BotChatPageAll->Trade != NULL))
1146 BotChatPageAll->Trade->invalidateCoords();
1148 // Send message to the server
1149 if (inventory != INVENTORIES::UNDEFINED)
1151 CBitMemStream out;
1152 const string sMsg = "ITEM:UNEQUIP";
1153 if (GenericMsgHeaderMngr.pushNameToStream(sMsg, out))
1155 // Fill the message (equipped inventory, equipped inventory slot)
1156 out.serial(inventory);
1157 out.serial(invSlot);
1158 NetMngr.push (out);
1160 pIM->incLocalSyncActionCounter();
1162 //nlinfo("impulseCallBack : %s %d %d sent", sMsg.c_str(), inventory, invSlot);
1164 else
1166 nlwarning ("don't know message name %s", sMsg.c_str());
1172 // ***************************************************************************
1173 // Observer on DB equipment branch
1174 // ***************************************************************************
1175 void CInventoryManager::CDBEquipObs::update(ICDBNode* node)
1177 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1178 string sTmp = node->getFullName();
1179 string sIE, sIE2; // Interface Element
1180 CCDBNodeLeaf *pNL = dynamic_cast<CCDBNodeLeaf*>(node);
1181 if (pNL == NULL) return;
1182 if (strnicmp(sTmp.c_str(),"LOCAL:INVENTORY:HAND",20) == 0)
1184 // Coming from hand
1185 sTmp = sTmp.substr(21,sTmp.size());
1186 sTmp = sTmp.substr(0,sTmp.rfind(':'));
1187 sint index;
1188 fromString(sTmp, index);
1189 if (index == 0)
1190 sIE = CTRL_HAND_RIGHT;
1191 else
1192 sIE = CTRL_HAND_LEFT;
1193 // update Hands.
1194 getInventory().Hands[index]= pNL->getValue16();
1196 else if (strnicmp(sTmp.c_str(),"LOCAL:INVENTORY:EQUIP",21) == 0)
1198 // Coming from equipement
1199 sTmp = sTmp.substr(22,sTmp.size());
1200 sTmp = sTmp.substr(0,sTmp.rfind(':'));
1201 sint32 nTmp;
1202 fromString(sTmp, nTmp);
1203 SLOT_EQUIPMENT::TSlotEquipment index = (SLOT_EQUIPMENT::TSlotEquipment)nTmp;
1204 switch(index)
1206 case SLOT_EQUIPMENT::HEADDRESS: sIE = CTRL_JEWEL_HEADDRESS;
1207 sIE2= CTRL_JEWL2_HEADDRESS; break;
1208 case SLOT_EQUIPMENT::EARL: sIE = CTRL_JEWEL_EARING_LEFT;
1209 sIE2= CTRL_JEWL2_EARING_LEFT; break;
1210 case SLOT_EQUIPMENT::EARR: sIE = CTRL_JEWEL_EARING_RIGHT;
1211 sIE2= CTRL_JEWL2_EARING_RIGHT; break;
1212 case SLOT_EQUIPMENT::NECKLACE: sIE = CTRL_JEWEL_NECK;
1213 sIE2= CTRL_JEWL2_NECK; break;
1214 case SLOT_EQUIPMENT::WRISTL: sIE = CTRL_JEWEL_BRACELET_LEFT;
1215 sIE2= CTRL_JEWL2_BRACELET_LEFT; break;
1216 case SLOT_EQUIPMENT::WRISTR: sIE = CTRL_JEWEL_BRACELET_RIGHT;
1217 sIE2= CTRL_JEWL2_BRACELET_RIGHT; break;
1218 case SLOT_EQUIPMENT::FINGERL: sIE = CTRL_JEWEL_RING_LEFT;
1219 sIE2= CTRL_JEWL2_RING_LEFT; break;
1220 case SLOT_EQUIPMENT::FINGERR: sIE = CTRL_JEWEL_RING_RIGHT;
1221 sIE2= CTRL_JEWL2_RING_RIGHT; break;
1222 case SLOT_EQUIPMENT::ANKLEL: sIE = CTRL_JEWEL_ANKLET_LEFT;
1223 sIE2= CTRL_JEWL2_ANKLET_LEFT; break;
1224 case SLOT_EQUIPMENT::ANKLER: sIE = CTRL_JEWEL_ANKLET_RIGHT;
1225 sIE2= CTRL_JEWL2_ANKLET_RIGHT; break;
1227 case SLOT_EQUIPMENT::HEAD: sIE = CTRL_ARMOR_HEAD;
1228 sIE2= CTRL_ARMR2_HEAD; break;
1229 case SLOT_EQUIPMENT::CHEST: sIE = CTRL_ARMOR_CHEST;
1230 sIE2= CTRL_ARMR2_CHEST; break;
1231 case SLOT_EQUIPMENT::ARMS: sIE = CTRL_ARMOR_ARMS;
1232 sIE2= CTRL_ARMR2_ARMS; break;
1233 case SLOT_EQUIPMENT::FEET: sIE = CTRL_ARMOR_FEET;
1234 sIE2= CTRL_ARMR2_FEET; break;
1235 case SLOT_EQUIPMENT::LEGS: sIE = CTRL_ARMOR_LEGS;
1236 sIE2= CTRL_ARMR2_LEGS; break;
1237 case SLOT_EQUIPMENT::HANDS: sIE = CTRL_ARMOR_HANDS;
1238 sIE2= CTRL_ARMR2_HANDS; break;
1240 default:
1241 nlwarning("entry not handled");
1242 return;
1243 break;
1245 // update Equips.
1246 getInventory().Equip[index]= pNL->getValue16();
1248 else return;
1250 // Set database for wearing the right item
1251 CDBCtrlSheet *pCS = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(sIE));
1252 CDBCtrlSheet *pCS2 = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(sIE2));
1254 // Remove Last reference and update database
1255 sint16 oldVal = pNL->getOldValue16();
1256 sint16 newVal = pNL->getValue16();
1257 if (oldVal != 0)
1258 getInventory().unwearBagItem (oldVal-1);
1260 if (newVal != 0)
1261 getInventory().wearBagItem (newVal-1);
1263 // Update Display
1264 if (newVal == 0)
1266 // in some case left sheet is same than right sheet so don't clear it now (ex: 2 hands item, right hand exclusive)
1267 if (sIE != CTRL_HAND_LEFT)
1269 if (pCS != NULL) pCS->setSheet("");
1270 if (pCS2 != NULL) pCS2->setSheet("");
1273 else
1275 if (pCS != NULL) pCS->setSheet(LOCAL_INVENTORY ":BAG:"+ toString(newVal-1));
1276 if (pCS2 != NULL) pCS2->setSheet(LOCAL_INVENTORY ":BAG:"+ toString(newVal-1));
1279 // Hands management
1280 if (sIE == CTRL_HAND_RIGHT)
1282 // if nothing in left hand -> return
1283 CDBCtrlSheet *pCSLeftHand = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_LEFT));
1284 if (pCSLeftHand == NULL)
1286 return;
1289 // reset display of left hand
1290 CViewRenderer &rVR = *CViewRenderer::getInstance();
1291 pCSLeftHand->setTextureNoItem(rVR.getTextureIdFromName("hand_left.tga"));
1292 pCSLeftHand->setGrayed(false);
1293 pCSLeftHand->setItemSlot(SLOTTYPE::stringToSlotType("LEFT_HAND"));
1294 pCSLeftHand->setActionOnLeftClick("proc");
1296 // If something in left hand check if we have to remove
1298 uint32 leftSheet = 0;
1299 CCDBNodeLeaf *pNL3 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":HAND:1:INDEX_IN_BAG", false);
1300 if (pNL3 == NULL) return;
1301 if (pNL3->getValue32() > 0)
1303 CCDBNodeLeaf *pNL4 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(pNL3->getValue32()-1) + ":SHEET", false);
1304 if (pNL4 == NULL) return;
1305 leftSheet = pNL4->getValue32();
1308 uint32 rightSheet = 0;
1309 if (newVal > 0)
1311 pNL3 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(newVal-1) + ":SHEET", false);
1312 if (pNL3 == NULL) return;
1313 rightSheet = pNL3->getValue32();
1316 uint32 lastRightSheet = 0;
1317 if (oldVal > 0)
1319 pNL3 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(oldVal-1) + ":SHEET", false);
1320 if (pNL3 == NULL) return;
1321 lastRightSheet = pNL3->getValue32();
1324 // If incompatible -> remove
1325 if (!getInventory().isLeftHandItemCompatibleWithRightHandItem(leftSheet, rightSheet, lastRightSheet))
1327 pCSLeftHand->setSheet("");
1329 // WORKAROUND: useful when an item is destroyed before it is unequipped (clean the left hand)
1330 if ((leftSheet == 0) && (rightSheet == 0))
1332 pCSLeftHand->setSheet("");
1336 // update display of left hand according to new right hand item
1337 if (newVal > 0)
1339 CCDBNodeLeaf *pNL2 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(newVal-1) + ":SHEET", false);
1340 if (pNL2 == NULL) return;
1342 if (getInventory().is2HandItem(pNL2->getValue32()))
1344 if (getInventory().isRangeWeaponItem(pNL2->getValue32()))
1346 pCSLeftHand->setItemSlot(SLOTTYPE::stringToSlotType("AMMO"));
1347 pCSLeftHand->setTextureNoItem(rVR.getTextureIdFromName("W_AM_logo.tga"));
1349 else
1351 pCSLeftHand->setSheet(LOCAL_INVENTORY ":BAG:"+ toString(newVal-1));
1352 pCSLeftHand->setGrayed(true);
1353 pCSLeftHand->setActionOnLeftClick("");
1359 // left hand item is changing
1360 if (sIE == CTRL_HAND_LEFT)
1362 CDBCtrlSheet *pCSLeftHand = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_LEFT));
1363 if ( pCSLeftHand )
1365 CViewRenderer &rVR = *CViewRenderer::getInstance();
1366 pCSLeftHand->setActionOnLeftClick("proc");
1367 pCSLeftHand->setGrayed(false);
1369 // if now there is nothing in left hand
1370 if (newVal == 0)
1372 // check if we clear display (have to manage 2 hands weapons for instance)
1373 bool clearLeftHandDisplay = true;
1374 CDBCtrlSheet * pCSRightHand = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getElementFromId(CTRL_HAND_RIGHT));
1375 if ( pCSRightHand && pCSRightHand->getSheetId() )
1377 CCDBNodeLeaf *pNL3 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":HAND:0:INDEX_IN_BAG", false);
1378 if (pNL3)
1380 if (pNL3->getValue32() > 0)
1382 CCDBNodeLeaf *pNL4 = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":BAG:" + toString(pNL3->getValue32()-1) + ":SHEET", false);
1383 if (pNL4)
1385 uint32 rightSheet = pNL4->getValue32();
1386 if (getInventory().is2HandItem(rightSheet))
1388 if (getInventory().isRangeWeaponItem(rightSheet))
1390 pCSLeftHand->setItemSlot(SLOTTYPE::stringToSlotType("AMMO"));
1391 pCSLeftHand->setTextureNoItem(rVR.getTextureIdFromName("W_AM_logo.tga"));
1393 else
1395 pCSLeftHand->setItemSlot(SLOTTYPE::stringToSlotType("LEFT_HAND"));
1396 pCSLeftHand->setTextureNoItem(rVR.getTextureIdFromName("hand_left.tga"));
1397 clearLeftHandDisplay = false;
1404 if(clearLeftHandDisplay)
1406 if (pCS != NULL) pCS->setSheet("");
1407 if (pCS2 != NULL) pCS2->setSheet("");
1414 // ***************************************************************************
1415 void CInventoryManager::CDBBagObs::update(ICDBNode* /* node */)
1417 if (IngameDbMngr.initInProgress()) return;
1419 getInventory().checkIndexInBagIntegrity();
1421 // AUTO EQUIP the player with incoming item if we can put this item in an equipment slot
1423 // if we are not initializing the DB
1425 CCDBNodeLeaf *pNL = dynamic_cast<CCDBNodeLeaf*>(node);
1426 if (pNL != NULL)
1427 if (pNL->getValue32() == 0)
1428 return;
1430 if (IngameDbMngr.initInProgress()) return;
1432 sint bagEntryIndex;
1434 string path = node->getFullName();
1435 path = path.substr(0,path.rfind(':'));
1436 path = path.substr(path.rfind(':')+1,path.size());
1438 fromString(path, bagEntryIndex);
1439 // equip only if slot empty
1440 getInventory().autoEquip(bagEntryIndex, false);
1444 // ***************************************************************************
1445 bool CInventoryManager::autoEquip(sint bagEntryIndex, bool allowReplace)
1447 uint i;
1449 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1450 IListSheetBase *pList = dynamic_cast<IListSheetBase*>(CWidgetManager::getInstance()->getElementFromId(LIST_BAG_TEXT));
1451 CDBCtrlSheet *pCSSrc = NULL;
1453 if (pList == NULL) return false;
1455 for (i = 0; i < MAX_BAGINV_ENTRIES; ++i)
1457 pCSSrc = pList->getSheet(i);
1458 string sTmp = pCSSrc->getSheet();
1459 sTmp = sTmp.substr(sTmp.rfind(':')+1,sTmp.size());
1460 sint nTmp;
1461 fromString(sTmp, nTmp);
1462 if (nTmp == bagEntryIndex)
1463 break;
1466 if (i == MAX_BAGINV_ENTRIES) return false;
1467 if (pCSSrc == NULL) return false;
1469 for (i = 0; i < MAX_HANDINV_ENTRIES; ++i)
1471 CDBCtrlSheet *pCSDst = getInventory().getHandSheet(i);
1472 if (pCSDst == NULL) continue;
1473 string dstPath = getInventory().getDBIndexPath(pCSDst);
1475 sint32 indexDstPath = NLGUI::CDBManager::getInstance()->getDbProp(dstPath+":INDEX_IN_BAG")->getValue16();
1477 // Already something in that slot?
1478 if (!allowReplace && indexDstPath > 0)
1479 continue;
1481 // Does the source and destination are items ?
1482 if (pCSSrc->getType() == CCtrlSheetInfo::SheetType_Item)
1483 if (pCSDst->getType() == CCtrlSheetInfo::SheetType_Item)
1485 // Right Slot ?
1486 if (pCSDst->canDropItem(pCSSrc))
1488 // Ok let us equip with this item
1489 string srcPath = pCSSrc->getSheet();
1490 getInventory().equip (srcPath, dstPath);
1491 return true;
1496 for (i = 0; i < MAX_EQUIPINV_ENTRIES; ++i)
1498 CDBCtrlSheet *pCSDst = getInventory().getEquipSheet(i);
1499 if (pCSDst == NULL) continue;
1500 string dstPath = getInventory().getDBIndexPath(pCSDst);
1501 sint32 indexDstPath = NLGUI::CDBManager::getInstance()->getDbProp(dstPath+":INDEX_IN_BAG")->getValue16();
1503 // Already something in that slot?
1504 if (!allowReplace && indexDstPath > 0)
1505 continue;
1507 // Does the source and destination are items ?
1508 if (pCSSrc->getType() == CCtrlSheetInfo::SheetType_Item)
1509 if (pCSDst->getType() == CCtrlSheetInfo::SheetType_Item)
1511 // Right Slot ?
1512 if (pCSDst->canDropItem(pCSSrc))
1514 // Ok let us equip with this item
1515 string srcPath = pCSSrc->getSheet();
1516 getInventory().equip (srcPath, dstPath);
1517 return true;
1521 return false;
1524 // ***************************************************************************
1525 void CInventoryManager::dropOrDestroyItem(CDBCtrlSheet *item, CBitMemStream &out, uint16 quantity)
1527 if (!item) return;
1528 uint16 inventory = (uint16) item->getInventoryIndex();
1529 // retrieve inventory & slot
1530 uint16 slot = (uint16) item->getIndexInDB();
1531 out.serial(inventory);
1532 out.serial(slot);
1533 out.serial(quantity);
1534 NetMngr.push(out);
1537 // ***************************************************************************
1538 static void checkEquipmentIntegrity(const string &equipVal)
1540 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1541 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(equipVal+":INDEX_IN_BAG",false);
1542 if (pNL != NULL)
1544 uint32 indexInBag = pNL->getValue16();
1545 if (indexInBag != 0)
1547 string sTmp = string(LOCAL_INVENTORY) + ":BAG:" + toString(indexInBag-1) + ":SHEET";
1548 CCDBNodeLeaf *pNLBag = NLGUI::CDBManager::getInstance()->getDbProp(sTmp,false);
1549 if (pNLBag != NULL)
1551 if (pNLBag->getValue32() == 0) // If no more item in this slot bag
1553 // if (! IngameDbMngr.initInProgress()) // Commented because init is end when we received equipment
1554 // pNL->setValue16(0); // Reset INDEX_IN_BAG
1556 else
1558 // If the slot was previously empty check that there is no reference on it
1559 // else update the reference
1560 if (pNLBag->getOldValue32() == 0)
1562 for (uint32 i = 0; i < MAX_EQUIPINV_ENTRIES; ++i)
1564 CDBCtrlSheet *pCSDst = getInventory().getEquipSheet(i);
1565 if (pCSDst == NULL) continue;
1566 string dstPath = getInventory().getDBIndexPath(pCSDst);
1567 sint32 indexDstPath = NLGUI::CDBManager::getInstance()->getDbProp(dstPath+":INDEX_IN_BAG")->getValue16();
1569 // Update the sheet id of the control sheet
1570 if (indexDstPath == (sint32)indexInBag)
1572 pCSDst->setSheetId(pNLBag->getValue32());
1582 // ***************************************************************************
1583 void CInventoryManager::checkIndexInBagIntegrity()
1585 string sTmp;
1586 uint32 i;
1588 for (i = 0; i < MAX_HANDINV_ENTRIES; ++i)
1590 sTmp = string(LOCAL_INVENTORY) + ":HAND:" + toString(i);
1591 checkEquipmentIntegrity(sTmp);
1594 for (i = 0; i < MAX_EQUIPINV_ENTRIES; ++i)
1596 sTmp = string(LOCAL_INVENTORY) + ":EQUIP:" + toString(i);
1597 checkEquipmentIntegrity(sTmp);
1601 // ***************************************************************************
1602 double CInventoryManager::getBranchBulk(const string &basePath, uint16 startItemIndex, uint16 numItems)
1604 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1605 CCDBNodeBranch *branch = NLGUI::CDBManager::getInstance()->getDbBranch(basePath);
1606 if (!branch)
1608 nlwarning("<getBranchBulk> Branch is NULL");
1609 return 0;
1612 double totalBulk = 0;
1614 uint16 lastIndexItem = std::min((uint16) (startItemIndex + numItems), (uint16) branch->getNbNodes());
1615 for (uint16 currItem = startItemIndex; currItem < lastIndexItem; ++ currItem)
1617 ICDBNode *node = branch->getNode(currItem);
1618 if (node)
1620 CCDBNodeLeaf *sheetNode = dynamic_cast<CCDBNodeLeaf *>(node->getNode(ICDBNode::CTextId("SHEET")));
1621 CCDBNodeLeaf *quantityNode = dynamic_cast<CCDBNodeLeaf *>(node->getNode(ICDBNode::CTextId("QUANTITY")));
1622 if (sheetNode && quantityNode)
1624 // get the Sheet
1625 CSheetId sheetId = CSheetId(sheetNode->getValue32());
1626 if (sheetId != CSheetId::Unknown)
1628 CItemSheet *itemSheet= dynamic_cast<CItemSheet*>(SheetMngr.get(sheetId));
1629 if(itemSheet)
1631 totalBulk += std::max((sint32)1, quantityNode->getValue32()) * itemSheet->Bulk;
1638 return totalBulk;
1642 *Get the number of used and max slots
1644 void CInventoryManager::getBranchSlotCounts(const std::string &basePath, uint& nbUsedSlots, uint& nbMaxSlots )
1646 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1647 CCDBNodeBranch *branch = NLGUI::CDBManager::getInstance()->getDbBranch(basePath);
1648 if (!branch)
1650 nlwarning("<getBranchSlotCounts> Branch is NULL");
1651 return;
1654 nbMaxSlots = 0; // different from nbNodes, because there can be non-slots leaves (e.g. guild money...)
1655 nbUsedSlots = 0;
1656 uint nbNodes = branch->getNbNodes();
1657 for ( uint i=0; i!=nbNodes; ++i )
1659 ICDBNode *node = branch->getNode(i);
1660 if (node)
1662 CCDBNodeLeaf *sheetNode = dynamic_cast<CCDBNodeLeaf *>(node->getNode(ICDBNode::CTextId("SHEET")));
1663 if (sheetNode)
1665 // Get the Sheet
1666 CSheetId sheetId = CSheetId(sheetNode->getValue32());
1667 if (sheetId != CSheetId::Unknown)
1669 ++nbUsedSlots;
1672 ++nbMaxSlots;
1679 // ***************************************************************************
1680 double CInventoryManager::getBagBulk(uint32 inventoryIndex)
1682 nlctassert(MAX_INVENTORY_ANIMAL==7);
1683 if (inventoryIndex == 0)
1684 return getBranchBulk(LOCAL_INVENTORY ":BAG", 0, MAX_BAGINV_ENTRIES);
1685 else if (inventoryIndex == 1)
1686 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL0", 0, MAX_ANIMALINV_ENTRIES);
1687 else if (inventoryIndex == 2)
1688 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL1", 0, MAX_ANIMALINV_ENTRIES);
1689 else if (inventoryIndex == 3)
1690 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL2", 0, MAX_ANIMALINV_ENTRIES);
1691 else if (inventoryIndex == 4)
1692 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL3", 0, MAX_ANIMALINV_ENTRIES);
1693 else if (inventoryIndex == 5)
1694 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL4", 0, MAX_ANIMALINV_ENTRIES);
1695 else if (inventoryIndex == 6)
1696 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL5", 0, MAX_ANIMALINV_ENTRIES);
1697 else if (inventoryIndex == 7)
1698 return getBranchBulk(LOCAL_INVENTORY ":PACK_ANIMAL6", 0, MAX_ANIMALINV_ENTRIES);
1699 else if (inventoryIndex == 8)
1700 return 0;
1701 else if (inventoryIndex == 9)
1702 return 0;
1703 else if (inventoryIndex == 10)
1704 return getBranchBulk(LOCAL_INVENTORY ":TEMP", 0, MAX_TEMPINV_ENTRIES);
1705 return 0;
1708 // ***************************************************************************
1709 double CInventoryManager::getItemBulk(uint32 sheetID)
1711 CItemSheet *itemSheet= dynamic_cast<CItemSheet*>(SheetMngr.get(CSheetId(sheetID)));
1712 if(itemSheet)
1713 return itemSheet->Bulk;
1714 return 0;
1717 // ***************************************************************************
1718 double CInventoryManager::getMaxBagBulk(uint32 inventoryIndex)
1720 nlctassert(MAX_INVENTORY_ANIMAL==7);
1721 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1722 CCDBNodeLeaf *pNL=NULL;
1723 if (inventoryIndex == 0)
1724 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:STATIC_DATA:BAG_BULK_MAX");
1725 else if (inventoryIndex == 1)
1726 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST0:BULK_MAX");
1727 else if (inventoryIndex == 2)
1728 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST1:BULK_MAX");
1729 else if (inventoryIndex == 3)
1730 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST2:BULK_MAX");
1731 else if (inventoryIndex == 4)
1732 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST3:BULK_MAX");
1733 else if (inventoryIndex == 5)
1734 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST4:BULK_MAX");
1735 else if (inventoryIndex == 6)
1736 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST5:BULK_MAX");
1737 else if (inventoryIndex == 7)
1738 pNL = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST6:BULK_MAX");
1739 if (pNL != NULL)
1740 return pNL->getValue32();
1741 return 0;
1744 // ***************************************************************************
1745 bool CInventoryManager::isSpaceInAllBagsForItem(CDBCtrlSheet *item)
1747 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1748 CDBCtrlSheet *pCSDst = item;
1749 if (!pCSDst->isSheetValid()) return false;
1750 string sTmp = pCSDst->getSheet();
1751 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp+":SHEET",false);
1752 CCDBNodeLeaf *pNLquantity = NLGUI::CDBManager::getInstance()->getDbProp(sTmp+":QUANTITY",false);
1753 if (pNL == NULL) return false;
1754 if (pNLquantity == NULL) return false;
1756 // Check if we can find empty space for this item (or stack of item)
1757 // in all of the bags that the player owe.
1759 CInventoryManager *pInv = CInventoryManager::getInstance();
1760 uint32 quantity = pNLquantity->getValue32();
1761 double totalBulk = quantity * pInv->getItemBulk(pNL->getValue32());
1762 // bool bPlaceFound = false;
1763 for (uint32 i = 0; i < 7; ++i)
1765 if (pInv->isInventoryAvailable((INVENTORIES::TInventory)CInventoryManager::InventoryIndexes[i]))
1766 if ((pInv->getBagBulk(i) + totalBulk) <= pInv->getMaxBagBulk(i))
1767 return true;
1769 return false;
1772 // ***************************************************************************
1773 bool CInventoryManager::isSpaceInBagForItem(CDBCtrlSheet *item, uint32 quantity, uint32 bagId)
1775 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1776 CDBCtrlSheet *pCSDst = item;
1777 if (!pCSDst->isSheetValid()) return false;
1778 string sTmp = pCSDst->getSheet();
1779 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp+":SHEET",false);
1780 if (pNL == NULL) return false;
1782 // Check if we can find empty space for this item (or stack of item)
1783 // in a given bag that the player owe.
1785 CInventoryManager *pInv = CInventoryManager::getInstance();
1786 double totalBulk = quantity * pInv->getItemBulk(pNL->getValue32());
1787 if (pInv->isInventoryAvailable((INVENTORIES::TInventory)CInventoryManager::InventoryIndexes[bagId]))
1788 if ((pInv->getBagBulk(bagId) + totalBulk) <= pInv->getMaxBagBulk(bagId))
1789 return true;
1790 return false;
1794 // ***************************************************************************
1795 // CTempInvManager
1796 // ***************************************************************************
1798 // Observers on DB
1799 // ***************************************************************************
1800 void CTempInvManager::CDBObs::update(ICDBNode* /* node */)
1802 CTempInvManager::getInstance()->update();
1805 void CTempInvManager::CDBObsType::update(ICDBNode* /* node */)
1807 CTempInvManager::getInstance()->updateType();
1810 void CTempInvManager::CDBForageQQObs::update(ICDBNode* /* node */)
1812 CTempInvManager::getInstance()->updateForageQQ( WhichOne );
1815 // ***************************************************************************
1816 CTempInvManager::CTempInvManager()
1818 _Mode = TEMP_INV_MODE::Unknown;
1820 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1822 string sPath = string("LOCAL:INVENTORY:TEMP");
1823 for (uint i = 0; i < MAX_TEMPINV_ENTRIES; ++i)
1825 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sPath+":"+toString(i)+":SHEET", false);
1826 if (pNL != NULL)
1828 ICDBNode::CTextId textId;
1829 pNL->addObserver(&_DBObs, textId);
1832 // Add Also the Mode to observe
1833 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sPath+":TYPE", false);
1834 if(pNL)
1836 ICDBNode::CTextId textId;
1837 pNL->addObserver(&_DBObsType, textId);
1840 // Forage
1841 pNL = NLGUI::CDBManager::getInstance()->getDbProp(sPath+":ENABLE_TAKE");
1842 if (pNL != NULL)
1844 ICDBNode::CTextId textId;
1845 pNL->addObserver(&_DBObs, textId);
1847 pNL = NLGUI::CDBManager::getInstance()->getDbProp(sPath+":0:QUANTITY");
1848 _DBForageQQObs[0].WhichOne = 0;
1849 if (pNL != NULL)
1851 ICDBNode::CTextId textId;
1852 pNL->addObserver(&_DBForageQQObs[0], textId);
1854 pNL = NLGUI::CDBManager::getInstance()->getDbProp(sPath+":0:QUALITY");
1855 _DBForageQQObs[1].WhichOne = 1;
1856 if (pNL != NULL)
1858 ICDBNode::CTextId textId;
1859 pNL->addObserver(&_DBForageQQObs[1], textId);
1863 // ***************************************************************************
1864 CTempInvManager::~CTempInvManager()
1868 // ***************************************************************************
1869 void CTempInvManager::releaseInstance()
1871 if( _Instance )
1872 delete _Instance;
1873 _Instance = NULL;
1876 // ***************************************************************************
1877 void CTempInvManager::update()
1879 bool bAllEmpty = true;
1880 // Check the database state
1881 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1882 string sPath = string("LOCAL:INVENTORY:TEMP");
1883 for (uint i = 0; i < MAX_TEMPINV_ENTRIES; i++)
1885 string sTmp = sPath + ":" + toString(i) + ":SHEET";
1886 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp);
1887 // uint32 nOldSheet = pNL->getOldValue32();
1888 uint32 nSheet = pNL->getValue32();
1889 if (nSheet != 0)
1890 bAllEmpty = false;
1893 _Mode = (TEMP_INV_MODE::TInventoryMode)NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:TYPE")->getValue8();
1895 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
1896 if (pGC == NULL)
1897 return;
1899 // show/hide weight info depending on temp inventory mode
1900 bool displayWeight = (_Mode == TEMP_INV_MODE::Craft);
1901 CViewBase *weightText = dynamic_cast<CViewBase*>(pGC->getView("weight_txt"));
1902 if (weightText != NULL)
1903 weightText->setActive(displayWeight);
1904 CViewBase *weightImg = dynamic_cast<CViewBase*>(pGC->getView("weight"));
1905 if (weightImg != NULL)
1906 weightImg->setActive(displayWeight);
1908 if (_Mode == TEMP_INV_MODE::Forage)
1910 // Disable/enable "Take all" button
1911 bool disableTake = (NLGUI::CDBManager::getInstance()->getDbProp(sPath+":ENABLE_TAKE")->getValue32() == 0);
1912 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP_INV:ALL_EMPTY")->setValue32(disableTake);
1913 if ( disableTake )
1915 // Display begin of forage
1916 pGC->setTitle( WIN_TEMPINV_TITLE_WAIT_FORAGING );
1917 _DBForageQQObs[0].FullValue = 0.0f;
1918 _DBForageQQObs[1].FullValue = 0.0f;
1920 else
1922 // Display forage result
1923 pGC->setTitle( WIN_TEMPINV_TITLE_FORAGE_RESULT );
1926 else
1928 // Write to the UI db the empty state
1929 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP_INV:ALL_EMPTY")->setValue32(bAllEmpty);
1932 if (bAllEmpty)
1934 // If all slots are empty, close the interface
1935 pGC->setActive(false);
1936 CAHManager::getInstance()->runActionHandler("phrase_update_all_memory_ctrl_regen_tick_range", NULL);
1938 else
1940 pGC->setActive(true);
1941 CAHManager::getInstance()->runActionHandler("phrase_update_all_memory_ctrl_regen_tick_range", NULL);
1942 // Something arrived, change text
1943 switch(_Mode)
1945 case TEMP_INV_MODE::Loot: pGC->setTitle(WIN_TEMPINV_TITLE_LOOT); break;
1946 case TEMP_INV_MODE::Quarter: pGC->setTitle(WIN_TEMPINV_TITLE_QUARTERING); break;
1947 case TEMP_INV_MODE::Forage: /* see above */ break;
1948 case TEMP_INV_MODE::BagFull: pGC->setTitle(WIN_TEMPINV_TITLE_BAGFULL); break;
1949 case TEMP_INV_MODE::Craft: pGC->setTitle(WIN_TEMPINV_TITLE_CRAFT); break;
1950 case TEMP_INV_MODE::MissionReward: pGC->setTitle(WIN_TEMPINV_TITLE_MISSIONREWARD); break;
1951 case TEMP_INV_MODE::Crystallize: pGC->setTitle(WIN_TEMPINV_TITLE_CRYSTALLIZE); break;
1953 case TEMP_INV_MODE::Unknown:
1954 default: pGC->setTitle(WIN_TEMPINV_TITLE_ERROR); break;
1959 // ***************************************************************************
1960 void CTempInvManager::updateType()
1962 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1963 _Mode = (TEMP_INV_MODE::TInventoryMode)NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:TYPE")->getValue8();
1964 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
1965 // Something arrived, change text
1966 switch(_Mode)
1968 case TEMP_INV_MODE::Loot: pGC->setTitle(WIN_TEMPINV_TITLE_LOOT); break;
1969 case TEMP_INV_MODE::Quarter: pGC->setTitle(WIN_TEMPINV_TITLE_QUARTERING); break;
1970 case TEMP_INV_MODE::Forage: /* see above */ break;
1971 case TEMP_INV_MODE::BagFull: pGC->setTitle(WIN_TEMPINV_TITLE_BAGFULL); break;
1972 case TEMP_INV_MODE::Craft: pGC->setTitle(WIN_TEMPINV_TITLE_CRAFT); break;
1973 case TEMP_INV_MODE::MissionReward: pGC->setTitle(WIN_TEMPINV_TITLE_MISSIONREWARD); break;
1974 case TEMP_INV_MODE::Crystallize: pGC->setTitle(WIN_TEMPINV_TITLE_CRYSTALLIZE); break;
1976 case TEMP_INV_MODE::Unknown:
1977 default: /*pGC->setTitle(WIN_TEMPINV_TITLE_ERROR);*/ // do not overwrite a locally-set title with the default one when ServerAutoCopy syncs the local db during 'make item' (craft)
1978 break;
1982 // ***************************************************************************
1983 // Called when INVENTORY:TEMP:0:QUANTITY or INVENTORY:TEMP:0:QUALITY is modified
1984 // Reacts only if mode is Forage
1985 void CTempInvManager::updateForageQQ( uint whichOne )
1987 if ( _Mode != TEMP_INV_MODE::Forage )
1988 return;
1990 // Avoid recursion, because we can't call CCDBNodeLeaf::setValue16() without calling observers!
1991 static bool isInUpdateForageQQ = false;
1992 if ( isInUpdateForageQQ )
1993 return;
1994 isInUpdateForageQQ = true;
1996 // Display forage progress with counters
1997 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1998 bool disableTake = (NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:ENABLE_TAKE")->getValue32() == 0);
1999 if ( disableTake )
2001 float qt = 0.f, ql = 0.f;
2002 switch ( whichOne )
2004 case 0:
2006 CCDBNodeLeaf *leafQt = NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:0:QUANTITY");
2007 uint16 qtX10 = (uint16)(leafQt->getValue16());
2008 qt = _DBForageQQObs[whichOne].FullValue = (((float)(uint)qtX10) / 10.0f);
2009 leafQt->setValue16( (sint16)(sint)qt );
2010 ql = _DBForageQQObs[1-whichOne].FullValue;
2012 break;
2013 case 1:
2015 CCDBNodeLeaf *leafQl = NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:0:QUALITY");
2016 uint16 qlX10 = (uint16)(leafQl->getValue16());
2017 ql = _DBForageQQObs[whichOne].FullValue = (((float)(uint)qlX10) / 10.0f);
2018 leafQl->setValue16( (sint16)(sint)ql );
2019 qt = _DBForageQQObs[1-whichOne].FullValue;
2021 break;
2022 default:;
2024 string title = CI18N::get( WIN_TEMPINV_TITLE_FORAGING );
2025 strFindReplace( title, "%qt", toString( "%.1f", qt ) );
2026 strFindReplace( title, "%ql", toString( "%.1f", ql ) );
2027 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
2028 pGC->setTitle( title );
2031 isInUpdateForageQQ = false;
2034 // ***************************************************************************
2035 void CTempInvManager::open(TEMP_INV_MODE::TInventoryMode m)
2037 _Mode = m;
2038 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2039 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
2041 // In Foraging mode, we can call open() on the inventory with the same contents (e.g. when changing Forage action)
2042 if ( _Mode != TEMP_INV_MODE::Forage )
2044 string sPath = string("LOCAL:INVENTORY:TEMP");
2045 for (uint i = 0; i < MAX_TEMPINV_ENTRIES; i++)
2047 string sTmp = sPath + ":" + toString(i) + ":SHEET";
2048 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp);
2049 pNL->setValue32(0);
2052 NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:TYPE")->setValue8((uint8)_Mode);
2054 IngameDbMngr.flushObserverCalls();
2055 NLGUI::CDBManager::getInstance()->flushObserverCalls();
2057 if (pGC != NULL)
2059 switch(_Mode)
2061 case TEMP_INV_MODE::Loot: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_LOOT); break;
2062 case TEMP_INV_MODE::Quarter: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_QUARTERING); break;
2063 case TEMP_INV_MODE::Forage: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_FORAGING); break;
2064 case TEMP_INV_MODE::BagFull: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_BAGFULL); break;
2065 case TEMP_INV_MODE::Craft: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_CRAFT); break;
2066 case TEMP_INV_MODE::MissionReward: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_MISSIONREWARD); break;
2067 case TEMP_INV_MODE::Crystallize: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_CRYSTALLIZE); break;
2069 case TEMP_INV_MODE::Unknown:
2070 default: pGC->setTitle(WIN_TEMPINV_TITLE_WAIT_ERROR); break;
2073 pGC->setActive(true);
2074 CAHManager::getInstance()->runActionHandler("phrase_update_all_memory_ctrl_regen_tick_range", NULL);
2078 // ***************************************************************************
2079 void CTempInvManager::close()
2081 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2082 string sPath = string("LOCAL:INVENTORY:TEMP");
2084 // Clear temp inventory if needed
2085 for (uint i = 0; i < MAX_TEMPINV_ENTRIES; i++)
2087 string sTmp = sPath + ":" + toString(i) + ":SHEET";
2088 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp);
2089 pNL->setValue32(0);
2092 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
2093 if (pIG != NULL)
2095 pIG->setActive(false);
2096 CAHManager::getInstance()->runActionHandler("phrase_update_all_memory_ctrl_regen_tick_range", NULL);
2100 // ***************************************************************************
2101 bool CTempInvManager::isOpened()
2103 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2104 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
2105 if (pGC != NULL)
2106 return pGC->getActive();
2107 return false;
2110 // ***************************************************************************
2111 // BAG LISTS COMMON STUFF (sort, options ...)
2112 // ***************************************************************************
2114 // ***************************************************************************
2115 #define BAG_ITEM_NOT_SORTED 1000000
2116 // Used for sorting
2117 void initStructForItemSort(vector<SSortStruct>&vTemp, sint32 sheetId, sint32 quality, sint32 indexInList, sint32 indexInDB)
2119 // Default value is the linear pos in the db (in case its not an item)
2120 vTemp[indexInList].Pos = toString("%08d", indexInDB);
2122 // if not empty
2123 if (sheetId != 0)
2125 CEntitySheet *pItem = SheetMngr.get(CSheetId(sheetId));
2126 if ((pItem != NULL) && (pItem->Type == CEntitySheet::ITEM))
2128 CItemSheet *pIS = safe_cast<CItemSheet*>(pItem);
2129 vTemp[indexInList].Pos = toString("%02d", pIS->Family);
2130 vTemp[indexInList].Pos += toString("%03d", pIS->ItemType);
2132 // add some specific sort for raw material
2133 if (pIS->Family == ITEMFAMILY::RAW_MATERIAL)
2134 vTemp[indexInList].Pos += toString("%010d", pIS->Mp.ItemPartBF);
2135 else
2136 vTemp[indexInList].Pos += toString("%010d", 0);
2138 // add some specific sort for teleport
2139 if (pIS->Family == ITEMFAMILY::TELEPORT)
2140 vTemp[indexInList].Pos += toString("%02d%02d", pIS->ItemOrigin, pIS->Teleport.Type);
2141 else
2142 vTemp[indexInList].Pos += toString("%02d%02d", 0, 0);
2145 vTemp[indexInList].Pos += toString("%03d", quality);
2147 // add sort by name
2148 vTemp[indexInList].Pos += CSheetId(sheetId).toString();
2151 // add at last the index in DB. to avoid resort for items that are exaclty the same
2152 vTemp[indexInList].Pos += toString("%03d", indexInDB);
2157 // ***************************************************************************
2158 // Used for common options
2159 bool SBagOptions::parse(xmlNodePtr cur, CInterfaceGroup * /* parentGroup */)
2161 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2162 // read params
2163 CXMLAutoPtr prop;
2165 // value
2166 prop = xmlGetProp (cur, (xmlChar*)"inv_type");
2167 if (prop)
2169 InvType = CInventoryManager::invTypeFromString(prop.str());
2171 else
2173 InvType = CInventoryManager::InvUnknown;
2174 nlwarning("cannot find inventory type");
2177 prop = xmlGetProp (cur, (xmlChar*)"filter_armor");
2178 if (prop) DbFilterArmor = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2180 prop = xmlGetProp (cur, (xmlChar*)"filter_weapon");
2181 if (prop) DbFilterWeapon = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2183 prop = xmlGetProp (cur, (xmlChar*)"filter_tool");
2184 if (prop) DbFilterTool = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2186 prop = xmlGetProp (cur, (xmlChar*)"filter_pet");
2187 if (prop) DbFilterPet = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2189 prop = xmlGetProp (cur, (xmlChar*)"filter_mp");
2190 if (prop) DbFilterMP = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2192 prop = xmlGetProp (cur, (xmlChar*)"filter_missmp");
2193 if (prop) DbFilterMissMP = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2195 prop = xmlGetProp (cur, (xmlChar*)"filter_tp");
2196 if (prop) DbFilterTP = NLGUI::CDBManager::getInstance()->getDbProp(prop.str());
2198 return true;
2201 // ***************************************************************************
2202 void SBagOptions::setSearchFilter(const string &s)
2204 SearchQualityMin = 0;
2205 SearchQualityMax = 999;
2206 SearchFilter.clear();
2207 SearchFilterChanged = true;
2209 if (!s.empty())
2211 std::vector<string> words;
2212 splitString(toLower(s), string(" "), words);
2214 size_t pos;
2215 for(int i = 0; i<words.size(); ++i)
2217 std::string kw = words[i];
2219 pos = kw.find("-");
2220 if (pos != std::string::npos)
2222 uint16 first;
2223 uint16 last;
2224 if (fromString(kw.substr(0, pos), first))
2225 SearchQualityMin = first;
2227 if (fromString(kw.substr(pos+1), last))
2228 SearchQualityMax = last;
2230 if (first == 0 && last == 0)
2231 SearchFilter.push_back(words[i]);
2233 else
2234 SearchFilter.push_back(words[i]);
2239 // ***************************************************************************
2240 bool SBagOptions::isSomethingChanged()
2242 bool bRet = false;
2244 if (DbFilterArmor != NULL)
2245 if ((DbFilterArmor->getValue8() != 0) != LastDbFilterArmor)
2247 bRet = true;
2248 LastDbFilterArmor = (DbFilterArmor->getValue8() != 0);
2251 if (DbFilterWeapon != NULL)
2252 if ((DbFilterWeapon->getValue8() != 0) != LastDbFilterWeapon)
2254 bRet = true;
2255 LastDbFilterWeapon = (DbFilterWeapon->getValue8() != 0);
2258 if (DbFilterTool != NULL)
2259 if ((DbFilterTool->getValue8() != 0) != LastDbFilterTool)
2261 bRet = true;
2262 LastDbFilterTool = (DbFilterTool->getValue8() != 0);
2265 if (DbFilterPet != NULL)
2266 if ((DbFilterPet->getValue8() != 0) != LastDbFilterPet)
2268 bRet = true;
2269 LastDbFilterPet = (DbFilterPet->getValue8() != 0);
2272 if (DbFilterMP != NULL)
2273 if ((DbFilterMP->getValue8() != 0) != LastDbFilterMP)
2275 bRet = true;
2276 LastDbFilterMP = (DbFilterMP->getValue8() != 0);
2279 if (DbFilterMissMP != NULL)
2280 if ((DbFilterMissMP->getValue8() != 0) != LastDbFilterMissMP)
2282 bRet = true;
2283 LastDbFilterMissMP = (DbFilterMissMP->getValue8() != 0);
2286 if (DbFilterTP != NULL)
2287 if ((DbFilterTP->getValue8() != 0) != LastDbFilterTP)
2289 bRet = true;
2290 LastDbFilterTP = (DbFilterTP->getValue8() != 0);
2293 if (SearchFilterChanged)
2295 bRet = true;
2296 SearchFilterChanged = false;
2299 return bRet;
2302 // ***************************************************************************
2303 bool SBagOptions::canDisplay(CDBCtrlSheet *pCS) const
2305 bool bDisplay = true;
2307 bool bFilterArmor = getFilterArmor();
2308 bool bFilterWeapon = getFilterWeapon();
2309 bool bFilterTool = getFilterTool();
2310 bool bFilterPet = getFilterPet();
2311 bool bFilterMP = getFilterMP();
2312 bool bFilterMissMP = getFilterMissMP();
2313 bool bFilterTP = getFilterTP();
2315 const CItemSheet *pIS = pCS->asItemSheet();
2316 if (pIS != NULL)
2318 if (SearchFilter.size() > 0)
2320 bool match = true;
2321 string lcName = toLower(pCS->getItemActualName());
2323 // add item quality as a keyword to match
2324 if (pCS->getQuality() > 1)
2326 lcName += string(" " + toString(pCS->getQuality()));
2329 for (uint i = 0; i< SearchFilter.size(); ++i)
2331 if (lcName.find(SearchFilter[i]) == string::npos)
2333 return false;
2338 // Quality range
2339 if (SearchQualityMin > pCS->getQuality() || SearchQualityMax < pCS->getQuality())
2340 return false;
2342 // Armor
2343 if ((pIS->Family == ITEMFAMILY::ARMOR) ||
2344 (pIS->Family == ITEMFAMILY::JEWELRY))
2345 if (!bFilterArmor) bDisplay = false;
2347 // Weapon
2348 if ((pIS->Family == ITEMFAMILY::SHIELD) ||
2349 (pIS->Family == ITEMFAMILY::MELEE_WEAPON) ||
2350 (pIS->Family == ITEMFAMILY::RANGE_WEAPON) ||
2351 (pIS->Family == ITEMFAMILY::AMMO) ||
2352 (pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ||
2353 (pIS->Family == ITEMFAMILY::ITEM_SAP_RECHARGE) ||
2354 (pIS->Family == ITEMFAMILY::BRICK) )
2355 if (!bFilterWeapon) bDisplay = false;
2357 // Tool
2358 if ((pIS->Family == ITEMFAMILY::CRAFTING_TOOL) ||
2359 (pIS->Family == ITEMFAMILY::HARVEST_TOOL) ||
2360 (pIS->Family == ITEMFAMILY::TAMING_TOOL) ||
2361 (pIS->Family == ITEMFAMILY::TRAINING_TOOL) ||
2362 (pIS->Family == ITEMFAMILY::BAG))
2363 if (!bFilterTool) bDisplay = false;
2365 // Pet
2366 if (pIS->Family == ITEMFAMILY::PET_ANIMAL_TICKET)
2367 if (!bFilterPet) bDisplay = false;
2369 // MP
2370 if ((pIS->Family == ITEMFAMILY::RAW_MATERIAL) && pIS->canBuildSomeItemPart())
2371 if (!bFilterMP) bDisplay = false;
2373 // Mission MP
2374 if ((pIS->Family == ITEMFAMILY::MISSION_ITEM) ||
2375 (pIS->Family == ITEMFAMILY::XP_CATALYSER) ||
2376 (pIS->Family == ITEMFAMILY::CONSUMABLE) ||
2377 ((pIS->Family == ITEMFAMILY::RAW_MATERIAL) && !pIS->canBuildSomeItemPart()))
2378 if (!bFilterMissMP) bDisplay = false;
2380 // Teleporter Pacts
2381 if ((pIS->Family == ITEMFAMILY::TELEPORT))
2382 if (!bFilterTP) bDisplay = false;
2384 // Jobs Items
2385 if (pIS->Id.toString().substr(0, 6) == "rpjob_")
2386 bDisplay = false;
2389 return bDisplay;
2392 // ***************************************************************************
2393 // CDBGroupListSheetBag
2394 // ***************************************************************************
2397 // ***************************************************************************
2398 bool CDBGroupListSheetBag::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
2400 if(!CDBGroupListSheetText::parse(cur, parentGroup))
2401 return false;
2403 // Parse options (type, filters ...)
2404 if (!_BO.parse(cur,parentGroup))
2405 return false;
2407 return true;
2410 // ***************************************************************************
2411 void CDBGroupListSheetBag::checkCoords ()
2413 CDBGroupListSheetText::checkCoords();
2414 if (_BO.isSomethingChanged())
2415 invalidateCoords();
2418 // ***************************************************************************
2419 void CDBGroupListSheetBag::CSheetChildBag::updateViewText(CDBGroupListSheetText * /* pFather */)
2421 // common method to update text as item
2422 updateViewTextAsItem();
2425 // ***************************************************************************
2426 bool CDBGroupListSheetBag::CSheetChildBag::isSheetValid(CDBGroupListSheetText *pFather)
2428 if (CSheetChild::isSheetValid(pFather))
2430 // Check if the control match the filters !
2431 CDBGroupListSheetBag *pList = dynamic_cast<CDBGroupListSheetBag*>(pFather);
2432 if (pList)
2433 return pList->canDisplay(Ctrl);
2435 return false;
2438 // ***************************************************************************
2439 void CDBGroupListSheetBag::CSheetChildBag::init(CDBGroupListSheetText *pFather, uint index)
2441 // init my parent
2442 CSheetChild::init(pFather, index);
2444 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2446 // **** Bind the quality
2448 // Basic quality
2449 string db= Ctrl->getSheet()+":QUALITY";
2450 if( NLGUI::CDBManager::getInstance()->getDbProp(db, false) )
2451 CurrentQuality.link ( db.c_str() );
2452 else
2454 // dummy link to ui:.....
2455 CurrentQuality.link("UI:DUMMY:QUALITY");
2456 CurrentQuality.setSInt32(0);
2461 // ***************************************************************************
2462 bool CDBGroupListSheetBag::CSheetChildBag::isInvalidated(CDBGroupListSheetText * /* pFather */)
2464 // quality change
2465 if( CurrentQuality.getSInt32() != LastQuality )
2466 return true;
2468 return false;
2471 // ***************************************************************************
2472 void CDBGroupListSheetBag::CSheetChildBag::update(CDBGroupListSheetText * /* pFather */)
2474 LastQuality= CurrentQuality.getSInt32();
2477 // ***************************************************************************
2478 void CDBGroupListSheetBag::onSwap (sint /* nDraggedSheet */, sint /* nDroppedSheet */)
2480 // No more used because automatic sort
2483 // ***************************************************************************
2484 void CDBGroupListSheetBag::sort()
2486 vector<SSortStruct> vTemp;
2488 vTemp.resize (_MaxItems);
2490 uint i;
2491 for (i = 0; i < _MaxItems; ++i)
2493 vTemp[i].SheetText = _SheetChildren[i];
2495 CDBCtrlSheet *ctrl= _SheetChildren[i]->Ctrl;
2496 initStructForItemSort (vTemp, ctrl->getSheetId(), ctrl->getQuality(), i, ctrl->getIndexInDB());
2499 std::sort(vTemp.begin(), vTemp.end());
2501 for (i = 0; i < _MaxItems; ++i)
2503 _SheetChildren[i] = vTemp[i].SheetText;
2507 // ***************************************************************************
2508 // CDBGroupIconListBag
2509 // ***************************************************************************
2511 // ***************************************************************************
2512 bool CDBGroupIconListBag::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
2514 if(!CDBGroupListSheet::parse(cur, parentGroup))
2515 return false;
2517 // Parse options (type, filters ...)
2518 if (!_BO.parse(cur,parentGroup))
2519 return false;
2521 return true;
2524 // ***************************************************************************
2525 void CDBGroupIconListBag::sort()
2527 vector<SSortStruct> vTemp;
2529 vTemp.resize (_MaxItems);
2531 uint i;
2532 for (i = 0; i < _MaxItems; ++i)
2534 vTemp[i].SheetIcon = _SheetChildren[i];
2536 CDBCtrlSheet *ctrl= _SheetChildren[i]->Ctrl;
2537 initStructForItemSort (vTemp, ctrl->getSheetId(), ctrl->getQuality(), i, ctrl->getIndexInDB());
2540 std::sort(vTemp.begin(), vTemp.end());
2542 for (i = 0; i < _MaxItems; ++i)
2544 _SheetChildren[i] = vTemp[i].SheetIcon;
2548 // ***************************************************************************
2549 void CDBGroupIconListBag::checkCoords ()
2551 CDBGroupListSheet::checkCoords();
2552 if (_BO.isSomethingChanged())
2553 invalidateCoords();
2556 // ***************************************************************************
2557 bool CDBGroupIconListBag::CSheetChildBag::isSheetValid(CDBGroupListSheet *pFather)
2559 if (CSheetChild::isSheetValid(pFather))
2561 // Check if the control match the filters !
2562 CDBGroupIconListBag *pList = dynamic_cast<CDBGroupIconListBag*>(pFather);
2563 if (pList)
2564 return pList->canDisplay(Ctrl);
2566 return false;
2571 // ***************************************************************************
2572 // CDBGroupListSheetFilterCLMSlot
2573 // ***************************************************************************
2575 // ***************************************************************************
2576 bool CDBGroupListSheetFilterCLMSlot::CSheetChildFilter::isSheetValid(CDBGroupListSheet *pFather)
2578 if (CSheetChild::isSheetValid(pFather))
2580 /* This filter look the ctrl who launch the modal where this list is displayed.
2581 If we can drop this ChildCtrl, on the CLM control, then ok, filtered
2582 Plus the ChildControl must not be locked
2584 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2585 CDBCtrlSheet *clmCtrl = dynamic_cast<CDBCtrlSheet*>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
2586 if (!clmCtrl || !Ctrl) return false;
2587 if (clmCtrl->getInventoryIndex() == INVENTORIES::exchange &&
2588 Ctrl->getInventoryIndex() == INVENTORIES::exchange)
2590 return false;
2592 if ((clmCtrl->getType() == CCtrlSheetInfo::SheetType_Item) &&
2593 (Ctrl->getType() == CCtrlSheetInfo::SheetType_Item) )
2595 // Ok if we can put in the slot Ctrl in clmCtrl
2596 if ( clmCtrl->canDropItem(Ctrl))
2598 string sTmp = Ctrl->getSheet();
2599 // Look if the source is locked
2600 sTmp = sTmp.substr(sTmp.rfind(':')+1,sTmp.size());
2601 sint32 nTmp;
2602 fromString(sTmp, nTmp);
2603 if (!getInventory().isBagItemWeared(nTmp))
2604 return true;
2608 return false;
2611 // ***************************************************************************
2612 // CDBGroupListSheetFilterExchangeable
2613 // ***************************************************************************
2615 // ***************************************************************************
2616 bool CDBGroupListSheetFilterExchangeable::CSheetChildFilter::isSheetValid(CDBGroupListSheet *pFather)
2618 if (CSheetChild::isSheetValid(pFather))
2620 if(!Ctrl)
2621 return false;
2622 extern bool checkCanExchangeItem(CDBCtrlSheet *);
2623 return checkCanExchangeItem(Ctrl);
2625 return false;
2628 // ***************************************************************************
2629 void CDBGroupListSheetFilterExchangeable::sort()
2631 vector<SSortStruct> vTemp;
2633 vTemp.resize (_MaxItems);
2635 uint i;
2636 for (i = 0; i < _MaxItems; ++i)
2638 vTemp[i].SheetIcon = _SheetChildren[i];
2640 CDBCtrlSheet *ctrl= _SheetChildren[i]->Ctrl;
2641 initStructForItemSort (vTemp, ctrl->getSheetId(), ctrl->getQuality(), i, ctrl->getIndexInDB());
2644 std::sort(vTemp.begin(), vTemp.end());
2646 for (i = 0; i < _MaxItems; ++i)
2648 _SheetChildren[i] = vTemp[i].SheetIcon;
2652 // ***************************************************************************
2653 bool CDBGroupListSheetFilterExchangeable::parse(xmlNodePtr cur, CInterfaceGroup *parentGroup)
2655 if(!CDBGroupListSheet::parse(cur, parentGroup))
2656 return false;
2658 // Parse options (type, filters ...)
2659 if (!_BO.parse(cur,parentGroup))
2660 return false;
2662 return true;
2665 // ***************************************************************************
2666 // ***************************************************************************
2667 // ***************************************************************************
2668 // ACTION HANDLERS
2669 // ***************************************************************************
2670 // ***************************************************************************
2671 // ***************************************************************************
2673 // ***************************************************************************
2674 // COMMON INVENTORIES DRAG'N'DROP
2675 // ***************************************************************************
2677 // ***************************************************************************
2678 class CHandlerInvCanDrag : public IActionHandler
2680 virtual void execute (CCtrlBase *pCaller, const string &/* Params */)
2682 CDBCtrlSheet *pCSSrc = dynamic_cast<CDBCtrlSheet*>(pCaller);
2683 if (pCSSrc == NULL) return;
2685 // Cannot drag an item if it is completely locked
2686 if (pCSSrc->getNonLockedQuantity() == 0)
2688 pCSSrc->setTempCanDrag(false);
2689 return;
2692 // If the item comes from an animal list which is not available -> cannot move
2693 if (strnicmp(pCSSrc->getSheet().c_str(), "LOCAL:INVENTORY:PACK_ANIMAL", 27) == 0)
2695 string sTmp = pCSSrc->getSheet().substr(0, pCSSrc->getSheet().rfind(':'));
2696 sTmp = sTmp.substr(27,sTmp.size());
2697 uint32 nAni;
2698 fromString(sTmp, nAni);
2699 INVENTORIES::TInventory inv = (INVENTORIES::TInventory)(INVENTORIES::pet_animal+nAni);
2700 pCSSrc->setTempCanDrag(getInventory().isInventoryAvailable(inv));
2704 REGISTER_ACTION_HANDLER( CHandlerInvCanDrag, "inv_can_drag" );
2706 // ***************************************************************************
2707 class CHandlerInvDrag : public IActionHandler
2709 virtual void execute (CCtrlBase *pCaller, const string &Params)
2711 CDBCtrlSheet *pCS = dynamic_cast<CDBCtrlSheet*>(pCaller);
2712 if (pCS == NULL) return;
2713 if (Params == "from_text_list")
2714 getInventory().beginDrag(pCS, CInventoryManager::TextList);
2715 else if (Params == "from_slot")
2716 getInventory().beginDrag(pCS, CInventoryManager::Slot);
2717 else if (Params == "from_icon_list")
2718 getInventory().beginDrag(pCS, CInventoryManager::IconList);
2719 else
2720 nlwarning("DND not binded");
2723 REGISTER_ACTION_HANDLER( CHandlerInvDrag, "inv_drag" );
2725 // ***************************************************************************
2726 // show/hide edit box, set keyboard focus if 'show'
2727 class CHandlerInvSearchButton : public IActionHandler
2729 virtual void execute (CCtrlBase *pCaller, const string &sParams)
2731 if (sParams.empty())
2733 nlwarning("inv_search_button: missing edit box shortid");
2734 return;
2737 CCtrlBaseButton* btn = dynamic_cast<CCtrlBaseButton *>(pCaller);
2738 if (!btn)
2740 nlwarning("inv_search_button pCaller == NULL, caller must be CCtrlBaseButton with 'toggle_button' type");
2741 return;
2744 string filter;
2745 std::string id = btn->getParent()->getId() + ":" + sParams + ":eb";
2746 CGroupEditBox *eb = dynamic_cast<CGroupEditBox*>(CWidgetManager::getInstance()->getElementFromId(id));
2747 if (!eb)
2749 nlwarning("inv_search_button: editbox (%s) not found\n", id.c_str());
2750 return;
2753 eb->getParent()->setActive(btn->getPushed());
2754 if (eb->getParent()->getActive())
2756 CWidgetManager::getInstance()->setCaptureKeyboard(eb);
2757 eb->setSelectionAll();
2758 filter = eb->getInputString();
2761 CDBGroupListSheetBag *pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(btn->getParent()->getId() + ":bag_list"));
2762 if (pList != NULL) pList->setSearchFilter(filter);
2764 CDBGroupIconListBag *pIcons = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(btn->getParent()->getId() + ":bag_icons"));
2765 if (pIcons != NULL) pIcons->setSearchFilter(filter);
2768 REGISTER_ACTION_HANDLER( CHandlerInvSearchButton, "inv_search_button" );
2770 // ***************************************************************************
2771 // if :eb is empty then hide edit box, unpush search button
2772 class CHandlerInvSearchUnfocus : public IActionHandler
2774 virtual void execute (CCtrlBase *pCaller, const string &sParams)
2776 if (!pCaller) return;
2778 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(pCaller);
2779 if (!eb || !eb->getInputString().empty()) return;
2781 // ui:interface:inventory:content:bag:iil:inv_query_eb:eb
2782 std::string id = pCaller->getParent()->getParent()->getId() + ":" + sParams;
2783 CCtrlBaseButton *btn = dynamic_cast<CCtrlBaseButton*>(CWidgetManager::getInstance()->getElementFromId(id));
2784 if (btn) btn->setPushed(false);
2786 // hide :inv_query_eb
2787 pCaller->getParent()->setActive(false);
2789 // clear filter
2790 CAHManager::getInstance()->runActionHandler("inv_set_search", pCaller, "");
2793 REGISTER_ACTION_HANDLER( CHandlerInvSearchUnfocus, "inv_search_unfocus" );
2795 // **********************************************************************************************************
2796 // set inventory search string
2797 class CHandlerInvSetSearch : public IActionHandler
2799 void execute (CCtrlBase *pCaller, const std::string &sParams)
2801 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(pCaller);
2802 if (!eb) return;
2804 // ui:interface:inventory:content:bag:iil:inv_query_eb:eb
2805 std::string id = pCaller->getParent()->getParent()->getId();
2807 CDBGroupListSheetBag *pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(id + ":bag_list"));
2808 if (pList != NULL) pList->setSearchFilter(eb->getInputString());
2810 CDBGroupIconListBag *pIcons = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(id + ":bag_icons"));
2811 if (pIcons != NULL) pIcons->setSearchFilter(eb->getInputString());
2814 REGISTER_ACTION_HANDLER( CHandlerInvSetSearch, "inv_set_search" );
2816 // ***************************************************************************
2817 // COMMON INVENTORIES Test if we can drop an item to a slot or a list
2818 class CHandlerInvCanDropTo : public IActionHandler
2820 virtual void execute (CCtrlBase *pCaller, const string &Params)
2822 // pCSSrc is the current dragged item
2823 // pCSDst is a slot or a list
2825 CInventoryManager *pInv = CInventoryManager::getInstance();
2826 if (!pInv->isDragging()) return; // To prevent other things to happens
2828 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2829 string src = getParam(Params, "src");
2830 CInterfaceElement *pElt = CWidgetManager::getInstance()->getElementFromId(src);
2831 CDBCtrlSheet *pCSSrc = dynamic_cast<CDBCtrlSheet*>(pElt);
2832 if (pCSSrc == NULL) return; // Cannot do anything if the incoming sheet is not a sheet
2834 // Special case if we want to DND an animal representation
2835 // -------------------------------------------------------
2837 const CItemSheet *pIS = pCSSrc->asItemSheet();
2838 if ((pIS != NULL) && (pIS->Family == ITEMFAMILY::PET_ANIMAL_TICKET))
2840 CDBCtrlSheet *pCSDst = dynamic_cast<CDBCtrlSheet*>(pCaller);
2841 if (pCSDst != NULL)
2843 // The destination must be exchange or gift
2844 if (strnicmp(pCSDst->getSheet().c_str(),"LOCAL:EXCHANGE:GIVE", 19) == 0)
2846 // The animal bag must be empty before giving it
2847 if (pIS->Pet.Slot > 0)
2848 if (pInv->isInventoryEmpty((INVENTORIES::TInventory)(INVENTORIES::pet_animal+(pIS->Pet.Slot-1))))
2849 pCSDst->setCanDrop (true);
2851 // Or moving in the bag (user sort)
2852 if (strnicmp(pCSDst->getSheet().c_str(),"LOCAL:INVENTORY:BAG", 19) == 0)
2853 pCSDst->setCanDrop (true);
2855 return;
2859 // The destination is a slot or something like that ?
2860 // --------------------------------------------------
2861 CDBCtrlSheet *pCSDst = dynamic_cast<CDBCtrlSheet*>(pCaller);
2862 if (pCSDst != NULL)
2864 // If we want to drop something on a reference slot (hand or equip)
2865 if (!pInv->getDBIndexPath(pCSDst).empty())
2867 // We must drag'n'drop an item
2868 if (pCSSrc && pCSSrc->getType() == CCtrlSheetInfo::SheetType_Item)
2869 if (pCSDst && pCSDst->getType() == CCtrlSheetInfo::SheetType_Item)
2871 if (!pInv->getDBIndexPath(pCSSrc).empty())
2873 // The item dragged comes from a slot check if this is the good type
2874 if (pCSDst->canDropItem(pCSSrc))
2875 pCSDst->setCanDrop ( true );
2877 else
2879 // The source must be from the bag
2880 if (strnicmp(pCSSrc->getSheet().c_str(),"LOCAL:INVENTORY:BAG", 19) == 0)
2881 pCSDst->setCanDrop ( true );
2885 else
2887 // Does the source and destination are items ?
2888 if (pCSSrc && pCSSrc->getType() == CCtrlSheetInfo::SheetType_Item)
2889 if (pCSDst && pCSDst->getType() == CCtrlSheetInfo::SheetType_Item)
2891 // Right Slot ?
2892 if (pCSDst->canDropItem(pCSSrc))
2893 pCSDst->setCanDrop ( true );
2896 return;
2899 // The destination is a list of items ?
2900 // ------------------------------------
2901 CDBGroupListSheetBag *pListDstText = dynamic_cast<CDBGroupListSheetBag*>(pCaller);
2902 CDBGroupIconListBag *pListDstIcon = dynamic_cast<CDBGroupIconListBag*>(pCaller);
2903 if ((pListDstText != NULL) || (pListDstIcon != NULL))
2905 bool bCanDrop = true;
2906 // WE CANT DND if we want to dnd from other bag than BAG to guild bag
2907 if (pListDstIcon != NULL)
2909 if (pListDstIcon->getInvType() == CInventoryManager::InvGuild)
2910 if (strnicmp(pCSSrc->getSheet().c_str(),"LOCAL:INVENTORY:BAG", 19) != 0)
2911 bCanDrop = false;
2913 if (pListDstText != NULL)
2915 if (pListDstText->getInvType() == CInventoryManager::InvGuild)
2916 if (strnicmp(pCSSrc->getSheet().c_str(),"LOCAL:INVENTORY:BAG", 19) != 0)
2917 bCanDrop = false;
2919 // WE CANT DND if we want to dnd from guild bag to other bag than BAG
2920 if (pListDstIcon != NULL)
2922 if (pListDstIcon->getInvType() != CInventoryManager::InvBag)
2923 if (strnicmp(pCSSrc->getSheet().c_str(),"SERVER:GUILD:INVENTORY", 19) == 0)
2924 bCanDrop = false;
2926 if (pListDstText != NULL)
2928 if (pListDstText->getInvType() != CInventoryManager::InvBag)
2929 if (strnicmp(pCSSrc->getSheet().c_str(),"SERVER:GUILD:INVENTORY", 19) == 0)
2930 bCanDrop = false;
2933 // WE CANT DND when packer/mount is too far
2934 if (pListDstIcon != NULL)
2936 if ((pListDstIcon->getInvType() == CInventoryManager::InvPA0) ||
2937 (pListDstIcon->getInvType() == CInventoryManager::InvPA1) ||
2938 (pListDstIcon->getInvType() == CInventoryManager::InvPA2) ||
2939 (pListDstIcon->getInvType() == CInventoryManager::InvPA3) ||
2940 (pListDstIcon->getInvType() == CInventoryManager::InvPA4) ||
2941 (pListDstIcon->getInvType() == CInventoryManager::InvPA5) ||
2942 (pListDstIcon->getInvType() == CInventoryManager::InvPA6))
2944 INVENTORIES::TInventory e = (INVENTORIES::TInventory)(INVENTORIES::pet_animal1 + (pListDstIcon->getInvType()-CInventoryManager::InvPA0));
2945 if (!pInv->isInventoryAvailable(e))
2946 bCanDrop = false;
2949 if (pListDstText != NULL)
2951 if ((pListDstText->getInvType() == CInventoryManager::InvPA0) ||
2952 (pListDstText->getInvType() == CInventoryManager::InvPA1) ||
2953 (pListDstText->getInvType() == CInventoryManager::InvPA2) ||
2954 (pListDstText->getInvType() == CInventoryManager::InvPA3) ||
2955 (pListDstText->getInvType() == CInventoryManager::InvPA4) ||
2956 (pListDstText->getInvType() == CInventoryManager::InvPA5) ||
2957 (pListDstText->getInvType() == CInventoryManager::InvPA6))
2959 INVENTORIES::TInventory e = (INVENTORIES::TInventory)(INVENTORIES::pet_animal1 + (pListDstText->getInvType()-CInventoryManager::InvPA0));
2960 if (!pInv->isInventoryAvailable(e))
2961 bCanDrop = false;
2965 // If the source is the equipment
2967 if (pListDstText != NULL) pListDstText->setCanDrop(bCanDrop);
2968 if (pListDstIcon != NULL) pListDstIcon->setCanDrop(bCanDrop);
2973 REGISTER_ACTION_HANDLER( CHandlerInvCanDropTo, "inv_can_drop" );
2975 // ***************************************************************************
2976 class CHandlerInvDropTo : public IActionHandler
2978 virtual void execute (CCtrlBase *pCaller, const string &Params)
2980 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2982 // Check that we have drag'n'drop from inventory (list or slot)
2983 // Or if we have launched the choose_bag modal
2984 // To prevent other things to happens
2985 if (!getInventory().isDragging())
2987 CInterfaceGroup *pIG = CWidgetManager::getInstance()->getModalWindow();
2988 if (pIG == NULL) return;
2989 if (pIG->getId() != "ui:interface:bag_choose") return;
2990 getInventory().beginDrag(NULL, CInventoryManager::TextList);
2992 // Special case for choose in bag dialog
2993 string src = getParam(Params, "src");
2994 CInterfaceElement *pElt = CWidgetManager::getInstance()->getElementFromId(src);
2995 CDBCtrlSheet *pCSSrc = dynamic_cast<CDBCtrlSheet*>(pElt);
2996 CDBCtrlSheet *pCSDst = dynamic_cast<CDBCtrlSheet*>(pCaller);
2998 string invPath = getInventory().getDBIndexPath(pCSSrc);
2999 string bagPath = pCSDst->getSheet();
3001 if (bagPath == "UI:EMPTY")
3002 getInventory().unequip (invPath);
3003 else
3004 getInventory().equip (bagPath, invPath);
3006 getInventory().endDrag();
3007 return;
3010 string src = getParam(Params, "src");
3011 CInterfaceElement *pElt = CWidgetManager::getInstance()->getElementFromId(src);
3012 CDBCtrlSheet *pCSSrc = dynamic_cast<CDBCtrlSheet*>(pElt);
3013 CDBCtrlSheet *pCSDst = dynamic_cast<CDBCtrlSheet*>(pCaller);
3014 if (pCSSrc == NULL) return;
3016 // Is the dragged sheet comes from an inventory list
3017 if (getInventory().isDraggingFromTextList() || getInventory().isDraggingFromIconList())
3019 // If the destination is an equipment slot ?
3020 if (pCSDst != NULL)
3022 string invPath = getInventory().getDBIndexPath(pCSDst); // Get the index in the equipment
3023 if (!invPath.empty())
3025 // Drop to the slot ie write the database with the index of the slot
3026 string bagPath = pCSSrc->getSheet(); // Get the database branch of the dragged sheet
3028 if (pCSSrc && pCSSrc->getType() == CCtrlSheetInfo::SheetType_Item)
3029 if (pCSDst && pCSDst->getType() == CCtrlSheetInfo::SheetType_Item)
3031 // If the destination slot match with the type of incoming item
3032 if (pCSDst->canDropItem(pCSSrc))
3034 // So directly equip
3035 getInventory().equip(bagPath, invPath);
3037 else
3039 // Else try to auto equip the player with the incoming item
3040 const string sTmp = bagPath.substr(bagPath.rfind(':')+1,bagPath.size());
3041 sint index;
3042 fromString(sTmp, index);
3043 if (!getInventory().autoEquip(index, false))
3044 getInventory().autoEquip(index, true);
3047 getInventory().endDrag();
3048 return;
3052 // If the destination is a list sheet
3053 IListSheetBase *pListDst = dynamic_cast<IListSheetBase*>(pCaller);
3054 if ((pListDst == NULL) && (pCSDst != NULL))
3055 pListDst = IListSheetBase::getListContaining(pCSDst);
3056 IListSheetBase *pListSrc = IListSheetBase::getListContaining(pCSSrc);
3057 if ((pListDst != NULL) && (pListSrc != NULL))
3059 // If the source list and destination list are the same
3060 if (pListDst == pListSrc)
3062 // no op
3063 getInventory().endDrag();
3064 return;
3066 else // Source list and destination list are not the same
3068 // Move the item to the destination list using the procedure move_to_xxx
3069 CDBGroupListSheetBag *pListDstText = dynamic_cast<CDBGroupListSheetBag*>(pListDst);
3070 CDBGroupIconListBag *pListDstIcon = dynamic_cast<CDBGroupIconListBag*>(pListDst);
3072 if (((pListDstText != NULL) && (pListDstText->getInvType() == CInventoryManager::InvBag)) ||
3073 ((pListDstIcon != NULL) && (pListDstIcon->getInvType() == CInventoryManager::InvBag)))
3075 CAHManager::getInstance()->runActionHandler("proc", pCSSrc, "move_to_bag");
3077 else if (((pListDstText != NULL) && ((pListDstText->getInvType() == CInventoryManager::InvPA0) ||
3078 (pListDstText->getInvType() == CInventoryManager::InvPA1) ||
3079 (pListDstText->getInvType() == CInventoryManager::InvPA2) ||
3080 (pListDstText->getInvType() == CInventoryManager::InvPA3) ||
3081 (pListDstText->getInvType() == CInventoryManager::InvPA4) ||
3082 (pListDstText->getInvType() == CInventoryManager::InvPA5) ||
3083 (pListDstText->getInvType() == CInventoryManager::InvPA6)
3084 )) ||
3085 ((pListDstIcon != NULL) && ((pListDstIcon->getInvType() == CInventoryManager::InvPA0) ||
3086 (pListDstIcon->getInvType() == CInventoryManager::InvPA1) ||
3087 (pListDstIcon->getInvType() == CInventoryManager::InvPA2) ||
3088 (pListDstIcon->getInvType() == CInventoryManager::InvPA3) ||
3089 (pListDstIcon->getInvType() == CInventoryManager::InvPA4) ||
3090 (pListDstIcon->getInvType() == CInventoryManager::InvPA5) ||
3091 (pListDstIcon->getInvType() == CInventoryManager::InvPA6)
3094 string sTmp;
3095 if (pListDstText != NULL) sTmp = toString("%d",pListDstText->getInvType()-CInventoryManager::InvPA0);
3096 if (pListDstIcon != NULL) sTmp = toString("%d",pListDstIcon->getInvType()-CInventoryManager::InvPA0);
3097 nlinfo("ici :%s", sTmp.c_str());
3098 CAHManager::getInstance()->runActionHandler("proc", pCSSrc, "move_to_pa|"+sTmp);
3100 else if (((pListDstText != NULL) && (pListDstText->getInvType() == CInventoryManager::InvGuild)) ||
3101 ((pListDstIcon != NULL) && (pListDstIcon->getInvType() == CInventoryManager::InvGuild)))
3103 if (strnicmp(pCSSrc->getSheet().c_str(), "LOCAL:INVENTORY:BAG", 19) == 0)
3104 CAHManager::getInstance()->runActionHandler("proc", pCSSrc, "move_to_guild");
3106 else if (((pListDstText != NULL) && (pListDstText->getInvType() == CInventoryManager::InvRoom)) ||
3107 ((pListDstIcon != NULL) && (pListDstIcon->getInvType() == CInventoryManager::InvRoom)))
3109 CAHManager::getInstance()->runActionHandler("proc", pCSSrc, "move_to_room");
3115 // Is the dragged sheet comes from another slot
3116 if (pCSDst != NULL)
3117 if (getInventory().isDraggingFromSlot())
3119 // Yes swap the 2 indices
3120 // Get the database branch of the dragged sheet
3121 string invPath1 = getInventory().getDBIndexPath(pCSSrc);
3122 // Get the index in the equipment
3123 string invPath2 = getInventory().getDBIndexPath(pCSDst);
3125 sint32 i1 = NLGUI::CDBManager::getInstance()->getDbProp(invPath1+":INDEX_IN_BAG")->getValue16();
3126 sint32 i2 = NLGUI::CDBManager::getInstance()->getDbProp(invPath2+":INDEX_IN_BAG")->getValue16();
3128 getInventory().unequip(invPath1);
3129 getInventory().unequip(invPath2);
3131 string sBag = LOCAL_INVENTORY ":BAG:";
3132 if (i2 != 0) getInventory().equip(sBag + toString(i2-1), invPath1);
3133 if (i1 != 0) getInventory().equip(sBag + toString(i1-1), invPath2);
3136 CAHManager::getInstance()->runActionHandler("inv_cannot_drop", pCSSrc);
3139 REGISTER_ACTION_HANDLER( CHandlerInvDropTo, "inv_drop" );
3142 // ***************************************************************************
3143 // EQUIPMENT
3144 class CHandlerInvCannotDrop : public IActionHandler
3146 virtual void execute (CCtrlBase *pCaller, const string &/* Params */)
3148 // Is the dragged sheet comes from a slot
3149 if (!getInventory().isDraggingFromTextList())
3151 // Unequip
3152 CDBCtrlSheet *pCSDst = dynamic_cast<CDBCtrlSheet*>(pCaller);
3153 string invPath = getInventory().getDBIndexPath(pCSDst);
3154 getInventory().unequip(invPath);
3156 getInventory().endDrag();
3159 REGISTER_ACTION_HANDLER( CHandlerInvCannotDrop, "inv_cannot_drop" );
3162 // ***************************************************************************
3163 class CHandlerInvAutoEquip : public IActionHandler
3165 public:
3166 virtual void execute (CCtrlBase *pCaller, const string &/* Params */)
3168 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
3169 if(cs)
3171 uint index= cs->getIndexInDB();
3172 if (!getInventory().autoEquip(index, false))
3173 getInventory().autoEquip(index, true);
3177 REGISTER_ACTION_HANDLER( CHandlerInvAutoEquip, "inv_auto_equip" );
3180 // **********************************************************************************************************
3181 class CHandlerLockInvItem : public IActionHandler
3183 void execute (CCtrlBase *pCaller, const std::string &sParams)
3185 // get the calling item
3186 CDBCtrlSheet *item = CDBCtrlSheet::getCurrSelSheet();
3187 if ( ! item)
3189 nlwarning("<CHandlerDestroyItem::execute> no caller sheet found");
3190 return;
3193 string lock = "1";
3194 if (item->getLockedByOwner())
3196 lock = "0";
3199 uint32 slot = item->getIndexInDB();
3200 uint32 inv = item->getInventoryIndex();
3201 INVENTORIES::TInventory inventory = INVENTORIES::UNDEFINED;
3202 inventory = (INVENTORIES::TInventory)(inv);
3203 if (inventory == INVENTORIES::UNDEFINED)
3205 return;
3207 NLMISC::ICommand::execute("a lockItem " + INVENTORIES::toString(inventory) + " " + toString(slot) + " " + lock, g_log);
3210 REGISTER_ACTION_HANDLER( CHandlerLockInvItem, "lock_inv_item" );
3212 // ***************************************************************************
3213 // Inventory Temporary
3214 // ***************************************************************************
3216 // ***************************************************************************
3217 class CHandlerInvTempToBag : public IActionHandler
3219 virtual void execute (CCtrlBase *pCaller, const string &/* Params */)
3221 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3223 // Disable the direct click on item in Forage mode and Can't take all
3224 if ( (CTempInvManager::getInstance()->getMode() == TEMP_INV_MODE::Forage) &&
3225 (NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:INVENTORY:TEMP:ENABLE_TAKE")->getValue32() == 0) )
3226 return;
3228 CDBCtrlSheet *pCSDst = dynamic_cast<CDBCtrlSheet*>(pCaller);
3229 if (!pCSDst->isSheetValid()) return;
3230 string sTmp = pCSDst->getSheet();
3232 sTmp = sTmp.substr(sTmp.rfind(':')+1, sTmp.size());
3233 uint16 index;
3234 fromString(sTmp, index);
3236 // If we cant find place display a message and dont send the request to the server
3237 if (!getInventory().isSpaceInAllBagsForItem(pCSDst))
3239 string msg = CI18N::get("msgCantPutItemInBag");
3240 string cat = getStringCategory(msg, msg);
3241 pIM->displaySystemInfo(msg, cat);
3242 return;
3245 sTmp = pCSDst->getSheet();
3246 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp+":SHEET",false);
3247 pNL->setValue32(0);
3249 CBitMemStream out;
3250 if (!GenericMsgHeaderMngr.pushNameToStream("ITEM:TEMP_TO_BAG", out))
3252 nlwarning ("don't know message name ITEM:TEMP_TO_BAG");
3254 else
3256 // Fill the message (temporary inventory slot)
3257 out.serial(index);
3258 NetMngr.push (out);
3259 //nlinfo("impulseCallBack : ITEM:TEMP_TO_BAG %d sent", index);
3263 REGISTER_ACTION_HANDLER( CHandlerInvTempToBag, "inv_temp_to_bag" );
3265 // ***************************************************************************
3266 class CHandlerInvTempAll : public IActionHandler
3268 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
3270 if (!CTempInvManager::getInstance()->isOpened()) return;
3271 if (NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP_INV:ALL_EMPTY")->getValue32() != 0) return;
3273 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3274 CInventoryManager *pInv = CInventoryManager::getInstance();
3276 // Try to put all items in the DB order in all the bags of the player : (bag, pa0-3, steed)
3277 vector <pair <double, double> > BagsBulk;
3278 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(0), pInv->getMaxBagBulk(0)));
3280 nlctassert(MAX_INVENTORY_ANIMAL==7);
3281 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal1))
3282 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(1), pInv->getMaxBagBulk(1)));
3283 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal2))
3284 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(2), pInv->getMaxBagBulk(2)));
3285 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal3))
3286 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(3), pInv->getMaxBagBulk(3)));
3287 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal4))
3288 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(4), pInv->getMaxBagBulk(4)));
3289 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal5))
3290 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(5), pInv->getMaxBagBulk(4)));
3291 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal6))
3292 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(6), pInv->getMaxBagBulk(4)));
3293 if (pInv->isInventoryAvailable(INVENTORIES::pet_animal7))
3294 BagsBulk.push_back(pair <double, double>(pInv->getBagBulk(7), pInv->getMaxBagBulk(4)));
3296 bool bPlaceFound = true;
3298 for (uint32 itemNb = 0; itemNb < MAX_TEMPINV_ENTRIES; ++itemNb)
3300 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":TEMP:" + toString(itemNb) + ":SHEET");
3301 CCDBNodeLeaf *pNLquantity = NLGUI::CDBManager::getInstance()->getDbProp(LOCAL_INVENTORY ":TEMP:" + toString(itemNb) + ":QUANTITY");
3302 if (pNL == NULL || pNLquantity == NULL) continue;
3303 if (pNL->getValue32() == 0 || pNLquantity->getValue32() == 0) continue;
3304 double itemBulk = pNLquantity->getValue32() * pInv->getItemBulk(pNL->getValue32());
3306 bool bLocalPlaceFound = false;
3307 for (uint32 i = 0; i < BagsBulk.size(); ++i)
3309 if ((BagsBulk[i].first + itemBulk) <= BagsBulk[i].second)
3311 BagsBulk[i].first += itemBulk;
3312 bLocalPlaceFound = true;
3313 break;
3316 if (!bLocalPlaceFound)
3318 bPlaceFound = false;
3319 break;
3323 if (!bPlaceFound)
3325 string msg = CI18N::get("msgCantPutItemInBag");
3326 string cat = getStringCategory(msg, msg);
3327 CInterfaceManager::getInstance()->displaySystemInfo(msg, cat);
3328 return;
3331 CBitMemStream out;
3332 if (!GenericMsgHeaderMngr.pushNameToStream("ITEM:ALL_TEMP", out))
3334 nlwarning ("don't know message name ITEM:ALL_TEMP");
3336 else
3338 NetMngr.push (out);
3339 //nlinfo("impulseCallBack : ITEM:ALL_TEMP sent");
3341 CTempInvManager::getInstance()->close();
3344 REGISTER_ACTION_HANDLER( CHandlerInvTempAll, "inv_temp_all" );
3346 // ***************************************************************************
3347 class CHandlerInvTempNone : public IActionHandler
3349 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
3351 CBitMemStream out;
3352 if (!GenericMsgHeaderMngr.pushNameToStream("ITEM:NO_TEMP", out))
3354 nlwarning ("don't know message name ITEM:NO_TEMP");
3356 else
3358 NetMngr.push (out);
3359 //nlinfo("impulseCallBack : ITEM:NO_TEMP sent");
3361 CTempInvManager::getInstance()->close();
3364 REGISTER_ACTION_HANDLER( CHandlerInvTempNone, "inv_temp_none" );
3367 // ***************************************************************************
3368 // ***************************************************************************
3369 // ItemInfo System
3370 // ***************************************************************************
3371 // ***************************************************************************
3373 // ***************************************************************************
3374 void CClientItemInfo::readFromImpulse(const CItemInfos &itemInfo)
3376 *(CItemInfos*)this= itemInfo;
3378 // Read now the version in the impulse
3379 InfoVersionFromMsg= itemInfo.versionInfo;
3382 // ***************************************************************************
3383 uint16 CInventoryManager::getItemSlotId(CDBCtrlSheet *ctrl)
3385 return getItemSlotId(ctrl->getSheet(), ctrl->getIndexInDB());
3388 // ***************************************************************************
3389 uint16 CInventoryManager::getItemSlotId(const std::string &itemDb, uint slotIndex)
3391 // then compare to all possible inventories (ugly)
3392 uint inventoryIndex= 0;
3393 for(uint i=0;i<NumInventories;i++)
3395 if( itemDb.find(InventoryDBs[i])!=string::npos )
3397 inventoryIndex= InventoryIndexes[i];
3398 break;
3402 // and compress the slotId
3403 return (inventoryIndex<<CItemInfos::SlotIdIndexBitSize) + slotIndex;
3406 // ***************************************************************************
3407 uint CInventoryManager::getItemSheetForSlotId(uint slotId) const
3409 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3411 // for all inventories
3412 for(uint i=0;i<NumInventories;i++)
3414 if( InventoryIndexes[i] == (slotId>>CItemInfos::SlotIdIndexBitSize) )
3416 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp( toString( "SERVER:%s:%d:SHEET", InventoryDBs[i].c_str(), (slotId&CItemInfos::SlotIdIndexBitMask)), false);
3417 if(node)
3418 return node->getValue32();
3419 else
3420 return 0;
3424 return 0;
3427 // ***************************************************************************
3428 const CClientItemInfo *CInventoryManager::getItemInfoCache(uint32 serial, uint32 createTime) const
3430 return _ItemInfoCache.getItemInfo(serial, createTime);
3433 // ***************************************************************************
3434 const CClientItemInfo &CInventoryManager::getItemInfo(uint slotId) const
3436 TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
3437 static CClientItemInfo empty;
3438 if (it == _ItemInfoMap.end() || !isItemInfoUpToDate(slotId))
3440 // if slot has not been populated yet or out of date, then return info from cache if possible
3441 const CItemImage *item = getServerItem(slotId);
3442 if (item && item->getItemId() > 0) {
3443 const CClientItemInfo *ret = _ItemInfoCache.getItemInfo(item->getItemId());
3444 if (ret != NULL)
3446 return *ret;
3451 if (it == _ItemInfoMap.end())
3453 return empty;
3456 return it->second;
3459 // ***************************************************************************
3460 bool CInventoryManager::isItemInfoAvailable(uint slotId) const
3462 TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
3463 return it != _ItemInfoMap.end();
3465 // ***************************************************************************
3466 bool CInventoryManager::isItemInfoUpToDate(uint slotId) const
3468 TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
3469 if (it == _ItemInfoMap.end())
3470 return true;
3472 // true if the version already matches
3473 return it->second.InfoVersionFromMsg == it->second.InfoVersionFromSlot;
3476 // ***************************************************************************
3477 void CInventoryManager::addItemInfoWaiter(IItemInfoWaiter *waiter)
3479 if(!waiter)
3480 return;
3482 // first remove the waiter if already here
3483 removeItemInfoWaiter(waiter);
3485 // Then push_front (stack)
3486 _ItemInfoWaiters.push_front(waiter);
3488 // update server msg
3489 updateItemInfoQueue();
3492 // ***************************************************************************
3493 void CInventoryManager::removeItemInfoWaiter(IItemInfoWaiter *waiter)
3495 TItemInfoWaiters::iterator it;
3496 for(it= _ItemInfoWaiters.begin();it!=_ItemInfoWaiters.end();it++)
3498 if(waiter==*it)
3500 _ItemInfoWaiters.erase(it);
3501 break;
3506 // ***************************************************************************
3507 void CInventoryManager::updateItemInfoWaiters(uint itemSlotId)
3509 // First verify if the versions matches. If differ, no need to update waiters since not good.
3510 if (!isItemInfoUpToDate(itemSlotId))
3512 return;
3515 bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading;
3517 // For all waiters that wait for this item slot
3518 TItemInfoWaiters::iterator it;
3519 for(it= _ItemInfoWaiters.begin();it!=_ItemInfoWaiters.end();)
3521 TItemInfoWaiters::iterator itNext=it;
3522 itNext++;
3523 IItemInfoWaiter *waiter=*it;
3524 // callback. NB: only ig the waiter agree the Sheet in the current slot id
3525 if(waiter->ItemSlotId == itemSlotId &&
3526 (isItemFromTrading || waiter->ItemSheet == getItemSheetForSlotId(itemSlotId)) )
3528 waiter->infoReceived();
3531 // in case it is erased in infoReceived()
3532 it= itNext;
3536 // ***************************************************************************
3537 void CInventoryManager::CItemInfoSlotVersionObs::update(ICDBNode* node)
3539 getInventory().onReceiveItemInfoSlotVersion(node);
3542 // ***************************************************************************
3543 void CInventoryManager::CItemSheetObs::update(ICDBNode* node)
3545 getInventory().onReceiveItemSheet(node);
3548 // ***************************************************************************
3549 void CInventoryManager::CItemInfoTradeObs::update(ICDBNode* /* node */)
3551 getInventory().onTradeChangeSession();
3554 // ***************************************************************************
3555 void CInventoryManager::onReceiveItemInfoSlotVersion(ICDBNode* node)
3557 uint itemSlotId;
3559 // valid only if of form 0:INFO_VERSION
3560 if( !dynamic_cast<CCDBNodeLeaf*>(node) || !node->getParent() || !node->getParent()->getName())
3561 return;
3563 // get the slot in inventory of the item
3564 uint slot;
3565 fromString(*node->getParent()->getName(), slot);
3567 // get the slotId for this DB
3568 itemSlotId= getItemSlotId(node->getFullName(), slot);
3570 // update the InfoVersionFromSlot
3571 _ItemInfoMap[itemSlotId].InfoVersionFromSlot= ((CCDBNodeLeaf*)node)->getValue8();
3573 // Look for Waiters that match this item slot => update
3574 updateItemInfoWaiters(itemSlotId);
3576 // new msg to send, because version updated?
3577 updateItemInfoQueue();
3580 // ***************************************************************************
3581 void CInventoryManager::onReceiveItemSheet(ICDBNode* node)
3583 // When a SHEET change, it may unblock some ITEM_INFO:GET calls or some info waiters update.
3584 uint itemSlotId;
3586 // valid only if of form 0:INFO_VERSION
3587 if( !dynamic_cast<CCDBNodeLeaf*>(node) || !node->getParent() || !node->getParent()->getName())
3588 return;
3590 // get the slot in inventory of the item
3591 uint slot;
3592 fromString(*node->getParent()->getName(), slot);
3594 // get the slotId for this DB
3595 itemSlotId= getItemSlotId(node->getFullName(), slot);
3597 // Look for Waiters that match this item slot => update
3598 updateItemInfoWaiters(itemSlotId);
3600 // new msg to send, because sheet ok?
3601 updateItemInfoQueue();
3604 // ***************************************************************************
3605 void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo)
3607 // update the Info
3608 uint itemSlotId = itemInfo.slotId;
3610 const CItemImage *item = getServerItem(itemSlotId);
3611 if (item && item->getItemId() > 0)
3613 _ItemInfoCache.readFromImpulse(item->getItemId(), itemInfo);
3616 // write in map, from DB.
3617 _ItemInfoMap[itemSlotId].readFromImpulse(itemInfo);
3619 // Look for Waiters that match this item slot => update
3620 updateItemInfoWaiters(itemSlotId);
3622 // new msg to send?
3623 updateItemInfoQueue();
3626 // ***************************************************************************
3627 void CInventoryManager::onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion)
3629 _ItemInfoMap[slotId].refreshInfoVersion(infoVersion);
3632 // ***************************************************************************
3633 void CInventoryManager::onTradeChangeSession()
3635 // Dummy set a 255 InfoVersionMsg for all items in trade. Because Server cannot do the code.
3636 for(uint i=0;i<TRADE_MAX_ENTRIES;i++)
3638 uint itemSlotId = getItemSlotId("TRADING", i);
3639 // Since InfoVersionFromSlot always == 0, a msg will be sent to have new version
3640 _ItemInfoMap[itemSlotId ].InfoVersionFromMsg= 255;
3641 _ItemInfoMap[itemSlotId ].InfoVersionSlotServerWaiting= 255;
3644 // new msg to send?
3645 updateItemInfoQueue();
3648 // ***************************************************************************
3649 void CInventoryManager::updateItemInfoQueue()
3651 if (!ConnectionReadySent) // CONNECTION:READY not yet sent, so we cannot send requests yet!
3653 // Caused by CNetworkConnection::reinit, and NLMISC::CCDBNodeBranch::resetData
3654 // TODO: Item sheets are effectively being set to 0, any way to detect this in particular?
3655 // Slots with sheet 0 won't have any info to request anyway!
3656 // Remove this check in favour of the assert lower down when properly implemented.
3657 nlwarning("Update item info queue (%i), but connection not ready", (int)_ItemInfoWaiters.size());
3658 return;
3661 // CONNECTION:READY not yet sent, so we cannot send requests yet!
3662 nlassert(ConnectionReadySent || !_ItemInfoWaiters.size());
3664 // For All waiters, look if one need update.
3665 TItemInfoWaiters::iterator it;
3666 for(it= _ItemInfoWaiters.begin();it!=_ItemInfoWaiters.end();it++)
3668 IItemInfoWaiter *waiter=*it;
3669 uint itemSlotId= waiter->ItemSlotId;
3670 TItemInfoMap::iterator it= _ItemInfoMap.find(itemSlotId);
3671 bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading;
3672 if(it!=_ItemInfoMap.end())
3674 CClientItemInfo &itemInfo= it->second;
3675 // If versions differ, and if a msg was not already sent to get the new version, then ask server
3676 // SheetId must also match
3677 if( itemInfo.InfoVersionFromSlot != itemInfo.InfoVersionFromMsg &&
3678 itemInfo.InfoVersionFromSlot != itemInfo.InfoVersionSlotServerWaiting &&
3679 ( isItemFromTrading || waiter->ItemSheet == getItemSheetForSlotId(itemSlotId)) )
3681 // Send a msg to server
3682 if(!ClientCfg.Local)
3684 CBitMemStream out;
3685 if (GenericMsgHeaderMngr.pushNameToStream("ITEM_INFO:GET", out))
3687 uint16 slotId= itemSlotId;
3688 out.serial( slotId );
3689 NetMngr.push(out);
3690 //nlinfo("impulseCallBack : ITEM_INFO:GET %d sent", slotId);
3692 else
3694 nlwarning(" unknown message name 'ITEM_INFO:GET'");
3697 // Debug
3698 else
3700 // debug:
3701 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3702 pIM->displaySystemInfo( toString("ITEM_INFO:GET, slotId: %d, slotVersion: %d",
3703 itemSlotId, itemInfo.InfoVersionFromSlot) );
3706 itemInfo.InfoVersionSlotServerWaiting= itemInfo.InfoVersionFromSlot;
3712 // ***************************************************************************
3713 void CInventoryManager::debugItemInfoWaiters()
3715 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3717 // For All waiters, log.
3718 TItemInfoWaiters::iterator it;
3719 for(it= _ItemInfoWaiters.begin();it!=_ItemInfoWaiters.end();it++)
3721 IItemInfoWaiter *waiter=*it;
3722 uint itemSlotId= waiter->ItemSlotId;
3723 TItemInfoMap::iterator itMap= _ItemInfoMap.find(itemSlotId);
3724 if(itMap!=_ItemInfoMap.end())
3726 CClientItemInfo &itemInfo= itMap->second;
3727 pIM->displaySystemInfo( toString("ItemInfoWaiter: slotId: %d, slotVersion: %d, msgVersion: %d, msgVersionWait: %d",
3728 itemSlotId, itemInfo.InfoVersionFromSlot, itemInfo.InfoVersionFromMsg, itemInfo.InfoVersionSlotServerWaiting) );
3733 // ***************************************************************************
3734 void CInventoryManager::debugItemInfoCache() const
3736 _ItemInfoCache.debugItemInfoCache();
3739 // ***************************************************************************
3740 void CInventoryManager::sortBag()
3742 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3743 CDBGroupIconListBag *pIconList;
3744 CDBGroupListSheetBag *pList;
3746 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_BAG_ICONS));
3747 if (pIconList != NULL) pIconList->needToSort();
3748 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_BAG_TEXT));
3749 if (pList != NULL) pList->needToSort();
3751 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_ROOM_ICONS));
3752 if (pIconList != NULL) pIconList->needToSort();
3753 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_ROOM_TEXT));
3754 if (pList != NULL) pList->needToSort();
3756 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_GUILD_ICONS));
3757 if (pIconList != NULL) pIconList->needToSort();
3758 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_GUILD_TEXT));
3759 if (pList != NULL) pList->needToSort();
3761 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA0_ICONS));
3762 if (pIconList != NULL) pIconList->needToSort();
3763 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA0_TEXT));
3764 if (pList != NULL) pList->needToSort();
3766 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA1_ICONS));
3767 if (pIconList != NULL) pIconList->needToSort();
3768 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA1_TEXT));
3769 if (pList != NULL) pList->needToSort();
3771 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA2_ICONS));
3772 if (pIconList != NULL) pIconList->needToSort();
3773 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA2_TEXT));
3774 if (pList != NULL) pList->needToSort();
3776 pIconList = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA3_ICONS));
3777 if (pIconList != NULL) pIconList->needToSort();
3778 pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(LIST_PA3_TEXT));
3779 if (pList != NULL) pList->needToSort();
3782 // ***************************************************************************
3783 bool CInventoryManager::isInventoryPresent(INVENTORIES::TInventory invId)
3785 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3787 // PA present?
3788 if(invId>=INVENTORIES::pet_animal && invId<INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
3790 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", invId-INVENTORIES::pet_animal), false);
3791 if(!node) return false;
3792 uint status= node->getValue32();
3794 return ANIMAL_STATUS::isSpawned((ANIMAL_STATUS::EAnimalStatus)status);
3796 else if (invId == INVENTORIES::guild)
3798 return (NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED", true)->getValue8() != 0);
3800 else if (invId == INVENTORIES::player_room)
3802 return (NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED", true)->getValue8() != 0);
3804 // other inventories (Bag...) are always present
3805 else
3806 return true;
3810 // ***************************************************************************
3811 bool CInventoryManager::isInventoryAvailable(INVENTORIES::TInventory invId)
3813 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3815 // PA available?
3816 if(invId>=INVENTORIES::pet_animal && invId<INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
3818 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", invId-INVENTORIES::pet_animal), false);
3819 if(!node) return false;
3820 uint status= node->getValue32();
3822 return ANIMAL_STATUS::isInventoryAvailable((ANIMAL_STATUS::EAnimalStatus)status);
3824 else if (invId == INVENTORIES::guild)
3826 return (NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED", true)->getValue8() != 0);
3828 else if (invId == INVENTORIES::player_room)
3830 return (NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED", true)->getValue8() != 0);
3832 // other inventories (Bag...) are always available
3833 else
3834 return true;
3837 // ***************************************************************************
3838 bool CInventoryManager::isInventoryEmpty(INVENTORIES::TInventory invId)
3840 if (!isInventoryPresent(invId)) return true;
3842 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3844 string sPath = "SERVER:INVENTORY";
3845 sint32 nNbEntries = 256;
3847 // PA present?
3848 if(invId>=INVENTORIES::pet_animal && invId<INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
3850 nNbEntries = MAX_ANIMALINV_ENTRIES;
3851 sPath += toString(":PACK_ANIMAL%d", invId-INVENTORIES::pet_animal);
3853 else if (invId == INVENTORIES::guild)
3855 nNbEntries = MAX_GUILDINV_ENTRIES;
3856 sPath += "GUILD";
3858 else if (invId == INVENTORIES::player_room)
3860 nNbEntries = MAX_ROOMINV_ENTRIES;
3861 sPath += "ROOM";
3863 else
3864 return true;
3867 for (uint32 i = 0; (sint)i < nNbEntries; ++i)
3869 CCDBNodeLeaf *pNL;
3870 pNL = NLGUI::CDBManager::getInstance()->getDbProp(sPath+toString(":%d:SHEET", i), false);
3871 if (pNL == NULL) return true;
3872 if (pNL->getValue32() != 0)
3873 return false;
3875 return true;
3878 // ***************************************************************************
3879 CItemImage &CInventoryManager::getPAItem(uint beastIndex, uint index)
3881 nlassert(beastIndex < MAX_INVENTORY_ANIMAL);
3882 nlassert(index < MAX_ANIMALINV_ENTRIES);
3883 return PAInv[beastIndex][index];
3886 // ***************************************************************************
3887 CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index)
3889 nlassert(beastIndex < MAX_INVENTORY_ANIMAL);
3890 nlassert(index < MAX_ANIMALINV_ENTRIES);
3891 return ServerPAInv[beastIndex][index];
3894 const CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index) const
3896 nlassert(beastIndex < MAX_INVENTORY_ANIMAL);
3897 nlassert(index < MAX_ANIMALINV_ENTRIES);
3898 return ServerPAInv[beastIndex][index];
3902 // ***************************************************************************
3903 CItemImage &CInventoryManager::getLocalItem(uint inv, uint index)
3905 if(inv==INVENTORIES::bag)
3906 return getBagItem(index);
3907 if(inv>=INVENTORIES::pet_animal && inv<INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
3908 return getPAItem(inv-INVENTORIES::pet_animal, index);
3910 nlstop;
3911 static CItemImage dummy;
3912 return dummy;
3915 // ***************************************************************************
3916 CItemImage &CInventoryManager::getServerItem(uint inv, uint index)
3918 if(inv==INVENTORIES::bag)
3919 return getServerBagItem(index);
3920 if(inv>=INVENTORIES::pet_animal && inv<INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
3921 return getServerPAItem(inv-INVENTORIES::pet_animal, index);
3923 nlstop;
3924 static CItemImage dummy;
3925 return dummy;
3928 // ***************************************************************************
3929 const CItemImage *CInventoryManager::getServerItem(uint slotId) const
3931 uint inv, index;
3932 getSlotInvIndex(slotId, inv, index);
3934 if (inv == INVENTORIES::bag)
3936 return &getServerBagItem(index);
3938 else if (inv >= INVENTORIES::pet_animal && inv <INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
3940 return &getServerPAItem(inv-INVENTORIES::pet_animal, index);
3942 else if (inv == INVENTORIES::temporary)
3944 return &getServerTempItem(index);
3946 else if (inv == INVENTORIES::guild)
3948 // player is in guild outpost or in guild hall
3949 if (getInventory().isInventoryAvailable(INVENTORIES::guild))
3951 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("SERVER:GUILD:INVENTORY:" + toString(index));
3952 if (itemBranch)
3954 static CItemImage image;
3955 image.build(itemBranch);
3956 return &image;
3959 return NULL;
3961 else if (inv == INVENTORIES::player_room)
3963 // player is in their room
3964 if (getInventory().isInventoryAvailable(INVENTORIES::player_room))
3966 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY ":ROOM:" + toString(index));
3967 if (itemBranch)
3969 static CItemImage image;
3970 image.build(itemBranch);
3971 return &image;
3974 return NULL;
3976 else if (inv == INVENTORIES::trading)
3978 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:TRADING:" + toString(index));
3979 if (itemBranch)
3981 static CItemImage image;
3982 image.build(itemBranch);
3983 return &image;
3986 else if (inv == INVENTORIES::exchange)
3988 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:GIVE:" + toString(index));
3989 if (itemBranch)
3991 static CItemImage image;
3992 image.build(itemBranch);
3993 return &image;
3996 else if (inv == INVENTORIES::exchange_proposition)
3998 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:RECEIVE:" + toString(index));
3999 if (itemBranch)
4001 static CItemImage image;
4002 image.build(itemBranch);
4003 return &image;
4006 else
4008 nlwarning("getServerItem: invalid inventory %d for slotId %d", inv, slotId);
4011 // invalid inventory
4012 return NULL;
4015 // ***************************************************************************
4016 CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &str)
4018 string sTmp = toLowerAscii(str);
4019 if (sTmp == "inv_bag") return InvBag;
4020 if (sTmp == "inv_pa0") return InvPA0;
4021 if (sTmp == "inv_pa1") return InvPA1;
4022 if (sTmp == "inv_pa2") return InvPA2;
4023 if (sTmp == "inv_pa3") return InvPA3;
4024 if (sTmp == "inv_pa4") return InvPA4;
4025 if (sTmp == "inv_pa5") return InvPA5;
4026 if (sTmp == "inv_pa6") return InvPA6;
4027 if (sTmp == "inv_guild") return InvGuild;
4028 if (sTmp == "inv_room") return InvRoom;
4029 return InvUnknown;
4032 // ***************************************************************************
4033 void CInventoryManager::getSlotInvIndex(uint slotId, uint &inv, uint &index) const
4035 inv = slotId >> CItemInfos::SlotIdIndexBitSize;
4036 index = slotId & CItemInfos::SlotIdIndexBitMask;