Merge remote-tracking branch 'tc/3.3.5' into 4.3.4

Conflicts:
	sql/updates/world/2015_11_09_02_world335.sql
	sql/updates/world/2015_11_09_02_world_335.sql
	sql/updates/world/2015_11_11_24_world_from_335_was_2015_11_09_02_world.sql
	sql/updates/world/2015_12_16_02_world335.sql
	sql/updates/world/2015_12_16_02_world_335.sql
	sql/updates/world/2015_12_18_19_world_from_335_was_2015_12_16_02_world_335.sql
	sql/updates/world/2016_01_02_00_world335.sql
	sql/updates/world/2016_01_02_00_world_335.sql
	sql/updates/world/2016_01_04_28_world_from_335_was_2016_01_02_00_world_335.sql
	sql/updates/world/2016_01_10_05_world335.sql
	sql/updates/world/2016_01_10_05_world_335.sql
	sql/updates/world/2016_01_12_01_world335.sql
	sql/updates/world/2016_01_12_01_world_335.sql
	sql/updates/world/2016_01_12_02_world335.sql
	sql/updates/world/2016_01_12_02_world_335.sql
	sql/updates/world/2016_01_14_12_world_from_335_was_2016_01_10_05_world_335.sql
	sql/updates/world/2016_01_14_14_world_from_335_was_2016_01_12_01_world_335.sql
	sql/updates/world/2016_01_14_15_world_from_335_was_2016_01_12_02_world_335.sql
	sql/updates/world/2016_01_15_00_world.sql
	sql/updates/world/2016_01_17_10_world.sql
	sql/updates/world/2016_01_17_11_world.sql
	sql/updates/world/2016_01_17_12_world.sql
	sql/updates/world/2016_01_17_13_world.sql
	sql/updates/world/2016_01_17_14_world.sql
	sql/updates/world/2016_01_17_15_world.sql
	sql/updates/world/2016_01_18_00_world.sql
	sql/updates/world/2016_01_19_00_world.sql
	sql/updates/world/2016_01_19_01_world.sql
	sql/updates/world/2016_01_19_02_world.sql
	sql/updates/world/2016_01_19_03_world.sql
	src/server/scripts/Spells/spell_paladin.cpp
This commit is contained in:
ariel-
2016-01-19 20:42:12 -03:00
26 changed files with 1684 additions and 793 deletions

View File

