diff options
Diffstat (limited to 'src/game/CombatAI.cpp')
-rw-r--r-- | src/game/CombatAI.cpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/game/CombatAI.cpp b/src/game/CombatAI.cpp new file mode 100644 index 00000000000..89628ccef57 --- /dev/null +++ b/src/game/CombatAI.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "CombatAI.h" +#include "SpellMgr.h" + +int AggressorAI::Permissible(const Creature *creature) +{ + // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight + if( !creature->isCivilian() && !creature->IsNeutralToAll() ) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} + +void AggressorAI::UpdateAI(const uint32 /*diff*/) +{ + if(!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); +} + +int CombatAI::Permissible(const Creature *creature) +{ + return PERMIT_BASE_NO; +} + +void CombatAI::InitializeAI() +{ + for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + if(me->m_spells[i] && GetSpellStore()->LookupEntry(me->m_spells[i])) + spells.push_back(me->m_spells[i]); + + CreatureAI::InitializeAI(); +} + +void CombatAI::Reset() +{ + events.Reset(); +} + +void CombatAI::JustDied(Unit *killer) +{ + for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + if(AISpellInfo[*i].condition == AICOND_DIE) + me->CastSpell(killer, *i, true); +} + +void CombatAI::EnterCombat(Unit *who) +{ + for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + { + if(AISpellInfo[*i].condition == AICOND_AGGRO) + me->CastSpell(who, *i, false); + else if(AISpellInfo[*i].condition == AICOND_COMBAT) + events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown); + } +} + +void CombatAI::UpdateAI(const uint32 diff) +{ + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(uint32 spellId = events.ExecuteEvent()) + { + DoCast(spellId); + events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown); + } + else + DoMeleeAttackIfReady(); +} + + +///////////////// +//CasterAI +///////////////// + +void CasterAI::InitializeAI() +{ + CombatAI::InitializeAI(); + + float m_attackDist = 30.0f; + for(SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr) + if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange) + m_attackDist = GetAISpellInfo(*itr)->maxRange; + if (m_attackDist == 30.0f) + m_attackDist = MELEE_RANGE; +} + +void CasterAI::EnterCombat(Unit *who) +{ + if (spells.empty()) + return; + + uint32 spell = rand()%spells.size(); + uint32 count = 0; + for(SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count) + { + if(AISpellInfo[*itr].condition == AICOND_AGGRO) + me->CastSpell(who, *itr, false); + else if (AISpellInfo[*itr].condition == AICOND_COMBAT) + { + uint32 cooldown = GetAISpellInfo(*itr)->realCooldown; + if (count == spell) + { + DoCast(spells[spell]); + cooldown += me->GetCurrentSpellCastTime(*itr); + } + events.ScheduleEvent(*itr, cooldown); + } + } +} + +void CasterAI::UpdateAI(const uint32 diff) +{ + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(uint32 spellId = events.ExecuteEvent()) + { + DoCast(spellId); + uint32 casttime = me->GetCurrentSpellCastTime(spellId); + events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown); + } +} + + +////////////// +//ArchorAI +////////////// + +ArchorAI::ArchorAI(Creature *c) : CreatureAI(c), m_canMelee(true) +{ + assert(me->m_spells[0]); + m_minRange = GetSpellMinRange(me->m_spells[0], false); + m_maxRange = GetSpellMaxRange(me->m_spells[0], false); + if(!m_minRange) + m_minRange = MELEE_RANGE; +} + +void ArchorAI::MoveInLineOfSight(Unit *who) +{ + if(!me->getVictim() && me->canAttack(who) + && me->IsWithinCombatRange(who, m_maxRange) + && me->IsWithinLOSInMap(who)) + AttackStart(who); +} + +void ArchorAI::AttackStart(Unit *who) +{ + if(who->IsFlying() || !me->IsWithinCombatRange(who, m_minRange)) + { + if(me->Attack(who, false)) + me->GetMotionMaster()->MoveIdle(); + } + else if(m_canMelee) + { + if(me->Attack(who, true)) + me->GetMotionMaster()->MoveChase(who); + } +} + +void ArchorAI::UpdateAI(const uint32 diff) +{ + if(!UpdateVictim()) + return; + + if(me->getVictim()->IsFlying() || !me->IsWithinCombatRange(me->getVictim(), m_minRange)) + { + if(!DoSpellAttackIfReady(me->m_spells[0])) + { + if(HostilReference *ref = me->getThreatManager().getCurrentVictim()) + ref->removeReference(); + else // i do not know when this could happen + EnterEvadeMode(); + } + } + else if(m_canMelee) + DoMeleeAttackIfReady(); + else if(HostilReference *ref = me->getThreatManager().getCurrentVictim()) + ref->removeReference(); +} |