mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-27 07:36:23 +00:00
Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -392,11 +392,13 @@ void Guardian::InitStats(uint32 duration)
|
||||
{
|
||||
Minion::InitStats(duration);
|
||||
|
||||
Unit* m_owner = GetOwner();
|
||||
InitStatsForLevel(m_owner->getLevel());
|
||||
if (Unit* m_owner = GetOwner())
|
||||
{
|
||||
InitStatsForLevel(m_owner->getLevel());
|
||||
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER && HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
|
||||
m_charmInfo->InitCharmCreateSpells();
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER && HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
|
||||
m_charmInfo->InitCharmCreateSpells();
|
||||
}
|
||||
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
@@ -349,14 +349,14 @@ public:
|
||||
m_flags = 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] T_FLAGS GetFlags() const { return m_flags; }
|
||||
[[nodiscard]] bool HasFlag(FLAG_TYPE flag) const { return m_flags & (1 << flag); }
|
||||
void AddFlag(FLAG_TYPE flag) { m_flags |= (1 << flag); }
|
||||
void DelFlag(FLAG_TYPE flag) { m_flags &= ~(1 << flag); }
|
||||
[[nodiscard]] T_FLAGS GetFlags() const { return m_flags; }
|
||||
[[nodiscard]] bool HasFlag(FLAG_TYPE flag) const { return m_flags & (1 << flag); }
|
||||
void AddFlag(FLAG_TYPE flag) { m_flags |= (1 << flag); }
|
||||
void DelFlag(FLAG_TYPE flag) { m_flags &= ~(1 << flag); }
|
||||
|
||||
[[nodiscard]] T_VALUES GetValue(FLAG_TYPE flag) const { return m_values[flag]; }
|
||||
void SetValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] = value; }
|
||||
void AddValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] += value; }
|
||||
void SetValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] = value; }
|
||||
void AddValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] += value; }
|
||||
|
||||
private:
|
||||
T_VALUES m_values[ARRAY_SIZE];
|
||||
|
||||
@@ -2947,7 +2947,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
|
||||
|
||||
// Check for attack from behind
|
||||
// xinef: if from behind or spell requires cast from behind
|
||||
if (!victim->HasInArc(M_PI, this) || spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET))
|
||||
if (!victim->HasInArc(M_PI, this))
|
||||
{
|
||||
if (!victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
|
||||
{
|
||||
@@ -2958,6 +2958,11 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
|
||||
canParry = false;
|
||||
canBlock = false;
|
||||
}
|
||||
else // Only deterrence as of 3.3.5
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET))
|
||||
canParry = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check creatures flags_extra for disable parry
|
||||
|
||||
@@ -807,6 +807,14 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
{
|
||||
if (pProto->SellPrice > 0)
|
||||
{
|
||||
uint32 money = pProto->SellPrice * count;
|
||||
if (_player->GetMoney() >= MAX_MONEY_AMOUNT - money) // prevent exceeding gold limit
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, nullptr, nullptr);
|
||||
_player->SendSellError(SELL_ERR_UNK, creature, itemguid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_ITEMDELETE_VENDOR))
|
||||
recoveryItem(pItem);
|
||||
|
||||
@@ -839,7 +847,6 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
_player->UpdateTitansGrip();
|
||||
}
|
||||
|
||||
uint32 money = pProto->SellPrice * count;
|
||||
_player->ModifyMoney(money);
|
||||
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money);
|
||||
}
|
||||
|
||||
@@ -1336,7 +1336,8 @@ GridMap::GridMap()
|
||||
_maxHeight = nullptr;
|
||||
_minHeight = nullptr;
|
||||
// Liquid data
|
||||
_liquidType = 0;
|
||||
_liquidGlobalEntry = 0;
|
||||
_liquidGlobalFlags = 0;
|
||||
_liquidOffX = 0;
|
||||
_liquidOffY = 0;
|
||||
_liquidWidth = 0;
|
||||
@@ -1513,7 +1514,8 @@ bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
|
||||
if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapLiquidMagic.asUInt)
|
||||
return false;
|
||||
|
||||
_liquidType = header.liquidType;
|
||||
_liquidGlobalEntry = header.liquidType;
|
||||
_liquidGlobalFlags = header.liquidFlags;
|
||||
_liquidOffX = header.offsetX;
|
||||
_liquidOffY = header.offsetY;
|
||||
_liquidWidth = header.width;
|
||||
@@ -1893,7 +1895,7 @@ inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float
|
||||
LiquidData liquidData;
|
||||
|
||||
// Check water type (if no water return)
|
||||
if (_liquidType || _liquidFlags)
|
||||
if (_liquidGlobalFlags || _liquidFlags)
|
||||
{
|
||||
// Get cell
|
||||
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
@@ -1903,38 +1905,34 @@ inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float
|
||||
int y_int = (int) cy & (MAP_RESOLUTION - 1);
|
||||
|
||||
// Check water type in cell
|
||||
int idx = (x_int >> 3) * 16 + (y_int >> 3);
|
||||
uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidType;
|
||||
uint32 entry = 0;
|
||||
if (_liquidEntry)
|
||||
int idx=(x_int>>3)*16 + (y_int>>3);
|
||||
uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidGlobalFlags;
|
||||
uint32 entry = _liquidEntry ? _liquidEntry[idx] : _liquidGlobalEntry;
|
||||
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry))
|
||||
{
|
||||
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(_liquidEntry[idx]))
|
||||
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
||||
uint32 liqTypeIdx = liquidEntry->Type;
|
||||
if (entry < 21)
|
||||
{
|
||||
entry = liquidEntry->Id;
|
||||
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
||||
uint32 liqTypeIdx = liquidEntry->Type;
|
||||
if (entry < 21)
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
entry = overrideLiquid;
|
||||
liqTypeIdx = liq->Type;
|
||||
}
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
entry = overrideLiquid;
|
||||
liqTypeIdx = liq->Type;
|
||||
}
|
||||
}
|
||||
|
||||
type |= 1 << liqTypeIdx;
|
||||
}
|
||||
|
||||
type |= 1 << liqTypeIdx;
|
||||
}
|
||||
|
||||
// Check req liquid type mask
|
||||
|
||||
@@ -128,7 +128,8 @@ struct map_heightHeader
|
||||
struct map_liquidHeader
|
||||
{
|
||||
uint32 fourcc;
|
||||
uint16 flags;
|
||||
uint8 flags;
|
||||
uint8 liquidFlags;
|
||||
uint16 liquidType;
|
||||
uint8 offsetX;
|
||||
uint8 offsetY;
|
||||
@@ -158,7 +159,6 @@ enum LiquidStatus
|
||||
#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)
|
||||
|
||||
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
||||
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
|
||||
|
||||
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
|
||||
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
|
||||
@@ -227,7 +227,8 @@ class GridMap
|
||||
uint8* _liquidFlags;
|
||||
float* _liquidMap;
|
||||
uint16 _gridArea;
|
||||
uint16 _liquidType;
|
||||
uint16 _liquidGlobalEntry;
|
||||
uint8 _liquidGlobalFlags;
|
||||
uint8 _liquidOffX;
|
||||
uint8 _liquidOffY;
|
||||
uint8 _liquidWidth;
|
||||
|
||||
@@ -608,11 +608,11 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id,
|
||||
}
|
||||
}
|
||||
|
||||
void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/)
|
||||
void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/, ObjectGuid targetGUID /*= ObjectGuid::Empty*/)
|
||||
{
|
||||
G3D::Vector3 dest = path.GetActualEndPosition();
|
||||
|
||||
MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH);
|
||||
MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH, nullptr, false, 0.0f, targetGUID);
|
||||
|
||||
// Charge movement is not started when using EVENT_CHARGE_PREPATH
|
||||
Movement::MoveSplineInit init(_owner);
|
||||
|
||||
@@ -219,7 +219,7 @@ public:
|
||||
void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z
|
||||
|
||||
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, const Movement::PointsArray* path = nullptr, bool generatePath = false, float orientation = 0.0f, ObjectGuid targetGUID = ObjectGuid::Empty);
|
||||
void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE);
|
||||
void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE, ObjectGuid targetGUID = ObjectGuid::Empty);
|
||||
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
|
||||
void MoveJumpTo(float angle, float speedXY, float speedZ);
|
||||
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = 0)
|
||||
|
||||
@@ -27,304 +27,31 @@
|
||||
#define MIN_QUIET_DISTANCE 28.0f
|
||||
#define MAX_QUIET_DISTANCE 43.0f
|
||||
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
|
||||
{
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_setMoveData(owner))
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
if (!_getPoint(owner, x, y, z)) {
|
||||
i_nextCheckTime.Reset(100);
|
||||
return;
|
||||
}
|
||||
|
||||
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MoveTo(x, y, z, true);
|
||||
init.SetWalk(false);
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool FleeingMovementGenerator<T>::_getPoint(T* owner, float& x, float& y, float& z)
|
||||
{
|
||||
if (!owner)
|
||||
return false;
|
||||
|
||||
const Map* _map = owner->GetMap();
|
||||
|
||||
x = owner->GetPositionX();
|
||||
y = owner->GetPositionY();
|
||||
z = owner->GetPositionZ();
|
||||
|
||||
float temp_x, temp_y, angle;
|
||||
// primitive path-finding
|
||||
for (uint8 i = 0; i < 18; ++i)
|
||||
{
|
||||
if (i_only_forward && i > 2)
|
||||
break;
|
||||
|
||||
float distance = 5.0f;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
angle = i_cur_angle;
|
||||
break;
|
||||
case 1:
|
||||
angle = i_cur_angle;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 2:
|
||||
angle = i_cur_angle;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 3:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI / 4);
|
||||
break;
|
||||
case 4:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI / 4);
|
||||
break;
|
||||
case 5:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI / 4);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 6:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI / 4);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 7:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI / 2);
|
||||
break;
|
||||
case 8:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI / 2);
|
||||
break;
|
||||
case 9:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI / 2);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 10:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI / 2);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 11:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI / 4);
|
||||
distance /= 4;
|
||||
break;
|
||||
case 12:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI / 4);
|
||||
distance /= 4;
|
||||
break;
|
||||
case 13:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI / 2);
|
||||
distance /= 4;
|
||||
break;
|
||||
case 14:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI / 2);
|
||||
distance /= 4;
|
||||
break;
|
||||
case 15:
|
||||
angle = i_cur_angle + static_cast<float>(3 * M_PI / 4);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 16:
|
||||
angle = i_cur_angle - static_cast<float>(3 * M_PI / 4);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 17:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI);
|
||||
distance /= 2;
|
||||
break;
|
||||
default:
|
||||
angle = 0.0f;
|
||||
distance = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
temp_x = x + distance * cos(angle);
|
||||
temp_y = y + distance * std::sin(angle);
|
||||
float temp_z = z;
|
||||
|
||||
if (!_map->CanReachPositionAndGetValidCoords(owner, temp_x, temp_y, temp_z, true, true))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(temp_z - z) || distance / std::fabs(temp_z - z) > 1.0f)
|
||||
{
|
||||
float temp_z_left = _map->GetHeight(owner->GetPhaseMask(), temp_x + 1.0f * cos(angle + static_cast<float>(M_PI / 2)), temp_y + 1.0f * std::sin(angle + static_cast<float>(M_PI / 2)), z, true);
|
||||
float temp_z_right = _map->GetHeight(owner->GetPhaseMask(), temp_x + 1.0f * cos(angle - static_cast<float>(M_PI / 2)), temp_y + 1.0f * std::sin(angle - static_cast<float>(M_PI / 2)), z, true);
|
||||
if (std::fabs(temp_z_left - temp_z) < 1.2f && std::fabs(temp_z_right - temp_z) < 1.2f)
|
||||
{
|
||||
// use new values
|
||||
x = temp_x;
|
||||
y = temp_y;
|
||||
z = temp_z;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset(urand(500, 1000));
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool FleeingMovementGenerator<T>::_setMoveData(T* owner)
|
||||
{
|
||||
float cur_dist_xyz = owner->GetDistance(i_caster_x, i_caster_y, i_caster_z);
|
||||
|
||||
if (i_to_distance_from_caster > 0.0f)
|
||||
{
|
||||
if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
|
||||
// if we reach lower distance
|
||||
(i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
|
||||
// if we can't be close
|
||||
(i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
|
||||
// if we reach bigger distance
|
||||
(cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
|
||||
(i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
|
||||
// if we leave 'quiet zone'
|
||||
{
|
||||
// we are very far or too close, stopping
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset(urand(500, 1000));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// now we are running, continue
|
||||
i_last_distance_from_caster = cur_dist_xyz;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float cur_dist;
|
||||
float angle_to_caster;
|
||||
|
||||
if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID))
|
||||
{
|
||||
cur_dist = fright->GetDistance(owner);
|
||||
if (cur_dist < cur_dist_xyz)
|
||||
{
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
i_caster_z = fright->GetPositionZ();
|
||||
angle_to_caster = fright->GetAngle(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_dist = cur_dist_xyz;
|
||||
angle_to_caster = owner->GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_dist = cur_dist_xyz;
|
||||
angle_to_caster = owner->GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI);
|
||||
}
|
||||
|
||||
// if we too close may use 'path-finding' else just stop
|
||||
i_only_forward = cur_dist >= MIN_QUIET_DISTANCE / 3;
|
||||
|
||||
//get angle and 'distance from caster' to run
|
||||
float angle;
|
||||
|
||||
if (i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
|
||||
{
|
||||
angle = (float)rand_norm() * (1.0f - cur_dist / MIN_QUIET_DISTANCE) * static_cast<float>(M_PI / 3) + (float)rand_norm() * static_cast<float>(M_PI * 2 / 3);
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE;
|
||||
i_only_forward = true;
|
||||
}
|
||||
else if (cur_dist < MIN_QUIET_DISTANCE)
|
||||
{
|
||||
angle = static_cast<float>(M_PI / 6) + (float)rand_norm() * static_cast<float>(M_PI * 2 / 3);
|
||||
i_to_distance_from_caster = cur_dist * 2 / 3 + (float)rand_norm() * (MIN_QUIET_DISTANCE - cur_dist * 2 / 3);
|
||||
}
|
||||
else if (cur_dist > MAX_QUIET_DISTANCE)
|
||||
{
|
||||
angle = (float)rand_norm() * static_cast<float>(M_PI / 3) + static_cast<float>(M_PI * 2 / 3);
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm() * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = (float)rand_norm() * static_cast<float>(M_PI);
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm() * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
}
|
||||
|
||||
int8 sign = (float)rand_norm() > 0.5f ? 1 : -1;
|
||||
i_cur_angle = sign * angle + angle_to_caster;
|
||||
|
||||
// current distance
|
||||
i_last_distance_from_caster = cur_dist;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::DoInitialize(T* owner)
|
||||
{
|
||||
if (!owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_path = nullptr;
|
||||
owner->SetUnitFlag(UNIT_FLAG_FLEEING);
|
||||
owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
|
||||
|
||||
_Init(owner);
|
||||
|
||||
if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID))
|
||||
{
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
i_caster_z = fright->GetPositionZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
i_caster_x = owner->GetPositionX();
|
||||
i_caster_y = owner->GetPositionY();
|
||||
i_caster_z = owner->GetPositionZ();
|
||||
}
|
||||
|
||||
i_only_forward = true;
|
||||
i_cur_angle = 0.0f;
|
||||
i_last_distance_from_caster = 0.0f;
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
_setTargetLocation(owner);
|
||||
owner->AddUnitState(UNIT_STATE_FLEEING);
|
||||
SetTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FleeingMovementGenerator<Creature>::_Init(Creature* owner)
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::DoFinalize(T*)
|
||||
{
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
//owner->SetTargetGuid(ObjectGuid());
|
||||
is_water_ok = owner->CanEnterWater();
|
||||
is_land_ok = owner->CanWalk();
|
||||
}
|
||||
|
||||
template<>
|
||||
void FleeingMovementGenerator<Player>::_Init(Player* )
|
||||
{
|
||||
is_water_ok = true;
|
||||
is_land_ok = true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void FleeingMovementGenerator<Player>::DoFinalize(Player* owner)
|
||||
{
|
||||
owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
|
||||
owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
|
||||
owner->ClearUnitState(UNIT_STATE_FLEEING);
|
||||
owner->StopMoving();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -332,8 +59,11 @@ void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner)
|
||||
{
|
||||
owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
|
||||
owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
|
||||
if (owner->GetVictim())
|
||||
owner->SetTarget(owner->GetVictim()->GetGUID());
|
||||
|
||||
if (Unit* victim = owner->GetVictim())
|
||||
{
|
||||
owner->SetTarget(victim->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -343,36 +73,140 @@ void FleeingMovementGenerator<T>::DoReset(T* owner)
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 diff)
|
||||
{
|
||||
if (!owner || !owner->IsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
|
||||
{
|
||||
_path = nullptr;
|
||||
_interrupt = true;
|
||||
owner->StopMoving();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
_interrupt = false;
|
||||
|
||||
i_nextCheckTime.Update(time_diff);
|
||||
if (i_nextCheckTime.Passed() && owner->movespline->Finalized())
|
||||
_setTargetLocation(owner);
|
||||
_timer.Update(diff);
|
||||
if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
|
||||
{
|
||||
SetTargetLocation(owner);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::SetTargetLocation(T* owner)
|
||||
{
|
||||
if (!owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
|
||||
{
|
||||
_path = nullptr;
|
||||
_interrupt = true;
|
||||
owner->StopMoving();
|
||||
return;
|
||||
}
|
||||
|
||||
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
|
||||
|
||||
Position destination = owner->GetPosition();
|
||||
GetPoint(owner, destination);
|
||||
|
||||
// Add LOS check for target point
|
||||
if (!owner->IsWithinLOS(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ()))
|
||||
{
|
||||
_timer.Reset(200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_path)
|
||||
{
|
||||
_path = std::make_unique<PathGenerator>(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
_path->Clear();
|
||||
}
|
||||
|
||||
_path->SetPathLengthLimit(30.0f);
|
||||
bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
|
||||
if (!result || (_path->GetPathType() & PathType(PATHFIND_NOPATH | PATHFIND_SHORTCUT | PATHFIND_FARFROMPOLY)))
|
||||
{
|
||||
_timer.Reset(100);
|
||||
return;
|
||||
}
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MovebyPath(_path->GetPath());
|
||||
init.SetWalk(false);
|
||||
int32 traveltime = init.Launch();
|
||||
_timer.Reset(traveltime + urand(800, 1500));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::GetPoint(T* owner, Position& position)
|
||||
{
|
||||
float casterDistance, casterAngle;
|
||||
if (Unit* fleeTarget = ObjectAccessor::GetUnit(*owner, _fleeTargetGUID))
|
||||
{
|
||||
casterDistance = fleeTarget->GetDistance(owner);
|
||||
if (casterDistance > 0.2f)
|
||||
{
|
||||
casterAngle = fleeTarget->GetAngle(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
casterAngle = frand(0.0f, 2.0f * float(M_PI));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
casterDistance = 0.0f;
|
||||
casterAngle = frand(0.0f, 2.0f * float(M_PI));
|
||||
}
|
||||
|
||||
float distance, angle;
|
||||
if (casterDistance < MIN_QUIET_DISTANCE)
|
||||
{
|
||||
distance = frand(0.4f, 1.3f) * (MIN_QUIET_DISTANCE - casterDistance);
|
||||
angle = casterAngle + frand(-float(M_PI) / 8.0f, float(M_PI) / 8.0f);
|
||||
}
|
||||
else if (casterDistance > MAX_QUIET_DISTANCE)
|
||||
{
|
||||
distance = frand(0.4f, 1.0f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
|
||||
angle = -casterAngle + frand(-float(M_PI) / 4.0f, float(M_PI) / 4.0f);
|
||||
}
|
||||
else // we are inside quiet range
|
||||
{
|
||||
distance = frand(0.6f, 1.2f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
|
||||
angle = frand(0.0f, 2.0f * float(M_PI));
|
||||
}
|
||||
|
||||
// In MovePositionToFirstCollision we have added owner's orientation
|
||||
// so now let's subtract it
|
||||
angle -= owner->GetOrientation();
|
||||
|
||||
owner->MovePositionToFirstCollision(position, distance, angle);
|
||||
}
|
||||
|
||||
template void FleeingMovementGenerator<Player>::DoInitialize(Player*);
|
||||
template void FleeingMovementGenerator<Creature>::DoInitialize(Creature*);
|
||||
template bool FleeingMovementGenerator<Player>::_setMoveData(Player*);
|
||||
template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature*);
|
||||
template bool FleeingMovementGenerator<Player>::_getPoint(Player*, float&, float&, float&);
|
||||
template bool FleeingMovementGenerator<Creature>::_getPoint(Creature*, float&, float&, float&);
|
||||
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player*);
|
||||
template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature*);
|
||||
template void FleeingMovementGenerator<Player>::DoReset(Player*);
|
||||
template void FleeingMovementGenerator<Creature>::DoReset(Creature*);
|
||||
template bool FleeingMovementGenerator<Player>::DoUpdate(Player*, uint32);
|
||||
template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
|
||||
template void FleeingMovementGenerator<Player>::SetTargetLocation(Player*);
|
||||
template void FleeingMovementGenerator<Creature>::SetTargetLocation(Creature*);
|
||||
template void FleeingMovementGenerator<Player>::GetPoint(Player*, Position&);
|
||||
template void FleeingMovementGenerator<Creature>::GetPoint(Creature*, Position&);
|
||||
|
||||
void TimedFleeingMovementGenerator::Finalize(Unit* owner)
|
||||
{
|
||||
|
||||
@@ -23,34 +23,24 @@
|
||||
template<class T>
|
||||
class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
FleeingMovementGenerator(ObjectGuid fright) : i_frightGUID(fright), i_nextCheckTime(0) {}
|
||||
public:
|
||||
explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _path(nullptr), _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false) {}
|
||||
|
||||
void DoInitialize(T*);
|
||||
void DoFinalize(T*);
|
||||
void DoReset(T*);
|
||||
bool DoUpdate(T*, uint32);
|
||||
MovementGeneratorType GetMovementGeneratorType() override { return FLEEING_MOTION_TYPE; }
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
|
||||
void DoInitialize(T*);
|
||||
void DoFinalize(T*);
|
||||
void DoReset(T*);
|
||||
bool DoUpdate(T*, uint32);
|
||||
|
||||
private:
|
||||
void _setTargetLocation(T*);
|
||||
bool _getPoint(T*, float& x, float& y, float& z);
|
||||
bool _setMoveData(T* owner);
|
||||
void _Init(T* );
|
||||
private:
|
||||
void SetTargetLocation(T*);
|
||||
void GetPoint(T*, Position& position);
|
||||
|
||||
bool is_water_ok : 1;
|
||||
bool is_land_ok : 1;
|
||||
bool i_only_forward: 1;
|
||||
|
||||
float i_caster_x;
|
||||
float i_caster_y;
|
||||
float i_caster_z;
|
||||
float i_last_distance_from_caster;
|
||||
float i_to_distance_from_caster;
|
||||
float i_cur_angle;
|
||||
ObjectGuid i_frightGUID;
|
||||
TimeTracker i_nextCheckTime;
|
||||
std::unique_ptr<PathGenerator> _path;
|
||||
ObjectGuid _fleeTargetGUID;
|
||||
TimeTracker _timer;
|
||||
bool _interrupt;
|
||||
};
|
||||
|
||||
class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature>
|
||||
|
||||
@@ -1537,7 +1537,7 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode
|
||||
if (apply)
|
||||
{
|
||||
// apply glow vision
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && type == INVISIBILITY_GENERAL)
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && (type == INVISIBILITY_GENERAL || type == INVISIBILITY_UNK10))
|
||||
target->SetByteFlag(PLAYER_FIELD_BYTES2, PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
|
||||
|
||||
target->m_invisibility.AddFlag(type);
|
||||
@@ -1568,14 +1568,14 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
target->m_invisibility.DelFlag(type);
|
||||
|
||||
// if not have invisibility auras of type INVISIBILITY_GENERAL
|
||||
// remove glow vision
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && type == INVISIBILITY_GENERAL)
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && !target->m_invisibility.HasFlag(INVISIBILITY_GENERAL) && !target->m_invisibility.HasFlag(INVISIBILITY_UNK10))
|
||||
{
|
||||
target->RemoveByteFlag(PLAYER_FIELD_BYTES2, PLAYER_FIELD_BYTES_2_OFFSET_AURA_VISION, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
|
||||
}
|
||||
|
||||
target->m_invisibility.DelFlag(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4875,7 +4875,7 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
|
||||
if (!m_preGeneratedPath)
|
||||
{
|
||||
Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetCombatReach(), unitTarget->GetRelativeAngle(m_caster));
|
||||
m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed);
|
||||
m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed, EVENT_CHARGE, nullptr, false, 0.0f, targetGUID);
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
@@ -4884,7 +4884,7 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed);
|
||||
m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed, targetGUID);
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
|
||||
@@ -1360,14 +1360,6 @@ bool SpellInfo::IsSingleTarget() const
|
||||
if (AttributesEx5 & SPELL_ATTR5_LIMIT_N)
|
||||
return true;
|
||||
|
||||
switch (GetSpellSpecific())
|
||||
{
|
||||
case SPELL_SPECIFIC_JUDGEMENT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3672,8 +3672,8 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].BasePoints = 0;
|
||||
});
|
||||
|
||||
// Krolmir, Hammer of Storms (13010)
|
||||
ApplySpellFix({ 56606, 56541 }, [](SpellInfo* spellInfo)
|
||||
// Riding Jokkum
|
||||
ApplySpellFix({ 56606 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].BasePoints = 1;
|
||||
});
|
||||
|
||||
@@ -15,330 +15,446 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: boss_kri, boss_yauj, boss_vem : The Bug Trio
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Temple of Ahn'Qiraj
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "temple_of_ahnqiraj.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CLEAVE = 26350,
|
||||
SPELL_TOXIC_VOLLEY = 25812,
|
||||
SPELL_POISON_CLOUD = 38718, //Only Spell with right dmg.
|
||||
SPELL_ENRAGE = 34624, //Changed cause 25790 is cast on gamers too. Same prob with old explosion of twin emperors.
|
||||
SPELL_BLOODY_DEATH = 25770,
|
||||
SPELL_FULL_HEAL = 17683,
|
||||
|
||||
SPELL_CHARGE = 26561,
|
||||
SPELL_KNOCKBACK = 26027,
|
||||
// Kri
|
||||
SPELL_CLEAVE = 26350,
|
||||
SPELL_THRASH = 3391,
|
||||
SPELL_TOXIC_VOLLEY = 25812,
|
||||
SPELL_POISON_CLOUD = 26590,
|
||||
|
||||
SPELL_HEAL = 25807,
|
||||
SPELL_FEAR = 19408
|
||||
// Vem
|
||||
SPELL_CHARGE = 26561,
|
||||
SPELL_KNOCKBACK = 18670,
|
||||
SPELL_KNOCKDOWN = 19128,
|
||||
SPELL_VENGEANCE = 25790,
|
||||
|
||||
// Yauj
|
||||
SPELL_HEAL = 25807,
|
||||
SPELL_FEAR = 26580,
|
||||
SPELL_RAVAGE = 3242,
|
||||
SPELL_DISPEL = 25808,
|
||||
|
||||
NPC_YAUJ_BROOD = 15621
|
||||
};
|
||||
|
||||
class boss_kri : public CreatureScript
|
||||
enum Misc
|
||||
{
|
||||
public:
|
||||
boss_kri() : CreatureScript("boss_kri") { }
|
||||
ACTION_CONSUME = 0,
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_kriAI>(creature);
|
||||
}
|
||||
EMOTE_DEVOURED = 0,
|
||||
|
||||
struct boss_kriAI : public ScriptedAI
|
||||
{
|
||||
boss_kriAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
POINT_CONSUME = 0,
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
uint32 Cleave_Timer;
|
||||
uint32 ToxicVolley_Timer;
|
||||
uint32 Check_Timer;
|
||||
|
||||
bool VemDead;
|
||||
bool Death;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Cleave_Timer = urand(4000, 8000);
|
||||
ToxicVolley_Timer = urand(6000, 12000);
|
||||
Check_Timer = 2000;
|
||||
|
||||
VemDead = false;
|
||||
Death = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (instance->GetData(DATA_BUG_TRIO_DEATH) < 2)// Unlootable if death
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
|
||||
instance->SetData(DATA_BUG_TRIO_DEATH, 1);
|
||||
}
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//Cleave_Timer
|
||||
if (Cleave_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
Cleave_Timer = urand(5000, 12000);
|
||||
}
|
||||
else Cleave_Timer -= diff;
|
||||
|
||||
//ToxicVolley_Timer
|
||||
if (ToxicVolley_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_TOXIC_VOLLEY);
|
||||
ToxicVolley_Timer = urand(10000, 15000);
|
||||
}
|
||||
else ToxicVolley_Timer -= diff;
|
||||
|
||||
if (!HealthAbovePct(5) && !Death)
|
||||
{
|
||||
DoCastVictim(SPELL_POISON_CLOUD);
|
||||
Death = true;
|
||||
}
|
||||
|
||||
if (!VemDead)
|
||||
{
|
||||
//Checking if Vem is dead. If yes we will enrage.
|
||||
if (Check_Timer <= diff)
|
||||
{
|
||||
if (instance->GetData(DATA_VEMISDEAD))
|
||||
{
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
VemDead = true;
|
||||
}
|
||||
Check_Timer = 2000;
|
||||
}
|
||||
else Check_Timer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
VEM_WAYPOINT_PATH = 876030
|
||||
};
|
||||
|
||||
class boss_vem : public CreatureScript
|
||||
const Position resetPoint = { -8582.0f, 2047.0f, -1.62f }; // Taken from CMangos
|
||||
|
||||
struct boss_bug_trio : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_vem() : CreatureScript("boss_vem") { }
|
||||
boss_bug_trio(Creature* creature) : BossAI(creature, DATA_BUG_TRIO) { Reset(); }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
bool CheckInRoom() override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_vemAI>(creature);
|
||||
if (me->GetExactDist2d(resetPoint) <= 10.f)
|
||||
{
|
||||
EnterEvadeMode(EVADE_REASON_BOUNDARY);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct boss_vemAI : public ScriptedAI
|
||||
void EnterCombatWithTrio(Unit* who)
|
||||
{
|
||||
boss_vemAI(Creature* creature) : ScriptedAI(creature)
|
||||
if (Creature* vem = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VEM)))
|
||||
if (vem->GetGUID() != me->GetGUID())
|
||||
vem->GetAI()->AttackStart(who);
|
||||
if (Creature* kri = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KRI)))
|
||||
if (kri->GetGUID() != me->GetGUID())
|
||||
kri->GetAI()->AttackStart(who);
|
||||
if (Creature* yauj = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_YAUJ)))
|
||||
if (yauj->GetGUID() != me->GetGUID())
|
||||
yauj->GetAI()->AttackStart(who);
|
||||
}
|
||||
|
||||
void EvadeAllBosses(EvadeReason why)
|
||||
{
|
||||
if (Creature* vem = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VEM)))
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
if (vem->GetGUID() != me->GetGUID())
|
||||
{
|
||||
if (vem->IsAlive() && !vem->IsInEvadeMode())
|
||||
vem->AI()->EnterEvadeMode(why);
|
||||
else
|
||||
vem->Respawn();
|
||||
}
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
uint32 Charge_Timer;
|
||||
uint32 KnockBack_Timer;
|
||||
uint32 Enrage_Timer;
|
||||
|
||||
bool Enraged;
|
||||
|
||||
void Reset() override
|
||||
if (Creature* kri = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KRI)))
|
||||
{
|
||||
Charge_Timer = urand(15000, 27000);
|
||||
KnockBack_Timer = urand(8000, 20000);
|
||||
Enrage_Timer = 120000;
|
||||
|
||||
Enraged = false;
|
||||
if (kri->GetGUID() != me->GetGUID())
|
||||
{
|
||||
if (kri->IsAlive() && !kri->IsInEvadeMode())
|
||||
kri->AI()->EnterEvadeMode(why);
|
||||
else
|
||||
kri->Respawn();
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
if (Creature* yauj = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_YAUJ)))
|
||||
{
|
||||
instance->SetData(DATA_VEM_DEATH, 0);
|
||||
if (instance->GetData(DATA_BUG_TRIO_DEATH) < 2)// Unlootable if death
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
instance->SetData(DATA_BUG_TRIO_DEATH, 1);
|
||||
if (yauj->GetGUID() != me->GetGUID())
|
||||
{
|
||||
if (yauj->IsAlive() && !yauj->IsInEvadeMode())
|
||||
yauj->AI()->EnterEvadeMode(why);
|
||||
else
|
||||
yauj->Respawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action != ACTION_CONSUME || dying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
}
|
||||
isEating = true;
|
||||
me->SetSpeed(MOVE_RUN, 45.f/7.f); // From sniffs
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
void MovementInform(uint32 type, uint32 /*id*/) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->SetSpeed(MOVE_RUN, 15.f/7.f); // From sniffs
|
||||
DoCastSelf(SPELL_FULL_HEAL, true);
|
||||
DoResetThreat();
|
||||
isEating = false;
|
||||
|
||||
_scheduler.Schedule(4s, [this](TaskContext /*context*/)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
if (Unit* target = me->GetVictim())
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(why);
|
||||
EvadeAllBosses(why);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
_scheduler.CancelAll();
|
||||
dying = false;
|
||||
isEating = false;
|
||||
instance->SetData(DATA_BUG_TRIO_DEATH, 0);
|
||||
me->SetSpeed(MOVE_RUN, 15.f / 7.f); // From sniffs
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetControlled(false, UNIT_STATE_ROOT);
|
||||
|
||||
if (me->GetEntry() == NPC_VEM)
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(VEM_WAYPOINT_PATH, true);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || isEating || !CheckInRoom())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(1, damage) && instance->GetData(DATA_BUG_TRIO_DEATH) < 2 && who->GetGUID() != me->GetGUID())
|
||||
{
|
||||
damage = 0;
|
||||
if (isEating)
|
||||
return;
|
||||
|
||||
//Charge_Timer
|
||||
if (Charge_Timer <= diff)
|
||||
_scheduler.CancelAll();
|
||||
me->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||
|
||||
DoFinalSpell();
|
||||
|
||||
// Move the other bugs to this bug position
|
||||
if (Creature* vem = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VEM)))
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
|
||||
if (target)
|
||||
if (vem->GetGUID() != me->GetGUID())
|
||||
{
|
||||
DoCast(target, SPELL_CHARGE);
|
||||
//me->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true, 1);
|
||||
AttackStart(target);
|
||||
vem->AI()->DoAction(ACTION_CONSUME);
|
||||
vem->GetMotionMaster()->MovePoint(POINT_CONSUME, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
|
||||
}
|
||||
|
||||
Charge_Timer = urand(8000, 16000);
|
||||
}
|
||||
else Charge_Timer -= diff;
|
||||
|
||||
//KnockBack_Timer
|
||||
if (KnockBack_Timer <= diff)
|
||||
if (Creature* kri = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KRI)))
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCKBACK);
|
||||
if (DoGetThreat(me->GetVictim()))
|
||||
DoModifyThreatPercent(me->GetVictim(), -80);
|
||||
KnockBack_Timer = urand(15000, 25000);
|
||||
if (kri->GetGUID() != me->GetGUID())
|
||||
{
|
||||
kri->AI()->DoAction(ACTION_CONSUME);
|
||||
kri->GetMotionMaster()->MovePoint(POINT_CONSUME, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
|
||||
}
|
||||
}
|
||||
else KnockBack_Timer -= diff;
|
||||
|
||||
//Enrage_Timer
|
||||
if (!Enraged && Enrage_Timer <= diff)
|
||||
if (Creature* yauj = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_YAUJ)))
|
||||
{
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
Enraged = true;
|
||||
if (yauj->GetGUID() != me->GetGUID())
|
||||
{
|
||||
yauj->AI()->DoAction(ACTION_CONSUME);
|
||||
yauj->GetMotionMaster()->MovePoint(POINT_CONSUME, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
|
||||
}
|
||||
}
|
||||
else Charge_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
_scheduler.Schedule(4s, [this](TaskContext /*context*/)
|
||||
{
|
||||
if (!me->IsInEvadeMode())
|
||||
{
|
||||
DoCastSelf(SPELL_BLOODY_DEATH, true);
|
||||
Talk(EMOTE_DEVOURED);
|
||||
me->DespawnOrUnsummon(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void DoFinalSpell()
|
||||
{
|
||||
switch (me->GetEntry())
|
||||
{
|
||||
case NPC_KRI:
|
||||
DoCastSelf(SPELL_POISON_CLOUD, true);
|
||||
break;
|
||||
case NPC_VEM:
|
||||
DoCastSelf(SPELL_VENGEANCE, true);
|
||||
break;
|
||||
case NPC_YAUJ:
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
{
|
||||
Position randomPos;
|
||||
me->GetRandomContactPoint(me, randomPos.m_positionX, randomPos.m_positionY, randomPos.m_positionZ);
|
||||
if (Creature* summon = me->SummonCreature(NPC_YAUJ_BROOD, randomPos))
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
if (killer->GetGUID() == me->GetGUID())
|
||||
{
|
||||
instance->SetData(DATA_BUG_TRIO_DEATH, 1);
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
TaskScheduler _scheduler;
|
||||
bool dying;
|
||||
bool isEating;
|
||||
};
|
||||
|
||||
class boss_yauj : public CreatureScript
|
||||
struct boss_kri : public boss_bug_trio
|
||||
{
|
||||
public:
|
||||
boss_yauj() : CreatureScript("boss_yauj") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_kri(Creature* creature) : boss_bug_trio(creature)
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_yaujAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_yaujAI : public ScriptedAI
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
boss_yaujAI(Creature* creature) : ScriptedAI(creature)
|
||||
EnterCombatWithTrio(who);
|
||||
|
||||
_scheduler.Schedule(4s, 8s, [this](TaskContext context)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
uint32 Heal_Timer;
|
||||
uint32 Fear_Timer;
|
||||
uint32 Check_Timer;
|
||||
|
||||
bool VemDead;
|
||||
|
||||
void Reset() override
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
context.Repeat(5s, 12s);
|
||||
})
|
||||
.Schedule(6s, 30s, [this](TaskContext context)
|
||||
{
|
||||
Heal_Timer = urand(25000, 40000);
|
||||
Fear_Timer = urand(12000, 24000);
|
||||
Check_Timer = 2000;
|
||||
|
||||
VemDead = false;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
DoCastVictim(SPELL_TOXIC_VOLLEY);
|
||||
context.Repeat(10s, 25s);
|
||||
})
|
||||
.Schedule(6s, [this](TaskContext context)
|
||||
{
|
||||
if (instance->GetData(DATA_BUG_TRIO_DEATH) < 2)// Unlootable if death
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
instance->SetData(DATA_BUG_TRIO_DEATH, 1);
|
||||
DoCastVictim(SPELL_THRASH);
|
||||
context.Repeat(2s, 6s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
struct boss_vem : public boss_bug_trio
|
||||
{
|
||||
boss_vem(Creature* creature) : boss_bug_trio(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
EnterCombatWithTrio(who);
|
||||
|
||||
_scheduler.Schedule(15s, 27s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [this](Unit* target) -> bool
|
||||
{
|
||||
if (Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000))
|
||||
Summoned->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
if (me->IsWithinMeleeRange(target) || target == me->GetVictim())
|
||||
return false;
|
||||
if (!me->IsWithinLOS(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()))
|
||||
return false;
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
DoCast(target, SPELL_CHARGE);
|
||||
}
|
||||
context.Repeat(8s, 16s);
|
||||
})
|
||||
.Schedule(10s, 20s, [this](TaskContext context)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
DoCastVictim(SPELL_KNOCKBACK);
|
||||
context.Repeat(10s, 20s);
|
||||
})
|
||||
.Schedule(5s, 8s, [this](TaskContext context)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//Fear_Timer
|
||||
if (Fear_Timer <= diff)
|
||||
DoCastVictim(SPELL_KNOCKDOWN);
|
||||
context.Repeat(15s, 20s);
|
||||
})
|
||||
.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
if (instance->GetData(DATA_BUG_TRIO_DEATH) == 2 && !me->HasAura(SPELL_VENGEANCE)) // Vem is the only one left.
|
||||
{
|
||||
DoCastVictim(SPELL_FEAR);
|
||||
DoResetThreat();
|
||||
Fear_Timer = 20000;
|
||||
DoCastSelf(SPELL_VENGEANCE, true);
|
||||
}
|
||||
else Fear_Timer -= diff;
|
||||
context.Repeat(1s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//Casting Heal to other twins or herself.
|
||||
if (Heal_Timer <= diff)
|
||||
struct boss_yauj : public boss_bug_trio
|
||||
{
|
||||
boss_yauj(Creature* creature) : boss_bug_trio(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
EnterCombatWithTrio(who);
|
||||
|
||||
_scheduler.Schedule(20s, 30s, [this](TaskContext context)
|
||||
{
|
||||
if (me->GetHealthPct() <= 93.f)
|
||||
{
|
||||
switch (urand(0, 2))
|
||||
{
|
||||
case 0:
|
||||
if (Creature* kri = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KRI)))
|
||||
DoCast(kri, SPELL_HEAL);
|
||||
break;
|
||||
case 1:
|
||||
if (Creature* vem = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VEM)))
|
||||
DoCast(vem, SPELL_HEAL);
|
||||
break;
|
||||
case 2:
|
||||
DoCast(me, SPELL_HEAL);
|
||||
break;
|
||||
}
|
||||
|
||||
Heal_Timer = 15000 + rand() % 15000;
|
||||
DoCastSelf(SPELL_HEAL);
|
||||
}
|
||||
else Heal_Timer -= diff;
|
||||
|
||||
//Checking if Vem is dead. If yes we will enrage.
|
||||
if (Check_Timer <= diff)
|
||||
else if (Unit* friendly = DoSelectLowestHpFriendly(100.f))
|
||||
{
|
||||
if (!VemDead)
|
||||
{
|
||||
if (instance->GetData(DATA_VEMISDEAD))
|
||||
{
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
VemDead = true;
|
||||
}
|
||||
}
|
||||
Check_Timer = 2000;
|
||||
DoCast(friendly, SPELL_HEAL);
|
||||
}
|
||||
else Check_Timer -= diff;
|
||||
context.Repeat(10s, 30s);
|
||||
})
|
||||
.Schedule(12s, 24s, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_FEAR);
|
||||
DoResetThreat();
|
||||
context.Repeat(20s);
|
||||
})
|
||||
.Schedule(12s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_RAVAGE);
|
||||
context.Repeat(10s, 15s);
|
||||
})
|
||||
.Schedule(10s, 30s, [this](TaskContext context)
|
||||
{
|
||||
std::list<Creature*> targets = DoFindFriendlyCC(50.f);
|
||||
if (!targets.empty())
|
||||
{
|
||||
if (Creature* target = *(targets.begin()))
|
||||
me->CastSpell(target, SPELL_DISPEL);
|
||||
}
|
||||
context.Repeat(10s, 15s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
class spell_vem_knockback : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_vem_knockback);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
if (Creature* cCaster = GetCaster()->ToCreature())
|
||||
{
|
||||
cCaster->getThreatMgr().modifyThreatPercent(target, -80);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_vem_knockback::HandleScriptEffect, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_vem_vengeance : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_vem_vengeance);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
targets.remove_if([&](WorldObject const* target) -> bool
|
||||
{
|
||||
return target->GetEntry() != NPC_YAUJ && target->GetEntry() != NPC_VEM && target->GetEntry() != NPC_KRI;
|
||||
});
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_vem_vengeance::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_bug_trio()
|
||||
{
|
||||
new boss_kri();
|
||||
new boss_vem();
|
||||
new boss_yauj();
|
||||
RegisterCreatureAI(boss_kri);
|
||||
RegisterCreatureAI(boss_vem);
|
||||
RegisterCreatureAI(boss_yauj);
|
||||
RegisterSpellScript(spell_vem_knockback);
|
||||
RegisterSpellScript(spell_vem_vengeance);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
ObjectGuid SkeramGUID;
|
||||
ObjectGuid VemGUID;
|
||||
ObjectGuid KriGUID;
|
||||
ObjectGuid YaujGUID;
|
||||
ObjectGuid VeklorGUID;
|
||||
ObjectGuid VeknilashGUID;
|
||||
ObjectGuid ViscidusGUID;
|
||||
@@ -88,6 +89,9 @@ public:
|
||||
case NPC_KRI:
|
||||
KriGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_YAUJ:
|
||||
YaujGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_VEKLOR:
|
||||
VeklorGUID = creature->GetGUID();
|
||||
break;
|
||||
@@ -106,11 +110,6 @@ public:
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_VEMISDEAD:
|
||||
if (IsBossDied[0])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case DATA_VEKLORISDEAD:
|
||||
if (IsBossDied[1])
|
||||
return 1;
|
||||
@@ -140,6 +139,8 @@ public:
|
||||
return VemGUID;
|
||||
case DATA_KRI:
|
||||
return KriGUID;
|
||||
case DATA_YAUJ:
|
||||
return YaujGUID;
|
||||
case DATA_VEKLOR:
|
||||
return VeklorGUID;
|
||||
case DATA_VEKNILASH:
|
||||
@@ -155,12 +156,11 @@ public:
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_VEM_DEATH:
|
||||
IsBossDied[0] = true;
|
||||
break;
|
||||
|
||||
case DATA_BUG_TRIO_DEATH:
|
||||
++BugTrioDeathCount;
|
||||
if (data != 0)
|
||||
++BugTrioDeathCount;
|
||||
else
|
||||
BugTrioDeathCount = 0;
|
||||
break;
|
||||
|
||||
case DATA_VEKLOR_DEATH:
|
||||
|
||||
@@ -27,8 +27,8 @@ enum DataTypes
|
||||
DATA_SKERAM = 1,
|
||||
DATA_KRI = 2,
|
||||
DATA_VEM = 3,
|
||||
DATA_VEMISDEAD = 4,
|
||||
DATA_VEM_DEATH = 5,
|
||||
DATA_YAUJ = 4,
|
||||
DATA_BUG_TRIO = 5,
|
||||
DATA_VEKLOR = 6,
|
||||
DATA_VEKLORISDEAD = 7,
|
||||
DATA_VEKLOR_DEATH = 8,
|
||||
@@ -60,6 +60,7 @@ enum Creatures
|
||||
NPC_SKERAM = 15263,
|
||||
NPC_VEM = 15544,
|
||||
NPC_KRI = 15511,
|
||||
NPC_YAUJ = 15543,
|
||||
NPC_VEKLOR = 15276,
|
||||
NPC_VEKNILASH = 15275,
|
||||
NPC_OURO = 15517,
|
||||
|
||||
@@ -80,14 +80,14 @@ enum AuriayaEvents
|
||||
EVENT_ENRAGE = 10,
|
||||
};
|
||||
|
||||
enum AuriayaSounds
|
||||
enum Texts
|
||||
{
|
||||
SOUND_AGGRO = 15473,
|
||||
SOUND_SLAY1 = 15474,
|
||||
SOUND_SLAY2 = 15475,
|
||||
SOUND_DEATH = 15476,
|
||||
SOUND_BERSERK = 15477,
|
||||
SOUND_WOUND = 15478,
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_BERSERK = 2,
|
||||
EMOTE_DEATH = 3,
|
||||
EMOTE_FEAR = 4,
|
||||
EMOTE_DEFFENDER = 5,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
@@ -186,26 +186,16 @@ public:
|
||||
|
||||
summons.DoZoneInCombat(NPC_SANCTUM_SENTRY);
|
||||
|
||||
me->Yell("Some things are better left alone!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_AGGRO);
|
||||
Talk(SAY_AGGRO);
|
||||
me->setActive(true);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (urand(0, 2))
|
||||
if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
|
||||
return;
|
||||
|
||||
if (urand(0, 1))
|
||||
{
|
||||
me->Yell("The secret dies with you!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAY1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("There is no escape!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAY2);
|
||||
}
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -216,8 +206,7 @@ public:
|
||||
EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
|
||||
summons.DoAction(ACTION_DESPAWN_ADDS, pred);
|
||||
summons.DespawnAll();
|
||||
me->TextEmote("Auriaya screams in agony.", nullptr, true);
|
||||
me->PlayDirectSound(SOUND_DEATH);
|
||||
Talk(EMOTE_DEATH);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
@@ -240,7 +229,7 @@ public:
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SUMMON_FERAL_DEFENDER:
|
||||
me->TextEmote("Auriaya begins to activate Feral Defender.", nullptr, true);
|
||||
Talk(EMOTE_DEFFENDER);
|
||||
me->CastSpell(me, SPELL_ACTIVATE_FERAL_DEFENDER, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
|
||||
events.ScheduleEvent(EVENT_REMOVE_IMMUNE, 3000);
|
||||
@@ -249,7 +238,7 @@ public:
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
|
||||
break;
|
||||
case EVENT_TERRIFYING_SCREECH:
|
||||
me->TextEmote("Auriaya begins to cast Terrifying Screech.", nullptr, true);
|
||||
Talk(EMOTE_FEAR);
|
||||
me->CastSpell(me, SPELL_TERRIFYING_SCREECH, false);
|
||||
events.RepeatEvent(35000);
|
||||
break;
|
||||
@@ -273,8 +262,7 @@ public:
|
||||
break;
|
||||
}
|
||||
case EVENT_ENRAGE:
|
||||
me->TextEmote("You waste my time!", nullptr, true);
|
||||
me->PlayDirectSound(SOUND_BERSERK);
|
||||
Talk(SAY_BERSERK);
|
||||
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -183,25 +183,26 @@ enum FreyaEvents
|
||||
EVENT_DETONATING_LASHER_FLAME_LASH = 55,
|
||||
};
|
||||
|
||||
enum FreyaSounds
|
||||
enum Texts
|
||||
{
|
||||
// STONEBARK
|
||||
SOUND_STONEBARK_AGGRO = 15500,
|
||||
SOUND_STONEBARK_SLAY1 = 15501,
|
||||
SOUND_STONEBARK_SLAY2 = 15502,
|
||||
SOUND_STONEBARK_DEATH = 15503,
|
||||
// Elder Brightleaf / Elder Ironbranch / Elder Stonebark
|
||||
SAY_ELDER_AGGRO = 0,
|
||||
SAY_ELDER_SLAY = 1,
|
||||
SAY_ELDER_DEATH = 2,
|
||||
|
||||
// IRONBRANCH
|
||||
SOUND_IRONBRANCH_AGGRO = 15493,
|
||||
SOUND_IRONBRANCH_SLAY1 = 15494,
|
||||
SOUND_IRONBRANCH_SLAY2 = 15495,
|
||||
SOUND_IRONBRANCH_DEATH = 15496,
|
||||
|
||||
// BRIGHTLEAF
|
||||
SOUND_BRIGHTLEAF_AGGRO = 15483,
|
||||
SOUND_BRIGHTLEAF_SLAY1 = 15485,
|
||||
SOUND_BRIGHTLEAF_SLAY2 = 15486,
|
||||
SOUND_BRIGHTLEAF_DEATH = 15487,
|
||||
// Freya
|
||||
SAY_AGGRO = 0,
|
||||
SAY_AGGRO_WITH_ELDER = 1,
|
||||
SAY_SLAY = 2,
|
||||
SAY_DEATH = 3,
|
||||
SAY_BERSERK = 4,
|
||||
SAY_SUMMON_CONSERVATOR = 5,
|
||||
SAY_SUMMON_TRIO = 6,
|
||||
SAY_SUMMON_LASHERS = 7,
|
||||
EMOTE_LIFEBINDERS_GIFT = 8,
|
||||
EMOTE_ALLIES_OF_NATURE = 9,
|
||||
EMOTE_GROUND_TREMOR = 10,
|
||||
EMOTE_IRON_ROOTS = 11,
|
||||
};
|
||||
|
||||
enum FreyaNPCs
|
||||
@@ -224,20 +225,6 @@ enum FreyaNPCs
|
||||
NPC_DETONATING_LASHER = 32918,
|
||||
};
|
||||
|
||||
enum FreyaSouns
|
||||
{
|
||||
SOUND_AGGRO = 15526,
|
||||
SOUND_ELDERS = 15527,
|
||||
SOUND_CONSERVATOR = 15528,
|
||||
SOUND_SLAY1 = 15529,
|
||||
SOUND_SLAY2 = 15530,
|
||||
SOUND_DEATH = 15531,
|
||||
SOUND_BERSERK = 15532,
|
||||
SOUND_TRIO = 15533,
|
||||
SOUND_DETONATING = 15534,
|
||||
SOUND_ASKHELP = 15535,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
ACTION_REMOVE_10_STACK = 10,
|
||||
@@ -322,32 +309,21 @@ public:
|
||||
if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
|
||||
return;
|
||||
|
||||
if (urand(0, 1))
|
||||
{
|
||||
me->Yell("Forgive me.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAY1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("From your death springs life anew!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAY2);
|
||||
}
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
// kaboom!
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
me->Yell("His hold on me dissipates. I can see clearly once more. Thank you, heroes.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_DEATH);
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
damage = 0;
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
me->SetHealth(me->GetMaxHealth());
|
||||
me->CombatStop();
|
||||
me->RemoveAllAuras();
|
||||
me->AttackStop();
|
||||
events.Reset();
|
||||
|
||||
summons.DespawnAll();
|
||||
@@ -360,7 +336,7 @@ public:
|
||||
continue;
|
||||
|
||||
if (Creature* e = ObjectAccessor::GetCreature(*me, _elderGUID[i]))
|
||||
Unit::Kill(e, e);
|
||||
e->DespawnOrUnsummon();
|
||||
|
||||
++_elderCount;
|
||||
}
|
||||
@@ -397,12 +373,12 @@ public:
|
||||
void SpawnWave()
|
||||
{
|
||||
_waveNumber = _waveNumber == 1 ? 3 : _waveNumber - 1;
|
||||
Talk(EMOTE_ALLIES_OF_NATURE);
|
||||
|
||||
// Wave of three
|
||||
if (_waveNumber == 1)
|
||||
{
|
||||
me->Yell("Children, assist me!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_TRIO);
|
||||
Talk(SAY_SUMMON_TRIO);
|
||||
me->SummonCreature(NPC_ANCIENT_WATER_SPIRIT, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
me->SummonCreature(NPC_STORM_LASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
me->SummonCreature(NPC_SNAPLASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
@@ -410,15 +386,13 @@ public:
|
||||
// Ancient Conservator
|
||||
else if (_waveNumber == 2)
|
||||
{
|
||||
me->Yell("Eonar, your servant requires aid!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_CONSERVATOR);
|
||||
Talk(SAY_SUMMON_CONSERVATOR);
|
||||
me->SummonCreature(NPC_ANCIENT_CONSERVATOR, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN);
|
||||
}
|
||||
// Detonating Lashers
|
||||
else if (_waveNumber == 3)
|
||||
{
|
||||
me->Yell("The swarm of the elements shall overtake you!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_DETONATING);
|
||||
Talk(SAY_SUMMON_LASHERS);
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
me->SummonCreature(NPC_DETONATING_LASHER, me->GetPositionX() + urand(5, 20), me->GetPositionY() + urand(5, 20), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN);
|
||||
}
|
||||
@@ -553,13 +527,11 @@ public:
|
||||
|
||||
if (_elderGUID[0] || _elderGUID[1] || _elderGUID[2])
|
||||
{
|
||||
me->Yell("Elders, grant me your strength!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_ELDERS);
|
||||
Talk(SAY_AGGRO_WITH_ELDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("The Conservatory must be protected!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_AGGRO);
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,6 +567,7 @@ public:
|
||||
break;
|
||||
case EVENT_FREYA_LIFEBINDER:
|
||||
{
|
||||
Talk(EMOTE_LIFEBINDERS_GIFT);
|
||||
events.RepeatEvent(45000);
|
||||
float x, y, z;
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
@@ -643,15 +616,16 @@ public:
|
||||
break;
|
||||
}
|
||||
case EVENT_FREYA_BERSERK:
|
||||
me->Yell("You have strayed too far, wasted too much time!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_BERSERK);
|
||||
Talk(SAY_BERSERK);
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
case EVENT_FREYA_GROUND_TREMOR:
|
||||
Talk(EMOTE_GROUND_TREMOR);
|
||||
me->CastSpell(me, SPELL_GROUND_TREMOR_FREYA, false);
|
||||
events.RepeatEvent(25000 + urand(0, 10000));
|
||||
break;
|
||||
case EVENT_FREYA_IRON_ROOT:
|
||||
Talk(EMOTE_IRON_ROOTS);
|
||||
me->CastCustomSpell(SPELL_IRON_ROOTS_FREYA, SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
events.RepeatEvent(45000 + urand(0, 10000));
|
||||
break;
|
||||
@@ -706,24 +680,14 @@ public:
|
||||
if (urand(0, 1))
|
||||
return;
|
||||
|
||||
if (urand(0, 1))
|
||||
{
|
||||
me->TextEmote("Angry roar");
|
||||
me->PlayDirectSound(SOUND_STONEBARK_SLAY1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("Such a waste.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_STONEBARK_SLAY2);
|
||||
}
|
||||
Talk(SAY_ELDER_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
if (killer && me->GetEntry() == killer->GetEntry())
|
||||
return;
|
||||
me->Yell("Matron, flee! They are ruthless....", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_STONEBARK_DEATH);
|
||||
Talk(SAY_ELDER_DEATH);
|
||||
|
||||
// Lumberjacked
|
||||
if (me->GetInstanceScript())
|
||||
@@ -737,8 +701,8 @@ public:
|
||||
events.ScheduleEvent(EVENT_STONEBARK_GROUND_TREMOR, 5000);
|
||||
events.ScheduleEvent(EVENT_STONEBARK_PETRIFIED_BARK, 20000);
|
||||
|
||||
me->Yell("This place will serve as your graveyard.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_STONEBARK_AGGRO);
|
||||
if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
|
||||
Talk(SAY_ELDER_AGGRO);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType damageType, SpellSchoolMask damageSchoolMask) override
|
||||
@@ -812,24 +776,14 @@ public:
|
||||
if (urand(0, 1))
|
||||
return;
|
||||
|
||||
if (urand(0, 1))
|
||||
{
|
||||
me->Yell("Fertilizer.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_BRIGHTLEAF_SLAY1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("Your corpse will nourish the soil!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_BRIGHTLEAF_SLAY2);
|
||||
}
|
||||
Talk(SAY_ELDER_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
if (killer && me->GetEntry() == killer->GetEntry())
|
||||
return;
|
||||
me->Yell("Matron, one has fallen!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_BRIGHTLEAF_DEATH);
|
||||
Talk(SAY_ELDER_DEATH);
|
||||
|
||||
// Lumberjacked
|
||||
if (me->GetInstanceScript())
|
||||
@@ -843,8 +797,8 @@ public:
|
||||
events.ScheduleEvent(EVENT_BRIGHTLEAF_SOLAR_FLARE, 5000);
|
||||
events.ScheduleEvent(EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM, 8000);
|
||||
|
||||
me->Yell("Matron, the Conservatory has been breached!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_BRIGHTLEAF_AGGRO);
|
||||
if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
|
||||
Talk(SAY_ELDER_AGGRO);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -933,24 +887,14 @@ public:
|
||||
if (urand(0, 1))
|
||||
return;
|
||||
|
||||
if (urand(0, 1))
|
||||
{
|
||||
me->Yell("I return you whence you came!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_IRONBRANCH_SLAY1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("BEGONE!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_IRONBRANCH_SLAY2);
|
||||
}
|
||||
Talk(SAY_ELDER_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
if (killer && me->GetEntry() == killer->GetEntry())
|
||||
return;
|
||||
me->Yell("Freya! They come for you.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_IRONBRANCH_DEATH);
|
||||
Talk(SAY_ELDER_DEATH);
|
||||
|
||||
// Lumberjacked
|
||||
if (me->GetInstanceScript())
|
||||
@@ -964,8 +908,8 @@ public:
|
||||
events.ScheduleEvent(EVENT_IRONBRANCH_IRON_ROOT, 15000);
|
||||
events.ScheduleEvent(EVENT_IRONBRANCH_THORN_SWARM, 3000);
|
||||
|
||||
me->Yell("Mortals have no place here!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_IRONBRANCH_AGGRO);
|
||||
if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
|
||||
Talk(SAY_ELDER_AGGRO);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
|
||||
@@ -57,26 +57,17 @@
|
||||
#define NPC_SCORCHED_GROUND 33123
|
||||
#define NPC_WATER_TRIGGER 22515
|
||||
|
||||
#define TEXT_AGGRO "Insolent whelps! Your blood will temper the weapons used to reclaim this world!"
|
||||
#define TEXT_ACTIVATE_CONSTRUCT "Arise, soldiers of the Iron Crucible! The Makers' will be done!"
|
||||
#define TEXT_SCORCH_1 "Let the inferno consume you!"
|
||||
#define TEXT_SCORCH_2 "BURN! Burn in the makers fire!"
|
||||
#define TEXT_SLAG_POT "I will burn away your impurities!"
|
||||
#define TEXT_SLAY_1 "More scraps for the scrapheap!"
|
||||
#define TEXT_SLAY_2 "Your bones will serve as kindling!"
|
||||
#define TEXT_BERSERK "Let it be finished!"
|
||||
#define TEXT_DEATH "I. Have. Failed."
|
||||
#define TEXT_FLAME_JETS "Ignis The Furnace Master begins to cast Flame Jets!"
|
||||
|
||||
#define SOUND_AGGRO 15564
|
||||
#define SOUND_ACTIVATE_CONSTRUCT 15565
|
||||
#define SOUND_SLAG_POT 15566
|
||||
#define SOUND_SCORCH_1 15567
|
||||
#define SOUND_SCORCH_2 15568
|
||||
#define SOUND_SLAY_1 15569
|
||||
#define SOUND_SLAY_2 15570
|
||||
#define SOUND_BERSERK 15571
|
||||
#define SOUND_DEATH 15572
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SUMMON = 1,
|
||||
SAY_SLAG_POT = 2,
|
||||
SAY_SCORCH = 3,
|
||||
SAY_SLAY = 4,
|
||||
SAY_BERSERK = 5,
|
||||
SAY_DEATH = 6,
|
||||
EMOTE_JETS = 7,
|
||||
};
|
||||
|
||||
#define ACHIEV_STOKIN_THE_FURNACE_EVENT 20951
|
||||
|
||||
@@ -260,8 +251,7 @@ public:
|
||||
events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32000);
|
||||
events.ScheduleEvent(EVENT_GRAB, 25000);
|
||||
|
||||
me->Yell(TEXT_AGGRO, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_AGGRO);
|
||||
Talk(SAY_AGGRO);
|
||||
DoZoneInCombat();
|
||||
|
||||
if( InstanceScript* m_pInstance = me->GetInstanceScript() )
|
||||
@@ -296,24 +286,15 @@ public:
|
||||
me->setActive(false);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if( rand() % 2 )
|
||||
{
|
||||
me->Yell(TEXT_SLAY_1, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAY_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell(TEXT_SLAY_2, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAY_2);
|
||||
}
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
me->Yell(TEXT_DEATH, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_DEATH);
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
if( me->GetInstanceScript() )
|
||||
me->GetInstanceScript()->SetData(TYPE_IGNIS, DONE);
|
||||
@@ -357,27 +338,18 @@ public:
|
||||
case 0:
|
||||
break;
|
||||
case EVENT_ACTIVATE_CONSTRUCT:
|
||||
Talk(SAY_SUMMON);
|
||||
me->CastCustomSpell(SPELL_ACTIVATE_CONSTRUCT, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
|
||||
if (++counter >= 20)
|
||||
{
|
||||
me->Yell(TEXT_BERSERK, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_BERSERK);
|
||||
Talk(SAY_BERSERK);
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
}
|
||||
events.RepeatEvent(RAID_MODE(40000, 30000));
|
||||
break;
|
||||
case EVENT_SPELL_SCORCH:
|
||||
if( rand() % 2 )
|
||||
{
|
||||
me->Yell(TEXT_SCORCH_1, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SCORCH_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell(TEXT_SCORCH_2, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SCORCH_2);
|
||||
}
|
||||
Talk(SAY_SCORCH);
|
||||
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||
me->DisableRotate(true);
|
||||
me->SendMovementFlagUpdate();
|
||||
@@ -390,7 +362,7 @@ public:
|
||||
me->DisableRotate(false);
|
||||
break;
|
||||
case EVENT_SPELL_FLAME_JETS:
|
||||
me->TextEmote(TEXT_FLAME_JETS, nullptr, true);
|
||||
Talk(EMOTE_JETS);
|
||||
me->CastSpell(me->GetVictim(), S_FLAME_JETS, false);
|
||||
events.RepeatEvent(25000);
|
||||
break;
|
||||
@@ -429,8 +401,7 @@ public:
|
||||
int8 pos = urand(0, playerGUIDs.size() - 1);
|
||||
if( Player* pTarget = ObjectAccessor::GetPlayer(*me, playerGUIDs.at(pos)) )
|
||||
{
|
||||
me->Yell(TEXT_SLAG_POT, LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(SOUND_SLAG_POT);
|
||||
Talk(SAY_SLAG_POT);
|
||||
me->CastSpell(pTarget, SPELL_GRAB, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,72 +25,68 @@
|
||||
#include "WaypointMgr.h"
|
||||
#include "ulduar.h"
|
||||
|
||||
#define SPELL_FLAMEBUFFET_10 64016
|
||||
#define SPELL_FLAMEBUFFET_25 64023
|
||||
#define S_FLAMEBUFFET RAID_MODE(SPELL_FLAMEBUFFET_10, SPELL_FLAMEBUFFET_25)
|
||||
#define SPELL_FIREBALL 63815
|
||||
#define SPELL_WINGBUFFET 62666
|
||||
#define SPELL_FLAMEBREATH_10 63317
|
||||
#define SPELL_FLAMEBREATH_25 64021
|
||||
#define S_FLAMEBREATH RAID_MODE(SPELL_FLAMEBREATH_10, SPELL_FLAMEBREATH_25)
|
||||
#define SPELL_FUSEARMOR 64771
|
||||
#define SPELL_DEVOURINGFLAME 63236
|
||||
#define SPELL_BERSERK 47008
|
||||
enum Spells
|
||||
{
|
||||
// Razorscale
|
||||
SPELL_FLAMEBUFFET_10 = 64016,
|
||||
SPELL_FLAMEBUFFET_25 = 64023,
|
||||
SPELL_FIREBALL = 63815,
|
||||
SPELL_WINGBUFFET = 62666,
|
||||
SPELL_FLAMEBREATH_10 = 63317,
|
||||
SPELL_FLAMEBREATH_25 = 64021,
|
||||
SPELL_FUSEARMOR = 64771,
|
||||
SPELL_FUSED_ARMOR = 64774, // Applied on 5th stack of SPELL_FUSEARMOR
|
||||
SPELL_DEVOURINGFLAME = 63236,
|
||||
SPELL_BERSERK = 47008,
|
||||
|
||||
#define SPELL_CHAIN_1 49679
|
||||
#define SPELL_CHAIN_2 49682
|
||||
#define SPELL_CHAIN_3 49683
|
||||
#define SPELL_CHAIN_4 49684
|
||||
#define SPELL_LAUNCH_CHAIN 62505
|
||||
//#define SPELL_HARPOON_SHOT_BUFF 62509
|
||||
//#define SPELL_HARPOON_FIRE_STATE 62696
|
||||
// Haproons
|
||||
SPELL_CHAIN_1 = 49679,
|
||||
SPELL_CHAIN_2 = 49682,
|
||||
SPELL_CHAIN_3 = 49683,
|
||||
SPELL_CHAIN_4 = 49684,
|
||||
SPELL_LAUNCH_CHAIN = 62505,
|
||||
|
||||
// Dark Rune Sentinel
|
||||
SPELL_WHIRLWIND = 63808,
|
||||
SPELL_BATTLE_SHOUT_10 = 46763,
|
||||
SPELL_BATTLE_SHOUT_25 = 64062,
|
||||
|
||||
// Dark Rune Guardian
|
||||
SPELL_STORMSTRIKE_DMG = 65971,
|
||||
SPELL_STORMSTRIKE_DEBUFF = 64757,
|
||||
|
||||
// Dark Rune Watcher
|
||||
SPELL_LIGHTINGBOLT_10 = 63809,
|
||||
SPELL_LIGHTINGBOLT_25 = 64696,
|
||||
SPELL_CHAINLIGHTNING_10 = 64758,
|
||||
SPELL_CHAINLIGHTNING_25 = 64759,
|
||||
};
|
||||
|
||||
#define SPELL_FLAMEBUFFET RAID_MODE(SPELL_FLAMEBUFFET_10, SPELL_FLAMEBUFFET_25)
|
||||
#define SPELL_FLAMEBREATH RAID_MODE(SPELL_FLAMEBREATH_10, SPELL_FLAMEBREATH_25)
|
||||
#define SPELL_BATTLE_SHOUT RAID_MODE(SPELL_BATTLE_SHOUT_10, SPELL_BATTLE_SHOUT_25)
|
||||
#define SPELL_LIGHTINGBOLT RAID_MODE(SPELL_LIGHTINGBOLT_10, SPELL_LIGHTINGBOLT_25)
|
||||
#define SPELL_CHAINLIGHTNING RAID_MODE(SPELL_CHAINLIGHTNING_10, SPELL_CHAINLIGHTNING_25)
|
||||
#define REQ_CHAIN_COUNT RAID_MODE(2, 4)
|
||||
|
||||
#define SPELL_DEVOURINGFLAME_SUMMON 63308
|
||||
//#define SPELL_DEVOURINGFLAME_GROUNDAURA_10 64709
|
||||
//#define SPELL_DEVOURINGFLAME_GROUNDAURA_25 64734
|
||||
//#define S_DEVOURINGFLAME_GROUNDAURA RAID_MODE(SPELL_DEVOURINGFLAME_GROUNDAURA_10, SPELL_DEVOURINGFLAME_GROUNDAURA_25)
|
||||
//#define NPC_DEVOURINGFLAME 34188
|
||||
#define SPELL_STORMSTRIKE 51876
|
||||
#define SPELL_WHIRLWIND 63808
|
||||
#define SPELL_LIGHTINGBOLT 63809
|
||||
#define SPELL_CHAINLIGHTNING 64758
|
||||
|
||||
#define NPC_DARK_RUNE_SENTINEL 33846
|
||||
#define NPC_DARK_RUNE_GUARDIAN 33388
|
||||
#define NPC_DARK_RUNE_WATCHER 33453
|
||||
#define NPC_EXPEDITION_ENGINEER 33287
|
||||
#define NPC_EXPEDITION_COMMANDER 33210
|
||||
//#define NPC_EXPEDITION_DEFENDER 33816
|
||||
//#define NPC_EXPEDITION_TRAPPER 33259
|
||||
#define NPC_RAZORSCALE 33186
|
||||
//#define NPC_HARPOON_FIRE_STATE 33282
|
||||
|
||||
#define GO_DRILL 195305
|
||||
#define GO_HARPOON_GUN_1 194519
|
||||
#define GO_HARPOON_GUN_2 194541
|
||||
#define GO_HARPOON_GUN_3 194542
|
||||
#define GO_HARPOON_GUN_4 194543
|
||||
#define GO_BROKEN_HARPOON 194565
|
||||
|
||||
#define TEXT_GOSSIP_ACTION "We are ready to help!"
|
||||
#define TEXT_EE_AGGRO "Give us a moment to prepare to build the turrets."
|
||||
#define TEXT_EE_MOVE_OUT "Ready to move out, keep those dwarves off of our backs!"
|
||||
#define TEXT_EE_FIRES_OUT "Fires out! Let's rebuild those turrets!"
|
||||
|
||||
#define TEXT_TURRET_READY "Harpoon Turret is ready for use!"
|
||||
#define TEXT_DEEP_BREATH "Razorscale takes a deep breath..."
|
||||
#define TEXT_GROUNDED_PERMANENTLY "Razorscale grounded permanently!"
|
||||
|
||||
#define CORDS_GROUND 588.0f, -166.0f, 391.1f
|
||||
#define CORDS_AIR 588.0f, -178.0f, 490.0f
|
||||
#define REPAIR_POINTS 25
|
||||
|
||||
enum eSay
|
||||
enum NPCs
|
||||
{
|
||||
SAY_COMMANDER_INTRO = 0,
|
||||
SAY_COMMANDER_GROUND = 1,
|
||||
SAY_COMMANDER_AGGRO = 2
|
||||
NPC_DARK_RUNE_SENTINEL = 33846,
|
||||
NPC_DARK_RUNE_GUARDIAN = 33388,
|
||||
NPC_DARK_RUNE_WATCHER = 33453,
|
||||
NPC_EXPEDITION_ENGINEER = 33287,
|
||||
NPC_EXPEDITION_COMMANDER = 33210,
|
||||
NPC_RAZORSCALE_CONTROLLER = 33233, // Trigger Creature
|
||||
};
|
||||
|
||||
enum GOs
|
||||
{
|
||||
GO_DRILL = 195305,
|
||||
GO_HARPOON_GUN_1 = 194519,
|
||||
GO_HARPOON_GUN_2 = 194541,
|
||||
GO_HARPOON_GUN_3 = 194542,
|
||||
GO_HARPOON_GUN_4 = 194543,
|
||||
GO_BROKEN_HARPOON = 194565,
|
||||
};
|
||||
|
||||
enum eEvents
|
||||
@@ -113,11 +109,40 @@ enum eEvents
|
||||
EVENT_SPELL_FLAME_BUFFET,
|
||||
};
|
||||
|
||||
enum eMisc
|
||||
enum Texts
|
||||
{
|
||||
POINT_RAZORSCALE_INIT = 1
|
||||
// Razorscale
|
||||
EMOTE_PERMA_GROUND = 0,
|
||||
EMOTE_BREATH = 1,
|
||||
EMOTE_BERSERK = 2,
|
||||
|
||||
// Expedition Commander
|
||||
SAY_COMMANDER_AGGRO = 0,
|
||||
SAY_COMMANDER_GROUND_PHASE = 1,
|
||||
SAY_COMMANDER_ENGINEERS_DEAD = 2, // Should be called when all engineers are dead, currently unused
|
||||
|
||||
// Expedition Engineer
|
||||
SAY_EE_AGGRO = 0,
|
||||
SAY_EE_START_REPAIR = 1,
|
||||
SAY_EE_REBUILD_TURRETS = 2,
|
||||
|
||||
// Harpoon
|
||||
EMOTE_HARPOON = 0,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
POINT_RAZORSCALE_INIT = 1,
|
||||
REPAIR_POINTS = 25,
|
||||
|
||||
// Expedition Commander Gossip
|
||||
GOSSIP_MENU_START_ENCOUNTER = 10314,
|
||||
NPC_TEXT_COMMANDER = 40100,
|
||||
};
|
||||
|
||||
const Position CORDS_GROUND = {588.0f, -166.0f, 391.1f};
|
||||
const Position CORDS_AIR = {588.0f, -178.0f, 490.0f};
|
||||
|
||||
class boss_razorscale : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -161,6 +186,11 @@ public:
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
ExpeditionEngineerGUIDs[i].Clear();
|
||||
|
||||
// Show gossip icon if previously hidden
|
||||
if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
|
||||
if (!commander->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP))
|
||||
commander->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
CommanderGUID.Clear();
|
||||
bGroundPhase = false;
|
||||
flyTimes = 0;
|
||||
@@ -195,7 +225,7 @@ public:
|
||||
break;
|
||||
ExpeditionEngineerGUIDs[i] = (*itr)->GetGUID();
|
||||
if (!i)
|
||||
(*itr)->Yell(TEXT_EE_AGGRO, LANG_UNIVERSAL);
|
||||
(*itr)->AI()->Talk(SAY_EE_AGGRO);
|
||||
++i;
|
||||
}
|
||||
if (Creature* c = me->FindNearestCreature(NPC_EXPEDITION_COMMANDER, 300.0f, true))
|
||||
@@ -260,7 +290,7 @@ public:
|
||||
if( count >= REQ_CHAIN_COUNT )
|
||||
{
|
||||
if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
|
||||
commander->AI()->Talk(SAY_COMMANDER_GROUND);
|
||||
commander->AI()->Talk(SAY_COMMANDER_GROUND_PHASE);
|
||||
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
events.CancelEvent(EVENT_SPELL_FIREBALL);
|
||||
@@ -348,8 +378,8 @@ public:
|
||||
case 0:
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
Talk(EMOTE_BERSERK);
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
events.RepeatEvent(600000);
|
||||
break;
|
||||
case EVENT_COMMANDER_SAY_AGGRO:
|
||||
if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
|
||||
@@ -360,7 +390,7 @@ public:
|
||||
if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i]))
|
||||
{
|
||||
if (!i)
|
||||
c->Yell(TEXT_EE_MOVE_OUT, LANG_UNIVERSAL);
|
||||
c->AI()->Talk(SAY_EE_START_REPAIR);
|
||||
c->AI()->SetData(1, 0); // start repairing
|
||||
}
|
||||
break;
|
||||
@@ -454,12 +484,12 @@ public:
|
||||
}
|
||||
break;
|
||||
case EVENT_WARN_DEEP_BREATH:
|
||||
me->TextEmote(TEXT_DEEP_BREATH, nullptr, true);
|
||||
Talk(EMOTE_BREATH);
|
||||
me->RemoveAura(62794);
|
||||
events.ScheduleEvent(EVENT_PHASE2_FLAME_BREATH, 2500);
|
||||
break;
|
||||
case EVENT_PHASE2_FLAME_BREATH:
|
||||
me->CastSpell(me, S_FLAMEBREATH, true);
|
||||
me->CastSpell(me, SPELL_FLAMEBREATH, true);
|
||||
events.ScheduleEvent(EVENT_FLY_UP, 2000);
|
||||
break;
|
||||
case EVENT_FLY_UP:
|
||||
@@ -485,6 +515,7 @@ public:
|
||||
|
||||
if( (me->GetHealth() * 100) / me->GetMaxHealth() < 50 ) // start phase 3
|
||||
{
|
||||
Talk(EMOTE_PERMA_GROUND);
|
||||
me->SetControlled(false, UNIT_STATE_ROOT);
|
||||
me->DisableRotate(false);
|
||||
DoResetThreat();
|
||||
@@ -527,12 +558,12 @@ public:
|
||||
if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i]))
|
||||
{
|
||||
if (!i)
|
||||
c->Yell(TEXT_EE_FIRES_OUT, LANG_UNIVERSAL);
|
||||
c->AI()->Talk(SAY_EE_REBUILD_TURRETS);
|
||||
c->AI()->SetData(1, 0); // start repairing
|
||||
}
|
||||
break;
|
||||
case EVENT_SPELL_FLAME_BREATH:
|
||||
me->CastSpell(me->GetVictim(), S_FLAMEBREATH, false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_FLAMEBREATH, false);
|
||||
events.RepeatEvent(20000);
|
||||
break;
|
||||
case EVENT_SPELL_DEVOURING_FLAME_GROUND:
|
||||
@@ -546,14 +577,14 @@ public:
|
||||
me->CastSpell(victim, SPELL_FUSEARMOR, false);
|
||||
if (Aura* aur = victim->GetAura(SPELL_FUSEARMOR))
|
||||
if (aur->GetStackAmount() == 5)
|
||||
victim->CastSpell(victim, 64774, true);
|
||||
victim->CastSpell(victim, SPELL_FUSED_ARMOR, true);
|
||||
events.RepeatEvent(10000);
|
||||
break;
|
||||
}
|
||||
events.RepeatEvent(2000);
|
||||
break;
|
||||
case EVENT_SPELL_FLAME_BUFFET:
|
||||
me->CastSpell(me->GetVictim(), S_FLAMEBUFFET, false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_FLAMEBUFFET, false);
|
||||
events.RepeatEvent(7000);
|
||||
break;
|
||||
}
|
||||
@@ -619,8 +650,8 @@ public:
|
||||
if (!razorscale || razorscale->IsInCombat())
|
||||
return true;
|
||||
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, TEXT_GOSSIP_ACTION, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
SendGossipMenuFor(player, 40100, creature);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_START_ENCOUNTER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
SendGossipMenuFor(player, NPC_TEXT_COMMANDER, creature);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -638,6 +669,9 @@ public:
|
||||
Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE));
|
||||
if (razorscale && !razorscale->IsInCombat())
|
||||
{
|
||||
// Do not show gossip icon if encounter is in progress
|
||||
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
// reset npcs NPC_HARPOON_FIRE_STATE
|
||||
for (uint8 i = 0; i < 4; ++i)
|
||||
if (Creature* hfs = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i)))
|
||||
@@ -679,7 +713,7 @@ public:
|
||||
return;
|
||||
|
||||
_introSpoken = true;
|
||||
Talk(SAY_COMMANDER_INTRO);
|
||||
//Talk(SAY_COMMANDER_INTRO); // No source leads to showing any text messages, perhaps only SOUND ID 15647 is played?
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -758,7 +792,8 @@ public:
|
||||
if( GameObject* wh = me->SummonGameObject(GetHarpoonGunIdForThisHFS(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 3 * M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 0) )
|
||||
{
|
||||
me->RemoveGameObject(wh, false);
|
||||
me->TextEmote(TEXT_TURRET_READY, nullptr, true);
|
||||
if (Creature* cr = me->SummonCreature(NPC_RAZORSCALE_CONTROLLER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 5000))
|
||||
cr->AI()->Talk(EMOTE_HARPOON);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -987,9 +1022,9 @@ public:
|
||||
else timer2 -= diff;
|
||||
if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), 65971, true);
|
||||
me->CastSpell(me->GetVictim(), 65971, true); // me->CastSpell(me->GetVictim(), 65972, true); // cast the same twice cus second one requires setting offhand damage
|
||||
me->CastSpell(me->GetVictim(), 64757, true);
|
||||
me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true);
|
||||
me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); // cast the same twice cus second one requires setting offhand damage
|
||||
me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DEBUFF, true);
|
||||
timer2 = urand(8000, 10000);
|
||||
return;
|
||||
}
|
||||
@@ -1034,7 +1069,7 @@ public:
|
||||
|
||||
if( timer1 <= diff )
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), RAID_MODE(64758, 64759), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_CHAINLIGHTNING, false);
|
||||
timer1 = urand(10000, 12000);
|
||||
return;
|
||||
}
|
||||
@@ -1043,7 +1078,7 @@ public:
|
||||
|
||||
if (timer2 <= diff)
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), RAID_MODE(63809, 64696), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_LIGHTINGBOLT, false);
|
||||
timer2 = 4000;
|
||||
return;
|
||||
}
|
||||
@@ -1090,7 +1125,7 @@ public:
|
||||
|
||||
if( timer1 <= diff )
|
||||
{
|
||||
me->CastSpell(me, RAID_MODE(46763, 64062), false);
|
||||
me->CastSpell(me, SPELL_BATTLE_SHOUT, false);
|
||||
timer1 = urand(15000, 20000);
|
||||
}
|
||||
else
|
||||
@@ -1100,7 +1135,7 @@ public:
|
||||
else timer2 -= diff;
|
||||
if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
me->CastSpell(me, 63808, false);
|
||||
me->CastSpell(me, SPELL_WHIRLWIND, false);
|
||||
timer2 = urand(10000, 12000);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,17 +91,20 @@ enum NPCs
|
||||
NPC_PILE_TRIGGER = 33337,
|
||||
};
|
||||
|
||||
enum Sounds
|
||||
enum Texts
|
||||
{
|
||||
XT_SOUND_AGGRO = 15724,
|
||||
XT_SOUND_HEART_OPEN = 15725,
|
||||
XT_SOUND_HEART_CLOSED = 15726,
|
||||
XT_SOUND_TANTARUM = 15727,
|
||||
XT_SOUND_SLAY1 = 15728,
|
||||
XT_SOUND_SLAY2 = 15729,
|
||||
XT_SOUND_ENRAGE = 15730,
|
||||
XT_SOUND_DEATH = 15731,
|
||||
XT_SOUND_SUMMON = 15732,
|
||||
SAY_AGGRO = 0,
|
||||
SAY_HEART_OPENED = 1,
|
||||
SAY_HEART_CLOSED = 2,
|
||||
SAY_TYMPANIC_TANTRUM = 3,
|
||||
SAY_SLAY = 4,
|
||||
SAY_BERSERK = 5,
|
||||
SAY_DEATH = 6,
|
||||
SAY_SUMMON = 7,
|
||||
EMOTE_HEART_OPENED = 8,
|
||||
EMOTE_HEART_CLOSED = 9,
|
||||
EMOTE_TYMPANIC_TANTRUM = 10,
|
||||
EMOTE_SCRAPBOT = 11,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
@@ -203,8 +206,7 @@ public:
|
||||
RescheduleEvents(); // Other events are scheduled here
|
||||
|
||||
me->setActive(true);
|
||||
me->Yell("New toys? For me? I promise I won't break them this time!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_AGGRO);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
if (m_pInstance)
|
||||
{
|
||||
@@ -223,23 +225,13 @@ public:
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER && !urand(0, 2))
|
||||
{
|
||||
if (urand(0, 1))
|
||||
{
|
||||
me->Yell("I... I think I broke it.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_SLAY1);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->Yell("I guess it doesn't bend that way.", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_SLAY2);
|
||||
}
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
me->Yell("You are bad... Toys... Very... Baaaaad!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_DEATH);
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
if (m_pInstance)
|
||||
{
|
||||
@@ -279,7 +271,7 @@ public:
|
||||
|
||||
me->CastSpell(me, SPELL_HEARTBREAK, true);
|
||||
|
||||
me->TextEmote("XT-002 Deconstructor's heart is severed from his body.", nullptr, true);
|
||||
Talk(EMOTE_HEART_CLOSED);
|
||||
events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4000);
|
||||
return;
|
||||
}
|
||||
@@ -329,8 +321,7 @@ public:
|
||||
me->SetControlled(true, UNIT_STATE_STUNNED);
|
||||
me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); // submerge with animation
|
||||
|
||||
me->Yell("So tired. I will rest for just a moment!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_HEART_OPEN);
|
||||
Talk(SAY_HEART_OPENED);
|
||||
|
||||
events.CancelEventGroup(1);
|
||||
events.ScheduleEvent(EVENT_START_SECOND_PHASE, 5000);
|
||||
@@ -355,21 +346,19 @@ public:
|
||||
events.ScheduleEvent(EVENT_GRAVITY_BOMB, 10000, 1);
|
||||
break;
|
||||
case EVENT_TYMPANIC_TANTARUM:
|
||||
me->TextEmote("XT-002 Deconstructor begins to cause the earth to quake.", nullptr, true);
|
||||
me->Yell("NO! NO! NO! NO! NO!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_TANTARUM);
|
||||
Talk(EMOTE_TYMPANIC_TANTRUM);
|
||||
Talk(SAY_TYMPANIC_TANTRUM);
|
||||
me->CastSpell(me, SPELL_TYMPANIC_TANTARUM, true);
|
||||
events.RepeatEvent(60000);
|
||||
return;
|
||||
case EVENT_ENRAGE:
|
||||
me->Yell("I'm tired of these toys. I don't want to play anymore!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_ENRAGE);
|
||||
Talk(SAY_BERSERK);
|
||||
me->CastSpell(me, SPELL_XT002_ENRAGE, true);
|
||||
break;
|
||||
|
||||
// Animation events
|
||||
case EVENT_START_SECOND_PHASE:
|
||||
me->TextEmote("XT-002 Deconstructor's heart is exposed and leaking energy.", nullptr, true);
|
||||
Talk(EMOTE_HEART_OPENED);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
|
||||
heart->GetAI()->DoAction(ACTION_AWAKEN_HEART);
|
||||
@@ -383,8 +372,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
me->Yell("I'm ready to play!", LANG_UNIVERSAL);
|
||||
me->PlayDirectSound(XT_SOUND_HEART_CLOSED);
|
||||
Talk(SAY_HEART_CLOSED);
|
||||
|
||||
me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
|
||||
// Hide heart
|
||||
@@ -619,7 +607,7 @@ public:
|
||||
}
|
||||
|
||||
if (!urand(0, 2))
|
||||
me->TextEmote("XT-002 Deconstructor consumes scrap bot to repair himself.", nullptr, true);
|
||||
pXT002->AI()->Talk(EMOTE_SCRAPBOT);
|
||||
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
@@ -28,11 +28,14 @@ enum Misc
|
||||
// TEXTS
|
||||
SAY_AGGRO = 0,
|
||||
SAY_KILL = 1,
|
||||
EMOTE_RANGE = 2,
|
||||
SAY_DEATH = 3,
|
||||
SAY_DRAKE_DEATH = 5,
|
||||
SAY_DRAKE_BREATH = 6,
|
||||
|
||||
// EMOTES
|
||||
EMOTE_DEEP_BREATH = 0,
|
||||
EMOTE_RANGE = 1,
|
||||
|
||||
// SPELLS
|
||||
SPELL_CRUSH_N = 50234,
|
||||
SPELL_CRUSH_H = 59330,
|
||||
@@ -41,9 +44,9 @@ enum Misc
|
||||
SPELL_WHIRLWIND_N = 50228,
|
||||
SPELL_WHIRLWIND_H = 50228,
|
||||
|
||||
SPELL_FLAME_VISUAL = 47592,
|
||||
SPELL_FLAME_BREATH_N = 47579,
|
||||
SPELL_FLAME_BREATH_H = 60020,
|
||||
SPELL_FREEZING_CLOUD_VISUAL = 47592,
|
||||
SPELL_FREEZING_CLOUD_N = 47579,
|
||||
SPELL_FREEZING_CLOUD_H = 60020,
|
||||
|
||||
SPELL_LAUNCH_HARPOON = 48642,
|
||||
|
||||
@@ -95,8 +98,6 @@ static Position SkadiPosition[] =
|
||||
{490.76f, -517.389f, 123.368f, 0.0f}
|
||||
};
|
||||
|
||||
#define EMOTE_IN_RANGE "Skadi the Ruthless is within range of the harpoon launchers"
|
||||
|
||||
enum phase
|
||||
{
|
||||
PHASE_NONE,
|
||||
@@ -323,8 +324,8 @@ public:
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == 47593) // SPELL_FLAME_VISUAL trigger
|
||||
target->CastSpell(target, me->GetMap()->IsHeroic() ? SPELL_FLAME_BREATH_H : SPELL_FLAME_BREATH_N, true);
|
||||
if (spellInfo->Id == 47593) // SPELL_FREEZING_CLOUD_VISUAL trigger
|
||||
target->CastSpell(target, me->GetMap()->IsHeroic() ? SPELL_FREEZING_CLOUD_H : SPELL_FREEZING_CLOUD_N, true);
|
||||
}
|
||||
|
||||
void SpawnFlameTriggers(uint8 point)
|
||||
@@ -341,13 +342,13 @@ public:
|
||||
{
|
||||
Creature* cr;
|
||||
if ((cr = me->SummonCreature(NPC_BREATH_TRIGGER, 483, -484.9f, 105, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000)))
|
||||
cr->CastSpell(cr, cr->GetMap()->IsHeroic() ? SPELL_FLAME_BREATH_H : SPELL_FLAME_BREATH_N, true);
|
||||
cr->CastSpell(cr, cr->GetMap()->IsHeroic() ? SPELL_FREEZING_CLOUD_H : SPELL_FREEZING_CLOUD_N, true);
|
||||
if ((cr = me->SummonCreature(NPC_BREATH_TRIGGER, 471.0f, -484.7f, 105, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000)))
|
||||
cr->CastSpell(cr, cr->GetMap()->IsHeroic() ? SPELL_FLAME_BREATH_H : SPELL_FLAME_BREATH_N, true);
|
||||
cr->CastSpell(cr, cr->GetMap()->IsHeroic() ? SPELL_FREEZING_CLOUD_H : SPELL_FREEZING_CLOUD_N, true);
|
||||
|
||||
for (uint8 j = 0; j < 7; j++)
|
||||
if ((cr = me->SummonCreature(NPC_BREATH_TRIGGER, 477.0f, -507.0f + (j * 3), 105.0f, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000)))
|
||||
cr->CastSpell(cr, cr->GetMap()->IsHeroic() ? SPELL_FLAME_BREATH_H : SPELL_FLAME_BREATH_N, true);
|
||||
cr->CastSpell(cr, cr->GetMap()->IsHeroic() ? SPELL_FREEZING_CLOUD_H : SPELL_FREEZING_CLOUD_N, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,15 +358,14 @@ public:
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
me->RemoveAurasDueToSpell(SPELL_FLAME_VISUAL);
|
||||
me->RemoveAurasDueToSpell(SPELL_FREEZING_CLOUD_VISUAL);
|
||||
me->SetFacingTo(M_PI * 2);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (m_pInstance)
|
||||
m_pInstance->SetData(SKADI_IN_RANGE, 1);
|
||||
|
||||
me->TextEmote(EMOTE_IN_RANGE, nullptr, true);
|
||||
Talk(EMOTE_RANGE);
|
||||
me->SetFacingTo(M_PI);
|
||||
break;
|
||||
}
|
||||
@@ -466,8 +466,9 @@ public:
|
||||
me->GetMotionMaster()->MovePoint(targetPoint, SkadiPosition[targetPoint].GetPositionX(), SkadiPosition[targetPoint].GetPositionY(), SkadiPosition[targetPoint].GetPositionZ());
|
||||
if (targetPoint <= 1)
|
||||
{
|
||||
Talk(EMOTE_DEEP_BREATH);
|
||||
SpawnFlameTriggers(targetPoint);
|
||||
me->CastSpell(me, SPELL_FLAME_VISUAL, false);
|
||||
me->CastSpell(me, SPELL_FREEZING_CLOUD_VISUAL, false);
|
||||
}
|
||||
|
||||
if (m_pInstance)
|
||||
|
||||
@@ -1472,6 +1472,48 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum OnslaughtGryphon
|
||||
{
|
||||
SPELL_DELIVER_GRYPHON = 54420,
|
||||
SPELL_ONSLAUGHT_GRYPHON = 49641,
|
||||
|
||||
NPC_CAPTURED_ONSLAUGHT_GRYPHON = 29415,
|
||||
|
||||
SEAT_PLAYER = 0
|
||||
};
|
||||
|
||||
class spell_deliver_gryphon : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_deliver_gryphon);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_DELIVER_GRYPHON, SPELL_ONSLAUGHT_GRYPHON });
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Vehicle* gryphon = caster->GetVehicleKit())
|
||||
{
|
||||
if (Unit* player = gryphon->GetPassenger(SEAT_PLAYER))
|
||||
{
|
||||
player->ExitVehicle();
|
||||
player->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE);
|
||||
player->RemoveAurasDueToSpell(SPELL_ONSLAUGHT_GRYPHON);
|
||||
player->SummonCreature(NPC_CAPTURED_ONSLAUGHT_GRYPHON, 7434.7f, 4213.3f, 316.52f, 3.88f, TEMPSUMMON_TIMED_DESPAWN, 1 * MINUTE * IN_MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_deliver_gryphon::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// Theirs
|
||||
/*######
|
||||
## npc_guardian_pavilion
|
||||
@@ -2159,6 +2201,7 @@ void AddSC_icecrown()
|
||||
new spell_anti_air_rocket_bomber();
|
||||
new npc_infra_green_bomber_generic();
|
||||
new spell_onslaught_or_call_bone_gryphon();
|
||||
RegisterSpellScript(spell_deliver_gryphon);
|
||||
|
||||
// Theirs
|
||||
new npc_guardian_pavilion();
|
||||
|
||||
@@ -28,13 +28,17 @@
|
||||
#define QUEST_SUMMON_AHUNE 11691
|
||||
#define ITEM_MAGMA_TOTEM 34953
|
||||
#define AHUNE_DEFAULT_MODEL 23344
|
||||
#define TEXT_RETREAT "Ahune Retreats. His defenses diminish."
|
||||
#define TEXT_RESURFACE "Ahune will soon resurface."
|
||||
|
||||
const Position AhuneSummonPos = {-97.3473f, -233.139f, -1.27587f, M_PI / 2};
|
||||
const Position TotemPos[3] = { {-115.141f, -143.317f, -2.09467f, 4.92772f}, {-120.178f, -144.398f, -2.23786f, 4.92379f}, {-125.277f, -145.463f, -1.95209f, 4.97877f} };
|
||||
const Position MinionSummonPos = {-97.154404f, -204.382675f, -1.19f, M_PI / 2};
|
||||
|
||||
enum Text
|
||||
{
|
||||
EMOTE_RETREAT = 0,
|
||||
EMOTE_RESURFACE = 1,
|
||||
};
|
||||
|
||||
enum EventSpells
|
||||
{
|
||||
SPELL_STARTING_BEAM = 46593,
|
||||
@@ -192,7 +196,7 @@ public:
|
||||
events.RescheduleEvent(EVENT_SUBMERGE, 10000);
|
||||
break;
|
||||
case EVENT_SUBMERGE:
|
||||
me->TextEmote(TEXT_RETREAT, nullptr, true);
|
||||
Talk(EMOTE_RETREAT);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->CastSpell(me, SPELL_SUBMERGE_0, true);
|
||||
me->CastSpell(me, SPELL_SELF_STUN, true);
|
||||
@@ -205,7 +209,7 @@ public:
|
||||
events.RescheduleEvent(EVENT_EMERGE_WARNING, 20000);
|
||||
break;
|
||||
case EVENT_EMERGE_WARNING:
|
||||
me->TextEmote(TEXT_RESURFACE, nullptr, true);
|
||||
Talk(EMOTE_RESURFACE);
|
||||
break;
|
||||
case EVENT_COMBAT_EMERGE:
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
Reference in New Issue
Block a user