*Update AI scripts. Use better default AI.
--HG-- branch : trunk
This commit is contained in:
@@ -55,6 +55,7 @@ void SummonList::DespawnAll()
|
||||
else
|
||||
{
|
||||
erase(begin());
|
||||
summon->SetVisibility(VISIBILITY_OFF);
|
||||
summon->setDeathState(JUST_DIED);
|
||||
summon->RemoveCorpse();
|
||||
}
|
||||
@@ -634,6 +635,37 @@ void Scripted_NoMovementAI::AttackStart(Unit* who)
|
||||
}
|
||||
}
|
||||
|
||||
void BossAI::_Reset()
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
instance->SetBossState(bossId, NOT_STARTED);
|
||||
}
|
||||
|
||||
void BossAI::_JustDied()
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
instance->SetBossState(bossId, DONE);
|
||||
}
|
||||
|
||||
void BossAI::_EnterCombat()
|
||||
{
|
||||
DoZoneInCombat();
|
||||
instance->SetBossState(bossId, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void BossAI::JustSummoned(Creature *summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
|
||||
void BossAI::SummonedCreatureDespawn(Creature *summon)
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
#define GOBJECT(x) (const_cast<GameObjectInfo*>(GetGameObjectInfo(x)))
|
||||
|
||||
void LoadOverridenSQLData()
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
class ScriptedInstance;
|
||||
|
||||
class SummonList : private std::list<uint64>
|
||||
{
|
||||
public:
|
||||
@@ -216,5 +218,30 @@ struct TRINITY_DLL_DECL NullCreatureAI : public ScriptedAI
|
||||
void UpdateAI(const uint32) {}
|
||||
};
|
||||
|
||||
struct TRINITY_DLL_DECL BossAI : public ScriptedAI
|
||||
{
|
||||
BossAI(Creature *c, uint32 id) : ScriptedAI(c), bossId(id)
|
||||
, summons(me), instance((ScriptedInstance*)c->GetInstanceData())
|
||||
{}
|
||||
|
||||
uint32 bossId;
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
ScriptedInstance *instance;
|
||||
|
||||
void JustSummoned(Creature *summon);
|
||||
void SummonedCreatureDespawn(Creature *summon);
|
||||
|
||||
void UpdateAI(const uint32 diff) = 0;
|
||||
|
||||
void _Reset();
|
||||
void _EnterCombat();
|
||||
void _JustDied();
|
||||
|
||||
void Reset() { _Reset(); }
|
||||
void EnterCombat(Unit *who) { _EnterCombat(); }
|
||||
void JustDied(Unit *killer) { _JustDied(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+73
-76
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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()))
|
||||
|
||||
Reference in New Issue
Block a user