Merge branch 'master' into Playerbot
This commit is contained in:
@@ -964,7 +964,7 @@ Expansion = 2
|
||||
# ClientCacheVersion
|
||||
# Description: Client cache version for client cache data reset. Use any value different
|
||||
# from DB and not recently been used to trigger client side cache reset.
|
||||
# Default: 0 - (Use DB value from world DB db_version.cache_id field)
|
||||
# Default: 0 - (Use DB value from world DB version.cache_id field)
|
||||
|
||||
ClientCacheVersion = 0
|
||||
|
||||
@@ -2826,6 +2826,14 @@ Rate.Creature.Aggro = 1
|
||||
|
||||
CreatureFamilyFleeAssistanceRadius = 30
|
||||
|
||||
#
|
||||
# CreatureLeashRadius
|
||||
# Description: Distance (in yards) for default leash due to being too far from pulled position.
|
||||
# Default: 30 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
|
||||
CreatureLeashRadius = 30
|
||||
|
||||
#
|
||||
# CreatureFamilyAssistanceRadius
|
||||
# Description: Distance for creatures calling for assistance from other creatures without
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
#include "MapReference.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Vehicle.h"
|
||||
#include "ZoneScript.h"
|
||||
#include <functional>
|
||||
|
||||
//Disable CreatureAI when charmed
|
||||
void CreatureAI::OnCharmed(bool /*apply*/)
|
||||
@@ -383,6 +385,115 @@ void CreatureAI::MoveBackwardsChecks()
|
||||
me->GetMotionMaster()->MoveBackwards(victim, moveDist);
|
||||
}
|
||||
|
||||
int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill, bool checkZ) const
|
||||
{
|
||||
static constexpr float BOUNDARY_STEP = 5.0f;
|
||||
static constexpr uint32 BOUNDARY_VISUALIZE_CREATURE = 21659; // Floaty Flavor Eye
|
||||
static constexpr float BOUNDARY_VISUALIZE_CREATURE_SCALE = 0.25f;
|
||||
static constexpr uint32 BOUNDARY_MAX_SPAWNS = 8000;
|
||||
static constexpr float BOUNDARY_MAX_DISTANCE = MAX_SEARCHER_DISTANCE;
|
||||
|
||||
float boundaryStep = fill && checkZ ? BOUNDARY_STEP * 2 : BOUNDARY_STEP;
|
||||
|
||||
Position const boundaryDirections[6] = {
|
||||
{boundaryStep, 0, 0 },
|
||||
{-boundaryStep, 0, 0 },
|
||||
{0, boundaryStep, 0 },
|
||||
{0, -boundaryStep, 0 },
|
||||
{0, 0, boundaryStep },
|
||||
{0, 0, -boundaryStep}
|
||||
};
|
||||
|
||||
if (!owner)
|
||||
return -1;
|
||||
|
||||
if (!_boundary || _boundary->empty())
|
||||
return LANG_CREATURE_MOVEMENT_NOT_BOUNDED;
|
||||
|
||||
Position startPosition = owner->GetPosition();
|
||||
if (!IsInBoundary(&startPosition)) // fall back to creature position
|
||||
{
|
||||
startPosition = me->GetPosition();
|
||||
if (!IsInBoundary(&startPosition)) // fall back to creature home position
|
||||
{
|
||||
startPosition = me->GetHomePosition();
|
||||
if (!IsInBoundary(&startPosition))
|
||||
return LANG_CREATURE_NO_INTERIOR_POINT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to spawn visualization creature
|
||||
auto spawnVisualizationCreature = [owner, duration, checkZ](Position const& pos)
|
||||
{
|
||||
if (TempSummon* summon =
|
||||
owner->SummonCreature(BOUNDARY_VISUALIZE_CREATURE, pos, TEMPSUMMON_TIMED_DESPAWN, duration))
|
||||
{
|
||||
summon->SetObjectScale(BOUNDARY_VISUALIZE_CREATURE_SCALE);
|
||||
summon->SetUnitFlag(UNIT_FLAG_STUNNED);
|
||||
summon->SetImmuneToAll(true);
|
||||
summon->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2);
|
||||
if (!checkZ)
|
||||
summon->SetDisableGravity(false);
|
||||
}
|
||||
};
|
||||
|
||||
struct PositionHash
|
||||
{
|
||||
std::size_t operator()(Position const& pos) const
|
||||
{
|
||||
// Convert to fixed precision coordinates.
|
||||
// We lose precision here, but we don't care about the exact position
|
||||
int32 x = int32(pos.m_positionX);
|
||||
int32 y = int32(pos.m_positionY);
|
||||
int32 z = int32(pos.m_positionZ);
|
||||
|
||||
return std::hash<int32_t>()(x) ^ std::hash<int32_t>()(y) ^ std::hash<int32_t>()(z);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_set<Position, PositionHash> visited;
|
||||
std::queue<Position> queue;
|
||||
queue.push(startPosition);
|
||||
visited.insert(startPosition);
|
||||
uint8 maxDirections = checkZ ? 6 : 4;
|
||||
uint32 spawns = 0;
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
Position currentPosition = queue.front();
|
||||
queue.pop();
|
||||
|
||||
for (uint8 i = 0; i < maxDirections; ++i)
|
||||
{
|
||||
Position const& direction = boundaryDirections[i];
|
||||
Position nextPosition = currentPosition;
|
||||
nextPosition.RelocateOffset(direction);
|
||||
|
||||
if (startPosition.GetExactDist(&nextPosition) > BOUNDARY_MAX_DISTANCE)
|
||||
break;
|
||||
|
||||
if (visited.find(nextPosition) != visited.end())
|
||||
continue; // already visited
|
||||
|
||||
visited.insert(nextPosition);
|
||||
|
||||
bool isInBoundary = IsInBoundary(&nextPosition);
|
||||
|
||||
if ((isInBoundary && fill) || !isInBoundary)
|
||||
{
|
||||
spawnVisualizationCreature(currentPosition);
|
||||
++spawns;
|
||||
if (spawns > BOUNDARY_MAX_SPAWNS)
|
||||
return LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED;
|
||||
}
|
||||
|
||||
if (isInBoundary)
|
||||
queue.push(nextPosition); // continue visiting
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CreatureAI::IsInBoundary(Position const* who) const
|
||||
{
|
||||
if (!_boundary)
|
||||
|
||||
@@ -209,6 +209,9 @@ public:
|
||||
|
||||
virtual void PetStopAttack() { }
|
||||
|
||||
// intended for encounter design/debugging. do not use for other purposes. expensive.
|
||||
int32 VisualizeBoundary(uint32 duration, Unit* owner = nullptr, bool fill = false, bool checkZ = false) const;
|
||||
|
||||
// boundary system methods
|
||||
virtual bool CheckInRoom();
|
||||
CreatureBoundary const* GetBoundary() const { return _boundary; }
|
||||
|
||||
@@ -96,7 +96,7 @@ void BattlegroundRV::PostUpdateImpl(uint32 diff)
|
||||
if (player->GetPositionZ() < 27.0f)
|
||||
TeleportUnitToNewZ(player, 28.28f, true);
|
||||
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM_FIRE; i < MAX_TOTEM_SLOT; ++i)
|
||||
if (player->m_SummonSlot[i])
|
||||
if (Creature* totem = GetBgMap()->GetCreature(player->m_SummonSlot[i]))
|
||||
if (totem->GetPositionZ() < 28.0f)
|
||||
|
||||
@@ -2672,29 +2672,30 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool skipDistCheck) const
|
||||
|
||||
// pussywizard: don't check distance to home position if recently damaged (allow kiting away from spawnpoint!)
|
||||
// xinef: this should include taunt auras
|
||||
if (!isWorldBoss() && (GetLastLeashExtensionTime() + 12 > GameTime::GetGameTime().count() || HasTauntAura()))
|
||||
if (!isWorldBoss() && (GetLastLeashExtensionTime() + GetLeashTimer() > GameTime::GetGameTime().count() || HasTauntAura()))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (skipDistCheck)
|
||||
return true;
|
||||
|
||||
// xinef: added size factor for huge npcs
|
||||
float dist = std::min<float>(GetDetectionRange() + GetObjectSize() * 2, 150.0f);
|
||||
float dist = sWorld->getFloatConfig(CONFIG_CREATURE_LEASH_RADIUS);
|
||||
|
||||
if (Unit* unit = GetCharmerOrOwner())
|
||||
if (GetCharmerOrOwner())
|
||||
{
|
||||
dist = std::min<float>(GetMap()->GetVisibilityRange() + GetObjectSize() * 2, 150.0f);
|
||||
return victim->IsWithinDist(unit, dist);
|
||||
return IsWithinDist(victim, dist);
|
||||
}
|
||||
|
||||
if (!dist)
|
||||
return true;
|
||||
|
||||
float x, y, z;
|
||||
x = y = z = 0.0f;
|
||||
if (GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE)->GetResetPosition(x, y, z))
|
||||
return IsInDist2d(x, y, dist);
|
||||
else
|
||||
{
|
||||
// to prevent creatures in air ignore attacks because distance is already too high...
|
||||
if (GetMovementTemplate().IsFlightAllowed())
|
||||
return victim->IsInDist2d(&m_homePosition, dist);
|
||||
else
|
||||
return victim->IsInDist(&m_homePosition, dist);
|
||||
}
|
||||
return IsInDist2d(&m_homePosition, dist);
|
||||
}
|
||||
|
||||
CreatureAddon const* Creature::GetCreatureAddon() const
|
||||
@@ -3730,6 +3731,16 @@ void Creature::UpdateLeashExtensionTime()
|
||||
(*GetLastLeashExtensionTimePtr()) = GameTime::GetGameTime().count();
|
||||
}
|
||||
|
||||
uint8 Creature::GetLeashTimer() const
|
||||
{ // Based on testing on Classic, seems to range from ~11s for low level mobs (1-5) to ~16s for high level mobs (70+)
|
||||
uint8 timerOffset = 11;
|
||||
|
||||
uint8 timerModifier = uint8(GetLevel() / 10) - 2;
|
||||
|
||||
// Formula is likely not quite correct, but better than flat timer
|
||||
return std::max<uint8>(timerOffset, timerOffset + timerModifier);
|
||||
}
|
||||
|
||||
bool Creature::CanPeriodicallyCallForAssistance() const
|
||||
{
|
||||
if (!IsInCombat())
|
||||
|
||||
@@ -391,6 +391,7 @@ public:
|
||||
void ClearLastLeashExtensionTimePtr();
|
||||
time_t GetLastLeashExtensionTime() const;
|
||||
void UpdateLeashExtensionTime();
|
||||
uint8 GetLeashTimer() const;
|
||||
|
||||
bool IsFreeToMove();
|
||||
static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;
|
||||
|
||||
@@ -8840,13 +8840,7 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId)
|
||||
battlefield->FillInitialWorldStates(packet);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
packet.Worldstates.reserve(4);
|
||||
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_2, 0);
|
||||
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_1, 0);
|
||||
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_0, 0);
|
||||
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_3, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,17 +51,17 @@ void Totem::InitStats(uint32 duration)
|
||||
if (Unit* owner = ObjectAccessor::GetUnit(*this, m_owner))
|
||||
{
|
||||
uint32 slot = m_Properties->Slot;
|
||||
if (owner->IsPlayer() && slot >= SUMMON_SLOT_TOTEM && slot < MAX_TOTEM_SLOT)
|
||||
if (owner->IsPlayer() && slot >= SUMMON_SLOT_TOTEM_FIRE && slot < MAX_TOTEM_SLOT)
|
||||
{
|
||||
WorldPackets::Totem::TotemCreated data;
|
||||
data.Totem = GetGUID();
|
||||
data.Slot = slot - SUMMON_SLOT_TOTEM;
|
||||
data.Slot = slot - SUMMON_SLOT_TOTEM_FIRE;
|
||||
data.Duration = duration;
|
||||
data.SpellID = GetUInt32Value(UNIT_CREATED_BY_SPELL);
|
||||
owner->ToPlayer()->SendDirectMessage(data.Write());
|
||||
|
||||
// set display id depending on caster's race
|
||||
SetDisplayId(owner->GetModelForTotem(PlayerTotemType(m_Properties->Id)));
|
||||
SetDisplayId(sObjectMgr->GetModelForTotem(SummonSlot(slot), Races(owner->getRace())));
|
||||
}
|
||||
|
||||
SetLevel(owner->GetLevel());
|
||||
@@ -133,7 +133,7 @@ void Totem::UnSummon(uint32 msTime)
|
||||
if (Unit* owner = GetOwner())
|
||||
{
|
||||
// clear owner's totem slot
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM_FIRE; i < MAX_TOTEM_SLOT; ++i)
|
||||
{
|
||||
if (owner->m_SummonSlot[i] == GetGUID())
|
||||
{
|
||||
|
||||
@@ -19261,7 +19261,7 @@ uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float c
|
||||
return CalculatePct(damage, percent);
|
||||
}
|
||||
|
||||
uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
|
||||
uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId)
|
||||
{
|
||||
// Hardcoded cases
|
||||
switch (spellId)
|
||||
@@ -19276,177 +19276,8 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
|
||||
|
||||
if (IsPlayer())
|
||||
{
|
||||
switch (form)
|
||||
{
|
||||
case FORM_CAT:
|
||||
// Based on Hair color
|
||||
if (getRace() == RACE_NIGHTELF)
|
||||
{
|
||||
uint8 hairColor = GetByteValue(PLAYER_BYTES, 3);
|
||||
switch (hairColor)
|
||||
{
|
||||
case 7: // Violet
|
||||
case 8:
|
||||
return 29405;
|
||||
case 3: // Light Blue
|
||||
return 29406;
|
||||
case 0: // Green
|
||||
case 1: // Light Green
|
||||
case 2: // Dark Green
|
||||
return 29407;
|
||||
case 4: // White
|
||||
return 29408;
|
||||
default: // original - Dark Blue
|
||||
return 892;
|
||||
}
|
||||
}
|
||||
// Based on Skin color
|
||||
else if (getRace() == RACE_TAUREN)
|
||||
{
|
||||
uint8 skinColor = GetByteValue(PLAYER_BYTES, 0);
|
||||
// Male
|
||||
if (getGender() == GENDER_MALE)
|
||||
{
|
||||
switch (skinColor)
|
||||
{
|
||||
case 12: // White
|
||||
case 13:
|
||||
case 14:
|
||||
case 18: // Completly White
|
||||
return 29409;
|
||||
case 9: // Light Brown
|
||||
case 10:
|
||||
case 11:
|
||||
return 29410;
|
||||
case 6: // Brown
|
||||
case 7:
|
||||
case 8:
|
||||
return 29411;
|
||||
case 0: // Dark
|
||||
case 1:
|
||||
case 2:
|
||||
case 3: // Dark Grey
|
||||
case 4:
|
||||
case 5:
|
||||
return 29412;
|
||||
default: // original - Grey
|
||||
return 8571;
|
||||
}
|
||||
}
|
||||
// Female
|
||||
else switch (skinColor)
|
||||
{
|
||||
case 10: // White
|
||||
return 29409;
|
||||
case 6: // Light Brown
|
||||
case 7:
|
||||
return 29410;
|
||||
case 4: // Brown
|
||||
case 5:
|
||||
return 29411;
|
||||
case 0: // Dark
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return 29412;
|
||||
default: // original - Grey
|
||||
return 8571;
|
||||
}
|
||||
}
|
||||
else if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
|
||||
return 892;
|
||||
else
|
||||
return 8571;
|
||||
case FORM_DIREBEAR:
|
||||
case FORM_BEAR:
|
||||
// Based on Hair color
|
||||
if (getRace() == RACE_NIGHTELF)
|
||||
{
|
||||
uint8 hairColor = GetByteValue(PLAYER_BYTES, 3);
|
||||
switch (hairColor)
|
||||
{
|
||||
case 0: // Green
|
||||
case 1: // Light Green
|
||||
case 2: // Dark Green
|
||||
return 29413; // 29415?
|
||||
case 6: // Dark Blue
|
||||
return 29414;
|
||||
case 4: // White
|
||||
return 29416;
|
||||
case 3: // Light Blue
|
||||
return 29417;
|
||||
default: // original - Violet
|
||||
return 2281;
|
||||
}
|
||||
}
|
||||
// Based on Skin color
|
||||
else if (getRace() == RACE_TAUREN)
|
||||
{
|
||||
uint8 skinColor = GetByteValue(PLAYER_BYTES, 0);
|
||||
// Male
|
||||
if (getGender() == GENDER_MALE)
|
||||
{
|
||||
switch (skinColor)
|
||||
{
|
||||
case 0: // Dark (Black)
|
||||
case 1:
|
||||
case 2:
|
||||
return 29418;
|
||||
case 3: // White
|
||||
case 4:
|
||||
case 5:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
return 29419;
|
||||
case 9: // Light Brown/Grey
|
||||
case 10:
|
||||
case 11:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
return 29420;
|
||||
case 18: // Completly White
|
||||
return 29421;
|
||||
default: // original - Brown
|
||||
return 2289;
|
||||
}
|
||||
}
|
||||
// Female
|
||||
else switch (skinColor)
|
||||
{
|
||||
case 0: // Dark (Black)
|
||||
case 1:
|
||||
return 29418;
|
||||
case 2: // White
|
||||
case 3:
|
||||
return 29419;
|
||||
case 6: // Light Brown/Grey
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
return 29420;
|
||||
case 10: // Completly White
|
||||
return 29421;
|
||||
default: // original - Brown
|
||||
return 2289;
|
||||
}
|
||||
}
|
||||
else if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
|
||||
return 2281;
|
||||
else
|
||||
return 2289;
|
||||
case FORM_FLIGHT:
|
||||
if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
|
||||
return 20857;
|
||||
return 20872;
|
||||
case FORM_FLIGHT_EPIC:
|
||||
if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
|
||||
return 21243;
|
||||
return 21244;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (uint32 ModelId = sObjectMgr->GetModelForShapeshift(form, ToPlayer()))
|
||||
return ModelId;
|
||||
}
|
||||
|
||||
uint32 modelid = 0;
|
||||
@@ -19472,104 +19303,6 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
|
||||
return modelid;
|
||||
}
|
||||
|
||||
uint32 Unit::GetModelForTotem(PlayerTotemType totemType)
|
||||
{
|
||||
switch (getRace())
|
||||
{
|
||||
case RACE_ORC:
|
||||
{
|
||||
switch (totemType)
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_FIRE: // fire
|
||||
return 30758;
|
||||
case SUMMON_TYPE_TOTEM_EARTH: // earth
|
||||
return 30757;
|
||||
case SUMMON_TYPE_TOTEM_WATER: // water
|
||||
return 30759;
|
||||
case SUMMON_TYPE_TOTEM_AIR: // air
|
||||
return 30756;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RACE_DWARF:
|
||||
{
|
||||
switch (totemType)
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_FIRE: // fire
|
||||
return 30754;
|
||||
case SUMMON_TYPE_TOTEM_EARTH: // earth
|
||||
return 30753;
|
||||
case SUMMON_TYPE_TOTEM_WATER: // water
|
||||
return 30755;
|
||||
case SUMMON_TYPE_TOTEM_AIR: // air
|
||||
return 30736;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RACE_TROLL:
|
||||
{
|
||||
switch (totemType)
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_FIRE: // fire
|
||||
return 30762;
|
||||
case SUMMON_TYPE_TOTEM_EARTH: // earth
|
||||
return 30761;
|
||||
case SUMMON_TYPE_TOTEM_WATER: // water
|
||||
return 30763;
|
||||
case SUMMON_TYPE_TOTEM_AIR: // air
|
||||
return 30760;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RACE_TAUREN:
|
||||
{
|
||||
switch (totemType)
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_FIRE: // fire
|
||||
return 4589;
|
||||
case SUMMON_TYPE_TOTEM_EARTH: // earth
|
||||
return 4588;
|
||||
case SUMMON_TYPE_TOTEM_WATER: // water
|
||||
return 4587;
|
||||
case SUMMON_TYPE_TOTEM_AIR: // air
|
||||
return 4590;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RACE_DRAENEI:
|
||||
{
|
||||
switch (totemType)
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_FIRE: // fire
|
||||
return 19074;
|
||||
case SUMMON_TYPE_TOTEM_EARTH: // earth
|
||||
return 19073;
|
||||
case SUMMON_TYPE_TOTEM_WATER: // water
|
||||
return 19075;
|
||||
case SUMMON_TYPE_TOTEM_AIR: // air
|
||||
return 19071;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: // One standard for other races.
|
||||
{
|
||||
switch (totemType)
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_FIRE: // fire
|
||||
return 4589;
|
||||
case SUMMON_TYPE_TOTEM_EARTH: // earth
|
||||
return 4588;
|
||||
case SUMMON_TYPE_TOTEM_WATER: // water
|
||||
return 4587;
|
||||
case SUMMON_TYPE_TOTEM_AIR: // air
|
||||
return 4590;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Unit* Unit::GetRedirectThreatTarget() const
|
||||
{
|
||||
return _redirectThreatInfo.GetTargetGUID() ? ObjectAccessor::GetUnit(*this, _redirectThreatInfo.GetTargetGUID()) : nullptr;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ItemTemplate.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "Object.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "ThreatMgr.h"
|
||||
@@ -599,23 +600,6 @@ enum ReactiveType
|
||||
MAX_REACTIVE
|
||||
};
|
||||
|
||||
#define SUMMON_SLOT_PET 0
|
||||
#define SUMMON_SLOT_TOTEM 1
|
||||
#define MAX_TOTEM_SLOT 5
|
||||
#define SUMMON_SLOT_MINIPET 5
|
||||
#define SUMMON_SLOT_QUEST 6
|
||||
#define MAX_SUMMON_SLOT 7
|
||||
|
||||
#define MAX_GAMEOBJECT_SLOT 4
|
||||
|
||||
enum PlayerTotemType
|
||||
{
|
||||
SUMMON_TYPE_TOTEM_FIRE = 63,
|
||||
SUMMON_TYPE_TOTEM_EARTH = 81,
|
||||
SUMMON_TYPE_TOTEM_WATER = 82,
|
||||
SUMMON_TYPE_TOTEM_AIR = 83,
|
||||
};
|
||||
|
||||
/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
|
||||
enum SpellCooldownFlags
|
||||
{
|
||||
@@ -1898,8 +1882,7 @@ public:
|
||||
void RestoreDisplayId();
|
||||
void SetNativeDisplayId(uint32 displayId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, displayId); }
|
||||
|
||||
[[nodiscard]] uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const;
|
||||
uint32 GetModelForTotem(PlayerTotemType totemType);
|
||||
[[nodiscard]] uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId);
|
||||
|
||||
// Unit positons
|
||||
[[nodiscard]] virtual bool IsInWater() const;
|
||||
|
||||
@@ -1785,6 +1785,139 @@ void ObjectMgr::LoadCreatureModelInfo()
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadPlayerTotemModels()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT TotemID, RaceID, ModelID from player_totem_model");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_INFO("server.loading", ">> Loaded 0 player totem model records. DB table `player_totem_model` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
SummonSlot totemSlot = SummonSlot(fields[0].Get<uint8>());
|
||||
uint8 race = fields[1].Get<uint8>();
|
||||
uint32 displayId = fields[2].Get<uint32>();
|
||||
|
||||
if (totemSlot < SUMMON_SLOT_TOTEM_FIRE || totemSlot >= MAX_TOTEM_SLOT)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong TotemSlot {} in `player_totem_model` table, skipped.", totemSlot);
|
||||
continue;
|
||||
}
|
||||
|
||||
ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race);
|
||||
if (!raceEntry)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Race {} defined in `player_totem_model` does not exists, skipped.", uint32(race));
|
||||
continue;
|
||||
}
|
||||
|
||||
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(displayId);
|
||||
if (!displayEntry)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "TotemSlot: {} defined in `player_totem_model` has non-existing model ({}), skipped.", totemSlot, displayId);
|
||||
continue;
|
||||
}
|
||||
|
||||
_playerTotemModel[std::make_pair(totemSlot, Races(race))] = displayId;
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} player totem model records in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
uint32 ObjectMgr::GetModelForTotem(SummonSlot totemSlot, Races race) const
|
||||
{
|
||||
auto itr = _playerTotemModel.find(std::make_pair(totemSlot, race));
|
||||
if (itr != _playerTotemModel.end())
|
||||
return itr->second;
|
||||
|
||||
LOG_ERROR("misc", "TotemSlot {} with RaceID ({}) have no totem model data defined, set to default model.", totemSlot, race);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadPlayerShapeshiftModels()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT ShapeshiftID, RaceID, CustomizationID, GenderID, ModelID from player_shapeshift_model");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_INFO("server.loading", ">> Loaded 0 player shapeshift model records. DB table `player_shapeshift_model` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
ShapeshiftForm shapeshiftForm = ShapeshiftForm(fields[0].Get<uint8>());
|
||||
uint8 race = fields[1].Get<uint8>();
|
||||
uint8 customizationID = fields[2].Get<uint8>();
|
||||
uint8 genderID = Gender(fields[3].Get<uint8>());
|
||||
uint32 modelId = fields[4].Get<uint32>();
|
||||
|
||||
ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race);
|
||||
if (!raceEntry)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Race {} defined in `player_shapeshift_model` does not exists, skipped.", uint32(race));
|
||||
continue;
|
||||
}
|
||||
|
||||
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(modelId);
|
||||
if (!displayEntry)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "ShapeshiftForm: {}, Race: {} defined in `player_shapeshift_model` has non-existing model ({}), skipped.", shapeshiftForm, race, modelId);
|
||||
continue;
|
||||
}
|
||||
|
||||
_playerShapeshiftModel[std::make_tuple(shapeshiftForm, race, customizationID, genderID)] = modelId;
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} player totem model records in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
uint32 ObjectMgr::GetModelForShapeshift(ShapeshiftForm form, Player* player) const
|
||||
{
|
||||
uint8 customizationID;
|
||||
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE)
|
||||
customizationID = player->GetByteValue(PLAYER_BYTES, 3); // Use Hair Color
|
||||
else
|
||||
customizationID = player->GetByteValue(PLAYER_BYTES, 0); // Use Skin Color
|
||||
|
||||
auto itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), customizationID, player->getGender()));
|
||||
if (itr != _playerShapeshiftModel.end())
|
||||
return itr->second; // Explicit combination
|
||||
|
||||
itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), customizationID, GENDER_NONE));
|
||||
if (itr != _playerShapeshiftModel.end())
|
||||
return itr->second; // Combination applied to both genders
|
||||
|
||||
itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), 255, player->getGender()));
|
||||
if (itr != _playerShapeshiftModel.end())
|
||||
return itr->second; // Default gender-dependent model
|
||||
|
||||
itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), 255, GENDER_NONE));
|
||||
if (itr != _playerShapeshiftModel.end())
|
||||
return itr->second; // Last resort
|
||||
|
||||
LOG_DEBUG("entities.player", "ShapeshiftForm {} with RaceID ({}) have no shapeshift model data defined, using fallback data.", form, player->getRace());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadLinkedRespawn()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
@@ -711,6 +711,10 @@ struct DungeonEncounter
|
||||
typedef std::list<DungeonEncounter const*> DungeonEncounterList;
|
||||
typedef std::unordered_map<uint32, DungeonEncounterList> DungeonEncounterContainer;
|
||||
|
||||
typedef std::map<std::pair<SummonSlot /*TotemSlot*/, Races /*RaceId*/>, uint32 /*DisplayId*/> PlayerTotemModelMap;
|
||||
|
||||
typedef std::map<std::tuple<ShapeshiftForm /*ShapeshiftID*/, uint8 /*RaceID*/, uint8 /*CustomizationID*/, uint8 /*GenderID*/>, uint32 /*ModelID*/> PlayerShapeshiftModelMap;
|
||||
|
||||
static constexpr uint32 MAX_QUEST_MONEY_REWARDS = 10;
|
||||
typedef std::array<uint32, MAX_QUEST_MONEY_REWARDS> QuestMoneyRewardArray;
|
||||
typedef std::unordered_map<uint32, QuestMoneyRewardArray> QuestMoneyRewardStore;
|
||||
@@ -777,6 +781,10 @@ public:
|
||||
[[nodiscard]] ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
|
||||
[[nodiscard]] std::vector<ItemTemplate*> const* GetItemTemplateStoreFast() const { return &_itemTemplateStoreFast; }
|
||||
|
||||
uint32 GetModelForTotem(SummonSlot totemSlot, Races race) const;
|
||||
|
||||
uint32 GetModelForShapeshift(ShapeshiftForm form, Player* player) const;
|
||||
|
||||
ItemSetNameEntry const* GetItemSetNameEntry(uint32 itemId)
|
||||
{
|
||||
ItemSetNameContainer::iterator itr = _itemSetNameStore.find(itemId);
|
||||
@@ -1036,6 +1044,8 @@ public:
|
||||
void LoadCreatureAddons();
|
||||
void LoadGameObjectAddons();
|
||||
void LoadCreatureModelInfo();
|
||||
void LoadPlayerTotemModels();
|
||||
void LoadPlayerShapeshiftModels();
|
||||
void LoadEquipmentTemplates();
|
||||
void LoadCreatureMovementOverrides();
|
||||
void LoadGameObjectLocales();
|
||||
@@ -1623,6 +1633,10 @@ private:
|
||||
|
||||
std::set<uint32> _transportMaps; // Helper container storing map ids that are for transports only, loaded from gameobject_template
|
||||
|
||||
PlayerTotemModelMap _playerTotemModel;
|
||||
|
||||
PlayerShapeshiftModelMap _playerShapeshiftModel;
|
||||
|
||||
QuestMoneyRewardStore _questMoneyRewards;
|
||||
|
||||
struct GameobjectInstanceSavedState
|
||||
|
||||
@@ -686,7 +686,7 @@ void WorldSession::HandleTotemDestroyed(WorldPackets::Totem::TotemDestroyed& tot
|
||||
return;
|
||||
|
||||
uint8 slotId = totemDestroyed.Slot;
|
||||
slotId += SUMMON_SLOT_TOTEM;
|
||||
slotId += SUMMON_SLOT_TOTEM_FIRE;
|
||||
|
||||
if (slotId >= MAX_TOTEM_SLOT)
|
||||
return;
|
||||
|
||||
@@ -3679,13 +3679,6 @@ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 m
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetId() == 53111) // Devour Humanoid
|
||||
{
|
||||
Unit::Kill(target, caster);
|
||||
if (caster->IsCreature())
|
||||
caster->ToCreature()->RemoveCorpse();
|
||||
}
|
||||
|
||||
caster->_ExitVehicle();
|
||||
// some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them
|
||||
caster->RemoveAurasDueToSpell(GetId());
|
||||
|
||||
@@ -3952,7 +3952,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
int32 basepoints0 = damage;
|
||||
// Cast Absorb on totems
|
||||
for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
|
||||
for (uint8 slot = SUMMON_SLOT_TOTEM_FIRE; slot < MAX_TOTEM_SLOT; ++slot)
|
||||
{
|
||||
if (!unitTarget->m_SummonSlot[slot])
|
||||
continue;
|
||||
@@ -5260,7 +5260,7 @@ void Spell::EffectDestroyAllTotems(SpellEffIndex /*effIndex*/)
|
||||
return;
|
||||
|
||||
int32 mana = 0;
|
||||
for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
|
||||
for (uint8 slot = SUMMON_SLOT_TOTEM_FIRE; slot < MAX_TOTEM_SLOT; ++slot)
|
||||
{
|
||||
if (!m_caster->m_SummonSlot[slot])
|
||||
continue;
|
||||
|
||||
@@ -5105,6 +5105,13 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx6 |= SPELL_ATTR6_ALLOW_WHILE_RIDING_VEHICLE;
|
||||
});
|
||||
|
||||
// Eye of Acherus Flight (Boost)
|
||||
ApplySpellFix({ 51923 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED;
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
|
||||
});
|
||||
|
||||
// Shattering Throw
|
||||
ApplySpellFix({ 64382 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
@@ -5112,6 +5119,27 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Attributes |= SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP;
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
43444, // Explosive Trap (Hex Lord Malacrass)
|
||||
43447, // Freezing Trap (Hex Lord Malacrass)
|
||||
43449, // Snake Trap (Hex Lord Malacrass)
|
||||
}, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_SUMMON_OBJECT_SLOT1;
|
||||
});
|
||||
|
||||
// Arcane Missiles
|
||||
ApplySpellFix({ 58529, 61592 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY);
|
||||
});
|
||||
|
||||
// Siphon Bloodgem
|
||||
ApplySpellFix({ 34367 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ChannelInterruptFlags &= ~AURA_INTERRUPT_FLAG_TURNING;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -193,6 +193,7 @@ enum WorldFloatConfigs
|
||||
CONFIG_LISTEN_RANGE_SAY,
|
||||
CONFIG_LISTEN_RANGE_TEXTEMOTE,
|
||||
CONFIG_LISTEN_RANGE_YELL,
|
||||
CONFIG_CREATURE_LEASH_RADIUS,
|
||||
CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS,
|
||||
CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS,
|
||||
CONFIG_CHANCE_OF_GM_SURVEY,
|
||||
|
||||
@@ -794,6 +794,7 @@ void World::LoadConfigSettings(bool reload)
|
||||
|
||||
_int_configs[CONFIG_EVENT_ANNOUNCE] = sConfigMgr->GetOption<int32>("Event.Announce", 0);
|
||||
|
||||
_float_configs[CONFIG_CREATURE_LEASH_RADIUS] = sConfigMgr->GetOption<float>("CreatureLeashRadius", 30.0f);
|
||||
_float_configs[CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS] = sConfigMgr->GetOption<float>("CreatureFamilyFleeAssistanceRadius", 30.0f);
|
||||
_float_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS] = sConfigMgr->GetOption<float>("CreatureFamilyAssistanceRadius", 10.0f);
|
||||
_int_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY] = sConfigMgr->GetOption<int32>("CreatureFamilyAssistanceDelay", 2000);
|
||||
@@ -1402,6 +1403,12 @@ void World::SetInitialWorldSettings()
|
||||
LOG_INFO("server.loading", "Loading SpellInfo Custom Attributes...");
|
||||
sSpellMgr->LoadSpellInfoCustomAttributes();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Player Totem models...");
|
||||
sObjectMgr->LoadPlayerTotemModels();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Player Shapeshift models...");
|
||||
sObjectMgr->LoadPlayerShapeshiftModels();
|
||||
|
||||
LOG_INFO("server.loading", "Loading GameObject Models...");
|
||||
LoadGameObjectModelList(_dataPath);
|
||||
|
||||
|
||||
@@ -596,12 +596,6 @@ enum WorldStateIDs
|
||||
WORLD_STATE_TRIAL_OF_THE_CRUSADER_UI_COUNT = 4389,
|
||||
WORLD_STATE_TRIAL_OF_THE_CRUSADER_UI_SHOW = 4390,
|
||||
|
||||
// Unknown
|
||||
WORLD_STATE_GENERIC_UNK_0 = 2322,
|
||||
WORLD_STATE_GENERIC_UNK_1 = 2323,
|
||||
WORLD_STATE_GENERIC_UNK_2 = 2324,
|
||||
WORLD_STATE_GENERIC_UNK_3 = 2325,
|
||||
|
||||
// Stranglethorn Fishing Extravaganza (Are these custom IDs?)
|
||||
WORLD_STATE_STRANGLETHORN_VALE_FISHING_PREV_WIN_TIME = 197,
|
||||
WORLD_STATE_STRANGLETHORN_VALE_FISHING_HAS_WINNER = 198,
|
||||
|
||||
@@ -105,7 +105,8 @@ public:
|
||||
{ "unitstate", HandleDebugUnitStateCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
{ "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "boundary", HandleDebugBoundaryCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
@@ -1388,6 +1389,27 @@ public:
|
||||
handler->PSendSysMessage("Created Cells In Map: {} / {}", map->GetCreatedCellsInMapCount(), TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebugBoundaryCommand(ChatHandler* handler, Optional<uint32> durationArg, Optional<EXACT_SEQUENCE("fill")> fill, Optional<EXACT_SEQUENCE("z")> checkZ)
|
||||
{
|
||||
Player* player = handler->GetPlayer();
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
Creature* target = handler->getSelectedCreature();
|
||||
if (!target || !target->IsAIEnabled)
|
||||
return false;
|
||||
|
||||
uint32 duration = durationArg.value_or(5 * IN_MILLISECONDS);
|
||||
if (duration > 180 * IN_MILLISECONDS) // arbitrary upper limit
|
||||
duration = 180 * IN_MILLISECONDS;
|
||||
|
||||
int32 errMsg = target->AI()->VisualizeBoundary(duration, player, fill.has_value(), checkZ.has_value());
|
||||
if (errMsg > 0)
|
||||
handler->PSendSysMessage(errMsg);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_debug_commandscript()
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
{ "join", HandleGroupJoinCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "remove", HandleGroupRemoveCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "disband", HandleGroupDisbandCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "revive", HandleGroupReviveCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "leader", HandleGroupLeaderCommand, SEC_GAMEMASTER, Console::No }
|
||||
};
|
||||
|
||||
@@ -257,6 +258,39 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGroupReviveCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
if (!target)
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
Player* targetPlayer = target->GetConnectedPlayer();
|
||||
Group* group = targetPlayer->GetGroup();
|
||||
std::string nameLink = handler->playerLink(target->GetName());
|
||||
|
||||
if (!group)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_NOT_IN_GROUP, nameLink);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (GroupReference* it = group->GetFirstMember(); it != nullptr; it = it->next())
|
||||
{
|
||||
Player* target = it->GetSource();
|
||||
if (target)
|
||||
{
|
||||
target->RemoveAurasDueToSpell(27827); // Spirit of Redemption
|
||||
target->ResurrectPlayer(!AccountMgr::IsPlayerAccount(target->GetSession()->GetSecurity()) ? 1.0f : 0.5f);
|
||||
target->SpawnCorpseBones();
|
||||
target->SaveToDB(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_group_commandscript()
|
||||
|
||||
@@ -25,18 +25,6 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
/* ScriptData
|
||||
SDName: Karazhan
|
||||
SD%Complete: 100
|
||||
SDComment: Support for Barnes (Opera controller) and Berthold (Doorman), Support for Quest 9645.
|
||||
SDCategory: Karazhan
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_barnes
|
||||
npc_berthold
|
||||
npc_image_of_medivh
|
||||
EndContentData */
|
||||
|
||||
enum Spells
|
||||
{
|
||||
@@ -51,7 +39,17 @@ enum Spells
|
||||
SPELL_FIRE_BALL = 30967,
|
||||
SPELL_UBER_FIREBALL = 30971,
|
||||
SPELL_CONFLAGRATION_BLAST = 30977,
|
||||
SPELL_MANA_SHIELD = 31635
|
||||
SPELL_MANA_SHIELD = 31635,
|
||||
|
||||
// Wrath of the Titans
|
||||
SPELL_WRATH_OF_THE_TITANS = 30554,
|
||||
|
||||
SPELL_WRATH_PROC_BLAST = 30605,
|
||||
SPELL_WRATH_PROC_BOLT = 30606,
|
||||
SPELL_WRATH_PROC_FLAME = 30607,
|
||||
SPELL_WRATH_PROC_SPITE = 30608,
|
||||
SPELL_WRATH_PROC_CHILL = 30609,
|
||||
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
@@ -608,10 +606,106 @@ class spell_karazhan_temptation : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 30610 - Wrath of the Titans Stacker
|
||||
class spell_karazhan_wrath_titans_stacker : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_karazhan_wrath_titans_stacker);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_WRATH_OF_THE_TITANS });
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
caster->CastSpell(caster, SPELL_WRATH_OF_THE_TITANS, true);
|
||||
if (Aura* aur = caster->GetAura(SPELL_WRATH_OF_THE_TITANS))
|
||||
aur->SetStackAmount(5);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_karazhan_wrath_titans_stacker::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
// 30554 - Wrath of the Titans
|
||||
class spell_karazhan_wrath_titans_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_karazhan_wrath_titans_aura);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_WRATH_PROC_BLAST, SPELL_WRATH_PROC_BOLT, SPELL_WRATH_PROC_FLAME, SPELL_WRATH_PROC_SPITE, SPELL_WRATH_PROC_CHILL });
|
||||
}
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (!eventInfo.GetSpellInfo())
|
||||
return false;
|
||||
|
||||
if (GetFirstSchoolInMask(eventInfo.GetSpellInfo()->GetSchoolMask()) == SPELL_SCHOOL_NORMAL)
|
||||
return false;
|
||||
|
||||
if (GetFirstSchoolInMask(eventInfo.GetSpellInfo()->GetSchoolMask()) == SPELL_SCHOOL_HOLY)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
|
||||
Unit* target = eventInfo.GetActionTarget();
|
||||
Player* caster = GetTarget()->ToPlayer();
|
||||
if (!target || !caster)
|
||||
return;
|
||||
|
||||
uint32 spellId = 0;
|
||||
switch (GetFirstSchoolInMask(eventInfo.GetSpellInfo()->GetSchoolMask()))
|
||||
{
|
||||
case SPELL_SCHOOL_FIRE:
|
||||
spellId = SPELL_WRATH_PROC_FLAME;
|
||||
break;
|
||||
case SPELL_SCHOOL_NATURE:
|
||||
spellId = SPELL_WRATH_PROC_BOLT;
|
||||
break;
|
||||
case SPELL_SCHOOL_FROST:
|
||||
spellId = SPELL_WRATH_PROC_CHILL;
|
||||
break;
|
||||
case SPELL_SCHOOL_SHADOW:
|
||||
spellId = SPELL_WRATH_PROC_SPITE;
|
||||
break;
|
||||
case SPELL_SCHOOL_ARCANE:
|
||||
spellId = SPELL_WRATH_PROC_BLAST;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
caster->CastSpell(target, spellId, true);
|
||||
ModStackAmount(-1);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_karazhan_wrath_titans_aura::CheckProc);
|
||||
OnEffectProc += AuraEffectProcFn(spell_karazhan_wrath_titans_aura::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_karazhan()
|
||||
{
|
||||
new npc_barnes();
|
||||
new npc_image_of_medivh();
|
||||
new at_karazhan_side_entrance();
|
||||
RegisterSpellScript(spell_karazhan_temptation);
|
||||
RegisterSpellScript(spell_karazhan_wrath_titans_stacker);
|
||||
RegisterSpellScript(spell_karazhan_wrath_titans_aura);
|
||||
}
|
||||
|
||||
@@ -37,145 +37,28 @@
|
||||
enum EyeOfAcherusMisc
|
||||
{
|
||||
SPELL_THE_EYE_OF_ACHERUS = 51852,
|
||||
SPELL_EYE_OF_ACHERUS_VISUAL = 51892,
|
||||
SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST = 51923,
|
||||
SPELL_EYE_OF_ACHERUS_FLIGHT = 51890,
|
||||
SPELL_ROOT_SELF = 51860,
|
||||
|
||||
EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION = 1,
|
||||
EVENT_UNROOT = 2,
|
||||
EVENT_LAUNCH_TOWARDS_DESTINATION = 3,
|
||||
EVENT_GRANT_CONTROL = 4,
|
||||
|
||||
SAY_LAUNCH_TOWARDS_DESTINATION = 0,
|
||||
SAY_EYE_UNDER_CONTROL = 1,
|
||||
|
||||
POINT_NEW_AVALON = 1,
|
||||
|
||||
EYE_POINT_DESTINATION_0 = 0,
|
||||
EYE_POINT_DESTINATION_1 = 1,
|
||||
EYE_POINT_DESTINATION_2 = 2,
|
||||
EYE_POINT_DESTINATION_3 = 3
|
||||
};
|
||||
|
||||
struct npc_eye_of_acherus : public ScriptedAI
|
||||
{
|
||||
npc_eye_of_acherus(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
creature->SetDisplayFromModel(0);
|
||||
creature->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
DoCastSelf(SPELL_ROOT_SELF);
|
||||
DoCastSelf(SPELL_EYE_OF_ACHERUS_VISUAL);
|
||||
_events.ScheduleEvent(EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION, 400ms);
|
||||
}
|
||||
|
||||
void OnCharmed(bool apply) override
|
||||
{
|
||||
if (!apply)
|
||||
{
|
||||
me->GetCharmerOrOwner()->RemoveAurasDueToSpell(SPELL_THE_EYE_OF_ACHERUS);
|
||||
me->GetCharmerOrOwner()->RemoveAurasDueToSpell(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION:
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
{
|
||||
Talk(SAY_LAUNCH_TOWARDS_DESTINATION, owner);
|
||||
}
|
||||
_events.ScheduleEvent(EVENT_UNROOT, 400ms);
|
||||
break;
|
||||
case EVENT_UNROOT:
|
||||
me->RemoveAurasDueToSpell(SPELL_ROOT_SELF);
|
||||
DoCastSelf(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST);
|
||||
_events.ScheduleEvent(EVENT_LAUNCH_TOWARDS_DESTINATION, 1s + 200ms);
|
||||
break;
|
||||
case EVENT_LAUNCH_TOWARDS_DESTINATION:
|
||||
{
|
||||
Position const EYE_DESTINATION_1 = { 2361.21f, -5660.45f, 496.744f, 0.0f };
|
||||
Position const EYE_DESTINATION_2 = { 2341.571f, -5672.797f, 538.3942f, 0.0f };
|
||||
Position const EYE_DESTINATION_3 = { 1957.4f, -5844.1f, 273.867f, 0.0f };
|
||||
Position const EYE_DESTINATION_4 = { 1758.01f, -5876.79f, 166.867f, 0.0f };
|
||||
|
||||
Movement::MoveSplineInit init(me);
|
||||
init.SetFly();
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
{
|
||||
init.SetVelocity(owner->GetSpeed(MOVE_RUN));
|
||||
}
|
||||
|
||||
me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_0, EYE_DESTINATION_1);
|
||||
me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_1, EYE_DESTINATION_2);
|
||||
me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_2, EYE_DESTINATION_3);
|
||||
me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_3, EYE_DESTINATION_4);
|
||||
_events.ScheduleEvent(EVENT_GRANT_CONTROL, 22s);
|
||||
break;
|
||||
}
|
||||
case EVENT_GRANT_CONTROL:
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
{
|
||||
Talk(SAY_EYE_UNDER_CONTROL, owner);
|
||||
}
|
||||
me->RemoveAurasDueToSpell(SPELL_ROOT_SELF);
|
||||
DoCastSelf(SPELL_EYE_OF_ACHERUS_FLIGHT);
|
||||
me->RemoveAurasDueToSpell(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 movementType, uint32 pointId) override
|
||||
{
|
||||
if (movementType != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
switch (pointId)
|
||||
{
|
||||
case POINT_NEW_AVALON:
|
||||
DoCastSelf(SPELL_ROOT_SELF);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
enum DeathComesFromOnHigh
|
||||
{
|
||||
SUMMON_GHOULS_ON_SCARLET_CRUSADE = 54522
|
||||
SPELL_CALL_OF_THE_DEAD = 51900
|
||||
};
|
||||
|
||||
// 51904 - Summon Ghouls On Scarlet Crusade
|
||||
class spell_q12641_death_comes_from_on_high_summon_ghouls : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q12641_death_comes_from_on_high_summon_ghouls);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SUMMON_GHOULS_ON_SCARLET_CRUSADE });
|
||||
return ValidateSpellInfo({ SPELL_CALL_OF_THE_DEAD });
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitEffect(effIndex);
|
||||
if (Unit* target = GetHitUnit())
|
||||
GetCaster()->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SUMMON_GHOULS_ON_SCARLET_CRUSADE, true);
|
||||
target->CastSpell(target, SPELL_CALL_OF_THE_DEAD, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -184,6 +67,35 @@ class spell_q12641_death_comes_from_on_high_summon_ghouls : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 52694 - Recall Eye of Acherus
|
||||
class spell_q12641_death_comes_from_on_high_recall_eye : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q12641_death_comes_from_on_high_recall_eye);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_THE_EYE_OF_ACHERUS });
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitEffect(effIndex);
|
||||
Unit* caster = GetCaster();
|
||||
Unit* owner = caster->GetCharmerOrOwner();
|
||||
|
||||
if (!caster || !owner)
|
||||
return;
|
||||
|
||||
if (owner->HasAura(SPELL_THE_EYE_OF_ACHERUS))
|
||||
owner->RemoveAurasDueToSpell(SPELL_THE_EYE_OF_ACHERUS);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_q12641_death_comes_from_on_high_recall_eye::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
enum deathsChallenge
|
||||
{
|
||||
SPELL_DUEL = 52996,
|
||||
@@ -1300,8 +1212,8 @@ class spell_lich_king_whisper : public SpellScript
|
||||
void AddSC_the_scarlet_enclave_c1()
|
||||
{
|
||||
// Ours
|
||||
RegisterCreatureAI(npc_eye_of_acherus);
|
||||
RegisterSpellScript(spell_q12641_death_comes_from_on_high_summon_ghouls);
|
||||
RegisterSpellScript(spell_q12641_death_comes_from_on_high_recall_eye);
|
||||
new npc_death_knight_initiate();
|
||||
RegisterSpellScript(spell_item_gift_of_the_harvester);
|
||||
RegisterSpellScript(spell_q12698_the_gift_that_keeps_on_giving);
|
||||
|
||||
@@ -15,27 +15,77 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CreatureScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
|
||||
enum DevourHumanoid
|
||||
{
|
||||
NPC_HEARTHGLEN_CRUSADER = 29102,
|
||||
NPC_TIRISFAL_CRUSADER = 29103
|
||||
};
|
||||
|
||||
// 53110 - Devour Humanoid
|
||||
class spell_q12779_an_end_to_all_things : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q12779_an_end_to_all_things);
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (caster->FindNearestCreature(NPC_HEARTHGLEN_CRUSADER, 15.0f, true) || caster->FindNearestCreature(NPC_TIRISFAL_CRUSADER, 15.0f, true))
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (GetHitUnit())
|
||||
GetHitUnit()->CastSpell(GetCaster(), GetEffectValue(), true);
|
||||
if (Creature* c = GetHitUnit()->ToCreature())
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
c->AI()->AttackStart(caster);
|
||||
c->CastSpell(caster, GetEffectValue(), true); // 53111
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_q12779_an_end_to_all_things::CheckCast);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_q12779_an_end_to_all_things::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// 53111 - Devour Humanoid (casted by the devoured creature)
|
||||
class spell_q12779_an_end_to_all_things_devour_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_q12779_an_end_to_all_things_devour_aura);
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetTarget();
|
||||
if (!caster || !target)
|
||||
return;
|
||||
|
||||
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
|
||||
{
|
||||
caster->SetDisableGravity(true);
|
||||
Unit::Kill(target, caster);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_q12779_an_end_to_all_things_devour_aura::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_the_scarlet_enclave_c3()
|
||||
{
|
||||
RegisterSpellScript(spell_q12779_an_end_to_all_things);
|
||||
RegisterSpellScript(spell_q12779_an_end_to_all_things_devour_aura);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "AreaTriggerScript.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "GameObjectScript.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellInfo.h"
|
||||
@@ -488,6 +490,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct go_eredar_twins_blaze : GameObjectAI
|
||||
{
|
||||
explicit go_eredar_twins_blaze(GameObject *object) : GameObjectAI(object) { };
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
// required for the trap to apply its startDelay
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (ObjectGuid creatureGUID = instance->GetGuidData(DATA_ALYTHESS))
|
||||
{
|
||||
me->SetOwnerGUID(creatureGUID);
|
||||
me->SetLootState(GO_NOT_READY);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_eredar_twins()
|
||||
{
|
||||
RegisterSunwellPlateauCreatureAI(boss_sacrolash);
|
||||
@@ -501,4 +519,5 @@ void AddSC_boss_eredar_twins()
|
||||
RegisterSpellScriptWithArgs(spell_eredar_twins_handle_touch_periodic, "spell_eredar_twins_handle_flame_touched_periodic", SPELL_FLAME_TOUCHED, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||
RegisterSpellScriptWithArgs(spell_eredar_twins_handle_touch_periodic, "spell_eredar_twins_handle_flame_touched_flame_sear", SPELL_FLAME_TOUCHED, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
|
||||
new at_sunwell_eredar_twins();
|
||||
RegisterGameObjectAI(go_eredar_twins_blaze);
|
||||
}
|
||||
|
||||
@@ -1003,6 +1003,9 @@ class spell_kiljaeden_sinister_reflection_clone : public SpellScript
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
if (targets.empty())
|
||||
return;
|
||||
|
||||
targets.sort(Acore::ObjectDistanceOrderPred(GetCaster()));
|
||||
WorldObject* target = targets.front();
|
||||
|
||||
@@ -1052,6 +1055,9 @@ class spell_kiljaeden_darkness_aura : public AuraScript
|
||||
|
||||
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
|
||||
return;
|
||||
|
||||
if (GetUnitOwner()->IsCreature())
|
||||
GetUnitOwner()->ToCreature()->AI()->DoAction(ACTION_NO_KILL_TALK);
|
||||
|
||||
@@ -1157,6 +1163,8 @@ class spell_kiljaeden_armageddon_missile : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 45856 - Breath: Haste
|
||||
// 45860 - Breath: Revitalize
|
||||
class spell_kiljaeden_dragon_breath : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_kiljaeden_dragon_breath);
|
||||
@@ -1166,9 +1174,16 @@ class spell_kiljaeden_dragon_breath : public SpellScript
|
||||
targets.remove_if(Acore::UnitAuraCheck(true, SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT));
|
||||
}
|
||||
|
||||
void HandleHit(SpellEffIndex /*effindex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
target->RemoveMovementImpairingAuras(false);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kiljaeden_dragon_breath::FilterTargets, EFFECT_ALL, TARGET_UNIT_CONE_ALLY);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_kiljaeden_dragon_breath::HandleHit, EFFECT_ALL, SPELL_EFFECT_ANY);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaDefines.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "Pet.h"
|
||||
@@ -23,19 +24,6 @@
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
/* ScriptData
|
||||
SDName: Isle_of_Queldanas
|
||||
SD%Complete: 100
|
||||
SDComment: Quest support: 11524, 11525, 11532, 11533, 11542, 11543, 11541
|
||||
SDCategory: Isle Of Quel'Danas
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_converted_sentry
|
||||
npc_greengill_slave
|
||||
EndContentData */
|
||||
|
||||
/*###### OUR: ######*/
|
||||
|
||||
enum ThalorienNpcs
|
||||
{
|
||||
@@ -677,13 +665,31 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
// 45396, 45398 - Weapon Coating Enchant
|
||||
class spell_gen_weapon_coating_enchant : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_gen_weapon_coating_enchant);
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
Unit* caster = eventInfo.GetActor();
|
||||
if (!caster)
|
||||
return false;
|
||||
|
||||
return (caster->GetZoneId() == AREA_ISLE_OF_QUEL_DANAS || caster->GetZoneId() == AREA_SUNWELL_PLATEAU || caster->GetZoneId() == AREA_MAGISTERS_TERRACE);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_gen_weapon_coating_enchant::CheckProc);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_isle_of_queldanas()
|
||||
{
|
||||
// OUR:
|
||||
new npc_bh_thalorien_dawnseeker();
|
||||
RegisterSpellScript(spell_bh_cleanse_quel_delar);
|
||||
new npc_grand_magister_rommath();
|
||||
|
||||
// THEIR:
|
||||
new npc_greengill_slave();
|
||||
RegisterSpellScript(spell_gen_weapon_coating_enchant);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
|
||||
enum eNoblegarden
|
||||
{
|
||||
SPELL_NOBLEGARDEN_BUNNY = 61734
|
||||
SPELL_NOBLEGARDEN_BUNNY = 61734,
|
||||
SPELL_WELL_FED = 24870,
|
||||
};
|
||||
|
||||
// 61712 Summon Noblegarden Bunny Controller
|
||||
@@ -55,7 +56,46 @@ class spell_summon_noblegarden_bunny_controller : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 61874 - Food (Noblegarden Chocolate, item 44791)
|
||||
class spell_item_noblegarden_chocolate : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_item_noblegarden_chocolate);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_WELL_FED });
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
_buffGiven = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlePeriodic(AuraEffect const* /*aurEff*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
uint32 duration = static_cast<uint32>(GetDuration());
|
||||
if (duration <= 14000 && !_buffGiven)
|
||||
{
|
||||
_buffGiven = true;
|
||||
caster->CastSpell(caster, SPELL_WELL_FED, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_item_noblegarden_chocolate::HandlePeriodic, EFFECT_0, SPELL_AURA_OBS_MOD_HEALTH);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _buffGiven;
|
||||
};
|
||||
|
||||
void AddSC_event_noblegarden_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_summon_noblegarden_bunny_controller);
|
||||
RegisterSpellScript(spell_item_noblegarden_chocolate);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ enum AhnKahetCreatures
|
||||
|
||||
enum AhnkahetSpells
|
||||
{
|
||||
SPELL_SHADOW_SICKLE = 56701, // Shadow Sickle Normal
|
||||
SPELL_SHADOW_SICKLE = 56701, // Shadow Sickle
|
||||
};
|
||||
|
||||
enum AhnkahetObjects
|
||||
|
||||
@@ -102,11 +102,7 @@ Position const MushroomPositions[MAX_MUSHROOMS_COUNT] =
|
||||
|
||||
struct boss_amanitar : public BossAI
|
||||
{
|
||||
boss_amanitar(Creature* creature) : BossAI(creature, DATA_AMANITAR), mushroomsSummoned(false)
|
||||
{
|
||||
creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
|
||||
creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
|
||||
}
|
||||
boss_amanitar(Creature* creature) : BossAI(creature, DATA_AMANITAR), mushroomsSummoned(false) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
|
||||
@@ -101,9 +101,7 @@ struct boss_elder_nadox : public BossAI
|
||||
events.ScheduleEvent(EVENT_PLAGUE, 5s, 8s);
|
||||
|
||||
if (IsHeroic())
|
||||
{
|
||||
events.ScheduleEvent(EVENT_BROOD_RAGE, 5s);
|
||||
}
|
||||
|
||||
// Cache eggs
|
||||
std::list<Creature*> eggs;
|
||||
@@ -122,7 +120,7 @@ struct boss_elder_nadox : public BossAI
|
||||
|
||||
eggs.clear();
|
||||
|
||||
// Guardian eggs
|
||||
// Guardian eggs
|
||||
me->GetCreatureListWithEntryInGrid(eggs, NPC_AHNKAHAR_GUARDIAN_EGG, 250.0f);
|
||||
if (!eggs.empty())
|
||||
{
|
||||
@@ -139,17 +137,13 @@ struct boss_elder_nadox : public BossAI
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
|
||||
{
|
||||
if (summon->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
|
||||
{
|
||||
respectYourElders = false;
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer())
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -160,7 +154,7 @@ struct boss_elder_nadox : public BossAI
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (!guardianSummoned && me->HealthBelowPctDamaged(55, damage))
|
||||
if (!guardianSummoned && me->HealthBelowPctDamaged(50, damage))
|
||||
{
|
||||
SummonHelpers(false);
|
||||
guardianSummoned = true;
|
||||
@@ -170,9 +164,7 @@ struct boss_elder_nadox : public BossAI
|
||||
uint32 GetData(uint32 type) const override
|
||||
{
|
||||
if (type == DATA_RESPECT_YOUR_ELDERS)
|
||||
{
|
||||
return respectYourElders ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -180,16 +172,12 @@ struct boss_elder_nadox : public BossAI
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (uint32 const eventId = events.ExecuteEvent())
|
||||
{
|
||||
@@ -218,9 +206,8 @@ struct boss_elder_nadox : public BossAI
|
||||
case EVENT_CHECK_HOME:
|
||||
{
|
||||
if (!me->HasAura(SPELL_ENRAGE) && (me->GetPositionZ() < 24.0f || !me->GetHomePosition().IsInDist(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 110.0f)))
|
||||
{
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
}
|
||||
events.Repeat(1s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -241,9 +228,7 @@ private:
|
||||
if (swarm)
|
||||
{
|
||||
if (swarmEggs.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a copy of guid list
|
||||
GuidList swarmEggs2 = swarmEggs;
|
||||
@@ -259,41 +244,29 @@ private:
|
||||
}
|
||||
|
||||
if (swarmEggs2.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
previousSwarmEgg_GUID = Acore::Containers::SelectRandomContainerElement(swarmEggs2);
|
||||
|
||||
if (Creature* egg = ObjectAccessor::GetCreature(*me, previousSwarmEgg_GUID))
|
||||
{
|
||||
egg->CastSpell(egg, SPELL_SUMMON_SWARMERS, true, nullptr, nullptr, me->GetGUID());
|
||||
}
|
||||
|
||||
if (roll_chance_f(33))
|
||||
{
|
||||
Talk(SAY_EGG_SAC);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (guardianEggs.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid const& guardianEggGUID = Acore::Containers::SelectRandomContainerElement(guardianEggs);
|
||||
if (Creature* egg = ObjectAccessor::GetCreature(*me, guardianEggGUID))
|
||||
{
|
||||
egg->CastSpell(egg, SPELL_SUMMON_SWARM_GUARD, true, nullptr, nullptr, me->GetGUID());
|
||||
}
|
||||
|
||||
Talk(EMOTE_HATCHES, me);
|
||||
|
||||
if (roll_chance_f(33))
|
||||
{
|
||||
Talk(SAY_EGG_SAC);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "InstanceMapScript.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
@@ -38,6 +39,11 @@ DoorData const doorData[] =
|
||||
{ 0, 0, DOOR_TYPE_ROOM }
|
||||
};
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ DATA_JEDOGA_SHADOWSEEKER, new ParallelogramBoundary(Position(460.365f, -661.997f, -20.985f), Position(364.958f,-790.211f, -14.207f), Position(347.436f,-657.978f,14.478f)) }
|
||||
};
|
||||
|
||||
class instance_ahnkahet : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -52,6 +58,7 @@ public:
|
||||
SetPersistentDataCount(MAX_PERSISTENT_DATA);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
LoadDoorData(doorData);
|
||||
LoadBossBoundaries(boundaries);
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
@@ -126,15 +133,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 56702 Shadow Sickle
|
||||
// 59103 Shadow Sickle
|
||||
// 56702, 59103 - Shadow Sickle
|
||||
class spell_shadow_sickle_periodic_damage : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_shadow_sickle_periodic_damage);
|
||||
|
||||
void HandlePeriodic(AuraEffect const* /*aurEff*/)
|
||||
{
|
||||
GetCaster()->CastSpell(nullptr, SPELL_SHADOW_SICKLE);
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster->IsCreature())
|
||||
return;
|
||||
|
||||
if (Unit* target = caster->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, 40.0f)) // Unknown if it targets only players
|
||||
caster->CastSpell(target, SPELL_SHADOW_SICKLE, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -94,6 +94,7 @@ public:
|
||||
InstanceScript* pInstance;
|
||||
EventMap events;
|
||||
float ZapAngle;
|
||||
uint8 step = 0;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -185,32 +186,37 @@ public:
|
||||
{
|
||||
Talk(SAY_AZURE);
|
||||
Talk(SAY_AZURE_EMOTE);
|
||||
switch (events.ExecuteEvent())
|
||||
switch (step)
|
||||
{
|
||||
case EVENT_CALL_AZURE_RING_CAPTAIN_1:
|
||||
me->CastSpell(me, SPELL_CALL_AZURE_RING_CAPTAIN_1, true);
|
||||
case 0:
|
||||
DoCast(SPELL_CALL_AZURE_RING_CAPTAIN_1);
|
||||
events.ScheduleEvent(EVENT_CALL_AZURE_RING_CAPTAIN_2, 16s);
|
||||
break;
|
||||
case EVENT_CALL_AZURE_RING_CAPTAIN_2:
|
||||
me->CastSpell(me, SPELL_CALL_AZURE_RING_CAPTAIN_2, true);
|
||||
case 1:
|
||||
DoCast(SPELL_CALL_AZURE_RING_CAPTAIN_2);
|
||||
events.ScheduleEvent(EVENT_CALL_AZURE_RING_CAPTAIN_3, 16s);
|
||||
break;
|
||||
case EVENT_CALL_AZURE_RING_CAPTAIN_3:
|
||||
me->CastSpell(me, SPELL_CALL_AZURE_RING_CAPTAIN_3, true);
|
||||
case 2:
|
||||
DoCast(SPELL_CALL_AZURE_RING_CAPTAIN_3);
|
||||
events.ScheduleEvent(EVENT_CALL_AZURE_RING_CAPTAIN_4, 16s);
|
||||
break;
|
||||
case EVENT_CALL_AZURE_RING_CAPTAIN_4:
|
||||
me->CastSpell(me, SPELL_CALL_AZURE_RING_CAPTAIN_4, true);
|
||||
case 3:
|
||||
DoCast(SPELL_CALL_AZURE_RING_CAPTAIN_4);
|
||||
events.ScheduleEvent(EVENT_CALL_AZURE_RING_CAPTAIN_1, 16s);
|
||||
break;
|
||||
}
|
||||
|
||||
step++;
|
||||
if (step > 3)
|
||||
step = 0;
|
||||
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
|
||||
{
|
||||
if (Creature* trigger = me->SummonCreature(NPC_ARCANE_BEAM, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 13000))
|
||||
{
|
||||
if (Creature* c = me->FindNearestCreature(NPC_AZURE_RING_CAPTAIN, 500.0f, true))
|
||||
c->CastSpell(trigger, SPELL_ARCANE_BEAM_VISUAL, true);
|
||||
trigger->GetMotionMaster()->MoveChase(target, 0.1f);
|
||||
trigger->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f, MOTION_SLOT_ACTIVE, false, false); /// @todo: sniff speed for NPC_ARCANE_BEAM (ID: 28239)
|
||||
trigger->CastSpell(me, SPELL_ARCANE_BEAM_PERIODIC_DAMAGE, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,11 @@ public:
|
||||
{
|
||||
EncounterStatus = IN_PROGRESS;
|
||||
if (Creature* c = instance->GetCreature(NPC_SinclariGUID))
|
||||
{
|
||||
c->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
c->AI()->Talk(SAY_SINCLARI_LEAVING);
|
||||
/// @todo: Missing orientation for Sinclari's movement and "interaction" animation with the nearby crystal.
|
||||
}
|
||||
events.RescheduleEvent(EVENT_GUARDS_FALL_BACK, 4s);
|
||||
}
|
||||
break;
|
||||
@@ -451,6 +455,7 @@ public:
|
||||
{
|
||||
if (Creature* c = instance->GetCreature(NPC_SinclariGUID))
|
||||
{
|
||||
c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
c->AI()->Talk(SAY_SINCLARI_DOOR_LOCK);
|
||||
}
|
||||
if (Creature* c = instance->GetCreature(NPC_DoorSealGUID))
|
||||
@@ -568,7 +573,13 @@ public:
|
||||
}
|
||||
|
||||
// reset positions of Sinclari and Guards
|
||||
if (Creature* c = instance->GetCreature(NPC_SinclariGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); }
|
||||
if (Creature* c = instance->GetCreature(NPC_SinclariGUID))
|
||||
{
|
||||
c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
c->DespawnOrUnsummon();
|
||||
c->SetRespawnTime(3);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < 4; ++i)
|
||||
if (Creature* c = instance->GetCreature(NPC_GuardGUID[i]))
|
||||
{
|
||||
|
||||
@@ -27,16 +27,15 @@
|
||||
#include "SpellScriptLoader.h"
|
||||
|
||||
/// @todo: Missing Sinclari Trigger announcements (32204) Look at its creature_text for more info.
|
||||
/// @todo: Activation Crystals (go_vh_activation_crystal) (193611) are spammable, should be a 1 time use per crystal.
|
||||
|
||||
enum Texts
|
||||
{
|
||||
GOSSIP_MENU_START_EVENT = 9998,
|
||||
GOSSIP_MENU_ITEM = 9997,
|
||||
GOSSIP_MENU_START_1 = 9997,
|
||||
GOSSIP_MENU_START_2 = 9998,
|
||||
GOSSIP_MENU_LATE_JOIN = 10275,
|
||||
|
||||
NPC_TEXT_SINCLARI_IN = 13853,
|
||||
NPC_TEXT_SINCLARI_ITEM = 13854,
|
||||
NPC_TEXT_SINCLARI_START = 13854,
|
||||
NPC_TEXT_SINCLARI_DONE = 13910,
|
||||
NPC_TEXT_SINCLARI_LATE_JOIN = 14271,
|
||||
};
|
||||
@@ -53,7 +52,11 @@ public:
|
||||
bool OnGossipHello(Player* /*player*/, GameObject* go) override
|
||||
{
|
||||
if (InstanceScript* pInstance = go->GetInstanceScript())
|
||||
{
|
||||
pInstance->SetData(DATA_ACTIVATE_DEFENSE_SYSTEM, 1);
|
||||
go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -73,8 +76,7 @@ public:
|
||||
switch (pInstance->GetData(DATA_ENCOUNTER_STATUS))
|
||||
{
|
||||
case NOT_STARTED:
|
||||
AddGossipItemFor(player, GOSSIP_MENU_ITEM, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_START_EVENT, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_START_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
SendGossipMenuFor(player, NPC_TEXT_SINCLARI_IN, creature->GetGUID());
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
@@ -94,13 +96,14 @@ public:
|
||||
switch (uiAction)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF+1:
|
||||
AddGossipItemFor(player, GOSSIP_MENU_START_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
SendGossipMenuFor(player, NPC_TEXT_SINCLARI_START, creature->GetGUID());
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+2:
|
||||
CloseGossipMenuFor(player);
|
||||
if (InstanceScript* pInstance = creature->GetInstanceScript())
|
||||
pInstance->SetData(DATA_START_INSTANCE, 1);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+2:
|
||||
SendGossipMenuFor(player, NPC_TEXT_SINCLARI_ITEM, creature->GetGUID());
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF+3:
|
||||
player->NearTeleportTo(playerTeleportPosition.GetPositionX(), playerTeleportPosition.GetPositionY(), playerTeleportPosition.GetPositionZ(), playerTeleportPosition.GetOrientation(), true);
|
||||
CloseGossipMenuFor(player);
|
||||
|
||||
@@ -2131,9 +2131,31 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum WaterTerror
|
||||
{
|
||||
SPELL_WATER_TERROR_FROST_NOVA = 57668
|
||||
};
|
||||
|
||||
// 57652 - Crashing Wave
|
||||
class spell_crashing_wave : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_crashing_wave);
|
||||
|
||||
void RecalculateDamage()
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
if (target->HasAura(SPELL_WATER_TERROR_FROST_NOVA))
|
||||
SetHitDamage(GetHitDamage() * 2);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_crashing_wave::RecalculateDamage);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_icecrown()
|
||||
{
|
||||
// Ours
|
||||
new npc_black_knight_graveyard();
|
||||
new npc_battle_at_valhalas();
|
||||
new npc_llod_generic();
|
||||
@@ -2147,10 +2169,9 @@ void AddSC_icecrown()
|
||||
new npc_infra_green_bomber_generic();
|
||||
RegisterSpellScript(spell_onslaught_or_call_bone_gryphon);
|
||||
RegisterSpellScript(spell_deliver_gryphon);
|
||||
|
||||
// Theirs
|
||||
new npc_guardian_pavilion();
|
||||
new npc_tournament_training_dummy();
|
||||
new npc_blessed_banner();
|
||||
new npc_frostbrood_skytalon();
|
||||
RegisterSpellScript(spell_crashing_wave);
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ struct boss_alar : public BossAI
|
||||
scheduler.Schedule(timer, GROUP_FLAME_BUFFET, [this](TaskContext context)
|
||||
{
|
||||
if (!me->SelectNearestTarget(me->GetCombatReach()) && !me->isMoving())
|
||||
DoCastVictim(SPELL_FLAME_BUFFET);
|
||||
DoCastAOE(SPELL_FLAME_BUFFET);
|
||||
|
||||
context.Repeat(2s);
|
||||
});
|
||||
@@ -372,11 +372,11 @@ struct boss_alar : public BossAI
|
||||
{
|
||||
_transitionScheduler.Update(diff);
|
||||
|
||||
scheduler.Update(diff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ class spell_sha_totemic_mastery : public AuraScript
|
||||
{
|
||||
PreventDefaultAction();
|
||||
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM_FIRE; i < MAX_TOTEM_SLOT; ++i)
|
||||
if (!GetTarget()->m_SummonSlot[i])
|
||||
return;
|
||||
|
||||
|
||||
@@ -3306,6 +3306,22 @@ enum SummonType
|
||||
SUMMON_TYPE_JEEVES = 12
|
||||
};
|
||||
|
||||
enum SummonSlot
|
||||
{
|
||||
SUMMON_SLOT_PET = 0,
|
||||
SUMMON_SLOT_TOTEM_FIRE = 1,
|
||||
SUMMON_SLOT_TOTEM_EARTH = 2,
|
||||
SUMMON_SLOT_TOTEM_WATER = 3,
|
||||
SUMMON_SLOT_TOTEM_AIR = 4,
|
||||
SUMMON_SLOT_MINIPET = 5,
|
||||
SUMMON_SLOT_QUEST = 6,
|
||||
|
||||
MAX_SUMMON_SLOT
|
||||
};
|
||||
|
||||
#define MAX_TOTEM_SLOT 5
|
||||
#define MAX_GAMEOBJECT_SLOT 4
|
||||
|
||||
enum EventId
|
||||
{
|
||||
EVENT_CHARGE = 1003,
|
||||
|
||||
Reference in New Issue
Block a user