// 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 "skill_manager.h" #include "interface_manager.h" #include "game_share/skills.h" #include "game_share/xml_auto_ptr.h" #include "game_share/character_title.h" #include "game_share/fame.h" #include "../sheet_manager.h" #include "../cdb_leaf.h" #include "action_handler.h" #include "sbrick_manager.h" #include "dbgroup_combo_box.h" #include "view_bitmap.h" #include "../net_manager.h" #include "sbrick_manager.h" #include "../user_entity.h" #include "../npc_icon.h" using namespace SKILLS; using namespace std; using namespace NLMISC; using namespace STRING_MANAGER; sint FAME_MIN_DBVALUE = -100; sint FAME_MAX_DBVALUE = 100; CSkillManager* CSkillManager::_Instance = NULL; extern CUserEntity *UserEntity; // *************************************************************************** // CSkillManager // *************************************************************************** // *************************************************************************** CSkillManager::CSkillManager() { _UnblockTitle = NULL; _Tree= NULL; for(uint i=0;isecond.EntitySheet; CSkillsTreeSheet *pSTS = dynamic_cast(pES); if (pSTS != NULL) { _Tree = pSTS; } CUnblockTitlesSheet *pUTS = dynamic_cast(pES); if (pUTS != NULL) { _UnblockTitle = pUTS; } itSheet++; } // must exist, else random access later.... nlassert(_Tree); nlassert(_UnblockTitle); // **** Data error management // For each skills uint i; for (i = 0; i < SKILLS::NUM_SKILLS; ++i) { vector &children= _Tree->SkillsTree[i].ChildSkills; for (sint32 j = 0; j < (sint32)children.size(); ++j) { if (children[j] >= SKILLS::NUM_SKILLS) { children.erase(children.begin()+j); j--; } } } // **** Min Skill Value mgt, also update max child skill value for(i=0;iTitlesUnblock.size() == CHARACTER_TITLE::NB_CHARACTER_TITLE); _TitlesUnblocked.resize(CHARACTER_TITLE::NB_CHARACTER_TITLE); for (i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { _TitlesUnblocked[i].Unblocked = false; _TitlesUnblocked[i].UnblockedSkillLists.resize (_UnblockTitle->TitlesUnblock[i].SkillsNeeded.size(), false); _TitlesUnblocked[i].UnblockedBricks.resize (_UnblockTitle->TitlesUnblock[i].BricksNeeded.size(), false); _TitlesUnblocked[i].UnblockedMinFames.resize (_UnblockTitle->TitlesUnblock[i].MinFames.size(), false); _TitlesUnblocked[i].UnblockedMaxFames.resize (_UnblockTitle->TitlesUnblock[i].MaxFames.size(), false); _TitlesUnblocked[i].UnblockedCiv = _UnblockTitle->TitlesUnblock[i].CivNeeded.empty(); _TitlesUnblocked[i].UnblockedCult = _UnblockTitle->TitlesUnblock[i].CultNeeded.empty(); _TitlesUnblocked[i].UnblockedCharOldness = _UnblockTitle->TitlesUnblock[i].CharOldness.empty(); _TitlesUnblocked[i].UnblockedCharPlayedTime = _UnblockTitle->TitlesUnblock[i].CharPlayedTime.empty(); _TitlesUnblocked[i].UnblockedAccountOldness = _UnblockTitle->TitlesUnblock[i].AccountOldness.empty(); _TitlesUnblocked[i].UnblockedAuthorRating = (_UnblockTitle->TitlesUnblock[i].AuthorRating == 0); _TitlesUnblocked[i].UnblockedAMRating = (_UnblockTitle->TitlesUnblock[i].AMRating == 0); _TitlesUnblocked[i].UnblockedOrganizerRating = (_UnblockTitle->TitlesUnblock[i].OrganizerRating == 0); _TitlesUnblocked[i].UnblockedItemLists.resize (_UnblockTitle->TitlesUnblock[i].ItemsNeeded.size(), false); } // **** Player State management CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get now the nodes on Skill values for(i=0;igetDbProp(toString("SERVER:CHARACTER_INFO:SKILLS:%d:SKILL", i), false); _SkillBaseValues[i]= pIM->getDbProp(toString("SERVER:CHARACTER_INFO:SKILLS:%d:BaseSKILL", i), false); } // compute max child values computeMaxChildValues(); // must be called after setting all _SkillBaseValues // Get a node used to inform interface that a skill has changed _TrackSkillChange= pIM->getDbProp("UI:VARIABLES:TRACK_SKILL_CHANGE", true); // Add a branch observer on skill value change pIM->getDbBranch("SERVER:CHARACTER_INFO:SKILLS")->addBranchObserver(&_SkillChangeObs); } // *************************************************************************** void CSkillManager::uninitInGame() { _UnblockTitle = NULL; _Tree= NULL; uint i; for(i=0;i= SKILLS::NUM_SKILLS)) return true; return _Tree->SkillsTree[eSkill].Skill == SKILLS::unknown; } // *************************************************************************** ESkills CSkillManager::getParent (ESkills eSkill) { nlassert(_Tree); if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS)) return SKILLS::unknown; if ((_Tree->SkillsTree[eSkill].ParentSkill < 0) || (_Tree->SkillsTree[eSkill].ParentSkill >= SKILLS::NUM_SKILLS)) return SKILLS::unknown; return _Tree->SkillsTree[eSkill].ParentSkill; } // *************************************************************************** const std::vector &CSkillManager::getChildren(SKILLS::ESkills eSkill) { nlassert(_Tree); static vector emptyVect; if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS)) return emptyVect; return _Tree->SkillsTree[eSkill].ChildSkills; } // *************************************************************************** bool CSkillManager::areSkillOnSameBranch(SKILLS::ESkills s0, SKILLS::ESkills s1) { SKILLS::ESkills parent; if ((s0 < 0) || (s0 >= SKILLS::NUM_SKILLS) || (s1 < 0) || (s1 >= SKILLS::NUM_SKILLS)) return false; // No if only one is unknown if(s0==SKILLS::unknown || s1==SKILLS::unknown) return false; // The 2 skills are on the same branch if: // the 2 are equals! if(s0==s1) return true; // one is parent of the other. parent= getParent(s0); while(parent!=SKILLS::unknown) { if(parent==s1) return true; parent= getParent(parent); } // or the other is parent of the one. parent= getParent(s1); while(parent!=SKILLS::unknown) { if(parent==s0) return true; parent= getParent(parent); } // else not on same branch return false; } // *************************************************************************** bool CSkillManager::isSkillAncestor(SKILLS::ESkills s0, SKILLS::ESkills s1) { SKILLS::ESkills parent; if ((s0 < 0) || (s0 >= SKILLS::NUM_SKILLS) || (s1 < 0) || (s1 >= SKILLS::NUM_SKILLS)) return false; // No if only one is unknown if(s0==SKILLS::unknown || s1==SKILLS::unknown) return false; // the 2 are equals? if(s0==s1) return true; // or if s1 has a parent == s0. parent= getParent(s1); while(parent!=SKILLS::unknown) { if(parent==s0) return true; parent= getParent(parent); } // else return false; } // *************************************************************************** uint32 CSkillManager::getMinSkillValue(SKILLS::ESkills eSkill) { if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS)) return 0; return _MinSkillValue[eSkill]; } // *************************************************************************** uint32 CSkillManager::getMaxSkillValue(SKILLS::ESkills eSkill) { nlassert(_Tree); if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS)) return 0; return _Tree->SkillsTree[eSkill].MaxSkillValue; } // *************************************************************************** uint32 CSkillManager::getSkillValue(SKILLS::ESkills eSkill) { if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS)) return 0; CCDBNodeLeaf *node= _SkillValues[eSkill]; if(node) return node->getValue32(); else return 0; } // *************************************************************************** uint32 CSkillManager::getBaseSkillValue(SKILLS::ESkills eSkill) { if ((eSkill < 0) || (eSkill >= SKILLS::NUM_SKILLS)) return 0; CCDBNodeLeaf *node= _SkillBaseValues[eSkill]; if(node) return node->getValue32(); else return 0; } // *************************************************************************** uint32 CSkillManager::getSkillValueMaxBranch(SKILLS::ESkills eSkill) { uint32 ret= getSkillValue(eSkill); while( (eSkill=getParent(eSkill)) !=SKILLS::unknown) { ret= max(ret, getSkillValue(eSkill)); } return ret; } // *************************************************************************** uint32 CSkillManager::getBaseSkillValueMaxBranch(SKILLS::ESkills eSkill) { uint32 ret= getBaseSkillValue(eSkill); while( (eSkill=getParent(eSkill)) !=SKILLS::unknown) { ret= max(ret, getBaseSkillValue(eSkill)); } return ret; } // *************************************************************************** uint32 CSkillManager::getSkillValueMaxChildren(SKILLS::ESkills eSkill) { uint32 ret= getSkillValue(eSkill); const vector & children = getChildren(eSkill); for( uint i=0; i= SKILLS::NUM_SKILLS)) return 0; return _MaxChildBaseSkillValue[eSkill]; } // *************************************************************************** bool CSkillManager::checkBaseSkillMetRequirement(SKILLS::ESkills eSkill, uint32 value) { if( eSkill == SKILLS::unknown ) { if(_MaxChildBaseSkillValue[SKILLS::SF] >= value) return true; if(_MaxChildBaseSkillValue[SKILLS::SM] >= value) return true; if(_MaxChildBaseSkillValue[SKILLS::SC] >= value) return true; if(_MaxChildBaseSkillValue[SKILLS::SH] >= value) return true; return false; } if (_MaxChildBaseSkillValue[eSkill] >= value) return true; while( (eSkill=getParent(eSkill)) !=SKILLS::unknown) { if (_MaxChildBaseSkillValue[eSkill] >= value) return true; } return false; } // *************************************************************************** void CSkillManager::computeMaxChildValues() { // Update all MaxBaseSkill for( uint i = 0 ; i < NUM_SKILLS ; ++i ) { const SKILLS::ESkills skill = SKILLS::ESkills(i); const uint32 value = getBaseSkillValue(skill); // if skill value > 0 and <= max, update parents for max child value if (value > 0 && value <= getMaxSkillValue(skill) ) updateParentSkillsMaxChildValue(skill); } } // *************************************************************************** void CSkillManager::updateParentSkillsMaxChildValue(SKILLS::ESkills eSkill) { const uint32 value = getBaseSkillValue(eSkill); // check current skill itself if (_MaxChildBaseSkillValue[eSkill] < value) _MaxChildBaseSkillValue[eSkill] = value; // parent skills while( (eSkill=getParent(eSkill)) !=SKILLS::unknown) { // if value if below max child skill value, exit if (_MaxChildBaseSkillValue[eSkill] >= value) return; _MaxChildBaseSkillValue[eSkill] = value; } } // *************************************************************************** void CSkillManager::appendSkillChangeCallback(ISkillChangeCallback *cb) { if(cb) _SkillChangeCallbackSet.insert(cb); } // *************************************************************************** void CSkillManager::removeSkillChangeCallback(ISkillChangeCallback *cb) { if(cb) _SkillChangeCallbackSet.erase(cb); } // *************************************************************************** void CSkillManager::onSkillChange() { // **** Check cache (don't call onSkillChange if just PROGRESS_BAR changed) bool someChange= false; for(uint i=0;igetValue32(); if(val!=_CacheSkillValues[i]) { someChange= true; _CacheSkillValues[i]= val; // NB: cannot break, because must update all cache } } // BaseSKILL if(_SkillBaseValues[i]) { sint32 val= _SkillBaseValues[i]->getValue32(); if(val!=_CacheSkillBaseValues[i]) { someChange= true; _CacheSkillBaseValues[i]= val; // NB: cannot break, because must update all cache } } } // **** only if some true change if(someChange) { CSkillManager::TSCCBSet::iterator it; // Call onSkillChange for any callback for(it=_SkillChangeCallbackSet.begin();it!=_SkillChangeCallbackSet.end();it++) { (*it)->onSkillChange(); } // Also increment a marker if(_TrackSkillChange) { sint32 val= _TrackSkillChange->getValue32(); _TrackSkillChange->setValue32(val+1); } // re-compute max child skill values CSkillManager::getInstance()->computeMaxChildValues(); } } // *************************************************************************** void CSkillManager::checkTitleUnblocked(CHARACTER_TITLE::ECharacterTitle i) { if (isTitleReserved(i)) return; // Is all unblocked ? bool bAllUnblockedSkill = false; uint k; if( _TitlesUnblocked[i].UnblockedSkillLists.size() ) { for (k = 0; k < _TitlesUnblocked[i].UnblockedSkillLists.size(); ++k) if (_TitlesUnblocked[i].UnblockedSkillLists[k] == true) { bAllUnblockedSkill = true; break; } } else bAllUnblockedSkill = true; bool bAllUnblockedItem = false; if( _TitlesUnblocked[i].UnblockedItemLists.size() ) { for (k = 0; k < _TitlesUnblocked[i].UnblockedItemLists.size(); ++k) if (_TitlesUnblocked[i].UnblockedItemLists[k] == true) { bAllUnblockedItem = true; break; } } else bAllUnblockedItem = true; bool bAllUnblockedBrick = true; for (k = 0; k < _TitlesUnblocked[i].UnblockedBricks.size(); ++k) if (_TitlesUnblocked[i].UnblockedBricks[k] == false) { bAllUnblockedBrick = false; break; } bool bAllUnblockedMinFame = true; for (k = 0; k < _TitlesUnblocked[i].UnblockedMinFames.size(); ++k) if (_TitlesUnblocked[i].UnblockedMinFames[k] == false) { bAllUnblockedMinFame = false; break; } bool bAllUnblockedMaxFame = true; for (k = 0; k < _TitlesUnblocked[i].UnblockedMaxFames.size(); ++k) if (_TitlesUnblocked[i].UnblockedMaxFames[k] == false) { bAllUnblockedMaxFame = false; break; } bool bUnblockedCiv = _TitlesUnblocked[i].UnblockedCiv; bool bUnblockedCult = _TitlesUnblocked[i].UnblockedCult; bool bUnblockedCharOldness = true; //_TitlesUnblocked[i].UnblockedCharOldness; bool bUnblockedCharPlayedTime = _TitlesUnblocked[i].UnblockedCharPlayedTime; bool bUnblockedAccountOldness = true; //_TitlesUnblocked[i].UnblockedAccountOldness; bool bAllUnblocked = bAllUnblockedSkill && bAllUnblockedBrick && bAllUnblockedItem && bAllUnblockedMinFame && bAllUnblockedMaxFame && bUnblockedCiv && bUnblockedCult && bUnblockedCharOldness && bUnblockedCharPlayedTime && bUnblockedAccountOldness; // If title availability changed if (bAllUnblocked != _TitlesUnblocked[i].Unblocked) { _TitlesUnblocked[i].Unblocked = bAllUnblocked; if (!IngameDbMngr.initInProgress()) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); if (bAllUnblocked) { // This is a new title, send a message string titleStr = CHARACTER_TITLE::toString((CHARACTER_TITLE::ECharacterTitle)i); bool womenTitle = (UserEntity && UserEntity->getGender() == GSGENDER::female); const ucstring newtitle(CStringManagerClient::getTitleLocalizedName(titleStr, womenTitle)); pIM->runActionHandler("message_popup", NULL, "text1="+newtitle.toUtf8()+"|text0="+CI18N::get("uiNewTitleBold").toUtf8()); } else { // Title is not available anymore, change current title if needed if (i == CHARACTER_TITLE::ECharacterTitle(_CurrentTitle)) { CBitMemStream out; static const char *msgName = "GUILD:SET_PLAYER_TITLE"; if(GenericMsgHeaderMngr.pushNameToStream(msgName, out)) { uint8 nNewTitle = uint8(CHARACTER_TITLE::Homin); setCurrentTitle(nNewTitle); out.serial(nNewTitle); NetMngr.push(out); //nlinfo("impulseCallBack : %s %d sent", msgName, nNewTitle); } else { nlwarning("unknown message name : '%s'.", msgName); } } } // Update title combo box pIM->runActionHandler("title_init_combobox", NULL); } } } // *************************************************************************** void CSkillManager::initTitles() { CSBrickManager *pBM = CSBrickManager::getInstance(); pBM->appendBrickLearnedCallback(&BrickLearnedCB); } // *************************************************************************** void CSkillManager::uninitTitles() { CSBrickManager *pBM = CSBrickManager::getInstance(); pBM->removeBrickLearnedCallback(&BrickLearnedCB); } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromSkill(SKILLS::ESkills eSkill, sint32 value) { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { if (_TitlesUnblocked[i].Unblocked) continue; string sSkill = SKILLS::toString(eSkill); CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; for (uint j = 0; j < rTU.SkillsNeeded.size(); ++j) // for all skill lists { if (! _TitlesUnblocked[i].UnblockedSkillLists[j]) // Not already unblocked { bool allSkillsFromListValidated = true; for (uint k = 0; k < rTU.SkillsNeeded[j].size(); ++k) // for all skills in current skill list { // if skill value too low if (value < rTU.SkillsLevelNeeded[j][k]) allSkillsFromListValidated = false; // If not the good skill (skill length test) if (sSkill.size() < rTU.SkillsNeeded[j][k].size()) { allSkillsFromListValidated = false; } else { // If not the good skill (bis) (skill hierarchy test) if (strncmp(sSkill.c_str(), rTU.SkillsNeeded[j][k].c_str(), rTU.SkillsNeeded[j][k].size()) != 0) { allSkillsFromListValidated = false; } } } if( allSkillsFromListValidated ) { // Ok we can unblock _TitlesUnblocked[i].UnblockedSkillLists[j] = true; checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } } } } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromBricks() { CSBrickManager *pSBM = CSBrickManager::getInstance(); for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { if (_TitlesUnblocked[i].Unblocked) continue; CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; for (uint j = 0; j < rTU.BricksNeeded.size(); ++j) if (! _TitlesUnblocked[i].UnblockedBricks[j]) // Not already unblocked { if (pSBM->isBrickKnown(rTU.BricksNeeded[j])) { _TitlesUnblocked[i].UnblockedBricks[j] = true; } } checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromMinFames( uint32 factionIndex, sint32 fameValue ) { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; // skip reserved titles if (rTU.Reserved) continue; for (uint j = 0; j < rTU.MinFames.size(); ++j) { if( rTU.MinFames[j] != factionIndex ) { continue; } const bool unblocked = (fameValue >= rTU.MinFameLevels[j]); if (unblocked != _TitlesUnblocked[i].UnblockedMinFames[j]) { _TitlesUnblocked[i].UnblockedMinFames[j] = unblocked; checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } break; // there should not be more than one fame prerequisite per faction per title } } } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromMaxFames( uint32 factionIndex, sint32 fameValue ) { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; // skip reserved titles if (rTU.Reserved) continue; for (uint j = 0; j < rTU.MaxFames.size(); ++j) { if( rTU.MaxFames[j] != factionIndex ) { continue; } const bool unblocked = (fameValue <= rTU.MaxFameLevels[j]); if (unblocked != _TitlesUnblocked[i].UnblockedMaxFames[j]) { _TitlesUnblocked[i].UnblockedMaxFames[j] = unblocked; checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } break; // there should not be more than one fame prerequisite per faction per title } } } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromCiv() { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; _TitlesUnblocked[i].UnblockedCiv = true; if( !rTU.CivNeeded.empty() ) { CInterfaceManager *im = CInterfaceManager::getInstance(); uint8 civNeeded = (uint8) PVP_CLAN::fromString(rTU.CivNeeded); if (IngameDbMngr.initInProgress()) { if (im->getDbProp("UI:SAVE:FAME:CIV_ALLEGIANCE")->getValue32() != civNeeded) _TitlesUnblocked[i].UnblockedCiv = false; continue; } else { CCDBNodeLeaf * civLeaf = im->getDbProp("SERVER:FAME:CIV_ALLEGIANCE"); uint8 civDBValue = civLeaf->getValue8(); im->getDbProp("UI:SAVE:FAME:CIV_ALLEGIANCE")->setValue32((uint32)civDBValue); if( civDBValue != civNeeded ) { _TitlesUnblocked[i].UnblockedCiv = false; continue; } } } checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromCult() { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; _TitlesUnblocked[i].UnblockedCult = true; if( !rTU.CultNeeded.empty() ) { CInterfaceManager *im = CInterfaceManager::getInstance(); uint8 cultNeeded = (uint8) PVP_CLAN::fromString(rTU.CultNeeded); if (IngameDbMngr.initInProgress()) { if (im->getDbProp("UI:SAVE:FAME:CULT_ALLEGIANCE")->getValue32() != cultNeeded) _TitlesUnblocked[i].UnblockedCult = false; continue; } else { CCDBNodeLeaf * cultLeaf = im->getDbProp("SERVER:FAME:CULT_ALLEGIANCE"); uint8 cultDBValue = cultLeaf->getValue8(); im->getDbProp("UI:SAVE:FAME:CULT_ALLEGIANCE")->setValue32((uint32)cultDBValue); if( cultDBValue != cultNeeded ) { _TitlesUnblocked[i].UnblockedCult = false; continue; } } } checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } // *************************************************************************** void CSkillManager::unblockTitleFromServer(CHARACTER_TITLE::ECharacterTitle ct) { if ( ! isTitleReserved(ct)) { nlwarning("server tries to unblock a title that is not reserved"); return; } _TitlesUnblocked[ct].Unblocked = true; // update emotes CInterfaceManager *pIM = CInterfaceManager::getInstance(); pIM->updateEmotes(); } /// --------------------------------------------- void CSkillManager::tryToUnblockTitleFromCharOldness( uint32 firstConnectedTime ) { uint32 time = CTime::getSecondsSince1970(); if( time > firstConnectedTime ) { if( firstConnectedTime == 0 ) { nlwarning(" first connect time is null !"); } uint32 oldness = (time - firstConnectedTime)/(60 * 60 * 24); for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { _TitlesUnblocked[i].UnblockedCharOldness = true; CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; if( !rTU.CharOldness.empty() ) { uint32 requiredOldness; fromString(rTU.CharOldness, requiredOldness); _TitlesUnblocked[i].UnblockedCharOldness = (oldness > requiredOldness); } checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } else { nlwarning(" bad first connect time ? %d",firstConnectedTime); } } /// --------------------------------------------- void CSkillManager::tryToUnblockTitleFromCharPlayedTime( uint32 playedTime ) { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { _TitlesUnblocked[i].UnblockedCharPlayedTime = true; CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; if( !rTU.CharPlayedTime.empty() ) { uint32 requiredPlayedTime; fromString(rTU.CharPlayedTime, requiredPlayedTime); _TitlesUnblocked[i].UnblockedCharPlayedTime = (playedTime/(60 * 60 * 24) > requiredPlayedTime); } checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } /// --------------------------------------------- void CSkillManager::tryToUnblockTitleFromAccountOldness( uint32 /* accountCreationTime */ ) { } /// --------------------------------------------- void CSkillManager::tryToUnblockTitleFromRingRatings( uint32 authorRating, uint32 amRating, uint32 masterlessRating ) { for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; if (rTU.Reserved) continue; _TitlesUnblocked[i].UnblockedAuthorRating = rTU.AuthorRating <= authorRating; _TitlesUnblocked[i].UnblockedAMRating = rTU.AMRating <= amRating; _TitlesUnblocked[i].UnblockedOrganizerRating = rTU.OrganizerRating <= masterlessRating; checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } // *************************************************************************** void CSkillManager::tryToUnblockTitleFromItems() { if (IngameDbMngr.initInProgress()) return; std::string branch = "LOCAL:INVENTORY:BAG"; CInterfaceManager *pIM = CInterfaceManager::getInstance(); // get inventory in bag CCDBNodeBranch *nb = pIM->getDbBranch(branch); if (!nb) return; // get items count uint numItems = nb->getNbNodes(); if (!numItems) return; for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { // if (_TitlesUnblocked[i].Unblocked) // continue; CUnblockTitlesSheet::STitleUnblock rTU = _UnblockTitle->TitlesUnblock[i]; // don't check reserved titles or titles without items if (rTU.Reserved || rTU.ItemsNeeded.empty()) continue; for (uint j = 0; j < rTU.ItemsNeeded.size(); ++j) // for all item lists { // if (_TitlesUnblocked[i].UnblockedItemLists[j]) // Not already unblocked // continue; uint numItemsFromListToValidate = (uint)rTU.ItemsNeeded[j].size(); for (uint k = 0; k < rTU.ItemsNeeded[j].size(); ++k) // for all items in current item list { // check items present in bag for (uint itemSlot = 0; itemSlot < numItems; ++itemSlot) { sint32 sheetItem = 0; sint32 qualityItem = 0; // get sheetid CCDBNodeLeaf *node = pIM->getDbProp(branch + ":" + toString(itemSlot) + ":SHEET", false); if (node) sheetItem = node->getValue32(); // slot empty if (!sheetItem) continue; // get quality node = pIM->getDbProp(branch + ":" + toString(itemSlot) + ":QUALITY", false); if (node) qualityItem = node->getValue32(); // sheetid and quality are identical if (qualityItem == rTU.ItemsQualityNeeded[j][k] && sheetItem == rTU.ItemsNeeded[j][k].asInt()) --numItemsFromListToValidate; // we found all items, don't process next ones if (!numItemsFromListToValidate) break; } } bool allItemsFromListValidated = (numItemsFromListToValidate == 0); // ok we can block or unblock if (allItemsFromListValidated != _TitlesUnblocked[i].UnblockedItemLists[j]) { _TitlesUnblocked[i].UnblockedItemLists[j] = allItemsFromListValidated; checkTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i); } } } } // *************************************************************************** void CSkillManager::blockTitleFromServer(CHARACTER_TITLE::ECharacterTitle ct) { if ( ! isTitleReserved(ct)) { nlwarning("server tries to block a title that is not reserved"); return; } _TitlesUnblocked[ct].Unblocked = false; // update emotes CInterfaceManager *pIM = CInterfaceManager::getInstance(); pIM->updateEmotes(); } // *************************************************************************** void CSkillManager::setPlayerTitle(const std::string &name) { setCurrentTitle(CHARACTER_TITLE::toCharacterTitle(name)); CInterfaceManager::getInstance()->runActionHandler("title_init_combobox", NULL); } // *************************************************************************** // *************************************************************************** // CHARACTER TITLE // *************************************************************************** // *************************************************************************** #define GROUP_TITLE_COMBO "ui:interface:info_player_skills:content:basics_skills:title:player_title" // *************************************************************************** class CHandlerTitleInit: public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); pIM->runActionHandler("title_combobox_button", NULL); // Setup UI:TITLE from current title CSkillManager *pSM = CSkillManager::getInstance(); uint i,j = 0; for (i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) if (pSM->isTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i)) { if (i == pSM->_CurrentTitle) { pIM->getDbProp("UI:TITLE")->setValue32(j); break; } j++; } } }; REGISTER_ACTION_HANDLER( CHandlerTitleInit, "title_init_combobox"); // *************************************************************************** class CHandlerTitleButton: public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */) { CSkillManager *pSM = CSkillManager::getInstance(); pSM->tryToUnblockTitleFromBricks(); pSM->tryToUnblockTitleFromCiv(); pSM->tryToUnblockTitleFromCult(); pSM->tryToUnblockTitleFromItems(); CInterfaceManager *pIM = CInterfaceManager::getInstance(); CDBGroupComboBox *pCB = dynamic_cast(pIM->getElementFromId(GROUP_TITLE_COMBO)); if (pCB != NULL) { pCB->resetTexts(); pSM->_UIUnblockedTitles.clear(); for (uint i = 0; i < CHARACTER_TITLE::NB_CHARACTER_TITLE; ++i) { if (pSM->isTitleUnblocked((CHARACTER_TITLE::ECharacterTitle)i)) { string titleStr = CHARACTER_TITLE::toString((CHARACTER_TITLE::ECharacterTitle)i); bool womenTitle = (UserEntity && UserEntity->getGender() == GSGENDER::female); const ucstring s(CStringManagerClient::getTitleLocalizedName(titleStr,womenTitle)); pCB->addText(s); pSM->_UIUnblockedTitles.push_back((CHARACTER_TITLE::ECharacterTitle)i); } } } } }; REGISTER_ACTION_HANDLER( CHandlerTitleButton, "title_combobox_button"); // *************************************************************************** class CHandlerTitleChanged: public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */) { CSkillManager *pSM = CSkillManager::getInstance(); uint8 nNewTitle = 0; CInterfaceManager *pIM = CInterfaceManager::getInstance(); CDBGroupComboBox *pCB = dynamic_cast(pIM->getElementFromId(GROUP_TITLE_COMBO)); if (pCB == NULL) return; if ((pCB->getSelection() < 0) || (pCB->getSelection() >= (sint32)pSM->_UIUnblockedTitles.size())) return; nNewTitle = (uint8)pSM->_UIUnblockedTitles[pCB->getSelection()]; // If new title choosen is different from current title -> Send the message to the server if (nNewTitle != pSM->_CurrentTitle) { CBitMemStream out; static const char *msgName = "GUILD:SET_PLAYER_TITLE"; if(GenericMsgHeaderMngr.pushNameToStream(msgName, out)) { pSM->setCurrentTitle(nNewTitle); out.serial(nNewTitle); NetMngr.push(out); //nlinfo("impulseCallBack : %s %d sent", msgName, nNewTitle); } else { nlwarning("unknown message name : '%s'.", msgName); } } } }; REGISTER_ACTION_HANDLER( CHandlerTitleChanged, "title_combobox_changed"); void CSkillManager::setCurrentTitle(uint8 title) { _CurrentTitle = title; CNPCIconCache::getInstance().onEventForMissionAvailabilityForThisChar(); }