Documentos de Académico
Documentos de Profesional
Documentos de Cultura
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright
information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "npc_stave_of_ancients.h"
#include "CreatureGroups.h"
#include "GameTime.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "Spell.h"
bool NPCStaveQuestAI::InNormalForm()
{
return me->GetEntry() == GetFormEntry("normal");
}
void NPCStaveQuestAI::RevealForm()
{
if (encounterStarted && InNormalForm())
{
me->UpdateEntry(GetFormEntry("evil"));
me->SetFullHealth();
me->DespawnOrUnsummon(900000);
}
}
void NPCStaveQuestAI::StorePlayerGUID()
{
if (!playerGUID.IsEmpty())
{
return;
}
Player* NPCStaveQuestAI::GetGossipPlayer()
{
return ObjectAccessor::GetPlayer(*me, gossipPlayerGUID);
}
if (unit->IsPlayer())
{
if (playerGUID != unit->GetGUID())
{
return true;
}
}
else
{
if (unit->GetOwnerGUID() != playerGUID)
{
// if a creature attacking isn't owned by the player its unfair
return true;
}
else if (!IsAllowedEntry(unit->GetEntry()))
{
// if not in the whitelist its unfair
return true;
}
}
return false;
}
bool NPCStaveQuestAI::IsFairFight()
{
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr
!= threatList.end(); ++itr)
{
Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
if (!(*itr)->getThreat())
{
// if target threat is 0 its fair, this prevents despawn in the case
when
// there is a bystander since UpdateVictim adds nearby enemies to the
threatlist
continue;
}
if (UnitIsUnfair(unit))
{
return false;
}
}
return true;
}
bool NPCStaveQuestAI::ValidThreatlist()
{
if (threatList.size() == 1)
{
return true;
}
return isFair;
}
void NPCStaveQuestAI::SetHomePosition()
{
Position homePosition = me->GetPosition();
if (homePosition.IsPositionValid())
{
me->SetHomePosition(homePosition);
}
}
void NPCStaveQuestAI::PrepareForEncounter()
{
encounterStarted = true;
me->GetMotionMaster()->MoveIdle();
me->GetMotionMaster()->Clear();
SetHomePosition();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
return true;
}
if (InNormalForm())
{
me->m_Events.KillAllEvents(true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
me->RemoveAura(aura);
}
void NPCStaveQuestAI::EvadeOnFeignDeath()
{
Player* player = ObjectAccessor::GetPlayer(*me, playerGUID);
if (player && player->HasAura(SPELL_FEIGN_DEATH))
{
EnterEvadeMode();
}
}
ScriptedAI::AttackStart(target);
}
EventMap events;
if (InNormalForm())
{
return;
}
if (UpdateVictim())
{
// This should prevent hunters from staying in combat when feign
death is used and there is a bystander with 0 threat
EvadeOnFeignDeath();
}
else
{
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
// In combat events
switch (eventId)
{
case EVENT_FOOLS_PLIGHT:
if (UnitIsUnfair(me->GetVictim()) || !QuestIncomplete(me-
>GetVictim(), ARTORIUS_HEAD))
{
me->CastSpell(me->GetVictim(), SPELL_FOOLS_PLIGHT, true);
}
events.RepeatEvent(urand(3000, 6000));
break;
case EVENT_RANGE_CHECK:
if (!me->GetVictim() || !me->GetVictim()->IsWithinDist2d(me,
60.0f))
{
EnterEvadeMode();
}
else
{
events.RepeatEvent(2000);
}
break;
case EVENT_UNFAIR_FIGHT:
if (!ValidThreatlist())
{
SetHomePosition();
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE |
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
me->SetImmuneToAll(true);
me->DespawnOrUnsummon(5000);
break;
}
events.RepeatEvent(2000);
break;
case ARTORIUS_EVENT_DEMONIC_DOOM:
if (!me->GetVictim()->HasAura(ARTORIUS_SPELL_DEMONIC_DOOM))
{
me->CastSpell(me->GetVictim(), ARTORIUS_SPELL_DEMONIC_DOOM,
false);
}
events.RepeatEvent(urand(5000, 10000));
break;
case ARTORIUS_EVENT_DEMONIC_ENRAGE:
me->CastSpell(me, SPELL_DEMONIC_ENRAGE, false);
events.RepeatEvent(urand(22000, 39000));
break;
}
DoMeleeAttackIfReady();
}
if (!InNormalForm())
{
bool applyAura = std::find(std::begin(serpentStings),
std::end(serpentStings), Spell->Id) != std::end(serpentStings);
if (applyAura)
{
me->AddAura(ARTORIUS_SPELL_STINGING_TRAUMA, me);
me->TextEmote(ARTORIUS_WEAKNESS_EMOTE);
}
}
}
return true;
}
return true;
}
};
EventMap events;
bool flaggedForDespawn;
DoMeleeAttackIfReady();
}
void FlagForDespawn()
{
flaggedForDespawn = true;
}
};
};
EventMap events;
ObjectGuid preciousGUID;
void SetPreciousGUID()
{
if (CreatureGroup* formation = me->GetFormation())
{
const CreatureGroup::CreatureGroupMemberType& members = formation-
>GetMembers();
for (CreatureGroup::CreatureGroupMemberType::const_iterator itr =
members.begin(); itr != members.end(); ++itr)
{
if (itr->first && itr->first->GetOriginalEntry() ==
PRECIOUS_NORMAL_ENTRY)
{
preciousGUID = itr->first->GetGUID();
}
}
}
}
Creature* Precious()
{
if (preciousGUID.IsEmpty())
{
SetPreciousGUID();
}
if (!preciousGUID.IsEmpty())
{
return ObjectAccessor::GetCreature(*me, preciousGUID);
}
return nullptr;
}
npc_precious::npc_preciousAI* PreciousAI()
{
if (Precious())
{
return CAST_AI(npc_precious::npc_preciousAI, Precious()->AI());
}
return nullptr;
}
void RespawnPet()
{
Position current = me->GetNearPosition(-5.0f, 0.0f);
Precious()->RemoveCorpse(false, false);
Precious()->SetPosition(current);
Precious()->SetHomePosition(current);
Precious()->setDeathState(JUST_RESPAWNED);
Precious()->UpdateObjectVisibility(true);
}
void HandlePetRespawn()
{
if (Precious() && Precious()->isDead())
{
RespawnPet();
}
}
if (!Precious())
{
return;
}
if (Precious()->isDead())
{
// Make it so that Precious respawns after Simone
uint32 respawnTime = me->GetRespawnTime() -
GameTime::GetGameTime().count();
Precious()->SetRespawnTime(respawnTime);
return;
}
if (petResetPos.IsPositionValid())
{
Precious()->SetHomePosition(petResetPos);
}
}
void CorpseRemoved(uint32& /*respawnDelay*/) override
{
if (!Precious())
{
return;
}
if (Precious()->IsInCombat())
{
// If Simone corpse is removed but pet is InCombat, EnterEvadeMode
and auto despawn on pet reaching home
PreciousAI()->EnterEvadeMode();
PreciousAI()->FlagForDespawn();
}
else
{
Precious()->DespawnOrUnsummon(0);
}
}
events.ScheduleEvent(SIMONE_EVENT_CHECK_PET_STATE, 2000);
}
if (!InNormalForm())
{
if (victim && (UnitIsUnfair(victim) || !QuestIncomplete(victim,
SIMONE_HEAD)))
{
me->CastSpell(victim, SPELL_FOOLS_PLIGHT, true);
}
events.ScheduleEvent(EVENT_RANGE_CHECK, 1000);
events.ScheduleEvent(EVENT_UNFAIR_FIGHT, 1000);
events.ScheduleEvent(SIMONE_EVENT_CHAIN_LIGHTNING, 3000);
events.ScheduleEvent(SIMONE_EVENT_TEMPTRESS_KISS, 1000);
}
events.ScheduleEvent(SIMONE_EVENT_CHECK_PET_STATE, 1000);
}
break;
}
if (UpdateVictim())
{
// This should prevent hunters from staying in combat when feign
death is used and there is a bystander with 0 threat
EvadeOnFeignDeath();
}
else
{
return;
}
// In combat events
switch (eventId)
{
case EVENT_FOOLS_PLIGHT:
if (InNormalForm() || UnitIsUnfair(me->GetVictim()) || !
QuestIncomplete(me->GetVictim(), SIMONE_HEAD))
{
me->CastSpell(me->GetVictim(), SPELL_FOOLS_PLIGHT, true);
}
events.RepeatEvent(urand(3000, 6000));
break;
case EVENT_RANGE_CHECK:
if (!me->GetVictim()->IsWithinDist2d(me, 60.0f))
{
EnterEvadeMode();
}
else
{
events.RepeatEvent(2000);
}
break;
case EVENT_UNFAIR_FIGHT:
if (!ValidThreatlist() || (PreciousAI() && !PreciousAI()-
>ValidThreatlist()))
{
SetHomePosition();
PreciousAI()->SetHomePosition();
Precious()->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE |
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
Precious()->SetImmuneToAll(true);
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE |
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
me->SetImmuneToAll(true);
Precious()->DespawnOrUnsummon(5000);
me->DespawnOrUnsummon(5000);
break;
}
events.RepeatEvent(2000);
break;
case SIMONE_EVENT_CHAIN_LIGHTNING:
me->CastSpell(me->GetVictim(), SIMONE_SPELL_CHAIN_LIGHTNING,
false);
events.RepeatEvent(7000);
break;
case SIMONE_EVENT_TEMPTRESS_KISS:
me->CastSpell(me->GetVictim(), SIMONE_SPELL_TEMPTRESS_KISS,
false);
events.RepeatEvent(45000);
break;
}
DoMeleeAttackIfReady();
}
return true;
}
return true;
}
};
EventMap events;
bool shouldDespawn;
if (me->IsInCombat())
{
summon->AI()->AttackStart(me->GetVictim());
}
}
me->RemoveAllMinionsByEntry(CREEPING_DOOM_ENTRY);
}
if (InNormalForm())
{
return;
}
if (encounterStarted)
{
me->CastSpell(me, NELSON_SPELL_SOUL_FLAME, true);
}
if (UpdateVictim())
{
// This should prevent hunters from staying in combat when feign
death is used and there is a bystander with 0 threat
EvadeOnFeignDeath();
}
else
{
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
events.RepeatEvent(1000);
return;
}
// In combat events
switch (eventId)
{
case EVENT_FOOLS_PLIGHT:
if (UnitIsUnfair(me->GetVictim()) || !QuestIncomplete(me-
>GetVictim(), NELSON_HEAD))
{
me->CastSpell(me->GetVictim(), SPELL_FOOLS_PLIGHT, true);
}
events.RepeatEvent(urand(3000, 6000));
break;
case EVENT_RANGE_CHECK:
if (!me->GetVictim()->IsWithinDist2d(me, 60.0f))
{
EnterEvadeMode();
}
else
{
events.RepeatEvent(2000);
}
break;
case EVENT_UNFAIR_FIGHT:
if (!ValidThreatlist() || shouldDespawn)
{
SetHomePosition();
me->RemoveAllMinionsByEntry(CREEPING_DOOM_ENTRY);
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE |
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
me->SetImmuneToAll(true);
me->CombatStop(true);
me->Say(NELSON_DESPAWN_SAY);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
me->DespawnOrUnsummon(5000);
break;
}
events.RepeatEvent(2000);
break;
case NELSON_EVENT_DREADFUL_FRIGHT:
me->CastSpell(me->GetVictim(), NELSON_SPELL_DREADFUL_FRIGHT,
false);
events.RepeatEvent(urand(12000, 19000));
break;
case NELSON_EVENT_CREEPING_DOOM:
me->CastSpell(me->GetVictim(), NELSON_SPELL_CREEPING_DOOM,
false);
events.RepeatEvent(urand(10000, 12000));
break;
}
DoMeleeAttackIfReady();
}
return true;
}
return true;
}
};
EventMap events;
if (!InNormalForm())
{
if (victim && (UnitIsUnfair(victim) || !QuestIncomplete(victim,
FRANKLIN_HEAD)))
{
me->CastSpell(victim, SPELL_FOOLS_PLIGHT, true);
}
events.ScheduleEvent(FRANKLIN_EVENT_DEMONIC_ENRAGE, urand(9000,
13000));
events.ScheduleEvent(EVENT_RANGE_CHECK, 1000);
events.ScheduleEvent(EVENT_UNFAIR_FIGHT, 1000);
}
if (UpdateVictim())
{
// This should prevent hunters from staying in combat when feign
death is used and there is a bystander with 0 threat
EvadeOnFeignDeath();
}
else
{
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
events.RepeatEvent(1000);
return;
}
// In combat events
switch (eventId)
{
case EVENT_FOOLS_PLIGHT:
if (InNormalForm() || UnitIsUnfair(me->GetVictim()) || !
QuestIncomplete(me->GetVictim(), FRANKLIN_HEAD))
{
me->CastSpell(me->GetVictim(), SPELL_FOOLS_PLIGHT, true);
}
events.RepeatEvent(urand(3000, 6000));
break;
case EVENT_RANGE_CHECK:
if (!me->GetVictim()->IsWithinDist2d(me, 60.0f))
{
EnterEvadeMode();
}
else
{
events.RepeatEvent(2000);
}
break;
case EVENT_UNFAIR_FIGHT:
if (!ValidThreatlist())
{
SetHomePosition();
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE |
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
me->SetImmuneToAll(true);
me->CombatStop(true);
me->Say(FRANKLIN_DESPAWN_SAY);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
me->DespawnOrUnsummon(5000);
break;
}
events.RepeatEvent(2000);
break;
case FRANKLIN_EVENT_DEMONIC_ENRAGE:
me->CastSpell(me, SPELL_DEMONIC_ENRAGE, false);
me->TextEmote(FRANKLIN_ENRAGE_EMOTE);
events.RepeatEvent(urand(9000, 22000));
break;
}
DoMeleeAttackIfReady();
}
if (Spell->Id == FRANKLIN_WEAKNESS_SCORPID_STING)
{
me->CastSpell(me, FRANKLIN_SPELL_ENTROPIC_STING, false);
}
}
void ScheduleEncounterStart(ObjectGuid playerGUID)
{
PrepareForEncounter();
gossipPlayerGUID = playerGUID;
events.ScheduleEvent(EVENT_ENCOUNTER_START, 5000);
}
};
return true;
}
return true;
}
};
void AddSC_npc_stave_of_ancients()
{
new npc_artorius();
new npc_precious();
new npc_simone();
new npc_nelson();
new npc_franklin();
}