@@ -77,7 +77,7 @@ public:
Talk(SAY_RESPAWN);
}
bool CheckInRoom()
bool CheckInRoom() override
{
if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
{

View File

@@ -78,7 +78,7 @@ public:
Talk(SAY_BUFF);
}
bool CheckInRoom()
bool CheckInRoom() override
{
if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
{

View File

@@ -22,12 +22,11 @@
#include "Player.h"
#include "TemporarySummon.h"
AreaBoundary const* const mainBoundary = new CircleBoundary(Position(563.26f, 139.6f), 75.0);
BossBoundaryData const boundaries = {
{ BOSS_BEASTS, mainBoundary },
{ BOSS_JARAXXUS, mainBoundary },
{ BOSS_CRUSADERS, mainBoundary },
{ BOSS_VALKIRIES, mainBoundary },
{ BOSS_BEASTS, new CircleBoundary(Position(563.26f, 139.6f), 75.0) },
{ BOSS_JARAXXUS, new CircleBoundary(Position(563.26f, 139.6f), 75.0) },
{ BOSS_CRUSADERS, new CircleBoundary(Position(563.26f, 139.6f), 75.0) },
{ BOSS_VALKIRIES, new CircleBoundary(Position(563.26f, 139.6f), 75.0) },
{ BOSS_ANUBARAK, new EllipseBoundary(Position(746.0f, 135.0f), 100.0, 75.0) }
};

View File

@@ -265,7 +265,7 @@ class boss_sindragosa : public CreatureScript
{
if (!instance->CheckRequiredBosses(DATA_SINDRAGOSA, victim->ToPlayer()))
{
EnterEvadeMode();
EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK);
instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT);
return;
}
@@ -276,6 +276,13 @@ class boss_sindragosa : public CreatureScript
Talk(SAY_AGGRO);
}
void EnterEvadeMode(EvadeReason why) override
{
if (_isInAirPhase && why == EVADE_REASON_BOUNDARY)
return;
BossAI::EnterEvadeMode(why);
}
void JustReachedHome() override
{
BossAI::JustReachedHome();

View File

@@ -15,382 +15,680 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "naxxramas.h"
enum Horsemen
enum Horseman
{
HORSEMEN_THANE,
HORSEMEN_LADY,
HORSEMEN_BARON,
HORSEMEN_SIR,
THANE = DATA_THANE,
LADY = DATA_LADY,
BARON = DATA_BARON,
SIR = DATA_SIR,
};
static const std::vector<Horseman> horsemen = { THANE, LADY, BARON, SIR }; // for iterating
enum Spells
{
SPELL_MARK_DAMAGE = 28836
/* all */
SPELL_MARK_DAMAGE = 28836,
SPELL_BERSERK = 26662,
SPELL_ENCOUNTER_CREDIT = 59450,
/* baron */
SPELL_BARON_MARK = 28834,
SPELL_UNHOLY_SHADOW = 28882,
/* thane */
SPELL_THANE_MARK = 28832,
SPELL_METEOR = 28884,
/* lady */
SPELL_SHADOW_BOLT = 57374,
SPELL_LADY_MARK = 28833,
SPELL_VOID_ZONE = 28863,
SPELL_UNYIELDING_PAIN = 57381,
/* sir */
SPELL_HOLY_BOLT = 57376,
SPELL_SIR_MARK = 28835,
SPELL_HOLY_WRATH = 28883,
SPELL_CONDEMNATION = 57377
};
enum Actions
{
ACTION_BEGIN_MOVEMENT = 1,
ACTION_BEGIN_FIGHTING
};
enum HorsemenData
{
DATA_MOVEMENT_FINISHED = DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT + 1, // make sure we don't conflict with the one from naxxramas.h
DATA_DEATH_TIME
};
enum Events
{
EVENT_NONE,
/* all */
EVENT_BERSERK = 1,
EVENT_MARK,
EVENT_CAST,
EVENT_BERSERK,
/* rivendare */
EVENT_UNHOLYSHADOW,
/* thane */
EVENT_METEOR,
/* lady */
EVENT_VOIDZONE,
/* sir */
EVENT_HOLYWRATH
};
const Position WaypointPositions[12] =
{
// Thane waypoints
{2542.3f, -2984.1f, 241.49f, 5.362f},
{2547.6f, -2999.4f, 241.34f, 5.049f},
{2542.9f, -3015.0f, 241.35f, 4.654f},
// Lady waypoints
{2498.3f, -2961.8f, 241.28f, 3.267f},
{2487.7f, -2959.2f, 241.28f, 2.890f},
{2469.4f, -2947.6f, 241.28f, 2.576f},
// Baron waypoints
{2553.8f, -2968.4f, 241.33f, 5.757f},
{2564.3f, -2972.5f, 241.33f, 5.890f},
{2583.9f, -2971.67f, 241.35f, 0.008f},
// Sir waypoints
{2534.5f, -2921.7f, 241.53f, 1.363f},
{2523.5f, -2902.8f, 241.28f, 2.095f},
{2517.8f, -2896.6f, 241.28f, 2.315f},
};
const uint32 NPC_HORSEMEN[] = {16064, 16065, 30549, 16063};
const uint32 SPELL_MARK[] = {28832, 28833, 28834, 28835};
#define SPELL_PRIMARY(i) RAID_MODE(SPELL_PRIMARY_N[i], SPELL_PRIMARY_H[i])
const uint32 SPELL_PRIMARY_N[] = {28884, 28863, 28882, 28883};
const uint32 SPELL_PRIMARY_H[] = {57467, 57463, 57369, 57466};
#define SPELL_SECONDARY(i) RAID_MODE(SPELL_SECONDARY_N[i], SPELL_SECONDARY_H[i])
const uint32 SPELL_SECONDARY_N[]= {0, 57374, 0, 57376};
const uint32 SPELL_SECONDARY_H[]= {0, 57464, 0, 57465};
const uint32 SPELL_PUNISH[] = {0, 57381, 0, 57377};
#define SPELL_BERSERK 26662
enum FourHorsemen
enum Yells
{
SAY_AGGRO = 0,
SAY_TAUNT = 1,
SAY_SPECIAL = 2,
SAY_SLAY = 3,
SAY_DEATH = 4
SAY_DEATH = 4,
EMOTE_RAGECAST = 7
};
class boss_four_horsemen : public CreatureScript
static const Position baronPath[3] = { { 2552.427f, -2969.737f, 241.3021f },{ 2566.759f, -2972.535f, 241.3217f },{ 2584.32f, -2971.96f, 241.3489f } };
static const Position thanePath[3] = { { 2540.095f, -2983.192f, 241.3344f },{ 2546.005f, -2999.826f, 241.3665f },{ 2542.697f, -3014.055f, 241.3371f } };
static const Position ladyPath[3] = { { 2507.94f, -2961.444f, 242.4557f },{ 2488.763f, -2960.007f, 241.2757f },{ 2468.26f, -2947.499f, 241.2753f } };
static const Position sirPath[3] = { { 2533.141f, -2922.14f, 241.2764f },{ 2525.254f, -2905.907f, 241.2761f },{ 2517.636f, -2897.253f, 241.2758f } };
struct boss_four_horsemen_baseAI : public BossAI
{
public:
boss_four_horsemen() : CreatureScript("boss_four_horsemen") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_four_horsemenAI>(creature);
}
struct boss_four_horsemenAI : public BossAI
{
boss_four_horsemenAI(Creature* creature) : BossAI(creature, BOSS_HORSEMEN)
public:
Creature* getHorsemanHandle(Horseman who) const
{
Initialize();
id = Horsemen(0);
for (uint8 i = 0; i < 4; ++i)
if (me->GetEntry() == NPC_HORSEMEN[i])
id = Horsemen(i);
caster = (id == HORSEMEN_LADY || id == HORSEMEN_SIR);
if (_which == who)
return me;
else
return ObjectAccessor::GetCreature(*me, instance->GetGuidData(who));
}
boss_four_horsemen_baseAI(Creature* creature, Horseman which, Position const* initialPath) :
BossAI(creature, BOSS_HORSEMEN), _which(which), _initialPath(initialPath), _myMovementFinished(false), _nextMovement(0), _timeDied(0), _ourMovementFinished(false)
{
if (!me->IsAlive() && instance->GetBossState(BOSS_HORSEMEN) != DONE)
me->SetRespawnTime(10);
}
void Initialize()
uint32 GetData(uint32 type) const override
{
uiEventStarterGUID.Clear();
nextWP = 0;
punishTimer = 2000;
nextMovementStarted = false;
movementCompleted = false;
movementStarted = false;
encounterActionAttack = false;
encounterActionReset = false;
doDelayPunish = false;
}
Horsemen id;
ObjectGuid uiEventStarterGUID;
uint8 nextWP;
uint32 punishTimer;
bool caster;
bool nextMovementStarted;
bool movementCompleted;
bool movementStarted;
bool encounterActionAttack;
bool encounterActionReset;
bool doDelayPunish;
void Reset() override
{
if (!encounterActionReset)
DoEncounteraction(NULL, false, true, false);
instance->SetData(DATA_HORSEMEN0 + id, NOT_STARTED);
me->SetReactState(REACT_AGGRESSIVE);
Initialize();
_Reset();
}
bool DoEncounteraction(Unit* who, bool attack, bool reset, bool checkAllDead)
{
Creature* Thane = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THANE));
Creature* Lady = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_LADY));
Creature* Baron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BARON));
Creature* Sir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SIR));
if (Thane && Lady && Baron && Sir)
switch (type)
{
if (attack && who)
case DATA_MOVEMENT_FINISHED:
return _myMovementFinished ? 1 : 0;
case DATA_DEATH_TIME:
return _timeDied;
case DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT:
{
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->encounterActionAttack = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->encounterActionAttack = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->encounterActionAttack = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->encounterActionAttack = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->AttackStart(who);
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->AttackStart(who);
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->AttackStart(who);
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->AttackStart(who);
uint32 minTime = 0, maxTime = 0;
for (Horseman boss : horsemen)
if (Creature* cBoss = getHorsemanHandle(boss))
{
uint32 deathTime = cBoss->AI()->GetData(DATA_DEATH_TIME);
if (!deathTime)
{
TC_LOG_WARN("scripts", "FourHorsemenAI: Checking for achievement credit but horseman %s is reporting not dead", cBoss->GetName().c_str());
return 0;
}
if (!minTime || deathTime < minTime)
minTime = deathTime;
if (!maxTime || deathTime > maxTime)
maxTime = deathTime;
}
else
{
TC_LOG_WARN("scripts", "FourHorsemenAI: Checking for achievement credit but horseman with id %u is not present", uint32(boss));
return 0;
}
return (getMSTimeDiff(minTime, maxTime) <= 15 * IN_MILLISECONDS) ? 1 : 0;
}
if (reset)
{
if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED)
{
if (!Thane->IsAlive())
Thane->Respawn();
if (!Lady->IsAlive())
Lady->Respawn();
if (!Baron->IsAlive())
Baron->Respawn();
if (!Sir->IsAlive())
Sir->Respawn();
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->encounterActionReset = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->encounterActionReset = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->encounterActionReset = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->encounterActionReset = true;
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->EnterEvadeMode();
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->EnterEvadeMode();
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->EnterEvadeMode();
ENSURE_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->EnterEvadeMode();
}
}
if (checkAllDead)
return !Thane->IsAlive() && !Lady->IsAlive() && !Baron->IsAlive() && !Sir->IsAlive();
default:
return 0;
}
return false;
}
void BeginFourHorsemenMovement()
void DoAction(int32 action) override
{
movementStarted = true;
me->SetReactState(REACT_PASSIVE);
me->SetWalk(false);
me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true);
switch (id)
switch (action)
{
case HORSEMEN_THANE:
me->GetMotionMaster()->MovePoint(0, WaypointPositions[0]);
case ACTION_BEGIN_MOVEMENT:
me->GetMotionMaster()->MovePoint(1, _initialPath[0], true);
break;
case HORSEMEN_LADY:
me->GetMotionMaster()->MovePoint(3, WaypointPositions[3]);
break;
case HORSEMEN_BARON:
me->GetMotionMaster()->MovePoint(6, WaypointPositions[6]);
break;
case HORSEMEN_SIR:
me->GetMotionMaster()->MovePoint(9, WaypointPositions[9]);
case ACTION_BEGIN_FIGHTING:
if (_ourMovementFinished)
break;
me->SetCombatPulseDelay(5);
BeginFighting();
_ourMovementFinished = true;
break;
}
}
void MovementInform(uint32 type, uint32 point) override
void CheckIsMovementFinished()
{
if (type != POINT_MOTION_TYPE)
return;
if (point == 2 || point == 5 || point == 8 || point == 11)
for (Horseman boss : horsemen)
{
movementCompleted = true;
me->SetReactState(REACT_AGGRESSIVE);
Unit* eventStarter = ObjectAccessor::GetUnit(*me, uiEventStarterGUID);
if (eventStarter && me->IsValidAttackTarget(eventStarter))
AttackStart(eventStarter);
else if (!UpdateVictim())
if (Creature* cBoss = getHorsemanHandle(boss))
{
EnterEvadeMode();
if (cBoss->IsAlive() && !cBoss->AI()->GetData(DATA_MOVEMENT_FINISHED))
return;
}
else
{
TC_LOG_WARN("scripts", "FourHorsemenAI: Checking if movement is finished but horseman with id %u is not present", uint32(boss));
ResetEncounter();
return;
}
}
if (caster)
{
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
}
for (Horseman boss : horsemen)
if (Creature* cBoss = getHorsemanHandle(boss))
cBoss->AI()->DoAction(ACTION_BEGIN_FIGHTING);
}
void BeginEncounter()
{
if (instance->GetBossState(BOSS_HORSEMEN) == IN_PROGRESS)
return;
if (!instance->CheckRequiredBosses(BOSS_HORSEMEN))
{
ResetEncounter();
return;
}
instance->SetBossState(BOSS_HORSEMEN, IN_PROGRESS);
Map::PlayerList const &players = me->GetMap()->GetPlayers();
if (players.isEmpty()) // sanity check
ResetEncounter();
nextMovementStarted = false;
nextWP = point + 1;
}
// switch to "who" if nearer than current target.
void SelectNearestTarget(Unit* who)
{
if (me->GetVictim() && me->GetDistanceOrder(who, me->GetVictim()) && me->IsValidAttackTarget(who))
for (Horseman boss : horsemen)
{
me->getThreatManager().modifyThreatPercent(me->GetVictim(), -100);
me->AddThreat(who, 1000000.0f);
}
}
if (Creature* cBoss = getHorsemanHandle(boss))
{
if (!cBoss->IsAlive())
{
ResetEncounter();
return;
}
cBoss->SetReactState(REACT_PASSIVE);
cBoss->AttackStop(); // clear initial target that was set on enter combat
cBoss->setActive(true);
void MoveInLineOfSight(Unit* who) override
for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
{
if (Player* player = it->GetSource())
{
if (player->IsGameMaster())
continue;
{
BossAI::MoveInLineOfSight(who);
if (caster)
SelectNearestTarget(who);
}
if (player->IsAlive())
{
cBoss->AddThreat(player, 0.0f);
cBoss->SetInCombatWith(player);
player->SetInCombatWith(cBoss);
}
}
}
void AttackStart(Unit* who) override
{
if (!movementCompleted && !movementStarted)
{
uiEventStarterGUID = who->GetGUID();
BeginFourHorsemenMovement();
if (!encounterActionAttack)
DoEncounteraction(who, true, false, false);
}
else if (movementCompleted && movementStarted)
{
if (caster)
me->Attack(who, false);
/* Why do the Four Horsemen run to opposite corners of the room when engaged? *
* They saw all the mobs leading up to them being AoE'd down and made a judgment call. */
cBoss->AI()->DoAction(ACTION_BEGIN_MOVEMENT);
}
else
BossAI::AttackStart(who);
{
TC_LOG_WARN("scripts", "FourHorsemenAI: Encounter starting but horseman with id %u is not present", uint32(boss));
ResetEncounter();
return;
}
}
}
void KilledUnit(Unit* /*victim*/) override
void ResetEncounter()
{
if (!(rand32() % 5))
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
events.Reset();
summons.DespawnAll();
instance->SetData(DATA_HORSEMEN0 + id, DONE);
if (DoEncounteraction(NULL, false, false, true))
if (instance->GetBossState(BOSS_HORSEMEN) == NOT_STARTED || instance->GetBossState(BOSS_HORSEMEN) == DONE)
return;
instance->SetBossState(BOSS_HORSEMEN, NOT_STARTED);
for (Horseman boss : horsemen)
{
instance->SetBossState(BOSS_HORSEMEN, DONE);
instance->SaveToDB();
// Achievements related to the 4-horsemen are given through spell 59450 which does not exist.
// There is thus no way it can be given by casting the spell on the players.
instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 59450);
if (Creature* cBoss = getHorsemanHandle(boss))
{
cBoss->DespawnOrUnsummon(0);
cBoss->SetRespawnTime(15);
}
else
{
TC_LOG_WARN("scripts", "FourHorsemenAI: Encounter resetting but horseman with id %u is not present", uint32(boss));
}
}
}
Talk(SAY_DEATH);
void EncounterCleared()
{
if (instance->GetBossState(BOSS_HORSEMEN) == DONE)
return;
instance->SetBossState(BOSS_HORSEMEN, DONE);
//instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ENCOUNTER_CREDIT);
DoCastAOE(SPELL_ENCOUNTER_CREDIT, true);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED) // another horseman already did it
return;
Talk(SAY_AGGRO);
BeginEncounter();
}
events.ScheduleEvent(EVENT_MARK, 15000);
events.ScheduleEvent(EVENT_CAST, 20000 + rand32() % 5000);
events.ScheduleEvent(EVENT_BERSERK, 15*100*1000);
void EnterEvadeMode(EvadeReason /*why*/) override
{
ResetEncounter();
}
void Reset() override
{
if (!me->IsAlive())
return;
_myMovementFinished = false;
_nextMovement = 0;
_timeDied = 0;
_ourMovementFinished = false;
me->SetReactState(REACT_AGGRESSIVE);
SetCombatMovement(false);
me->SetCombatPulseDelay(0);
me->ResetLootMode();
events.Reset();
summons.DespawnAll();
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY, victim);
}
void JustDied(Unit* /*killer*/) override
{
if (instance->GetBossState(BOSS_HORSEMEN) != IN_PROGRESS) // necessary in case a horseman gets one-shot
{
BeginEncounter();
return;
}
Talk(SAY_DEATH);
_timeDied = getMSTime();
for (Horseman boss : horsemen)
{
if (Creature* cBoss = getHorsemanHandle(boss))
{
if (cBoss->IsAlive())
{
// in case a horseman dies while moving (unlikely but possible especially in non-335 branch)
CheckIsMovementFinished();
return;
}
}
else
{
TC_LOG_WARN("scripts", "FourHorsemenAI: %s died but horseman with id %u is not present", me->GetName().c_str(), uint32(boss));
ResetEncounter();
}
}
EncounterCleared();
}
void MovementInform(uint32 type, uint32 i) override
{
if (type != POINT_MOTION_TYPE)
return;
if (i < 3)
_nextMovement = i; // delay to next updateai to prevent it from instantly expiring
else
{
_myMovementFinished = true;
CheckIsMovementFinished();
}
}
void UpdateAI(uint32 diff) override
{
if (nextWP && movementStarted && !movementCompleted && !nextMovementStarted)
if (_nextMovement)
{
nextMovementStarted = true;
me->GetMotionMaster()->MovePoint(nextWP, WaypointPositions[nextWP]);
me->GetMotionMaster()->MovePoint(_nextMovement + 1, _initialPath[_nextMovement], true);
_nextMovement = 0;
}
if (!UpdateVictim() || !CheckInRoom() || !movementCompleted)
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MARK:
if (!(rand32() % 5))
Talk(SAY_SPECIAL);
DoCastAOE(SPELL_MARK[id]);
events.ScheduleEvent(EVENT_MARK, 15000);
break;
case EVENT_CAST:
if (!(rand32() % 5))
Talk(SAY_TAUNT);
if (caster)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
DoCast(target, SPELL_PRIMARY(id));
}
else
DoCastVictim(SPELL_PRIMARY(id));
events.ScheduleEvent(EVENT_CAST, 15000);
break;
case EVENT_BERSERK:
Talk(SAY_SPECIAL);
DoCast(me, EVENT_BERSERK);
break;
}
}
if (punishTimer <= diff)
{
if (doDelayPunish)
{
DoCastAOE(SPELL_PUNISH[id], true);
doDelayPunish = false;
}
punishTimer = 2000;
} else punishTimer -= diff;
if (!caster)
DoMeleeAttackIfReady();
else if ((!DoSpellAttackIfReady(SPELL_SECONDARY(id)) || !me->IsWithinLOSInMap(me->GetVictim())) && movementCompleted && !doDelayPunish)
doDelayPunish = true;
_UpdateAI(diff);
}
};
virtual void BeginFighting() = 0;
virtual void _UpdateAI(uint32 /*diff*/) = 0;
private:
const Horseman _which;
const Position* _initialPath;
bool _myMovementFinished;
uint8 _nextMovement;
uint32 _timeDied;
protected:
bool _ourMovementFinished;
};
class boss_four_horsemen_baron : public CreatureScript
{
public:
boss_four_horsemen_baron() : CreatureScript("boss_four_horsemen_baron") { }
struct boss_four_horsemen_baronAI : public boss_four_horsemen_baseAI
{
boss_four_horsemen_baronAI(Creature* creature) : boss_four_horsemen_baseAI(creature, BARON, baronPath) { }
void BeginFighting() override
{
SetCombatMovement(true);
me->SetReactState(REACT_AGGRESSIVE);
ThreatManager& threat = me->getThreatManager();
if (threat.isThreatListEmpty())
{
if (Unit* nearest = me->SelectNearestPlayer(5000.0f))
{
me->AddThreat(nearest, 1.0f);
AttackStart(nearest);
}
else
ResetEncounter();
}
else
AttackStart(threat.getHostilTarget());
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(3,7));
}
void _UpdateAI(uint32 diff) override
{
if (!_ourMovementFinished || !UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BERSERK:
DoCastAOE(SPELL_BERSERK, true);
break;
case EVENT_MARK:
DoCastAOE(SPELL_BARON_MARK, true);
events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS);
break;
case EVENT_UNHOLYSHADOW:
DoCastVictim(SPELL_UNHOLY_SHADOW);
events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(10,30));
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_UNHOLY_SHADOW)
Talk(SAY_SPECIAL);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_four_horsemen_baronAI>(creature);
}
};
class boss_four_horsemen_thane : public CreatureScript
{
public:
boss_four_horsemen_thane() : CreatureScript("boss_four_horsemen_thane") { }
struct boss_four_horsemen_thaneAI : public boss_four_horsemen_baseAI
{
boss_four_horsemen_thaneAI(Creature* creature) : boss_four_horsemen_baseAI(creature, THANE, thanePath), _shouldSay(true) { }
void BeginFighting() override
{
SetCombatMovement(true);
me->SetReactState(REACT_AGGRESSIVE);
ThreatManager& threat = me->getThreatManager();
if (threat.isThreatListEmpty())
{
if (Unit* nearest = me->SelectNearestPlayer(5000.0f))
{
me->AddThreat(nearest, 1.0f);
AttackStart(nearest);
}
else
ResetEncounter();
}
else
AttackStart(threat.getHostilTarget());
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_METEOR, urandms(10,15));
}
void _UpdateAI(uint32 diff) override
{
if (!_ourMovementFinished || !UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BERSERK:
DoCastAOE(SPELL_BERSERK, true);
break;
case EVENT_MARK:
DoCastAOE(SPELL_THANE_MARK, true);
events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS);
break;
case EVENT_METEOR:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true))
{
DoCast(target, SPELL_METEOR);
_shouldSay = true;
}
events.ScheduleEvent(EVENT_METEOR, urandms(13,17));
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
{
if (_shouldSay && spell->Id == SPELL_METEOR)
{
Talk(SAY_SPECIAL);
_shouldSay = false;
}
}
private:
bool _shouldSay; // throttle to make sure we only talk on first target hit by meteor
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_four_horsemen_thaneAI>(creature);
}
};
class boss_four_horsemen_lady : public CreatureScript
{
public:
boss_four_horsemen_lady() : CreatureScript("boss_four_horsemen_lady") { }
struct boss_four_horsemen_ladyAI : public boss_four_horsemen_baseAI
{
boss_four_horsemen_ladyAI(Creature* creature) : boss_four_horsemen_baseAI(creature, LADY, ladyPath) { }
void BeginFighting() override
{
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_VOIDZONE, urandms(5,10));
}
void _UpdateAI(uint32 diff) override
{
if (!me->IsInCombat())
return;
if (!_ourMovementFinished)
return;
if (me->getThreatManager().isThreatListEmpty())
{
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
return;
}
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BERSERK:
DoCastAOE(SPELL_BERSERK, true);
break;
case EVENT_MARK:
DoCastAOE(SPELL_LADY_MARK, true);
events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS);
break;
case EVENT_VOIDZONE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
{
DoCast(target, SPELL_VOID_ZONE, true);
Talk(SAY_SPECIAL);
}
events.ScheduleEvent(EVENT_VOIDZONE, urandms(12, 18));
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 45.0f, true))
DoCast(target, SPELL_SHADOW_BOLT);
else
{
DoCastAOE(SPELL_UNYIELDING_PAIN);
Talk(EMOTE_RAGECAST);
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_four_horsemen_ladyAI>(creature);
}
};
class boss_four_horsemen_sir : public CreatureScript
{
public:
boss_four_horsemen_sir() : CreatureScript("boss_four_horsemen_sir") { }
struct boss_four_horsemen_sirAI : public boss_four_horsemen_baseAI
{
boss_four_horsemen_sirAI(Creature* creature) : boss_four_horsemen_baseAI(creature, SIR, sirPath), _shouldSay(true) { }
void BeginFighting() override
{
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_HOLYWRATH, urandms(13,18));
}
void _UpdateAI(uint32 diff) override
{
if (!me->IsInCombat())
return;
if (!_ourMovementFinished)
return;
if (me->getThreatManager().isThreatListEmpty())
{
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
return;
}
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BERSERK:
DoCastAOE(SPELL_BERSERK, true);
break;
case EVENT_MARK:
DoCastAOE(SPELL_SIR_MARK, true);
events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS);
break;
case EVENT_HOLYWRATH:
if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 45.0f, true))
{
DoCast(target, SPELL_HOLY_WRATH, true);
_shouldSay = true;
}
events.ScheduleEvent(EVENT_HOLYWRATH, urandms(10,18));
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 45.0f, true))
DoCast(target, SPELL_HOLY_BOLT);
else
{
DoCastAOE(SPELL_CONDEMNATION);
Talk(EMOTE_RAGECAST);
}
}
void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
{
if (_shouldSay && spell->Id == SPELL_HOLY_WRATH)
{
Talk(SAY_SPECIAL);
_shouldSay = false;
}
}
private:
bool _shouldSay; // throttle to make sure we only talk on first target hit by holy wrath
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_four_horsemen_sirAI>(creature);
}
};
class spell_four_horsemen_mark : public SpellScriptLoader
@@ -450,6 +748,9 @@ class spell_four_horsemen_mark : public SpellScriptLoader
void AddSC_boss_four_horsemen()
{
new boss_four_horsemen();
new boss_four_horsemen_baron();
new boss_four_horsemen_thane();
new boss_four_horsemen_lady();
new boss_four_horsemen_sir();
new spell_four_horsemen_mark();
}

