diff options
author | Kudlaty <none@none> | 2009-12-14 20:47:43 +0100 |
---|---|---|
committer | Kudlaty <none@none> | 2009-12-14 20:47:43 +0100 |
commit | 379cbb72af7869950e04d59b9903ab0dd2618a68 (patch) | |
tree | b2d2f724d74e2ed605f685b2c8317118d0fb8f9e /src | |
parent | 45d74f8e05b0442a08713c12287f6becda34f892 (diff) |
Mangos merge: [8874] Extract player skills from data blob. #526
Converted by Azazel.
--HG--
branch : trunk
Diffstat (limited to 'src')
-rw-r--r-- | src/game/CharacterHandler.cpp | 1 | ||||
-rw-r--r-- | src/game/Player.cpp | 472 | ||||
-rw-r--r-- | src/game/Player.h | 27 | ||||
-rw-r--r-- | src/game/PlayerDump.cpp | 3 |
4 files changed, 311 insertions, 192 deletions
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 14a69e2b732..ca2561f4771 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -92,6 +92,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs WHERE guid='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT spell, spec FROM character_talent WHERE guid='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, "SELECT type, time, data FROM character_account_data WHERE guid='%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid)); return res; } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 26443e9c379..e5613cbb703 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -4252,6 +4252,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid); CharacterDatabase.CommitTransaction(); //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); @@ -5294,15 +5295,12 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if(skill_id == SKILL_FIST_WEAPONS) skill_id = SKILL_UNARMED; - uint16 i=0; - for (; i < PLAYER_MAX_SKILLS; i++) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill_id) - break; - - if(i>=PLAYER_MAX_SKILLS) + SkillStatusMap::iterator itr = mSkillStatus.find(skill_id); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return false; - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); + uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); + uint32 data = GetUInt32Value(valueIndex); uint32 value = SKILL_VALUE(data); uint32 max = SKILL_MAX(data); @@ -5315,7 +5313,9 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if(new_value > max) new_value = max; - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,max)); + SetUInt32Value(valueIndex,MAKE_SKILL_VALUE(new_value,max)); + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,skill_id); return true; } @@ -5424,13 +5424,13 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) return false; } - uint16 i=0; - for (; i < PLAYER_MAX_SKILLS; i++) - if ( SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_INDEX(i))) == SkillId ) break; - if ( i >= PLAYER_MAX_SKILLS ) + SkillStatusMap::iterator itr = mSkillStatus.find(SkillId); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return false; - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); + uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); + + uint32 data = GetUInt32Value(valueIndex); uint16 SkillValue = SKILL_VALUE(data); uint16 MaxValue = SKILL_MAX(data); @@ -5445,7 +5445,9 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) if(new_value > MaxValue) new_value = MaxValue; - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,MaxValue)); + SetUInt32Value(valueIndex,MAKE_SKILL_VALUE(new_value,MaxValue)); + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; for (uint32* bsl = &bonusSkillLevels[0]; *bsl; ++bsl) { if((SkillValue < *bsl && new_value >= *bsl)) @@ -5544,19 +5546,20 @@ void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, bool de void Player::ModifySkillBonus(uint32 skillid,int32 val, bool talent) { - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skillid) - { - uint32 bonus_val = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); - int16 temp_bonus = SKILL_TEMP_BONUS(bonus_val); - int16 perm_bonus = SKILL_PERM_BONUS(bonus_val); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skillid); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return; - if(talent) // permanent bonus stored in high part - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),MAKE_SKILL_BONUS(temp_bonus,perm_bonus+val)); - else // temporary/item bonus stored in low part - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),MAKE_SKILL_BONUS(temp_bonus+val,perm_bonus)); - return; - } + uint32 bonusIndex = PLAYER_SKILL_BONUS_INDEX(itr->second.pos); + + uint32 bonus_val = GetUInt32Value(bonusIndex); + int16 temp_bonus = SKILL_TEMP_BONUS(bonus_val); + int16 perm_bonus = SKILL_PERM_BONUS(bonus_val); + + if(talent) // permanent bonus stored in high part + SetUInt32Value(bonusIndex,MAKE_SKILL_BONUS(temp_bonus,perm_bonus+val)); + else // temporary/item bonus stored in low part + SetUInt32Value(bonusIndex,MAKE_SKILL_BONUS(temp_bonus+val,perm_bonus)); } void Player::UpdateSkillsForLevel() @@ -5566,53 +5569,67 @@ void Player::UpdateSkillsForLevel() bool alwaysMaxSkill = sWorld.getConfig(CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL); - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if (GetUInt32Value(PLAYER_SKILL_INDEX(i))) - { - uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; + for(SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ++itr) + { + if(itr->second.uState == SKILL_DELETED) + continue; - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(pskill); - if (!pSkill) - continue; + uint32 pskill = itr->first; + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(pskill); + if (!pSkill) + continue; - if (GetSkillRangeType(pSkill,false) != SKILL_RANGE_LEVEL) - continue; + if (GetSkillRangeType(pSkill,false) != SKILL_RANGE_LEVEL) + continue; - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); - uint32 max = SKILL_MAX(data); - uint32 val = SKILL_VALUE(data); + uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); + uint32 data = GetUInt32Value(valueIndex); + uint32 max = SKILL_MAX(data); + uint32 val = SKILL_VALUE(data); - /// update only level dependent max skill values - if (max != 1) + /// update only level dependent max skill values + if (max != 1) + { + /// maximize skill always + if (alwaysMaxSkill) + { + SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(maxSkill,maxSkill)); + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; + } + else if(max != maxconfskill) /// update max skill value if current max skill not maximized { - /// miximize skill always - if (alwaysMaxSkill) - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(maxSkill,maxSkill)); - /// update max skill value if current max skill not maximized - else if (max != maxconfskill) - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(val,maxSkill)); + SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(val,maxSkill)); + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; } } + } } void Player::UpdateSkillsToMaxSkillsForLevel() { - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if (GetUInt32Value(PLAYER_SKILL_INDEX(i))) - { - uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - if (IsProfessionOrRidingSkill(pskill)) - continue; - uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)); - - uint32 max = SKILL_MAX(data); + for(SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ++itr) + { + if(itr->second.uState == SKILL_DELETED) + continue; - if (max > 1) - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(max,max)); + uint32 pskill = itr->first; + if (IsProfessionOrRidingSkill(pskill)) + continue; + uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); + uint32 data = GetUInt32Value(valueIndex); + uint32 max = SKILL_MAX(data); - if (pskill == SKILL_DEFENSE) - UpdateDefenseBonusesMod(); + if (max > 1) + { + SetUInt32Value(valueIndex,MAKE_SKILL_VALUE(max,max)); + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; } + if (pskill == SKILL_DEFENSE) + UpdateDefenseBonusesMod(); + } } // This functions sets a skill line value (and adds if doesn't exist yet) @@ -5622,16 +5639,16 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) if (!id) return; - uint16 i = 0; - for (; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == id) - break; + SkillStatusMap::iterator itr = mSkillStatus.find(id); - if (i < PLAYER_MAX_SKILLS) //has skill + //has skill + if(itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED) { if (currVal) { - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal)); + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos),MAKE_SKILL_VALUE(currVal,maxVal)); + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; learnSkillRewardedSpells(id, currVal); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,id); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL,id); @@ -5639,9 +5656,15 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) else //remove { // clear skill fields - SetUInt32Value(PLAYER_SKILL_INDEX(i),0); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),0); - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); + SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos),0); + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos),0); + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos),0); + + // mark as deleted or simply remove from map if not saved yet + if(itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_DELETED; + else + mSkillStatus.erase(itr); // remove all spells that related to this skill for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) @@ -5652,56 +5675,62 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) } else if (currVal) //add { - for (i = 0; i < PLAYER_MAX_SKILLS; ++i) + for (int i=0; i < PLAYER_MAX_SKILLS; ++i) if (!GetUInt32Value(PLAYER_SKILL_INDEX(i))) + { + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); + if (!pSkill) { - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); - if (!pSkill) - { - sLog.outError("Skill not found in SkillLineStore: skill #%u", id); - return; - } - // enable unlearn button for primary professions only - if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); - else - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal)); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,id); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL,id); - - // apply skill bonuses - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); - - // temporary bonuses - AuraEffectList const& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL); - for (AuraEffectList::const_iterator j = mModSkill.begin(); j != mModSkill.end(); ++j) - if ((*j)->GetMiscValue() == int32(id)) - (*j)->ApplyModifier(true); - - // permanent bonuses - AuraEffectList const& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT); - for (AuraEffectList::const_iterator j = mModSkillTalent.begin(); j != mModSkillTalent.end(); ++j) - if ((*j)->GetMiscValue() == int32(id)) - (*j)->ApplyModifier(true); - - // Learn all spells for skill - learnSkillRewardedSpells(id, currVal); + sLog.outError("Skill not found in SkillLineStore: skill #%u", id); return; } + // enable unlearn button for primary professions only + if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); + else + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal)); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,id); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL,id); + + // insert new entry or update if not deleted old entry yet + if(itr != mSkillStatus.end()) + { + itr->second.pos = i; + itr->second.uState = SKILL_CHANGED; + } + else + mSkillStatus.insert(SkillStatusMap::value_type(id, SkillStatusData(i, SKILL_NEW))); + + // apply skill bonuses + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); + + // temporary bonuses + AuraEffectList const& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL); + for (AuraEffectList::const_iterator j = mModSkill.begin(); j != mModSkill.end(); ++j) + if ((*j)->GetMiscValue() == int32(id)) + (*j)->ApplyModifier(true); + + // permanent bonuses + AuraEffectList const& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT); + for (AuraEffectList::const_iterator j = mModSkillTalent.begin(); j != mModSkillTalent.end(); ++j) + if ((*j)->GetMiscValue() == int32(id)) + (*j)->ApplyModifier(true); + + // Learn all spells for skill + learnSkillRewardedSpells(id, currVal); + return; } + } } bool Player::HasSkill(uint32 skill) const { - if (!skill) + if(!skill) return false; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - return true; - - return false; + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + return (itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED); } uint16 Player::GetSkillValue(uint32 skill) const @@ -5709,19 +5738,16 @@ uint16 Player::GetSkillValue(uint32 skill) const if (!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; - int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); - result += SKILL_TEMP_BONUS(bonus); - result += SKILL_PERM_BONUS(bonus); - return result < 0 ? 0 : result; - } - } - return 0; + uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)); + + int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); + result += SKILL_TEMP_BONUS(bonus); + result += SKILL_PERM_BONUS(bonus); + return result < 0 ? 0 : result; } uint16 Player::GetMaxSkillValue(uint32 skill) const @@ -5729,60 +5755,54 @@ uint16 Player::GetMaxSkillValue(uint32 skill) const if (!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; - int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); - result += SKILL_TEMP_BONUS(bonus); - result += SKILL_PERM_BONUS(bonus); - return result < 0 ? 0 : result; - } - } - return 0; + uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)); + + int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); + result += SKILL_TEMP_BONUS(bonus); + result += SKILL_PERM_BONUS(bonus); + return result < 0 ? 0 : result; } uint16 Player::GetPureMaxSkillValue(uint32 skill) const { - if (!skill) + if(!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; - return 0; + return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))); } uint16 Player::GetBaseSkillValue(uint32 skill) const { - if (!skill) + if(!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - { - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - { - int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)))); - result += SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); - return result < 0 ? 0 : result; - } - } - return 0; + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; + + int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); + result += SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos))); + return result < 0 ? 0 : result; } uint16 Player::GetPureSkillValue(uint32 skill) const { - if (!skill) + if(!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; - return 0; + return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))); } int16 Player::GetSkillPermBonusValue(uint32 skill) const @@ -5790,11 +5810,11 @@ int16 Player::GetSkillPermBonusValue(uint32 skill) const if (!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - return SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; - return 0; + return SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos))); } int16 Player::GetSkillTempBonusValue(uint32 skill) const @@ -5802,11 +5822,11 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const if (!skill) return 0; - for (uint16 i = 0; i < PLAYER_MAX_SKILLS; ++i) - if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill) - return SKILL_TEMP_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i))); + SkillStatusMap::const_iterator itr = mSkillStatus.find(skill); + if(itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) + return 0; - return 0; +return SKILL_TEMP_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos))); } void Player::SendActionButtons(uint32 state) const @@ -15145,7 +15165,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetUInt32Value(PLAYER_TRACK_CREATURES, 0 ); SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 ); - _LoadSkills(); + _LoadSkills(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSKILLS)); // make sure the unit is considered out of combat for proper loading ClearInCombat(); @@ -16445,6 +16465,7 @@ void Player::SaveToDB() _SaveSpellCooldowns(); _SaveActions(); _SaveAuras(); + _SaveSkills(); m_achievementMgr.SaveToDB(); m_reputationMgr.SaveToDB(); _SaveEquipmentSets(); @@ -16693,6 +16714,45 @@ void Player::_SaveDailyQuestStatus() GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx),uint64(m_lastDailyQuestTime)); } +void Player::_SaveSkills() +{ + // we don't need transactions here. + for( SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ) + { + if(itr->second.uState == SKILL_UNCHANGED) + { + ++itr; + continue; + } + + if(itr->second.uState == SKILL_DELETED) + { + CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u' AND skill = '%u' ", GetGUIDLow(), itr->first ); + mSkillStatus.erase(itr++); + continue; + } + + uint32 valueData = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)); + uint16 value = SKILL_VALUE(valueData); + uint16 max = SKILL_MAX(valueData); + + switch (itr->second.uState) + { + case SKILL_NEW: + CharacterDatabase.PExecute("INSERT INTO character_skills (guid, skill, value, max) VALUES ('%u', '%u', '%u', '%u')", + GetGUIDLow(), itr->first, value, max); + break; + case SKILL_CHANGED: + CharacterDatabase.PExecute("UPDATE character_skills SET value = '%u',max = '%u'WHERE guid = '%u' AND skill = '%u' ", + value, max, GetGUIDLow(), itr->first ); + break; + }; + itr->second.uState = SKILL_UNCHANGED; + + ++itr; + } +} + void Player::_SaveSpells() { for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();) @@ -21003,43 +21063,77 @@ void Player::learnSpellHighRank(uint32 spellid) learnSpellHighRank(next); } -void Player::_LoadSkills() +void Player::_LoadSkills(QueryResult *result) { - // Note: skill data itself loaded from `data` field. This is only cleanup part of load + // 0 1 2 + // SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid)); - // reset skill modifiers and set correct unlearn flags - for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++) + uint32 count = 0; + if (result) { - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); + do + { + Field *fields = result->Fetch(); - // set correct unlearn bit - uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - if(!id) continue; + uint16 skill = fields[0].GetUInt16(); + uint16 value = fields[1].GetUInt16(); + uint16 max = fields[2].GetUInt16(); - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); - if(!pSkill) continue; + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(skill); + if(!pSkill) + { + sLog.outError("Character %u has skill %u that does not exist.", GetGUIDLow(), skill); + continue; + } - // enable unlearn button for primary professions only - if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); - else - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); + // set fixed skill ranges + switch(GetSkillRangeType(pSkill,false)) + { + case SKILL_RANGE_LANGUAGE: // 300..300 + value = max = 300; + break; + case SKILL_RANGE_MONO: // 1..1, grey monolite bar + value = max = 1; + break; + default: + break; + } + if(value == 0) + { + sLog.outError("Character %u has skill %u with value 0. Will be deleted.", GetGUIDLow(), skill); + CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u' AND skill = '%u' ", GetGUIDLow(), skill ); + continue; + } - // set fixed skill ranges - switch(GetSkillRangeType(pSkill,false)) - { - case SKILL_RANGE_LANGUAGE: // 300..300 - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(300,300)); - break; - case SKILL_RANGE_MONO: // 1..1, grey monolite bar - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(1,1)); - break; - default: + // enable unlearn button for primary professions only + if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) + SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill,1)); + else + SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill,0)); + + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count),MAKE_SKILL_VALUE(value, max)); + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count),0); + + mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(count, SKILL_UNCHANGED))); + + learnSkillRewardedSpells(skill, value); + + ++count; + + if(count >= PLAYER_MAX_SKILLS) // client limit + { + sLog.outError("Character %u has more than %u skills.", PLAYER_MAX_SKILLS); break; - } + } + } while (result->NextRow()); + delete result; + } - uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); - learnSkillRewardedSpells(id, vskill); + for (; count < PLAYER_MAX_SKILLS; ++count) + { + SetUInt32Value(PLAYER_SKILL_INDEX(count), 0); + SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count),0); + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count),0); } // special settings diff --git a/src/game/Player.h b/src/game/Player.h index 56e3cb97b6c..162e2e29b00 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -573,6 +573,25 @@ enum QuestSlotStateMask QUEST_STATE_FAIL = 0x0002 }; +enum SkillUpdateState +{ + SKILL_UNCHANGED = 0, + SKILL_CHANGED = 1, + SKILL_NEW = 2, + SKILL_DELETED = 3 +}; + +struct SkillStatusData +{ + SkillStatusData(uint8 _pos, SkillUpdateState _uState) : pos(_pos), uState(_uState) + { + } + uint8 pos; + SkillUpdateState uState; +}; + +typedef UNORDERED_MAP<uint32, SkillStatusData> SkillStatusMap; + class Quest; class Spell; class Item; @@ -799,7 +818,8 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOADGLYPHS = 22, PLAYER_LOGIN_QUERY_LOADTALENTS = 23, PLAYER_LOGIN_QUERY_LOADACCOUNTDATA = 24, - MAX_PLAYER_LOGIN_QUERY = 25 + PLAYER_LOGIN_QUERY_LOADSKILLS = 25, + MAX_PLAYER_LOGIN_QUERY = 26 }; enum PlayerDelayedOperations @@ -2271,7 +2291,7 @@ Spell * m_spellModTakingSpell; void _LoadQuestStatus(QueryResult *result); void _LoadDailyQuestStatus(QueryResult *result); void _LoadGroup(QueryResult *result); - void _LoadSkills(); + void _LoadSkills(QueryResult *result); void _LoadSpells(QueryResult *result); void _LoadFriendList(QueryResult *result); bool _LoadHomeBind(QueryResult *result); @@ -2292,6 +2312,7 @@ Spell * m_spellModTakingSpell; void _SaveMail(); void _SaveQuestStatus(); void _SaveDailyQuestStatus(); + void _SaveSkills(); void _SaveSpells(); void _SaveEquipmentSets(); void _SaveBGData(); @@ -2340,6 +2361,8 @@ Spell * m_spellModTakingSpell; QuestStatusMap mQuestStatus; + SkillStatusMap mSkillStatus; + uint32 m_GuildIdInvited; uint32 m_ArenaTeamIdInvited; diff --git a/src/game/PlayerDump.cpp b/src/game/PlayerDump.cpp index 4a34b7f5102..75833364396 100644 --- a/src/game/PlayerDump.cpp +++ b/src/game/PlayerDump.cpp @@ -26,7 +26,7 @@ #include "ObjectMgr.h" // Character Dump tables -#define DUMP_TABLE_COUNT 26 +#define DUMP_TABLE_COUNT 27 struct DumpTable { @@ -47,6 +47,7 @@ static DumpTable dumpTables[DUMP_TABLE_COUNT] = { "character_action", DTT_CHAR_TABLE }, { "character_aura", DTT_CHAR_TABLE }, { "character_homebind", DTT_CHAR_TABLE }, + { "character_skills", DTT_CHAR_TABLE }, { "character_account_data", DTT_CHAR_TABLE }, { "character_glyphs", DTT_CHAR_TABLE }, { "character_talent", DTT_CHAR_TABLE }, |