// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // *************************************************************************** #include "stdpch.h" #include "group_skills.h" #include "interface_manager.h" #include "nel/gui/interface_expr.h" #include "view_text.h" #include "view_bitmap.h" #include "dbview_number.h" #include "dbview_bar.h" #include "game_share/skills.h" #include "nel/misc/xml_auto_ptr.h" #include "skill_manager.h" #include "nel/misc/i_xml.h" #include "../string_manager_client.h" #include "../user_entity.h" // *************************************************************************** using namespace std; using namespace NLMISC; // *************************************************************************** #define DB_SKILLS "SERVER:CHARACTER_INFO:SKILLS" #define WIN_TREE_LIST "sbtree:tree_list" extern CUserEntity *UserEntity; // Context help extern void contextHelp (const std::string &help); NLMISC_REGISTER_OBJECT(CViewBase, CGroupSkills, std::string, "skills_displayer"); bool CGroupSkills::InhibitSkillUpFX = true; // *************************************************************************** bool CGroupSkills::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); if(!CInterfaceGroup::parse(cur, parentGroup)) return false; CXMLAutoPtr ptr; // read _TemplateSkill ptr = (char*) xmlGetProp (cur, (xmlChar*)"template_skill"); if (ptr) { _TemplateSkill = (const char*)ptr; } // read _AHCtrlNode ptr = (char*) xmlGetProp (cur, (xmlChar*)"node_handler"); if (ptr) { _AHCtrlNode = (const char*)ptr; } // Add observer on the skill parameter because if the skill is coming to be not-zero, a new skill must be displayed _SkillsObs.Owner = this; string sTmp; for (uint k = 0; k < SKILLS::NUM_SKILLS; ++k) { sTmp = string(DB_SKILLS)+":"+NLMISC::toString((sint32)k)+":BaseSKILL"; NLGUI::CDBManager::getInstance()->getDB()->addObserver (&_SkillsObs, ICDBNode::CTextId( sTmp )); } _MustRebuild = true; // create all the Tree Nodes now createAllTreeNodes(); return true; } // *************************************************************************** void CGroupSkills::clearGroups() { CInterfaceGroup::clearGroups(); } // *************************************************************************** void CGroupSkills::checkCoords () { if (_MustRebuild) rebuild(); CInterfaceGroup::checkCoords(); } // *************************************************************************** void CGroupSkills::rebuild() { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CSkillManager *pSM = CSkillManager::getInstance(); // **** first time bind? if(!_Tree) { _Tree = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(getId(),WIN_TREE_LIST)); if (_Tree == NULL) { nlwarning("cant find tree"); return; } // setup _Tree->setRootNode (_TreeRoot); _Tree->selectLine(0); } // **** Update the Show flag of each node // for each skill for (uint32 i = 0; i < SKILLS::NUM_SKILLS; ++i) { bool show= false; if (!pSM->isUnknown((SKILLS::ESkills)i)) { // Show level 0 and level 1 skills + skills that have a PARENT with value > 0 SKILLS::ESkills parentSkill= pSM->getParent((SKILLS::ESkills)i); // if no grand parent, or if grand parent trained if (pSM->getParent(parentSkill) == SKILLS::unknown || pSM->getBaseSkillValue(parentSkill) > 0) show= true; } // set shown? if(_AllNodes[i]) _AllNodes[i]->Show= show; } // refresh _Tree->forceRebuild(); invalidateCoords(); _MustRebuild = false; } // *************************************************************************** void CGroupSkills::CSkillsObs::update (ICDBNode *node) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CCDBNodeLeaf *leaf = NLMISC::safe_cast(node); // Rebuild all only if new skill (previously level 0) if (leaf->getOldValue32() == 0) Owner->_MustRebuild= true; // Popup a message if previous was not 0 if ((leaf->getOldValue32() != 0) && (leaf->getValue32() != 0)) // prevent displaying FX when resetData() is called during a Far TP { CGroupSkills::InhibitSkillUpFX = false; ICDBNode *skill = node->getParent(); if (skill) { ICDBNode *skillParent = skill->getParent(); if (skillParent) { uint skillId; if (skillParent->getNodeIndex (skill, skillId)) { CAHManager::getInstance()->runActionHandler("skill_popup", NULL, "skillId="+toString(skillId)+"|delta="+toString(leaf->getValue32()-leaf->getOldValue32())); // Context help contextHelp ("skill"); } } } } else { if( !CGroupSkills::InhibitSkillUpFX ) // TODO: couldn't this be replaced by IngameDbMngr.initInProgress()? { UserEntity->skillUp(); } } // Check if this skill canunblock title CSkillManager *pSM = CSkillManager::getInstance(); string sTmp = leaf->getFullName(); sTmp = sTmp.substr(0, sTmp.rfind(':')); sTmp = sTmp.substr(sTmp.rfind(':')+1,sTmp.size()); sint32 eSkills; fromString(sTmp, eSkills); pSM->tryToUnblockTitleFromSkill((SKILLS::ESkills)eSkills, leaf->getValue32()); } // *************************************************************************** // Get the skill buf text static DECLARE_INTERFACE_USER_FCT(getSkillBaseText) { if (args.size() != 2) { nlwarning(" Expecting 2 arg."); return false; } if (!args[0].toInteger() && !args[1].toInteger()) { nlwarning(" Can't convert arg 0/1 to a int value."); return false; } sint64 skillValue= args[0].getInteger(); sint64 skillBase= args[1].getInteger(); if(skillValue!=skillBase) { result.setUCString( toString("(%d)", skillBase) ); } else { result.setUCString( ucstring() ); } return true; } REGISTER_INTERFACE_USER_FCT("getSkillBaseText", getSkillBaseText); // *************************************************************************** class CSortNode { public: CGroupTree::SNode *Node; sint Value; bool operator<(const CSortNode &o) const { return ValuegetDB()->removeObserver(&_SkillsObs, ICDBNode::CTextId( sTmp ) ); } // first remove any nodes from the tree group if( _Tree ) { // reset now the node hierarchy. NB: the node hierarchy is also deleted _Tree->setRootNode(NULL); } _Tree= NULL; // template nodes not linked to hierarchy will memory leak, we must remove them also for (sint i = 0; i > tempVec(2); ucstring sSkillName; while ((!bQuit) && (nCounter < 32)) // Counter is used to not infinitly loop { nCounter++; bQuit = true; // Try to create a skill for (uint32 i = 0; i < SKILLS::NUM_SKILLS; ++i) if (_AllNodes[i] == NULL) // not already created { if (pSM->isUnknown((SKILLS::ESkills)i)) continue; // Create all skills SKILLS::ESkills parentSkill= pSM->getParent((SKILLS::ESkills)i); // if parent, the parent node must be created if (parentSkill != SKILLS::unknown) { if (_AllNodes[parentSkill] == NULL) { bQuit = false; continue; } } // Ok lets create it CGroupTree::SNode *pNode = new CGroupTree::SNode; pNode->Id = NLMISC::toString(i); // get Skill Name sSkillName = STRING_MANAGER::CStringManagerClient::getSkillLocalizedName((SKILLS::ESkills)i); // just text or template? if(_TemplateSkill.empty()) { pNode->DisplayText = true; pNode->Template = NULL; pNode->Text= sSkillName; } else { pNode->DisplayText = false; // create the template tempVec[0].first="id"; tempVec[0].second= pNode->Id; tempVec[1].first="skillid"; tempVec[1].second= NLMISC::toString(i); CInterfaceGroup *pIG = pIM->createGroupInstance(_TemplateSkill, getId() + ":" + WIN_TREE_LIST, tempVec); if (pIG == NULL) nlwarning("error"); // Set Skill Name CViewText *pViewSkillName = dynamic_cast(pIG->getView("name")); if (pViewSkillName != NULL) pViewSkillName->setText (sSkillName); // Set Skill Max Value CViewText *pViewSkillMax = dynamic_cast(pIG->getView("max")); if (pViewSkillMax != NULL) pViewSkillMax->setText (toString(pSM->getMaxSkillValue((SKILLS::ESkills)i))); pNode->Template = pIG; } // Action handler? if(!_AHCtrlNode.empty()) { pNode->AHName= _AHCtrlNode; pNode->AHParams= NLMISC::toString(i); } // bkup _AllNodes[i] = pNode; // not opened by default pNode->Opened= false; // Attach to the good parent if (parentSkill == SKILLS::unknown) _TreeRoot->addChild(pNode); else _AllNodes[parentSkill]->addChild(pNode); } } // Sort the First level in this order: Combat/Magic/Craft/Forage/Others. vector sortNodes; sortNodes.resize(_TreeRoot->Children.size()); uint i; for(i=0;i<_TreeRoot->Children.size();i++) { sortNodes[i].Node= _TreeRoot->Children[i]; // get the skill value of this node sint skillValue; fromString(_TreeRoot->Children[i]->Id, skillValue); // Special sort: if(skillValue==SKILLS::SF) skillValue= -4; if(skillValue==SKILLS::SM) skillValue= -3; if(skillValue==SKILLS::SC) skillValue= -2; if(skillValue==SKILLS::SH) skillValue= -1; // prepare tri sortNodes[i].Value= skillValue; } sort(sortNodes.begin(), sortNodes.end()); // store sorted values for(i=0;i<_TreeRoot->Children.size();i++) { _TreeRoot->Children[i]= sortNodes[i].Node; } }