aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/game/Creature.h14
-rw-r--r--src/game/NPCHandler.cpp50
-rw-r--r--src/game/ObjectMgr.cpp27
-rw-r--r--src/game/Player.cpp72
-rw-r--r--src/game/SpellMgr.cpp53
5 files changed, 142 insertions, 74 deletions
diff --git a/src/game/Creature.h b/src/game/Creature.h
index 58974fe0c83..e7ddd64a7bb 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -370,21 +370,21 @@ typedef std::list<VendorItemCount> VendorItemCounts;
struct TrainerSpell
{
- TrainerSpell() : spell(0), spellCost(0), reqSkill(0), reqSkillValue(0), reqLevel(0), learnedSpell(0) {}
-
- TrainerSpell(uint32 _spell, uint32 _spellCost, uint32 _reqSkill, uint32 _reqSkillValue, uint32 _reqLevel, uint32 _learnedspell)
- : spell(_spell), spellCost(_spellCost), reqSkill(_reqSkill), reqSkillValue(_reqSkillValue), reqLevel(_reqLevel), learnedSpell(_learnedspell)
- {}
+ TrainerSpell() : spell(0), spellCost(0), reqSkill(0), reqSkillValue(0), reqLevel(0)
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
+ learnedSpell[i] = 0;
+ }
uint32 spell;
uint32 spellCost;
uint32 reqSkill;
uint32 reqSkillValue;
uint32 reqLevel;
- uint32 learnedSpell;
+ uint32 learnedSpell[3];
// helpers
- bool IsCastable() const { return learnedSpell != spell; }
+ bool IsCastable() const { return learnedSpell[0] != spell; }
};
typedef UNORDERED_MAP<uint32 /*spellid*/, TrainerSpell> TrainerSpellMap;
diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp
index cba689d0a76..c7e5619bdf9 100644
--- a/src/game/NPCHandler.cpp
+++ b/src/game/NPCHandler.cpp
@@ -159,11 +159,23 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
{
TrainerSpell const* tSpell = &itr->second;
- if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
+ bool valid = true;
+ bool primary_prof_first_rank = false;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
+ {
+ if (!tSpell->learnedSpell[i])
+ continue;
+ if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i]))
+ {
+ valid = false;
+ break;
+ }
+ if (spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell[i]))
+ primary_prof_first_rank = true;
+ }
+ if (!valid)
continue;
- bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
- SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell);
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
@@ -178,16 +190,28 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
data << uint32(tSpell->reqSkillValue);
//prev + req or req + 0
uint8 maxReq = 0;
- if (!tSpell->IsCastable() && chain_node && chain_node->prev)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
{
- data << uint32(chain_node->prev);
- ++maxReq;
- }
- SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->spell);
- for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2)
- {
- data << uint32(itr2->second);
- ++maxReq;
+ if (!tSpell->learnedSpell[i])
+ continue;
+ if (SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell[i]))
+ {
+ if (chain_node->prev)
+ {
+ data << uint32(chain_node->prev);
+ ++maxReq;
+ }
+ }
+ if (maxReq == 3)
+ break;
+ SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]);
+ for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2)
+ {
+ data << uint32(itr2->second);
+ ++maxReq;
+ }
+ if (maxReq == 3)
+ break;
}
while (maxReq < 3)
{
@@ -258,7 +282,7 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
SendPacket(&data);
// learn explicitly or cast explicitly
- if(trainer_spell->IsCastable ())
+ if(trainer_spell->IsCastable())
//FIXME: prof. spell entry in trainer list not marked gray until list re-open.
_player->CastSpell(_player,trainer_spell->spell,true);
else
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index ccac86f9202..4f9f2b1faa2 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -8015,20 +8015,33 @@ void ObjectMgr::LoadTrainerSpell()
trainerSpell.reqLevel = spellinfo->spellLevel;
// calculate learned spell for profession case when stored cast-spell
- trainerSpell.learnedSpell = spell;
- for (uint8 i = 0; i <3; ++i)
+ trainerSpell.learnedSpell[0] = spell;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if(spellinfo->Effect[i] != SPELL_EFFECT_LEARN_SPELL)
continue;
- if(SpellMgr::IsProfessionOrRidingSpell(spellinfo->EffectTriggerSpell[i]))
+ // player must be able to cast spell on himself
+ if (spellinfo->EffectImplicitTargetA[i] != 0 && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_TARGET_ALLY && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_TARGET_ANY)
{
- trainerSpell.learnedSpell = spellinfo->EffectTriggerSpell[i];
- break;
+ sLog.outErrorDb("Table `npc_trainer` has spell %u for trainer entry %u with learn effect which has incorrect target type, ignoring learn effect!", spell, entry);
+ continue;
}
+ if (trainerSpell.learnedSpell[0] == spell)
+ trainerSpell.learnedSpell[0] = 0;
+
+ trainerSpell.learnedSpell[i] = spellinfo->EffectTriggerSpell[i];
}
- if(SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell))
- data.trainerType = 2;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (!trainerSpell.learnedSpell[i])
+ continue;
+ if(SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell[i]))
+ {
+ data.trainerType = 2;
+ break;
+ }
+ }
++count;
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index f3383c8e5bc..af898061aea 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -4093,52 +4093,64 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
if (!trainer_spell)
return TRAINER_SPELL_RED;
- if (!trainer_spell->learnedSpell)
- return TRAINER_SPELL_RED;
-
+ bool hasSpell = true;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
+ {
+ if (!trainer_spell->learnedSpell[i])
+ continue;
+
+ if(!HasSpell(trainer_spell->learnedSpell[i]))
+ {
+ hasSpell = false;
+ break;
+ }
+ }
// known spell
- if(HasSpell(trainer_spell->learnedSpell))
+ if (hasSpell)
return TRAINER_SPELL_GRAY;
- // check race/class requirement
- if(!IsSpellFitByClassAndRace(trainer_spell->learnedSpell))
+ // check skill requirement
+ if(trainer_spell->reqSkill && GetBaseSkillValue(trainer_spell->reqSkill) < trainer_spell->reqSkillValue)
return TRAINER_SPELL_RED;
// check level requirement
if(getLevel() < trainer_spell->reqLevel)
return TRAINER_SPELL_RED;
- if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->learnedSpell))
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
{
- // check prev.rank requirement
- if(spell_chain->prev && !HasSpell(spell_chain->prev))
- return TRAINER_SPELL_RED;
- }
+ if (!trainer_spell->learnedSpell[i])
+ continue;
- SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(trainer_spell->spell);
- for (SpellsRequiringSpellMap::const_iterator itr = spellsRequired.first; itr != spellsRequired.second; ++itr)
- {
- // check additional spell requirement
- if(!HasSpell(itr->second))
+ // check race/class requirement
+ if(!IsSpellFitByClassAndRace(trainer_spell->learnedSpell[i]))
return TRAINER_SPELL_RED;
- }
- // check skill requirement
- if(trainer_spell->reqSkill && GetBaseSkillValue(trainer_spell->reqSkill) < trainer_spell->reqSkillValue)
- return TRAINER_SPELL_RED;
-
- // exist, already checked at loading
- SpellEntry const* spell = sSpellStore.LookupEntry(trainer_spell->learnedSpell);
-
- // secondary prof. or not prof. spell
- uint32 skill = spell->EffectMiscValue[1];
+ if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->learnedSpell[i]))
+ {
+ // check prev.rank requirement
+ if(spell_chain->prev && !HasSpell(spell_chain->prev))
+ return TRAINER_SPELL_RED;
+ }
- if(spell->Effect[1] != SPELL_EFFECT_SKILL || !IsPrimaryProfessionSkill(skill))
- return TRAINER_SPELL_GREEN;
+ SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(trainer_spell->learnedSpell[i]);
+ for (SpellsRequiringSpellMap::const_iterator itr = spellsRequired.first; itr != spellsRequired.second; ++itr)
+ {
+ // check additional spell requirement
+ if(!HasSpell(itr->second))
+ return TRAINER_SPELL_RED;
+ }
+ }
// check primary prof. limit
- if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell->Id) && GetFreePrimaryProfessionPoints() == 0)
- return TRAINER_SPELL_GREEN_DISABLED;
+ // first rank of primary profession spell when there are no proffesions avalible is disabled
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
+ {
+ if (!trainer_spell->learnedSpell[i])
+ continue;
+ if((spellmgr.IsPrimaryProfessionFirstRankSpell(trainer_spell->learnedSpell[i])) && (GetFreePrimaryProfessionPoints() == 0))
+ return TRAINER_SPELL_GREEN_DISABLED;
+ }
return TRAINER_SPELL_GREEN;
}
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 74310036a0d..4049150baed 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -1660,12 +1660,18 @@ bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId)
if(!spellInfo)
return false;
- if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
- return false;
-
- uint32 skill = spellInfo->EffectMiscValue[1];
+ for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i)
+ {
+ if(spellInfo->Effect[i] == SPELL_EFFECT_SKILL)
+ {
+ uint32 skill = spellInfo->EffectMiscValue[i];
- return IsProfessionOrRidingSkill(skill);
+ bool found = IsProfessionOrRidingSkill(skill);
+ if (found)
+ return true;
+ }
+ }
+ return false;
}
bool SpellMgr::IsProfessionSpell(uint32 spellId)
@@ -1674,12 +1680,18 @@ bool SpellMgr::IsProfessionSpell(uint32 spellId)
if(!spellInfo)
return false;
- if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
- return false;
-
- uint32 skill = spellInfo->EffectMiscValue[1];
+ for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i)
+ {
+ if(spellInfo->Effect[i] == SPELL_EFFECT_SKILL)
+ {
+ uint32 skill = spellInfo->EffectMiscValue[i];
- return IsProfessionSkill(skill);
+ bool found = IsProfessionSkill(skill);
+ if (found)
+ return true;
+ }
+ }
+ return false;
}
bool SpellMgr::IsPrimaryProfessionSpell(uint32 spellId)
@@ -1688,12 +1700,18 @@ bool SpellMgr::IsPrimaryProfessionSpell(uint32 spellId)
if(!spellInfo)
return false;
- if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
- return false;
-
- uint32 skill = spellInfo->EffectMiscValue[1];
+ for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i)
+ {
+ if(spellInfo->Effect[i] == SPELL_EFFECT_SKILL)
+ {
+ uint32 skill = spellInfo->EffectMiscValue[i];
- return IsPrimaryProfessionSkill(skill);
+ bool found = IsPrimaryProfessionSkill(skill);
+ if (found)
+ return true;
+ }
+ }
+ return false;
}
bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
@@ -1965,7 +1983,8 @@ void SpellMgr::LoadSpellScriptTarget()
}
if (!targetfound)
{
- sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46).",spellId,targetEntry);
+ sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)\
+ ,TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60)",spellId,targetEntry);
continue;
}
@@ -3227,7 +3246,7 @@ void SpellMgr::LoadSpellRequired()
uint32 spell_id = fields[0].GetUInt32();
uint32 spell_req = fields[1].GetUInt32();
- // check if chain is made with valid first spell
+ // validate table
SpellEntry const * spell = sSpellStore.LookupEntry(spell_id);
if (!spell)
{