diff --git a/src/game/Object/GameObject.cpp b/src/game/Object/GameObject.cpp index 2580159d..589cfc85 100644 --- a/src/game/Object/GameObject.cpp +++ b/src/game/Object/GameObject.cpp @@ -365,13 +365,22 @@ void GameObject::Update(uint32 update_diff, uint32 p_time) } } - // Should trap trigger? - Unit* enemy = NULL; // pointer to appropriate target if found any - MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, radius); - MaNGOS::UnitSearcher checker(enemy, u_check); - Cell::VisitAllObjects(this, checker, radius); - if (enemy) - { Use(enemy); } + SpellEntry const* se = sSpellStore.LookupEntry(goInfo->trap.spellId); + if(IsAreaOfEffectSpell(se)) + { + MaNGOS::AllSpecificUnitsInGameObjectRangeDo unit_do(this, radius, IsPositiveSpell(se)); + MaNGOS::UnitWorker worker(unit_do); + Cell::VisitAllObjects(this,worker,radius); + } + else + { + Unit* targetUnit = NULL; // pointer to appropriate target if found any + MaNGOS::AnySpecificUnitInGameObjectRangeCheck u_check(this, radius, IsPositiveSpell(se)); + MaNGOS::UnitSearcher checker(targetUnit, u_check); + Cell::VisitAllObjects(this, checker, radius); + if (targetUnit) + { Use(targetUnit); } + } } if (uint32 max_charges = goInfo->GetCharges()) diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index bbf9e561..5ef069a8 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -2912,43 +2912,40 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible if (newspell.active && !newspell.disabled) { - SpellChainMapNext const& nextMap = sSpellMgr.GetSpellChainNext(); - for (SpellChainMapNext::const_iterator next_itr = nextMap.lower_bound(spell_id); next_itr != nextMap.upper_bound(spell_id); ++next_itr) + do { - uint32 tested_spell_id = next_itr->second; // synonym just for the code clarity - if (m_spells.find(tested_spell_id) == m_spells.end()) + uint32 prev_spell_id = sSpellMgr.GetPrevSpellInChain(spell_id); // get the previous spell in chain (if any) + if(!prev_spell_id) //spell_id does not have ranks or is the first spell in chain; must add in spellbook + continue; + + if ((m_spells.find(prev_spell_id) == m_spells.end())) continue; - PlayerSpell &lowerRank = m_spells[tested_spell_id]; - if (lowerRank.state == PLAYERSPELL_REMOVED || !lowerRank.active) + PlayerSpell* lowerRank = &m_spells[prev_spell_id]; + if (lowerRank->state == PLAYERSPELL_REMOVED || !lowerRank->active) continue; - SpellEntry const *spell_old = sSpellStore.LookupEntry(tested_spell_id); // was checked for NULL in SpellMgr::LoadSpellChains() + SpellEntry const *spell_old = sSpellStore.LookupEntry(prev_spell_id); SpellEntry const *spell_new = spellInfo; - if (sSpellMgr.IsHighRankOfSpell(tested_spell_id, spell_id) && sSpellMgr.IsRankedSpellNonStackableInSpellBook(spell_old)) + + if (sSpellMgr.IsRankedSpellNonStackableInSpellBook(spell_old)) { - spell_new = spell_old; - spell_old = spellInfo; - lowerRank = newspell; + if (IsInWorld()) // not send spell (re-/over-)learn packets at loading + { + WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); + data << uint16(spell_old->Id); + data << uint16(spell_new->Id); + GetSession()->SendPacket(&data); + } + + // mark lower rank disabled (SMSG_SUPERCEDED_SPELL replaced it in client by new) + lowerRank->active = false; + if (lowerRank->state != PLAYERSPELL_NEW) + lowerRank->state = PLAYERSPELL_CHANGED; + + canAddToSpellBook = false; } - else if (!(sSpellMgr.IsHighRankOfSpell(spell_id, tested_spell_id) && sSpellMgr.IsRankedSpellNonStackableInSpellBook(spell_new))) - continue; - - if (IsInWorld()) // not send spell (re-/over-)learn packets at loading - { - WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); - data << uint16(spell_old->Id); - data << uint16(spell_new->Id); - GetSession()->SendPacket(&data); - } - - // mark lower rank disabled (SMSG_SUPERCEDED_SPELL replaced it in client by new) - lowerRank.active = false; - if (lowerRank.state != PLAYERSPELL_NEW) - lowerRank.state = PLAYERSPELL_CHANGED; - - canAddToSpellBook = false; - } + } while(0); } m_spells[spell_id] = newspell; diff --git a/src/game/WorldHandlers/GridNotifiers.h b/src/game/WorldHandlers/GridNotifiers.h index 7975ee39..68f4d5c6 100644 --- a/src/game/WorldHandlers/GridNotifiers.h +++ b/src/game/WorldHandlers/GridNotifiers.h @@ -378,6 +378,28 @@ namespace MaNGOS template void Visit(GridRefManager&) {} }; + // unit worker + template + struct UnitWorker + { + Do& i_do; + + explicit UnitWorker(Do& _do) : i_do(_do) {} + + void Visit(PlayerMapType& m) + { + for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr) + { i_do(itr->getSource()); } + } + void Visit(CreatureMapType& m) + { + for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr) + { i_do(itr->getSource()); } + } + + template void Visit(GridRefManager&) {} + }; + // Creature searchers template @@ -927,6 +949,60 @@ namespace MaNGOS bool i_targetForPlayer; }; + class AnySpecificUnitInGameObjectRangeCheck + { + public: + AnySpecificUnitInGameObjectRangeCheck(GameObject* go, float range, bool friendly = true) + : i_obj(go), i_range(range), i_isFriendly(friendly) + { + } + WorldObject const& GetFocusObject() const { return *i_obj; } + bool operator()(Unit* u) + { + // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems + if (!u->IsTargetableForAttack()) + { return false; } + + if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem()) + { return false; } + + if ((i_isFriendly ? i_obj->IsFriendlyTo(u) : i_obj->IsHostileTo(u)) && i_obj->IsWithinDistInMap(u, i_range)) + { return true; } + + return false; + } + private: + GameObject* i_obj; + float i_range; + bool i_isFriendly; + }; + + class AllSpecificUnitsInGameObjectRangeDo + { + public: + AllSpecificUnitsInGameObjectRangeDo(GameObject* go, float range, bool friendly = true) + : i_obj(go), i_range(range), i_isFriendly(friendly) + { + } + WorldObject const& GetFocusObject() const { return *i_obj; } + void operator()(Unit* u) + { + // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems + if (!u->IsTargetableForAttack()) + { return; } + + if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem()) + { return; } + + if ((i_isFriendly ? i_obj->IsFriendlyTo(u) : i_obj->IsHostileTo(u)) && i_obj->IsWithinDistInMap(u, i_range)) + { i_obj->Use(u); } + } + private: + GameObject* i_obj; + float i_range; + bool i_isFriendly; + }; + // do attack at call of help to friendly crearture class CallOfHelpCreatureInRangeDo {