diff options
author | megamage <none@none> | 2009-05-20 11:44:38 -0500 |
---|---|---|
committer | megamage <none@none> | 2009-05-20 11:44:38 -0500 |
commit | 6473e943581439f57918abfa91a4d5a29e2f343c (patch) | |
tree | 01b7419dcc1ac0444375d11b22cd55d72897854a /src/game/UnitAI.cpp | |
parent | d1d194b4c78aec34d65a15ea68acff5c3a48687c (diff) |
*Update Naxx scripts. Now only Kelthuzad is incompleted
--HG--
branch : trunk
Diffstat (limited to 'src/game/UnitAI.cpp')
-rw-r--r-- | src/game/UnitAI.cpp | 281 |
1 files changed, 274 insertions, 7 deletions
diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp index 12dc20692c6..c159861697c 100644 --- a/src/game/UnitAI.cpp +++ b/src/game/UnitAI.cpp @@ -22,17 +22,19 @@ #include "Player.h" #include "Creature.h" #include "SpellAuras.h" +#include "SpellMgr.h" +#include "CreatureAIImpl.h" void UnitAI::AttackStart(Unit *victim) { - if(!victim) - return; - - if(me->Attack(victim, true)) - { - //DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow()); + if(victim && me->Attack(victim, true)) me->GetMotionMaster()->MoveChase(victim); - } +} + +void UnitAI::AttackStartCaster(Unit *victim, float dist) +{ + if(victim && me->Attack(victim, false)) + me->GetMotionMaster()->MoveChase(victim, dist); } void UnitAI::DoMeleeAttackIfReady() @@ -61,6 +63,271 @@ void UnitAI::DoMeleeAttackIfReady() } } +bool UnitAI::DoSpellAttackIfReady(uint32 spell) +{ + if(me->hasUnitState(UNIT_STAT_CASTING)) + return true; + + if(me->isAttackReady()) + { + if(me->IsWithinCombatRange(me->getVictim(), GetSpellMaxRange(spell, false))) + { + me->CastSpell(me->getVictim(), spell, false); + me->resetAttackTimer(); + } + else + return false; + } + return true; +} + +inline bool SelectTargetHelper(const Unit * me, const Unit * target, const bool &playerOnly, const float &dist, const int32 &aura) +{ + if(playerOnly && target->GetTypeId() != TYPEID_PLAYER) + return false; + + if(dist && !me->IsWithinCombatRange(target, dist)) + return false; + + if(aura) + { + if(aura > 0) + { + if(!target->HasAura(aura)) + return false; + } + else + { + if(target->HasAura(aura)) + return false; + } + } + + return true; +} + +struct TargetDistanceOrder : public std::binary_function<const Unit *, const Unit *, bool> +{ + const Unit * me; + TargetDistanceOrder(const Unit* Target) : me(Target) {}; + // functor for operator ">" + bool operator()(const Unit * _Left, const Unit * _Right) const + { + return (me->GetDistanceSq(_Left) < me->GetDistanceSq(_Right)); + } +}; + +Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura) +{ + if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + { + std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList(); + if(position >= m_threatlist.size()) + return NULL; + + std::list<Unit*> targetList; + for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura)) + targetList.push_back((*itr)->getTarget()); + + if(position >= targetList.size()) + return NULL; + + targetList.sort(TargetDistanceOrder(me)); + + if(targetType == SELECT_TARGET_NEAREST) + { + std::list<Unit*>::iterator i = targetList.begin(); + advance(i, position); + return *i; + } + else + { + std::list<Unit*>::reverse_iterator i = targetList.rbegin(); + advance(i, position); + return *i; + } + } + else + { + std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList(); + std::list<HostilReference*>::iterator i; + while(position < m_threatlist.size()) + { + if(targetType == SELECT_TARGET_BOTTOMAGGRO) + { + i = m_threatlist.end(); + advance(i, - (int32)position - 1); + } + else + { + i = m_threatlist.begin(); + if(targetType == SELECT_TARGET_TOPAGGRO) + advance(i, position); + else // random + advance(i, position + rand()%(m_threatlist.size() - position)); + } + + if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura)) + return (*i)->getTarget(); + else + m_threatlist.erase(i); + } + } + + return NULL; +} + +void UnitAI::SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura) +{ + if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + { + std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return; + + for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura)) + targetList.push_back((*itr)->getTarget()); + + targetList.sort(TargetDistanceOrder(me)); + targetList.resize(num); + if(targetType == SELECT_TARGET_FARTHEST) + targetList.reverse(); + } + else + { + std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList(); + std::list<HostilReference*>::iterator i; + while(!m_threatlist.empty() && num) + { + if(targetType == SELECT_TARGET_BOTTOMAGGRO) + { + i = m_threatlist.end(); + --i; + } + else + { + i = m_threatlist.begin(); + if(targetType == SELECT_TARGET_RANDOM) + advance(i, rand()%m_threatlist.size()); + } + + if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura)) + { + targetList.push_back((*i)->getTarget()); + --num; + } + m_threatlist.erase(i); + } + } +} + +void UnitAI::DoCast(uint32 spellId) +{ + Unit *target = NULL; + //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target); + switch(AISpellInfo[spellId].target) + { + default: + case AITARGET_SELF: target = me; break; + case AITARGET_VICTIM: target = me->getVictim(); break; + case AITARGET_ENEMY: + { + const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); + bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; + float range = GetSpellMaxRange(spellInfo, false); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, GetSpellMaxRange(spellInfo, false), playerOnly); + break; + } + case AITARGET_ALLY: target = me; break; + case AITARGET_BUFF: target = me; break; + case AITARGET_DEBUFF: + { + const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); + bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; + float range = GetSpellMaxRange(spellInfo, false); + if(!(spellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE) + && !(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) + && SelectTargetHelper(me, me->getVictim(), playerOnly, range, -(int32)spellId)) + target = me->getVictim(); + else + target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId); + break; + } + } + + if(target) + me->CastSpell(target, spellId, false); +} + +void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered) +{ + if(!victim || me->hasUnitState(UNIT_STAT_CASTING) && !triggered) + return; + + me->CastSpell(victim, spellId, triggered); +} + +void UnitAI::DoCastAOE(uint32 spellId, bool triggered) +{ + if(!triggered && me->hasUnitState(UNIT_STAT_CASTING)) + return; + + me->CastSpell((Unit*)NULL, spellId, triggered); +} + +#define UPDATE_TARGET(a) {if(AIInfo->target<a) AIInfo->target=a;} + +void UnitAI::FillAISpellInfo() +{ + AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()]; + + AISpellInfoType *AIInfo = AISpellInfo; + const SpellEntry * spellInfo; + + for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo) + { + spellInfo = GetSpellStore()->LookupEntry(i); + if(!spellInfo) + continue; + + if(spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) + AIInfo->condition = AICOND_DIE; + else if(IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1) + AIInfo->condition = AICOND_AGGRO; + else + AIInfo->condition = AICOND_COMBAT; + + if(AIInfo->cooldown < spellInfo->RecoveryTime) + AIInfo->cooldown = spellInfo->RecoveryTime; + + if(!GetSpellMaxRange(spellInfo, false)) + UPDATE_TARGET(AITARGET_SELF) + else + { + for(uint32 j = 0; j < 3; ++j) + { + uint32 targetType = spellInfo->EffectImplicitTargetA[j]; + + if(targetType == TARGET_UNIT_TARGET_ENEMY + || targetType == TARGET_DST_TARGET_ENEMY) + UPDATE_TARGET(AITARGET_VICTIM) + else if(targetType == TARGET_UNIT_AREA_ENEMY_DST) + UPDATE_TARGET(AITARGET_ENEMY) + + if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) + { + if(targetType == TARGET_UNIT_TARGET_ENEMY) + UPDATE_TARGET(AITARGET_DEBUFF) + else if(IsPositiveSpell(i)) + UPDATE_TARGET(AITARGET_BUFF) + } + } + } + } +} + //Enable PlayerAI when charmed void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } |