diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/scripts/include/sc_creature.cpp | 32 | ||||
-rw-r--r-- | src/bindings/scripts/include/sc_creature.h | 27 | ||||
-rw-r--r-- | src/game/AggressorAI.cpp | 125 | ||||
-rw-r--r-- | src/game/AggressorAI.h | 34 | ||||
-rw-r--r-- | src/game/CreatureAI.cpp | 38 | ||||
-rw-r--r-- | src/game/CreatureAIRegistry.cpp | 1 | ||||
-rw-r--r-- | src/game/CreatureAISelector.cpp | 12 | ||||
-rw-r--r-- | src/game/SpellMgr.cpp | 3 | ||||
-rw-r--r-- | src/game/Unit.cpp | 16 | ||||
-rw-r--r-- | src/game/UnitAI.cpp | 7 |
10 files changed, 205 insertions, 90 deletions
diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index 42ee15074ed..e5a6eb958e0 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -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() diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h index 8336df545b6..26bf5fb400b 100644 --- a/src/bindings/scripts/include/sc_creature.h +++ b/src/bindings/scripts/include/sc_creature.h @@ -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 diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index a637e7e40f0..286138fc991 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -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*/) { + if(!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); } -void AggressorAI::EnterEvadeMode() +int SpellAI::Permissible(const Creature *creature) { - 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; - } + return PERMIT_BASE_NO; +} - Unit* victim = ObjectAccessor::GetUnit(*m_creature, i_victimGuid ); +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]); +} - 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); - } +void SpellAI::Reset() +{ + events.Reset(); +} - if(!m_creature->GetCharmerOrOwner()) - { - m_creature->RemoveAllAuras(); +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); +} - // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead - if( m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE ) - m_creature->GetMotionMaster()->MoveTargetedHome(); +void SpellAI::EnterCombat(Unit *who) +{ + for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + { + 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); } - 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*/) +void SpellAI::UpdateAI(const uint32 diff) { - // update i_victimGuid if m_creature->getVictim() !=0 and changed if(!UpdateVictim()) return; - i_victimGuid = m_creature->getVictim()->GetGUID(); + events.Update(diff); - if( m_creature->isAttackReady() ) + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(uint32 spellId = events.ExecuteEvent()) { - if( m_creature->IsWithinMeleeRange(m_creature->getVictim())) + Unit *target = NULL; + //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target); + switch(AISpellInfo[spellId].target) { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); + 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(); } - diff --git a/src/game/AggressorAI.h b/src/game/AggressorAI.h index 983498716e6..94a6b0b3bf1 100644 --- a/src/game/AggressorAI.h +++ b/src/game/AggressorAI.h @@ -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 *); +}; + +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: - uint64 i_victimGuid; - AggressorState i_state; - TimeTracker i_tracker; + EventMap events; + SpellVct spells; }; -#endif +#endif diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index 011ffab22e5..123fa1182a1 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -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; + } + } } } } diff --git a/src/game/CreatureAIRegistry.cpp b/src/game/CreatureAIRegistry.cpp index fc7130b0913..162ebd9b47c 100644 --- a/src/game/CreatureAIRegistry.cpp +++ b/src/game/CreatureAIRegistry.cpp @@ -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(); diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index b270de289c7..bac4f3a4973 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -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) { diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index a23f32d1a52..9b1cb798849 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -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() diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 3f09eec9351..28d2fbd619b 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -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 diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp index 4914bd36b7c..c991c75603d 100644 --- a/src/game/UnitAI.cpp +++ b/src/game/UnitAI.cpp @@ -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())) |