1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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>
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/>.
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
;
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 // ***************************************************************************
55 // ***************************************************************************
58 // ***************************************************************************
59 CSkillManager::CSkillManager()
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
);
95 CUnblockTitlesSheet
*pUTS
= dynamic_cast<CUnblockTitlesSheet
*>(pES
);
102 // must exist, else random access later....
104 nlassert(_UnblockTitle
);
106 // **** Data error management
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
);
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
;
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
)
194 if ((eSkill
< 0) || (eSkill
>= SKILLS::NUM_SKILLS
))
196 return _Tree
->SkillsTree
[eSkill
].Skill
== SKILLS::unknown
;
199 // ***************************************************************************
200 ESkills
CSkillManager::getParent (ESkills eSkill
)
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
)
215 static vector
<SKILLS::ESkills
> emptyVect
;
216 if ((eSkill
< 0) || (eSkill
>= SKILLS::NUM_SKILLS
))
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
))
230 // No if only one is unknown
231 if(s0
==SKILLS::unknown
|| s1
==SKILLS::unknown
)
234 // The 2 skills are on the same branch if:
240 // one is parent of the other.
241 parent
= getParent(s0
);
242 while(parent
!=SKILLS::unknown
)
246 parent
= getParent(parent
);
249 // or the other is parent of the one.
250 parent
= getParent(s1
);
251 while(parent
!=SKILLS::unknown
)
255 parent
= getParent(parent
);
258 // else not on same branch
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
))
271 // No if only one is unknown
272 if(s0
==SKILLS::unknown
|| s1
==SKILLS::unknown
)
279 // or if s1 has a parent == s0.
280 parent
= getParent(s1
);
281 while(parent
!=SKILLS::unknown
)
285 parent
= getParent(parent
);
293 // ***************************************************************************
294 uint32
CSkillManager::getMinSkillValue(SKILLS::ESkills eSkill
)
296 if ((eSkill
< 0) || (eSkill
>= SKILLS::NUM_SKILLS
))
298 return _MinSkillValue
[eSkill
];
301 // ***************************************************************************
302 uint32
CSkillManager::getMaxSkillValue(SKILLS::ESkills eSkill
)
305 if ((eSkill
< 0) || (eSkill
>= SKILLS::NUM_SKILLS
))
307 return _Tree
->SkillsTree
[eSkill
].MaxSkillValue
;
310 // ***************************************************************************
311 uint32
CSkillManager::getSkillValue(SKILLS::ESkills eSkill
)
313 if ((eSkill
< 0) || (eSkill
>= SKILLS::NUM_SKILLS
))
316 CCDBNodeLeaf
*node
= _SkillValues
[eSkill
];
318 return node
->getValue32();
323 // ***************************************************************************
324 uint32
CSkillManager::getBaseSkillValue(SKILLS::ESkills eSkill
)
326 if ((eSkill
< 0) || (eSkill
>= SKILLS::NUM_SKILLS
))
329 CCDBNodeLeaf
*node
= _SkillBaseValues
[eSkill
];
331 return node
->getValue32();
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
));
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
));
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
]));
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
))
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
)
391 if(_MaxChildBaseSkillValue
[SKILLS::SM
] >= value
)
393 if(_MaxChildBaseSkillValue
[SKILLS::SC
] >= value
)
395 if(_MaxChildBaseSkillValue
[SKILLS::SH
] >= value
)
401 if (_MaxChildBaseSkillValue
[eSkill
] >= value
)
404 while( (eSkill
=getParent(eSkill
)) !=SKILLS::unknown
)
406 if (_MaxChildBaseSkillValue
[eSkill
] >= value
)
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
;
435 while( (eSkill
=getParent(eSkill
)) !=SKILLS::unknown
)
437 // if value if below max child skill value, exit
438 if (_MaxChildBaseSkillValue
[eSkill
] >= value
)
441 _MaxChildBaseSkillValue
[eSkill
] = value
;
445 // ***************************************************************************
446 void CSkillManager::appendSkillChangeCallback(ISkillChangeCallback
*cb
)
449 _SkillChangeCallbackSet
.insert(cb
);
452 // ***************************************************************************
453 void CSkillManager::removeSkillChangeCallback(ISkillChangeCallback
*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
++)
469 sint32 val
= _SkillValues
[i
]->getValue32();
470 if(val
!=_CacheSkillValues
[i
])
473 _CacheSkillValues
[i
]= val
;
474 // NB: cannot break, because must update all cache
478 if(_SkillBaseValues
[i
])
480 sint32 val
= _SkillBaseValues
[i
]->getValue32();
481 if(val
!=_CacheSkillBaseValues
[i
])
484 _CacheSkillBaseValues
[i
]= val
;
485 // NB: cannot break, because must update all cache
490 // **** only if some true change
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;
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;
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;
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;
552 bool bAllUnblockedMinFame
= true;
553 for (k
= 0; k
< _TitlesUnblocked
[i
].UnblockedMinFames
.size(); ++k
)
554 if (_TitlesUnblocked
[i
].UnblockedMinFames
[k
] == false)
556 bAllUnblockedMinFame
= false;
559 bool bAllUnblockedMaxFame
= true;
560 for (k
= 0; k
< _TitlesUnblocked
[i
].UnblockedMaxFames
.size(); ++k
)
561 if (_TitlesUnblocked
[i
].UnblockedMaxFames
[k
] == false)
563 bAllUnblockedMaxFame
= false;
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"));
596 // Title is not available anymore, change current title if needed
597 if (i
== CHARACTER_TITLE::ECharacterTitle(_CurrentTitle
))
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
);
607 //nlinfo("impulseCallBack : %s %d sent", msgName, nNewTitle);
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;
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
)
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
)
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
)
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;
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;
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;
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;
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");
852 _TitlesUnblocked
[ct
].Unblocked
= true;
855 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
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
);
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())
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
);
953 uint numItems
= nb
->getNbNodes();
957 for (uint i
= 0; i
< CHARACTER_TITLE::NB_CHARACTER_TITLE
; ++i
)
959 // if (_TitlesUnblocked[i].Unblocked)
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
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;
983 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(branch
+ ":" + toString(itemSlot
) + ":SHEET", false);
985 sheetItem
= (uint32
)node
->getValue32();
992 node
= NLGUI::CDBManager::getInstance()->getDbProp(branch
+ ":" + toString(itemSlot
) + ":QUALITY", false);
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
)
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");
1026 _TitlesUnblocked
[ct
].Unblocked
= false;
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 // ***************************************************************************
1044 // ***************************************************************************
1045 // ***************************************************************************
1047 #define GROUP_TITLE_COMBO "ui:interface:info_player_skills:content:webinfos:title:player_title"
1049 // ***************************************************************************
1050 class CHandlerTitleInit
: public IActionHandler
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();
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
);
1073 REGISTER_ACTION_HANDLER( CHandlerTitleInit
, "title_init_combobox");
1075 // ***************************************************************************
1076 class CHandlerTitleButton
: public IActionHandler
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
));
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
);
1102 pSM
->_UIUnblockedTitles
.push_back((CHARACTER_TITLE::ECharacterTitle
)i
);
1108 REGISTER_ACTION_HANDLER( CHandlerTitleButton
, "title_combobox_button");
1111 // ***************************************************************************
1112 class CHandlerTitleChanged
: public IActionHandler
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
)
1131 static const char *msgName
= "GUILD:SET_PLAYER_TITLE";
1132 if(GenericMsgHeaderMngr
.pushNameToStream(msgName
, out
))
1134 pSM
->setCurrentTitle(nNewTitle
);
1135 out
.serial(nNewTitle
);
1137 //nlinfo("impulseCallBack : %s %d sent", msgName, nNewTitle);
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();