aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKudlaty <none@none>2009-12-14 20:47:43 +0100
committerKudlaty <none@none>2009-12-14 20:47:43 +0100
commit379cbb72af7869950e04d59b9903ab0dd2618a68 (patch)
treeb2d2f724d74e2ed605f685b2c8317118d0fb8f9e /src
parent45d74f8e05b0442a08713c12287f6becda34f892 (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.cpp1
-rw-r--r--src/game/Player.cpp472
-rw-r--r--src/game/Player.h27
-rw-r--r--src/game/PlayerDump.cpp3
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 },