Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / interface_v3 / action_handler_help.cpp
blob4417966bbafb8b5ed955435e7f1368c7cf362141
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 //
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Affero General Public License as
11 // published by the Free Software Foundation, either version 3 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Affero General Public License for more details.
19 // You should have received a copy of the GNU Affero General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "stdpch.h"
27 #include "nel/gui/action_handler.h"
28 #include "interface_manager.h"
29 #include "bot_chat_manager.h"
30 #include "../sheet_manager.h"
31 #include "skill_manager.h"
32 #include "dbctrl_sheet.h"
33 #include "nel/gui/interface_expr.h"
34 #include "nel/gui/group_container.h"
35 #include "nel/gui/group_editbox.h"
36 #include "group_quick_help.h"
37 #include "nel/gui/view_text_id.h"
38 #include "../user_entity.h"
39 #include "../entities.h"
40 #include "nel/gui/dbgroup_combo_box.h"
41 #include "nel/gui/dbview_bar.h"
42 #include "../debug_client.h"
43 #include "interface_3d_scene.h"
44 #include "character_3d.h"
45 #include "item_special_effect.h"
46 #include "item_consumable_effect.h"
47 #include "bonus_malus.h"
48 // Game share
49 #include "game_share/slot_types.h"
50 #include "game_share/item_family.h"
51 #include "game_share/skills.h"
52 #include "game_share/armor_types.h"
53 #include "game_share/weapon_types.h"
54 #include "game_share/damage_types.h"
55 #include "game_share/ecosystem.h"
56 #include "game_share/mp_category.h"
57 #include "game_share/item_origin.h"
58 #include "game_share/shield_types.h"
59 #include "game_share/trade_slot_type.h"
60 #include "../string_manager_client.h"
61 #include "game_share/sphrase_com.h"
62 #include "sbrick_manager.h"
63 #include "sphrase_manager.h"
64 #include "action_handler_help.h"
65 #include "nel/misc/i18n.h"
66 #include "nel/misc/algo.h"
67 #include "nel/net/email.h"
68 #include "game_share/mission_desc.h"
69 #include "game_share/inventories.h"
70 #include "game_share/visual_slot_manager.h"
71 #include "game_share/prerequisit_infos.h"
72 #include "game_share/resistance_type.h"
73 #include "../r2/editor.h"
74 #include "../init.h"
75 #include "../browse_faq.h"
76 #include "people_list.h"
77 #include "people_interraction.h"
79 extern CSheetManager SheetMngr;
81 extern NLMISC::CLog g_log;
83 using namespace std;
84 using namespace NLMISC;
85 using namespace STRING_MANAGER;
88 ///////////////////////////////////
89 // STATIC FUNCTIONS DECLARATIONS //
90 ///////////////////////////////////
91 static void setupCreatorName(CSheetHelpSetup &setup);
92 static void setHelpText(CSheetHelpSetup &setup, const string &text);
93 static void setHelpTextID(CSheetHelpSetup &setup, sint32 id);
94 static void fillSabrinaPhraseListBrick(const CSPhraseCom &phrase, IListSheetBase *listBrick);
95 static void setupListBrickHeader(CSheetHelpSetup &setup);
96 static void hideListBrickHeader(CSheetHelpSetup &setup);
98 static void setupHelpPage(CInterfaceGroup *window, const string &url);
99 static void setupHelpTitle(CInterfaceGroup *group, const string &title);
100 static void setHelpCtrlSheet(CSheetHelpSetup &setup, uint32 sheetId);
102 // Setup help for an item in a window (type is known)
103 static void setupItemHelp(CSheetHelpSetup &setup);
104 static void setupPactHelp(CSheetHelpSetup &setup);
105 static void setupSkillToTradeHelp(CSheetHelpSetup &setup);
106 static void setupSabrinaBrickHelp(CSheetHelpSetup &setup, bool auraDisabled= false);
107 void setupSabrinaPhraseHelp(CSheetHelpSetup &setup, const class CSPhraseCom &phrase, uint32 phraseSheetId);
108 static void setupMissionHelp(CSheetHelpSetup &setup);
110 // ***************************************************************************
111 #define INFO_LIST_ITEM "list_item"
112 #define INFO_LIST_BRICK "list_brick"
113 #define INFO_LIST_BRICK_HEADER "list_brick_header"
114 #define INFO_LIST_BRICK_REQUIREMENT "list_brick_requirement"
115 #define INFO_GROUP_MP_STAT "mp_stats"
116 #define INFO_GROUP_CHAR_3D "char3d"
117 #define INFO_ITEM_PREVIEW "item_preview"
118 #define INFO_ITEM_PREVIEW_SCENE_3D "scene_item_preview"
119 #define ITEM_PREVIEW_WIDTH 200
121 // ***************************************************************************
122 std::deque<uint> CInterfaceHelp::_ActiveWindows;
123 std::vector<CInterfaceHelp::CInfoWindow> CInterfaceHelp::_InfoWindows;
124 bool CInterfaceHelp::_InfoWindowInit= false;
125 CInterfaceHelp::CFittedWeaponWeightObserver CInterfaceHelp::_FittedWeaponWeightObserver;
128 // ***************************************************************************
129 void CInterfaceHelp::CInfoWindow::infoReceived()
131 // refresh text
132 if(CtrlSheet && Window)
134 CSheetHelpSetup setup;
135 setup.setupDefaultIDs();
136 setup.HelpWindow = Window;
137 setup.SrcSheet = CtrlSheet;
138 refreshItemHelp(setup);
142 // ***************************************************************************
143 void CInterfaceHelp::CInfoWindow::missionInfoReceived(const CPrerequisitInfos &infos)
145 // refresh text
146 if(CtrlSheet && Window)
148 CSheetHelpSetup setup;
149 setup.setupDefaultIDs();
150 setup.HelpWindow = Window;
151 setup.SrcSheet = CtrlSheet;
152 refreshMissionHelp(setup, infos);
156 // ***************************************************************************
157 void CInterfaceHelp::initWindows()
159 if(_InfoWindowInit)
160 return;
162 _InfoWindowInit= true;
164 // Get the Max window allowed.
165 CInterfaceManager *pIM= CInterfaceManager::getInstance();
167 sint maxHelpWindow;
168 fromString(CWidgetManager::getInstance()->getParser()->getDefine("MAX_HELP_WINDOW"), maxHelpWindow);
170 // Allow Max 256. More may be a script error...
171 clamp(maxHelpWindow, 0, 256);
173 for(sint i=0;i<maxHelpWindow;i++)
175 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:sheet_help"+toString(i)));
176 // if the window exist, insert
177 if(group)
179 CInfoWindow newInfo;
180 newInfo.Window= group->getId();
181 newInfo.KeepButton= group->getId() + ":header_opened:keep";
182 _InfoWindows.push_back(newInfo);
184 else
185 break;
187 // add observers for the update of phrase help texts (depends of weight of equipped weapons)
188 for (uint i = 0; i < MAX_HANDINV_ENTRIES; ++i)
190 CCDBNodeLeaf *pNodeLeaf = NLGUI::CDBManager::getInstance()->getDbProp(string(LOCAL_INVENTORY) + ":HAND:" + toString(i), false);
191 if(pNodeLeaf)
193 ICDBNode::CTextId textId;
194 pNodeLeaf->addObserver(&_FittedWeaponWeightObserver, textId);
201 // ***************************************************************************
202 void CInterfaceHelp::release()
204 if (_InfoWindowInit)
206 _InfoWindowInit = false;
207 _InfoWindows.clear();
209 CInterfaceManager *pIM= CInterfaceManager::getInstance();
210 // add observers for the update of phrase help texts (depends of weight of equipped weapons)
211 for (uint i = 0; i < MAX_HANDINV_ENTRIES; ++i)
213 CCDBNodeLeaf *pNodeLeaf = NLGUI::CDBManager::getInstance()->getDbProp(string(LOCAL_INVENTORY) + ":HAND:" + toString(i), false);
214 if(pNodeLeaf)
216 ICDBNode::CTextId textId;
217 pNodeLeaf->removeObserver(&_FittedWeaponWeightObserver, textId);
222 // ***************************************************************************
223 void CInterfaceHelp::CFittedWeaponWeightObserver::update(ICDBNode* node)
225 CInterfaceHelp::updateWindowSPhraseTexts();
228 // ***************************************************************************
229 CInterfaceGroup *CInterfaceHelp::activateNextWindow(CDBCtrlSheet *elt, sint forceKeepWindow)
231 CInterfaceManager *pIM = CInterfaceManager::getInstance();
233 // update WindowList if possible
234 initWindows();
235 sint maxHelpWindow= (sint)_InfoWindows.size();
238 // Update Active window list
239 uint i;
240 for(i=0;i<_ActiveWindows.size();)
242 CInterfaceGroup *group= _InfoWindows[_ActiveWindows[i]].Window;
243 // if the window has been closed, remove it from list
244 if(!group->getActive())
246 _ActiveWindows.erase(_ActiveWindows.begin()+i);
248 else
249 i++;
252 bool showSlotAndCreator = false;
253 // If an active window get the same object, abort, but make it top.
254 for(i=0;i<_ActiveWindows.size();i++)
256 CInterfaceGroup *group= _InfoWindows[_ActiveWindows[i]].Window;
257 CDBCtrlSheet *ctrlSrc= elt;
258 // get the ctrl sheet in this help window.
259 CDBCtrlSheet *ctrlDst= dynamic_cast<CDBCtrlSheet*>(group->getCtrl(":ctrl_slot"));
260 if(ctrlDst && ctrlSrc)
262 // if same Aspect
263 if( ctrlSrc->sameAspect(ctrlDst) )
265 bool ok= true;
267 // for items, must also test if they have the same itemSlotId, cause relies also on "ItemInfo system"
268 if(elt->getType() == CCtrlSheetInfo::SheetType_Item)
270 showSlotAndCreator = true;
272 CDBCtrlSheet *realCtrlDst= _InfoWindows[_ActiveWindows[i]].CtrlSheet;
273 if(!realCtrlDst)
274 ok= false;
275 else if( getInventory().getItemSlotId(ctrlSrc) != getInventory().getItemSlotId(realCtrlDst) )
276 ok= false;
279 // if success to find same element
280 if(ok)
282 // then don't neet to open a new window, but make the older top.
283 CWidgetManager::getInstance()->setTopWindow(group);
284 return NULL;
290 // If some free window possible, search which to take
291 sint newIndexWindow= -1;
292 bool mustAddToActiveWindows= true;
293 // if an active window is not in KeepMode, get it.
294 for(i=0;i<_ActiveWindows.size();i++)
296 // must also test forceKeep for special Action Help which open Brick Help
297 if(!_InfoWindows[_ActiveWindows[i]].KeepMode && forceKeepWindow!=(sint)_ActiveWindows[i])
299 newIndexWindow= _ActiveWindows[i];
300 mustAddToActiveWindows= false;
301 break;
305 // If not found get new closed one.
306 if(newIndexWindow==-1)
308 if(_ActiveWindows.size() < (uint)maxHelpWindow)
310 // flag each active window
311 static std::vector<bool> windowActive;
312 windowActive.clear();
313 windowActive.resize(maxHelpWindow, false);
314 for(i=0;i<_ActiveWindows.size();i++)
316 windowActive[_ActiveWindows[i]]= true;
319 // Search the first window closed, and that is in KeepMode (if possible)
320 sint newIndexWindowKeep= -1;
321 for(i=0;i<(uint)maxHelpWindow;i++)
323 if(!windowActive[i])
325 // Keep the first window not active
326 if(newIndexWindow==-1)
327 newIndexWindow= i;
328 // Keep the first window not active, that is in KeepMode
329 if(_InfoWindows[i].KeepMode && newIndexWindowKeep==-1)
330 newIndexWindowKeep= i;
333 // Fail?
334 if( newIndexWindow==-1 )
335 return NULL;
336 // success to take a "keep" one?
337 if(newIndexWindowKeep!=-1)
338 newIndexWindow= newIndexWindowKeep;
340 else
342 // All the info window are opened (and should not be in KeepMode....), take the last recently opened.
343 newIndexWindow= _ActiveWindows.front();
344 // free space
345 _ActiveWindows.pop_front();
349 // get the next window
350 CInterfaceGroup *group= _InfoWindows[newIndexWindow].Window;
351 nlassert(group);
353 CInterfaceElement *ctrl = group->getElement(group->getId()+":content:ctrl_slot");
354 if (ctrl) ctrl->setActive(showSlotAndCreator);
355 ctrl = group->getElement(group->getId()+":content:creator");
356 if (ctrl) ctrl->setActive(showSlotAndCreator);
357 ctrl = group->getElement(group->getId()+":content:creator_header");
358 if (ctrl) ctrl->setActive(showSlotAndCreator);
360 // activate it, set top, copy item watched
361 group->setActive(true);
362 CWidgetManager::getInstance()->setTopWindow(group);
363 _InfoWindows[newIndexWindow].CtrlSheet= elt;
364 // insert in list
365 if(mustAddToActiveWindows)
366 _ActiveWindows.push_back(newIndexWindow);
368 // If Item or mission, must add a callBack when itemInfo (or missionInfo) OK.
369 if (elt)
371 if( elt->getType() == CCtrlSheetInfo::SheetType_Item )
373 _InfoWindows[newIndexWindow].ItemSheet= elt->getSheetId();
374 _InfoWindows[newIndexWindow].ItemSlotId= getInventory().getItemSlotId(elt);
376 // Add the waiter only if really needed (not for raw materials)
377 const CItemSheet *itemSheet= elt->asItemSheet();
378 if(itemSheet && itemSheet->Family != ITEMFAMILY::RAW_MATERIAL )
379 getInventory().addItemInfoWaiter(&_InfoWindows[newIndexWindow]);
381 else if ( elt->getType() == CCtrlSheetInfo::SheetType_Mission )
383 _InfoWindows[newIndexWindow].MissionSlotId = (uint16)elt->getIndexInDB();
384 CBotChatManager::getInstance()->addMissionInfoWaiter(&_InfoWindows[newIndexWindow]);
388 // recompute at next pass
389 group->invalidateCoords();
391 // Hide some components.
392 // Hide the creator name
393 CSheetHelpSetup setup;
394 setup.setupDefaultIDs();
395 setup.SrcSheet = elt;
396 setup.HelpWindow = group;
397 //setupCreatorName(setup);
399 // Hide elements by defaults
400 resetSheetHelp(setup);
402 return group;
406 // ***************************************************************************
407 void CInterfaceHelp::removeWaiterItemInfo(uint i)
409 if(i<_InfoWindows.size())
410 getInventory().removeItemInfoWaiter(&_InfoWindows[i]);
413 // ***************************************************************************
414 void CInterfaceHelp::removeWaiterMissionInfo(uint i)
416 if(i<_InfoWindows.size())
417 CBotChatManager::getInstance()->removeMissionInfoWaiter(&_InfoWindows[i]);
420 // ***************************************************************************
421 void CInterfaceHelp::changeKeepMode(uint i)
423 if(i<_InfoWindows.size())
425 _InfoWindows[i].KeepMode= !_InfoWindows[i].KeepMode;
426 bool state= _InfoWindows[i].KeepMode;
427 if(_InfoWindows[i].KeepButton)
428 _InfoWindows[i].KeepButton->setPushed(state);
432 // ***************************************************************************
433 void CInterfaceHelp::setKeepMode(uint i, bool state)
435 if(i<_InfoWindows.size())
437 _InfoWindows[i].KeepMode= state;
438 if(_InfoWindows[i].KeepButton)
439 _InfoWindows[i].KeepButton->setPushed(state);
444 // ***************************************************************************
445 void CInterfaceHelp::closeAll()
447 // update WindowList if possible
448 initWindows();
449 sint maxHelpWindow= (sint)_InfoWindows.size();
451 _ActiveWindows.clear();
452 // For all windows
453 for(uint i=0;i<(uint)maxHelpWindow;i++)
455 _InfoWindows[i].Window->setActive(false);
460 // ***************************************************************************
461 void CInterfaceHelp::resetWindowPos(sint y)
463 CInterfaceManager *pIM= CInterfaceManager::getInstance();
465 // update WindowList if possible
466 initWindows();
467 sint maxHelpWindow= (sint)_InfoWindows.size();
469 uint32 w, h;
470 CViewRenderer::getInstance()->getScreenSize(w,h);
472 // For all windows, reset pos
473 for(uint i=0;i<(uint)maxHelpWindow;i++)
475 _InfoWindows[i].Window->setX(i*_InfoWindows[i].Window->getW(false));
476 _InfoWindows[i].Window->setY((sint)h+y);
477 _InfoWindows[i].Window->invalidateCoords();
481 // ***************************************************************************
482 void CInterfaceHelp::serialInfoWindows(NLMISC::IStream &f)
484 f.serialVersion(0);
486 vector<CInfoWindowSave> infoWindowSave;
487 if(f.isReading())
489 // Setup pos by default (for case where number of windows differ)
490 resetWindowPos(-100);
492 f.serialCont(infoWindowSave);
493 uint minSize= (uint)min(infoWindowSave.size(), _InfoWindows.size());
494 for(uint i=0;i<minSize;i++)
496 _InfoWindows[i].Window->setX(infoWindowSave[i].X);
497 _InfoWindows[i].Window->setY(infoWindowSave[i].Y);
498 _InfoWindows[i].Window->invalidateCoords();
501 else
503 infoWindowSave.resize(_InfoWindows.size());
504 for(uint i=0;i<infoWindowSave.size();i++)
506 infoWindowSave[i].X= _InfoWindows[i].Window->getX();
507 infoWindowSave[i].Y= _InfoWindows[i].Window->getY();
509 f.serialCont(infoWindowSave);
513 // ***************************************************************************
514 void CInterfaceHelp::debugOpenedInfoWindows()
516 for(uint i=0;i<_ActiveWindows.size();i++)
518 uint index= _ActiveWindows[i];
519 uint sheetId= 0;
520 if(_InfoWindows[index].CtrlSheet)
521 sheetId= _InfoWindows[index].CtrlSheet->getSheetId();
522 if(sheetId)
524 nlinfo("debugInfoWindow: %s", CSheetId(sheetId).toString().c_str() );
529 // ***************************************************************************
530 void CInterfaceHelp::updateWindowSPhraseTexts()
532 CSPhraseManager *pPM= CSPhraseManager::getInstance();
534 for(uint i=0;i<_ActiveWindows.size();i++)
536 uint index= _ActiveWindows[i];
537 CDBCtrlSheet *ctrl= _InfoWindows[index].CtrlSheet;
538 CInterfaceGroup *group= _InfoWindows[index].Window;
539 if(group && ctrl && (ctrl->isSPhraseId() || ctrl->isSPhrase()) )
541 CSheetHelpSetup setup;
542 setup.setupDefaultIDs();
543 setup.HelpWindow = group;
544 setup.SrcSheet = ctrl;
545 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getCtrl("ctrl_slot"));
547 if(ctrl->isSPhraseId())
549 // reset up the complete window
550 setupSabrinaPhraseHelp(setup, pPM->getPhrase(ctrl->getSPhraseId()), 0);
552 else if(ctrl->isSPhrase())
554 CSPhraseCom phrase;
555 uint32 phraseSheetId= setup.SrcSheet->getSheetId();
556 pPM->buildPhraseFromSheet(phrase, phraseSheetId);
557 setupSabrinaPhraseHelp(setup, phrase, phraseSheetId);
563 // ***************************************************************************
564 /** Close all the helps.
566 class CHandlerCloseHelp : public IActionHandler
568 void execute (CCtrlBase *pCaller, const string &sParams)
570 CInterfaceHelp::closeAll();
573 REGISTER_ACTION_HANDLER( CHandlerCloseHelp, "close_help");
576 // ***************************************************************************
577 /** Build the help window for an item and open it.
579 class CHandlerOpenItemHelp : public IActionHandler
581 void execute (CCtrlBase *pCaller, const string &sParams)
583 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
584 if (cs != NULL && cs->getSheetId()!=0 )
586 // get the forceKeep param (for Building info)
587 sint forceKeepWindow= -1;
588 string forceKeepWindowStr= getParam(sParams, "force_keep");
589 if(!forceKeepWindowStr.empty())
590 fromString(forceKeepWindowStr, forceKeepWindow);
592 // open the next window
593 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(cs, forceKeepWindow);
594 if (!group) return;
595 CSheetHelpSetup setup;
596 setup.setupDefaultIDs();
597 setup.HelpWindow = group;
598 setup.SrcSheet = cs;
599 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getElement(group->getId()+":content:ctrl_slot"));
600 setupItemHelp(setup);
604 REGISTER_ACTION_HANDLER( CHandlerOpenItemHelp, "open_item_help");
607 // ***************************************************************************
608 /** Build the help window for a pact and open it.
610 class CHandlerOpenPactHelp : public IActionHandler
612 void execute (CCtrlBase *pCaller, const string &sParams)
614 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
615 if (cs != NULL && cs->getSheetId()!=0 )
617 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(cs);
618 if (!group) return;
619 CSheetHelpSetup setup;
620 setup.setupDefaultIDs();
621 setup.HelpWindow = group;
622 setup.SrcSheet = cs;
623 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getElement(group->getId()+":content:ctrl_slot"));
624 setupPactHelp(setup);
628 REGISTER_ACTION_HANDLER( CHandlerOpenPactHelp, "open_pact_help");
631 // ***************************************************************************
632 /** Build the help window for a targeted entity to know what the title means
634 class CHandlerOpenTitleHelp : public IActionHandler
636 void execute (CCtrlBase *pCaller, const string &sParams)
638 // display web profile if necessary
639 if (getParam(sParams, "from") == "contact")
641 if (pCaller == NULL)
642 return;
644 CInterfaceGroup *fatherGC = pCaller->getParent();
645 if (fatherGC == NULL)
646 return;
647 fatherGC = fatherGC->getParent();
648 if (fatherGC == NULL)
649 return;
650 string str = fatherGC->getId().substr(0,fatherGC->getId().rfind('_'));
651 str = str.substr(str.rfind(':')+1, str.size());
652 CPeopleList *peopleList = PeopleInterraction.getPeopleListFromContainerID(str);
653 if (peopleList == NULL)
654 return;
656 sint index = peopleList->getIndexFromContainerID(fatherGC->getId());
657 if (index == -1)
658 return;
659 string name = peopleList->getName(index);
660 if ( ! name.empty())
662 CAHManager::getInstance()->runActionHandler("show_hide", pCaller, "profile|pname="+name+"|ptype="+toString((int)CEntityCL::Player));
664 return;
666 else if (getParam(sParams, "from") == "target")
668 // Require info on the target
669 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
670 if (selection == NULL) return;
671 //if(selection->isNPC())
673 string name = selection->getEntityName();
674 if(name.empty())
676 // try to get the name from the string manager (for npc)
677 uint32 nDBid = selection->getNameId();
678 if (nDBid != 0)
680 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
681 pSMC->getString (nDBid, name);
682 string copyName = name;
683 name = CEntityCL::removeTitleAndShardFromName(name);
684 if (name.empty())
686 CCharacterCL *pChar = dynamic_cast<CCharacterCL*>(selection);
687 bool woman = false;
688 if (pChar != NULL)
689 woman = pChar->getGender() == GSGENDER::female;
691 // extract the replacement id
692 string strNewTitle = CEntityCL::getTitleFromName(copyName);
694 // retrieve the translated string
695 if (!strNewTitle.empty())
696 name = STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(strNewTitle, woman);
697 else
698 name.clear();
702 if(!name.empty())
703 CAHManager::getInstance()->runActionHandler("show_hide", pCaller, "profile|pname="+name+"|ptype="+toString((int)selection->Type));
704 return;
708 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(NULL);
709 if (!group) return;
711 // prepare the help window
712 CSheetHelpSetup setup;
713 setup.setupDefaultIDs();
714 setup.HelpWindow = group;
715 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getElement(group->getId()+":content:ctrl_slot"));
717 // Get name and title
718 // ------------------
719 string name;
720 string title;
721 bool reservedTitle = false;
722 string sFrom = getParam(sParams, "from");
723 if (sFrom == "target")
725 // Require info on the target
726 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
727 if (selection == NULL) return;
728 name = CEntityCL::removeTitleAndShardFromName(selection->getEntityName());
729 title = selection->getTitle();
730 reservedTitle = selection->hasReservedTitle();
732 else if (sFrom == "user")
734 // Require info on the local_player
735 name = CEntityCL::removeTitleAndShardFromName(UserEntity->getEntityName());
736 title = UserEntity->getTitle();
737 reservedTitle = UserEntity->hasReservedTitle();
739 else return;
741 // Get Title info (bricks and skills needed)
742 // -----------------------------------------
743 CUnblockTitlesSheet *pUTS = dynamic_cast<CUnblockTitlesSheet*>(SheetMngr.get(CSheetId("unblock.titles")));
744 if (pUTS == NULL)
746 nlwarning("cant find unblock.titles");
747 return;
750 // get title id number from the title id
751 uint titleIDnb;
752 for (titleIDnb = 0; titleIDnb < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++titleIDnb)
754 bool women = UserEntity && UserEntity->getGender()==GSGENDER::female;
755 if (CStringManagerClient::getTitleLocalizedName(CHARACTER_TITLE::toString((CHARACTER_TITLE::ECharacterTitle)titleIDnb),women) == title)
756 break;
759 // Retrieve all infos about the title
760 const CUnblockTitlesSheet::STitleUnblock *pTU = NULL;
761 if (titleIDnb != CHARACTER_TITLE::NB_CHARACTER_TITLE)
762 pTU = &pUTS->TitlesUnblock[titleIDnb];
765 // Display all infos found
766 // -----------------------
767 string titleText = CI18N::get("uihelpTitleFormat");
768 strFindReplace(titleText, "%name", name);
770 // Display title
771 string::size_type p1 = title.find('(');
772 if (p1 != string::npos)
774 string::size_type p2 = title.find(')', p1+1);
775 if (p2 != string::npos)
776 title = title.substr(p1+1, p2-p1-1);
778 strFindReplace(titleText, "%title", title);
780 // Display all skills needed to obtain this title
781 string sSkillsNeeded;
782 if (!title.empty() && pTU == NULL)
783 sSkillsNeeded = CI18N::get("uiTitleCantObtain");
785 if (pTU != NULL)
787 sSkillsNeeded = CI18N::get("uiTitleSkillHeader");
788 if (pTU->SkillsNeeded.empty() || reservedTitle)
790 sSkillsNeeded += CI18N::get("uiTitleSkillNoNeed");
792 else
794 for (uint i = 0; i < pTU->SkillsNeeded.size(); ++i)
796 for (uint j = 0; j < pTU->SkillsNeeded[i].size(); ++j)
798 uint skillNb;
799 for (skillNb = 0; skillNb < SKILLS::NUM_SKILLS; ++skillNb)
800 if (pTU->SkillsNeeded[i][j] == SKILLS::toString((SKILLS::ESkills)skillNb))
801 break;
803 if (skillNb != SKILLS::NUM_SKILLS)
805 sSkillsNeeded += CStringManagerClient::getSkillLocalizedName((SKILLS::ESkills)skillNb);
806 sSkillsNeeded += " (" + toString(pTU->SkillsLevelNeeded[i][j]) + ")";
807 sSkillsNeeded += "\n";
809 else
811 nlwarning("cant find skill : %s", pTU->SkillsNeeded[i][j].c_str());
814 if( i != pTU->SkillsNeeded.size()-1 )
816 sSkillsNeeded += CI18N::get("uiTitleSkillOr");
817 sSkillsNeeded +="\n";
822 strFindReplace(titleText, "%skills", sSkillsNeeded);
824 // Display all bricks needed to obtain this title
825 string sBricksNeeded;
826 if (pTU != NULL)
828 sBricksNeeded = CI18N::get("uiTitleBrickHeader");
829 if (pTU->BricksNeeded.empty() || reservedTitle)
831 sBricksNeeded += CI18N::get("uiTitleBrickNoNeed");
833 else
835 // Get the list of "requirement bricks"
836 string listID = group->getId() + setup.PrefixForExtra + INFO_LIST_BRICK_REQUIREMENT;
837 IListSheetBase *listBrick= dynamic_cast<IListSheetBase*>(group->getElement(listID));
838 if(listBrick)
840 CSPhraseCom phrase;
841 phrase.Bricks = pTU->BricksNeeded;
842 fillSabrinaPhraseListBrick(phrase, listBrick);
846 strFindReplace(titleText, "%bricks", sBricksNeeded);
848 // setup the text
849 setHelpText(setup, titleText);
850 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpTitleInfo"));
852 // hide the ctrl sheet
853 setHelpCtrlSheet(setup, 0);
857 REGISTER_ACTION_HANDLER( CHandlerOpenTitleHelp, "open_title_help");
859 // ***************************************************************************
860 /** Build the help for a skill that is to trade
862 class CHandlerOpenSkillToTradeHelp : public IActionHandler
864 void execute (CCtrlBase *pCaller, const string &sParams)
866 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
867 if (cs != NULL)
869 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(cs);
870 if (!group) return;
871 CSheetHelpSetup setup;
872 setup.setupDefaultIDs();
873 setup.HelpWindow = group;
874 setup.SrcSheet = cs;
875 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getElement(group->getId()+":content:ctrl_slot"));
876 setupSkillToTradeHelp(setup);
880 REGISTER_ACTION_HANDLER( CHandlerOpenSkillToTradeHelp, "open_skill_to_trade_help");
882 // ***************************************************************************
883 /** Build the help window for a pact/item/brick and open it.
885 class CHandlerOpenHelpAuto : public IActionHandler
887 void execute (CCtrlBase *pCaller, const string &sParams)
889 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
890 if (!cs)
892 nlwarning("<CHandlerOpenHelpAuto::execute> no caller sheet found.");
893 return;
895 if (cs->getSheetId()!=0 )
897 // create group to display help
898 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(cs);
899 if (!group) return;
900 // setup the item.
901 CSheetHelpSetup setup;
902 setup.setupDefaultIDs();
903 setup.HelpWindow = group;
904 setup.SrcSheet = cs;
905 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getElement(group->getId()+":content:ctrl_slot"));
906 setupSheetHelp(setup);
910 REGISTER_ACTION_HANDLER( CHandlerOpenHelpAuto, "open_help_auto");
912 // ***************************************************************************
913 /** Browse an URL into a CGroupHTML
915 class CHandlerBrowse : public IActionHandler
917 void execute (CCtrlBase *pCaller, const string &sParams)
919 string container = getParam (sParams, "name");
920 CInterfaceElement *element = CWidgetManager::getInstance()->getElementFromId(container);
921 CInterfaceGroup *elementGroup = dynamic_cast<CInterfaceGroup*>(element);
923 string urls = getParam (sParams, "url");
925 bool show = getParam (sParams, "show") != "0";
927 bool localizePage= getParam (sParams, "localize")=="1";
929 // Action Handler?
930 if (strncmp (urls.c_str(), "ah:", 3) == 0)
932 // Find next action handler
933 string::size_type start = 3;
934 string::size_type end = urls.find ("&&", start);
935 if (end == string::npos)
936 end = urls.size();
937 while (start < end)
939 // Extract the url
940 string url = urls.substr(start, end-start);
942 // Run an action handler
943 string::size_type index = url.find_first_of("&");
944 if (index == string::npos)
945 index = url.size();
946 string action = url.substr(0, index);
947 string params;
948 if (index<url.size())
949 params = url.substr(index+1, url.size()-index-1);
951 // Replace '&'
952 if(action=="command")
954 // Replace : by ' '
955 index = 0;
956 while ((index = params.find_first_of("&", index)) != string::npos)
958 params[index] = ' ';
961 else
963 // Replace : by '|'
964 index = 0;
965 while ((index = params.find_first_of("&", index)) != string::npos)
967 params[index] = '|';
971 // Replace %HH encoding with ASCII values (AFTER '&' replacing, to possibly have reals '&')
972 for(uint i=0;i<params.size();i++)
974 if(params[i]=='%' && i<params.size()-2)
976 if(isxdigit(params[i+1]) && isxdigit(params[i+2])) // FIXME: Locale dependent
978 // read value from heax decimal
979 uint8 val= 0;
980 params[i+1]= tolower(params[i+1]); // FIXME: toLowerAscii
981 params[i+2]= tolower(params[i+2]); // FIXME: toLowerAscii
982 if(isdigit(params[i+1])) val= params[i+1]-'0';
983 else val= 10+ params[i+1]-'a';
984 val*=16;
985 if(isdigit(params[i+2])) val+= params[i+2]-'0';
986 else val+= 10+ params[i+2]-'a';
988 // write
989 params[i]= val;
990 // erase heax value
991 params.erase(i+1, 2);
996 CInterfaceManager::parseTokens(params);
997 // go. NB: the action handler himself may translate params from utf8
998 CAHManager::getInstance()->runActionHandler(action, elementGroup, params);
1000 // Next name
1001 start = end+2;
1002 end = urls.find ("&&", start);
1003 if (end == string::npos)
1004 end = urls.size();
1007 else
1009 // Get the group HTML
1010 if (element)
1012 // Group HTML ?
1013 CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(element);
1014 if (groupHtml)
1016 if (show)
1018 // Look for a parent container
1019 CInterfaceGroup *parent = groupHtml->getParent();
1020 while (parent)
1022 if (parent->getParent() && (parent->getParent()->getId() == "ui:interface"))
1024 parent->setActive(true);
1025 break;
1028 parent = parent->getParent();
1032 // localize if wanted
1033 if(localizePage)
1034 strFindReplace(urls, "_wk.", string("_")+ClientCfg.getHtmlLanguageCode()+"." );
1036 // Browse the url
1037 groupHtml->browse(urls.c_str());
1038 // Set top of the page
1039 CCtrlScroll *pScroll = groupHtml->getScrollBar();
1040 if (pScroll != NULL)
1041 pScroll->moveTrackY(10000);
1047 REGISTER_ACTION_HANDLER( CHandlerBrowse, "browse");
1049 // ***************************************************************************
1050 /** Browse Undo into a CGroupHTML
1052 class CHandlerBrowseUndo : public IActionHandler
1054 public:
1055 void execute (CCtrlBase *pCaller, const string &sParams)
1057 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1058 string container = getParam (sParams, "name");
1059 CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId(container));
1060 if (groupHtml)
1062 groupHtml->browseUndo();
1066 REGISTER_ACTION_HANDLER( CHandlerBrowseUndo, "browse_undo");
1068 // ***************************************************************************
1069 /** Browse Redo into a CGroupHTML
1071 class CHandlerBrowseRedo : public IActionHandler
1073 public:
1074 void execute (CCtrlBase *pCaller, const string &sParams)
1076 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1077 string container = getParam (sParams, "name");
1078 CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId(container));
1079 if (groupHtml)
1081 groupHtml->browseRedo();
1085 REGISTER_ACTION_HANDLER( CHandlerBrowseRedo, "browse_redo");
1087 // ***************************************************************************
1088 /** Browse Redo into a CGroupHTML
1090 class CHandlerBrowseRefresh : public IActionHandler
1092 public:
1093 void execute (CCtrlBase *pCaller, const string &sParams)
1095 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1096 string container = getParam (sParams, "name");
1097 CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId(container));
1098 if (groupHtml)
1100 groupHtml->refresh();
1104 REGISTER_ACTION_HANDLER( CHandlerBrowseRefresh, "browse_refresh");
1108 // ***************************************************************************
1109 class CHandlerHTMLSubmitForm : public IActionHandler
1111 void execute (CCtrlBase *pCaller, const string &sParams)
1113 string container = getParam (sParams, "name");
1115 uint button;
1116 if (!fromString(getParam(sParams, "button"), button))
1118 nlwarning("Invalid button index: '%s', expected integer", getParam(sParams, "button").c_str());
1119 return;
1122 sint32 x = pCaller ? pCaller->getEventX() : 0;
1123 sint32 y = pCaller ? pCaller->getEventY() : 0;
1125 CInterfaceElement *element = CWidgetManager::getInstance()->getElementFromId(container);
1127 // Group HTML ?
1128 CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(element);
1129 if (groupHtml)
1131 groupHtml->submitForm(button, x, y);
1133 else
1135 nlwarning("CGroupHTML with id '%s' not found.", container.c_str());
1140 REGISTER_ACTION_HANDLER( CHandlerHTMLSubmitForm, "html_submit_form");
1142 //////////////////////////////////
1143 // STATIC FUNCTIONS DEFINITIONS //
1144 //////////////////////////////////
1146 // ***************************************************************************
1147 static void setupHelpPage(CInterfaceGroup *window, const string &url)
1149 // must be a container
1150 CGroupContainer *gc= dynamic_cast<CGroupContainer*>(window);
1151 if(gc)
1152 gc->setHelpPage(url);
1155 // ***************************************************************************
1156 void setHelpText(CSheetHelpSetup &setup, const string &text)
1158 string copyStr= text;
1159 // remove trailing \n
1160 while(!copyStr.empty() && copyStr[copyStr.size()-1]=='\n')
1162 copyStr.resize(copyStr.size()-1);
1165 if (!setup.HelpWindow) return;
1166 CViewText *viewText= dynamic_cast<CViewText *>(setup.HelpWindow->getView(setup.ViewText));
1167 if(viewText)
1169 viewText->setTextFormatTaged(copyStr);
1171 CInterfaceGroup *viewTextGroup = setup.HelpWindow->getGroup(setup.ScrollTextGroup);
1172 if (viewTextGroup) viewTextGroup->setActive(true);
1173 if (!setup.ScrollTextIdGroup.empty())
1175 viewTextGroup = setup.HelpWindow->getGroup(setup.ScrollTextIdGroup);
1176 if (viewTextGroup) viewTextGroup->setActive(false);
1180 // ***************************************************************************
1181 void setHelpCtrlSheet(CSheetHelpSetup &setup, uint32 sheetId)
1183 if(setup.DestSheet)
1184 setup.DestSheet->setSheetId (sheetId);
1187 // ***************************************************************************
1188 void setHelpTextID(CSheetHelpSetup &setup, sint32 id)
1190 if (!setup.HelpWindow) return;
1191 CViewTextID *viewTextID = dynamic_cast<CViewTextID *>(setup.HelpWindow->getView(setup.ViewTextID));
1192 if(viewTextID)
1194 viewTextID->setTextId(id);
1196 if (!setup.ScrollTextGroup.empty())
1198 CInterfaceGroup *viewTextGroup = setup.HelpWindow->getGroup(setup.ScrollTextGroup);
1199 if (viewTextGroup) viewTextGroup->setActive(false);
1201 CInterfaceGroup *viewTextGroup = setup.HelpWindow->getGroup(setup.ScrollTextIdGroup);
1202 if (viewTextGroup) viewTextGroup->setActive(true);
1205 // ***************************************************************************
1206 static void setupHelpTitle(CInterfaceGroup *group, const string &title)
1208 CGroupContainer *pGC= dynamic_cast<CGroupContainer*>(group);
1209 if(!group)
1210 return;
1211 pGC->setTitle(title);
1214 // ***************************************************************************
1215 static void setupSkillToTradeHelp(CSheetHelpSetup &setup)
1217 if (!setup.HelpWindow) return;
1219 // get the calling item
1220 if (!setup.SrcSheet)
1222 nlwarning("<CHandlerOpenBrickHelp::execute> no caller sheet found.");
1223 return;
1226 SKILLS::ESkills skill = setup.SrcSheet->getSkill();
1227 if (skill >= SKILLS::unknown)
1229 nlwarning("bad skill");
1230 return;
1234 if(setup.DestSheet)
1236 setup.SrcSheet->copyAspect(setup.DestSheet);
1237 setup.DestSheet->setActive(true);
1240 string skillText;
1242 // Name in title
1243 const char *title = CStringManagerClient::getSkillLocalizedName(skill);
1244 setupHelpTitle(setup.HelpWindow, title);
1246 // search all job that have minimum required level for that skill
1247 // CInterfaceManager *im = CInterfaceManager::getInstance();
1248 // for (uint career = 0; career < JOBS::NUM_CAREER_DB_SLOTS; ++career)
1249 // {
1250 // for (uint job = 0; job < 8; ++job)
1251 // {
1252 // string dbPath = toString("CHARACTER_INFO:CAREER%d:JOB%d:JOB_CAP", (int) career, (int) job);
1253 // uint level = (uint) NLGUI::CDBManager::getInstance()->getDbProp(dbPath)->getValue32();
1254 // if (level != 0) // has the player this job ?
1255 // {
1256 // // check if level in this job is enough to get the skills
1257 // // TODO finish it
1258 // /*
1259 // JOBS::TJob job = JOBS::getJobFromDBIndex(career, job);
1260 // if (job != JOBS::Unknown)
1261 // {
1262 // }*/
1263 // }
1264 // }
1265 // }
1267 // setup skill desc if available.
1268 const char *desc = CStringManagerClient::getSkillLocalizedDescription(skill);
1269 if (*desc)
1271 skillText += "\n";
1272 skillText += desc;
1275 setHelpText(setup, skillText);
1279 // ***************************************************************************
1280 static string toReadableFloat(float val)
1282 sint iv= sint(val * 10);
1283 if((iv%10)==0)
1285 return toString(iv/10);
1287 else
1289 return toString("%.1f", val);
1293 // ***************************************************************************
1294 static string toPercentageText(float val)
1296 sint iv= sint(val * 1000);
1297 if((iv%10)==0)
1299 return toString(iv/10);
1301 else
1303 val= float(iv)/10;
1304 return toString("%.1f", val);
1308 // ***************************************************************************
1309 void getItemDefenseText(CDBCtrlSheet *item, string &itemText)
1311 // retrieve the current itemInfo
1312 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1314 // Parry/Dodge
1315 strFindReplace(itemText, "%dodge", toString(itemInfo.DodgeModifier) );
1316 strFindReplace(itemText, "%parry", toString(itemInfo.ParryModifier) );
1318 // Display All protections
1319 strFindReplace( itemText, "%protect", toPercentageText(itemInfo.ProtectionFactor) );
1320 strFindReplace( itemText, "%p_slash", toString(itemInfo.MaxSlashingProtection) );
1321 strFindReplace( itemText, "%p_pierce", toString(itemInfo.MaxPiercingProtection) );
1322 strFindReplace( itemText, "%p_blunt", toString(itemInfo.MaxBluntProtection) );
1326 void getDamageText(CDBCtrlSheet *item, const CItemSheet*pIS, string &itemText, bool displayAsMod)
1328 // retrieve the current itemInfo
1329 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1331 string strMod;
1332 if(displayAsMod)
1333 strMod= "+";
1334 strFindReplace(itemText, "%dmg", strMod + toString(itemInfo.CurrentDamage));
1335 if(displayAsMod)
1336 strMod= "+";
1337 strFindReplace(itemText, "%max_dmg", strMod + toString(itemInfo.MaxDamage));
1339 if(pIS->Family!=ITEMFAMILY::AMMO)
1341 // Display the Dodge/Parry Modifier
1342 strFindReplace(itemText, "%dodge", toString(itemInfo.DodgeModifier) );
1343 strFindReplace(itemText, "%parry", toString(itemInfo.ParryModifier) );
1345 // Display the Adversary Dodge/Parry Modifier
1346 strFindReplace(itemText, "%adv_dodge", toString(itemInfo.AdversaryDodgeModifier) );
1347 strFindReplace(itemText, "%adv_parry", toString(itemInfo.AdversaryParryModifier) );
1351 void getSpeedText(CDBCtrlSheet *item, string &itemText, bool displayAsMod)
1353 // retrieve the current itemInfo
1354 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1356 string strMod;
1357 if(displayAsMod)
1358 strMod= itemInfo.HitRate>=0?"+":"";
1359 strFindReplace(itemText, "%speed", strMod + toReadableFloat(itemInfo.HitRate));
1362 void getRangeText(CDBCtrlSheet *item, string &itemText, bool displayAsMod)
1364 // retrieve the current itemInfo
1365 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1367 string strMod;
1368 if(displayAsMod)
1369 strMod= itemInfo.Range>=0?"+":"";
1370 strFindReplace(itemText, "%range", strMod + toReadableFloat(itemInfo.Range/1000.f));
1373 void getHPAndSapLoadText(CDBCtrlSheet *item, const CItemSheet*pIS, string &itemText)
1375 // retrieve the current itemInfo
1376 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1378 if(pIS->Family != ITEMFAMILY::RAW_MATERIAL)
1380 // must find first hpmax! (else replace error)
1381 strFindReplace(itemText, "%hpmax", toString(itemInfo.HpMax) );
1382 strFindReplace(itemText, "%hp", toString(itemInfo.Hp) );
1383 // SapLoad
1384 strFindReplace(itemText, "%sapmax", toString(itemInfo.SapLoadMax) );
1385 strFindReplace(itemText, "%sap", toString(itemInfo.SapLoadCurrent) );
1390 void getBuffText(CDBCtrlSheet *item, string &itemText)
1392 // retrieve the current itemInfo
1393 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1395 const string valIds[]={"Hp", "Sap", "Sta", "Focus"};
1396 sint32 vals[]= {itemInfo.HpBuff, itemInfo.SapBuff, itemInfo.StaBuff, itemInfo.FocusBuff};
1397 uint numVals= sizeof(vals) / sizeof(vals[0]);
1398 string bufInfo;
1400 // For each buf, append a line if !=0
1401 for(uint i=0;i<numVals;i++)
1403 sint32 modifier= vals[i];
1404 if(modifier!=0)
1406 string line= CI18N::get( "uihelpItem" + valIds[i] + (modifier>0?"Bonus":"Malus") );
1407 strFindReplace(line, "%val", toString(modifier) );
1408 bufInfo+= line;
1412 // append a \n before
1413 if(!bufInfo.empty())
1414 bufInfo = "\n" + bufInfo + "\n";
1416 // Display the buff info.
1417 strFindReplace(itemText, "%buffs", bufInfo);
1420 void getMagicProtection(CDBCtrlSheet *item, string &itemText)
1422 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1423 // retrieve the current itemInfo
1424 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1426 string mProtInfo;
1428 // Header (always here, because at least max absorb)
1429 mProtInfo= CI18N::get("uihelpMagicProtectFormatHeader");
1431 // For each protection
1432 for(uint i=0;i<CClientItemInfo::MaxMagicProtectionByJewel;i++)
1434 if(itemInfo.MagicProtection[i] != PROTECTION_TYPE::None)
1436 // Protection info
1437 string str= CI18N::get("uihelpMagicProtectFormat");
1438 strFindReplace(str, "%t", CI18N::get("pt"+PROTECTION_TYPE::toString(itemInfo.MagicProtection[i])) );
1439 strFindReplace(str, "%v", toString(itemInfo.MagicProtectionFactor[i]) );
1440 mProtInfo+= str;
1444 // add Max damage absorbed
1446 // Mul item quality by a constant
1447 uint maxAbsorb= item->getQuality();
1448 CCDBNodeLeaf *nodeFactor= NLGUI::CDBManager::getInstance()->getDbProp(CWidgetManager::getInstance()->getParser()->getDefine("player_protect_absorbfactor"), false);
1449 if(nodeFactor)
1450 maxAbsorb= maxAbsorb*nodeFactor->getValue32()/100;
1452 // Add to text
1453 string str= CI18N::get("uihelpMagicProtectMaxAbsorbFormat");
1454 strFindReplace(str, "%v", toString(maxAbsorb) );
1455 mProtInfo+= str;
1458 // replace in item info
1459 strFindReplace(itemText, "%magic_protection", mProtInfo);
1462 void getMagicResistance(CDBCtrlSheet *item, string &itemText)
1464 // retrieve the current itemInfo
1465 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1467 string mResistInfo;
1469 // Header (always here, because at least max absorb)
1470 mResistInfo= CI18N::get("uihelpMagicResistFormatHeader");
1472 // For each resistance
1473 uint32 resist[RESISTANCE_TYPE::NB_RESISTANCE_TYPE];
1474 nlctassert(RESISTANCE_TYPE::NB_RESISTANCE_TYPE==5);
1475 resist[RESISTANCE_TYPE::Desert]= itemInfo.DesertMagicResistance;
1476 resist[RESISTANCE_TYPE::Forest]= itemInfo.ForestMagicResistance;
1477 resist[RESISTANCE_TYPE::Lacustre]= itemInfo.LacustreMagicResistance;
1478 resist[RESISTANCE_TYPE::Jungle]= itemInfo.JungleMagicResistance;
1479 resist[RESISTANCE_TYPE::PrimaryRoot]= itemInfo.PrimaryRootMagicResistance;
1480 for(uint i=0;i<RESISTANCE_TYPE::NB_RESISTANCE_TYPE;i++)
1482 if(resist[i] != 0)
1484 // Resist info
1485 string str= CI18N::get("uihelpMagicResistFormat");
1486 strFindReplace(str, "%t", CI18N::get("rs"+RESISTANCE_TYPE::toString((RESISTANCE_TYPE::TResistanceType)i) ));
1487 strFindReplace(str, "%v", toReadableFloat(float(resist[i])/100) );
1488 mResistInfo+= str;
1492 // replace in item info
1493 strFindReplace(itemText, "%magic_resistance", mResistInfo);
1496 void getActionMalus(CDBCtrlSheet *item, string &itemText)
1498 // retrieve the current itemInfo
1499 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1501 strFindReplace(itemText, "%actmalus", toPercentageText(itemInfo.WearEquipmentMalus) );
1504 void getBulkText(CDBCtrlSheet *item, const CItemSheet*pIS, string &itemText)
1506 // Display direct value: because cannot know where this item will be drop!! (bag, mektoub etc...)
1507 float slotBulkTotal= max((sint32)1, item->getQuantity()) * pIS->Bulk;
1509 // If stackable and bulk not 0, display in form "1 (10)". where (10) is the total of quantity*bulk
1510 if(pIS->Stackable>1 && pIS->Bulk>0)
1511 strFindReplace(itemText, "%bulk", toString("%.2f (%.2f)", pIS->Bulk, slotBulkTotal) );
1512 // else simple form
1513 else
1514 strFindReplace(itemText, "%bulk", toString("%.2f", slotBulkTotal) );
1517 void getWeightText(CDBCtrlSheet *item, const CItemSheet*pIS, string &itemText)
1519 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1521 CCDBNodeLeaf *pWG = NLGUI::CDBManager::getInstance()->getDbProp(item->getSheet()+":WEIGHT",false);
1522 if(pWG)
1524 // must mul weight by quantity
1525 sint32 slotWeight= pWG->getValue32();
1526 sint32 slotWeightTotal= max((sint32)1, item->getQuantity()) * slotWeight;
1528 // if stackable and weight not 0, display in form "1 (10)". where (10) is the total of quantity*weight
1529 if(pIS->Stackable>1 && slotWeight>0)
1531 string sws;
1532 string swt;
1533 if( (slotWeight%DB_WEIGHT_SCALE) == 0) sws= toString("%d", slotWeight/DB_WEIGHT_SCALE );
1534 else sws= toString("%.2f", float(slotWeight)/DB_WEIGHT_SCALE);
1535 if( (slotWeightTotal%DB_WEIGHT_SCALE) == 0) swt= toString("%d", slotWeightTotal/DB_WEIGHT_SCALE );
1536 else swt= toString("%.2f", float(slotWeightTotal)/DB_WEIGHT_SCALE);
1538 // combine
1539 strFindReplace(itemText, "%weight", toString("%s (%s)", sws.c_str(), swt.c_str() ));
1541 // else display in simple form
1542 else
1544 if( (slotWeightTotal%DB_WEIGHT_SCALE) == 0)
1545 strFindReplace(itemText, "%weight", toString("%d", slotWeightTotal/DB_WEIGHT_SCALE ));
1546 else
1547 strFindReplace(itemText, "%weight", toString("%.2f", float(slotWeightTotal)/DB_WEIGHT_SCALE) );
1550 else
1551 strFindReplace(itemText, "%weight", "???" );
1554 void getMagicBonus(CDBCtrlSheet *item, string &itemText)
1556 // retrieve the current itemInfo
1557 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1559 nlctassert(CClientItemInfo::NumMagicFactorType==4);
1560 const string valIds[CClientItemInfo::NumMagicFactorType]={"OffElemental", "OffAffliction", "DefHeal", "DefAffliction"};
1561 string mbInfo;
1563 // For each magic bonus, test first if equal
1564 sint32 allCastSpeedFactor= sint(itemInfo.CastingSpeedFactor[0]*100);
1565 sint32 allMagicPowerFactor= sint(itemInfo.MagicPowerFactor[0]*100);
1566 bool equal= true;
1567 for(uint i=1;i<CClientItemInfo::NumMagicFactorType;i++)
1569 sint32 cs= sint(itemInfo.CastingSpeedFactor[i]*100);
1570 sint32 mp= sint(itemInfo.MagicPowerFactor[i]*100);
1571 if( cs!=allCastSpeedFactor ||
1572 mp!=allMagicPowerFactor )
1574 equal= false;
1575 break;
1579 // if all are equal
1580 if(equal)
1582 // if 0, just display nothing
1583 if(allCastSpeedFactor!=0 || allMagicPowerFactor!=0)
1585 // else display "all"
1586 string line= CI18N::get( "uihelpItemMagicBonusAll");
1587 strFindReplace(line, "%cs", toString("%+d", allCastSpeedFactor) );
1588 strFindReplace(line, "%mp", toString("%+d", allMagicPowerFactor) );
1589 mbInfo+= line;
1592 else
1594 // then display info separated for each
1595 for(uint i=0;i<CClientItemInfo::NumMagicFactorType;i++)
1597 sint32 cs= sint(itemInfo.CastingSpeedFactor[i]*100);
1598 sint32 mp= sint(itemInfo.MagicPowerFactor[i]*100);
1599 if(cs!=0 || mp!=0)
1601 string line= CI18N::get( string("uihelpItemMagicBonus") + valIds[i] );
1602 strFindReplace(line, "%cs", toString("%+d", cs) );
1603 strFindReplace(line, "%mp", toString("%+d", mp) );
1604 mbInfo+= line;
1609 // append a \n before
1610 if(!mbInfo.empty())
1612 // add spell level header
1613 string spellRuleFmt= CI18N::get("uihelpItemMagicBonusHeader");
1614 strFindReplace(spellRuleFmt, "%mglvl", toString(item->getQuality()));
1615 mbInfo= spellRuleFmt + mbInfo;
1618 // Display the buff info.
1619 strFindReplace(itemText, "%magic_bonus", mbInfo);
1622 void getItemRequirementText(CDBCtrlSheet *item, const CItemSheet*pIS, string &itemText)
1624 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1625 bool requiredNeeded= false;
1626 string fmt, fmtc;
1628 // retrieve the current itemInfo
1629 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1631 if( itemInfo.RequiredCharac != CHARACTERISTICS::Unknown && itemInfo.RequiredCharacLevel != 0 )
1633 // Build the req string
1634 if(pIM->isItemCaracRequirementMet(itemInfo.RequiredCharac, (sint32)itemInfo.RequiredCharacLevel))
1635 fmtc = CI18N::get("uihelpItemCaracReqMetFmt");
1636 else
1637 fmtc = CI18N::get("uihelpItemCaracReqNotMetFmt");
1638 strFindReplace(fmtc, "%d", toString((uint)itemInfo.RequiredCharacLevel));
1639 strFindReplace(fmtc, "%s", CI18N::get(toString("uiCaracId%d", (uint)itemInfo.RequiredCharac)) );
1641 //strFindReplace(itemText, "%caracreq", fmtc );
1642 requiredNeeded = true;
1644 else
1646 //strFindReplace(itemText, "%caracreq", "" );
1649 if( itemInfo.RequiredSkillLevel > 0 )
1651 if( itemInfo.RequiredSkill != SKILLS::unknown )
1653 if (CSkillManager::getInstance()->checkBaseSkillMetRequirement(itemInfo.RequiredSkill, itemInfo.RequiredSkillLevel))
1654 fmt = CI18N::get("uihelpItemSkillReqMetFmt");
1655 else
1656 fmt = CI18N::get("uihelpItemSkillReqNotMetFmt");
1658 strFindReplace(fmt, "%d", toString((uint)itemInfo.RequiredSkillLevel));
1659 const char *skillName = STRING_MANAGER::CStringManagerClient::getSkillLocalizedName(itemInfo.RequiredSkill);
1660 strFindReplace(fmt, "%s", skillName);
1662 else
1664 if (CSkillManager::getInstance()->checkBaseSkillMetRequirement(SKILLS::unknown, itemInfo.RequiredSkillLevel))
1665 fmt = CI18N::get("uihelpItemAnySkillReqMetFmt");
1666 else
1667 fmt = CI18N::get("uihelpItemAnySkillReqNotMetFmt");
1669 strFindReplace(fmt, "%d", toString((uint)itemInfo.RequiredSkillLevel));
1672 strFindReplace(itemText, "%skillreq", fmt );
1673 requiredNeeded = true;
1675 else
1677 strFindReplace(itemText, "%skillreq", "" );
1680 if( itemInfo.RequiredSkillLevel2 > 0 )
1682 if( itemInfo.RequiredSkill2 != SKILLS::unknown )
1684 if (CSkillManager::getInstance()->checkBaseSkillMetRequirement(itemInfo.RequiredSkill2, itemInfo.RequiredSkillLevel2))
1685 fmt = CI18N::get("uihelpItemSkillReqMetFmt");
1686 else
1687 fmt = CI18N::get("uihelpItemSkillReqNotMetFmt");
1689 strFindReplace(fmt, "%d", toString((uint)itemInfo.RequiredSkillLevel2));
1690 const char *skillName = STRING_MANAGER::CStringManagerClient::getSkillLocalizedName(itemInfo.RequiredSkill2);
1691 strFindReplace(fmt, "%s", skillName);
1693 else
1695 if (CSkillManager::getInstance()->checkBaseSkillMetRequirement(SKILLS::unknown, itemInfo.RequiredSkillLevel2))
1696 fmt = CI18N::get("uihelpItemAnySkillReqMetFmt");
1697 else
1698 fmt = CI18N::get("uihelpItemAnySkillReqNotMetFmt");
1700 strFindReplace(fmt, "%d", toString((uint)itemInfo.RequiredSkillLevel2));
1703 strFindReplace(itemText, "%skillreq2", fmt );
1704 requiredNeeded = true;
1706 else
1708 strFindReplace(itemText, "%skillreq2", "" );
1711 if( requiredNeeded )
1712 strFindReplace(itemText, "%caracreq", fmtc );
1713 else
1714 strFindReplace(itemText, "%caracreq", CI18N::get("uihelpItemCaracReqNone") );
1716 #if 0
1717 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1719 // retrieve the current itemInfo
1720 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1722 CHARACTERISTICS::TCharacteristics caracType;
1723 float caracValue= 0.f;
1725 bool req = pIS->hasCharacRequirement(item->getQuality(), caracType, caracValue);
1727 bool req2 = (itemInfo.RequiredCharac != CHARACTERISTICS::Unknown && itemInfo.MinRequiredCharacLevel > 0);
1728 bool skillReq = (itemInfo.MinRequiredSkillLevel > 0 && itemInfo.RequiredSkill != SKILLS::unknown);
1730 // check item specific req
1731 if (req2)
1733 if (req)
1735 if (itemInfo.RequiredCharac == caracType && itemInfo.MinRequiredCharacLevel > caracValue)
1737 caracValue = itemInfo.MinRequiredCharacLevel;
1738 req2 = false;
1741 else
1743 caracValue = itemInfo.MinRequiredCharacLevel;
1744 caracType = itemInfo.RequiredCharac;
1745 req2 = false;
1746 req = true;
1750 if(req)
1752 // Build the req string
1753 string fmt;
1754 if(pIM->isItemCaracRequirementMet(caracType, (sint32)caracValue))
1755 fmt= CI18N::get("uihelpItemCaracReqMetFmt");
1756 else
1757 fmt= CI18N::get("uihelpItemCaracReqNotMetFmt");
1758 strFindReplace(fmt, "%d", toString((uint)caracValue));
1759 strFindReplace(fmt, "%s", CI18N::get(toString("uiCaracId%d", (uint)caracType)) );
1761 if (req2)
1763 fmt += CI18N::get("uihelpItemCaracReqAnd");
1764 if ( pIM->isItemCaracRequirementMet(itemInfo.RequiredCharac, (sint32)itemInfo.MinRequiredCharacLevel) )
1765 fmt += CI18N::get("uihelpItemCaracReqMetFmt");
1766 else
1767 fmt += CI18N::get("uihelpItemCaracReqNotMetFmt");
1768 strFindReplace(fmt, "%d", toString((uint)itemInfo.MinRequiredCharacLevel));
1769 strFindReplace(fmt, "%s", CI18N::get(toString("uiCaracId%d", (uint)itemInfo.RequiredCharac)) );
1772 strFindReplace(itemText, "%caracreq", fmt );
1774 else if (!skillReq)
1776 // empty
1777 strFindReplace(itemText, "%caracreq", CI18N::get("uihelpItemCaracReqNone") );
1779 else // skillReq and no charac req
1781 // empty
1782 strFindReplace(itemText, "%caracreq", "" );
1785 if (skillReq)
1787 // Build the req string
1788 string fmt;
1789 if (req)
1790 fmt = CI18N::get("uihelpItemCaracReqAnd");
1792 if (CSkillManager::getInstance()->checkBaseSkillMetRequirement(itemInfo.RequiredSkill, itemInfo.MinRequiredSkillLevel))
1793 fmt += CI18N::get("uihelpItemSkillReqMetFmt");
1794 else
1795 fmt += CI18N::get("uihelpItemSkillReqNotMetFmt");
1796 strFindReplace(fmt, "%d", toString((uint)itemInfo.MinRequiredSkillLevel));
1797 const char *skillName = STRING_MANAGER::CStringManagerClient::getSkillLocalizedName(itemInfo.RequiredSkill);
1798 strFindReplace(fmt, "%s", skillName);
1800 strFindReplace(itemText, "%skillreq", fmt );
1802 else
1804 strFindReplace(itemText, "%skillreq", "" );
1806 #endif
1809 void getSkillModVsType(CDBCtrlSheet *item, const CItemSheet*pIS, string &itemText)
1811 // retrieve the current itemInfo
1812 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1814 string sMod;
1815 // check skill mod
1816 if(!itemInfo.TypeSkillMods.empty())
1818 for (uint i = 0 ; i < itemInfo.TypeSkillMods.size() ; ++i)
1820 EGSPD::CClassificationType::TClassificationType type = itemInfo.TypeSkillMods[i].Type;
1822 sMod= CI18N::get("uihelpSkillModVsType");
1823 strFindReplace(sMod, "%mod", NLMISC::toString(itemInfo.TypeSkillMods[i].Modifier));
1824 strFindReplace(sMod, "%type", CStringManagerClient::getClassificationTypeLocalizedName(type));
1825 sMod += "\n\n";
1827 // TODO : process ALL mod
1828 break;
1832 strFindReplace(itemText, "%skill_mod_vs_type", sMod);
1835 void getArmorBonus(CDBCtrlSheet *item, string &itemText, const CItemSheet*pIS)
1837 string armor_bonus;
1838 sint32 level = 0;
1840 if (pIS->Armor.ArmorType == ARMORTYPE::HEAVY)
1841 level = item->getQuality();
1842 else if (pIS->Armor.ArmorType == ARMORTYPE::MEDIUM)
1843 level = item->getQuality() / 2;
1845 if (pIS->Armor.ArmorType == ARMORTYPE::HEAVY || pIS->Armor.ArmorType == ARMORTYPE::MEDIUM)
1846 armor_bonus = "@{FFFF}(+@{2F2F}" + toString(level) + " @{FFFF}" + CI18N::get("uiHP") + ")";
1848 strFindReplace(itemText, "%armor_bonus", armor_bonus);
1851 // ***************************************************************************
1852 void getItemText (CDBCtrlSheet *item, string &itemText, const CItemSheet*pIS)
1854 if ((item == NULL) || (pIS == NULL))
1855 return;
1857 // *** Select the correct format according to item family.
1858 switch(pIS->Family)
1860 case ITEMFAMILY::ARMOR : itemText= CI18N::get("uihelpItemArmorFormat"); break;
1861 case ITEMFAMILY::MELEE_WEAPON : itemText= CI18N::get("uihelpItemMeleeWeaponFormat"); break;
1862 case ITEMFAMILY::RANGE_WEAPON : itemText= CI18N::get("uihelpItemRangeWeaponFormat"); break;
1863 case ITEMFAMILY::AMMO : itemText= CI18N::get("uihelpItemAmmoFormat"); break;
1864 case ITEMFAMILY::RAW_MATERIAL : itemText= CI18N::get("uihelpItemMPFormat"); break;
1865 case ITEMFAMILY::SHIELD : itemText= CI18N::get("uihelpItemShieldFormat"); break;
1866 case ITEMFAMILY::CRAFTING_TOOL : itemText= CI18N::get("uihelpItemCraftingToolFormat"); break;
1867 case ITEMFAMILY::HARVEST_TOOL : itemText= CI18N::get("uihelpItemHarvestToolFormat"); break;
1868 case ITEMFAMILY::TAMING_TOOL : itemText= CI18N::get("uihelpItemTamingToolFormat"); break;
1869 case ITEMFAMILY::JEWELRY : itemText= CI18N::get("uihelpItemJewelFormat"); break;
1870 case ITEMFAMILY::CRYSTALLIZED_SPELL : itemText= CI18N::get("uihelpItemCrystalSpell"); break;
1871 case ITEMFAMILY::ITEM_SAP_RECHARGE : itemText= CI18N::get("uihelpItemChargeSpell"); break;
1872 case ITEMFAMILY::PET_ANIMAL_TICKET : itemText= CI18N::get("uihelpItemAnimal"); break;
1873 case ITEMFAMILY::TELEPORT : itemText= CI18N::get("uihelpItemTeleport"); break;
1874 case ITEMFAMILY::COSMETIC : itemText= CI18N::get("uihelpItemCosmetic"); break;
1875 case ITEMFAMILY::SCROLL : itemText= CI18N::get("uihelpItemScroll"); break;
1876 case ITEMFAMILY::SCROLL_R2 : itemText = CI18N::get("uihelpItemScrollR2"); break;
1877 case ITEMFAMILY::CONSUMABLE : itemText= CI18N::get("uihelpItemConsumableFormat"); break;
1878 default: itemText= CI18N::get("uihelpItemDefaultFormat");
1882 // *** Replace Common part
1883 strFindReplace(itemText, "%origin", CI18N::get("io"+ITEM_ORIGIN::enumToString(pIS->ItemOrigin)) );
1884 strFindReplace(itemText, "%quality", toString(item->getQuality()) );
1885 strFindReplace(itemText, "%quantity", toString(item->getQuantity()) );
1886 // display Weight
1887 getWeightText(item, pIS, itemText);
1888 // display Bulk
1889 getBulkText(item, pIS, itemText);
1890 // Get the SapLoad...
1891 getHPAndSapLoadText(item, pIS, itemText);
1892 // Get carac and skill Requirement
1893 getItemRequirementText(item, pIS, itemText);
1894 // Get Item effect
1895 CItemSpecialEffectHelper::getInstance()->getItemSpecialEffectText(pIS, itemText);
1897 // Description
1898 const char *desc = CStringManagerClient::getItemLocalizedDescription(pIS->Id);
1899 if (*desc)
1901 strFindReplace(itemText, "%desc", "@{FFF9}" + CI18N::get("uiMissionDesc") + "\n@{FFFF}" + desc + "\n" );
1903 else
1904 strFindReplace(itemText, "%desc", string() );
1906 // Custom text
1907 const CClientItemInfo &itemInfo = getInventory().getItemInfo(getInventory().getItemSlotId(item) );
1908 if (!itemInfo.CustomText.empty())
1910 std::string text = itemInfo.CustomText.toUtf8();
1911 if (text.size() > 3 && text[0]=='@' && ((text[1]=='W' && text[2]=='E' && text[3]=='B') || (text[1]=='L' && text[2]=='U' && text[3]=='A')))
1913 strFindReplace(itemText, "%custom_text", string() );
1915 else
1917 strFindReplace(itemText, "%custom_text", "\n@{FFFF}" + itemInfo.CustomText.toUtf8() + "\n");
1918 string itemMFC = CI18N::get("uiItemTextMessageFromCrafter");
1919 strFindReplace(itemText, "%mfc", itemMFC);
1922 else
1923 strFindReplace(itemText, "%custom_text", string() );
1925 if ( pIS->Family == ITEMFAMILY::COSMETIC )
1927 EGSPD::CPeople::TPeople people = ITEM_ORIGIN::itemOriginStringToPeopleEnum( ITEM_ORIGIN::enumToString( pIS->ItemOrigin ) );
1928 if ( UserEntity->getGender() != pIS->Cosmetic.Gender || UserEntity->people() != people )
1929 strFindReplace(itemText, "%cansell", CI18N::get("uihelpItemCosmeticDontFit") );
1930 else
1931 strFindReplace(itemText, "%cansell", string() );
1933 else if(pIS->DropOrSell )
1934 strFindReplace(itemText, "%cansell", string() );
1935 else
1936 strFindReplace(itemText, "%cansell", CI18N::get("uihelpItemCantSell") );
1938 // *** Replace special for each type
1939 switch(pIS->Family)
1941 case ITEMFAMILY::ARMOR :
1943 strFindReplace(itemText, "%armor", CI18N::get("at"+ARMORTYPE::toString(pIS->Armor.ArmorType)));
1944 // Armor bonus based on armor type
1945 getArmorBonus(item, itemText, pIS);
1946 // Protection
1947 getItemDefenseText(item, itemText);
1948 // Player buffs
1949 getBuffText(item, itemText);
1950 // action malus
1951 getActionMalus(item, itemText);
1953 break;
1954 case ITEMFAMILY::MELEE_WEAPON :
1956 strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(pIS->MeleeWeapon.Skill) );
1957 strFindReplace(itemText, "%cat", CI18N::get("wt"+WEAPONTYPE::toString(pIS->MeleeWeapon.WeaponType)) );
1958 strFindReplace(itemText, "%dmtype", CI18N::get("dt"+DMGTYPE::toString(pIS->MeleeWeapon.DamageType)) );
1959 strFindReplace(itemText, "%reach", toString(pIS->MeleeWeapon.MeleeRange) );
1960 // Damage / Speed
1961 getDamageText(item, pIS, itemText, false);
1962 getSpeedText(item, itemText, false);
1963 // Player buffs
1964 getBuffText(item, itemText);
1965 // action malus
1966 getActionMalus(item, itemText);
1967 // magical bonus
1968 getMagicBonus(item, itemText);
1969 // skill bonus against specific types
1970 getSkillModVsType(item, pIS, itemText);
1972 break;
1973 case ITEMFAMILY::RANGE_WEAPON :
1975 strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(pIS->RangeWeapon.Skill) );
1976 strFindReplace(itemText, "%cat", CI18N::get("wt"+WEAPONTYPE::toString(pIS->RangeWeapon.WeaponType)) );
1977 // Damage / Speed / Range
1978 getDamageText(item, pIS, itemText, true);
1979 getSpeedText(item, itemText, false);
1980 getRangeText(item, itemText, false);
1981 // Player buffs
1982 getBuffText(item, itemText);
1983 // action malus
1984 getActionMalus(item, itemText);
1985 // magical bonus
1986 getMagicBonus(item, itemText);
1987 // skill bonus against specific types
1988 getSkillModVsType(item, pIS, itemText);
1990 break;
1991 case ITEMFAMILY::AMMO :
1993 // Localization
1994 strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(pIS->Ammo.Skill) ) ;
1995 strFindReplace(itemText, "%dmtype", CI18N::get("dt"+DMGTYPE::toString(pIS->Ammo.DamageType)) );
1996 // WARNING: here 999 is hardcoded because of the new global limit of stacks (999), Ammo.Magazine should not be used anymore
1997 if (item->getUseQuantity())
1998 strFindReplace(itemText, "%magazine", toString(item->getQuantity()) + " / " + toString(999 /*pIS->Ammo.Magazine*/) );
1999 else
2000 strFindReplace(itemText, "%magazine", toString(999 /*pIS->Ammo.Magazine*/) );
2002 // Damage / Speed / Range
2003 getDamageText(item, pIS, itemText, false);
2004 getSpeedText(item, itemText, true);
2005 getRangeText(item, itemText, true);
2007 break;
2008 case ITEMFAMILY::RAW_MATERIAL :
2010 // Basics
2011 strFindReplace(itemText, "%ecosystem", CI18N::get("ecosys"+ECOSYSTEM::toString(pIS->Mp.Ecosystem)) ) ;
2012 strFindReplace(itemText, "%family", RM_FAMILY::toLocalString(pIS->Mp.Family) ) ;
2013 strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(pIS->Mp.HarvestSkill) ) ;
2015 // MpColor
2016 if( RM_COLOR::validColor(pIS->Mp.MpColor) )
2017 strFindReplace(itemText, "%mpcolor", RM_COLOR::toLocalString(pIS->Mp.MpColor) ) ;
2018 else
2019 strFindReplace(itemText, "%mpcolor", "???" );
2021 // Craft some part?
2022 if(pIS->canBuildSomeItemPart())
2024 string fmt= CI18N::get("uihelpItemMPCraft");
2025 string ipList;
2026 pIS->getItemPartListAsText(ipList);
2027 strFindReplace(fmt, "%ip", ipList);
2028 strFindReplace(itemText, "%craft", fmt);
2030 // Craft Mp requirement?
2031 else if(pIS->isUsedAsCraftRequirement())
2032 strFindReplace(itemText, "%craft", CI18N::get("uihelpItemMPCraftRequirement"));
2033 // No Craft at all
2034 else
2035 strFindReplace(itemText, "%craft", CI18N::get("uihelpItemMPNoCraft"));
2037 break;
2038 case ITEMFAMILY::SHIELD :
2040 //strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(SHIELDTYPE::shieldTypeToSkill(pIS->Shield.ShieldType)) );
2041 strFindReplace(itemText, "%cat", CI18N::get("st"+SHIELDTYPE::toString(pIS->Shield.ShieldType)) );
2042 // Protection
2043 getItemDefenseText(item, itemText);
2044 // Player buffs
2045 getBuffText(item, itemText);
2046 // action malus
2047 getActionMalus(item, itemText);
2049 break;
2050 // Crafting Tool: the skill is not valid, since depends on what is built.
2051 case ITEMFAMILY::CRAFTING_TOOL :
2053 strFindReplace(itemText, "%tool", CI18N::get("tool"+TOOL_TYPE::toString(pIS->Tool.CraftingToolType)) );
2054 // Player buffs
2055 getBuffText(item, itemText);
2057 break;
2058 case ITEMFAMILY::HARVEST_TOOL :
2060 strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(pIS->Tool.Skill) );
2061 // Player buffs
2062 getBuffText(item, itemText);
2064 break;
2065 case ITEMFAMILY::TAMING_TOOL :
2067 strFindReplace(itemText, "%skill", CStringManagerClient::getSkillLocalizedName(pIS->Tool.Skill) );
2068 strFindReplace(itemText, "%cmdrange", toString(pIS->Tool.CommandRange) );
2069 strFindReplace(itemText, "%maxpacker", toString(pIS->Tool.MaxDonkey) );
2071 break;
2072 case ITEMFAMILY::JEWELRY :
2074 // Player buffs
2075 getBuffText(item, itemText);
2076 // Magic protection
2077 getMagicProtection(item, itemText);
2078 // Magic Resistances
2079 getMagicResistance(item, itemText);
2081 break;
2082 case ITEMFAMILY::CONSUMABLE :
2084 strFindReplace(itemText, "%consumption_time", toString(pIS->Consumable.ConsumptionTime));
2085 strFindReplace(itemText, "%overdose_timer_min", toString(pIS->Consumable.OverdoseTimer/60));
2086 strFindReplace(itemText, "%overdose_timer_sec", toString(pIS->Consumable.OverdoseTimer % 60));
2087 // Get Item Consumable infos
2088 CItemConsumableEffectHelper::getInstance()->getItemConsumableEffectText(pIS, itemText, item->getQuality());
2090 break;
2091 case ITEMFAMILY::SCROLL_R2:
2093 strFindReplace(itemText, "%r2_description_text", toString(itemInfo.R2ItemDescription));
2094 strFindReplace(itemText, "%r2_comment_text", toString(itemInfo.R2ItemComment));
2096 break;
2097 case ITEMFAMILY::PET_ANIMAL_TICKET:
2099 string nr = (itemInfo.PetNumber > 0) ? toString(itemInfo.PetNumber) : "(slot)" + toString(item->getIndexInDB());
2100 strFindReplace(itemText, "%petnumber", nr);
2102 break;
2103 default:
2105 strFindReplace(itemText, "%no_rent", pIS->IsItemNoRent ? CI18N::get("uihelpItemNoRent") : string(""));
2106 strFindReplace(itemText, "%descnr", pIS->IsItemNoRent ? CI18N::get("uihelpItemNoRentDesc") : string(""));
2108 break;
2111 #ifdef NL_DEBUG
2112 INVENTORIES::TInventory inventory = (INVENTORIES::TInventory)item->getInventoryIndex();
2113 sint32 slot = item->getIndexInDB();
2114 string debugText = NLMISC::toString("inventory: %s\nslot: %d\n", INVENTORIES::toString(inventory).c_str(), slot);
2115 itemText = debugText + itemText;
2116 #endif
2120 // ***************************************************************************
2121 static void setupEnchantedItem(CSheetHelpSetup &setup, string &itemText)
2123 // if don't find the tag in the text (eg: if not useful), no-op
2124 static const string enchantTag("%enchantment");
2125 if( itemText.find(enchantTag) == string::npos )
2126 return;
2128 // retrieve the current itemInfo
2129 CDBCtrlSheet *ctrl= setup.SrcSheet;
2130 CInterfaceGroup *group= setup.HelpWindow;
2131 if(!ctrl || !group)
2132 return;
2133 const CClientItemInfo &itemInfo= getInventory().getItemInfo(getInventory().getItemSlotId(ctrl) );
2134 IListSheetBase *listBrick= dynamic_cast<IListSheetBase*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_LIST_BRICK));
2136 // if the item is enchanted
2137 if( !itemInfo.Enchantment.empty())
2139 CSPhraseManager *pPM= CSPhraseManager::getInstance();
2141 // fill the enchantement info
2142 string enchantInfo;
2143 const CItemSheet *pIS= ctrl->asItemSheet();
2144 if(pIS && pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL)
2145 pPM->buildPhraseDesc(enchantInfo, itemInfo.Enchantment, 0, false, "uihelpPhraseCrystalSpellFormat");
2146 else
2147 pPM->buildPhraseDesc(enchantInfo, itemInfo.Enchantment, 0, false, "uihelpPhraseEnchantmentFormat");
2149 // replace
2150 strFindReplace(itemText, enchantTag, enchantInfo );
2152 // if exist, setup text header
2153 if(listBrick)
2154 setupListBrickHeader(setup);
2156 // fill the bricks
2157 fillSabrinaPhraseListBrick(itemInfo.Enchantment, listBrick);
2159 else
2161 // must hide the listBrick
2162 if(listBrick)
2163 listBrick->setActive(false);
2165 // hide the list brick header
2166 hideListBrickHeader(setup);
2168 // hide the text
2169 strFindReplace(itemText, enchantTag, string());
2174 // ***************************************************************************
2175 static void setupRawMaterialStats(CSheetHelpSetup &setup)
2177 // retrieve the current itemInfo
2178 CDBCtrlSheet *ctrl= setup.SrcSheet;
2179 CInterfaceGroup *group= setup.HelpWindow;
2180 if(!ctrl || !group)
2181 return;
2183 // get the group for raw material stat
2184 CInterfaceGroup *groupMp= dynamic_cast<CInterfaceGroup*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_GROUP_MP_STAT));
2185 if(!groupMp)
2186 return;
2188 // if the item is a Mp
2189 const CItemSheet *pIS= ctrl->asItemSheet();
2190 if(pIS && pIS->Family == ITEMFAMILY::RAW_MATERIAL)
2192 // If the MP can craft some item part
2193 if(pIS->canBuildSomeItemPart())
2195 // activate the mp stat group
2196 groupMp->setActive(true);
2198 // Initialize the itempart selection combo box
2199 CDBGroupComboBox *pCB= dynamic_cast<CDBGroupComboBox*>(groupMp->getElement(groupMp->getId()+":item_part_choice" ));
2200 if( pCB )
2202 pCB->resetTexts();
2203 for(uint i=0;i<RM_FABER_TYPE::NUM_FABER_TYPE;i++)
2205 RM_FABER_TYPE::TRMFType faberType= RM_FABER_TYPE::TRMFType(i);
2207 if(pIS->canBuildItemPart(faberType))
2209 pCB->addText(RM_FABER_TYPE::toLocalString(faberType));
2213 // force reset, but try to keep the precedent selection
2214 // (useful to test same item-part from different MPs)
2215 sint32 precSel= pCB->getSelection();
2216 pCB->setSelection(1);
2217 pCB->setSelection(0);
2218 if(precSel>=0 && precSel<(sint32)pCB->getNumTexts())
2220 pCB->setSelection(precSel);
2224 else
2226 // just hide it
2227 groupMp->setActive(false);
2230 else
2232 // just hide it
2233 groupMp->setActive(false);
2237 // ***************************************************************************
2238 void resetSheetHelp(CSheetHelpSetup &setup)
2240 CInterfaceGroup *group= setup.HelpWindow;
2241 if(!group)
2242 return;
2244 // Hide the list of items by default
2245 IListSheetBase *listItem= dynamic_cast<IListSheetBase*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_LIST_ITEM));
2246 if(listItem)
2248 listItem->setActive(false);
2251 // Hide the item preview by default
2252 CInterfaceElement *elt= group->getElement(group->getId()+setup.PrefixForExtra+INFO_ITEM_PREVIEW);
2253 if(elt)
2255 elt->setActive(false);
2258 // Hide the list of brick by default
2259 IListSheetBase *listBrick= dynamic_cast<IListSheetBase*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_LIST_BRICK));
2260 if(listBrick)
2262 listBrick->setActive(false);
2264 // Hide the mpstats by default
2265 CInterfaceGroup *groupMp= dynamic_cast<CInterfaceGroup*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_GROUP_MP_STAT));
2266 if(groupMp)
2267 groupMp->setActive(false);
2268 // Hide the list of brick requirement by default
2269 listBrick= dynamic_cast<IListSheetBase*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_LIST_BRICK_REQUIREMENT));
2270 if(listBrick)
2272 listBrick->setActive(false);
2274 // Hide the listBrick header by default
2275 CViewText *view= dynamic_cast<CViewText*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_LIST_BRICK_HEADER));
2276 if(view)
2278 view->setActive(false);
2281 CInterfaceGroup *groupCosmetic = dynamic_cast<CInterfaceGroup*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_GROUP_CHAR_3D));
2282 if(groupCosmetic)
2283 groupCosmetic->setActive(false);
2287 // ***************************************************************************
2288 static void setupItemHelp(CSheetHelpSetup &setup)
2290 if (!setup.HelpWindow) return;
2292 // get the calling item
2293 if (!setup.SrcSheet || setup.SrcSheet->getType()!=CCtrlSheetInfo::SheetType_Item )
2295 nlwarning("<CHandlerOpenItemHelp::execute> no caller sheet found");
2296 return;
2299 // If the sheet is 0, don't open!
2300 if(setup.SrcSheet->getSheetId()==0)
2301 return;
2303 if(setup.DestSheet)
2305 setup.SrcSheet->copyAspect(setup.DestSheet);
2306 setup.DestSheet->setActive(true);
2309 // NB: for raw materials only, must do each once only, must not do it at refresh, cause combo reseted
2310 setupRawMaterialStats(setup);
2312 // update the item Help
2313 refreshItemHelp(setup);
2317 // ***************************************************************************
2318 void setupCosmetic(CSheetHelpSetup &setup, CItemSheet *pIS)
2320 nlassert(pIS);
2321 if(pIS->Family!=ITEMFAMILY::COSMETIC)
2322 return;
2324 EGSPD::CPeople::TPeople people = ITEM_ORIGIN::itemOriginStringToPeopleEnum( ITEM_ORIGIN::enumToString( pIS->ItemOrigin ) );
2325 if ( !( UserEntity->getGender() != pIS->Cosmetic.Gender || UserEntity->people() != people ) )
2327 CInterfaceGroup *groupCosmetic = dynamic_cast<CInterfaceGroup*>(setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_GROUP_CHAR_3D));
2328 if(groupCosmetic)
2329 groupCosmetic->setActive(true);
2330 // display the character head in the help window
2331 CCharacterSummary cs;
2332 SCharacter3DSetup::setupCharacterSummaryFromSERVERDB( cs );
2333 // we dont want to display helmets
2334 cs.VisualPropA.PropertySubData.HatModel = SCharacter3DSetup::getDB ( "SERVER:USER:HAIR_TYPE" );
2335 cs.VisualPropA.PropertySubData.HatColor = SCharacter3DSetup::getDB ("SERVER:USER:HAIR_COLOR");
2336 if ( pIS->ItemType == ITEM_TYPE::HAIR_MALE || pIS->ItemType == ITEM_TYPE::HAIR_FEMALE )
2337 cs.VisualPropA.PropertySubData.HatModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::HEAD_SLOT );
2338 else if ( pIS->ItemType == ITEM_TYPE::TATOO_MALE || pIS->ItemType == ITEM_TYPE::TATOO_FEMALE )
2339 cs.VisualPropC.PropertySubData.Tattoo = pIS->Cosmetic.VPValue;
2340 else if ( pIS->ItemType == ITEM_TYPE::HAIRCOLOR_MALE || pIS->ItemType == ITEM_TYPE::HAIRCOLOR_FEMALE )
2341 cs.VisualPropA.PropertySubData.HatColor = pIS->Cosmetic.VPValue;
2342 else
2343 nlwarning("<setupItemHelp> Invalid cosmetic item type '%s'",ITEM_TYPE::toString( pIS->ItemType ).c_str() );
2345 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D",cs );
2349 // ***************************************************************************
2350 void setupItemPreview(CSheetHelpSetup &setup, CItemSheet *pIS)
2352 nlassert(pIS);
2354 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2355 CCDBNodeBranch *dbBranch = NLGUI::CDBManager::getInstance()->getDbBranch( setup.SrcSheet->getSheet() );
2358 CInterfaceElement *elt = setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_ITEM_PREVIEW);
2359 if (elt == NULL)
2360 return;
2362 CInterfaceGroup *ig = dynamic_cast<CInterfaceGroup*>(elt);
2364 if ( ! ig)
2366 return;
2369 static sint32 helpWidth = setup.HelpWindow->getW();
2370 bool scene_inactive = ! NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_3D_ITEM_PREVIEW")->getValueBool();
2371 if (scene_inactive ||
2372 (pIS->Family != ITEMFAMILY::ARMOR &&
2373 pIS->Family != ITEMFAMILY::MELEE_WEAPON &&
2374 pIS->Family != ITEMFAMILY::RANGE_WEAPON &&
2375 pIS->Family != ITEMFAMILY::SHIELD))
2377 setup.HelpWindow->setW(helpWidth);
2378 ig->setActive(false);
2379 return;
2381 else
2383 setup.HelpWindow->setW(helpWidth + ITEM_PREVIEW_WIDTH);
2384 ig->setActive(true);
2387 CInterface3DScene *sceneI = dynamic_cast<CInterface3DScene *>(ig->getGroup("scene_item_preview"));
2388 if (!sceneI)
2390 nlwarning("Can't retrieve character 3d view, or bad type");
2391 ig->setActive(false);
2392 return;
2395 CInterface3DCharacter *char3DI = NULL;
2396 if (sceneI->getCharacter3DCount() != 0)
2397 char3DI = sceneI->getCharacter3D(0);
2399 if (char3DI == NULL)
2401 nlwarning("Can't retrieve char 3D Interface");
2402 ig->setActive(false);
2403 return;
2406 CInterface3DCamera *camera = sceneI->getCamera(0);
2407 if (camera == NULL)
2409 nlwarning("Can't retrieve camera");
2410 ig->setActive(false);
2411 return;
2415 SCharacter3DSetup c3Ds;
2417 CCharacterSummary cs;
2418 SCharacter3DSetup::setupCharacterSummaryFromSERVERDB( cs );
2420 float camHeight = -0.85f;
2422 if (pIS->Family == ITEMFAMILY::ARMOR)
2424 if (pIS->ItemType == ITEM_TYPE::LIGHT_BOOTS || pIS->ItemType == ITEM_TYPE::MEDIUM_BOOTS || pIS->ItemType == ITEM_TYPE::HEAVY_BOOTS)
2426 CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
2427 cs.VisualPropB.PropertySubData.FeetModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::FEET_SLOT );
2428 cs.VisualPropB.PropertySubData.FeetColor = color->getValue32();
2429 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2430 camHeight = -1.15f;
2432 else if (pIS->ItemType == ITEM_TYPE::LIGHT_GLOVES || pIS->ItemType == ITEM_TYPE::MEDIUM_GLOVES || pIS->ItemType == ITEM_TYPE::HEAVY_GLOVES)
2434 CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
2435 cs.VisualPropB.PropertySubData.HandsModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::HANDS_SLOT );
2436 cs.VisualPropB.PropertySubData.HandsColor = color->getValue32();
2437 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2438 //cs.VisualPropB.PropertySubData.HandsColor = pIS->Color;
2440 else if (pIS->ItemType == ITEM_TYPE::LIGHT_SLEEVES || pIS->ItemType == ITEM_TYPE::MEDIUM_SLEEVES || pIS->ItemType == ITEM_TYPE::HEAVY_SLEEVES)
2442 CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
2443 cs.VisualPropA.PropertySubData.ArmModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::ARMS_SLOT );
2444 cs.VisualPropA.PropertySubData.ArmColor = color->getValue32();
2445 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2446 //cs.VisualPropA.PropertySubData.ArmColor = pIS->Color;
2447 camHeight = -0.55f;
2449 else if (pIS->ItemType == ITEM_TYPE::LIGHT_PANTS || pIS->ItemType == ITEM_TYPE::MEDIUM_PANTS || pIS->ItemType == ITEM_TYPE::HEAVY_PANTS)
2451 CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
2452 cs.VisualPropA.PropertySubData.TrouserModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::LEGS_SLOT );
2453 cs.VisualPropA.PropertySubData.TrouserColor = color->getValue32();
2454 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2455 camHeight = -1.00f;
2457 else if (pIS->ItemType == ITEM_TYPE::LIGHT_VEST || pIS->ItemType == ITEM_TYPE::MEDIUM_VEST || pIS->ItemType == ITEM_TYPE::HEAVY_VEST)
2459 CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
2460 cs.VisualPropA.PropertySubData.JacketModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::CHEST_SLOT );
2461 cs.VisualPropA.PropertySubData.JacketColor = color->getValue32();
2462 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2463 camHeight = -0.55f;
2465 else if (pIS->ItemType == ITEM_TYPE::HEAVY_HELMET)
2467 CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
2468 cs.VisualPropA.PropertySubData.HatModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::HEAD_SLOT );
2469 cs.VisualPropA.PropertySubData.HatColor = color->getValue32();
2470 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2471 camHeight = -0.35f;
2474 else if (pIS->Family == ITEMFAMILY::SHIELD)
2476 cs.VisualPropA.PropertySubData.WeaponLeftHand = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::LEFT_HAND_SLOT );
2477 if (cs.VisualPropA.PropertySubData.WeaponRightHand != 0)
2479 CItemSheet *pES = SheetMngr.getItem(SLOTTYPE::RIGHT_HAND_SLOT, cs.VisualPropA.PropertySubData.WeaponRightHand);
2480 if (pES->ItemType == ITEM_TYPE::TWO_HAND_AXE || pES->ItemType == ITEM_TYPE::TWO_HAND_MACE || pES->ItemType == ITEM_TYPE::TWO_HAND_SWORD ||
2481 pES->ItemType == ITEM_TYPE::MAGICIAN_STAFF || pES->ItemType == ITEM_TYPE::AUTOLAUCH || pES->ItemType == ITEM_TYPE::LAUNCHER || pES->ItemType == ITEM_TYPE::RIFLE)
2482 cs.VisualPropA.PropertySubData.WeaponRightHand = 0;
2484 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2487 else if (pIS->Family == ITEMFAMILY::MELEE_WEAPON || pIS->Family == ITEMFAMILY::RANGE_WEAPON)
2489 cs.VisualPropA.PropertySubData.WeaponRightHand = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::RIGHT_HAND_SLOT );
2490 cs.VisualPropA.PropertySubData.WeaponLeftHand = 0;
2491 SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
2493 else
2494 nlwarning("<setupItemPreview> Invalid armour or weapon item type '%s'", ITEM_TYPE::toString( pIS->ItemType ).c_str() );
2496 if (camera == NULL)
2497 return;
2499 camera->setTgtZ(camHeight);
2500 char3DI->setAnim(CAnimationStateSheet::Idle);
2503 // ***************************************************************************
2504 void refreshItemHelp(CSheetHelpSetup &setup)
2506 // Setup creator name view
2507 setupCreatorName(setup);
2509 // **** setup the item Text info
2510 string itemText;
2511 CEntitySheet *pES = SheetMngr.get ( CSheetId(setup.SrcSheet->getSheetId()) );
2512 if ((pES != NULL) && (pES->type() == CEntitySheet::ITEM))
2514 CItemSheet *pIS = (CItemSheet*)pES;
2516 // ---- Common
2517 string title = setup.SrcSheet->getItemActualName();
2518 setupHelpTitle(setup.HelpWindow, title );
2519 getItemText (setup.SrcSheet, itemText, pIS);
2521 // ---- Enchanted items only
2522 setupEnchantedItem(setup, itemText);
2524 // ---- Cosmetic only
2525 setupCosmetic (setup, pIS);
2527 // ---- item preview
2528 setupItemPreview(setup, pIS);
2531 // if this is a R2 plot item, Add comment and description
2533 // BORIS : 06/09/2006 : removed because seams to build a double 'description' in the item info windows
2534 // const CItemSheet *pIS= setup.SrcSheet->asItemSheet();
2535 // if (pIS)
2536 // {
2537 // if (pIS->Family == ITEMFAMILY::SCROLL_R2)
2538 // {
2539 // const R2::TMissionItem *mi = R2::getEditor().getPlotItemInfos((uint32) setup.SrcSheet->getSheetId());
2540 // if (mi)
2541 // {
2542 // itemText += CI18N::get("uiRingPlotItemDesc");
2543 // itemText += mi->Description.empty() ? CI18N::get("uiRingPlotItemEmpty")
2544 // : mi->Description;
2545 // //itemText += "\n@{6F6F}" + CI18N::get("uiRingPlotItemComment") + "\n";
2546 // /*
2547 // itemText += mi->Comment.empty() ? CI18N::get("uiRingPlotItemEmpty")
2548 // : ("\n" + mi->Comment);
2549 // */
2550 // }
2551 // }
2552 // }
2555 // **** setup the text
2556 setHelpText(setup, itemText);
2560 // ***************************************************************************
2561 static void setupPactHelp(CSheetHelpSetup &setup)
2563 if (!setup.HelpWindow) return;
2565 // get the calling item
2566 if (!setup.SrcSheet)
2568 nlwarning("<CHandlerOpenBrickHelp::execute> no caller sheet found.");
2569 return;
2572 // If the sheet is 0, don't open!
2573 if(setup.SrcSheet->getSheetId()==0)
2574 return;
2576 const CPactSheet *pact = setup.SrcSheet->asPactSheet();
2577 if (!pact)
2579 nlwarning("<CHandlerOpenBrickHelp::execute> can't get pact.");
2580 return;
2583 // Level of the pact is in the quality.
2584 sint32 pactLevel = setup.SrcSheet->getQuality();
2586 if (pactLevel < 0 || pactLevel >= (sint32) pact->PactLose.size())
2588 nlwarning("<CHandlerOpenBrickHelp::execute> bad level for pact.");
2589 return;
2592 if(setup.DestSheet)
2594 setup.SrcSheet->copyAspect(setup.DestSheet);
2595 setup.DestSheet->setActive(true);
2599 const CPactSheet::SPact &pactLose = pact->PactLose[pactLevel];
2600 // **** setup the brick Text info
2601 string pactText;
2603 // TODO Localisation
2604 setupHelpTitle(setup.HelpWindow, pactLose.Name);
2606 pactText= CI18N::get("uihelpPactFormat");
2607 strFindReplace(pactText, "%lvl", toString(pactLevel));
2608 strFindReplace(pactText, "%hp", toString(pactLose.LoseHitPointsLevel));
2609 strFindReplace(pactText, "%sta", toString(pactLose.LoseStaminaLevel));
2610 strFindReplace(pactText, "%sap", toString(pactLose.LoseSapLevel));
2611 strFindReplace(pactText, "%skill", toString(pactLose.LoseSkillsLevel));
2613 // **** setup the text
2614 setHelpText(setup, pactText);
2615 return;
2618 // ***************************************************************************
2619 static void setupMissionHelp(CSheetHelpSetup &setup)
2621 // get the calling item
2622 if (!setup.SrcSheet)
2624 nlwarning("<setupMissionHelp> no caller sheet found.");
2625 return;
2628 // setup the item.
2629 // CDBCtrlSheet *ctrlMission= dynamic_cast<CDBCtrlSheet*>(setup.HelpWindow->getCtrl("ctrl_slot"));
2630 if(setup.DestSheet)
2632 setup.SrcSheet->copyAspect(setup.DestSheet);
2633 setup.DestSheet->setActive(true);
2636 // get detail text id from db
2637 if (!setup.SrcSheet->getRootBranch()) return;
2638 CCDBNodeLeaf *detailTextLeaf = dynamic_cast<CCDBNodeLeaf *>(setup.SrcSheet->getRootBranch()->getNode(ICDBNode::CTextId("DETAIL_TEXT")));
2639 if (!detailTextLeaf) return;
2641 // Change the title according to Mission Client Type
2642 MISSION_DESC::TIconId iconId= (MISSION_DESC::TIconId)setup.SrcSheet->getSheetId();
2643 MISSION_DESC::TClientMissionType mType= MISSION_DESC::getClientMissionType(iconId);
2644 if(mType==MISSION_DESC::Mission)
2645 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpMission"));
2646 else if(mType==MISSION_DESC::ZCRequirement)
2647 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpZCRequirement"));
2648 else if(mType==MISSION_DESC::BuildingRequirement)
2649 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpBuildingRequirement"));
2650 else if(mType==MISSION_DESC::ZCCharge)
2651 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpZCCharge"));
2652 else if(mType==MISSION_DESC::Building)
2653 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpBuilding"));
2654 else if(mType==MISSION_DESC::RMBuy)
2655 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpRMBuy"));
2656 else if(mType==MISSION_DESC::RMUpgrade)
2657 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpRMUpgrade"));
2658 else
2659 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpMission") );
2662 // **** setup the text id
2663 setHelpTextID(setup, detailTextLeaf->getValue32());
2665 CViewTextID *viewTextTitleID = dynamic_cast<CViewTextID *>(setup.HelpWindow->getView("text_title_id"));
2666 if (viewTextTitleID != NULL)
2668 CCDBNodeLeaf *titleTextLeaf = dynamic_cast<CCDBNodeLeaf*>(setup.SrcSheet->getRootBranch()->getNode(ICDBNode::CTextId("TEXT")));
2669 if (titleTextLeaf == NULL) return;
2670 viewTextTitleID->setTextId(titleTextLeaf->getValue32());
2675 // ***************************************************************************
2676 void refreshMissionHelp(CSheetHelpSetup &setup, const CPrerequisitInfos &infos)
2678 static NLMISC::CRGBA orange(250,150,0);
2679 static NLMISC::CRGBA darkGreen(0,150,0);
2681 if (infos.Prerequisits.size() > 15)
2683 // blabla
2686 bool conditionValidated = false;
2688 // NB : firts prerequisit MUST be an 'and'
2689 for (uint i = 0 ; i < infos.Prerequisits.size() ; )
2691 nlassert(infos.Prerequisits[i].IsMandatory);
2692 conditionValidated = infos.Prerequisits[i].Validated;
2694 // check 'or' conditions, if any or (or enclosing 'and') is validated then global block is matched
2695 uint orIndexMax;
2696 for ( orIndexMax = i+1 ; orIndexMax < infos.Prerequisits.size() ; ++orIndexMax )
2698 if (infos.Prerequisits[orIndexMax].IsMandatory)
2699 break;
2701 if (infos.Prerequisits[orIndexMax].Validated)
2702 conditionValidated = true;
2705 // fill text, choose color according to conditions and block
2706 for (uint j = i ; j < orIndexMax ; ++j )
2708 const string text = setup.HelpWindow->getId() + ":content:scroll_text_id:text_list:" + NLMISC::toString("text_%u",j+1);
2709 CViewText *viewText = dynamic_cast<CViewText *>(setup.HelpWindow->getElement(text));
2710 if (viewText)
2712 viewText->setActive(true);
2713 if (infos.Prerequisits[j].IsMandatory)
2714 viewText->setHardText("uiMissionAnd");
2715 else
2716 viewText->setHardText("uiMissionOr");
2719 const string textId = setup.HelpWindow->getId() + ":content:scroll_text_id:text_list:" + NLMISC::toString("text_id_prereq_%u",j+1);
2721 CViewTextID *viewTextID = dynamic_cast<CViewTextID *>(setup.HelpWindow->getElement(textId));
2722 if(viewTextID)
2724 // not validated : change color to red
2725 if (!infos.Prerequisits[j].Validated)
2727 if (!conditionValidated)
2728 viewTextID->setColor(orange);
2729 else
2730 viewTextID->setColor(CRGBA::White);
2732 else
2733 viewTextID->setColor(darkGreen);
2735 viewTextID->setActive(true);
2736 viewTextID->setTextId(infos.Prerequisits[j].Description);
2740 // go to next 'and' statement (or end)
2741 i = orIndexMax;
2744 // inactivate other lines
2745 for (uint i = (uint)infos.Prerequisits.size(); i < 15 ; ++i)
2747 const string text = setup.HelpWindow->getId() + ":content:scroll_text_id:text_list:" + NLMISC::toString("text_%u",i+1);
2748 CViewText *viewText = dynamic_cast<CViewText *>(setup.HelpWindow->getElement(text));
2749 if (viewText)
2750 viewText->setActive(false);
2752 const string textId = setup.HelpWindow->getId() + ":content:scroll_text_id:text_list:" + NLMISC::toString("text_id_prereq_%u",i+1);
2753 CViewTextID *viewTextID = dynamic_cast<CViewTextID *>(setup.HelpWindow->getElement(textId));
2754 if(viewTextID)
2755 viewTextID->setActive(false);
2758 if (!setup.ScrollTextGroup.empty())
2760 CInterfaceGroup *viewTextGroup = setup.HelpWindow->getGroup(setup.ScrollTextGroup);
2761 if (viewTextGroup) viewTextGroup->setActive(false);
2763 CInterfaceGroup *viewTextGroup = setup.HelpWindow->getGroup(setup.ScrollTextIdGroup);
2764 if (viewTextGroup) viewTextGroup->setActive(true);
2767 // ***************************************************************************
2768 class CPlayerShardNameRemover : public IOnReceiveTextId
2770 virtual void onReceiveTextId(std::string &str)
2772 str= CEntityCL::removeShardFromName(str);
2775 static CPlayerShardNameRemover PlayerShardNameRemover;
2777 // ***************************************************************************
2778 void setupCreatorName(CSheetHelpSetup &setup)
2780 if (!setup.HelpWindow) return;
2781 CViewTextID *vtid = dynamic_cast<CViewTextID*>(setup.HelpWindow->getView(setup.CreatorViewTextID));
2782 CViewText *vthd = dynamic_cast<CViewText*>(setup.HelpWindow->getView("creator_header"));
2783 if (vtid != NULL)
2785 bool bIsRM = false;
2786 if (setup.SrcSheet)
2788 const CItemSheet *pIS= dynamic_cast<const CItemSheet*>(SheetMngr.get(CSheetId(setup.SrcSheet->getSheetId())));
2789 bIsRM = (pIS && pIS->Family == ITEMFAMILY::RAW_MATERIAL);
2792 // if a RM or not an item, disable the view
2793 if(!setup.SrcSheet || bIsRM || setup.SrcSheet->getType()!=CCtrlSheetInfo::SheetType_Item )
2795 // important else a brick could display a creator name....
2796 vtid->setActive(false);
2797 if(vthd)
2798 vthd->setActive(false);
2800 else
2802 // get the CreatorTextID
2803 uint32 itemSlotId= getInventory().getItemSlotId(setup.SrcSheet);
2804 uint32 creatorTextId= getInventory().getItemInfo(itemSlotId).CreatorName;
2806 vtid->setActive(true);
2807 vtid->setTextId(creatorTextId);
2808 vtid->setOnReceiveTextId(&PlayerShardNameRemover);
2809 if(vthd)
2810 vthd->setActive(creatorTextId!=0);
2815 // ***************************************************************************
2816 // ***************************************************************************
2817 // Outpost Building Help
2818 // ***************************************************************************
2819 // ***************************************************************************
2822 // ***************************************************************************
2823 void fillOutpostBuildingListItem(const std::vector<NLMISC::CSheetId> &mps, IListSheetBase *listItem, uint32 qualityLevel)
2825 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2827 if(listItem)
2829 listItem->setActive(true);
2830 string branchBase= listItem->getDbBranchName();
2831 // setup mps
2832 uint i;
2833 for(i=0;i<mps.size();i++)
2835 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:SHEET", branchBase.c_str(), i));
2836 if(node)
2837 node->setValue32(mps[i].asInt());
2838 node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:QUALITY", branchBase.c_str(), i), false);
2839 if(node)
2840 node->setValue32(qualityLevel);
2841 node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:PREREQUISIT_VALID", branchBase.c_str(), i), false);
2842 if(node)
2843 node->setValue32(1);
2845 // Reset other to 0.
2846 for(;;i++)
2848 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:SHEET", branchBase.c_str(), i), false);
2849 if(node)
2850 node->setValue32(0);
2851 else
2852 break;
2857 // ***************************************************************************
2858 void setupOutpostBuildingHelp(CSheetHelpSetup &setup)
2860 // get the calling item
2861 if (!setup.SrcSheet)
2863 nlwarning("<setupOutpostBuildingHelp> no caller sheet found.");
2864 return;
2867 // setup the item.
2868 if(setup.DestSheet)
2870 setup.SrcSheet->copyAspect(setup.DestSheet);
2871 setup.DestSheet->setActive(true);
2874 const COutpostBuildingSheet *pOBS = setup.SrcSheet->asOutpostBuildingSheet();
2875 if (pOBS == NULL)
2877 nlwarning("<setupOutpostBuildingHelp> can't get outpost building sheet.");
2878 return;
2881 setupHelpTitle(setup.HelpWindow, CI18N::get("uihelpOutpostBuilding"));
2883 string sOBText;
2885 sOBText = CI18N::get("uihelpOBFormat_"+COutpostBuildingSheet::toString(pOBS->OBType));
2888 string timeText;
2889 timeText = toString(pOBS->CostTime/60) + CI18N::get("uiBotChatTimeMinute");
2890 if ((pOBS->CostTime % 60) != 0)
2891 timeText += toString(pOBS->CostTime%60) + CI18N::get("uiBotChatTimeSecond");
2893 strFindReplace(sOBText, "%costtime", timeText);
2896 strFindReplace(sOBText, "%costdapper", toString(pOBS->CostDapper));
2898 // Set name of the building
2899 strFindReplace(sOBText, "%name", STRING_MANAGER::CStringManagerClient::getOutpostBuildingLocalizedName(pOBS->Id));
2901 // For driller, set lvl
2902 strFindReplace(sOBText, "%lvl", toString(pOBS->MPLevelOfHighestExtractRate));
2904 // **** setup the text
2905 setHelpText(setup, sOBText);
2907 // **** raw materials stats for driller to buy
2908 if(pOBS->OBType==COutpostBuildingSheet::OB_Driller)
2910 // Get the list of bricks container
2911 IListSheetBase *listItem= dynamic_cast<IListSheetBase*>(setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_LIST_ITEM));
2913 // setup the bricks
2914 fillOutpostBuildingListItem(pOBS->Mps, listItem, pOBS->MPLevelOfHighestExtractRate);
2918 // ***************************************************************************
2919 // ***************************************************************************
2920 // SBrick / Phrase help
2921 // ***************************************************************************
2922 // ***************************************************************************
2925 // ***************************************************************************
2926 static bool getAuraDisabledState(CDBCtrlSheet *cs)
2928 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2930 if(!cs)
2931 return false;
2933 // Get the DISABLED DBprop
2934 string db= cs->getSheet() + ":DISABLED";
2935 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(db, false);
2936 return node && node->getValue32()!=0;
2939 // ***************************************************************************
2940 static sint getBonusMalusSpecialTT(CDBCtrlSheet *cs)
2942 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2944 if(!cs)
2945 return 0;
2947 // Get the SPECIAL_TOOLTIP DBprop
2948 string db= cs->getSheet() + ":SPECIAL_TOOLTIP";
2949 return NLGUI::CDBManager::getInstance()->getDbValue32 (db);
2953 // ***************************************************************************
2954 void getSabrinaBrickText(CSBrickSheet *pBR, string &brickText)
2956 if(!pBR)
2957 return;
2959 // *** get the formated text according to Brick type.
2960 if( pBR->isFaber() && pBR->isMandatory() )
2962 brickText= CI18N::get("uihelpBrickFaberFormat");
2964 else
2966 brickText= CI18N::get("uihelpBrickFormat");
2969 // *** Basics
2970 // Level
2971 strFindReplace(brickText, "%lvl", toString(pBR->Level));
2972 // Kill the whole text between %ks, if the skill is unknown
2973 const string killSkill("%ks");
2974 if( pBR->getSkill()==SKILLS::unknown )
2976 string::size_type pos0= brickText.find(killSkill);
2977 if(pos0 != string::npos)
2979 string::size_type pos1= brickText.find(killSkill, pos0 + killSkill.size() );
2980 if(pos1 != string::npos)
2981 brickText.replace(pos0, pos1+killSkill.size()-pos0, string() );
2984 else
2986 // remove %ks tag
2987 while(strFindReplace(brickText, "%ks", ""));
2989 // Skill, or array of skill for combat
2990 if(pBR->UsedSkills.size()==1)
2991 strFindReplace(brickText, "%skill", CStringManagerClient::getSkillLocalizedName(pBR->getSkill()));
2992 else
2994 string fullSkillText;
2995 bool first= true;
2996 for(uint i=0;i<pBR->UsedSkills.size();i++)
2998 SKILLS::ESkills skill= pBR->UsedSkills[i];
2999 if(skill!=SKILLS::unknown)
3001 if(!first)
3002 fullSkillText+= CI18N::get("uihelpBrickCombatSkillSeparator");
3003 first= false;
3004 fullSkillText+= CStringManagerClient::getSkillLocalizedName(skill);
3008 strFindReplace(brickText, "%skill", fullSkillText);
3012 // Cost
3013 strFindReplace(brickText, "%cost", toString(pBR->SabrinaCost));
3014 // Header Cost: cost or credit
3015 if(pBR->SabrinaCost>=0)
3016 strFindReplace(brickText, "%hcost", CI18N::get("uihelpSabrinaCost") );
3017 else
3018 strFindReplace(brickText, "%hcost", CI18N::get("uihelpSabrinaCredit") );
3020 // Relative Cost
3021 // Kill the whole text between %krc, if the relative cost is 0
3022 if(pBR->SabrinaRelativeCost==0.f)
3024 const string killRC("%krc");
3025 string::size_type pos0= brickText.find(killRC);
3026 if(pos0 != string::npos)
3028 string::size_type pos1= brickText.find(killRC, pos0 + killRC.size() );
3029 if(pos1 != string::npos)
3030 brickText.replace(pos0, pos1+killRC.size()-pos0, string() );
3033 else
3035 // remove %krc tag
3036 while(strFindReplace(brickText, "%krc", ""));
3039 strFindReplace(brickText, "%relative_cost", toPercentageText(pBR->SabrinaRelativeCost)+string("%"));
3040 // Header Cost: cost or credit
3041 if(pBR->SabrinaRelativeCost>=0.f)
3042 strFindReplace(brickText, "%hrel_cost", CI18N::get("uihelpSabrinaRelCost") );
3043 else
3044 strFindReplace(brickText, "%hrel_cost", CI18N::get("uihelpSabrinaRelCredit") );
3047 // Description
3048 strFindReplace(brickText, "%desc", CStringManagerClient::getSBrickLocalizedDescription(pBR->Id) );
3050 // *** Faber
3051 if( pBR->isFaber() && pBR->isMandatory() )
3053 // Display the ToolType required.
3054 strFindReplace(brickText, "%tool", CI18N::get("tool"+TOOL_TYPE::toString(pBR->FaberPlan.ToolType)));
3056 // --- Display MP itempart information
3057 if(pBR->FaberPlan.ItemPartMps.empty())
3059 strFindReplace(brickText, "%mpinfo", CI18N::get("uihelpMpNone"));
3061 else
3063 string mpInfo;
3064 for(uint i=0;i<pBR->FaberPlan.ItemPartMps.size();i++)
3066 CSBrickSheet::CFaberPlan::CItemPartMP &mpSlot= pBR->FaberPlan.ItemPartMps[i];
3068 // Display the part this slot build.
3069 mpInfo+= "@{T4}";
3070 mpInfo+= RM_FABER_TYPE::toLocalString(mpSlot.FaberTypeFilter);
3071 mpInfo+= "\n";
3073 // replace in brickText
3074 strFindReplace(brickText, "%mpinfo", mpInfo);
3077 // --- Display MP formula information
3078 if(pBR->FaberPlan.FormulaMps.empty())
3080 strFindReplace(brickText, "%mpformula", CI18N::get("uihelpMpNone"));
3082 else
3084 string mpInfo;
3085 for(uint i=0;i<pBR->FaberPlan.FormulaMps.size();i++)
3087 CSBrickSheet::CFaberPlan::CFormulaMP &mpSlot= pBR->FaberPlan.FormulaMps[i];
3089 // Display the required item
3090 mpInfo+= "@{T4}";
3091 mpInfo+= STRING_MANAGER::CStringManagerClient::getItemLocalizedName(mpSlot.ItemRequired);
3092 mpInfo+= "\n";
3094 // replace in brickText
3095 strFindReplace(brickText, "%mpformula", mpInfo);
3099 // *** Magic
3100 string magicResistStr;
3101 // Has Some Magic Resistance setuped?
3102 if( pBR->isMagic() && pBR->MagicResistType!=RESISTANCE_TYPE::None)
3104 magicResistStr= CI18N::get("uihelpBrickMagicResist");
3105 strFindReplace(magicResistStr, "%t", CI18N::get("rs"+RESISTANCE_TYPE::toString(pBR->MagicResistType) ));
3107 strFindReplace(brickText, "%magicresist", magicResistStr);
3111 // ***************************************************************************
3113 * Used both by setupSabrinaPhraseHelp() and setupEnchantedItem()
3115 void fillSabrinaPhraseListBrick(const CSPhraseCom &phrase, IListSheetBase *listBrick)
3117 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3118 CSBrickManager *pBM= CSBrickManager::getInstance();
3120 if(listBrick)
3122 listBrick->setActive(true);
3123 string branchBase= listBrick->getDbBranchName();
3124 // setup phrase bricks
3125 uint i;
3126 for(i=0;i<phrase.Bricks.size();i++)
3128 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:SHEET", branchBase.c_str(), i));
3129 if(node)
3130 node->setValue32(phrase.Bricks[i].asInt());
3132 // For requirements bricks, update the LOCKED state
3133 node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:LOCKED", branchBase.c_str(), i));
3134 if(node)
3136 if(pBM->isBrickKnown(phrase.Bricks[i]))
3137 node->setValue32(0);
3138 else
3139 // 2 to redify it
3140 node->setValue32(2);
3143 // Reset other to 0.
3144 for(;;i++)
3146 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:SHEET", branchBase.c_str(), i), false);
3147 if(node)
3148 node->setValue32(0);
3149 else
3150 break;
3155 void hideListBrickHeader(CSheetHelpSetup &setup)
3157 // CInterfaceManager *pIM= CInterfaceManager::getInstance();
3159 // get the header text
3160 CViewText *view= dynamic_cast<CViewText*>(setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_LIST_BRICK_HEADER));
3161 if(view)
3163 view->setActive(false);
3167 void setupListBrickHeader(CSheetHelpSetup &setup)
3169 // get the header text
3170 CViewText *view= dynamic_cast<CViewText*>(setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_LIST_BRICK_HEADER));
3171 if(view)
3173 view->setActive(true);
3174 view->setTextFormatTaged(CI18N::get("uihelpPhraseHeaderBricks"));
3179 // ***************************************************************************
3180 /* phraseSheetId: not null if comes from a .sphrase Sheet, used to show progression info
3182 void setupSabrinaPhraseHelp(CSheetHelpSetup &setup, const CSPhraseCom &phrase, uint32 phraseSheetId)
3184 CSPhraseManager *pPM = CSPhraseManager::getInstance();
3186 if(!setup.SrcSheet || phrase.empty())
3187 return;
3189 if(!setup.HelpWindow)
3190 return;
3192 // setup the item.
3193 if(setup.DestSheet)
3195 setup.SrcSheet->copyAspect(setup.DestSheet);
3196 setup.DestSheet->setActive(true);
3199 // **** setup the phrase Text info
3200 setupHelpTitle(setup.HelpWindow, phrase.Name.toUtf8());
3202 // get the phraseText
3203 string phraseText;
3204 // if required, add the .sphrase requirements.
3205 // NB: don't add if from bot chat validation (useless cause already filtered by server)
3206 pPM->buildPhraseDesc(phraseText, phrase, phraseSheetId, !setup.FromBotChat);
3209 // **** If interesting to do it, setup the brick list
3210 if( pPM->allowListBrickInHelp(phrase) )
3212 // Get the list of bricks container
3213 IListSheetBase *listBrick= dynamic_cast<IListSheetBase*>(setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_LIST_BRICK));
3215 // if exist, setup text header
3216 if(listBrick)
3217 setupListBrickHeader(setup);
3219 // setup the bricks
3220 fillSabrinaPhraseListBrick(phrase, listBrick);
3224 // **** For .sphrase only, setup the requirement bricks
3225 if(phraseSheetId!=0)
3227 IListSheetBase *listBrick= dynamic_cast<IListSheetBase*>(setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_LIST_BRICK_REQUIREMENT));
3228 if(listBrick)
3230 CSPhraseCom dummyPhrase;
3231 pPM->buildPhraseBrickRequirement(phraseSheetId, dummyPhrase.Bricks);
3232 if(!dummyPhrase.Bricks.empty())
3234 phraseText+= CI18N::get("uihelpPhraseBrickRequirement");
3235 fillSabrinaPhraseListBrick(dummyPhrase, listBrick);
3241 // **** setup the final text
3242 setHelpText(setup, phraseText);
3246 // ***************************************************************************
3247 static void setupSabrinaBrickHelp(CSheetHelpSetup &setup, bool auraDisabled)
3249 if (!setup.HelpWindow) return;
3251 // get the calling item
3252 if (!setup.SrcSheet || !setup.SrcSheet->isSBrick() )
3254 nlwarning("<CHandlerOpenBrickHelp::execute> no caller sheet found");
3255 return;
3258 // If the sheet is 0, don't open!
3259 if(setup.SrcSheet->getSheetId()==0)
3260 return;
3262 // setup the item.
3263 if(setup.DestSheet)
3265 setup.SrcSheet->copyAspect(setup.DestSheet);
3266 setup.DestSheet->setActive(true);
3270 // **** setup the brick Text info
3271 string brickText;
3272 CSBrickManager *pBM= CSBrickManager::getInstance();
3273 CSBrickSheet *pBR= pBM->getBrick(CSheetId(setup.SrcSheet->getSheetId()));
3274 if(pBR)
3276 const char *title = CStringManagerClient::getSBrickLocalizedName(pBR->Id);
3277 setupHelpTitle(setup.HelpWindow, title);
3279 // add brick info
3280 getSabrinaBrickText(pBR, brickText);
3282 // Append special Aura Info
3283 if(auraDisabled)
3285 brickText+= CI18N::get("uihelpAuraDisabled");
3290 // **** setup the text
3291 setHelpText(setup, brickText);
3294 // ***************************************************************************
3295 void CSheetHelpSetup::setupDefaultIDs()
3297 ViewText = "text";
3298 ViewTextID = "text_id";
3299 ScrollTextGroup = "scroll_text";
3300 ScrollTextIdGroup = "scroll_text_id";
3301 CreatorViewTextID = "creator";
3302 PrefixForExtra= ":content:scroll_text:text_list:";
3303 FromBotChat= false;
3306 // ***************************************************************************
3307 void setupSheetHelp(CSheetHelpSetup &setup)
3309 if (!setup.SrcSheet) return;
3310 switch(setup.SrcSheet->getType())
3312 case CCtrlSheetInfo::SheetType_Skill: setupSkillToTradeHelp(setup); break;
3313 case CCtrlSheetInfo::SheetType_Item: setupItemHelp(setup); break;
3314 case CCtrlSheetInfo::SheetType_Pact: setupPactHelp(setup); break;
3315 case CCtrlSheetInfo::SheetType_Mission: setupMissionHelp(setup); break;
3316 case CCtrlSheetInfo::SheetType_SPhrase:
3318 CSPhraseCom phrase;
3319 CSPhraseManager *pPM= CSPhraseManager::getInstance();
3320 uint32 phraseSheetId= setup.SrcSheet->getSheetId();
3321 pPM->buildPhraseFromSheet(phrase, phraseSheetId);
3322 setupSabrinaPhraseHelp(setup, phrase, phraseSheetId);
3323 break;
3325 case CCtrlSheetInfo::SheetType_OutpostBuilding: setupOutpostBuildingHelp(setup); break;
3326 default:
3327 nlwarning("<CHandlerOpenHelpAuto> Bad item type.");
3328 break;
3333 // ***************************************************************************
3334 class CHandlerOpenPhraseIdHelp : public IActionHandler
3336 public:
3337 virtual void execute (CCtrlBase *pCaller, const string &Params)
3339 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
3340 if (cs != NULL && cs->getType()==CCtrlSheetInfo::SheetType_SPhraseId)
3342 // Get the CSPhraseCom pointed.
3343 sint32 id= cs->getSPhraseId();
3344 if(id!=0)
3346 CSPhraseManager *pPM= CSPhraseManager::getInstance();
3347 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(cs);
3348 if (!group) return;
3349 CSheetHelpSetup setup;
3350 setup.setupDefaultIDs();
3351 setup.HelpWindow = group;
3352 setup.SrcSheet = cs;
3353 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getCtrl("ctrl_slot"));
3354 setupSabrinaPhraseHelp(setup, pPM->getPhrase(id), 0);
3359 REGISTER_ACTION_HANDLER( CHandlerOpenPhraseIdHelp, "open_phraseid_help");
3362 // ***************************************************************************
3363 class CHandlerOpenSBrickHelp : public IActionHandler
3365 public:
3366 virtual void execute (CCtrlBase *pCaller, const string &Params)
3368 CSBrickManager *pBM= CSBrickManager::getInstance();
3369 CDBCtrlSheet *cs = dynamic_cast<CDBCtrlSheet*>(pCaller);
3371 // No Info if bad control / no sheetid
3372 if(!cs || cs->getSheetId()==0)
3373 return;
3374 CSheetId brickSheetId= CSheetId(cs->getSheetId());
3375 // No Info for the special "Remove Me" brick
3376 if(brickSheetId == pBM->getInterfaceRemoveBrick() )
3377 return;
3378 // No Info for special "XP catalyzer" or "PVP oupost" interface brick in bonus malus window
3379 string brickName= brickSheetId.toString();
3380 string xpCatBrickPrefix= "big_xpcat_";
3381 string ringXpCatBrickPrefix= "big_ring_xpcat_";
3382 string pvpOutpostBrickPrefix= "big_outpost_pvp_";
3383 if(brickName.compare(0, xpCatBrickPrefix.size(), xpCatBrickPrefix)==0)
3384 return;
3385 if(brickName.compare(0, ringXpCatBrickPrefix.size(), ringXpCatBrickPrefix)==0)
3386 return;
3387 if(brickName.compare(0, pvpOutpostBrickPrefix.size(), pvpOutpostBrickPrefix)==0)
3388 return;
3390 // Else, Ok open the window
3392 // get the forceKeep param (for Action info)
3393 sint forceKeepWindow= -1;
3394 string forceKeepWindowStr= getParam(Params, "force_keep");
3395 if(!forceKeepWindowStr.empty())
3396 fromString(forceKeepWindowStr, forceKeepWindow);
3397 // get the Aura Disabled param
3398 bool auraDisabled= false;
3399 string auraDisabledStr= getParam(Params, "test_aura_disabled");
3400 bool tmpAuraDisabled;
3401 fromString(auraDisabledStr, tmpAuraDisabled);
3402 if(tmpAuraDisabled)
3403 auraDisabled= getAuraDisabledState(cs);
3405 // open
3406 CInterfaceGroup *group = CInterfaceHelp::activateNextWindow(cs, forceKeepWindow);
3407 if (!group) return;
3408 CSheetHelpSetup setup;
3409 setup.setupDefaultIDs();
3410 setup.HelpWindow = group;
3411 setup.SrcSheet = cs;
3412 setup.DestSheet = dynamic_cast<CDBCtrlSheet*>(group->getCtrl("ctrl_slot"));
3413 setupSabrinaBrickHelp(setup, auraDisabled);
3417 REGISTER_ACTION_HANDLER( CHandlerOpenSBrickHelp, "open_sbrick_help");
3421 // ***************************************************************************
3422 class CHandlerOnCloseHelp : public IActionHandler
3424 public:
3425 virtual void execute (CCtrlBase *pCaller, const string &Params)
3427 // Remove the waiter for special ItemInfo
3428 uint index;
3429 fromString(Params, index);
3430 CInterfaceHelp::removeWaiterItemInfo(index);
3431 CInterfaceHelp::removeWaiterMissionInfo(index);
3433 // unpuhsed the "Keep" button.
3434 CInterfaceHelp::setKeepMode(index, false);
3437 REGISTER_ACTION_HANDLER( CHandlerOnCloseHelp, "on_close_help");
3440 // ***************************************************************************
3441 class CHandlerHelpKeep : public IActionHandler
3443 public:
3444 virtual void execute (CCtrlBase *pCaller, const string &Params)
3446 // flag
3447 uint index;
3448 fromString(Params, index);
3449 CInterfaceHelp::changeKeepMode(index);
3452 REGISTER_ACTION_HANDLER( CHandlerHelpKeep, "help_keep");
3455 // ***************************************************************************
3456 class CHandlerHelpResetPos : public IActionHandler
3458 public:
3459 virtual void execute(CCtrlBase *pCaller, const string &Params)
3461 sint y;
3462 fromString(getParam(Params, "y"), y);
3463 // update WindowList if possible
3464 CInterfaceHelp::resetWindowPos(y);
3467 REGISTER_ACTION_HANDLER( CHandlerHelpResetPos, "help_reset_pos");
3471 //-----------------------------------------------
3472 // setConsoModSuccessTooltip
3473 //-----------------------------------------------
3474 void setConsoModSuccessTooltip( CDBCtrlSheet *cs )
3476 if(!cs)
3477 return;
3479 CInterfaceManager * pIM = CInterfaceManager::getInstance();
3481 CCDBNodeLeaf * nodeSM = NULL;
3482 string ustr;
3483 if( CSheetId(cs->getSheetId()).toString() == "mod_melee_success.sbrick" )
3485 ustr = CI18N::get("uittModMeleeSuccess");
3486 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:MELEE", false);
3488 else
3489 if( CSheetId(cs->getSheetId()).toString() == "mod_range_success.sbrick" )
3491 ustr = CI18N::get("uittModRangeSuccess");
3492 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:RANGE", false);
3494 else
3495 if( CSheetId(cs->getSheetId()).toString() == "mod_craft_success.sbrick" )
3497 ustr = CI18N::get("uittModCraftSuccess");
3498 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:CRAFT", false);
3500 else
3501 if( CSheetId(cs->getSheetId()).toString() == "mod_defense_success.sbrick" )
3503 ustr = CI18N::get("uittModDefenseSuccess");
3504 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:DODGE", false);
3506 else
3507 if( CSheetId(cs->getSheetId()).toString() == "mod_dodge_success.sbrick" )
3509 ustr = CI18N::get("uittModDodgeSuccess");
3510 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:DODGE", false);
3512 else
3513 if( CSheetId(cs->getSheetId()).toString() == "mod_parry_success.sbrick" )
3515 ustr = CI18N::get("uittModParrySuccess");
3516 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:PARRY", false);
3518 else
3519 if( CSheetId(cs->getSheetId()).toString() == "mod_forage_success.sbrick" )
3521 ustr = CI18N::get("uittModForageSuccess");
3522 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:ECO:"+toString((uint8)ECOSYSTEM::common_ecosystem)+":FORAGE", false);
3524 else
3525 if( CSheetId(cs->getSheetId()).toString() == "mod_desert_forage_success.sbrick" )
3527 ustr = CI18N::get("uittModDesertForageSuccess");
3528 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:ECO:"+toString((uint8)ECOSYSTEM::desert)+":FORAGE", false);
3530 else
3531 if( CSheetId(cs->getSheetId()).toString() == "mod_forest_forage_success.sbrick" )
3533 ustr = CI18N::get("uittModForestForageSuccess");
3534 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:ECO:"+toString((uint8)ECOSYSTEM::forest)+":FORAGE", false);
3536 else
3537 if( CSheetId(cs->getSheetId()).toString() == "mod_lacustre_forage_success.sbrick" )
3539 ustr = CI18N::get("uittModLacustreForageSuccess");
3540 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:ECO:"+toString((uint8)ECOSYSTEM::lacustre)+":FORAGE", false);
3542 else
3543 if( CSheetId(cs->getSheetId()).toString() == "mod_jungle_forage_success.sbrick" )
3545 ustr = CI18N::get("uittModJungleForageSuccess");
3546 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:ECO:"+toString((uint8)ECOSYSTEM::jungle)+":FORAGE", false);
3548 else
3549 if( CSheetId(cs->getSheetId()).toString() == "mod_primary_root_forage_success.sbrick" )
3551 ustr = CI18N::get("uittModPrimaryRootForageSuccess");
3552 nodeSM = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:ECO:"+toString((uint8)ECOSYSTEM::primary_root)+":FORAGE", false);
3555 if( nodeSM )
3557 if( nodeSM->getValue32() < 0 )
3558 strFindReplace(ustr, "%modifier", "@{E42F}-"+toString(nodeSM->getValue32())+"@{FFFF}");
3559 else
3560 strFindReplace(ustr, "%modifier", "@{0F0F}"+toString(nodeSM->getValue32())+"@{FFFF}");
3562 // replace the context help that is required.
3563 CWidgetManager::getInstance()->setContextHelpText(ustr);
3568 // ***************************************************************************
3569 class CHandlerAuraModifierTooltip : public IActionHandler
3571 public:
3572 virtual void execute(CCtrlBase *pCaller, const string &Params)
3574 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3575 CDBCtrlSheet *cs= dynamic_cast<CDBCtrlSheet*>(pCaller);
3576 if(!cs)
3577 return;
3579 // set value of consumable's tootltip
3580 setConsoModSuccessTooltip(cs);
3582 // special tooltip? (pvp outpost and xp catalyzer)
3583 sint specialTTId= getBonusMalusSpecialTT(cs);
3584 if(specialTTId==BONUS_MALUS::XpCatalyser)
3585 CWidgetManager::getInstance()->setContextHelpText(CI18N::get("uittXpBonus"));
3586 else if(specialTTId==BONUS_MALUS::OutpostPVPOn)
3587 CWidgetManager::getInstance()->setContextHelpText(CI18N::get("uittPvpOutpostOn"));
3588 else if(specialTTId==BONUS_MALUS::OutpostPVPOutOfZone)
3589 CWidgetManager::getInstance()->setContextHelpText(CI18N::get("uittPvpOutpostOutOfZone"));
3590 else if(specialTTId==BONUS_MALUS::OutpostPVPInRound)
3591 CWidgetManager::getInstance()->setContextHelpText(CI18N::get("uittPvpOutpostInRound"));
3592 else if(specialTTId==BONUS_MALUS::DeathPenalty)
3594 CCDBNodeLeaf * node = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:USER:DEATH_XP_MALUS", false);
3595 if( node )
3597 string txt = CI18N::get("uittDeathPenalty");
3598 strFindReplace(txt, "%dp", toString((100*node->getValue16())/254));
3599 CWidgetManager::getInstance()->setContextHelpText(txt);
3602 // if disabled.
3603 else if( getAuraDisabledState(cs) )
3605 // get the normal string, and append a short info.
3606 string str;
3607 cs->getContextHelp(str);
3609 str+= CI18N::get("uittAuraDisabled");
3611 // and replace the context help that is required.
3612 CWidgetManager::getInstance()->setContextHelpText(str);
3614 // else keep the default one
3617 REGISTER_ACTION_HANDLER( CHandlerAuraModifierTooltip, "aura_modifier_tooltip");
3619 // ***************************************************************************
3620 class CHandlerUserPaToolTip : public IActionHandler
3622 public:
3623 virtual void execute(CCtrlBase *pCaller, const string &Params)
3625 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3627 uint8 index;
3628 fromString(Params, index);
3629 --index; // Param is 1-based so subtract 1
3630 if (index >= MAX_INVENTORY_ANIMAL)
3632 return;
3635 string txt;
3636 CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:NAME", index));
3637 if (node && CStringManagerClient::instance()->getDynString(node->getValue32(), txt))
3639 CWidgetManager::getInstance()->setContextHelpText(CEntityCL::removeTitleFromName(txt));
3643 REGISTER_ACTION_HANDLER( CHandlerUserPaToolTip, "userpa_name_tooltip");
3645 // ***************************************************************************
3646 class CHandlerAnimalDeadPopupTooltip : public IActionHandler
3648 public:
3649 virtual void execute(CCtrlBase *pCaller, const string &Params)
3651 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3652 // Find the mount's db leaf
3653 CCDBNodeBranch *animalsNode = safe_cast<CCDBNodeBranch*>(NLGUI::CDBManager::getInstance()->getDB()->getNode( ICDBNode::CTextId( "SERVER:PACK_ANIMAL" ), false ));
3654 BOMB_IF( ! animalsNode, "! animalsNode", return; );
3655 sint32 minTimeRemaining = -1;
3656 uint nbAnimals = (uint)animalsNode->getNbNodes();
3657 for ( uint i=0; i!=nbAnimals; ++i )
3659 CCDBNodeLeaf *statusNode = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d", i) + ":STATUS", false);
3660 if (statusNode && ANIMAL_STATUS::isDead((ANIMAL_STATUS::EAnimalStatus)statusNode->getValue32()) )
3662 ICDBNode *beastNode = animalsNode->getNode( i );
3663 // CCDBNodeLeaf *uidLeaf = safe_cast<CCDBNodeLeaf*>(beastNode->getNode( ICDBNode::CTextId( "UID" ) ));
3664 CCDBNodeLeaf *despawnLeaf = safe_cast<CCDBNodeLeaf*>(beastNode->getNode( ICDBNode::CTextId( "DESPAWN" ) ));
3665 if( minTimeRemaining == -1 )
3667 minTimeRemaining = despawnLeaf->getValue32();
3669 else
3670 if( minTimeRemaining > despawnLeaf->getValue32() )
3672 minTimeRemaining = despawnLeaf->getValue32();
3677 string str;
3678 BOMB_IF( minTimeRemaining < 0, "at least one animal should be dead", return; );
3680 str += CI18N::get("uittAnimalDeadPopupToolTip");
3681 str += " : ";
3682 str += toString(minTimeRemaining);
3684 // replace the context help that is required.
3685 CWidgetManager::getInstance()->setContextHelpText(str);
3688 REGISTER_ACTION_HANDLER( CHandlerAnimalDeadPopupTooltip, "animal_dead_popup_tooltip");
3692 // ***************************************************************************
3693 // ***************************************************************************
3694 // ***************************************************************************
3695 // MILKO STUFF
3696 // ***************************************************************************
3697 // ***************************************************************************
3698 // ***************************************************************************
3700 #include "../motion/user_controls.h"
3701 #include "../entities.h"
3702 #include "people_interraction.h"
3703 #include "../net_manager.h"
3705 // ***************************************************************************
3706 class CAHMilkoKick: public IActionHandler
3708 public:
3709 virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */)
3711 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
3712 if (selection != NULL)
3714 sint n = PeopleInterraction.TeamList.getIndexFromName(selection->getEntityName());
3715 if (n >= 0)
3717 const char *msgName = "TEAM:KICK";
3718 CBitMemStream out;
3719 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
3721 uint8 teamMember = (uint8)n;
3722 out.serialEnum(teamMember);
3723 NetMngr.push(out);
3724 //nlinfo("impulseCallBack : %s %d sent", msgName, teamMember);
3726 else
3727 nlwarning("unknown message named '%s'.", msgName);
3732 REGISTER_ACTION_HANDLER( CAHMilkoKick, "milko_kick");
3735 // ***************************************************************************
3736 // ***************************************************************************
3737 // ***************************************************************************
3738 // RAW MATERIAL STATS
3739 // ***************************************************************************
3740 // ***************************************************************************
3741 // ***************************************************************************
3744 // ***************************************************************************
3745 static void onMpChangeItemPart(CInterfaceGroup *wnd, uint32 itemSheetId, const string &statPrefixId)
3747 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3749 uint i;
3751 if(!wnd || !itemSheetId)
3752 return;
3754 // get the item sheet
3755 const CItemSheet *pIS= dynamic_cast<const CItemSheet *>(SheetMngr.get(CSheetId(itemSheetId)));
3756 if(!pIS || pIS->Family!=ITEMFAMILY::RAW_MATERIAL)
3757 return;
3759 // get the group for raw material stat
3760 CInterfaceGroup *groupMp= dynamic_cast<CInterfaceGroup*>(wnd->getElement(wnd->getId()+statPrefixId+INFO_GROUP_MP_STAT));
3761 if(!groupMp)
3762 return;
3764 // get the combo box
3765 CDBGroupComboBox *pCB= dynamic_cast<CDBGroupComboBox*>(groupMp->getElement(groupMp->getId()+":item_part_choice" ));
3766 if( !pCB )
3767 return;
3769 // get the selection
3770 uint comboSelection= pCB->getSelection();
3772 // get the related FaberType
3773 RM_FABER_TYPE::TRMFType faberType= RM_FABER_TYPE::MPL;
3774 uint bitCount= 0;
3775 for(i=0;i<RM_FABER_TYPE::NUM_FABER_TYPE;i++)
3777 if(pIS->Mp.ItemPartBF & (uint64)(1 << i))
3779 if(bitCount==comboSelection)
3781 faberType= RM_FABER_TYPE::TRMFType(i);
3782 break;
3784 bitCount++;
3788 // get the item part
3789 if(!pIS->canBuildItemPart(faberType))
3790 return;
3791 const CItemSheet::CMpItemPart &itemPart= pIS->getItemPart(faberType);
3794 // **** Build Icon
3795 // get the icon
3796 CViewBitmap *viewBmp= dynamic_cast<CViewBitmap*>(groupMp->getElement(groupMp->getId()+":icon" ));
3797 if(viewBmp)
3799 // texture name in config.xml
3800 viewBmp->setTexture(CWidgetManager::getInstance()->getParser()->getDefine( RM_FABER_TYPE::toIconDefineString(faberType) ));
3804 // **** Build text
3805 // get the text
3806 CViewText *viewText= dynamic_cast<CViewText*>(groupMp->getElement(groupMp->getId()+":text" ));
3807 if(viewText)
3809 string mpCraft;
3811 // add the Origin filter.
3812 string originFilterKey= "iompf" + ITEM_ORIGIN::enumToString((ITEM_ORIGIN::EItemOrigin)itemPart.OriginFilter);
3813 mpCraft+= CI18N::get(originFilterKey);
3815 viewText->setText(mpCraft);
3819 // **** Build Stat bars
3820 // default: hide all
3821 for(i=0;i<RM_FABER_STAT_TYPE::NumRMStatType;i++)
3823 // get the stat group
3824 CInterfaceGroup *groupStat= dynamic_cast<CInterfaceGroup*>(groupMp->getElement(groupMp->getId()+toString(":stat%d",i) ));
3825 if(groupStat)
3826 groupStat->setActive(false);
3828 // enable only one that are relevant for this item part
3829 uint groupIndex= 0;
3830 for(i=0;i<RM_FABER_STAT_TYPE::NumRMStatType;i++)
3832 RM_FABER_STAT_TYPE::TRMStatType statType= RM_FABER_STAT_TYPE::TRMStatType(i);
3834 // if this stat is not relevant for this item part, don't display it!
3835 if(!RM_FABER_STAT_TYPE::isStatRelevant(faberType, statType))
3836 continue;
3838 // get the next stat group
3839 CInterfaceGroup *groupStat= dynamic_cast<CInterfaceGroup*>(groupMp->getElement(groupMp->getId()+toString(":stat%d",groupIndex) ));
3840 if(groupStat)
3842 groupStat->setActive(true);
3843 // fill text and bar according to stat
3844 CViewText *statTitle= dynamic_cast<CViewText*>(groupStat->getElement(groupStat->getId()+":text" ));
3845 CDBViewBar *statValue= dynamic_cast<CDBViewBar*>(groupStat->getElement(groupStat->getId()+":bar" ));
3846 if(statTitle)
3847 statTitle->setText(RM_FABER_STAT_TYPE::toLocalString(statType));
3848 if(statValue)
3849 statValue->setValue(itemPart.Stats[i]);
3852 groupIndex++;
3858 // ***************************************************************************
3859 // MP Item Part selection in a info window
3860 class CAHItemHelpMpChangeItemPart : public IActionHandler
3862 public:
3863 virtual void execute(CCtrlBase * /* pCaller */, const string &Params)
3865 // get the info window associated
3866 uint infoWindowIndex;
3867 fromString(Params, infoWindowIndex);
3868 if(infoWindowIndex>=CInterfaceHelp::_InfoWindows.size())
3869 return;
3870 CInterfaceHelp::CInfoWindow &infoWindow= CInterfaceHelp::_InfoWindows[infoWindowIndex];
3872 // just to have the correct 'PrefixForExtra' string.
3873 CSheetHelpSetup dummy;
3874 dummy.setupDefaultIDs();
3876 // common method for info and botchat
3877 if(infoWindow.CtrlSheet)
3879 onMpChangeItemPart(infoWindow.Window, infoWindow.CtrlSheet->getSheetId(), dummy.PrefixForExtra);
3883 REGISTER_ACTION_HANDLER( CAHItemHelpMpChangeItemPart, "item_help_mp_change_item_part");
3886 // ***************************************************************************
3887 // same, but for BotChat dialog box
3888 class CAHItemBotChatMpChangeItemPart : public IActionHandler
3890 public:
3891 virtual void execute(CCtrlBase * /* pCaller */, const string &Params)
3893 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3895 // retreive direct params
3896 string wndStr= getParam(Params, "wnd");
3897 string dbitem= getParam(Params, "dbitem");
3898 string prefix= getParam(Params, "prefix");
3900 CInterfaceGroup *wnd= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(wndStr));
3901 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(dbitem);
3903 // common method for info and botchat
3904 if(wnd && node)
3906 onMpChangeItemPart(wnd, node->getValue32(), prefix);
3910 REGISTER_ACTION_HANDLER( CAHItemBotChatMpChangeItemPart, "item_botchat_mp_change_item_part");
3914 // ***************************************************************************
3915 // ***************************************************************************
3916 // Stat report
3917 // ***************************************************************************
3918 // ***************************************************************************
3921 // ***************************************************************************
3923 void updateStatReport ()
3925 // After 30 game minutes, send a stat report
3926 const uint64 time4StatReport = 60*30*1000;
3927 if ((ingameTime0 () <= time4StatReport) && (ingameTime1 () > time4StatReport))
3929 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3930 CAHManager::getInstance()->runActionHandler ("proc", NULL, "proc_stat_report");
3934 // ***************************************************************************
3936 extern string getSystemInformation();
3937 class CAHSendStatReport : public IActionHandler
3939 public:
3941 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
3943 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3944 pIM->displaySystemInfo(CI18N::get ("uiSendingStatReport"));
3945 string s = getDebugInformation();
3946 s += getSystemInformation();
3948 string progname;
3949 string moduleName;
3950 #ifdef NL_OS_WINDOWS
3951 wchar_t name[1024];
3952 GetModuleFileNameW(NULL, name, 1023);
3953 moduleName = wideToUtf8(name);
3954 #else
3955 // TODO for Linux
3956 #endif
3957 progname = CFile::getFilename(moduleName);
3958 progname += " ";
3959 progname += "Statistic Report";
3961 bool res = NLNET::sendEmail ("", "", "", progname, s, "");
3962 if (res)
3963 nlinfo ("Stat report sent");
3964 else
3965 nlwarning ("Can't send stat report");
3968 REGISTER_ACTION_HANDLER (CAHSendStatReport, "send_stat_report");
3970 // ***************************************************************************
3971 class CHandlerMkInMode : public IActionHandler
3973 public:
3974 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
3976 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3978 CCDBNodeLeaf *pVal = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:MK_MODE", false);
3979 if(pVal)
3981 sint32 mode = pVal->getValue32() + 1;
3982 if (mode > 5)
3983 mode = 1;
3984 pVal->setValue32(mode);
3988 REGISTER_ACTION_HANDLER( CHandlerMkInMode, "mk_inc_mode");
3990 // ***************************************************************************
3991 class CHandlerBrowseFAQ : public IActionHandler
3993 public:
3994 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
3996 #ifdef NL_OS_WINDOWS
3997 NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver();
3998 if (Driver)
4000 HWND wnd = (HWND) Driver->getDisplay();
4001 ShowWindow(wnd, SW_MINIMIZE);
4003 #endif
4004 browseFAQ(ClientCfg.ConfigFile);
4007 REGISTER_ACTION_HANDLER( CHandlerBrowseFAQ, "browse_faq");