/* Copyright (C) 2006,2007 ScriptDev2
* 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
* (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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../../sc_defines.h"
#include "../../../../../game/TargetedMovementGenerator.h"
#include "../../../../../game/SpellAuras.h"
//Spells
#define SPELL_ACID_GEYSER 40630
#define SPELL_ACIDIC_WOUND 40481
#define SPELL_ARCING_SMASH 40599
#define SPELL_BLOODBOIL 42005 // This spell is AoE whereas it shouldn't
#define SPELL_FEL_ACID 40508
#define SPELL_FEL_RAGE_SELF 40594
#define SPELL_FEL_RAGE_TARGET 40604
#define SPELL_FEL_RAGE_2 40616
#define SPELL_FEL_RAGE_3 41625
#define SPELL_KNOCKBACK 38576
#define SPELL_TAUNT_GURTOGG 40603
#define SPELL_INSIGNIFIGANCE 40618
//Speech'n'Sound
#define SAY_AGGRO "Horde will crush you!"
#define SOUND_AGGRO 11432
#define SAY_SLAY1 "Time to feast!"
#define SOUND_SLAY1 11433
#define SAY_SLAY2 "More! I want more!"
#define SOUND_SLAY2 11434
#define SAY_SPECIAL1 "Drink your blood! Eat your flesh!"
#define SOUND_SPECIAL1 11435
#define SAY_SPECIAL2 "I hunger!"
#define SOUND_SPECIAL2 11436
#define SAY_ENRAGE "I'll rip the meat from your bones!"
#define SOUND_ENRAGE 11437
#define SOUND_DEATH 11439
//This is used to sort the players by distance in preparation for the Bloodboil cast.
struct TargetDistanceOrder : public std::binary_function
{
const Unit* MainTarget;
TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {};
// functor for operator ">"
bool operator()(const Unit* _Left, const Unit* _Right) const
{
return (MainTarget->GetDistanceSq(_Left) > MainTarget->GetDistanceSq(_Right));
}
};
struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI
{
boss_gurtogg_bloodboilAI(Creature *c) : ScriptedAI(c)
{
pInstance = ((ScriptedInstance*)c->GetInstanceData());
SetVariables();
}
ScriptedInstance* pInstance;
uint32 BloodboilTimer;
uint32 BloodboilCount;
uint32 AcidGeyserTimer;
uint32 AcidicWoundTimer;
uint32 ArcingSmashTimer;
uint32 EnrageTimer;
uint32 FelAcidTimer;
uint32 KnockbackTimer;
uint32 PhaseChangeTimer;
bool Phase1;
bool InCombat;
void SetVariables()
{
if(pInstance)
pInstance->SetData("GurtoggBloodboilEvent", 0);
BloodboilTimer = 10000;
BloodboilCount = 0;
AcidGeyserTimer = 1000;
AcidicWoundTimer = 6000;
ArcingSmashTimer = 19000;
EnrageTimer = 600000;
FelAcidTimer = 25000;
KnockbackTimer = 10000;
PhaseChangeTimer = 60000;
InCombat = false;
Phase1 = true;
}
void EnterEvadeMode()
{
InCombat = false;
(*m_creature).GetMotionMaster()->Clear(false);
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who)
{
if(!who)
return;
if(who->isTargetableForAttack() && who!= m_creature)
{
DoStartMeleeAttack(who);
if(!InCombat)
{
DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_AGGRO);
InCombat = true;
if(pInstance) pInstance->SetData("GurtoggBloodboilEvent", 1);
}
}
}
void MoveInLineOfSight(Unit *who)
{
if(who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))
{
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
{
if(who->HasStealthAura())
who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
if(who && who->isAlive())
m_creature->AddThreat(who, 1.0f);
if(!InCombat)
{
DoYell(SAY_AGGRO,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_AGGRO);
InCombat = true;
if(pInstance) pInstance->SetData("GurtoggBloodboilEvent", 1);
}
}
}
}
void KilledUnit(Unit *victim)
{
switch(rand()%2)
{
case 0:
DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_SLAY1);
break;
case 1:
DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_SLAY2);
break;
}
}
void JustDied(Unit *victim)
{
if(pInstance)
pInstance->SetData("GurtoggBloodboilEvent", 3);
DoPlaySoundToSet(m_creature,SOUND_DEATH);
}
// Note: This seems like a very complicated fix.
void CastBloodboil()
{
// Get the Threat List
std::list m_threatlist = m_creature->getThreatManager().getThreatList();
if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue
std::list targets;
std::list::iterator itr = m_threatlist.begin();
std::advance(itr, 0);
for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container
{
Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) //only on alive players
targets.push_back( target);
}
//Sort the list of players
targets.sort(TargetDistanceOrder(m_creature));
//Resize so we only get top 5
targets.resize(5);
//Aura each player in the targets list with Bloodboil. Aura code copied+pasted from Aura command in Level3.cpp
SpellEntry const *spellInfo = GetSpellStore()->LookupEntry( SPELL_BLOODBOIL );
if(spellInfo)
{
for(std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
Unit* target = *itr;
if(!target) return;
for(uint32 i = 0;i<3;i++)
{
uint8 eff = spellInfo->Effect[i];
if (eff>=TOTAL_SPELL_EFFECTS)
continue;
Aura *Aur = new Aura(spellInfo, i, NULL, target);
target->AddAura(Aur);
}
}
}
}
void UpdateAI(const uint32 diff)
{
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
if(ArcingSmashTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_ARCING_SMASH);
ArcingSmashTimer = 19000;
}else ArcingSmashTimer -= diff;
if(FelAcidTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_FEL_ACID);
FelAcidTimer = 25000;
}else FelAcidTimer -= diff;
if(EnrageTimer < diff)
{
//TODO: Find Enrage Spell
EnrageTimer = 600000;
DoYell(SAY_ENRAGE,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_ENRAGE);
}else EnrageTimer -= diff;
if(Phase1)
{
if(BloodboilTimer < diff)
{
BloodboilCount++;
if(BloodboilCount < 5)
BloodboilTimer = 10000*BloodboilCount;
else return; // Only cast it five times
CastBloodboil();
}else BloodboilTimer -= diff;
if(KnockbackTimer < diff)
{
Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0);
if(target)
{
(m_creature->getThreatManager()).modifyThreatPercent(target, -40);
DoCast(target, SPELL_KNOCKBACK);
}
KnockbackTimer = 22000;
}else KnockbackTimer -= diff;
if(AcidicWoundTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_ACIDIC_WOUND);
AcidicWoundTimer = 10000;
}else AcidicWoundTimer -= diff;
}
if(!Phase1)
{
if(AcidGeyserTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_ACID_GEYSER);
AcidGeyserTimer = 30000;
}else AcidGeyserTimer -= diff;
}
if(PhaseChangeTimer < diff)
{
if(Phase1)
{
Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);
if(target && target->isAlive())
{
m_creature->TauntApply(target);
DoCast(m_creature, SPELL_INSIGNIFIGANCE, true);
DoCast(target, SPELL_FEL_RAGE_TARGET, true);
DoCast(target, SPELL_FEL_RAGE_2, true);
DoCast(target, SPELL_FEL_RAGE_3, true);
//Cast this without triggered so that it appears in combat logs and shows visual.
DoCast(m_creature, SPELL_FEL_RAGE_SELF);
switch(rand()%2)
{
case 0:
DoYell(SAY_SPECIAL1,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_SPECIAL1);
break;
case 1:
DoYell(SAY_SPECIAL2,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, SOUND_SPECIAL2);
break;
}
AcidGeyserTimer = 1000;
Phase1 = false;
PhaseChangeTimer = 30000;
}
}
if(!Phase1) // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage
{
m_creature->TauntFadeOut(m_creature->getVictim());
Phase1 = true;
BloodboilTimer = 10000;
BloodboilCount = 0;
AcidicWoundTimer += 2000;
ArcingSmashTimer += 2000;
FelAcidTimer += 2000;
KnockbackTimer += 2000;
PhaseChangeTimer = 60000;
}
}else PhaseChangeTimer -= diff;
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI_boss_gurtogg_bloodboil(Creature *_Creature)
{
return new boss_gurtogg_bloodboilAI (_Creature);
}
void AddSC_boss_gurtogg_bloodboil()
{
Script *newscript;
newscript = new Script;
newscript->Name="boss_gurtogg_bloodboil";
newscript->GetAI = GetAI_boss_gurtogg_bloodboil;
m_scripts[nrscripts++] = newscript;
}