diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/DataStores/DBCStores.cpp | 158 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCStores.h | 11 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCStructure.h | 13 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCfmt.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 219 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 15 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 90 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 39 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_learn.cpp | 2 |
14 files changed, 355 insertions, 207 deletions
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index a4ba710f5db..2f5f3f9159d 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -21,6 +21,7 @@ #include "Containers.h" #include "Log.h" #include "SharedDefines.h" +#include "SpellInfo.h" #include "SpellMgr.h" #include "TransportMgr.h" #include "DBCfmt.h" @@ -192,8 +193,13 @@ DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore(Specialization DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt); DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt); DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt); +DBCStorage <SpellEffectScalingEntry> sSpellEffectScalingStore(SpellEffectScalingfmt); + SpellCategoryStore sSpellsByCategoryStore; PetFamilySpellsStore sPetFamilySpellsStore; +SpellsPerClassStore sSpellsPerClassStore; +ClassBySkillIdStore sClassBySkillIdStore; +SpellEffectScallingByEffectId sSpellEffectScallingByEffectId; DBCStorage <SpellScalingEntry> sSpellScalingStore(SpellScalingEntryfmt); @@ -217,6 +223,8 @@ DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt); DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt); DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt); TalentBySpellIDMap sTalentBySpellIDMap; +SpecializationSpellsMap sSpecializationSpellsMap; +SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap; DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt); DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt); @@ -544,6 +552,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCastTimesStore, dbcPath, "SpellCastTimes.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellDurationStore, dbcPath, "SpellDuration.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellFocusObjectStore, dbcPath, "SpellFocusObject.dbc");//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellEffectScalingStore, dbcPath, "SpellEffectScaling.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentStore, dbcPath, "SpellItemEnchantment.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentConditionStore, dbcPath, "SpellItemEnchantmentCondition.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRadiusStore, dbcPath, "SpellRadius.dbc");//19116 @@ -553,41 +562,67 @@ void LoadDBCStores(const std::string& dataPath) //LoadDBC(availableDbcLocales, bad_dbc_files, sStableSlotPricesStore, dbcPath, "StableSlotPrices.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//15595 - // Must be done when sSkillLineAbilityStore, sSpellStore, sSpellLevelsStore and sCreatureFamilyStore are all loaded - /* TODO: Requires spells attributes from SpellMisc.db2 is loaded after dbc + for (uint32 j = 0; j < sSpellEffectScalingStore.GetNumRows(); j++) + { + SpellEffectScalingEntry const* spellEffectScaling = sSpellEffectScalingStore.LookupEntry(j); + if (!spellEffectScaling) + continue; + + sSpellEffectScallingByEffectId.insert(std::make_pair(spellEffectScaling->SpellEffectID, j)); + } + std::map<std::string, uint32> classIdByName; + for (uint32 j = 0; j < sChrClassesStore.GetNumRows(); j++) + { + ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(j); + if (!classEntry) + continue; + + classIdByName.insert(std::make_pair(std::string(classEntry->Name_lang), j)); + } + + for (uint32 j = 0; j < sSkillLineStore.GetNumRows(); j++) + { + SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(j); + if (!skillEntry) + continue; + + if (skillEntry->CategoryID!= SKILL_CATEGORY_CLASS) + continue; + + std::map<std::string, uint32> ::const_iterator iter = classIdByName.find(std::string(skillEntry->DisplayName_lang)); + if (iter == classIdByName.end()) + continue; + + sClassBySkillIdStore.insert(std::make_pair(j, iter->second)); + } + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) { - SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j); - if (!skillLine) + SkillLineAbilityEntry const* skillAbility = sSkillLineAbilityStore.LookupEntry(j); + if (!skillAbility) continue; - SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->SpellID); + if (skillAbility->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillAbility->SpellID); if (!spellInfo) continue; - SpellLevelsEntry const* levels = sSpellLevelsStore.LookupEntry(spellInfo->SpellLevelsID); - if (spellInfo->SpellLevelsID && (!levels || levels->spellLevel)) + SpellLevelsEntry const* spellLevels = sSpellLevelsStore.LookupEntry(spellInfo->LevelsID); + if (!spellLevels || !spellLevels->SpellLevel) continue; - if (spellInfo && spellInfo->Attributes & SPELL_ATTR0_PASSIVE) - { - for (uint32 i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i) - { - CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i); - if (!cFamily) - continue; + uint32 classId = GetClassBySkillId(skillAbility->SkillLine); - if (skillLine->SkillLine != cFamily->SkillLine[0] && skillLine->SkillLine != cFamily->SkillLine[1]) - continue; + if (!classId) + continue; - if (skillLine->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) - continue; + if (sSpellsPerClassStore.find(classId) == sSpellsPerClassStore.end()) + sSpellsPerClassStore.insert(make_pair(classId, std::list<SkillLineAbilityEntry const*>())); - sPetFamilySpellsStore[i].insert(spellInfo->ID); - } - } + sSpellsPerClassStore[classId].push_back(skillAbility); } - */ LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595 @@ -1183,3 +1218,82 @@ std::set<uint32> const& GetPhasesForGroup(uint32 group) { return sPhasesByGroup[group]; } + +uint32 GetClassBySkillId(uint32 skillId) +{ + ClassBySkillIdStore::const_iterator iter = sClassBySkillIdStore.find(skillId); + if (iter != sClassBySkillIdStore.end()) + return iter->second; + return 0; +} + +uint32 GetSkillIdByClass(uint32 classId) +{ + for (ClassBySkillIdStore::const_iterator iter = sClassBySkillIdStore.begin(); iter != sClassBySkillIdStore.end(); iter++) + if (iter->second == classId) + return iter->first; + return 0; +} + +std::list<uint32> GetSpellsForLevels(uint32 classId, uint32 raceMask, uint32 specializationId, uint32 minLevel, uint32 maxLevel) +{ + std::list<uint32> spellList; + + if (classId != 0) + { + SpellsPerClassStore::const_iterator classIter = sSpellsPerClassStore.find(classId); + if (classIter != sSpellsPerClassStore.end()) + { + const std::list<SkillLineAbilityEntry const*>& learnSpellList = classIter->second; + for (std::list<SkillLineAbilityEntry const*>::const_iterator iter = learnSpellList.begin(); iter != learnSpellList.end(); iter++) + { + SkillLineAbilityEntry const* skillLine = *iter; + if (!skillLine) + continue; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->SpellID); + if (!spellInfo) + continue; + + if (skillLine->RaceMask && !(skillLine->RaceMask & raceMask)) + continue; + + if (spellInfo->SpellLevel <= minLevel || spellInfo->SpellLevel > maxLevel) + continue; + + spellList.push_back(spellInfo->Id); + } + } + } + + if (!specializationId) + return spellList; + + SpecializationSpellsMap::const_iterator specIter = sSpecializationSpellsMap.find(specializationId); + if (specIter != sSpecializationSpellsMap.end()) + { + const std::vector<uint32>& learnSpellList = specIter->second; + for (int i = 0; i < learnSpellList.size(); i++) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learnSpellList[i]); + if (!spellInfo) + { + TC_LOG_ERROR("spells", "GetSpellsForLevels: spell %u not found in spellstore", learnSpellList[i]); + continue; + } + if (spellInfo->SpellLevel <= minLevel || spellInfo->SpellLevel > maxLevel) + continue; + + spellList.push_back(spellInfo->Id); + } + } + return spellList; +} + +uint32 GetTalentSpellCost(uint32 spellId) +{ + TalentBySpellIDMap::const_iterator itr = sTalentBySpellIDMap.find(spellId); + if (itr == sTalentBySpellIDMap.end()) + return 0; + return 1; +}
\ No newline at end of file diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index e9a9b3c692f..a631a471eb4 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -26,11 +26,14 @@ #include <list> +typedef std::map<uint32, uint32> SpecializationOverrideSpellsList; +typedef std::map<uint32, SpecializationOverrideSpellsList> SpecializationOverrideSpellsMap; + typedef std::list<uint32> SimpleFactionsList; SimpleFactionsList const* GetFactionTeamList(uint32 faction); char const* GetPetName(uint32 petfamily, uint32 dbclang); - +uint32 GetTalentSpellCost(uint32 spellId); TalentEntry const* GetTalentBySpellID(uint32 spellID); int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found @@ -66,6 +69,9 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT void Zone2MapCoordinates(float &x, float &y, uint32 zone); void Map2ZoneCoordinates(float &x, float &y, uint32 zone); +uint32 GetClassBySkillId(uint32 skillId); +uint32 GetSkillIdByClass(uint32 classId); +std::list<uint32> GetSpellsForLevels(uint32 classId, uint32 raceMask, uint32 specializationId, uint32 minLevel, uint32 maxLevel); typedef std::map<uint32/*pair32(map, diff)*/, MapDifficulty> MapDifficultyMap; MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); @@ -94,6 +100,9 @@ typedef std::unordered_map<uint32, SpecializationSpellsBySpecEntry> Specializati typedef ChrSpecializationEntry const* ChrSpecializationByIndexArray[MAX_CLASSES][MAX_SPECIALIZATIONS]; typedef std::unordered_map<uint32, TalentEntry const*> TalentBySpellIDMap; +typedef std::map<uint32, std::vector<uint32> > SpecializationSpellsMap; +extern SpecializationSpellsMap sSpecializationSpellsMap; +extern SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap; extern DBCStorage <AchievementEntry> sAchievementStore; extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 77182b1bdf9..4a58428abb1 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1803,6 +1803,16 @@ struct SpellEffectEntry #define MAX_SPELL_EFFECTS 32 #define MAX_EFFECT_MASK 0xFFFFFFFF +// SpellEffectScaling.dbc +struct SpellEffectScalingEntry +{ + uint32 ID; // 0 + float Coefficient; // 1 + float Variance; // 2 + float ResourceCoefficient; // 3 + uint32 SpellEffectID; // 4 +}; + // SpellAuraOptions.dbc struct SpellAuraOptionsEntry { @@ -1865,6 +1875,9 @@ typedef std::set<uint32> SpellCategorySet; typedef std::map<uint32, SpellCategorySet > SpellCategoryStore; typedef std::set<uint32> PetFamilySpellsSet; typedef std::map<uint32, PetFamilySpellsSet > PetFamilySpellsStore; +typedef std::unordered_map<uint32, std::list<SkillLineAbilityEntry const*> > SpellsPerClassStore; +typedef std::unordered_map<uint32, uint32> ClassBySkillIdStore; +typedef std::unordered_map<uint32, uint32> SpellEffectScallingByEffectId; struct SpellCastTimesEntry { diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 9f53cb09ad8..bd0283aee7f 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -135,6 +135,7 @@ const std::string CustomSpellEffectEntryIndex = "Id"; char const SpellEntryfmt[] = "nsxxxiiiiiiiiiiiiiiiiiii"; const std::string CustomSpellEntryfmt = "ppppppppppppppapaaaaaaaaapaaaaaapapppaapppaaapa"; const std::string CustomSpellEntryIndex = "Id"; +char const SpellEffectScalingfmt[] = "nfffi"; char const SpellFocusObjectfmt[] = "nx"; char const SpellItemEnchantmentfmt[] = "niiiiiiiiiixiiiiiiiiiiifff"; char const SpellItemEnchantmentConditionfmt[] = "nbbbbbiiiiibbbbbbbbbbiiiiibbbbb"; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c9a782cc78b..be86bf2b13d 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1121,7 +1121,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac } // original spells - LearnDefaultSkills(); + LearnDefaultSpells(); LearnCustomSpells(); // original action bar @@ -3528,9 +3528,11 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent return false; } + uint32 talentCost = GetTalentSpellCost(spellId); + // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned) // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive - if (!loading && spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_LEARN_SPELL)) + if (!loading && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) { // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show) CastSpell(this, spellId, true); @@ -3541,12 +3543,15 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent if (IsNeedCastPassiveSpellAtLearn(spellInfo)) CastSpell(this, spellId, true); } - else if (spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_SKILL_STEP)) + else if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP)) { CastSpell(this, spellId, true); return false; } + // update used talent points count + SetUsedTalentCount(GetUsedTalentCount() + talentCost); + // update free primary prof.points (if any, can be none in case GM .learn prof. learning) if (uint32 freeProfs = GetFreePrimaryProfessionPoints()) { @@ -3554,38 +3559,58 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent SetFreePrimaryProfessions(freeProfs-1); } + // add dependent skills + uint16 maxskill = GetMaxSkillValueForLevel(); + + SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId); + SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); - // add dependent skills if this spell is not learned from adding skill already - if (!fromSkill) + if (spellLearnSkill) { - if (SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId)) - { - uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill); - uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill); + uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill); + uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill); - if (skill_value < spellLearnSkill->value) - skill_value = spellLearnSkill->value; + if (skill_value < spellLearnSkill->value) + skill_value = spellLearnSkill->value; - uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : spellLearnSkill->maxvalue; + uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue; - if (skill_max_value < new_skill_max_value) - skill_max_value = new_skill_max_value; + if (skill_max_value < new_skill_max_value) + skill_max_value = new_skill_max_value; - SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value); - } - else + SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value); + } + else + { + // not ranked skills + for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx) { - // not ranked skills - for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx) - { - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine); - if (!pSkill) - continue; + SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine); + if (!pSkill) + continue; + + if (HasSkill(pSkill->ID)) + continue; - ///@todo: confirm if rogues start with lockpicking skill at level 1 but only receive the spell to use it at level 16 - if ((_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->ID)) || (pSkill->ID == SKILL_LOCKPICKING && _spell_idx->second->TrivialSkillLineRankHigh == 0)) - LearnDefaultSkill(pSkill->ID, 0); + if (_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN || + // lockpicking/runeforging special case, not have SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN + ((pSkill->ID == SKILL_LOCKPICKING || pSkill->ID == SKILL_RUNEFORGING) && (_spell_idx->second->TrivialSkillLineRankHigh == 0 || _spell_idx->second->TrivialSkillLineRankHigh == 1))) + { + switch (GetSkillRangeType(pSkill, _spell_idx->second->RaceMask!= 0)) + { + case SKILL_RANGE_LANGUAGE: + SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 300, 300); + break; + case SKILL_RANGE_LEVEL: + SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 1, GetMaxSkillValueForLevel()); + break; + case SKILL_RANGE_MONO: + SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 1, 1); + break; + default: + break; + } } } } @@ -5868,14 +5893,14 @@ void Player::UpdateSkillsForLevel() continue; uint32 pskill = itr->first; - SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pskill, getRace(), getClass()); - if (!rcEntry) + SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(pskill); + if (!pSkill) continue; - if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL) + if (GetSkillRangeType(pSkill, false) != SKILL_RANGE_LEVEL) continue; - if (IsWeaponSkill(rcEntry->SkillID)) + if (IsWeaponSkill(pSkill->ID)) continue; uint16 field = itr->second.pos / 2; @@ -17424,7 +17449,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // after spell and quest load InitTalentForLevel(); - LearnDefaultSkills(); + LearnDefaultSpells(); LearnCustomSpells(); // must be before inventory (some items required reputation check) @@ -23220,7 +23245,7 @@ void Player::ResetSpells(bool myClassOnly) for (PlayerSpellMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter) RemoveSpell(iter->first, false, false); // only iter->first can be accessed, object by iter->second can be deleted already - LearnDefaultSkills(); + LearnDefaultSpells(); LearnCustomSpells(); LearnQuestRewardedSpells(); } @@ -23243,69 +23268,18 @@ void Player::LearnCustomSpells() } } -void Player::LearnDefaultSkills() +void Player::LearnDefaultSpells() { - // learn default race/class skills + // learn default race/class spells PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); - for (PlayerCreateInfoSkills::const_iterator itr = info->skills.begin(); itr != info->skills.end(); ++itr) + for (PlayerCreateInfoSpells::const_iterator itr = info->spells.begin(); itr != info->spells.end(); ++itr) { - uint32 skillId = itr->SkillId; - if (HasSkill(skillId)) - continue; - - LearnDefaultSkill(skillId, itr->Rank); - } -} - -void Player::LearnDefaultSkill(uint32 skillId, uint16 rank) -{ - SkillRaceClassInfoEntry const* rcInfo = GetSkillRaceClassInfo(skillId, getRace(), getClass()); - if (!rcInfo) - return; - - TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial skill, id = %u", uint32(getClass()), uint32(getRace()), skillId); - switch (GetSkillRangeType(rcInfo)) - { - case SKILL_RANGE_LANGUAGE: - SetSkill(skillId, 0, 300, 300); - break; - case SKILL_RANGE_LEVEL: - { - uint16 skillValue = 1; - uint16 maxValue = GetMaxSkillValueForLevel(); - if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE) - skillValue = maxValue; - else if (getClass() == CLASS_DEATH_KNIGHT) - skillValue = std::min(std::max<uint16>({ 1, uint16((getLevel() - 1) * 5) }), maxValue); - else if (skillId == SKILL_FIST_WEAPONS) - skillValue = std::max<uint16>(1, GetSkillValue(SKILL_UNARMED)); - else if (skillId == SKILL_LOCKPICKING) - skillValue = std::max<uint16>(1, GetSkillValue(SKILL_LOCKPICKING)); - - SetSkill(skillId, 0, skillValue, maxValue); - break; - } - case SKILL_RANGE_MONO: - SetSkill(skillId, 0, 1, 1); - break; - case SKILL_RANGE_RANK: - { - if (!rank) - break; - - SkillTiersEntry const* tier = sSkillTiersStore.LookupEntry(rcInfo->SkillTierID); - uint16 maxValue = tier->Value[std::max<int32>(rank - 1, 0)]; - uint16 skillValue = 1; - if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE) - skillValue = maxValue; - else if (getClass() == CLASS_DEATH_KNIGHT) - skillValue = std::min(std::max<uint16>({ uint16(1), uint16((getLevel() - 1) * 5) }), maxValue); - - SetSkill(skillId, rank, skillValue, maxValue); - break; - } - default: - break; + uint32 tspell = *itr; + TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getRace()), tspell); + if (!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add + AddSpell(tspell, true, true, true, false); + else // but send in normal spell in game learn case + LearnSpell(tspell, true); } } @@ -23423,36 +23397,31 @@ void Player::LearnQuestRewardedSpells() void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) { - uint32 raceMask = getRaceMask(); + uint32 raceMask = getRaceMask(); uint32 classMask = getClassMask(); for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) { - SkillLineAbilityEntry const* ability = sSkillLineAbilityStore.LookupEntry(j); - if (!ability || ability->SkillLine != skillId) - continue; - - if (!sSpellMgr->GetSpellInfo(ability->SpellID)) + SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j); + if (!pAbility || pAbility->SkillLine != skillId || pAbility->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) continue; - - if (ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) - continue; - // Check race if set - if (ability->RaceMask && !(ability->RaceMask & raceMask)) + if (pAbility->RaceMask && !(pAbility->RaceMask & raceMask)) continue; - // Check class if set - if (ability->ClassMask && !(ability->ClassMask & classMask)) + if (pAbility->ClassMask && !(pAbility->ClassMask & classMask)) continue; - // need unlearn spell - if (skillValue < ability->MinSkillLineRank && ability->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) - RemoveSpell(ability->SpellID); - // need learn - else if (!IsInWorld()) - AddSpell(ability->SpellID, true, true, true, false, false, true); - else - LearnSpell(ability->SpellID, true, true); + if (sSpellMgr->GetSpellInfo(pAbility->SpellID)) + { + // need unlearn spell + if (skillValue < pAbility->MinSkillLineRank) + RemoveSpell(pAbility->SpellID); + // need learn + else if (!IsInWorld()) + AddSpell(pAbility->SpellID, true, true, true, false); + else + LearnSpell(pAbility->SpellID, true); + } } } @@ -25167,8 +25136,8 @@ void Player::_LoadSkills(PreparedQueryResult result) uint16 value = fields[1].GetUInt16(); uint16 max = fields[2].GetUInt16(); - SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass()); - if (!rcEntry) + SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skill); + if (!skillLine) { TC_LOG_ERROR("entities.player", "Character: %s (%s Race: %u Class: %u) has skill %u not allowed for his race/class combination", GetName().c_str(), GetGUID().ToString().c_str(), uint32(getRace()), uint32(getClass()), skill); @@ -25178,7 +25147,7 @@ void Player::_LoadSkills(PreparedQueryResult result) } // set fixed skill ranges - switch (GetSkillRangeType(rcEntry)) + switch (GetSkillRangeType(skillLine, false)) { case SKILL_RANGE_LANGUAGE: // 300..300 value = max = 300; @@ -25212,19 +25181,15 @@ void Player::_LoadSkills(PreparedQueryResult result) SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_ID_OFFSET + field, offset, skill); uint16 step = 0; - SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(rcEntry->SkillID); - if (skillLine) - { - if (skillLine->CategoryID == SKILL_CATEGORY_SECONDARY) - step = max / 75; + if (skillLine->CategoryID == SKILL_CATEGORY_SECONDARY) + step = max / 75; - if (skillLine->CategoryID == SKILL_CATEGORY_PROFESSION) - { - step = max / 75; + if (skillLine->CategoryID == SKILL_CATEGORY_PROFESSION) + { + step = max / 75; - if (professionCount < 2) - SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + professionCount++, skill); - } + if (professionCount < 2) + SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + professionCount++, skill); } SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_STEP_OFFSET + field, offset, step); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1dcd75a156e..2d919159819 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -329,7 +329,7 @@ enum ReputationSource }; #define ACTION_BUTTON_ACTION(X) (uint64(X) & 0x00000000FFFFFFFF) -#define ACTION_BUTTON_TYPE(X) ((uint64(X) & 0xFFFFFFFF00000000) >> 32) +#define ACTION_BUTTON_TYPE(X) ((uint64(X) & 0xFFFFFFFF00000000) >> 56) #define MAX_ACTION_BUTTON_ACTION_VALUE (0xFFFFFFFF) struct ActionButton @@ -344,7 +344,7 @@ struct ActionButton uint32 GetAction() const { return ACTION_BUTTON_ACTION(packedData); } void SetActionAndType(uint32 action, ActionButtonType type) { - uint64 newData = uint64(action) | (uint64(type) << 32); + uint64 newData = uint64(action) | (uint64(type) << 56); if (newData != packedData || uState == ACTIONBUTTON_DELETED) { packedData = newData; @@ -412,9 +412,9 @@ struct PlayerInfo uint16 displayId_f; PlayerCreateInfoItems item; PlayerCreateInfoSpells customSpells; + PlayerCreateInfoSpells spells; PlayerCreateInfoSpells castSpells; PlayerCreateInfoActions action; - PlayerCreateInfoSkills skills; PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 }; @@ -1270,6 +1270,9 @@ struct PlayerTalentInfo uint8 ActiveGroup; uint8 GroupsCount; + + uint32 UsedTalentCount; + private: PlayerTalentInfo(PlayerTalentInfo const&); }; @@ -1821,8 +1824,7 @@ class Player : public Unit, public GridObject<Player> void RemoveSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true); void ResetSpells(bool myClassOnly = false); void LearnCustomSpells(); - void LearnDefaultSkills(); - void LearnDefaultSkill(uint32 skillId, uint16 rank); + void LearnDefaultSpells(); void LearnQuestRewardedSpells(); void LearnQuestRewardedSpells(Quest const* quest); void LearnSpellHighestRank(uint32 spellid); @@ -1833,6 +1835,9 @@ class Player : public Unit, public GridObject<Player> std::string GetGuildName(); // Talents + uint32 GetUsedTalentCount() const { return _talentMgr->UsedTalentCount; } + void SetUsedTalentCount(uint32 talents) { _talentMgr->UsedTalentCount = talents; } + uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; } void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; } uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index a01251af433..040c9600852 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3270,17 +3270,16 @@ void ObjectMgr::LoadPlayerInfo() } } - - // Load playercreate skills - TC_LOG_INFO("server.loading", "Loading Player Create Skill Data..."); + // Load playercreate spells + TC_LOG_INFO("server.loading", "Loading Player Create Spell Data..."); { uint32 oldMSTime = getMSTime(); - QueryResult result = WorldDatabase.PQuery("SELECT raceMask, classMask, skill, rank FROM playercreateinfo_skills"); + QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM playercreateinfo_spell"); if (!result) { - TC_LOG_ERROR("server.loading", ">> Loaded 0 player create skills. DB table `playercreateinfo_skills` is empty."); + TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `playercreateinfo_spell` is empty."); } else { @@ -3291,31 +3290,17 @@ void ObjectMgr::LoadPlayerInfo() Field* fields = result->Fetch(); uint32 raceMask = fields[0].GetUInt32(); uint32 classMask = fields[1].GetUInt32(); - PlayerCreateInfoSkill skill; - skill.SkillId = fields[2].GetUInt16(); - skill.Rank = fields[3].GetUInt16(); - - if (skill.Rank >= MAX_SKILL_STEP) - { - TC_LOG_ERROR("sql.sql", "Skill rank value %hu set for skill %hu raceMask %u classMask %u is too high, max allowed value is %d", skill.Rank, skill.SkillId, raceMask, classMask, MAX_SKILL_STEP); - continue; - } + uint32 spellId = fields[2].GetUInt32(); if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_skills` table, ignoring.", raceMask); + TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell` table, ignoring.", raceMask); continue; } if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_skills` table, ignoring.", classMask); - continue; - } - - if (!sSkillLineStore.LookupEntry(skill.SkillId)) - { - TC_LOG_ERROR("sql.sql", "Wrong skill id %u in `playercreateinfo_skills` table, ignoring.", skill.SkillId); + TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell` table, ignoring.", classMask); continue; } @@ -3327,26 +3312,28 @@ void ObjectMgr::LoadPlayerInfo() { if (classMask == 0 || ((1 << (classIndex - 1)) & classMask)) { - if (!GetSkillRaceClassInfo(skill.SkillId, raceIndex, classIndex)) - continue; - if (PlayerInfo* info = _playerInfo[raceIndex][classIndex]) { - info->skills.push_back(skill); + info->spells.push_back(spellId); ++count; } + // We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them. + // Either split the masks per class, or per race, which kind of kills the point yet. + // else if (raceMask != 0 && classMask != 0) + // TC_LOG_ERROR("sql.sql", "Racemask/classmask (%u/%u) combination was found containing an invalid race/class combination (%u/%u) in `%s` (Spell %u), ignoring.", raceMask, classMask, raceIndex, classIndex, tableName.c_str(), spellId); } } } } - } while (result->NextRow()); + } + while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u player create skills in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } } - // Load playercreate spells - TC_LOG_INFO("server.loading", "Loading Player Create Spell Data..."); + // Load playercreate custom spells + TC_LOG_INFO("server.loading", "Loading Player Create Custom Spell Data..."); { uint32 oldMSTime = getMSTime(); @@ -3354,7 +3341,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `playercreateinfo_spell_custom` is empty."); + TC_LOG_ERROR("server.loading", ">> Loaded 0 player create custom spells. DB table `playercreateinfo_spell_custom` is empty."); } else { @@ -7850,27 +7837,34 @@ int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 rac return 0; } -SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry) +SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial) { - SkillLineEntry const* skill = sSkillLineStore.LookupEntry(rcEntry->SkillID); - if (!skill) - return SKILL_RANGE_NONE; - - if (sSkillTiersStore.LookupEntry(rcEntry->SkillTierID)) - return SKILL_RANGE_RANK; - - if (rcEntry->SkillID == SKILL_RUNEFORGING) - return SKILL_RANGE_MONO; - - switch (skill->CategoryID) + switch (pSkill->CategoryID) { - case SKILL_CATEGORY_ARMOR: - return SKILL_RANGE_MONO; case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE; + case SKILL_CATEGORY_WEAPON: + return SKILL_RANGE_LEVEL; + case SKILL_CATEGORY_ARMOR: + case SKILL_CATEGORY_CLASS: + if (pSkill->ID != SKILL_LOCKPICKING) + return SKILL_RANGE_MONO; + else + return SKILL_RANGE_LEVEL; + case SKILL_CATEGORY_SECONDARY: + case SKILL_CATEGORY_PROFESSION: + // not set skills for professions and racial abilities + if (IsProfessionSkill(pSkill->ID)) + return SKILL_RANGE_RANK; + else if (racial) + return SKILL_RANGE_NONE; + else + return SKILL_RANGE_MONO; + default: + case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc + case SKILL_CATEGORY_GENERIC: //only GENERIC(DND) + return SKILL_RANGE_NONE; } - - return SKILL_RANGE_LEVEL; } void ObjectMgr::LoadGameTele() @@ -9367,4 +9361,4 @@ std::string ObjectMgr::GetRealmName(uint32 realm) const { RealmNameContainer::const_iterator iter = _realmNameStore.find(realm); return iter != _realmNameStore.end() ? iter->second : ""; -} +}
\ No newline at end of file diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e7191735ca1..bf0d889057b 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -668,7 +668,7 @@ enum SkillRangeType SKILL_RANGE_NONE // 0..0 always }; -SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry); +SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial); #define MAX_PLAYER_NAME 12 // max allowed by client name length #define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length (> MAX_PLAYER_NAME for support declined names) diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 1acddcc5523..015ce3224a3 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -274,8 +274,6 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint32 tryEffMa if (!effMask) return NULL; - TC_LOG_ERROR("spells", "TryRefreshStackOrCreate spell %u tryEffMask %u effMask %u", spellproto->Id, tryEffMask, effMask); - if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID)) { // we've here aura, which script triggered removal after modding stack amount diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 85ad4a67d3f..8eefeae232a 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1253,6 +1253,9 @@ bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell, uin SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); for (SpellEffectInfo const* effect : effects) { + if (!effect) + continue; + if (effect->TargetA.GetTarget() != TARGET_UNIT_CASTER && effect->TargetA.GetTarget() != TARGET_DEST_CASTER && effect->TargetB.GetTarget() != TARGET_UNIT_CASTER && effect->TargetB.GetTarget() != TARGET_DEST_CASTER) { @@ -1297,6 +1300,9 @@ bool SpellInfo::IsStackableWithRanks() const SpellEffectInfoVector effects = GetEffectsForDifficulty(DIFFICULTY_NONE); for (SpellEffectInfo const* effect : effects) { + if (!effect) + continue; + switch (SpellFamilyName) { case SPELLFAMILY_PALADIN: diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 3211ff389e8..22c68271aba 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3739,3 +3739,42 @@ void SpellMgr::LoadSpellInfoCorrections() TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in %u ms", GetMSTimeDiffToNow(oldMSTime)); } + +void SpellMgr::LoadPetFamilySpellsStore() +{ + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + { + SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j); + if (!skillLine) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->SpellID); + if (!spellInfo) + continue; + + SpellLevelsEntry const* levels = sSpellLevelsStore.LookupEntry(spellInfo->LevelsID); + if (spellInfo->LevelsID && (!levels || levels->SpellLevel)) + continue; + + if (SpellMiscEntry const* spellMisc = sSpellMiscStore.LookupEntry(spellInfo->MiscID)) + { + if (spellMisc->Attributes & SPELL_ATTR0_PASSIVE) + { + for (uint32 i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i) + { + CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i); + if (!cFamily) + continue; + + if (skillLine->SkillLine != cFamily->SkillLine[0] && skillLine->SkillLine != cFamily->SkillLine[1]) + continue; + + if (skillLine->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + continue; + + sPetFamilySpellsStore[i].insert(spellInfo->ID); + } + } + } + } +} diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 5be0cfda84c..0e591a27e81 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -699,6 +699,8 @@ class SpellMgr } uint32 GetSpellInfoStoreSize() const { return mSpellInfoMap.size(); } + void LoadPetFamilySpellsStore(); + private: SpellInfo* _GetSpellInfo(uint32 spellId) { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : NULL; } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index a9d12fd11f8..c24bd53bd57 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1413,6 +1413,8 @@ void World::SetInitialWorldSettings() LoadDBCStores(m_dataPath); LoadDB2Stores(m_dataPath); + sSpellMgr->LoadPetFamilySpellsStore(); + TC_LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 2cf97403595..9d2d4426efe 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -306,7 +306,7 @@ public: if (!handler->extractPlayerTarget((char*)args, &target)) return false; - target->LearnDefaultSkills(); + target->LearnDefaultSpells(); target->LearnCustomSpells(); target->LearnQuestRewardedSpells(); |