Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / interface_v3 / skill_manager.cpp
blob9d10cde0aeb24e3740a20e602f7691a04b37d522
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 #include "stdpch.h"
24 #include "skill_manager.h"
25 #include "interface_manager.h"
26 #include "game_share/skills.h"
27 #include "nel/misc/xml_auto_ptr.h"
28 #include "game_share/character_title.h"
29 #include "game_share/fame.h"
30 #include "../sheet_manager.h"
31 #include "nel/misc/cdb_leaf.h"
32 #include "nel/gui/action_handler.h"
33 #include "sbrick_manager.h"
34 #include "nel/gui/dbgroup_combo_box.h"
35 #include "nel/gui/view_bitmap.h"
36 #include "../net_manager.h"
37 #include "sbrick_manager.h"
38 #include "../user_entity.h"
39 #include "../npc_icon.h"
41 using namespace SKILLS;
42 using namespace std;
43 using namespace NLMISC;
44 using namespace STRING_MANAGER;
46 sint FAME_MIN_DBVALUE = -100;
47 sint FAME_MAX_DBVALUE = 100;
49 CSkillManager* CSkillManager::_Instance = NULL;
51 extern CUserEntity *UserEntity;
53 // ***************************************************************************
54 // CSkillManager
55 // ***************************************************************************
58 // ***************************************************************************
59 CSkillManager::CSkillManager()
61 _UnblockTitle = NULL;
62 _Tree= NULL;
64 for(uint i=0;i<SKILLS::NUM_SKILLS;i++)
66 _SkillValues[i]= NULL;
67 _SkillBaseValues[i]= NULL;
68 _MaxChildBaseSkillValue[i] = 0;
69 _CacheSkillValues[i]= 0;
70 _CacheSkillBaseValues[i]= 0;
73 _TrackSkillChange= NULL;
76 // ***************************************************************************
77 CSkillManager::~CSkillManager()
82 // ***************************************************************************
83 void CSkillManager::initInGame()
85 const CSheetManager::TEntitySheetMap &mSheets = SheetMngr.getSheets();
86 CSheetManager::TEntitySheetMap::const_iterator itSheet = mSheets.begin();
87 while (itSheet != mSheets.end())
89 CEntitySheet *pES = itSheet->second.EntitySheet;
90 CSkillsTreeSheet *pSTS = dynamic_cast<CSkillsTreeSheet*>(pES);
91 if (pSTS != NULL)
93 _Tree = pSTS;
95 CUnblockTitlesSheet *pUTS = dynamic_cast<CUnblockTitlesSheet*>(pES);
96 if (pUTS != NULL)
98 _UnblockTitle = pUTS;
100 itSheet++;
102 // must exist, else random access later....
103 nlassert(_Tree);
104 nlassert(_UnblockTitle);
106 // **** Data error management
107 // For each skills
108 uint i;
109 for (i = 0; i < SKILLS::NUM_SKILLS; ++i)
111 vector<SKILLS::ESkills> &children= _Tree->SkillsTree[i].ChildSkills;
112 for (sint32 j = 0; j < (sint32)children.size(); ++j)
114 if (children[j] >= SKILLS::NUM_SKILLS)
116 children.erase(children.begin()+j);
117 j--;
122 // **** Min Skill Value mgt, also update max child skill value
123 for(i=0;i<NUM_SKILLS;++i)
125 _MinSkillValue[i]= getMaxSkillValue(getParent(SKILLS::ESkills(i)));
128 // **** CHARACTER TITLE management
129 nlassert(_UnblockTitle->TitlesUnblock.size() == CHARACTER_TITLE::NB_CHARACTER_TITLE);
130 _TitlesUnblocked.resize(CHARACTER_TITLE::NB_CHARACTER_TITLE);
131 for (i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
133 _TitlesUnblocked[i].Unblocked = false;
134 _TitlesUnblocked[i].UnblockedSkillLists.resize (_UnblockTitle->TitlesUnblock[i].SkillsNeeded.size(), false);
135 _TitlesUnblocked[i].UnblockedBricks.resize (_UnblockTitle->TitlesUnblock[i].BricksNeeded.size(), false);
136 _TitlesUnblocked[i].UnblockedMinFames.resize (_UnblockTitle->TitlesUnblock[i].MinFames.size(), false);
137 _TitlesUnblocked[i].UnblockedMaxFames.resize (_UnblockTitle->TitlesUnblock[i].MaxFames.size(), false);
138 _TitlesUnblocked[i].UnblockedCiv = _UnblockTitle->TitlesUnblock[i].CivNeeded.empty();
139 _TitlesUnblocked[i].UnblockedCult = _UnblockTitle->TitlesUnblock[i].CultNeeded.empty();
140 _TitlesUnblocked[i].UnblockedCharOldness = _UnblockTitle->TitlesUnblock[i].CharOldness.empty();
141 _TitlesUnblocked[i].UnblockedCharPlayedTime = _UnblockTitle->TitlesUnblock[i].CharPlayedTime.empty();
142 _TitlesUnblocked[i].UnblockedAccountOldness = _UnblockTitle->TitlesUnblock[i].AccountOldness.empty();
143 _TitlesUnblocked[i].UnblockedAuthorRating = (_UnblockTitle->TitlesUnblock[i].AuthorRating == 0);
144 _TitlesUnblocked[i].UnblockedAMRating = (_UnblockTitle->TitlesUnblock[i].AMRating == 0);
145 _TitlesUnblocked[i].UnblockedOrganizerRating = (_UnblockTitle->TitlesUnblock[i].OrganizerRating == 0);
146 _TitlesUnblocked[i].UnblockedItemLists.resize (_UnblockTitle->TitlesUnblock[i].ItemsNeeded.size(), false);
150 // **** Player State management
151 CInterfaceManager *pIM= CInterfaceManager::getInstance();
152 // get now the nodes on Skill values
153 for(i=0;i<SKILLS::NUM_SKILLS;i++)
155 _SkillValues[i]= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:CHARACTER_INFO:SKILLS:%d:SKILL", i), false);
156 _SkillBaseValues[i]= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:CHARACTER_INFO:SKILLS:%d:BaseSKILL", i), false);
159 // compute max child values
160 computeMaxChildValues(); // must be called after setting all _SkillBaseValues
162 // Get a node used to inform interface that a skill has changed
163 _TrackSkillChange= NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:TRACK_SKILL_CHANGE", true);
164 // Add a branch observer on skill value change
165 NLGUI::CDBManager::getInstance()->addBranchObserver( "SERVER:CHARACTER_INFO:SKILLS", &_SkillChangeObs );
168 // ***************************************************************************
169 void CSkillManager::uninitInGame()
171 _UnblockTitle = NULL;
172 _Tree= NULL;
174 uint i;
175 for(i=0;i<SKILLS::NUM_SKILLS;i++)
177 _SkillValues[i]= NULL;
178 _SkillBaseValues[i]= NULL;
179 _MaxChildBaseSkillValue[i] = 0;
180 _CacheSkillValues[i]= 0;
181 _CacheSkillBaseValues[i]= 0;
184 _TrackSkillChange= NULL;
186 contReset(_TitlesUnblocked);
190 // ***************************************************************************
191 bool CSkillManager::isUnknown (SKILLS::ESkills eSkill)
193 nlassert(_Tree);
194 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
195 return true;
196 return _Tree->SkillsTree[eSkill].Skill == SKILLS::unknown;
199 // ***************************************************************************
200 ESkills CSkillManager::getParent (ESkills eSkill)
202 nlassert(_Tree);
203 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
204 return SKILLS::unknown;
205 if ((_Tree->SkillsTree[eSkill].ParentSkill < 0) ||
206 (_Tree->SkillsTree[eSkill].ParentSkill >= SKILLS::NUM_SKILLS))
207 return SKILLS::unknown;
208 return _Tree->SkillsTree[eSkill].ParentSkill;
211 // ***************************************************************************
212 const std::vector<SKILLS::ESkills> &CSkillManager::getChildren(SKILLS::ESkills eSkill)
214 nlassert(_Tree);
215 static vector<SKILLS::ESkills> emptyVect;
216 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
217 return emptyVect;
218 return _Tree->SkillsTree[eSkill].ChildSkills;
222 // ***************************************************************************
223 bool CSkillManager::areSkillOnSameBranch(SKILLS::ESkills s0, SKILLS::ESkills s1)
225 SKILLS::ESkills parent;
227 if ((s0 < 0) || (s0 >= SKILLS::NUM_SKILLS) || (s1 < 0) || (s1 >= SKILLS::NUM_SKILLS))
228 return false;
230 // No if only one is unknown
231 if(s0==SKILLS::unknown || s1==SKILLS::unknown)
232 return false;
234 // The 2 skills are on the same branch if:
236 // the 2 are equals!
237 if(s0==s1)
238 return true;
240 // one is parent of the other.
241 parent= getParent(s0);
242 while(parent!=SKILLS::unknown)
244 if(parent==s1)
245 return true;
246 parent= getParent(parent);
249 // or the other is parent of the one.
250 parent= getParent(s1);
251 while(parent!=SKILLS::unknown)
253 if(parent==s0)
254 return true;
255 parent= getParent(parent);
258 // else not on same branch
259 return false;
263 // ***************************************************************************
264 bool CSkillManager::isSkillAncestor(SKILLS::ESkills s0, SKILLS::ESkills s1)
266 SKILLS::ESkills parent;
268 if ((s0 < 0) || (s0 >= SKILLS::NUM_SKILLS) || (s1 < 0) || (s1 >= SKILLS::NUM_SKILLS))
269 return false;
271 // No if only one is unknown
272 if(s0==SKILLS::unknown || s1==SKILLS::unknown)
273 return false;
275 // the 2 are equals?
276 if(s0==s1)
277 return true;
279 // or if s1 has a parent == s0.
280 parent= getParent(s1);
281 while(parent!=SKILLS::unknown)
283 if(parent==s0)
284 return true;
285 parent= getParent(parent);
288 // else
289 return false;
293 // ***************************************************************************
294 uint32 CSkillManager::getMinSkillValue(SKILLS::ESkills eSkill)
296 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
297 return 0;
298 return _MinSkillValue[eSkill];
301 // ***************************************************************************
302 uint32 CSkillManager::getMaxSkillValue(SKILLS::ESkills eSkill)
304 nlassert(_Tree);
305 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
306 return 0;
307 return _Tree->SkillsTree[eSkill].MaxSkillValue;
310 // ***************************************************************************
311 uint32 CSkillManager::getSkillValue(SKILLS::ESkills eSkill)
313 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
314 return 0;
316 CCDBNodeLeaf *node= _SkillValues[eSkill];
317 if(node)
318 return node->getValue32();
319 else
320 return 0;
323 // ***************************************************************************
324 uint32 CSkillManager::getBaseSkillValue(SKILLS::ESkills eSkill)
326 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
327 return 0;
329 CCDBNodeLeaf *node= _SkillBaseValues[eSkill];
330 if(node)
331 return node->getValue32();
332 else
333 return 0;
336 // ***************************************************************************
337 uint32 CSkillManager::getSkillValueMaxBranch(SKILLS::ESkills eSkill)
339 uint32 ret= getSkillValue(eSkill);
340 while( (eSkill=getParent(eSkill)) !=SKILLS::unknown)
342 ret= max(ret, getSkillValue(eSkill));
344 return ret;
347 // ***************************************************************************
348 uint32 CSkillManager::getBaseSkillValueMaxBranch(SKILLS::ESkills eSkill)
350 uint32 ret= getBaseSkillValue(eSkill);
351 while( (eSkill=getParent(eSkill)) !=SKILLS::unknown)
353 ret= max(ret, getBaseSkillValue(eSkill));
355 return ret;
358 // ***************************************************************************
359 uint32 CSkillManager::getSkillValueMaxChildren(SKILLS::ESkills eSkill)
361 uint32 ret= getSkillValue(eSkill);
362 const vector<SKILLS::ESkills> & children = getChildren(eSkill);
363 for( uint i=0; i<children.size(); ++i )
365 ret= max(ret, getSkillValueMaxChildren(children[i]));
367 return ret;
370 // ***************************************************************************
371 uint32 CSkillManager::getBestSkillValue(SKILLS::ESkills eSkill)
373 return max(getSkillValueMaxBranch(eSkill), getSkillValueMaxChildren(eSkill));
376 // ***************************************************************************
377 uint32 CSkillManager::getBaseSkillValueMaxChildren(SKILLS::ESkills eSkill)
379 if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS))
380 return 0;
381 return _MaxChildBaseSkillValue[eSkill];
384 // ***************************************************************************
385 bool CSkillManager::checkBaseSkillMetRequirement(SKILLS::ESkills eSkill, uint32 value)
387 if( eSkill == SKILLS::unknown )
389 if(_MaxChildBaseSkillValue[SKILLS::SF] >= value)
390 return true;
391 if(_MaxChildBaseSkillValue[SKILLS::SM] >= value)
392 return true;
393 if(_MaxChildBaseSkillValue[SKILLS::SC] >= value)
394 return true;
395 if(_MaxChildBaseSkillValue[SKILLS::SH] >= value)
396 return true;
398 return false;
401 if (_MaxChildBaseSkillValue[eSkill] >= value)
402 return true;
404 while( (eSkill=getParent(eSkill)) !=SKILLS::unknown)
406 if (_MaxChildBaseSkillValue[eSkill] >= value)
407 return true;
409 return false;
412 // ***************************************************************************
413 void CSkillManager::computeMaxChildValues()
415 // Update all MaxBaseSkill
416 for( uint i = 0 ; i < NUM_SKILLS ; ++i )
418 const SKILLS::ESkills skill = SKILLS::ESkills(i);
419 const uint32 value = getBaseSkillValue(skill);
420 // if skill value > 0 and <= max, update parents for max child value
421 if (value > 0 && value <= getMaxSkillValue(skill) )
422 updateParentSkillsMaxChildValue(skill);
426 // ***************************************************************************
427 void CSkillManager::updateParentSkillsMaxChildValue(SKILLS::ESkills eSkill)
429 const uint32 value = getBaseSkillValue(eSkill);
430 // check current skill itself
431 if (_MaxChildBaseSkillValue[eSkill] < value)
432 _MaxChildBaseSkillValue[eSkill] = value;
434 // parent skills
435 while( (eSkill=getParent(eSkill)) !=SKILLS::unknown)
437 // if value if below max child skill value, exit
438 if (_MaxChildBaseSkillValue[eSkill] >= value)
439 return;
441 _MaxChildBaseSkillValue[eSkill] = value;
445 // ***************************************************************************
446 void CSkillManager::appendSkillChangeCallback(ISkillChangeCallback *cb)
448 if(cb)
449 _SkillChangeCallbackSet.insert(cb);
452 // ***************************************************************************
453 void CSkillManager::removeSkillChangeCallback(ISkillChangeCallback *cb)
455 if(cb)
456 _SkillChangeCallbackSet.erase(cb);
459 // ***************************************************************************
460 void CSkillManager::onSkillChange()
462 // **** Check cache (don't call onSkillChange if just PROGRESS_BAR changed)
463 bool someChange= false;
464 for(uint i=0;i<SKILLS::NUM_SKILLS;i++)
466 // SKILL
467 if(_SkillValues[i])
469 sint32 val= _SkillValues[i]->getValue32();
470 if(val!=_CacheSkillValues[i])
472 someChange= true;
473 _CacheSkillValues[i]= val;
474 // NB: cannot break, because must update all cache
477 // BaseSKILL
478 if(_SkillBaseValues[i])
480 sint32 val= _SkillBaseValues[i]->getValue32();
481 if(val!=_CacheSkillBaseValues[i])
483 someChange= true;
484 _CacheSkillBaseValues[i]= val;
485 // NB: cannot break, because must update all cache
490 // **** only if some true change
491 if(someChange)
493 CSkillManager::TSCCBSet::iterator it;
494 // Call onSkillChange for any callback
495 for(it=_SkillChangeCallbackSet.begin();it!=_SkillChangeCallbackSet.end();it++)
497 (*it)->onSkillChange();
500 // Also increment a marker
501 if(_TrackSkillChange)
503 sint32 val= _TrackSkillChange->getValue32();
504 _TrackSkillChange->setValue32(val+1);
507 // re-compute max child skill values
508 CSkillManager::getInstance()->computeMaxChildValues();
512 // ***************************************************************************
513 void CSkillManager::checkTitleUnblocked(CHARACTER_TITLE::ECharacterTitle i, bool show_message)
515 if (isTitleReserved(i)) return;
517 // Is all unblocked ?
518 bool bAllUnblockedSkill = false;
519 uint k;
520 if( _TitlesUnblocked[i].UnblockedSkillLists.size() )
522 for (k = 0; k < _TitlesUnblocked[i].UnblockedSkillLists.size(); ++k)
523 if (_TitlesUnblocked[i].UnblockedSkillLists[k] == true)
525 bAllUnblockedSkill = true;
526 break;
529 else
530 bAllUnblockedSkill = true;
532 bool bAllUnblockedItem = false;
533 if( _TitlesUnblocked[i].UnblockedItemLists.size() )
535 for (k = 0; k < _TitlesUnblocked[i].UnblockedItemLists.size(); ++k)
536 if (_TitlesUnblocked[i].UnblockedItemLists[k] == true)
538 bAllUnblockedItem = true;
539 break;
542 else
543 bAllUnblockedItem = true;
545 bool bAllUnblockedBrick = true;
546 for (k = 0; k < _TitlesUnblocked[i].UnblockedBricks.size(); ++k)
547 if (_TitlesUnblocked[i].UnblockedBricks[k] == false)
549 bAllUnblockedBrick = false;
550 break;
552 bool bAllUnblockedMinFame = true;
553 for (k = 0; k < _TitlesUnblocked[i].UnblockedMinFames.size(); ++k)
554 if (_TitlesUnblocked[i].UnblockedMinFames[k] == false)
556 bAllUnblockedMinFame = false;
557 break;
559 bool bAllUnblockedMaxFame = true;
560 for (k = 0; k < _TitlesUnblocked[i].UnblockedMaxFames.size(); ++k)
561 if (_TitlesUnblocked[i].UnblockedMaxFames[k] == false)
563 bAllUnblockedMaxFame = false;
564 break;
567 bool bUnblockedCiv = _TitlesUnblocked[i].UnblockedCiv;
568 bool bUnblockedCult = _TitlesUnblocked[i].UnblockedCult;
570 bool bUnblockedCharOldness = true; //_TitlesUnblocked[i].UnblockedCharOldness;
571 bool bUnblockedCharPlayedTime = _TitlesUnblocked[i].UnblockedCharPlayedTime;
572 bool bUnblockedAccountOldness = true; //_TitlesUnblocked[i].UnblockedAccountOldness;
575 bool bAllUnblocked = bAllUnblockedSkill && bAllUnblockedBrick && bAllUnblockedItem && bAllUnblockedMinFame && bAllUnblockedMaxFame
576 && bUnblockedCiv && bUnblockedCult && bUnblockedCharOldness && bUnblockedCharPlayedTime
577 && bUnblockedAccountOldness;
579 // If title availability changed
580 if (bAllUnblocked != _TitlesUnblocked[i].Unblocked)
582 _TitlesUnblocked[i].Unblocked = bAllUnblocked;
583 if (!IngameDbMngr.initInProgress())
585 CInterfaceManager *pIM = CInterfaceManager::getInstance();
586 if (bAllUnblocked && show_message)
588 // This is a new title, send a message
589 string titleStr = CHARACTER_TITLE::toString((CHARACTER_TITLE::ECharacterTitle)i);
590 bool womenTitle = (UserEntity && UserEntity->getGender() == GSGENDER::female);
591 const char *newtitle(CStringManagerClient::getTitleLocalizedName(titleStr, womenTitle));
592 CAHManager::getInstance()->runActionHandler("message_popup", NULL, string("text1=") + newtitle + "|text0=" + CI18N::get("uiNewTitleBold"));
594 else
596 // Title is not available anymore, change current title if needed
597 if (i == CHARACTER_TITLE::ECharacterTitle(_CurrentTitle))
599 CBitMemStream out;
600 static const char *msgName = "GUILD:SET_PLAYER_TITLE";
601 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
603 uint8 nNewTitle = uint8(CHARACTER_TITLE::Homin);
604 setCurrentTitle(nNewTitle);
605 out.serial(nNewTitle);
606 NetMngr.push(out);
607 //nlinfo("impulseCallBack : %s %d sent", msgName, nNewTitle);
609 else
611 nlwarning("unknown message name : '%s'.", msgName);
616 // Update title combo box
617 CAHManager::getInstance()->runActionHandler("title_init_combobox", NULL);
622 // ***************************************************************************
623 void CSkillManager::initTitles()
625 CSBrickManager *pBM = CSBrickManager::getInstance();
626 pBM->appendBrickLearnedCallback(&BrickLearnedCB);
629 // ***************************************************************************
630 void CSkillManager::uninitTitles()
632 CSBrickManager *pBM = CSBrickManager::getInstance();
633 pBM->removeBrickLearnedCallback(&BrickLearnedCB);
636 // ***************************************************************************
637 void CSkillManager::tryToUnblockTitleFromSkill(SKILLS::ESkills eSkill, sint32 value)
639 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
641 if (_TitlesUnblocked[i].Unblocked) continue;
643 string sSkill = SKILLS::toString(eSkill);
645 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
647 if (rTU.Reserved) continue;
649 for (uint j = 0; j < rTU.SkillsNeeded.size(); ++j) // for all skill lists
651 if (! _TitlesUnblocked[i].UnblockedSkillLists[j]) // Not already unblocked
653 bool allSkillsFromListValidated = true;
655 for (uint k = 0; k < rTU.SkillsNeeded[j].size(); ++k) // for all skills in current skill list
657 // if skill value too low
658 if (value < rTU.SkillsLevelNeeded[j][k])
659 allSkillsFromListValidated = false;
661 // If not the good skill (skill length test)
662 if (sSkill.size() < rTU.SkillsNeeded[j][k].size())
664 allSkillsFromListValidated = false;
666 else
668 // If not the good skill (bis) (skill hierarchy test)
669 if (strncmp(sSkill.c_str(), rTU.SkillsNeeded[j][k].c_str(), rTU.SkillsNeeded[j][k].size()) != 0)
671 allSkillsFromListValidated = false;
675 if( allSkillsFromListValidated )
677 // Ok we can unblock
678 _TitlesUnblocked[i].UnblockedSkillLists[j] = true;
679 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i);
686 // ***************************************************************************
687 void CSkillManager::tryToUnblockTitleFromBricks(bool show_message)
689 CSBrickManager *pSBM = CSBrickManager::getInstance();
691 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
693 if (_TitlesUnblocked[i].Unblocked) continue;
695 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
697 if (rTU.Reserved) continue;
699 for (uint j = 0; j < rTU.BricksNeeded.size(); ++j)
700 if (! _TitlesUnblocked[i].UnblockedBricks[j]) // Not already unblocked
702 if (pSBM->isBrickKnown(rTU.BricksNeeded[j]))
704 _TitlesUnblocked[i].UnblockedBricks[j] = true;
708 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i, show_message);
712 // ***************************************************************************
713 void CSkillManager::tryToUnblockTitleFromMinFames( uint32 factionIndex, sint32 fameValue )
715 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
717 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
719 // skip reserved titles
720 if (rTU.Reserved) continue;
722 for (uint j = 0; j < rTU.MinFames.size(); ++j)
724 if( rTU.MinFames[j] != factionIndex )
726 continue;
728 const bool unblocked = (fameValue >= rTU.MinFameLevels[j]);
729 if (unblocked != _TitlesUnblocked[i].UnblockedMinFames[j])
731 _TitlesUnblocked[i].UnblockedMinFames[j] = unblocked;
732 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i);
734 break; // there should not be more than one fame prerequisite per faction per title
739 // ***************************************************************************
740 void CSkillManager::tryToUnblockTitleFromMaxFames( uint32 factionIndex, sint32 fameValue )
742 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
744 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
746 // skip reserved titles
747 if (rTU.Reserved) continue;
749 for (uint j = 0; j < rTU.MaxFames.size(); ++j)
751 if( rTU.MaxFames[j] != factionIndex )
753 continue;
755 const bool unblocked = (fameValue <= rTU.MaxFameLevels[j]);
756 if (unblocked != _TitlesUnblocked[i].UnblockedMaxFames[j])
758 _TitlesUnblocked[i].UnblockedMaxFames[j] = unblocked;
759 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i);
761 break; // there should not be more than one fame prerequisite per faction per title
767 // ***************************************************************************
768 void CSkillManager::tryToUnblockTitleFromCiv(bool show_message)
770 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
772 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
774 if (rTU.Reserved) continue;
776 _TitlesUnblocked[i].UnblockedCiv = true;
777 if( !rTU.CivNeeded.empty() )
779 CInterfaceManager *im = CInterfaceManager::getInstance();
780 uint8 civNeeded = (uint8) PVP_CLAN::fromString(rTU.CivNeeded);
782 if (IngameDbMngr.initInProgress())
784 if (NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:FAME:CIV_ALLEGIANCE")->getValue32() != civNeeded)
785 _TitlesUnblocked[i].UnblockedCiv = false;
786 continue;
788 else
790 CCDBNodeLeaf * civLeaf = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:FAME:CIV_ALLEGIANCE");
791 uint8 civDBValue = civLeaf->getValue8();
792 NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:FAME:CIV_ALLEGIANCE")->setValue32((uint32)civDBValue);
794 if( civDBValue != civNeeded )
796 _TitlesUnblocked[i].UnblockedCiv = false;
797 continue;
801 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i, show_message);
805 // ***************************************************************************
806 void CSkillManager::tryToUnblockTitleFromCult(bool show_message)
809 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
811 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
813 if (rTU.Reserved) continue;
815 _TitlesUnblocked[i].UnblockedCult = true;
816 if( !rTU.CultNeeded.empty() )
818 CInterfaceManager *im = CInterfaceManager::getInstance();
819 uint8 cultNeeded = (uint8) PVP_CLAN::fromString(rTU.CultNeeded);
821 if (IngameDbMngr.initInProgress())
823 if (NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:FAME:CULT_ALLEGIANCE")->getValue32() != cultNeeded)
824 _TitlesUnblocked[i].UnblockedCult = false;
825 continue;
827 else
829 CCDBNodeLeaf * cultLeaf = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:FAME:CULT_ALLEGIANCE");
830 uint8 cultDBValue = cultLeaf->getValue8();
831 NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:FAME:CULT_ALLEGIANCE")->setValue32((uint32)cultDBValue);
833 if( cultDBValue != cultNeeded )
835 _TitlesUnblocked[i].UnblockedCult = false;
836 continue;
840 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i, show_message);
844 // ***************************************************************************
845 void CSkillManager::unblockTitleFromServer(CHARACTER_TITLE::ECharacterTitle ct)
847 if ( ! isTitleReserved(ct))
849 nlwarning("server tries to unblock a title that is not reserved");
850 return;
852 _TitlesUnblocked[ct].Unblocked = true;
854 // update emotes
855 CInterfaceManager *pIM = CInterfaceManager::getInstance();
856 pIM->updateEmotes();
860 /// ---------------------------------------------
861 void CSkillManager::tryToUnblockTitleFromCharOldness( uint32 firstConnectedTime )
863 uint32 time = CTime::getSecondsSince1970();
864 if( time > firstConnectedTime )
866 if( firstConnectedTime == 0 )
868 nlwarning("<CSkillManager::tryToUnblockTitleFromCharOldness> first connect time is null !");
871 uint32 oldness = (time - firstConnectedTime)/(60 * 60 * 24);
873 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
875 _TitlesUnblocked[i].UnblockedCharOldness = true;
877 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
879 if (rTU.Reserved) continue;
881 if( !rTU.CharOldness.empty() )
883 uint32 requiredOldness;
884 fromString(rTU.CharOldness, requiredOldness);
885 _TitlesUnblocked[i].UnblockedCharOldness = (oldness > requiredOldness);
887 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i);
890 else
892 nlwarning("<CSkillManager::tryToUnblockTitleFromCharOldness> bad first connect time ? %d",firstConnectedTime);
896 /// ---------------------------------------------
897 void CSkillManager::tryToUnblockTitleFromCharPlayedTime( uint32 playedTime )
899 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
901 _TitlesUnblocked[i].UnblockedCharPlayedTime = true;
903 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
904 if (rTU.Reserved) continue;
906 if( !rTU.CharPlayedTime.empty() )
908 uint32 requiredPlayedTime;
909 fromString(rTU.CharPlayedTime, requiredPlayedTime);
910 _TitlesUnblocked[i].UnblockedCharPlayedTime = (playedTime/(60 * 60 * 24) > requiredPlayedTime);
912 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i);
916 /// ---------------------------------------------
917 void CSkillManager::tryToUnblockTitleFromAccountOldness( uint32 /* accountCreationTime */ )
921 /// ---------------------------------------------
922 void CSkillManager::tryToUnblockTitleFromRingRatings( uint32 authorRating, uint32 amRating, uint32 masterlessRating )
924 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
926 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
927 if (rTU.Reserved) continue;
929 _TitlesUnblocked[i].UnblockedAuthorRating = rTU.AuthorRating <= authorRating;
930 _TitlesUnblocked[i].UnblockedAMRating = rTU.AMRating <= amRating;
931 _TitlesUnblocked[i].UnblockedOrganizerRating = rTU.OrganizerRating <= masterlessRating;
933 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i);
937 // ***************************************************************************
938 void CSkillManager::tryToUnblockTitleFromItems(bool show_message)
940 if (IngameDbMngr.initInProgress())
941 return;
943 std::string branch = "LOCAL:INVENTORY:BAG";
945 CInterfaceManager *pIM = CInterfaceManager::getInstance();
947 // get inventory in bag
948 CCDBNodeBranch *nb = NLGUI::CDBManager::getInstance()->getDbBranch(branch);
949 if (!nb)
950 return;
952 // get items count
953 uint numItems = nb->getNbNodes();
954 if (!numItems)
955 return;
957 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
959 // if (_TitlesUnblocked[i].Unblocked)
960 // continue;
962 CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i];
964 // don't check reserved titles or titles without items
965 if (rTU.Reserved || rTU.ItemsNeeded.empty()) continue;
967 for (uint j = 0; j < rTU.ItemsNeeded.size(); ++j) // for all item lists
969 // if (_TitlesUnblocked[i].UnblockedItemLists[j]) // Not already unblocked
970 // continue;
972 uint numItemsFromListToValidate = (uint)rTU.ItemsNeeded[j].size();
974 for (uint k = 0; k < rTU.ItemsNeeded[j].size(); ++k) // for all items in current item list
976 // check items present in bag
977 for (uint itemSlot = 0; itemSlot < numItems; ++itemSlot)
979 uint32 sheetItem = 0;
980 sint32 qualityItem = 0;
982 // get sheetid
983 CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp(branch + ":" + toString(itemSlot) + ":SHEET", false);
984 if (node)
985 sheetItem = (uint32)node->getValue32();
987 // slot empty
988 if (!sheetItem)
989 continue;
991 // get quality
992 node = NLGUI::CDBManager::getInstance()->getDbProp(branch + ":" + toString(itemSlot) + ":QUALITY", false);
993 if (node)
994 qualityItem = node->getValue32();
996 // sheetid and quality are identical
997 if (qualityItem == rTU.ItemsQualityNeeded[j][k] && sheetItem == rTU.ItemsNeeded[j][k].asInt())
998 --numItemsFromListToValidate;
1000 // we found all items, don't process next ones
1001 if (!numItemsFromListToValidate)
1002 break;
1006 bool allItemsFromListValidated = (numItemsFromListToValidate == 0);
1008 // ok we can block or unblock
1009 if (allItemsFromListValidated != _TitlesUnblocked[i].UnblockedItemLists[j])
1011 _TitlesUnblocked[i].UnblockedItemLists[j] = allItemsFromListValidated;
1012 checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i, show_message);
1018 // ***************************************************************************
1019 void CSkillManager::blockTitleFromServer(CHARACTER_TITLE::ECharacterTitle ct)
1021 if ( ! isTitleReserved(ct))
1023 nlwarning("server tries to block a title that is not reserved");
1024 return;
1026 _TitlesUnblocked[ct].Unblocked = false;
1028 // update emotes
1029 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1030 pIM->updateEmotes();
1033 // ***************************************************************************
1034 void CSkillManager::setPlayerTitle(const std::string &name)
1036 setCurrentTitle(CHARACTER_TITLE::toCharacterTitle(name));
1037 CAHManager::getInstance()->runActionHandler("title_init_combobox", NULL);
1041 // ***************************************************************************
1042 // ***************************************************************************
1043 // CHARACTER TITLE
1044 // ***************************************************************************
1045 // ***************************************************************************
1047 #define GROUP_TITLE_COMBO "ui:interface:info_player_skills:content:webinfos:title:player_title"
1049 // ***************************************************************************
1050 class CHandlerTitleInit: public IActionHandler
1052 public:
1053 virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */)
1055 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1056 CAHManager::getInstance()->runActionHandler("title_combobox_button", NULL);
1058 // Setup UI:TITLE from current title
1059 CSkillManager *pSM = CSkillManager::getInstance();
1060 uint i,j = 0;
1061 for (i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
1062 if (pSM->isTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i))
1064 if (i == pSM->_CurrentTitle)
1066 NLGUI::CDBManager::getInstance()->getDbProp("UI:TITLE")->setValue32(j);
1067 break;
1069 j++;
1073 REGISTER_ACTION_HANDLER( CHandlerTitleInit, "title_init_combobox");
1075 // ***************************************************************************
1076 class CHandlerTitleButton: public IActionHandler
1078 public:
1079 virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */)
1081 CSkillManager *pSM = CSkillManager::getInstance();
1082 // Try to unblock titles without showing the new title message
1083 pSM->tryToUnblockTitleFromBricks(false);
1084 pSM->tryToUnblockTitleFromCiv(false);
1085 pSM->tryToUnblockTitleFromCult(false);
1086 pSM->tryToUnblockTitleFromItems(false);
1088 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1089 CDBGroupComboBox *pCB = dynamic_cast<CDBGroupComboBox*>(CWidgetManager::getInstance()->getElementFromId(GROUP_TITLE_COMBO));
1090 if (pCB != NULL)
1092 pCB->resetTexts();
1093 pSM->_UIUnblockedTitles.clear();
1094 for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i)
1096 if (pSM->isTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i))
1098 string titleStr = CHARACTER_TITLE::toString((CHARACTER_TITLE::ECharacterTitle)i);
1099 bool womenTitle = (UserEntity && UserEntity->getGender() == GSGENDER::female);
1100 const char *s = CStringManagerClient::getTitleLocalizedName(titleStr, womenTitle);
1101 pCB->addText(s);
1102 pSM->_UIUnblockedTitles.push_back((CHARACTER_TITLE::ECharacterTitle)i);
1108 REGISTER_ACTION_HANDLER( CHandlerTitleButton, "title_combobox_button");
1111 // ***************************************************************************
1112 class CHandlerTitleChanged: public IActionHandler
1114 public:
1115 virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */)
1117 CSkillManager *pSM = CSkillManager::getInstance();
1118 uint8 nNewTitle = 0;
1120 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1121 CDBGroupComboBox *pCB = dynamic_cast<CDBGroupComboBox*>(CWidgetManager::getInstance()->getElementFromId(GROUP_TITLE_COMBO));
1122 if (pCB == NULL) return;
1123 if ((pCB->getSelection() < 0) || (pCB->getSelection() >= (sint32)pSM->_UIUnblockedTitles.size())) return;
1125 nNewTitle = (uint8)pSM->_UIUnblockedTitles[pCB->getSelection()];
1127 // If new title choosen is different from current title -> Send the message to the server
1128 if (nNewTitle != pSM->_CurrentTitle)
1130 CBitMemStream out;
1131 static const char *msgName = "GUILD:SET_PLAYER_TITLE";
1132 if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
1134 pSM->setCurrentTitle(nNewTitle);
1135 out.serial(nNewTitle);
1136 NetMngr.push(out);
1137 //nlinfo("impulseCallBack : %s %d sent", msgName, nNewTitle);
1139 else
1141 nlwarning("unknown message name : '%s'.", msgName);
1146 REGISTER_ACTION_HANDLER( CHandlerTitleChanged, "title_combobox_changed");
1149 void CSkillManager::setCurrentTitle(uint8 title)
1151 _CurrentTitle = title;
1152 CNPCIconCache::getInstance().onEventForMissionAvailabilityForThisChar();