diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/scripts/ScriptMgr.cpp | 2 | ||||
-rw-r--r-- | src/bindings/scripts/include/sc_creature.cpp | 79 | ||||
-rw-r--r-- | src/bindings/scripts/include/sc_creature.h | 4 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp | 361 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp | 8 | ||||
-rw-r--r-- | src/game/AggressorAI.cpp | 2 | ||||
-rw-r--r-- | src/game/Creature.cpp | 3 | ||||
-rw-r--r-- | src/game/CreatureAI.cpp | 55 | ||||
-rw-r--r-- | src/game/CreatureAI.h | 3 | ||||
-rw-r--r-- | src/game/Unit.cpp | 2 |
10 files changed, 441 insertions, 78 deletions
diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp index 4d7ed09fff4..849c4d64be5 100644 --- a/src/bindings/scripts/ScriptMgr.cpp +++ b/src/bindings/scripts/ScriptMgr.cpp @@ -389,6 +389,7 @@ extern void AddSC_boss_sapphiron(); extern void AddSC_boss_four_horsemen(); extern void AddSC_boss_faerlina(); extern void AddSC_boss_heigan(); +extern void AddSC_boss_gothik(); extern void AddSC_instance_naxxramas(); //Netherstorm @@ -1327,6 +1328,7 @@ void ScriptsInit(char const* cfg_file = "trinitycore.conf") AddSC_boss_sapphiron(); AddSC_boss_four_horsemen(); AddSC_boss_heigan(); + AddSC_boss_gothik(); AddSC_instance_naxxramas(); //Netherstorm diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index 0b874773ffc..e575e40fac1 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -17,13 +17,26 @@ struct TSpellSummary { uint8 Effects; // set of enum SelectEffect } *SpellSummary; +void SummonList::DoZoneInCombat(uint32 entry) +{ + for(iterator i = begin(); i != end();) + { + Creature *summon = Unit::GetCreature(*m_creature, *i); + ++i; + if(summon && summon->IsAIEnabled + && (!entry || summon->GetEntry() == entry)) + summon->AI()->DoZoneInCombat(); + } +} + void SummonList::DoAction(uint32 entry, uint32 info) { for(iterator i = begin(); i != end();) { Creature *summon = Unit::GetCreature(*m_creature, *i); ++i; - if(summon && summon->IsAIEnabled) + if(summon && summon->IsAIEnabled + && (!entry || summon->GetEntry() == entry)) summon->AI()->DoAction(info); } } @@ -213,6 +226,19 @@ Creature* ScriptedAI::DoSpawnCreature(uint32 id, float x, float y, float z, floa return m_creature->SummonCreature(id,m_creature->GetPositionX() + x,m_creature->GetPositionY() + y,m_creature->GetPositionZ() + z, angle, (TempSummonType)type, despawntime); } +Creature *ScriptedAI::DoSummon(uint32 entry, const float pos[4], uint32 despawntime, TempSummonType type) +{ + return me->SummonCreature(entry, pos[0], pos[1], pos[2], pos[3], type, despawntime); +} + +Creature *ScriptedAI::DoSummon(uint32 entry, WorldObject *obj, float radius, uint32 despawntime, TempSummonType type) +{ + float x, y, z; + obj->GetGroundPointAroundUnit(x, y, z, radius * rand_norm(), rand_norm()*2*M_PI); + return me->SummonCreature(entry, x, y, z, me->GetOrientation(), type, despawntime); +} + + Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position) { //ThreatList m_threatlist; @@ -493,6 +519,11 @@ void ScriptedAI::DoTeleportTo(float x, float y, float z, uint32 time) m_creature->SendMonsterMove(x, y, z, time); } +void ScriptedAI::DoTeleportTo(const float pos[4]) +{ + me->NearTeleportTo(pos[0], pos[1], pos[2], pos[3]); +} + void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float x, float y, float z, float o) { if(!pUnit || pUnit->GetTypeId() != TYPEID_PLAYER) @@ -642,7 +673,8 @@ void BossAI::_EnterCombat() void BossAI::JustSummoned(Creature *summon) { summons.Summon(summon); - DoZoneInCombat(summon); + if(me->isInCombat()) + DoZoneInCombat(summon); } void BossAI::SummonedCreatureDespawn(Creature *summon) @@ -667,25 +699,36 @@ void LoadOverridenSQLData() goInfo->trap.radius = 50; } -#define SPELL(x) const_cast<SpellEntry*>(GetSpellStore()->LookupEntry(x)) - void LoadOverridenDBCData() { SpellEntry *spellInfo; - - // Black Temple : Illidan : Parasitic Shadowfiend Passive - if(spellInfo = SPELL(41913)) - spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends - - //temp, not needed in 310 - if(spellInfo = SPELL(28531)) - { - spellInfo->DurationIndex = 21; - spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA_ENEMY; - } - if(spellInfo = SPELL(55799)) + for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) { - spellInfo->DurationIndex = 21; - spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA_ENEMY; + spellInfo = (SpellEntry*)GetSpellStore()->LookupEntry(i); + if(!spellInfo) + continue; + + switch(i) + { + // Black Temple : Illidan : Parasitic Shadowfiend Passive + case 41013: + spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends + break; + //temp, not needed in 310 + case 28531: + case 55799: + spellInfo->DurationIndex = 21; + spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA_ENEMY; + break; + // Naxxramas: Gothik : Inform Inf range + case 27892: + case 27928: + case 27935: + case 27915: + case 27931: + case 27937: + spellInfo->rangeIndex = 13; + break; + } } } diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h index 0fb716bbe0e..80016619e8b 100644 --- a/src/bindings/scripts/include/sc_creature.h +++ b/src/bindings/scripts/include/sc_creature.h @@ -23,6 +23,7 @@ class SummonList : private std::list<uint64> void DespawnEntry(uint32 entry); void DespawnAll(); void DoAction(uint32 entry, uint32 info); + void DoZoneInCombat(uint32 entry = 0); private: Creature *m_creature; }; @@ -152,6 +153,7 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI void DoModifyThreatPercent(Unit *pUnit, int32 pct); void DoTeleportTo(float x, float y, float z, uint32 time = 0); + void DoTeleportTo(const float pos[4]); void DoAction(const int32 param) {} @@ -170,6 +172,8 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI //Spawns a creature relative to m_creature Creature* DoSpawnCreature(uint32 id, float x, float y, float z, float angle, uint32 type, uint32 despawntime); + Creature *DoSummon(uint32 entry, const float pos[4], uint32 despawntime = 30000, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN); + Creature *DoSummon(uint32 entry, WorldObject *obj, float radius = 5.0f, uint32 despawntime = 30000, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN); //Selects a unit from the creature's current aggro list Unit* SelectUnit(SelectAggroTarget target, uint32 position); diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp index 3a9c6a5b47a..7def6c370f4 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* 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 @@ -14,14 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Gothik -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" #define SAY_SPEECH -1533040 #define SAY_KILL -1533041 @@ -29,37 +23,336 @@ EndScriptData */ #define SAY_TELEPORT -1533043 //Gothik -#define SPELL_HARVESTSOUL 28679 -#define SPELL_SHADOWBOLT HEROIC(29317,56405) -#define SPELL_SOUL_SIPHON 43591 // cannot find the correct spell +#define SPELL_HARVEST_SOUL 28679 +#define SPELL_SHADOW_BOLT HEROIC(29317,56405) + +#define SPELL_INFORM_LIVE_TRAINEE 27892 +#define SPELL_INFORM_LIVE_KNIGHT 27928 +#define SPELL_INFORM_LIVE_RIDER 27935 +#define SPELL_INFORM_DEAD_TRAINEE 27915 +#define SPELL_INFORM_DEAD_KNIGHT 27931 +#define SPELL_INFORM_DEAD_RIDER 27937 + +#define MOB_LIVE_TRAINEE 16124 +#define MOB_LIVE_KNIGHT 16125 +#define MOB_LIVE_RIDER 16126 +#define MOB_DEAD_TRAINEE 16127 +#define MOB_DEAD_KNIGHT 16148 +#define MOB_DEAD_RIDER 16150 +#define MOB_DEAD_HORSE 16149 + +const struct Waves { uint32 entry, number, time; } +waves[] = +{ + {MOB_LIVE_TRAINEE, 2, 20000}, + {MOB_LIVE_TRAINEE, 2, 20000}, + {MOB_LIVE_TRAINEE, 2, 10000}, + {MOB_LIVE_KNIGHT, 1, 10000}, + {MOB_LIVE_TRAINEE, 2, 15000}, + {MOB_LIVE_KNIGHT, 1, 10000}, + {MOB_LIVE_TRAINEE, 2, 15000}, + {MOB_LIVE_TRAINEE, 2, 0}, + {MOB_LIVE_KNIGHT, 1, 10000}, + {MOB_LIVE_RIDER, 1, 10000}, + {MOB_LIVE_TRAINEE, 2, 5000}, + {MOB_LIVE_KNIGHT, 1, 15000}, + {MOB_LIVE_TRAINEE, 2, 0}, + {MOB_LIVE_RIDER, 1, 10000}, + {MOB_LIVE_KNIGHT, 2, 10000}, + {MOB_LIVE_TRAINEE, 2, 10000}, + {MOB_LIVE_RIDER, 1, 5000}, + {MOB_LIVE_KNIGHT, 1, 5000}, + {MOB_LIVE_TRAINEE, 2, 20000}, + {MOB_LIVE_TRAINEE, 2, 0}, + {MOB_LIVE_KNIGHT, 1, 0}, + {MOB_LIVE_RIDER, 1, 15000}, + {MOB_LIVE_TRAINEE, 2, 29000}, + {0, 0, 0}, +}; + +#define POS_Y_GATE -3360.78f + +enum Events +{ + EVENT_SUMMON = 1, + EVENT_HARVEST, + EVENT_BOLT, +}; + +#define POS_LIVE 3 +#define POS_DEAD 5 + +const float PosSummonLive[POS_LIVE][4] = +{ + {2669.7, -3430.9, 268.56, 1.6}, + {2692.0, -3430.9, 268.56, 1.6}, + {2714.1, -3430.9, 268.56, 1.6}, +}; + +const float PosSummonDead[POS_DEAD][4] = +{ + {2725.1, -3310.0, 268.85, 3.4}, + {2699.3, -3322.8, 268.60, 3.3}, + {2733.1, -3348.5, 268.84, 3.1}, + {2682.8, -3304.2, 268.85, 3.9}, + {2664.8, -3340.7, 268.23, 3.7}, +}; + +const float PosGround[4] = {2691.2, -3362.7, 267.68, 1.7}; +const float PosPlatform[4] = {2640.5, -3360.6, 285.26, 0}; + +struct TRINITY_DLL_DECL boss_gothikAI : public BossAI +{ + boss_gothikAI(Creature *c) : BossAI(c, BOSS_GOTHIK) {} + + uint32 waveCount; + std::vector<Creature*> liveTrigger; + std::vector<Creature*> deadTrigger; + + void Reset() + { + liveTrigger.clear(); + deadTrigger.clear(); + me->setActive(false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + me->SetReactState(REACT_PASSIVE); + _Reset(); + } + + void EnterCombat(Unit *who) + { + for(uint32 i = 0; i < POS_LIVE; ++i) + if(Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummonLive[i])) + liveTrigger.push_back(trigger); + for(uint32 i = 0; i < POS_DEAD; ++i) + if(Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummonDead[i])) + deadTrigger.push_back(trigger); + + if(liveTrigger.size() < POS_LIVE || deadTrigger.size() < POS_DEAD) + { + error_log("Script Gothik: cannot summon triggers!"); + EnterEvadeMode(); + return; + } + + _EnterCombat(); + me->setActive(true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + waveCount = 0; + events.ScheduleEvent(EVENT_SUMMON, 30000); + DoTeleportTo(PosPlatform); + DoScriptText(SAY_SPEECH, me); + if(instance) + instance->SetData(DATA_GOTHIK_GATE, 1); + } + + void JustSummoned(Creature *summon) + { + if(summon->GetEntry() == WORLD_TRIGGER) + summon->setActive(true); + else + { + summon->AI()->DoAction(me->HasReactState(REACT_PASSIVE) ? 1 : 0); + summon->AI()->EnterEvadeMode(); + } + summons.Summon(summon); + } + + void KilledUnit(Unit* victim) + { + if(!(rand()%5)) + DoScriptText(SAY_KILL, me); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + uint32 spellId = 0; + switch(spell->Id) + { + case SPELL_INFORM_LIVE_TRAINEE: spellId = SPELL_INFORM_DEAD_TRAINEE; break; + case SPELL_INFORM_LIVE_KNIGHT: spellId = SPELL_INFORM_DEAD_KNIGHT; break; + case SPELL_INFORM_LIVE_RIDER: spellId = SPELL_INFORM_DEAD_RIDER; break; + } + if(spellId && me->isInCombat()) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_SPELLCAST); + me->CastSpell(deadTrigger[rand()%POS_DEAD], spellId, true); + } + } + + void SpellHitTarget(Unit *target, const SpellEntry *spell) + { + if(!me->isInCombat()) + return; + + switch(spell->Id) + { + case SPELL_INFORM_DEAD_TRAINEE: DoSummon(MOB_DEAD_TRAINEE, target, 0); break; + case SPELL_INFORM_DEAD_KNIGHT: DoSummon(MOB_DEAD_KNIGHT, target, 0); break; + case SPELL_INFORM_DEAD_RIDER: DoSummon(MOB_DEAD_RIDER, target, 1.0f); + DoSummon(MOB_DEAD_HORSE, target, 1.0f); break; + } + } + + void UpdateAI(const uint32 diff) + { + if(!me->isInCombat()) + return; + + if(me->getThreatManager().isThreatListEmpty()) + { + EnterEvadeMode(); + return; + } + + if(me->HasReactState(REACT_AGGRESSIVE) && !UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SUMMON: + if(waves[waveCount].entry) + { + for(uint32 i = 0; i < waves[waveCount].number; ++i) + DoSummon(waves[waveCount].entry, liveTrigger[rand()%POS_LIVE], 1.0f); + events.ScheduleEvent(EVENT_SUMMON, waves[waveCount].time); + ++waveCount; + } + else + { + DoScriptText(SAY_TELEPORT, me); + DoTeleportTo(PosGround); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + if(instance) + instance->SetData(DATA_GOTHIK_GATE, 0); + summons.DoAction(0, 0); + summons.DoZoneInCombat(); + events.ScheduleEvent(EVENT_BOLT, 1000); + events.ScheduleEvent(EVENT_HARVEST, 15000); + } + break; + case EVENT_BOLT: + DoCast(me->getVictim(), SPELL_SHADOW_BOLT); + events.ScheduleEvent(EVENT_BOLT, 1000); + return; + case EVENT_HARVEST: + DoCast(me->getVictim(), SPELL_HARVEST_SOUL); + events.ScheduleEvent(EVENT_HARVEST, 15000); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_gothik_minionAI : public SpellAI +{ + mob_gothik_minionAI(Creature *c) : SpellAI(c) + { + liveSide = me->GetPositionY() < POS_Y_GATE; + } + + bool liveSide; + bool gateClose; + +#define SIDE_CHECK(who) (liveSide == (who->GetPositionY() < POS_Y_GATE)) + + void DoAction(const int32 param) + { + gateClose = param; + } + + void DamageTaken(Unit *attacker, uint32 &damage) + { + if(gateClose && !SIDE_CHECK(attacker)) + damage = 0; + } + + void JustDied(Unit *killer) + { + if(me->isSummon()) + { + if(Unit *owner = ((TempSummon*)me)->GetSummoner()) + SpellAI::JustDied(owner); + } + } + + void EnterEvadeMode() + { + if(!gateClose) + { + SpellAI::EnterEvadeMode(); + return; + } + + if(!_EnterEvadeMode()) + return; -//Unrelenting Trainee -#define SPELL_EAGLECLAW 30285 -#define SPELL_KNOCKDOWN_PASSIVE 6961 + Map *map = me->GetMap(); + if(map->IsDungeon()) + { + Map::PlayerList const &PlayerList = map->GetPlayers(); + for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if(i->getSource()->isAlive() && SIDE_CHECK(i->getSource())) + { + AttackStart(i->getSource()); + return; + } + } + } -//Unrelenting Deathknight -#define SPELL_CHARGE 22120 -#define SPELL_SHADOW_MARK 27825 + me->GetMotionMaster()->MoveIdle(); + Reset(); + } -//Unrelenting Rider -#define SPELL_UNHOLY_AURA 55606 -#define H_SPELL_UNHOLY_AURA 55608 -#define SPELL_SHADOWBOLT_VOLLEY 27831 //Search thru targets and find those who have the SHADOW_MARK to cast this on -#define H_SPELL_SHADOWBOLT_VOLLEY 55638 + void UpdateAI(const uint32 diff) + { + if(gateClose && (!SIDE_CHECK(me) || me->getVictim() && !SIDE_CHECK(me->getVictim()))) + { + EnterEvadeMode(); + return; + } -//Spectral Trainee -#define SPELL_ARCANE_EXPLOSION 27989 + SpellAI::UpdateAI(diff); + } +}; -//Spectral Deathknight -#define SPELL_WHIRLWIND 28334 -#define SPELL_SUNDER_ARMOR 25051 //cannot find sunder that reduces armor by 2950 -#define SPELL_CLEAVE 20677 -#define SPELL_MANA_BURN 17631 +CreatureAI* GetAI_boss_gothik(Creature *_Creature) +{ + return new boss_gothikAI (_Creature); +} -//Spectral Rider -#define SPELL_LIFEDRAIN 24300 -//USES SAME UNHOLY AURA AS UNRELENTING RIDER +CreatureAI* GetAI_mob_gothik_minion(Creature *_Creature) +{ + return new mob_gothik_minionAI (_Creature); +} -//Spectral Horse -#define SPELL_STOMP 27993 +void AddSC_boss_gothik() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gothik"; + newscript->GetAI = &GetAI_boss_gothik; + newscript->RegisterSelf(); + newscript = new Script; + newscript->Name="mob_gothik_minion"; + newscript->GetAI = &GetAI_mob_gothik_minion; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp index 23f44f5daf8..e5913660c3f 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp @@ -86,9 +86,10 @@ struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData LoadDoorData(doorData); } + std::set<Creature*> Worshipper; std::set<GameObject*> HeiganEruption[4]; + GameObject *GothikGate; Creature *Sapphiron; - std::set<Creature*> Worshipper; void OnCreatureCreate(Creature *creature, bool add) { @@ -114,6 +115,7 @@ struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData switch(go->GetEntry()) { case GO_BIRTH: if(!add && Sapphiron) Sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH); return; + case GO_GOTHIK_GATE: GothikGate = add ? go : NULL; break; } AddDoor(go, add); @@ -140,6 +142,10 @@ struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData case DATA_HEIGAN_ERUPT: HeiganErupt(value); break; + case DATA_GOTHIK_GATE: + if(GothikGate) + GothikGate->SetGoState(GOState(value)); + break; } } diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index 286138fc991..22ebe87cdc6 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -104,7 +104,7 @@ void SpellAI::UpdateAI(const uint32 diff) break; } } - me->CastSpell(target, spellId, false); + if(target) me->CastSpell(target, spellId, false); events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown); } else diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 85109997390..f322d8326e1 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -455,6 +455,9 @@ void Creature::Update(uint32 diff) } else { + // for delayed spells + m_Events.Update( diff ); + m_deathTimer -= diff; if (m_groupLootTimer && lootingGroupLeaderGUID) { diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index ea65d233a17..0864bc973ab 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -39,6 +39,9 @@ void CreatureAI::DoZoneInCombat(Creature* creature) if (!creature) creature = me; + if(!creature->CanHaveThreatList()) + return; + Map *map = creature->GetMap(); if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated { @@ -46,7 +49,7 @@ void CreatureAI::DoZoneInCombat(Creature* creature) return; } - if(!creature->getVictim()) + if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim()) { if(Unit *target = creature->SelectNearestTarget()) creature->AI()->AttackStart(target); @@ -54,29 +57,30 @@ void CreatureAI::DoZoneInCombat(Creature* creature) { if(Unit *summoner = ((TempSummon*)creature)->GetSummoner()) { - if(summoner->getVictim() - && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(summoner->getVictim()))) - creature->AI()->AttackStart(summoner->getVictim()); + Unit *target = summoner->getAttackerForHelper(); + if(!target && summoner->CanHaveThreatList() && !summoner->getThreatManager().isThreatListEmpty()) + target = summoner->getThreatManager().getHostilTarget(); + if(target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target))) + creature->AI()->AttackStart(target); } } } - if (!creature->CanHaveThreatList() || !creature->getVictim()) + if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim()) { - sLog.outError("DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? ((Creature*)creature)->GetEntry() : 0); + sLog.outError("DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry()); return; } Map::PlayerList const &PlayerList = map->GetPlayers(); for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { - if (Player* i_pl = i->getSource()) - if (i_pl->isAlive()) - { - creature->SetInCombatWith(i_pl); - i_pl->SetInCombatWith(creature); - creature->AddThreat(i_pl, 0.0f); - } + if (i->getSource()->isAlive()) + { + creature->SetInCombatWith(i->getSource()); + i->getSource()->SetInCombatWith(creature); + creature->AddThreat(i->getSource(), 0.0f); + } } } @@ -102,10 +106,10 @@ bool CreatureAI::UpdateVictim() return me->getVictim(); } -void CreatureAI::EnterEvadeMode() +bool CreatureAI::_EnterEvadeMode() { - if(me->IsInEvadeMode()) - return; + if(me->IsInEvadeMode() || !me->isAlive()) + return false; me->RemoveAllAuras(); me->DeleteThreatList(); @@ -113,13 +117,18 @@ void CreatureAI::EnterEvadeMode() me->LoadCreaturesAddon(); me->SetLootRecipient(NULL); - if(me->isAlive()) - { - if(Unit *owner = me->GetCharmerOrOwner()) - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE); - else - me->GetMotionMaster()->MoveTargetedHome(); - } + return true; +} + +void CreatureAI::EnterEvadeMode() +{ + if(!_EnterEvadeMode()) + return; + + if(Unit *owner = me->GetCharmerOrOwner()) + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE); + else + me->GetMotionMaster()->MoveTargetedHome(); Reset(); } diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index 605e904c71a..c46dd2a54f2 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -168,6 +168,9 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI static AISpellInfoType *AISpellInfo; static void FillAISpellInfo(); + + protected: + bool _EnterEvadeMode(); }; enum Permitions diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index f142ea623a5..66576396dfa 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -9958,7 +9958,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); if(enemy) { - if(!((Creature*)this)->HasReactState(REACT_PASSIVE) && ((Creature*)this)->IsAIEnabled) + if(((Creature*)this)->IsAIEnabled) ((Creature*)this)->AI()->EnterCombat(enemy); if(((Creature*)this)->GetFormation()) ((Creature*)this)->GetFormation()->MemberAttackStart((Creature*)this, enemy); |