diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 42afa4eef..a9902e8fa 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -2027,40 +2027,101 @@ void Creature::SetInCombatWithZone() } } -Unit* Creature::SelectAttackingTarget(AttackingTarget target, uint32 position) const +bool Creature::MeetsSelectAttackingRequirement(Unit* pTarget, SpellEntry const* pSpellInfo, uint32 selectFlags) const +{ + if (selectFlags & SELECT_FLAG_PLAYER && pTarget->GetTypeId() != TYPEID_PLAYER) + return false; + + if (selectFlags & SELECT_FLAG_POWER_MANA && pTarget->getPowerType() != POWER_MANA) + return false; + else if (selectFlags & SELECT_FLAG_POWER_RAGE && pTarget->getPowerType() != POWER_RAGE) + return false; + else if (selectFlags & SELECT_FLAG_POWER_ENERGY && pTarget->getPowerType() != POWER_ENERGY) + return false; + else if (selectFlags & SELECT_FLAG_POWER_RUNIC && pTarget->getPowerType() != POWER_RUNIC_POWER) + return false; + + if (selectFlags & SELECT_FLAG_IN_MELEE_RANGE && !CanReachWithMeleeAttack(pTarget)) + return false; + + if (selectFlags & SELECT_FLAG_IN_LOS && !IsWithinLOSInMap(pTarget)) + return false; + + if (pSpellInfo) + { + switch (pSpellInfo->rangeIndex) + { + case SPELL_RANGE_IDX_SELF_ONLY: return false; + case SPELL_RANGE_IDX_ANYWHERE: return true; + case SPELL_RANGE_IDX_COMBAT: return CanReachWithMeleeAttack(pTarget); + } + + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(pSpellInfo->rangeIndex); + float max_range = GetSpellMaxRange(srange); + float min_range = GetSpellMinRange(srange); + float dist = GetCombatDistance(pTarget); + + return dist < max_range && dist >= min_range; + } + + return true; +} + +Unit* Creature::SelectAttackingTarget(AttackingTarget target, uint32 position, uint32 uiSpellEntry, uint32 selectFlags) const +{ + return SelectAttackingTarget(target, position, sSpellStore.LookupEntry(uiSpellEntry), selectFlags); +} + +Unit* Creature::SelectAttackingTarget(AttackingTarget target, uint32 position, SpellEntry const* pSpellInfo /*= NULL*/, uint32 selectFlags/*= 0*/) const { if (!CanHaveThreatList()) return NULL; - //ThreatList m_threatlist; + // ThreatList m_threatlist; ThreatList const& threatlist = getThreatManager().getThreatList(); - ThreatList::const_iterator i = threatlist.begin(); - ThreatList::const_reverse_iterator r = threatlist.rbegin(); + ThreatList::const_iterator itr = threatlist.begin(); + ThreatList::const_reverse_iterator ritr = threatlist.rbegin(); if (position >= threatlist.size() || !threatlist.size()) return NULL; - switch(target) + switch (target) { case ATTACKING_TARGET_RANDOM: { - advance(i, position + (rand() % (threatlist.size() - position))); - return GetMap()->GetUnit((*i)->getUnitGuid()); + std::vector suitableUnits; + suitableUnits.reserve(threatlist.size() - position); + advance(itr, position); + for (itr; itr != threatlist.end(); ++itr) + if (Unit* pTarget = GetMap()->GetUnit((*itr)->getUnitGuid())) + if (!selectFlags || MeetsSelectAttackingRequirement(pTarget, pSpellInfo, selectFlags)) + suitableUnits.push_back(pTarget); + + if (!suitableUnits.empty()) + return suitableUnits[urand(0, suitableUnits.size()-1)]; + + break; } case ATTACKING_TARGET_TOPAGGRO: { - advance(i, position); - return GetMap()->GetUnit((*i)->getUnitGuid()); + advance(itr, position); + for (itr; itr != threatlist.end(); ++itr) + if (Unit* pTarget = GetMap()->GetUnit((*itr)->getUnitGuid())) + if (!selectFlags || MeetsSelectAttackingRequirement(pTarget, pSpellInfo, selectFlags)) + return pTarget; + + break; } case ATTACKING_TARGET_BOTTOMAGGRO: { - advance(r, position); - return GetMap()->GetUnit((*r)->getUnitGuid()); + advance(ritr, position); + for (ritr; ritr != threatlist.rend(); ++ritr) + if (Unit* pTarget = GetMap()->GetUnit((*itr)->getUnitGuid())) + if (!selectFlags || MeetsSelectAttackingRequirement(pTarget, pSpellInfo, selectFlags)) + return pTarget; + + break; } - // TODO: implement these - //case ATTACKING_TARGET_RANDOM_PLAYER: - //case ATTACKING_TARGET_TOPAGGRO_PLAYER: - //case ATTACKING_TARGET_BOTTOMAGGRO_PLAYER: } return NULL; diff --git a/src/game/Creature.h b/src/game/Creature.h index ca554fca4..b7b8aeb48 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -288,11 +288,17 @@ enum AttackingTarget ATTACKING_TARGET_RANDOM = 0, //Just selects a random target ATTACKING_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom ATTACKING_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top - /* not implemented - ATTACKING_TARGET_RANDOM_PLAYER, //Just selects a random target (player only) - ATTACKING_TARGET_TOPAGGRO_PLAYER, //Selects targes from top aggro to bottom (player only) - ATTACKING_TARGET_BOTTOMAGGRO_PLAYER, //Selects targets from bottom aggro to top (player only) - */ +}; + +enum SelectFlags +{ + SELECT_FLAG_IN_LOS = 0x001, // Default Selection Requirement for Spell-targets + SELECT_FLAG_PLAYER = 0x002, + SELECT_FLAG_POWER_MANA = 0x004, // For Energy based spells, like manaburn + SELECT_FLAG_POWER_RAGE = 0x008, + SELECT_FLAG_POWER_ENERGY = 0x010, + SELECT_FLAG_POWER_RUNIC = 0x020, + SELECT_FLAG_IN_MELEE_RANGE = 0x040, }; // Vendors @@ -651,7 +657,8 @@ class MANGOS_DLL_SPEC Creature : public Unit void SetInCombatWithZone(); - Unit* SelectAttackingTarget(AttackingTarget target, uint32 position) const; + Unit* SelectAttackingTarget(AttackingTarget target, uint32 position, uint32 uiSpellEntry, uint32 selectFlags = 0) const; + Unit* SelectAttackingTarget(AttackingTarget target, uint32 position, SpellEntry const* pSpellInfo = NULL, uint32 selectFlags = 0) const; bool HasQuest(uint32 quest_id) const; bool HasInvolvedQuest(uint32 quest_id) const; @@ -686,6 +693,8 @@ class MANGOS_DLL_SPEC Creature : public Unit void SetVirtualItem(VirtualItemSlot slot, uint32 item_id) { SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot, item_id); } protected: + bool MeetsSelectAttackingRequirement(Unit* pTarget, SpellEntry const* pSpellInfo, uint32 selectFlags) const; + bool CreateFromProto(uint32 guidlow, CreatureInfo const* cinfo, Team team, const CreatureData *data = NULL, GameEventCreatureData const* eventData =NULL); bool InitEntry(uint32 entry, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL); diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 645cd2ea6..6b9acb446 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -1304,6 +1304,7 @@ enum SpellRangeIndex { SPELL_RANGE_IDX_SELF_ONLY = 1, // 0.0 SPELL_RANGE_IDX_COMBAT = 2, // 5.5 (but dynamic) + SPELL_RANGE_IDX_ANYWHERE = 13, // 500000 (anywhere) }; enum DamageEffectType diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 8bbba6845..8bea4c0e1 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -5981,7 +5981,9 @@ SpellCastResult Spell::CheckRange(bool strict) switch(m_spellInfo->rangeIndex) { // self cast doesn't need range checking -- also for Starshards fix + // spells that can be cast anywhere also need no check case SPELL_RANGE_IDX_SELF_ONLY: + case SPELL_RANGE_IDX_ANYWHERE: return SPELL_CAST_OK; // combat range spells are treated differently case SPELL_RANGE_IDX_COMBAT: diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 5d811a2f2..0da3f3eb8 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -1080,18 +1080,11 @@ void Aura::TriggerSpell() { trigger_spell_id = 25779; // Mana Burn - // expected selection current fight target - triggerTarget = GetTarget()->getVictim(); - if (!triggerTarget || triggerTarget->GetMaxPower(POWER_MANA) <= 0) + if (GetTarget()->GetTypeId() != TYPEID_UNIT) return; - triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id); - if (!triggeredSpellInfo) - return; - - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(triggeredSpellInfo->rangeIndex); - float max_range = GetSpellMaxRange(srange); - if (!triggerTarget->IsWithinDist(GetTarget(),max_range)) + triggerTarget = ((Creature*)GetTarget())->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, trigger_spell_id, SELECT_FLAG_POWER_MANA); + if (!triggerTarget) return; break; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index c3f8af134..4570f7194 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11792" + #define REVISION_NR "11793" #endif // __REVISION_NR_H__