diff options
-rw-r--r-- | src/game/Creature.h | 14 | ||||
-rw-r--r-- | src/game/NPCHandler.cpp | 50 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 27 | ||||
-rw-r--r-- | src/game/Player.cpp | 72 | ||||
-rw-r--r-- | src/game/SpellMgr.cpp | 53 |
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) { |