mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 22:26:22 +00:00
fix(Core/Player): Use SkillLineAbility.dbc to determine player initia… (#6015)
* fix(Core/Player): Use SkillLineAbility.dbc to determine player initial spells - skill assignment done in a new table `playercreateinfo_skills` * Cherry-pick2a3546ca36* Cherry-Pickd28b66bca8* Cherry-Pick193408f335- Closes https://github.com/azerothcore/azerothcore-wotlk/issues/1659 - Closes https://github.com/azerothcore/azerothcore-wotlk/issues/6036 - Closes https://github.com/chromiecraft/chromiecraft/issues/693 Co-Authored-By: Shauren shauren.trinity@gmail.com Co-Authored-By: Rothend 67004168+Rothend@users.noreply.github.com Co-Authored-By: claudiodfc claudio.daniel.f.c@gmail.com
This commit is contained in:
106
data/sql/updates/pending_db_world/rev_1621752432246342200.sql
Normal file
106
data/sql/updates/pending_db_world/rev_1621752432246342200.sql
Normal file
@@ -0,0 +1,106 @@
|
||||
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1621752432246342200');
|
||||
|
||||
DROP TABLE IF EXISTS `skillraceclassinfo_dbc`;
|
||||
CREATE TABLE `skillraceclassinfo_dbc` (
|
||||
`ID` INT NOT NULL DEFAULT 0,
|
||||
`SkillID` INT NOT NULL DEFAULT 0,
|
||||
`RaceMask` INT NOT NULL DEFAULT 0,
|
||||
`ClassMask` INT NOT NULL DEFAULT 0,
|
||||
`Flags` INT NOT NULL DEFAULT 0,
|
||||
`MinLevel` INT NOT NULL DEFAULT 0,
|
||||
`SkillTierID` INT NOT NULL DEFAULT 0,
|
||||
`SkillCostIndex` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=UTF8MB4;
|
||||
|
||||
DROP TABLE IF EXISTS `playercreateinfo_spell`;
|
||||
|
||||
DROP TABLE IF EXISTS `playercreateinfo_skills`;
|
||||
CREATE TABLE `playercreateinfo_skills` (
|
||||
`raceMask` INT UNSIGNED NOT NULL,
|
||||
`classMask` INT UNSIGNED NOT NULL,
|
||||
`skill` SMALLINT UNSIGNED NOT NULL,
|
||||
`rank` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`comment` VARCHAR(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`raceMask`,`classMask`,`skill`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
|
||||
|
||||
DELETE FROM `playercreateinfo_skills`;
|
||||
INSERT INTO `playercreateinfo_skills` (`raceMask`, `classMask`, `skill`, `rank`, `comment`) VALUES
|
||||
(0, 0, 95, 0, 'Defense'),
|
||||
(0, 0, 162, 0, 'Unarmed'),
|
||||
(0, 0, 183, 0, 'GENERIC (DND)'),
|
||||
(0, 0, 415, 0, 'Cloth'),
|
||||
(0, 0, 777, 0, 'Mounts'),
|
||||
(0, 0, 778, 0, 'Companion Pets'),
|
||||
(0, 1, 26, 0, 'Warrior - Arms'),
|
||||
(0, 1, 256, 0, 'Warrior - Fury'),
|
||||
(0, 1, 257, 0, 'Warrior - Protection'),
|
||||
(0, 2, 184, 0, 'Paladin - Retribution'),
|
||||
(0, 2, 267, 0, 'Paladin - Protection'),
|
||||
(0, 2, 594, 0, 'Paladin - Holy'),
|
||||
(0, 4, 50, 0, 'Hunter - Beast Mastery'),
|
||||
(0, 4, 51, 0, 'Hunter - Survival'),
|
||||
(0, 4, 163, 0, 'Hunter - Marksmanship'),
|
||||
(0, 8, 38, 0, 'Rogue - Combat'),
|
||||
(0, 8, 39, 0, 'Rogue - Subtlety'),
|
||||
(0, 8, 176, 0, 'Thrown'),
|
||||
(0, 8, 253, 0, 'Rogue - Assassination'),
|
||||
(0, 16, 56, 0, 'Priest - Holy'),
|
||||
(0, 16, 78, 0, 'Priest - Shadow'),
|
||||
(0, 16, 613, 0, 'Priest - Discipline'),
|
||||
(0, 32, 129, 4, 'Death Knight - First Aid'),
|
||||
(0, 32, 229, 0, 'Polearms'),
|
||||
(0, 32, 293, 0, 'Plate'),
|
||||
(0, 32, 762, 0, 'Death Knight - Riding'),
|
||||
(0, 32, 770, 0, 'Death Knight - Blood'),
|
||||
(0, 32, 771, 0, 'Death Knight - Frost'),
|
||||
(0, 32, 772, 0, 'Death Knight - Unholy'),
|
||||
(0, 35, 55, 0, 'Two-Handed Swords'),
|
||||
(0, 35, 413, 0, 'Mail'),
|
||||
(0, 37, 44, 0, 'Axes'),
|
||||
(0, 37, 172, 0, 'Two-Handed Axes'),
|
||||
(0, 39, 43, 0, 'Swords'),
|
||||
(0, 40, 118, 0, 'Dual Wield'),
|
||||
(0, 64, 373, 0, 'Shaman - Enhancement'),
|
||||
(0, 64, 374, 0, 'Shaman - Restoration'),
|
||||
(0, 64, 375, 0, 'Shaman - Elemental'),
|
||||
(0, 67, 433, 0, 'Shield'),
|
||||
(0, 128, 6, 0, 'Mage - Frost'),
|
||||
(0, 128, 8, 0, 'Mage - Fire'),
|
||||
(0, 128, 237, 0, 'Mage - Arcane'),
|
||||
(0, 256, 354, 0, 'Warlock - Demonology'),
|
||||
(0, 256, 355, 0, 'Warlock - Affliction'),
|
||||
(0, 256, 593, 0, 'Warlock - Destruction'),
|
||||
(0, 400, 228, 0, 'Wands'),
|
||||
(0, 1024, 134, 0, 'Druid - Feral'),
|
||||
(0, 1024, 573, 0, 'Druid - Restoration'),
|
||||
(0, 1024, 574, 0, 'Druid - Balance'),
|
||||
(0, 1107, 54, 0, 'Maces'),
|
||||
(0, 1135, 414, 0, 'Leather'),
|
||||
(0, 1488, 136, 0, 'Staves'),
|
||||
(1, 0, 754, 0, 'Human - Racial'),
|
||||
(2, 0, 125, 0, 'Orc - Racial'),
|
||||
(4, 0, 101, 0, 'Dwarf - Racial'),
|
||||
(4, 0, 111, 0, 'Language: Dwarven'),
|
||||
(8, 0, 113, 0, 'Language: Darnassian'),
|
||||
(8, 0, 126, 0, 'Night Elf - Racial'),
|
||||
(16, 0, 220, 0, 'Undead - Racial'),
|
||||
(16, 0, 673, 0, 'Language: Forsaken'),
|
||||
(32, 0, 115, 0, 'Language: Taurahe'),
|
||||
(32, 0, 124, 0, 'Tauren - Racial'),
|
||||
(36, 4, 46, 0, 'Guns'),
|
||||
(64, 0, 313, 0, 'Language: Gnomish'),
|
||||
(64, 0, 753, 0, 'Gnome - Racial'),
|
||||
(128, 0, 315, 0, 'Language: Troll'),
|
||||
(128, 0, 733, 0, 'Troll - Racial'),
|
||||
(512, 0, 137, 0, 'Language: Thalassian'),
|
||||
(512, 0, 756, 0, 'Blood Elf - Racial'),
|
||||
(650, 4, 45, 0, 'Bows'),
|
||||
(690, 0, 109, 0, 'Language: Orcish'),
|
||||
(735, 1293, 173, 0, 'Daggers'),
|
||||
(1024, 0, 759, 0, 'Language: Draenei'),
|
||||
(1024, 0, 760, 0, 'Draenei - Racial'),
|
||||
(1024, 4, 226, 0, 'Crossbows'),
|
||||
(1061, 3, 160, 0, 'Two-Handed Maces'),
|
||||
(1101, 0, 98, 0, 'Language: Common');
|
||||
@@ -1478,7 +1478,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first);
|
||||
for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
|
||||
{
|
||||
if (skillIter->second->skillId == achievementCriteria->learn_skillline_spell.skillLine)
|
||||
if (skillIter->second->SkillLine == achievementCriteria->learn_skillline_spell.skillLine)
|
||||
{
|
||||
// xinef: do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
|
||||
++spellCount;
|
||||
@@ -1540,7 +1540,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first);
|
||||
for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
|
||||
{
|
||||
if (skillIter->second->skillId == achievementCriteria->learn_skill_line.skillLine)
|
||||
if (skillIter->second->SkillLine == achievementCriteria->learn_skill_line.skillLine)
|
||||
{
|
||||
// xinef: do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
|
||||
++spellCount;
|
||||
|
||||
@@ -291,10 +291,10 @@ bool SpellChatLink::ValidateName(char* buffer, const char* context)
|
||||
LOG_DEBUG("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line ability not found for spell %u", context, _spell->Id);
|
||||
return false;
|
||||
}
|
||||
SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId);
|
||||
SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillInfo->SkillLine);
|
||||
if (!skillLine)
|
||||
{
|
||||
LOG_DEBUG("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line not found for skill %u", context, skillInfo->skillId);
|
||||
LOG_DEBUG("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line not found for skill %u", context, skillInfo->SkillLine);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,9 @@ DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt
|
||||
|
||||
DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
|
||||
DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
|
||||
DBCStorage <SkillRaceClassInfoEntry> sSkillRaceClassInfoStore(SkillRaceClassInfofmt);
|
||||
SkillRaceClassInfoMap SkillRaceClassInfoBySkill;
|
||||
DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt);
|
||||
|
||||
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
|
||||
|
||||
@@ -324,6 +327,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LOAD_DBC(sScalingStatValuesStore, "ScalingStatValues.dbc", "scalingstatvalues_dbc");
|
||||
LOAD_DBC(sSkillLineStore, "SkillLine.dbc", "skillline_dbc");
|
||||
LOAD_DBC(sSkillLineAbilityStore, "SkillLineAbility.dbc", "skilllineability_dbc");
|
||||
LOAD_DBC(sSkillRaceClassInfoStore, "SkillRaceClassInfo.dbc", "skillraceclassinfo_dbc");
|
||||
LOAD_DBC(sSoundEntriesStore, "SoundEntries.dbc", "soundentries_dbc");
|
||||
LOAD_DBC(sSpellStore, "Spell.dbc", "spell_dbc");
|
||||
LOAD_DBC(sSpellCastTimesStore, "SpellCastTimes.dbc", "spellcasttimes_dbc");
|
||||
@@ -392,21 +396,35 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
if (i->Category)
|
||||
sSpellsByCategoryStore[i->Category].insert(i->Id);
|
||||
|
||||
for (SkillRaceClassInfoEntry const* entry : sSkillRaceClassInfoStore)
|
||||
{
|
||||
if (sSkillLineStore.LookupEntry(entry->SkillID))
|
||||
{
|
||||
SkillRaceClassInfoBySkill.emplace(entry->SkillID, entry);
|
||||
}
|
||||
}
|
||||
|
||||
for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore)
|
||||
{
|
||||
SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
|
||||
SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->Spell);
|
||||
if (spellInfo && spellInfo->Attributes & SPELL_ATTR0_PASSIVE)
|
||||
{
|
||||
for (CreatureFamilyEntry const* cFamily : sCreatureFamilyStore)
|
||||
{
|
||||
if (skillLine->skillId != cFamily->skillLine[0] && skillLine->skillId != cFamily->skillLine[1])
|
||||
if (skillLine->SkillLine != cFamily->skillLine[0] && skillLine->SkillLine != cFamily->skillLine[1])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spellInfo->SpellLevel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL)
|
||||
if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sPetFamilySpellsStore[cFamily->ID].insert(spellInfo->Id);
|
||||
}
|
||||
@@ -1081,3 +1099,24 @@ uint32 GetDefaultMapLight(uint32 mapId)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_)
|
||||
{
|
||||
SkillRaceClassInfoBounds bounds = SkillRaceClassInfoBySkill.equal_range(skill);
|
||||
for (SkillRaceClassInfoMap::iterator itr = bounds.first; itr != bounds.second; ++itr)
|
||||
{
|
||||
if (itr->second->RaceMask && !(itr->second->RaceMask & (1 << (race - 1))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (itr->second->ClassMask && !(itr->second->ClassMask & (1 << (class_ - 1))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, ui
|
||||
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty);
|
||||
uint32 GetDefaultMapLight(uint32 mapId);
|
||||
|
||||
typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoMap;
|
||||
typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
|
||||
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
|
||||
|
||||
extern DBCStorage <AchievementEntry> sAchievementStore;
|
||||
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
|
||||
extern DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore;
|
||||
@@ -129,6 +133,7 @@ extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore;
|
||||
extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore;
|
||||
extern DBCStorage <SkillLineEntry> sSkillLineStore;
|
||||
extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
|
||||
extern DBCStorage <SkillTiersEntry> sSkillTiersStore;
|
||||
extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
|
||||
extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
|
||||
extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ChannelMgr.h"
|
||||
#include "CharacterDatabaseCleaner.h"
|
||||
#include "Chat.h"
|
||||
#include "Config.h"
|
||||
#include "Common.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "CreatureAI.h"
|
||||
@@ -1186,7 +1187,8 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
||||
}
|
||||
|
||||
// original spells
|
||||
learnDefaultSpells();
|
||||
LearnDefaultSkills();
|
||||
LearnCustomSpells();
|
||||
|
||||
// original action bar
|
||||
for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
|
||||
@@ -4077,12 +4079,6 @@ bool Player::_addSpell(uint32 spellId, uint8 addSpecMask, bool temporary, bool l
|
||||
SetFreePrimaryProfessions(freeProfs - 1);
|
||||
}
|
||||
|
||||
// pussywizard: update 310 flyer speed
|
||||
if (!Has310Flyer(false))
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310)
|
||||
SetHas310Flyer(true);
|
||||
|
||||
uint16 maxskill = GetMaxSkillValueForLevel();
|
||||
SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId);
|
||||
SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
|
||||
@@ -4102,29 +4098,28 @@ bool Player::_addSpell(uint32 spellId, uint8 addSpecMask, bool temporary, bool l
|
||||
}
|
||||
else
|
||||
{
|
||||
// pussywizard: checked, ok
|
||||
// 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->skillId);
|
||||
if (!pSkill || HasSkill(pSkill->id))
|
||||
continue;
|
||||
|
||||
if (_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || // pussywizard: learning autolearned spell from skill ensures having the skill
|
||||
((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0)) // pussywizard: learning any spell from lockpicking or runeforging ensures having the skill
|
||||
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
|
||||
if (!pSkill)
|
||||
{
|
||||
switch (GetSkillRangeType(pSkill, _spell_idx->second->racemask != 0))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_spell_idx->second->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id))
|
||||
{
|
||||
LearnDefaultSkill(pSkill->id, 0);
|
||||
}
|
||||
|
||||
if (pSkill->id == SKILL_MOUNTS && !Has310Flyer(false))
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
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;
|
||||
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310)
|
||||
{
|
||||
SetHas310Flyer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4135,8 +4130,8 @@ bool Player::_addSpell(uint32 spellId, uint8 addSpecMask, bool temporary, bool l
|
||||
{
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
|
||||
{
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE, _spell_idx->second->skillId);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->skillId);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE, _spell_idx->second->SkillLine);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->SkillLine);
|
||||
}
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spellId);
|
||||
}
|
||||
@@ -4194,9 +4189,9 @@ void Player::learnSpell(uint32 spellId)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporary)
|
||||
void Player::removeSpell(uint32 spell_id, uint8 removeSpecMask, bool onlyTemporary)
|
||||
{
|
||||
PlayerSpellMap::iterator itr = m_spells.find(spellId);
|
||||
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
|
||||
if (itr == m_spells.end())
|
||||
return;
|
||||
|
||||
@@ -4210,15 +4205,15 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
|
||||
|
||||
// pussywizard: remove non-talent higher ranks (recursive)
|
||||
// pussywizard: do this at the beginning, not in the middle of removing!
|
||||
if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spellId))
|
||||
if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
|
||||
if (!GetTalentSpellPos(nextSpell))
|
||||
removeSpell(nextSpell, removeSpecMask, onlyTemporary);
|
||||
|
||||
// xinef: if current spell has talentcost, remove spells requiring this spell
|
||||
uint32 firstRankSpellId = sSpellMgr->GetFirstSpellInChain(spellId);
|
||||
uint32 firstRankSpellId = sSpellMgr->GetFirstSpellInChain(spell_id);
|
||||
if (GetTalentSpellCost(firstRankSpellId))
|
||||
{
|
||||
SpellsRequiringSpellMapBounds spellsRequiringSpell = sSpellMgr->GetSpellsRequiringSpellBounds(spellId);
|
||||
SpellsRequiringSpellMapBounds spellsRequiringSpell = sSpellMgr->GetSpellsRequiringSpellBounds(firstRankSpellId);
|
||||
for (auto spellsItr = spellsRequiringSpell.first; spellsItr != spellsRequiringSpell.second; ++spellsItr)
|
||||
{
|
||||
removeSpell(spellsItr->second, removeSpecMask, onlyTemporary);
|
||||
@@ -4226,7 +4221,7 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
|
||||
}
|
||||
|
||||
// pussywizard: re-search, it can be corrupted in prev loop
|
||||
itr = m_spells.find(spellId);
|
||||
itr = m_spells.find(spell_id);
|
||||
if (itr == m_spells.end())
|
||||
return;
|
||||
|
||||
@@ -4249,13 +4244,13 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
|
||||
// xinef: this is used for talents and they are not removed in removeSpell function...
|
||||
// xinef: however ill leave this here just in case
|
||||
// pussywizard: remove owned aura obtained from currently removed spell
|
||||
RemoveOwnedAura(spellId);
|
||||
RemoveOwnedAura(spell_id);
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
// pussywizard: remove pet auras
|
||||
if (PetAura const* petSpell = sSpellMgr->GetPetAura(spellId, i))
|
||||
if (PetAura const* petSpell = sSpellMgr->GetPetAura(spell_id, i))
|
||||
RemovePetAura(petSpell);
|
||||
|
||||
// pussywizard: remove all triggered auras
|
||||
@@ -4275,13 +4270,13 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
|
||||
if (Has310Flyer(false))
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310)
|
||||
Has310Flyer(true, spellId);
|
||||
Has310Flyer(true, spell_id);
|
||||
|
||||
// pussywizard: remove dependent skill
|
||||
SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId);
|
||||
SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spell_id);
|
||||
if (spellLearnSkill)
|
||||
{
|
||||
uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId);
|
||||
uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spell_id);
|
||||
|
||||
if (!prev_spell) // pussywizard: first rank, remove skill
|
||||
SetSkill(spellLearnSkill->skill, 0, 0, 0);
|
||||
@@ -4313,24 +4308,28 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
|
||||
}
|
||||
else
|
||||
{
|
||||
// pussywizard: checked, ok
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spell_id);
|
||||
// most likely will never be used, haven't heard of cases where players unlearn a mount
|
||||
if (Has310Flyer(false) && spellInfo)
|
||||
{
|
||||
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId);
|
||||
if (!pSkill)
|
||||
continue;
|
||||
|
||||
// pussywizard: don't understand why whole skill is removed when just single spell from it is removed
|
||||
if ((_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL && pSkill->categoryId != SKILL_CATEGORY_CLASS) || // pussywizard: don't unlearn class skills
|
||||
((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0))
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
{
|
||||
// not reset skills for professions and racial abilities
|
||||
if ((pSkill->categoryId == SKILL_CATEGORY_SECONDARY || pSkill->categoryId == SKILL_CATEGORY_PROFESSION) && (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask != 0))
|
||||
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
|
||||
if (!pSkill)
|
||||
continue;
|
||||
|
||||
// pussywizard: this is needed for weapon/armor/language skills to remove them when loosing spell
|
||||
SetSkill(pSkill->id, GetSkillStep(pSkill->id), 0, 0);
|
||||
if (_spell_idx->second->SkillLine == SKILL_MOUNTS)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &&
|
||||
spellInfo->Effects[i].CalcValue() == 310)
|
||||
{
|
||||
Has310Flyer(true, spell_id); // with true as first argument its also used to set/remove the flag
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4338,8 +4337,8 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
|
||||
// pussywizard: remove from spell book (can't be replaced by previous rank, because such spells can't be unlearnt)
|
||||
if (!onlyTemporary || ((!spellInfo->HasAttribute(SpellAttr0(SPELL_ATTR0_PASSIVE | SPELL_ATTR0_DO_NOT_DISPLAY)) || !spellInfo->HasAnyAura()) && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)))
|
||||
{
|
||||
sScriptMgr->OnPlayerForgotSpell(this, spellId);
|
||||
SendLearnPacket(spellId, false);
|
||||
sScriptMgr->OnPlayerForgotSpell(this, spell_id);
|
||||
SendLearnPacket(spell_id, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4363,7 +4362,7 @@ bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId)
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(itr->first);
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
{
|
||||
if (_spell_idx->second->skillId != SKILL_MOUNTS)
|
||||
if (_spell_idx->second->SkillLine != SKILL_MOUNTS)
|
||||
break; // We can break because mount spells belong only to one skillline (at least 310 flyers do)
|
||||
|
||||
spellInfo = sSpellMgr->AssertSpellInfo(itr->first);
|
||||
@@ -6304,9 +6303,6 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
|
||||
if (!skill_id)
|
||||
return false;
|
||||
|
||||
if (skill_id == SKILL_FIST_WEAPONS)
|
||||
skill_id = SKILL_UNARMED;
|
||||
|
||||
SkillStatusMap::iterator itr = mSkillStatus.find(skill_id);
|
||||
if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
|
||||
return false;
|
||||
@@ -6328,6 +6324,7 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
|
||||
SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(new_value, max));
|
||||
if (itr->second.uState != SKILL_NEW)
|
||||
itr->second.uState = SKILL_CHANGED;
|
||||
|
||||
UpdateSkillEnchantments(skill_id, value, new_value);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skill_id);
|
||||
return true;
|
||||
@@ -6355,25 +6352,25 @@ bool Player::UpdateCraftSkill(uint32 spellid)
|
||||
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
{
|
||||
if (_spell_idx->second->skillId)
|
||||
if (_spell_idx->second->SkillLine)
|
||||
{
|
||||
uint32 SkillValue = GetPureSkillValue(_spell_idx->second->skillId);
|
||||
uint32 SkillValue = GetPureSkillValue(_spell_idx->second->SkillLine);
|
||||
|
||||
// Alchemy Discoveries here
|
||||
SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spellid);
|
||||
if (spellEntry && spellEntry->Mechanic == MECHANIC_DISCOVERY)
|
||||
{
|
||||
if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
|
||||
if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->SkillLine, spellid, this))
|
||||
learnSpell(discoveredSpell);
|
||||
}
|
||||
|
||||
uint32 craft_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
|
||||
|
||||
return UpdateSkillPro(_spell_idx->second->skillId, SkillGainChance(SkillValue,
|
||||
_spell_idx->second->max_value,
|
||||
(_spell_idx->second->max_value + _spell_idx->second->min_value) / 2,
|
||||
_spell_idx->second->min_value),
|
||||
craft_skill_gain);
|
||||
return UpdateSkillPro(_spell_idx->second->SkillLine, SkillGainChance(SkillValue,
|
||||
_spell_idx->second->TrivialSkillLineRankHigh,
|
||||
(_spell_idx->second->TrivialSkillLineRankHigh + _spell_idx->second->TrivialSkillLineRankLow) / 2,
|
||||
_spell_idx->second->TrivialSkillLineRankLow),
|
||||
craft_skill_gain);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -6524,7 +6521,7 @@ void Player::UpdateWeaponSkill(Unit* victim, WeaponAttackType attType)
|
||||
UpdateSkill(SKILL_UNARMED, weapon_skill_gain);
|
||||
UpdateSkill(SKILL_FIST_WEAPONS, weapon_skill_gain);
|
||||
}
|
||||
else if (tmpitem)
|
||||
else if (tmpitem && tmpitem->GetTemplate()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE)
|
||||
{
|
||||
switch (tmpitem->GetTemplate()->SubClass)
|
||||
{
|
||||
@@ -6610,11 +6607,11 @@ void Player::UpdateSkillsForLevel()
|
||||
continue;
|
||||
|
||||
uint32 pskill = itr->first;
|
||||
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(pskill);
|
||||
if (!pSkill)
|
||||
SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pskill, getRace(), getClass());
|
||||
if (!rcEntry)
|
||||
continue;
|
||||
|
||||
if (GetSkillRangeType(pSkill, false) != SKILL_RANGE_LEVEL)
|
||||
if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL)
|
||||
continue;
|
||||
|
||||
uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos);
|
||||
@@ -6626,7 +6623,7 @@ void Player::UpdateSkillsForLevel()
|
||||
if (max != 1)
|
||||
{
|
||||
/// maximize skill always
|
||||
if (alwaysMaxSkill)
|
||||
if (alwaysMaxSkill || (rcEntry->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE))
|
||||
{
|
||||
SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(maxSkill, maxSkill));
|
||||
if (itr->second.uState != SKILL_NEW)
|
||||
@@ -6717,8 +6714,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
|
||||
// remove all spells that related to this skill
|
||||
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
|
||||
if (SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j))
|
||||
if (pAbility->skillId == id)
|
||||
removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->spellId), SPEC_MASK_ALL, false);
|
||||
if (pAbility->SkillLine == id)
|
||||
removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->Spell), SPEC_MASK_ALL, false);
|
||||
}
|
||||
}
|
||||
else if (newVal) //add
|
||||
@@ -18395,7 +18392,9 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, SQLQueryHolder* holder)
|
||||
m_specsCount = fields[64].GetUInt8();
|
||||
m_activeSpec = fields[65].GetUInt8();
|
||||
|
||||
learnDefaultSpells(); // pussywizard: move before loading spells and talents
|
||||
LearnDefaultSkills();
|
||||
LearnCustomSpells();
|
||||
|
||||
_LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS));
|
||||
_LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
|
||||
|
||||
@@ -23868,16 +23867,109 @@ void Player::resetSpells()
|
||||
for (PlayerSpellMap::const_iterator iter = spellMap.begin(); iter != spellMap.end(); ++iter)
|
||||
removeSpell(iter->first, SPEC_MASK_ALL, false);
|
||||
|
||||
learnDefaultSpells();
|
||||
LearnDefaultSkills();
|
||||
LearnCustomSpells();
|
||||
learnQuestRewardedSpells();
|
||||
}
|
||||
|
||||
void Player::learnDefaultSpells()
|
||||
void Player::LearnCustomSpells()
|
||||
{
|
||||
// xinef: learn default race/class spells
|
||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(true), getClass());
|
||||
for (PlayerCreateInfoSpells::const_iterator itr = info->spell.begin(); itr != info->spell.end(); ++itr)
|
||||
_addSpell(*itr, SPEC_MASK_ALL, true);
|
||||
if (!sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// learn default race/class spells
|
||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass());
|
||||
for (PlayerCreateInfoSpells::const_iterator itr = info->customSpells.begin(); itr != info->customSpells.end(); ++itr)
|
||||
{
|
||||
uint32 tspell = *itr;
|
||||
LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getRace()), tspell);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::LearnDefaultSkills()
|
||||
{
|
||||
// learn default race/class skills
|
||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass());
|
||||
for (PlayerCreateInfoSkills::const_iterator itr = info->skills.begin(); itr != info->skills.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;
|
||||
|
||||
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 (sWorld->getBoolConfig(CONFIG_ALWAYS_MAXSKILL) && !IsProfessionOrRidingSkill(skillId))
|
||||
{
|
||||
skillValue = maxValue;
|
||||
}
|
||||
else 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;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::learnQuestRewardedSpells(Quest const* quest)
|
||||
@@ -23932,40 +24024,47 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
|
||||
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
|
||||
{
|
||||
SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j);
|
||||
if (!pAbility || pAbility->skillId != skill_id || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
|
||||
continue;
|
||||
// Check race if set
|
||||
if (pAbility->racemask && !(pAbility->racemask & raceMask))
|
||||
continue;
|
||||
// Check class if set
|
||||
if (pAbility->classmask && !(pAbility->classmask & classMask))
|
||||
continue;
|
||||
|
||||
if (sSpellMgr->GetSpellInfo(pAbility->spellId))
|
||||
if (!pAbility || pAbility->SkillLine != skill_id)
|
||||
{
|
||||
// need unlearn spell
|
||||
if (skill_value < pAbility->req_skill_value)
|
||||
removeSpell(pAbility->spellId, SPEC_MASK_ALL, true);
|
||||
// need learn
|
||||
else
|
||||
{
|
||||
// Xinef: there is next spell and we have enough skill value to obtain it - skip current spell
|
||||
if (pAbility->req_skill_value > 1 && pAbility->forward_spellid)
|
||||
{
|
||||
bool hasForwardSpell = false;
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(pAbility->forward_spellid);
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
if (skill_value >= _spell_idx->second->req_skill_value)
|
||||
{
|
||||
hasForwardSpell = true;
|
||||
break;
|
||||
}
|
||||
if (hasForwardSpell)
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
addSpell(pAbility->spellId, SPEC_MASK_ALL, true, true, true);
|
||||
}
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pAbility->Spell);
|
||||
if (!spellInfo)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pAbility->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && pAbility->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check race if set
|
||||
if (pAbility->RaceMask && !(pAbility->RaceMask & raceMask))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check class if set
|
||||
if (pAbility->ClassMask && !(pAbility->ClassMask & classMask))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// need unlearn spell
|
||||
if (skill_value < pAbility->MinSkillLineRank && pAbility->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE)
|
||||
{
|
||||
removeSpell(pAbility->Spell, GetActiveSpec(), true);
|
||||
}
|
||||
// need learn
|
||||
else if (!IsInWorld())
|
||||
{
|
||||
addSpell(pAbility->Spell, true, true, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
learnSpell(pAbility->Spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24189,11 +24288,11 @@ bool Player::IsSpellFitByClassAndRace(uint32 spell_id) const
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
{
|
||||
// skip wrong race skills
|
||||
if (_spell_idx->second->racemask && (_spell_idx->second->racemask & racemask) == 0)
|
||||
if (_spell_idx->second->RaceMask && (_spell_idx->second->RaceMask & racemask) == 0)
|
||||
continue;
|
||||
|
||||
// skip wrong class skills
|
||||
if (_spell_idx->second->classmask && (_spell_idx->second->classmask & classmask) == 0)
|
||||
if (_spell_idx->second->ClassMask && (_spell_idx->second->ClassMask & classmask) == 0)
|
||||
continue;
|
||||
|
||||
return true;
|
||||
@@ -24658,7 +24757,7 @@ bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const
|
||||
return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE);
|
||||
}
|
||||
|
||||
uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
|
||||
uint32 Player::GetBaseWeaponSkillValue(WeaponAttackType attType) const
|
||||
{
|
||||
Item* item = GetWeaponForAttack(attType, true);
|
||||
|
||||
@@ -24666,8 +24765,8 @@ uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
|
||||
if (attType != BASE_ATTACK && !item)
|
||||
return 0;
|
||||
|
||||
// weapon skill or (unarmed for base attack and for fist weapons)
|
||||
uint32 skill = (item && item->GetSkill() != SKILL_FIST_WEAPONS) ? item->GetSkill() : uint32(SKILL_UNARMED);
|
||||
// weapon skill or (unarmed for base attack)
|
||||
uint32 skill = item ? item->GetSkill() : uint32(SKILL_UNARMED);
|
||||
return GetBaseSkillValue(skill);
|
||||
}
|
||||
|
||||
@@ -25830,15 +25929,15 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
uint16 value = fields[1].GetUInt16();
|
||||
uint16 max = fields[2].GetUInt16();
|
||||
|
||||
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
|
||||
if (!pSkill)
|
||||
SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass());
|
||||
if (!rcEntry)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character %s has skill %u that does not exist.", GetGUID().ToString().c_str(), skill);
|
||||
continue;
|
||||
}
|
||||
|
||||
// set fixed skill ranges
|
||||
switch (GetSkillRangeType(pSkill, false))
|
||||
switch (GetSkillRangeType(rcEntry))
|
||||
{
|
||||
case SKILL_RANGE_LANGUAGE: // 300..300
|
||||
value = max = 300;
|
||||
@@ -25846,9 +25945,12 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
case SKILL_RANGE_MONO: // 1..1, grey monolite bar
|
||||
value = max = 1;
|
||||
break;
|
||||
case SKILL_RANGE_LEVEL:
|
||||
max = GetMaxSkillValueForLevel();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character %s has skill %u with value 0. Will be deleted.", GetGUID().ToString().c_str(), skill);
|
||||
@@ -25863,11 +25965,20 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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));
|
||||
uint16 skillStep = 0;
|
||||
if (SkillTiersEntry const* skillTier = sSkillTiersStore.LookupEntry(rcEntry->SkillTierID))
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_SKILL_STEP; ++i)
|
||||
{
|
||||
if (skillTier->Value[skillStep] == max)
|
||||
{
|
||||
skillStep = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill, skillStep));
|
||||
|
||||
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count), MAKE_SKILL_VALUE(value, max));
|
||||
SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0);
|
||||
@@ -25892,34 +26003,6 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count), 0);
|
||||
SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0);
|
||||
}
|
||||
|
||||
// special settings
|
||||
if (getClass() == CLASS_DEATH_KNIGHT)
|
||||
{
|
||||
uint8 base_level = std::min(getLevel(), uint8(sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)));
|
||||
if (base_level < 1)
|
||||
base_level = 1;
|
||||
uint16 base_skill = (base_level - 1) * 5; // 270 at starting level 55
|
||||
if (base_skill < 1)
|
||||
base_skill = 1; // skill mast be known and then > 0 in any case
|
||||
|
||||
if (GetPureSkillValue(SKILL_FIRST_AID) < base_skill)
|
||||
SetSkill(SKILL_FIRST_AID, 4 /*artisan*/, base_skill, 300);
|
||||
if (GetPureSkillValue(SKILL_AXES) < base_skill)
|
||||
SetSkill(SKILL_AXES, 0, base_skill, base_skill);
|
||||
if (GetPureSkillValue(SKILL_DEFENSE) < base_skill)
|
||||
SetSkill(SKILL_DEFENSE, 0, base_skill, base_skill);
|
||||
if (GetPureSkillValue(SKILL_POLEARMS) < base_skill)
|
||||
SetSkill(SKILL_POLEARMS, 0, base_skill, base_skill);
|
||||
if (GetPureSkillValue(SKILL_SWORDS) < base_skill)
|
||||
SetSkill(SKILL_SWORDS, 0, base_skill, base_skill);
|
||||
if (GetPureSkillValue(SKILL_2H_AXES) < base_skill)
|
||||
SetSkill(SKILL_2H_AXES, 0, base_skill, base_skill);
|
||||
if (GetPureSkillValue(SKILL_2H_SWORDS) < base_skill)
|
||||
SetSkill(SKILL_2H_SWORDS, 0, base_skill, base_skill);
|
||||
if (GetPureSkillValue(SKILL_UNARMED) < base_skill)
|
||||
SetSkill(SKILL_UNARMED, 0, base_skill, base_skill);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Player::GetPhaseMaskForSpawn() const
|
||||
|
||||
@@ -282,6 +282,14 @@ struct PlayerCreateInfoAction
|
||||
|
||||
typedef std::list<PlayerCreateInfoAction> PlayerCreateInfoActions;
|
||||
|
||||
struct PlayerCreateInfoSkill
|
||||
{
|
||||
uint16 SkillId;
|
||||
uint16 Rank;
|
||||
};
|
||||
|
||||
typedef std::list<PlayerCreateInfoSkill> PlayerCreateInfoSkills;
|
||||
|
||||
struct PlayerInfo
|
||||
{
|
||||
// existence checked by displayId != 0
|
||||
@@ -296,8 +304,9 @@ struct PlayerInfo
|
||||
uint16 displayId_m{0};
|
||||
uint16 displayId_f{0};
|
||||
PlayerCreateInfoItems item;
|
||||
PlayerCreateInfoSpells spell;
|
||||
PlayerCreateInfoSpells customSpells;
|
||||
PlayerCreateInfoActions action;
|
||||
PlayerCreateInfoSkills skills;
|
||||
|
||||
PlayerLevelInfo* levelInfo{nullptr}; //[level-1] 0..MaxPlayerLevel-1
|
||||
};
|
||||
@@ -1693,7 +1702,9 @@ public:
|
||||
void learnSpell(uint32 spellId);
|
||||
void removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporary);
|
||||
void resetSpells();
|
||||
void learnDefaultSpells();
|
||||
void LearnCustomSpells();
|
||||
void LearnDefaultSkills();
|
||||
void LearnDefaultSkill(uint32 skillId, uint16 rank);
|
||||
void learnQuestRewardedSpells();
|
||||
void learnQuestRewardedSpells(Quest const* quest);
|
||||
void learnSpellHighRank(uint32 spellid);
|
||||
|
||||
@@ -3220,12 +3220,10 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target)
|
||||
if (IsInFeralForm())
|
||||
return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
|
||||
|
||||
// weapon skill or (unarmed for base attack and fist weapons)
|
||||
uint32 skill;
|
||||
if (item && item->GetSkill() != SKILL_FIST_WEAPONS)
|
||||
// weapon skill or (unarmed for base attack)
|
||||
uint32 skill = SKILL_UNARMED;
|
||||
if (item)
|
||||
skill = item->GetSkill();
|
||||
else
|
||||
skill = SKILL_UNARMED;
|
||||
|
||||
// in PvP use full skill instead current skill value
|
||||
value = (target && target->IsControlledByPlayer())
|
||||
|
||||
@@ -3485,17 +3485,90 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
}
|
||||
}
|
||||
|
||||
// Load playercreate skills
|
||||
LOG_INFO("server.loading", "Loading Player Create Skill Data...");
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = WorldDatabase.PQuery("SELECT raceMask, classMask, skill, `rank` FROM playercreateinfo_skills");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("server.loading", ">> Loaded 0 player create skills. DB table `playercreateinfo_skills` is empty.");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_skills` table, ignoring.", raceMask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_skills` table, ignoring.", classMask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sSkillLineStore.LookupEntry(skill.SkillId))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong skill id %u in `playercreateinfo_skills` table, ignoring.", skill.SkillId);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex)
|
||||
{
|
||||
if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask))
|
||||
{
|
||||
for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex)
|
||||
{
|
||||
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);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded %u player create skills in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
}
|
||||
|
||||
// Load playercreate spells
|
||||
LOG_INFO("server.loading", "Loading Player Create Spell Data...");
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
std::string tableName = sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell";
|
||||
QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM %s", tableName.c_str());
|
||||
QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM playercreateinfo_spell_custom");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("sql.sql", ">> Loaded 0 player create spells. DB table `%s` is empty.", sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell");
|
||||
LOG_INFO("server.loading", ">> Loaded 0 player create spells. DB table `playercreateinfo_spell_custom` is empty.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3510,13 +3583,13 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
|
||||
if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell` table, ignoring.", raceMask);
|
||||
LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell_custom` table, ignoring.", raceMask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell` table, ignoring.", classMask);
|
||||
LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell_custom` table, ignoring.", classMask);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3530,7 +3603,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
{
|
||||
if (PlayerInfo* info = _playerInfo[raceIndex][classIndex])
|
||||
{
|
||||
info->spell.push_back(spellId);
|
||||
info->customSpells.push_back(spellId);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
@@ -3539,7 +3612,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded %u player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", ">> Loaded %u custom player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
}
|
||||
@@ -7943,37 +8016,33 @@ int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 rac
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial)
|
||||
SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry)
|
||||
{
|
||||
switch (pSkill->categoryId)
|
||||
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)
|
||||
{
|
||||
case SKILL_CATEGORY_ARMOR:
|
||||
return SKILL_RANGE_MONO;
|
||||
case SKILL_CATEGORY_LANGUAGES:
|
||||
return SKILL_RANGE_LANGUAGE;
|
||||
case SKILL_CATEGORY_WEAPON:
|
||||
if (pSkill->id != SKILL_FIST_WEAPONS)
|
||||
return SKILL_RANGE_LEVEL;
|
||||
else
|
||||
return SKILL_RANGE_MONO;
|
||||
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()
|
||||
|
||||
@@ -645,7 +645,7 @@ enum SkillRangeType
|
||||
SKILL_RANGE_NONE, // 0..0 always
|
||||
};
|
||||
|
||||
SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial);
|
||||
SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry);
|
||||
|
||||
#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)
|
||||
|
||||
@@ -111,7 +111,7 @@ void LoadSkillDiscoveryTable()
|
||||
}
|
||||
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
SkillDiscoveryStore[-int32(_spell_idx->second->skillId)].push_back(SkillDiscoveryEntry(spellId, reqSkillValue, chance));
|
||||
SkillDiscoveryStore[-int32(_spell_idx->second->SkillLine)].push_back(SkillDiscoveryEntry(spellId, reqSkillValue, chance));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -153,7 +153,7 @@ uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player)
|
||||
return 0;
|
||||
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
|
||||
uint32 skillvalue = bounds.first != bounds.second ? player->GetSkillValue(bounds.first->second->skillId) : uint32(0);
|
||||
uint32 skillvalue = bounds.first != bounds.second ? player->GetSkillValue(bounds.first->second->SkillLine) : uint32(0);
|
||||
|
||||
float full_chance = 0;
|
||||
for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
|
||||
|
||||
@@ -970,10 +970,10 @@ bool SpellInfo::IsAbilityLearnedWithProfession() const
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
{
|
||||
SkillLineAbilityEntry const* pAbility = _spell_idx->second;
|
||||
if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
|
||||
if (!pAbility || pAbility->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE)
|
||||
continue;
|
||||
|
||||
if (pAbility->req_skill_value > 0)
|
||||
if (pAbility->MinSkillLineRank > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -985,7 +985,7 @@ bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const
|
||||
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id);
|
||||
|
||||
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
|
||||
if (_spell_idx->second->skillId == uint32(skillType))
|
||||
if (_spell_idx->second->SkillLine == uint32(skillType))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -40,7 +40,7 @@ bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
|
||||
{
|
||||
SkillLineAbilityMapBounds skillBounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
|
||||
for (SkillLineAbilityMap::const_iterator itr = skillBounds.first; itr != skillBounds.second; ++itr)
|
||||
if (itr->second->skillId == skillId)
|
||||
if (itr->second->SkillLine == skillId)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -2031,7 +2031,7 @@ void SpellMgr::LoadSkillLineAbilityMap()
|
||||
if (!SkillInfo)
|
||||
continue;
|
||||
|
||||
mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->spellId, SkillInfo));
|
||||
mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->Spell, SkillInfo));
|
||||
++count;
|
||||
}
|
||||
|
||||
@@ -2270,13 +2270,13 @@ void SpellMgr::LoadPetLevelupSpellMap()
|
||||
// (!creatureFamily->skillLine[1] || skillLine->skillId != creatureFamily->skillLine[1]))
|
||||
// continue;
|
||||
|
||||
if (skillLine->skillId != creatureFamily->skillLine[j])
|
||||
if (skillLine->SkillLine != creatureFamily->skillLine[j])
|
||||
continue;
|
||||
|
||||
if (skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL)
|
||||
if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spell = GetSpellInfo(skillLine->spellId);
|
||||
SpellInfo const* spell = GetSpellInfo(skillLine->Spell);
|
||||
if (!spell) // not exist or triggered or talent
|
||||
continue;
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry->spellId);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry->Spell);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
@@ -290,7 +290,8 @@ public:
|
||||
if (!handler->extractPlayerTarget((char*)args, &target))
|
||||
return false;
|
||||
|
||||
target->learnDefaultSpells();
|
||||
target->LearnDefaultSkills();
|
||||
target->LearnCustomSpells();
|
||||
target->learnQuestRewardedSpells();
|
||||
|
||||
handler->PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST, handler->GetNameLink(target).c_str());
|
||||
@@ -404,26 +405,26 @@ public:
|
||||
continue;
|
||||
|
||||
// wrong skill
|
||||
if (skillLine->skillId != skillId)
|
||||
if (skillLine->SkillLine != skillId)
|
||||
continue;
|
||||
|
||||
// not high rank
|
||||
if (skillLine->forward_spellid)
|
||||
if (skillLine->SupercededBySpell)
|
||||
continue;
|
||||
|
||||
// skip racial skills
|
||||
if (skillLine->racemask != 0)
|
||||
if (skillLine->RaceMask != 0)
|
||||
continue;
|
||||
|
||||
// skip wrong class skills
|
||||
if (skillLine->classmask && (skillLine->classmask & classmask) == 0)
|
||||
if (skillLine->ClassMask && (skillLine->ClassMask & classmask) == 0)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->spellId);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->Spell);
|
||||
if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo))
|
||||
continue;
|
||||
|
||||
player->learnSpell(skillLine->spellId);
|
||||
player->learnSpell(skillLine->Spell);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -310,8 +310,8 @@ enum MapFlags
|
||||
|
||||
enum AbilytyLearnType
|
||||
{
|
||||
ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1,
|
||||
ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2
|
||||
SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE = 1, // Spell state will update depending on skill value
|
||||
SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN = 2 // Spell will be learned/removed together with entire skill
|
||||
};
|
||||
|
||||
enum ItemEnchantmentType
|
||||
@@ -333,6 +333,16 @@ enum ItemLimitCategoryMode
|
||||
ITEM_LIMIT_CATEGORY_MODE_EQUIP = 1, // limit applied to amount equipped items (including used gems)
|
||||
};
|
||||
|
||||
enum SkillRaceClassInfoFlags
|
||||
{
|
||||
SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2,
|
||||
SKILL_FLAG_ALWAYS_MAX_VALUE = 0x10,
|
||||
SKILL_FLAG_UNLEARNABLE = 0x20, // Skill can be unlearned
|
||||
SKILL_FLAG_INCLUDE_IN_SORT = 0x80, // Spells belonging to a skill with this flag will additionally compare skill ids when sorting spellbook in client
|
||||
SKILL_FLAG_NOT_TRAINABLE = 0x100,
|
||||
SKILL_FLAG_MONO_VALUE = 0x400 // Skill always has value 1 - clientside display flag, real value can be different
|
||||
};
|
||||
|
||||
enum SpellCategoryFlags
|
||||
{
|
||||
SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused
|
||||
|
||||
@@ -1467,22 +1467,19 @@ struct ScalingStatValuesEntry
|
||||
// uint32 displayOrder; // 19 m_sortIndex
|
||||
//};
|
||||
|
||||
//struct SkillRaceClassInfoEntry{
|
||||
// uint32 id; // 0 m_ID
|
||||
// uint32 skillId; // 1 m_skillID
|
||||
// uint32 raceMask; // 2 m_raceMask
|
||||
// uint32 classMask; // 3 m_classMask
|
||||
// uint32 flags; // 4 m_flags
|
||||
// uint32 reqLevel; // 5 m_minLevel
|
||||
// uint32 skillTierId; // 6 m_skillTierID
|
||||
// uint32 skillCostID; // 7 m_skillCostIndex
|
||||
//};
|
||||
struct SkillRaceClassInfoEntry
|
||||
{
|
||||
//uint32 ID; // 0
|
||||
uint32 SkillID; // 1
|
||||
uint32 RaceMask; // 2
|
||||
uint32 ClassMask; // 3
|
||||
uint32 Flags; // 4
|
||||
//uint32 MinLevel; // 5
|
||||
uint32 SkillTierID; // 6
|
||||
//uint32 SkillCostIndex; // 7
|
||||
};
|
||||
|
||||
//struct SkillTiersEntry{
|
||||
// uint32 id; // 0 m_ID
|
||||
// uint32 skillValue[16]; // 1-17 m_cost
|
||||
// uint32 maxSkillValue[16]; // 18-32 m_valueMax
|
||||
//};
|
||||
#define MAX_SKILL_STEP 16
|
||||
|
||||
struct SkillLineEntry
|
||||
{
|
||||
@@ -1501,19 +1498,26 @@ struct SkillLineEntry
|
||||
|
||||
struct SkillLineAbilityEntry
|
||||
{
|
||||
uint32 id; // 0 m_ID
|
||||
uint32 skillId; // 1 m_skillLine
|
||||
uint32 spellId; // 2 m_spell
|
||||
uint32 racemask; // 3 m_raceMask
|
||||
uint32 classmask; // 4 m_classMask
|
||||
//uint32 racemaskNot; // 5 m_excludeRace
|
||||
//uint32 classmaskNot; // 6 m_excludeClass
|
||||
uint32 req_skill_value; // 7 m_minSkillLineRank
|
||||
uint32 forward_spellid; // 8 m_supercededBySpell
|
||||
uint32 learnOnGetSkill; // 9 m_acquireMethod
|
||||
uint32 max_value; // 10 m_trivialSkillLineRankHigh
|
||||
uint32 min_value; // 11 m_trivialSkillLineRankLow
|
||||
//uint32 characterPoints[2]; // 12-13 m_characterPoints[2]
|
||||
uint32 ID; // 0
|
||||
uint32 SkillLine; // 1
|
||||
uint32 Spell; // 2
|
||||
uint32 RaceMask; // 3
|
||||
uint32 ClassMask; // 4
|
||||
//uint32 ExcludeRace; // 5
|
||||
//uint32 ExcludeClass; // 6
|
||||
uint32 MinSkillLineRank; // 7
|
||||
uint32 SupercededBySpell; // 8
|
||||
uint32 AcquireMethod; // 9
|
||||
uint32 TrivialSkillLineRankHigh; // 10
|
||||
uint32 TrivialSkillLineRankLow; // 11
|
||||
//uint32 CharacterPoints[2]; // 12-13
|
||||
};
|
||||
|
||||
struct SkillTiersEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
//uint32 Cost[MAX_SKILL_STEP]; // 1-16
|
||||
uint32 Value[MAX_SKILL_STEP]; // 17-32
|
||||
};
|
||||
|
||||
struct SoundEntriesEntry
|
||||
|
||||
@@ -82,6 +82,8 @@ char constexpr ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiii";
|
||||
char constexpr ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiii";
|
||||
char constexpr SkillLinefmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi";
|
||||
char constexpr SkillLineAbilityfmt[] = "niiiixxiiiiixx";
|
||||
char constexpr SkillRaceClassInfofmt[] = "diiiixix";
|
||||
char constexpr SkillTiersfmt[] = "nxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiii";
|
||||
char constexpr SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
char constexpr SpellCastTimefmt[] = "nixx";
|
||||
char constexpr SpellCategoryfmt[] = "ni";
|
||||
|
||||
Reference in New Issue
Block a user