*Add SpellCasterAI as a framework for casting only units (like ebon gargoyle or mirror image.

--HG--
branch : trunk
This commit is contained in:
QAston
2009-08-06 23:10:36 +02:00
parent 91885a7790
commit 50c73d433c
8 changed files with 80 additions and 48 deletions

View File

@@ -1639,12 +1639,13 @@ CreatureAI* GetAI_mob_mojo(Creature *_Creature)
return new mob_mojoAI (_Creature);
}
struct TRINITY_DLL_DECL npc_mirror_image : SpellAI
struct TRINITY_DLL_DECL npc_mirror_image : SpellCasterAI
{
npc_mirror_image(Creature *c) : SpellAI(c) {Reset();}
npc_mirror_image(Creature *c) : SpellCasterAI(c) {}
void Reset()
void InitializeAI()
{
SpellCasterAI::InitializeAI();
Unit * owner = me->GetOwner();
if (!owner)
return;
@@ -1656,43 +1657,7 @@ struct TRINITY_DLL_DECL npc_mirror_image : SpellAI
owner->CastSpell(me, 45204, false);
}
void 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)
{
uint32 cooldown = GetAISpellInfo(*itr)->cooldown;
if (count == spell)
{
DoCast(spells[spell]);
cooldown += me->GetCurrentSpellCastTime(*itr);
}
events.ScheduleEvent(*itr, cooldown);
}
}
void 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)->cooldown);
}
}
// Do not reload creature templates on evade mode enter - prevent visual lost
void EnterEvadeMode()
{
if(me->IsInEvadeMode() || !me->isAlive())
@@ -1707,7 +1672,6 @@ struct TRINITY_DLL_DECL npc_mirror_image : SpellAI
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, m_creature->GetFollowAngle(), MOTION_SLOT_ACTIVE);
}
}
};
CreatureAI* GetAI_npc_mirror_image(Creature *_Creature)

View File

@@ -91,3 +91,58 @@ void SpellAI::UpdateAI(const uint32 diff)
else
DoMeleeAttackIfReady();
}
void SpellCasterAI::InitializeAI()
{
SpellAI::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 SpellCasterAI::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 SpellCasterAI::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);
}
}

View File

@@ -53,4 +53,16 @@ class TRINITY_DLL_SPEC SpellAI : public CreatureAI
SpellVct spells;
};
class TRINITY_DLL_SPEC SpellCasterAI : public SpellAI
{
public:
explicit SpellCasterAI(Creature *c) : SpellAI(c) {m_attackDist = MELEE_RANGE;}
void InitializeAI();
void AttackStart(Unit * victim){SpellAI::AttackStartCaster(victim, m_attackDist);}
void UpdateAI(const uint32 diff);
void EnterCombat(Unit *who);
private:
float m_attackDist;
};
#endif

View File

@@ -246,10 +246,13 @@ enum AICondition
struct AISpellInfoType
{
AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {}
AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT)
, cooldown(AI_DEFAULT_COOLDOWN), realCooldown(0), maxRange(0.0f){}
AITarget target;
AICondition condition;
uint32 cooldown;
uint32 realCooldown;
float maxRange;
};
TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i);

View File

@@ -542,7 +542,6 @@ Map::Add(T *obj)
//also, trigger needs to cast spell, if not update, cannot see visual
//if(obj->GetTypeId() != TYPEID_UNIT)
UpdateObjectVisibility(obj,cell,p);
AddNotifier(obj);
}

View File

@@ -6856,7 +6856,6 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties
TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster);
if(!summon)
return;
if(summon->HasSummonMask(SUMMON_MASK_GUARDIAN))
((Guardian*)summon)->InitStatsForLevel(level);

View File

@@ -11491,10 +11491,6 @@ Unit* Creature::SelectVictim()
//next-victim-selection algorithm and evade mode are called
//threat list sorting etc.
//This should not be called by unit who does not have a threatlist
//or who does not have threat (totem/pet/critter)
//otherwise enterevademode every update
Unit* target = NULL;
// First checking if we have some taunt on us
const AuraEffectList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT);

View File

@@ -325,6 +325,10 @@ void UnitAI::FillAISpellInfo()
}
}
}
AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime;
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
if (srange)
AIInfo->maxRange = srange->maxRangeHostile * 3 / 4;
}
}