*Update AI scripts. Use better default AI.

--HG--
branch : trunk
This commit is contained in:
megamage
2009-05-10 22:48:22 -05:00
parent 904300b4c2
commit 82f886e3c1
10 changed files with 219 additions and 104 deletions
+73 -76
View File
@@ -19,16 +19,9 @@
*/
#include "AggressorAI.h"
#include "Errors.h"
#include "Creature.h"
#include "ObjectAccessor.h"
#include "VMapFactory.h"
#include "World.h"
#include "SpellMgr.h"
#include <list>
int
AggressorAI::Permissible(const Creature *creature)
int AggressorAI::Permissible(const Creature *creature)
{
// have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
if( !creature->isCivilian() && !creature->IsNeutralToAll() )
@@ -37,79 +30,83 @@ AggressorAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
AggressorAI::AggressorAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
void AggressorAI::UpdateAI(const uint32 /*diff*/)
{
}
void AggressorAI::EnterEvadeMode()
{
if( !m_creature->isAlive() )
{
DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", m_creature->GetGUIDLow());
i_victimGuid = 0;
m_creature->CombatStop(true);
m_creature->DeleteThreatList();
return;
}
Unit* victim = ObjectAccessor::GetUnit(*m_creature, i_victimGuid );
if( !victim )
{
DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", m_creature->GetGUIDLow());
}
else if( !victim->isAlive() )
{
DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", m_creature->GetGUIDLow());
}
else if( victim->HasStealthAura() )
{
DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", m_creature->GetGUIDLow());
}
else if( victim->isInFlight() )
{
DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", m_creature->GetGUIDLow());
}
else
{
DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", m_creature->GetGUIDLow());
//i_state = STATE_LOOK_AT_VICTIM;
//i_tracker.Reset(TIME_INTERVAL_LOOK);
}
if(!m_creature->GetCharmerOrOwner())
{
m_creature->RemoveAllAuras();
// Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
if( m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
m_creature->GetMotionMaster()->MoveTargetedHome();
}
else if (m_creature->GetOwner() && m_creature->GetOwner()->isAlive())
m_creature->GetMotionMaster()->MoveFollow(m_creature->GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
m_creature->DeleteThreatList();
i_victimGuid = 0;
m_creature->CombatStop(true);
m_creature->SetLootRecipient(NULL);
}
void
AggressorAI::UpdateAI(const uint32 /*diff*/)
{
// update i_victimGuid if m_creature->getVictim() !=0 and changed
if(!UpdateVictim())
return;
i_victimGuid = m_creature->getVictim()->GetGUID();
DoMeleeAttackIfReady();
}
if( m_creature->isAttackReady() )
int SpellAI::Permissible(const Creature *creature)
{
return PERMIT_BASE_NO;
}
void SpellAI::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]);
}
void SpellAI::Reset()
{
events.Reset();
}
void SpellAI::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 SpellAI::EnterCombat(Unit *who)
{
for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
{
if( m_creature->IsWithinMeleeRange(m_creature->getVictim()))
{
m_creature->AttackerStateUpdate(m_creature->getVictim());
m_creature->resetAttackTimer();
}
if(AISpellInfo[*i].condition == AICOND_AGGRO)
me->CastSpell(who, *i, true);
else if(AISpellInfo[*i].condition == AICOND_COMBAT)
events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown);
}
}
void SpellAI::UpdateAI(const uint32 diff)
{
if(!UpdateVictim())
return;
events.Update(diff);
if(me->hasUnitState(UNIT_STAT_CASTING))
return;
if(uint32 spellId = events.ExecuteEvent())
{
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: target = SelectTarget(SELECT_TARGET_RANDOM); 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);
target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId);
break;
}
}
me->CastSpell(target, spellId, false);
events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown);
}
else
DoMeleeAttackIfReady();
}
+21 -17
View File
@@ -22,31 +22,35 @@
#define TRINITY_AGGRESSORAI_H
#include "CreatureAI.h"
#include "Timer.h"
#include "CreatureAIImpl.h"
class Creature;
class TRINITY_DLL_DECL AggressorAI : public CreatureAI
{
enum AggressorState
{
STATE_NORMAL = 1,
STATE_LOOK_AT_VICTIM = 2
};
public:
explicit AggressorAI(Creature *c);
void EnterEvadeMode();
explicit AggressorAI(Creature *c) : CreatureAI(c) {}
void UpdateAI(const uint32);
static int Permissible(const Creature *);
private:
uint64 i_victimGuid;
AggressorState i_state;
TimeTracker i_tracker;
};
#endif
typedef std::vector<uint32> SpellVct;
class TRINITY_DLL_DECL SpellAI : public CreatureAI
{
public:
explicit SpellAI(Creature *c) : CreatureAI(c) {}
void InitializeAI();
void Reset();
void EnterCombat(Unit* who);
void JustDied(Unit *killer);
void UpdateAI(const uint32 diff);
static int Permissible(const Creature *);
private:
EventMap events;
SpellVct spells;
};
#endif
+34 -4
View File
@@ -21,9 +21,8 @@
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "Creature.h"
#include "Player.h"
#include "Pet.h"
#include "World.h"
#include "SpellMgr.h"
//Disable CreatureAI when charmed
void CreatureAI::OnCharmed(bool apply)
@@ -261,16 +260,47 @@ void CreatureAI::FillAISpellInfo()
{
AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()];
AISpellInfoType *AIInfo = AISpellInfo;
const SpellEntry * spellInfo;
for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo)
{
spellInfo = GetSpellStore()->LookupEntry(i);
if (!spellInfo)
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;
for(uint32 j = 0; j < 3; ++j)
{
if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY
|| spellInfo->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY)
{
if(AIInfo->target < AITARGET_VICTIM)
AIInfo->target = AITARGET_VICTIM;
}
if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
{
if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY)
{
if(AIInfo->target < AITARGET_DEBUFF)
AIInfo->target = AITARGET_DEBUFF;
}
else if(IsPositiveSpell(i))
{
if(AIInfo->target < AITARGET_BUFF)
AIInfo->target = AITARGET_BUFF;
}
}
}
}
}
+1
View File
@@ -46,6 +46,7 @@ namespace AIRegistry
(new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf();
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
(new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf();
(new CreatureAIFactory<SpellAI>("SpellAI"))->RegisterSelf();
(new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf();
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
+12
View File
@@ -69,6 +69,18 @@ namespace FactorySelector
ai_factory = ai_registry.GetRegistryItem("CritterAI");
}
if(!ai_factory)
{
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{
if(creature->m_spells[i])
{
ai_factory = ai_registry.GetRegistryItem("SpellAI");
break;
}
}
}
// select by permit check
if(!ai_factory)
{
+3
View File
@@ -27,6 +27,7 @@
#include "Chat.h"
#include "Spell.h"
#include "BattleGroundMgr.h"
#include "CreatureAI.h"
bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS];
@@ -2520,6 +2521,8 @@ void SpellMgr::LoadSpellCustomAttr()
SummonPropertiesEntry *properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121));
properties->Type = SUMMON_TYPE_TOTEM;
CreatureAI::FillAISpellInfo();
}
void SpellMgr::LoadSpellLinked()
+11 -5
View File
@@ -11607,11 +11607,14 @@ void CharmInfo::InitPossessCreateSpells()
{
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{
uint32 spellid = ((Creature*)m_unit)->m_spells[i];
if(IsPassiveSpell(spellid))
m_unit->CastSpell(m_unit, spellid, true);
uint32 spellId = ((Creature*)m_unit)->m_spells[i];
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
spellId = 0;
if(IsPassiveSpell(spellId))
m_unit->CastSpell(m_unit, spellId, true);
else
AddSpellToAB(0, spellid, ACT_DISABLED);
AddSpellToAB(0, spellId, ACT_DISABLED);
}
}
}
@@ -11629,6 +11632,10 @@ void CharmInfo::InitCharmCreateSpells()
for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
{
uint32 spellId = ((Creature*)m_unit)->m_spells[x];
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
spellId = 0;
m_charmspells[x].spellId = spellId;
if(!spellId)
@@ -11643,7 +11650,6 @@ void CharmInfo::InitCharmCreateSpells()
{
ActiveStates newstate;
bool onlyselfcast = true;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
if(!spellInfo) onlyselfcast = false;
for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
+5 -2
View File
@@ -35,8 +35,11 @@ void UnitAI::AttackStart(Unit *victim)
void UnitAI::DoMeleeAttackIfReady()
{
if(me->hasUnitState(UNIT_STAT_CASTING))
return;
//Make sure our attack is ready and we aren't currently casting before checking distance
if (me->isAttackReady() && !me->hasUnitState(UNIT_STAT_CASTING))
if (me->isAttackReady())
{
//If we are within range melee the target
if (me->IsWithinMeleeRange(me->getVictim()))
@@ -45,7 +48,7 @@ void UnitAI::DoMeleeAttackIfReady()
me->resetAttackTimer();
}
}
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK) && !me->hasUnitState(UNIT_STAT_CASTING))
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
{
//If we are within range melee the target
if (me->IsWithinMeleeRange(me->getVictim()))