1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "item_group_manager.h"
23 #include "interface_v3/inventory_manager.h"
24 #include "nel/gui/widget_manager.h"
25 #include "nel/misc/sheet_id.h"
26 #include "nel/misc/stream.h"
27 #include "nel/misc/o_xml.h"
28 #include "nel/misc/i_xml.h"
29 #include "nel/misc/file.h"
30 #include "nel/misc/xml_macros.h"
31 #include "libxml/tree.h"
32 #include "game_share/item_type.h"
33 #include "client_sheets/item_sheet.h"
34 #include "net_manager.h"
35 #include "connection.h" // Used to access PlayerSelectedFileName for xml filename
36 #include "nel/gui/db_manager.h"
37 #include "interface_v3/interface_manager.h"
38 #include "nel/gui/group_menu.h"
39 #include "nel/misc/i18n.h"
40 #include "nel/misc/algo.h"
41 CItemGroupManager
*CItemGroupManager::_Instance
= NULL
;
43 CItemGroup::CItemGroup()
47 // return true if any item in the group match the parameter ; slot is UNDEFINED unless the item has been found in the group
48 bool CItemGroup::contains(CDBCtrlSheet
*pCS
)
50 for (int i
= 0; i
< items
.size(); i
++)
52 CItem item
= items
[i
];
53 if (item
.createTime
== pCS
->getItemCreateTime() && item
.serial
== pCS
->getItemSerial())
59 void CItemGroup::addSheet(CDBCtrlSheet
*pCS
, CSlot slot
, bool removeEmpty
)
64 if (pCS
->isSheetValid())
66 addItem(CItem(pCS
->getItemCreateTime(), pCS
->getItemSerial(), slot
));
74 void CItemGroup::addItem(CItem item
)
76 if (!item
.dstSlot
.isValid())
79 // Check if item already exists in group, this could happen if:
80 // 1. Creating a group with a 2-hand item (and the item is found both in handR and handL)
81 // 2. If user incorrectly edits the xml file
82 for (int i
= 0; i
< items
.size(); i
++)
84 CItem existingItem
= items
[i
];
85 if (existingItem
.createTime
== item
.createTime
&& existingItem
.serial
== item
.serial
)
87 nldebug("<CItemGroup::addItem> Not adding duplicate item, createTime: %d, serial: %d", item
.createTime
, item
.serial
);
88 // If duplicate item because of a 2-hand item:
89 // If it's existing as a left hand item, overwrite it as a right hand item instead (so we have only 1 correct item)
90 if (existingItem
.dstSlot
== CSlot::handSlot(1) && item
.dstSlot
== CSlot::handSlot(0))
91 existingItem
.dstSlot
= CSlot::handSlot(0);
96 items
.push_back(item
);
99 void CItemGroup::addRemoveSlot(CSlot slot
)
104 removeSlots
.push_back(slot
);
107 void CItemGroup::CItem::equip(uint32
&equipTime
)
111 nlwarning("<CItemGroup::CItem::equip> inv item is invalid");
115 if (!dstSlot
.isValid())
117 nlwarning("<CItemGroup::CItem::equip> item destination slot is invalid");
121 // if item is already equipped, and in the good slot, no need to equip
122 if (dstSlot
.getSheet()->isSheetEqual(pCS
))
127 // make sure the item can go into the slot (for example left-hand item can't always in left-hand slot)
128 // this is also checked on the server, but avoids visual glitch if checked on client too
129 if (!dstSlot
.getSheet()->canDropItem(pCS
))
131 nlwarning("<CItemGroup::CItem::equip> item %d can't be dropped in slot %s", pCS
->getSheetId(), dstSlot
.toDbPath().c_str());
135 std::string srcPath
= pCS
->getSheet();
136 equipTime
= std::max(equipTime
, pCS
->asItemSheet()->EquipTime
);
137 CInventoryManager::getInstance()->equip(srcPath
, dstSlot
.toDbPath());
140 // return if the item is already in it's destination slot
141 bool CItemGroup::CItem::isInDestinationSlot()
143 return dstSlot
.getSheet()->getInventoryIndex() == pCS
->getInventoryIndex() && dstSlot
.getSheet()->getIndexInDB() == pCS
->getIndexInDB();
146 void CItemGroup::CSlot::writeTo(xmlNodePtr node
)
148 xmlSetProp(node
, (const xmlChar
*)"branch", (const xmlChar
*)INVENTORIES::toString(branch
).c_str());
149 xmlSetProp(node
, (const xmlChar
*)"index", (const xmlChar
*)NLMISC::toString(index
).c_str());
152 void CItemGroup::CItem::writeTo(xmlNodePtr node
)
154 xmlSetProp(node
, (const xmlChar
*)"createTime", (const xmlChar
*)NLMISC::toString(createTime
).c_str());
155 xmlSetProp(node
, (const xmlChar
*)"serial", (const xmlChar
*)NLMISC::toString(serial
).c_str());
156 dstSlot
.writeTo(node
);
159 void CItemGroup::writeTo(xmlNodePtr node
)
161 xmlNodePtr groupNode
= xmlNewChild(node
, NULL
, (const xmlChar
*)"group", NULL
);
162 xmlSetProp(groupNode
, (const xmlChar
*)"name", (const xmlChar
*)name
.c_str());
163 for (int i
= 0; i
< items
.size(); i
++)
165 xmlNodePtr itemNode
= xmlNewChild(groupNode
, NULL
, (const xmlChar
*)"item", NULL
);
166 items
[i
].writeTo(itemNode
);
168 for (int i
= 0; i
< removeSlots
.size(); i
++)
170 xmlNodePtr removeNode
= xmlNewChild(groupNode
, NULL
, (const xmlChar
*)"remove", NULL
);
171 removeSlots
[i
].writeTo(removeNode
);
175 CItemGroup::CSlot
CItemGroup::CSlot::readFromV1(xmlNodePtr node
)
179 XML_READ_STRING(node
, "slot", equipSlot
, "");
180 return CItemGroup::CSlot::fromSlotEquipment(SLOT_EQUIPMENT::stringToSlotEquipment(NLMISC::toUpperAscii(equipSlot
)));
183 CItemGroup::CSlot
CItemGroup::CSlot::readFromV2(xmlNodePtr node
)
186 INVENTORIES::TInventory branch
= INVENTORIES::UNDEFINED
;
187 prop
= xmlGetProp(node
, (xmlChar
*)"branch");
189 branch
= INVENTORIES::toInventory((const char *)prop
);
192 prop
= (char *)xmlGetProp(node
, (xmlChar
*)"index");
194 NLMISC::fromString((const char *)prop
, index
);
196 return CSlot(branch
, index
);
199 CItemGroup::CItem
CItemGroup::CItem::readFrom(xmlNodePtr node
)
203 sint32 createTime
= 0;
204 prop
= (char *)xmlGetProp(node
, (xmlChar
*)"createTime");
206 NLMISC::fromString((const char *)prop
, createTime
);
208 // Version 0 does not use createTime, version 0 is not supported for migrations
210 nlwarning("<CItemGroup::CItem::readFrom> Possibly on unsupported item group version, please remake the item group or contact support.");
213 prop
= (char *)xmlGetProp(node
, (xmlChar
*)"serial");
215 NLMISC::fromString((const char *)prop
, serial
);
217 return CItem(createTime
, serial
, CSlot());
220 void CItemGroup::deserialize(xmlNodePtr node
, std::string version
)
224 prop
= (char *)xmlGetProp(node
, (xmlChar
*)"name");
226 NLMISC::fromString((const char *)prop
, name
);
228 xmlNodePtr curNode
= node
->children
;
233 slot
= CSlot::readFromV1(curNode
);
234 else if (version
== "2")
235 slot
= CSlot::readFromV2(curNode
);
238 nlwarning("<CItemGroup::deserialize> unknown version, can't deserialize group");
242 if (strcmp((char *)curNode
->name
, "item") == 0)
244 CItem item
= CItem::readFrom(curNode
);
248 else if (strcmp((char *)curNode
->name
, "remove") == 0)
251 curNode
= curNode
->next
;
254 // sort the items by slot (important so that left hand is equipped after right hand)
255 std::sort(items
.begin(), items
.end());
258 // Updates the CDBCtrlSheet in each CItem
259 // ! This function must be called before every interaction with items of a CItemGroup
261 // Explanation: We must link the CItem (which just represents identifiers of an item) of the CItemGroup
262 // with an item in the current inventory. Basically, here we are locating the position of the item in the inventory
263 // and we are setting it to the pCS property of CItem, so we can then equip or move CItem via its CDBCtrlSheet.
264 // It is possible that the item is deleted or moved, so we must check for this.
265 void CItemGroup::updateSheets()
267 CInventoryManager
*pIM
= CInventoryManager::getInstance();
268 for (uint i
= 0; i
< items
.size(); i
++)
270 CItem item
= items
[i
];
272 for (int i
= 0; i
< INVENTORIES::NUM_ALL_INVENTORY
; i
++)
274 INVENTORIES::TInventory inventory
= (INVENTORIES::TInventory
)i
;
275 if (pIM
->isInventoryAvailable(inventory
))
277 std::string dbPath
= CInventoryManager::invToDbPath(inventory
);
278 if (dbPath
.empty() || (inventory
== INVENTORIES::guild
&& !ClientCfg
.ItemGroupAllowGuild
))
280 nldebug("<CItemGroup::updateSheets> Inventory type %s not supported", INVENTORIES::toString(inventory
).c_str());
283 IListSheetBase
*pList
= dynamic_cast<IListSheetBase
*>(CWidgetManager::getInstance()->getElementFromId(dbPath
));
284 for (int i
= 0; i
< pList
->getNbSheet(); i
++)
286 CDBCtrlSheet
*pCS
= pList
->getSheet(i
);
287 if (item
.createTime
== pCS
->getItemCreateTime() && item
.serial
== pCS
->getItemSerial())
300 nlinfo("<CItemGroup::updateSheets> Item not found in inventory: createTime: %d, serial: %d", item
.createTime
, item
.serial
);
307 const std::string
CItemGroup::CSlot::toDbPath()
309 std::string dbPath
= "";
310 std::string dbBranch
= INVENTORIES::toLocalDbBranch(branch
);
312 if (!dbBranch
.empty())
313 dbPath
= string(LOCAL_INVENTORY
) + ":" + dbBranch
+ ":" + NLMISC::toString(index
);
318 const std::string
CItemGroup::CSlot::toString()
320 std::string commonName
;
321 if (branch
== INVENTORIES::handling
)
322 commonName
= "Hand" + string(index
== 0 ? "R" : "L");
323 else if (branch
== INVENTORIES::equipment
)
324 commonName
= SLOT_EQUIPMENT::toString((SLOT_EQUIPMENT::TSlotEquipment
)index
);
325 else if (branch
== INVENTORIES::hotbar
)
326 commonName
= "Pocket #" + NLMISC::toString(index
+ 1);
328 commonName
= "unknown";
329 return NLMISC::toString("%s:%sindex=\"%d\"", commonName
.c_str(), string(10 - commonName
.length(), ' ').c_str(), index
);
332 bool CItemGroup::CSlot::isValid()
334 return ((branch
== INVENTORIES::handling
&& index
< MAX_HANDINV_ENTRIES
)
335 || (branch
== INVENTORIES::equipment
&& index
< MAX_EQUIPINV_ENTRIES
)
336 || (branch
== INVENTORIES::hotbar
&& index
< MAX_HOTBARINV_ENTRIES
));
339 CDBCtrlSheet
*CItemGroup::CSlot::getSheet()
341 CInventoryManager
*pIM
= CInventoryManager::getInstance();
342 CDBCtrlSheet
*pCS
= NULL
;
343 if (branch
== INVENTORIES::handling
)
344 pCS
= pIM
->getHandSheet(index
);
345 else if (branch
== INVENTORIES::equipment
)
346 pCS
= pIM
->getEquipSheet(index
);
347 else if (branch
== INVENTORIES::hotbar
)
348 pCS
= pIM
->getHotbarSheet(index
);
352 CItemGroup::CSlot
CItemGroup::CSlot::fromSlotEquipment(SLOT_EQUIPMENT::TSlotEquipment slotEquipment
)
355 if (slotEquipment
== SLOT_EQUIPMENT::HANDR
)
357 else if (slotEquipment
== SLOT_EQUIPMENT::HANDL
)
360 slot
= equipSlot(slotEquipment
);
364 CItemGroupManager::CItemGroupManager()
368 void CItemGroupManager::init()
374 void CItemGroupManager::linkInterface()
376 // attach item group subgroup to right-click in bag group
377 CWidgetManager
*pWM
= CWidgetManager::getInstance();
378 CGroupMenu
*pRootMenu
= dynamic_cast<CGroupMenu
*>(pWM
->getElementFromId(MENU_IN_BAG
));
379 CGroupSubMenu
*pMenu
= pRootMenu
->getRootMenu();
381 CGroupMenu
*pGroupMenu
= dynamic_cast<CGroupMenu
*>(pWM
->getElementFromId(ITEMGROUP_MENU
));
382 CGroupSubMenu
*pGroupSubMenu
= NULL
;
384 pGroupSubMenu
= pGroupMenu
->getRootMenu();
385 if (pMenu
&& pGroupSubMenu
)
386 pMenu
->setSubMenu(pMenu
->getNumLine() - 1, pGroupSubMenu
);
388 nlwarning("<CItemGroupManager::linkInterface> Couldn't link group submenu to item_menu_in_bag, check your widgets.xml file");
390 // must draw the list equip tab
394 void CItemGroupManager::uninit()
401 void CItemGroupManager::unlinkInterface()
403 // We need to unlink our menu to avoid crash on interface release
404 CWidgetManager
*pWM
= CWidgetManager::getInstance();
405 CGroupMenu
*pGroupMenu
= dynamic_cast<CGroupMenu
*>(pWM
->getElementFromId(ITEMGROUP_MENU
));
406 CGroupSubMenu
*pGroupSubMenu
= NULL
;
408 pGroupSubMenu
= pGroupMenu
->getRootMenu();
411 if (pGroupMenu
&& pGroupSubMenu
)
412 pGroupMenu
->delGroup(pGroupSubMenu
, true);
416 std::string
CItemGroupManager::getFilePath(std::string playerName
)
418 return "save/groups_" + playerName
+ ".xml";
421 // Inspired from macro parsing
422 void CItemGroupManager::saveGroups()
424 if (PlayerSelectedFileName
.empty())
426 nlwarning("<CItemGroupManager::saveGroups> Trying to save group with an empty PlayerSelectedFileName, aborting");
430 std::string userGroupFileName
= getFilePath(PlayerSelectedFileName
);
434 if (f
.open(userGroupFileName
, false, false, true))
436 NLMISC::COXml xmlStream
;
438 xmlDocPtr doc
= xmlStream
.getDocument();
439 xmlNodePtr comment
= xmlNewDocComment(doc
, (const xmlChar
*)generateDocumentation().c_str());
440 xmlNodePtr node
= xmlNewDocNode(doc
, NULL
, (const xmlChar
*)"item_groups", NULL
);
441 xmlSetProp(node
, (const xmlChar
*)"version", (const xmlChar
*)ITEMGROUPS_CURRENT_VERSION
);
442 xmlDocSetRootElement(doc
, comment
);
443 xmlAddSibling(comment
, node
);
444 for (int i
= 0; i
< _Groups
.size(); i
++)
446 CItemGroup group
= _Groups
[i
];
453 nlwarning("<CItemGroupManager::saveGroups> Can't open the file %s", userGroupFileName
.c_str());
455 catch (const NLMISC::Exception
&e
)
457 nlwarning("<CItemGroupManager::saveGroups> Error while writing the file %s : %s.", userGroupFileName
.c_str(), e
.what());
461 bool CItemGroupManager::loadGroups()
463 if (PlayerSelectedFileName
.empty())
465 nlwarning("<CItemGroupManager::loadGroups> Trying to load group with an empty PlayerSelectedFileName, aborting");
469 std::string userGroupFileName
= getFilePath(PlayerSelectedFileName
);
470 if (!NLMISC::CFile::fileExists(userGroupFileName
) || NLMISC::CFile::getFileSize(userGroupFileName
) == 0)
472 nlinfo("<CItemGroupManager::loadGroups> No item groups file found !");
477 f
.open(userGroupFileName
);
478 NLMISC::CIXml xmlStream
;
479 xmlNodePtr globalEnclosing
;
484 globalEnclosing
= xmlStream
.getRootNode();
486 catch (const NLMISC::EXmlParsingError
&ex
)
488 nlwarning("<CItemGroupManager::loadGroups> Failed to parse '%s', skip", userGroupFileName
.c_str());
491 if (!globalEnclosing
)
493 nlwarning("<CItemGroupManager::loadGroups> no root element in item_group xml, skipping xml parsing");
496 if (strcmp(((char *)globalEnclosing
->name
), "item_groups"))
498 nlwarning("<CItemGroupManager::loadGroups> wrong root element in item_group xml, skipping xml parsing");
502 // get version of the item groups file
505 XML_READ_STRING(globalEnclosing
, "version", version
, "1");
507 // check if we need to migrate item groups save file
508 if (version
!= ITEMGROUPS_CURRENT_VERSION
)
510 nlinfo("<CItemGroupManager::loadGroups> item group version mismatch, performing migration if possible");
511 // backup current file
512 NLMISC::CFile::copyFile(getFilePath(PlayerSelectedFileName
+ "_backup"), getFilePath(PlayerSelectedFileName
));
515 xmlNodePtr curNode
= globalEnclosing
->children
;
518 if (strcmp((char *)curNode
->name
, "group") == 0)
521 group
.deserialize(curNode
, version
);
523 nlwarning("<CItemGroupManager::loadGroups> Item group '%s' loaded empty. Possibly on unsupported item group version, please remake the item group or contact support.", group
.name
.c_str());
524 _Groups
.push_back(group
);
526 curNode
= curNode
->next
;
533 void CItemGroupManager::undrawGroupsList()
535 CGroupList
*pParent
= dynamic_cast<CGroupList
*>(CWidgetManager::getInstance()->getElementFromId(LIST_ITEMGROUPS
));
538 pParent
->clearGroups();
539 pParent
->setDynamicDisplaySize(false);
540 CGroupList
*pParent2
= dynamic_cast<CGroupList
*>(CWidgetManager::getInstance()->getElementFromId(LIST_ITEMGROUPS_2
));
543 pParent2
->clearGroups();
544 pParent2
->setDynamicDisplaySize(false);
547 void CItemGroupManager::drawGroupsList()
549 // rebuild groups list
551 CGroupList
*pParent
= dynamic_cast<CGroupList
*>(CWidgetManager::getInstance()->getElementFromId(LIST_ITEMGROUPS
));
554 CGroupList
*pParent2
= dynamic_cast<CGroupList
*>(CWidgetManager::getInstance()->getElementFromId(LIST_ITEMGROUPS_2
));
557 CViewBase
*pView
= pParent
->getParent()->getView(LIST_EMPTY_TEXT
);
558 CViewBase
*pView2
= pParent2
->getParent()->getView(LIST_EMPTY_TEXT
);
561 pView
->setActive(true);
562 pView2
->setActive(true);
567 pView
->setActive(false);
568 pView2
->setActive(false);
570 for (uint i
= 0; i
< _Groups
.size(); i
++)
572 CInterfaceGroup
*pLine
= generateGroupsListLine(LIST_ITEMGROUPS
, i
);
575 CInterfaceGroup
*pLine2
= generateGroupsListLine(LIST_ITEMGROUPS_2
, i
);
580 pLine
->setParent(pParent
);
581 pParent
->addChild(pLine
);
582 pLine2
->setParent(pParent2
);
583 pParent2
->addChild(pLine2
);
587 CInterfaceGroup
*CItemGroupManager::generateGroupsListLine(std::string parent
, uint i
)
589 // create the group line
590 std::string templateId
= parent
+ ":g" + NLMISC::toString(i
).c_str();
591 std::vector
<std::pair
<string
, string
>> vParams
;
592 vParams
.push_back(std::pair
<string
, string
>("id", templateId
));
593 vParams
.push_back(std::pair
<string
, string
>("name", _Groups
[i
].name
));
594 CInterfaceGroup
*pLine
= NULL
;
595 pLine
= CWidgetManager::getInstance()->getParser()->createGroupInstance(TEMPLATE_ITEMGROUP_ITEM
, parent
, vParams
);
600 CViewText
*pViewName
= dynamic_cast<CViewText
*>(pLine
->getView(TEMPLATE_ITEMGROUP_ITEM_NAME
));
602 pViewName
->setText(_Groups
[i
].name
);
607 // move a group from all available inventory to dst
608 bool CItemGroupManager::moveGroup(std::string name
, INVENTORIES::TInventory dst
)
610 CItemGroup
*group
= findGroup(name
);
613 nlinfo("<CItemGroupManager::moveGroup> group %s not found", name
.c_str());
617 if (dst
== INVENTORIES::UNDEFINED
)
619 nlinfo("<CItemGroupManager::moveGroup> Destination inventory not found");
623 // update location of items in the inventory
624 group
->updateSheets();
626 CInventoryManager
*pIM
= CInventoryManager::getInstance();
627 for (uint i
= 0; i
< group
->items
.size(); i
++)
629 CItemGroup::CItem item
= group
->items
[i
];
634 // if the item is equipped, don't move
635 CItemGroup::CSlot currentSlot
;
636 if (isItemEquipped(item
.pCS
, currentSlot
))
638 // if item is equipped, but not already in the wanted slot, unequip it first
639 if (!item
.dstSlot
.getSheet()->isSheetEqual(item
.pCS
))
640 pIM
->unequip(currentSlot
.toDbPath());
644 // If the item is already in dst inventory, no need to move it
645 if (item
.pCS
->getInventoryIndex() == dst
)
648 CAHManager::getInstance()->runActionHandler("move_item", item
.pCS
, "to=lists|nblist=1|listsheet0=" + CInventoryManager::invToDbPath(dst
));
654 bool CItemGroupManager::equipGroup(std::string name
, bool pullBefore
)
656 CItemGroup
*pGroup
= findGroup(name
);
659 nlinfo("<CItemGroupManager::equipGroup> group %s not found", name
.c_str());
664 moveGroup(name
, INVENTORIES::bag
);
666 // we must update the location of items, even after they were moved
667 pGroup
->updateSheets();
669 // first, unequip all remove slots
670 for (int i
= 0; i
< pGroup
->removeSlots
.size(); i
++)
672 CItemGroup::CSlot slot
= pGroup
->removeSlots
[i
];
673 std::string dbPath
= slot
.toDbPath();
675 CInventoryManager::getInstance()->unequip(dbPath
);
679 uint32 equipTime
= 0;
680 for (int i
= 0; i
< pGroup
->items
.size(); i
++)
682 CItemGroup::CItem item
= pGroup
->items
[i
];
684 item
.equip(equipTime
);
690 bool CItemGroupManager::createGroup(std::string name
, bool removeEmpty
)
695 CInventoryManager
*pIM
= CInventoryManager::getInstance();
696 CItemGroup group
= CItemGroup();
699 for (i
= 0; i
< MAX_HANDINV_ENTRIES
; i
++)
701 group
.addSheet(pIM
->getHandSheet(i
), CItemGroup::CSlot::handSlot(i
), removeEmpty
);
703 for (i
= 0; i
< MAX_EQUIPINV_ENTRIES
; ++i
)
705 group
.addSheet(pIM
->getEquipSheet(i
), CItemGroup::CSlot::equipSlot(i
), removeEmpty
);
707 for (i
= 0; i
< MAX_HOTBARINV_ENTRIES
; ++i
)
709 group
.addSheet(pIM
->getHotbarSheet(i
), CItemGroup::CSlot::hotbarSlot(i
), removeEmpty
);
712 _Groups
.push_back(group
);
714 // must redraw the list equip tab
720 bool CItemGroupManager::deleteGroup(std::string name
)
722 std::vector
<CItemGroup
> tmp
;
723 for (int i
= 0; i
< _Groups
.size(); i
++)
725 CItemGroup group
= _Groups
[i
];
726 if (group
.name
== name
)
728 tmp
.push_back(group
);
730 // Nothing removed, error
731 if (tmp
.size() == _Groups
.size())
735 // must redraw the list equip tab
741 void CItemGroupManager::listGroup()
743 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
744 pIM
->displaySystemInfo(NLMISC::CI18N::get("cmdListGroupHeader"));
745 for (int i
= 0; i
< _Groups
.size(); i
++)
747 CItemGroup group
= _Groups
[i
];
748 string msg
= NLMISC::CI18N::get("cmdListGroupLine");
749 NLMISC::strFindReplace(msg
, "%name", group
.name
);
750 NLMISC::strFindReplace(msg
, "%size", NLMISC::toString(group
.items
.size()));
751 pIM
->displaySystemInfo(msg
);
756 std::vector
<std::string
> CItemGroupManager::getGroupNames(CDBCtrlSheet
*pCS
)
758 std::vector
<std::string
> out
;
759 for (int i
= 0; i
< _Groups
.size(); i
++)
761 CItemGroup group
= _Groups
[i
];
762 if (group
.contains(pCS
))
763 out
.push_back(group
.name
);
769 CItemGroup
*CItemGroupManager::findGroup(std::string name
)
771 for (int i
= 0; i
< _Groups
.size(); i
++)
773 if (_Groups
[i
].name
== name
)
779 // Workaround: sometimes item are marked as equipped by pIM->isBagItemWeared() even though they aren't really
780 // Because of a synchronisation error between client and server
781 bool CItemGroupManager::isItemEquipped(CDBCtrlSheet
*pItem
, CItemGroup::CSlot
&equipSlot
)
785 nlinfo("<CItemGroupManager::isItemEquipped> item is null");
789 CInventoryManager
*pIM
= CInventoryManager::getInstance();
791 for (uint i
= 0; i
< MAX_HANDINV_ENTRIES
; i
++)
793 pCS
= pIM
->getHandSheet(i
);
794 equipSlot
= CItemGroup::CSlot::handSlot(i
);
795 if (pItem
->isSheetEqual(pCS
))
798 for (uint32 i
= 0; i
< MAX_EQUIPINV_ENTRIES
; ++i
)
800 pCS
= pIM
->getEquipSheet(i
);
801 equipSlot
= CItemGroup::CSlot::equipSlot(i
);
802 if (pItem
->isSheetEqual(pCS
))
806 for (uint32 i
= 0; i
< MAX_HOTBARINV_ENTRIES
; ++i
)
808 pCS
= pIM
->getHotbarSheet(i
);
809 equipSlot
= CItemGroup::CSlot::hotbarSlot(i
);
810 if (pItem
->isSheetEqual(pCS
))
816 std::string
CItemGroupManager::generateDocumentation()
820 out
+= "\r\nItem Groups - Version " + string(ITEMGROUPS_CURRENT_VERSION
) + "\r\n\r\n/// branch=\"handling\" ///\r\n";
821 for (i
= 0; i
< MAX_HANDINV_ENTRIES
; i
++)
822 out
+= CItemGroup::CSlot::handSlot(i
).toString() + "\r\n";
823 out
+= "\r\n/// branch=\"equipment\" ///\r\n";
824 for (i
= 0; i
< MAX_EQUIPINV_ENTRIES
; ++i
)
825 if (i
!= SLOT_EQUIPMENT::HANDL
&& i
!= SLOT_EQUIPMENT::HANDR
)
826 out
+= CItemGroup::CSlot::equipSlot(i
).toString() + "\r\n";
827 out
+= "\r\n/// branch=\"hotbar\" ///\r\n";
828 for (i
= 0; i
< MAX_HOTBARINV_ENTRIES
; ++i
)
829 out
+= CItemGroup::CSlot::hotbarSlot(i
).toString() + "\r\n";
833 // Singleton management
834 CItemGroupManager
*CItemGroupManager::getInstance()
837 _Instance
= new CItemGroupManager();
841 void CItemGroupManager::releaseInstance()