Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / interface_v3 / group_skills.cpp
blob146117d1703ecd5fad56d98ec853f9c397b32a00
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 // ***************************************************************************
24 #include "stdpch.h"
26 #include "group_skills.h"
27 #include "interface_manager.h"
28 #include "nel/gui/interface_expr.h"
30 #include "nel/gui/view_text.h"
31 #include "nel/gui/view_bitmap.h"
32 #include "nel/gui/dbview_number.h"
33 #include "nel/gui/dbview_bar.h"
35 #include "game_share/skills.h"
36 #include "nel/misc/xml_auto_ptr.h"
38 #include "skill_manager.h"
39 #include "nel/misc/i_xml.h"
41 #include "../string_manager_client.h"
43 #include "../user_entity.h"
45 // ***************************************************************************
46 using namespace std;
47 using namespace NLMISC;
49 // ***************************************************************************
50 #define DB_SKILLS "SERVER:CHARACTER_INFO:SKILLS"
51 #define WIN_TREE_LIST "sbtree:tree_list"
53 extern CUserEntity *UserEntity;
55 // Context help
56 extern void contextHelp (const std::string &help);
58 NLMISC_REGISTER_OBJECT(CViewBase, CGroupSkills, std::string, "skills_displayer");
61 bool CGroupSkills::InhibitSkillUpFX = true;
64 // ***************************************************************************
65 bool CGroupSkills::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
67 CInterfaceManager *pIM= CInterfaceManager::getInstance();
69 if(!CInterfaceGroup::parse(cur, parentGroup))
70 return false;
72 CXMLAutoPtr ptr;
74 // read _TemplateSkill
75 ptr = (char*) xmlGetProp (cur, (xmlChar*)"template_skill");
76 if (ptr)
78 _TemplateSkill = (const char*)ptr;
81 // read _AHCtrlNode
82 ptr = (char*) xmlGetProp (cur, (xmlChar*)"node_handler");
83 if (ptr)
85 _AHCtrlNode = (const char*)ptr;
89 // Add observer on the skill parameter because if the skill is coming to be not-zero, a new skill must be displayed
90 _SkillsObs.Owner = this;
92 string sTmp;
93 ICDBNode::CTextId textId;
95 for (uint k = 0; k < SKILLS::NUM_SKILLS; ++k)
97 sTmp = string(DB_SKILLS)+":"+NLMISC::toString((sint32)k)+":BaseSKILL";
98 textId = ICDBNode::CTextId( sTmp );
99 NLGUI::CDBManager::getInstance()->getDB()->addObserver (&_SkillsObs, textId );
102 _MustRebuild = true;
104 // create all the Tree Nodes now
105 createAllTreeNodes();
107 return true;
110 // ***************************************************************************
111 void CGroupSkills::clearGroups()
113 CInterfaceGroup::clearGroups();
116 // ***************************************************************************
117 void CGroupSkills::checkCoords ()
119 if (_MustRebuild)
120 rebuild();
121 CInterfaceGroup::checkCoords();
125 // ***************************************************************************
126 void CGroupSkills::rebuild()
128 CInterfaceManager *pIM = CInterfaceManager::getInstance();
129 CSkillManager *pSM = CSkillManager::getInstance();
131 // **** first time bind?
132 if(!_Tree)
134 _Tree = dynamic_cast<CGroupTree*>(CWidgetManager::getInstance()->getElementFromId(getId(),WIN_TREE_LIST));
135 if (_Tree == NULL)
137 nlwarning("cant find tree");
138 return;
141 // setup
142 _Tree->setRootNode (_TreeRoot);
143 _Tree->selectLine(0);
146 // **** Update the Show flag of each node
147 // for each skill
148 for (uint32 i = 0; i < SKILLS::NUM_SKILLS; ++i)
150 bool show= false;
151 if (!pSM->isUnknown((SKILLS::ESkills)i))
153 // Show level 0 and level 1 skills + skills that have a PARENT with value > 0
154 SKILLS::ESkills parentSkill= pSM->getParent((SKILLS::ESkills)i);
156 // if no grand parent, or if grand parent trained
157 if (pSM->getParent(parentSkill) == SKILLS::unknown ||
158 pSM->getBaseSkillValue(parentSkill) > 0)
159 show= true;
162 // set shown?
163 if(_AllNodes[i])
164 _AllNodes[i]->Show= show;
167 // refresh
168 _Tree->forceRebuild();
170 invalidateCoords();
171 _MustRebuild = false;
175 // ***************************************************************************
177 void CGroupSkills::CSkillsObs::update (ICDBNode *node)
179 CInterfaceManager *pIM = CInterfaceManager::getInstance();
181 CCDBNodeLeaf *leaf = NLMISC::safe_cast<CCDBNodeLeaf *>(node);
183 // Rebuild all only if new skill (previously level 0)
184 if (leaf->getOldValue32() == 0)
185 Owner->_MustRebuild= true;
187 // Popup a message if previous was not 0
188 if ((leaf->getOldValue32() != 0) &&
189 (leaf->getValue32() != 0)) // prevent displaying FX when resetData() is called during a Far TP
191 CGroupSkills::InhibitSkillUpFX = false;
193 ICDBNode *skill = node->getParent();
194 if (skill)
196 ICDBNode *skillParent = skill->getParent();
197 if (skillParent)
199 uint skillId;
200 if (skillParent->getNodeIndex (skill, skillId))
202 CAHManager::getInstance()->runActionHandler("skill_popup", NULL, "skillId="+toString(skillId)+"|delta="+toString(leaf->getValue32()-leaf->getOldValue32()));
204 // Context help
205 contextHelp ("skill");
210 else
212 if( !CGroupSkills::InhibitSkillUpFX ) // TODO: couldn't this be replaced by IngameDbMngr.initInProgress()?
214 UserEntity->skillUp();
218 // Check if this skill canunblock title
219 CSkillManager *pSM = CSkillManager::getInstance();
220 string sTmp = leaf->getFullName();
221 sTmp = sTmp.substr(0, sTmp.rfind(':'));
222 sTmp = sTmp.substr(sTmp.rfind(':')+1,sTmp.size());
223 sint32 eSkills;
224 fromString(sTmp, eSkills);
225 pSM->tryToUnblockTitleFromSkill((SKILLS::ESkills)eSkills, leaf->getValue32());
229 // ***************************************************************************
230 // Get the skill buf text
231 static DECLARE_INTERFACE_USER_FCT(getSkillBaseText)
233 if (args.size() != 2)
235 nlwarning("<getSkillBaseText> Expecting 2 arg.");
236 return false;
238 if (!args[0].toInteger() && !args[1].toInteger())
240 nlwarning("<getSkillBaseText> Can't convert arg 0/1 to a int value.");
241 return false;
244 sint64 skillValue= args[0].getInteger();
245 sint64 skillBase= args[1].getInteger();
247 if(skillValue!=skillBase)
249 result.setString( toString("(%d)", skillBase) );
251 else
253 result.setString( std::string() );
256 return true;
258 REGISTER_INTERFACE_USER_FCT("getSkillBaseText", getSkillBaseText);
261 // ***************************************************************************
262 class CSortNode
264 public:
265 CGroupTree::SNode *Node;
266 sint Value;
268 bool operator<(const CSortNode &o) const
270 return Value<o.Value;
273 // constructor
274 CGroupSkills::CGroupSkills( const TCtorParam &param ) :
275 CInterfaceGroup(param)
277 _MustRebuild = false;
278 _Tree= NULL;
279 _TreeRoot= NULL;
282 // destructor
283 CGroupSkills::~CGroupSkills()
285 // remove observers
286 _SkillsObs.Owner = NULL;
288 CInterfaceManager *pIM= CInterfaceManager::getInstance();
289 string sTmp;
290 ICDBNode::CTextId textId;
291 for (uint k = 0; k < SKILLS::NUM_SKILLS; ++k)
293 sTmp = string(DB_SKILLS)+":"+NLMISC::toString((sint32)k)+":BaseSKILL";
294 textId = ICDBNode::CTextId( sTmp );
295 NLGUI::CDBManager::getInstance()->getDB()->removeObserver(&_SkillsObs, textId );
298 // first remove any nodes from the tree group
299 if( _Tree )
301 // reset now the node hierarchy. NB: the node hierarchy is also deleted
302 _Tree->setRootNode(NULL);
304 _Tree= NULL;
306 // template nodes not linked to hierarchy will memory leak, we must remove them also
307 for (sint i = 0; i<SKILLS::NUM_SKILLS; i++)
309 // is the refptr still allocated?
310 if(_AllNodes[i])
312 // NB: delete call makeOrphan, and delete children that may still be in the array
313 // but it's OK, because tested with refptr
314 delete _AllNodes[i];
315 _AllNodes[i]= NULL;
319 // still allocated (refptr) ?
320 if(_TreeRoot)
322 delete _TreeRoot;
323 _TreeRoot = NULL;
326 void CGroupSkills::createAllTreeNodes()
328 CInterfaceManager *pIM = CInterfaceManager::getInstance();
329 CSkillManager *pSM = CSkillManager::getInstance();
331 // Construct the snode hierarchy structure
332 _TreeRoot = new CGroupTree::SNode;
333 _AllNodes.resize(SKILLS::NUM_SKILLS, NULL);
334 bool bQuit = false;
335 uint nCounter = 0;
337 // local variable (avoid realloc in loop)
338 vector< pair<string, string> > tempVec(2);
339 const char *sSkillName;
341 while ((!bQuit) && (nCounter < 32)) // Counter is used to not infinitly loop
343 nCounter++;
344 bQuit = true;
345 // Try to create a skill
346 for (uint32 i = 0; i < SKILLS::NUM_SKILLS; ++i)
347 if (_AllNodes[i] == NULL) // not already created
349 if (pSM->isUnknown((SKILLS::ESkills)i)) continue;
351 // Create all skills
352 SKILLS::ESkills parentSkill= pSM->getParent((SKILLS::ESkills)i);
354 // if parent, the parent node must be created
355 if (parentSkill != SKILLS::unknown)
357 if (_AllNodes[parentSkill] == NULL)
359 bQuit = false;
360 continue;
364 // Ok lets create it
365 CGroupTree::SNode *pNode = new CGroupTree::SNode;
366 pNode->Id = NLMISC::toString(i);
368 // get Skill Name
369 sSkillName = STRING_MANAGER::CStringManagerClient::getSkillLocalizedName((SKILLS::ESkills)i);
371 // just text or template?
372 if(_TemplateSkill.empty())
374 pNode->DisplayText = true;
375 pNode->Template = NULL;
376 pNode->Text= sSkillName;
378 else
380 pNode->DisplayText = false;
382 // create the template
383 tempVec[0].first="id"; tempVec[0].second= pNode->Id;
384 tempVec[1].first="skillid"; tempVec[1].second= NLMISC::toString(i);
385 CInterfaceGroup *pIG = CWidgetManager::getInstance()->getParser()->createGroupInstance(_TemplateSkill, getId() + ":" + WIN_TREE_LIST, tempVec);
386 if (pIG == NULL)
387 nlwarning("error");
388 // Set Skill Name
389 CViewText *pViewSkillName = dynamic_cast<CViewText*>(pIG->getView("name"));
390 if (pViewSkillName != NULL)
391 pViewSkillName->setText (sSkillName);
392 // Set Skill Max Value
393 CViewText *pViewSkillMax = dynamic_cast<CViewText*>(pIG->getView("max"));
394 if (pViewSkillMax != NULL)
395 pViewSkillMax->setText (toString(pSM->getMaxSkillValue((SKILLS::ESkills)i)));
396 pNode->Template = pIG;
400 // Action handler?
401 if(!_AHCtrlNode.empty())
403 pNode->AHName= _AHCtrlNode;
404 pNode->AHParams= NLMISC::toString(i);
407 // bkup
408 _AllNodes[i] = pNode;
410 // not opened by default
411 pNode->Opened= false;
413 // Attach to the good parent
414 if (parentSkill == SKILLS::unknown)
415 _TreeRoot->addChild(pNode);
416 else
417 _AllNodes[parentSkill]->addChild(pNode);
421 // Sort the First level in this order: Combat/Magic/Craft/Forage/Others.
422 vector<CSortNode> sortNodes;
423 sortNodes.resize(_TreeRoot->Children.size());
424 uint i;
425 for(i=0;i<_TreeRoot->Children.size();i++)
427 sortNodes[i].Node= _TreeRoot->Children[i];
428 // get the skill value of this node
429 sint skillValue;
430 fromString(_TreeRoot->Children[i]->Id, skillValue);
431 // Special sort:
432 if(skillValue==SKILLS::SF)
433 skillValue= -4;
434 if(skillValue==SKILLS::SM)
435 skillValue= -3;
436 if(skillValue==SKILLS::SC)
437 skillValue= -2;
438 if(skillValue==SKILLS::SH)
439 skillValue= -1;
440 // prepare tri
441 sortNodes[i].Value= skillValue;
443 sort(sortNodes.begin(), sortNodes.end());
444 // store sorted values
445 for(i=0;i<_TreeRoot->Children.size();i++)
447 _TreeRoot->Children[i]= sortNodes[i].Node;