File diff suppressed because it is too large Load Diff

View File

@@ -91,15 +91,6 @@ DoorData const doorData[] =
{ 0, 0, DOOR_TYPE_ROOM }
};
MinionData const minionData[] =
{
{ NPC_SIR, BOSS_HORSEMEN },
{ NPC_THANE, BOSS_HORSEMEN },
{ NPC_LADY, BOSS_HORSEMEN },
{ NPC_BARON, BOSS_HORSEMEN },
{ 0, 0, }
};
ObjectData const objectData[] =
{
{ GO_NAXX_PORTAL_ARACHNID, DATA_NAXX_PORTAL_ARACHNID },
@@ -152,11 +143,8 @@ class instance_naxxramas : public InstanceMapScript
SetBossNumber(EncounterCount);
LoadBossBoundaries(boundaries);
LoadDoorData(doorData);
LoadMinionData(minionData);
LoadObjectData(nullptr, objectData);
minHorsemenDiedTime = 0;
maxHorsemenDiedTime = 0;
AbominationCount = 0;
hadAnubRekhanGreet = false;
hadFaerlinaGreet = false;
@@ -179,6 +167,9 @@ class instance_naxxramas : public InstanceMapScript
case NPC_RAZUVIOUS:
RazuviousGUID = creature->GetGUID();
break;
case NPC_GOTHIK:
GothikGUID = creature->GetGUID();
break;
case NPC_THANE:
ThaneGUID = creature->GetGUID();
break;
@@ -215,13 +206,6 @@ class instance_naxxramas : public InstanceMapScript
default:
break;
}
AddMinion(creature, true);
}
void OnCreatureRemove(Creature* creature) override
{
AddMinion(creature, false);
}
void ProcessEvent(WorldObject* /*source*/, uint32 eventId) override
@@ -351,25 +335,6 @@ class instance_naxxramas : public InstanceMapScript
if (GameObject* gate = instance->GetGameObject(GothikGateGUID))
gate->SetGoState(GOState(value));
break;
case DATA_HORSEMEN0:
case DATA_HORSEMEN1:
case DATA_HORSEMEN2:
case DATA_HORSEMEN3:
if (value == NOT_STARTED)
{
minHorsemenDiedTime = 0;
maxHorsemenDiedTime = 0;
}
else if (value == DONE)
{
time_t now = time(NULL);
if (minHorsemenDiedTime == 0)
minHorsemenDiedTime = now;
maxHorsemenDiedTime = now;
}
break;
case DATA_ABOMINATION_KILLED:
AbominationCount = value;
break;
@@ -416,6 +381,8 @@ class instance_naxxramas : public InstanceMapScript
return FaerlinaGUID;
case DATA_RAZUVIOUS:
return RazuviousGUID;
case DATA_GOTHIK:
return GothikGUID;
case DATA_THANE:
return ThaneGUID;
case DATA_LADY:
@@ -648,13 +615,13 @@ class instance_naxxramas : public InstanceMapScript
{
switch (criteria_id)
{
case 7600: // Criteria for achievement 2176: And They Would All Go Down Together 15sec of each other 10-man
if (Difficulty(instance->GetSpawnMode()) == RAID_DIFFICULTY_10MAN_NORMAL && (maxHorsemenDiedTime - minHorsemenDiedTime) < 15)
return true;
return false;
case 7601: // Criteria for achievement 2177: And They Would All Go Down Together 15sec of each other 25-man
if (Difficulty(instance->GetSpawnMode()) == RAID_DIFFICULTY_25MAN_NORMAL && (maxHorsemenDiedTime - minHorsemenDiedTime) < 15)
return true;
// And They Would All Go Down Together (kill 4HM within 15sec of each other)
case 7600: // 25-man
case 7601: // 10-man
if (criteria_id + instance->GetSpawnMode() == 7601)
return false;
if (Creature* baron = instance->GetCreature(BaronGUID)) // it doesn't matter which one we use, really
return (baron->AI()->GetData(DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT) == 1u);
return false;
// Difficulty checks are done on DB.
// Criteria for achievement 2186: The Immortal (25-man)
@@ -693,6 +660,7 @@ class instance_naxxramas : public InstanceMapScript
// Instructor Razuvious
ObjectGuid RazuviousGUID;
// Gothik the Harvester
ObjectGuid GothikGUID;
ObjectGuid GothikGateGUID;
// The Four Horsemen
ObjectGuid ThaneGUID;
@@ -700,8 +668,6 @@ class instance_naxxramas : public InstanceMapScript
ObjectGuid BaronGUID;
ObjectGuid SirGUID;
ObjectGuid HorsemenChestGUID;
time_t minHorsemenDiedTime;
time_t maxHorsemenDiedTime;
/* The Construct Quarter */
// Thaddius

View File

@@ -50,10 +50,7 @@ enum Data
DATA_HAD_FAERLINA_GREET,
DATA_HAD_THADDIUS_GREET,
DATA_HORSEMEN0,
DATA_HORSEMEN1,
DATA_HORSEMEN2,
DATA_HORSEMEN3,
DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT,
DATA_ABOMINATION_KILLED,
DATA_NAXX_PORTAL_ARACHNID,
@@ -67,6 +64,7 @@ enum Data64
DATA_ANUBREKHAN,
DATA_FAERLINA,
DATA_RAZUVIOUS,
DATA_GOTHIK,
DATA_THANE,
DATA_LADY,
DATA_BARON,
@@ -89,6 +87,7 @@ enum CreaturesIds
NPC_ANUBREKHAN = 15956,
NPC_FAERLINA = 15953,
NPC_RAZUVIOUS = 16061,
NPC_GOTHIK = 16060,
NPC_THANE = 16064,
NPC_LADY = 16065,
NPC_BARON = 30549,

View File

@@ -48,8 +48,6 @@ EndContentData */
enum AshyenAndKeleth
{
GOSSIP_REWARD_BLESS = 0,
NPC_ASHYEN = 17900,
NPC_KELETH = 17901,
@@ -117,7 +115,6 @@ public:
if (spell)
{
creature->CastSpell(player, spell, true);
creature->AI()->Talk(GOSSIP_REWARD_BLESS);
}
}
@@ -145,7 +142,6 @@ public:
if (spell)
{
creature->CastSpell(player, spell, true);
creature->AI()->Talk(GOSSIP_REWARD_BLESS);
}
}
player->CLOSE_GOSSIP_MENU();

View File

@@ -41,6 +41,12 @@ enum PaladinSpells
SPELL_PALADIN_CONCENTRACTION_AURA = 19746,
SPELL_PALADIN_DIVINE_PURPOSE_PROC = 90174,
SPELL_PALADIN_DIVINE_SACRIFICE = 64205,
SPELL_PALADIN_BEACON_OF_LIGHT = 53563,
SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 = 53652,
SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_2 = 53653,
SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3 = 53654,
SPELL_PALADIN_HOLY_LIGHT = 635,
SPELL_PALADIN_DIVINE_STORM = 53385,
SPELL_PALADIN_DIVINE_STORM_DUMMY = 54171,
SPELL_PALADIN_DIVINE_STORM_HEAL = 54172,
@@ -49,7 +55,6 @@ enum PaladinSpells
SPELL_PALADIN_FORBEARANCE = 25771,
SPELL_PALADIN_GLYPH_OF_SALVATION = 63225,
SPELL_PALADIN_HAND_OF_SACRIFICE = 6940,
SPELL_PALADIN_HOLY_LIGHT = 635,
SPELL_PALADIN_HOLY_SHOCK_R1 = 20473,
SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE = 25912,
SPELL_PALADIN_HOLY_SHOCK_R1_HEALING = 25914,
@@ -1010,6 +1015,68 @@ class spell_pal_lay_on_hands : public SpellScriptLoader
}
};
// 53651 - Light's Beacon - Beacon of Light
class spell_pal_light_s_beacon : public SpellScriptLoader
{
public:
spell_pal_light_s_beacon() : SpellScriptLoader("spell_pal_light_s_beacon") { }
class spell_pal_light_s_beacon_AuraScript : public AuraScript
{
PrepareAuraScript(spell_pal_light_s_beacon_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_BEACON_OF_LIGHT)
|| !sSpellMgr->GetSpellInfo(SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1)
|| !sSpellMgr->GetSpellInfo(SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_2)
|| !sSpellMgr->GetSpellInfo(SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3)
|| !sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_LIGHT))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (GetTarget()->HasAura(SPELL_PALADIN_BEACON_OF_LIGHT, eventInfo.GetActor()->GetGUID()))
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
if (!procSpell)
return;
uint32 healSpellId = procSpell->IsRankOf(sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_LIGHT)) ? SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 : SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3;
uint32 heal = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount());
Unit* beaconTarget = GetCaster();
if (!beaconTarget || !beaconTarget->HasAura(SPELL_PALADIN_BEACON_OF_LIGHT, eventInfo.GetActor()->GetGUID()))
return;
/// @todo: caster must be the healed unit to perform distance checks correctly
/// but that will break animation on clientside
/// caster in spell packets must be the healing unit
eventInfo.GetActor()->CastCustomSpell(healSpellId, SPELLVALUE_BASE_POINT0, heal, beaconTarget, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pal_light_s_beacon_AuraScript::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pal_light_s_beacon_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_pal_light_s_beacon_AuraScript();
}
};
// 31789 - Righteous Defense
class spell_pal_righteous_defense : public SpellScriptLoader
{
@@ -1295,6 +1362,7 @@ void AddSC_paladin_spell_scripts()
new spell_pal_item_healing_discount();
new spell_pal_judgement();
new spell_pal_lay_on_hands();
new spell_pal_light_s_beacon();
new spell_pal_righteous_defense();
new spell_pal_sacred_shield();
new spell_pal_shield_of_the_righteous();