@@ -714,7 +714,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (me->IsRooted()) // Rooted inhabit type, never move/reposition
|
||||
continue;
|
||||
|
||||
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
|
||||
if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE)
|
||||
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (distanceToTarget < spellMinRange || !(isWithinLOSInMap || isSpellIgnoreLOS))
|
||||
|
||||
@@ -336,6 +336,9 @@ inline void Battleground::_CheckSafePositions(uint32 diff)
|
||||
|
||||
for (auto const& [playerGuid, player] : GetPlayers())
|
||||
{
|
||||
if (player->IsGameMaster())
|
||||
continue;
|
||||
|
||||
Position pos = player->GetPosition();
|
||||
Position const* startPos = GetTeamStartPosition(player->GetBgTeamId());
|
||||
|
||||
|
||||
@@ -12852,9 +12852,21 @@ void Player::ResurectUsingRequestData()
|
||||
|
||||
void Player::SetClientControl(Unit* target, bool allowMove, bool packetOnly /*= false*/)
|
||||
{
|
||||
ASSERT(target);
|
||||
// refuse to grant control if target has UNIT_STATE_CHARMED
|
||||
if (target->HasUnitState(UNIT_STATE_CHARMED) && (GetGUID() != target->GetCharmerGUID()))
|
||||
{
|
||||
LOG_ERROR("entities.player", "Player '{}' attempt to client control '{}', which is charmed by GUID {}", GetName(), target->GetName(), target->GetCharmerGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// still affected by some aura that shouldn't allow control, only allow on last such aura to be removed
|
||||
if (target->HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED))
|
||||
allowMove = false;
|
||||
|
||||
WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size() + 1);
|
||||
data << target->GetPackGUID();
|
||||
data << uint8((allowMove && !target->HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED)) ? 1 : 0);
|
||||
data << uint8(allowMove ? 1 : 0);
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// We want to set the packet only
|
||||
|
||||
@@ -1447,6 +1447,7 @@ public:
|
||||
bool SatisfyQuestConditions(Quest const* qInfo, bool msg);
|
||||
bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const;
|
||||
bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const;
|
||||
bool SatisfyQuestBreadcrumb(Quest const* qInfo, bool msg) const;
|
||||
bool SatisfyQuestNextChain(Quest const* qInfo, bool msg) const;
|
||||
bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg) const;
|
||||
bool SatisfyQuestDay(Quest const* qInfo, bool msg) const;
|
||||
|
||||
@@ -239,7 +239,7 @@ bool Player::CanSeeStartQuest(Quest const* quest)
|
||||
if (!sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) &&
|
||||
SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
|
||||
SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) &&
|
||||
SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
|
||||
SatisfyQuestPrevChain(quest, false) && SatisfyQuestBreadcrumb(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
|
||||
SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false))
|
||||
{
|
||||
return GetLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= quest->GetMinLevel();
|
||||
@@ -256,6 +256,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg)
|
||||
&& SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg)
|
||||
&& SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg)
|
||||
&& SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg)
|
||||
&& SatisfyQuestBreadcrumb(quest, msg)
|
||||
&& SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg)
|
||||
&& SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg)
|
||||
&& SatisfyQuestConditions(quest, msg);
|
||||
@@ -1217,6 +1218,39 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Player::SatisfyQuestBreadcrumb(Quest const* qInfo, bool msg) const
|
||||
{
|
||||
uint32 breadcrumbForQuestId = qInfo->GetBreadcrumbForQuestId();
|
||||
if (breadcrumbForQuestId)
|
||||
{
|
||||
QuestStatus status = GetQuestStatus(breadcrumbForQuestId);
|
||||
if (status != QUEST_STATUS_NONE || IsQuestRewarded(breadcrumbForQuestId))
|
||||
{
|
||||
if (msg)
|
||||
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::vector<uint32> const* breadcrumbs = sObjectMgr->GetBreadcrumbsForQuest(qInfo->GetQuestId()))
|
||||
{
|
||||
for (uint32 breadcrumbQuestId : *breadcrumbs)
|
||||
{
|
||||
QuestStatus status = GetQuestStatus(breadcrumbQuestId);
|
||||
if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_FAILED)
|
||||
{
|
||||
if (msg)
|
||||
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) const
|
||||
{
|
||||
uint32 nextQuest = qInfo->GetNextQuestInChain();
|
||||
|
||||
@@ -5177,7 +5177,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
|
||||
// Xinef: if stealer has same aura
|
||||
Aura* curAura = stealer->GetAura(aura->GetId());
|
||||
if (!curAura || (!curAura->IsPermanent() && curAura->GetDuration() < (int32)dur))
|
||||
if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID()))
|
||||
if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, stealer->GetGUID()))
|
||||
{
|
||||
// created aura must not be single target aura,, so stealer won't loose it on recast
|
||||
if (newAura->IsSingleTarget())
|
||||
@@ -5189,6 +5189,13 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
|
||||
}
|
||||
// FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
|
||||
newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]);
|
||||
|
||||
// Reset periodic timers so stolen HoTs tick properly
|
||||
// For stolen auras we need fresh tick counters since no ticks have occurred yet
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (AuraEffect* aurEff = newAura->GetEffect(i))
|
||||
aurEff->ResetPeriodic(true);
|
||||
|
||||
newAura->ApplyForTargets();
|
||||
}
|
||||
}
|
||||
@@ -11124,6 +11131,8 @@ void Unit::SetCharm(Unit* charm, bool apply)
|
||||
}
|
||||
else
|
||||
{
|
||||
charm->ClearUnitState(UNIT_STATE_CHARMED);
|
||||
|
||||
if (IsPlayer())
|
||||
{
|
||||
if (!RemoveGuidValue(UNIT_FIELD_CHARM, charm->GetGUID()))
|
||||
@@ -18631,7 +18640,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
|
||||
ASSERT(type != CHARM_TYPE_POSSESS || charmer->IsPlayer());
|
||||
if (type == CHARM_TYPE_VEHICLE && !IsVehicle()) // pussywizard
|
||||
throw 1;
|
||||
ASSERT((type == CHARM_TYPE_VEHICLE) == IsVehicle());
|
||||
ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
|
||||
|
||||
LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {} ({}), charmed {} ({}), type {}.",
|
||||
charmer->GetEntry(), charmer->GetGUID().ToString(), GetEntry(), GetGUID().ToString(), uint32(type));
|
||||
@@ -18804,6 +18813,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
|
||||
else if (IsPlayer())
|
||||
RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
||||
|
||||
AddUnitState(UNIT_STATE_CHARMED);
|
||||
|
||||
if (Creature* creature = ToCreature())
|
||||
creature->RefreshSwimmingFlag();
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ enum UnitState
|
||||
{
|
||||
UNIT_STATE_DIED = 0x00000001, // player has fake death aura
|
||||
UNIT_STATE_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone
|
||||
//UNIT_STATE_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone
|
||||
UNIT_STATE_CHARMED = 0x00000004, // having any kind of charm aura on self
|
||||
UNIT_STATE_STUNNED = 0x00000008,
|
||||
UNIT_STATE_ROAMING = 0x00000010,
|
||||
UNIT_STATE_CHASE = 0x00000020,
|
||||
@@ -201,7 +201,7 @@ enum UnitState
|
||||
UNIT_STATE_NO_COMBAT_MOVEMENT = 0x40000000, // should not be changed outside the core and should be placed at the end
|
||||
UNIT_STATE_LOGOUT_TIMER = 0x80000000, // Unit is logging out
|
||||
|
||||
UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE
|
||||
UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_CHARMED | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE
|
||||
| UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED
|
||||
| UNIT_STATE_DISTRACTED | UNIT_STATE_ISOLATED | UNIT_STATE_ATTACK_PLAYER | UNIT_STATE_CASTING
|
||||
| UNIT_STATE_POSSESSED | UNIT_STATE_CHARGING | UNIT_STATE_JUMPING | UNIT_STATE_MOVE | UNIT_STATE_ROTATING
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "TemporarySummon.h"
|
||||
#include "Unit.h"
|
||||
#include "Util.h"
|
||||
#include <algorithm>
|
||||
|
||||
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
|
||||
_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
|
||||
@@ -562,6 +563,11 @@ bool Vehicle::IsVehicleInUse()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vehicle::IsControllableVehicle() const
|
||||
{
|
||||
return std::ranges::any_of(Seats, [](auto const& seat) { return seat.second.SeatInfo->CanControl(); });
|
||||
}
|
||||
|
||||
void Vehicle::TeleportVehicle(float x, float y, float z, float ang)
|
||||
{
|
||||
_me->GetMap()->LoadGrid(x, y);
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
void RemoveAllPassengers();
|
||||
void Dismiss();
|
||||
bool IsVehicleInUse();
|
||||
[[nodiscard]] bool IsControllableVehicle() const;
|
||||
void TeleportVehicle(float x, float y, float z, float ang);
|
||||
|
||||
SeatMap Seats;
|
||||
|
||||
@@ -4738,10 +4738,10 @@ void ObjectMgr::LoadQuests()
|
||||
}
|
||||
|
||||
// Load `quest_template_addon`
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
result = WorldDatabase.Query("SELECT ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay, "
|
||||
//9 10 11 12 13 14 15 16 17
|
||||
"RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, RewardMailSenderEntry, SpecialFlags FROM quest_template_addon LEFT JOIN quest_mail_sender ON Id=QuestId");
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
result = WorldDatabase.Query("SELECT ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, BreadcrumbForQuestId, RewardMailTemplateID, "
|
||||
//9 10 11 12 13 14 15 16 17 18
|
||||
"RewardMailDelay, RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, RewardMailSenderEntry, SpecialFlags FROM quest_template_addon LEFT JOIN quest_mail_sender ON Id=QuestId");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -5318,12 +5318,54 @@ void ObjectMgr::LoadQuests()
|
||||
|
||||
if (qinfo->ExclusiveGroup)
|
||||
mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
|
||||
|
||||
if (uint32 breadcrumbForQuestId = qinfo->GetBreadcrumbForQuestId())
|
||||
{
|
||||
if (_questTemplates.find(breadcrumbForQuestId) == _questTemplates.end())
|
||||
LOG_ERROR("sql.sql", "Quest {} has BreadcrumbForQuestId {}, but no such quest exists", qinfo->GetQuestId(), breadcrumbForQuestId);
|
||||
else
|
||||
_breadcrumbsForQuest[breadcrumbForQuestId].push_back(qinfo->GetQuestId());
|
||||
|
||||
if (qinfo->GetNextQuestId())
|
||||
LOG_ERROR("sql.sql", "Quest {} is a breadcrumb quest but also has NextQuestID {} set", qinfo->GetQuestId(), qinfo->GetNextQuestId());
|
||||
if (qinfo->GetExclusiveGroup())
|
||||
LOG_ERROR("sql.sql", "Quest {} is a breadcrumb quest but also has ExclusiveGroup {} set", qinfo->GetQuestId(), qinfo->GetExclusiveGroup());
|
||||
}
|
||||
|
||||
if (qinfo->TimeAllowed)
|
||||
qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED);
|
||||
if (qinfo->RequiredPlayerKills)
|
||||
qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL);
|
||||
}
|
||||
|
||||
for (auto const& [questId, quest] : _questTemplates)
|
||||
{
|
||||
if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, questId, nullptr))
|
||||
continue;
|
||||
|
||||
uint32 breadcrumbForQuestId = quest->GetBreadcrumbForQuestId();
|
||||
if (!breadcrumbForQuestId)
|
||||
continue;
|
||||
|
||||
std::set<uint32> visitedQuests;
|
||||
visitedQuests.insert(questId);
|
||||
|
||||
while (breadcrumbForQuestId)
|
||||
{
|
||||
if (!visitedQuests.insert(breadcrumbForQuestId).second)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Breadcrumb quests {} and {} form a loop", questId, breadcrumbForQuestId);
|
||||
break;
|
||||
}
|
||||
|
||||
Quest const* targetQuest = GetQuestTemplate(breadcrumbForQuestId);
|
||||
if (!targetQuest)
|
||||
break;
|
||||
|
||||
breadcrumbForQuestId = targetQuest->GetBreadcrumbForQuestId();
|
||||
}
|
||||
}
|
||||
|
||||
// check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
|
||||
for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
|
||||
@@ -1146,6 +1146,18 @@ public:
|
||||
|
||||
ExclusiveQuestGroups mExclusiveQuestGroups;
|
||||
|
||||
typedef std::unordered_map<uint32, std::vector<uint32>> BreadcrumbQuestMap;
|
||||
BreadcrumbQuestMap _breadcrumbsForQuest;
|
||||
|
||||
[[nodiscard]] std::vector<uint32> const* GetBreadcrumbsForQuest(uint32 questId) const
|
||||
{
|
||||
auto itr = _breadcrumbsForQuest.find(questId);
|
||||
if (itr != _breadcrumbsForQuest.end())
|
||||
return &itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MailLevelReward const* GetMailLevelReward(uint32 level, uint32 raceMask)
|
||||
{
|
||||
MailLevelRewardContainer::const_iterator map_itr = _mailLevelRewardStore.find(level);
|
||||
|
||||
@@ -128,11 +128,11 @@ namespace Movement
|
||||
// MoveSplineFlag::Enter_Cycle support dropped
|
||||
//if (splineflags & SPLINEFLAG_ENTER_CYCLE)
|
||||
//cyclic_point = 1; // shouldn't be modified, came from client
|
||||
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
|
||||
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point, args.initialOrientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
|
||||
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], args.initialOrientation);
|
||||
}
|
||||
|
||||
// init spline timestamps
|
||||
|
||||
@@ -199,18 +199,20 @@ namespace Movement
|
||||
return length;
|
||||
}
|
||||
|
||||
void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m)
|
||||
void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation)
|
||||
{
|
||||
m_mode = m;
|
||||
cyclic = false;
|
||||
initialOrientation = orientation;
|
||||
|
||||
(this->*initializers[m_mode])(controls, count, cyclic, 0);
|
||||
}
|
||||
|
||||
void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point)
|
||||
void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation)
|
||||
{
|
||||
m_mode = m;
|
||||
cyclic = true;
|
||||
initialOrientation = orientation;
|
||||
|
||||
(this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
|
||||
}
|
||||
@@ -253,14 +255,18 @@ namespace Movement
|
||||
if (cyclic_point == 0)
|
||||
points[0] = controls[count - 1];
|
||||
else
|
||||
points[0] = controls[0].lerp(controls[1], -1);
|
||||
points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f };
|
||||
|
||||
points[high_index + 1] = controls[cyclic_point];
|
||||
points[high_index + 2] = controls[cyclic_point + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
points[0] = controls[0].lerp(controls[1], -1);
|
||||
if (m_mode == ModeCatmullrom)
|
||||
points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f };
|
||||
else
|
||||
points[0] = controls[0].lerp(controls[1], -1);
|
||||
|
||||
points[high_index + 1] = controls[count - 1];
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Movement
|
||||
|
||||
uint8 m_mode{UninitializedMode};
|
||||
bool cyclic{false};
|
||||
float initialOrientation{0};
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -116,8 +117,8 @@ namespace Movement
|
||||
[[nodiscard]] const Vector3& getPoint(index_type i) const { return points[i];}
|
||||
|
||||
/** Initializes spline. Don't call other methods while spline not initialized. */
|
||||
void init_spline(const Vector3* controls, index_type count, EvaluationMode m);
|
||||
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point);
|
||||
void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation);
|
||||
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation);
|
||||
|
||||
/** As i can see there are a lot of ways how spline can be initialized
|
||||
would be no harm to have some custom initializers. */
|
||||
@@ -170,8 +171,8 @@ namespace Movement
|
||||
void computeIndex(float t, index_type& out_idx, float& out_u) const;
|
||||
|
||||
/** Initializes spline. Don't call other methods while spline not initialized. */
|
||||
void init_spline(const Vector3* controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);}
|
||||
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point);}
|
||||
void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation = 0) { SplineBase::init_spline(controls, count, m, orientation);}
|
||||
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation = 0) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point, orientation);}
|
||||
|
||||
/** Initializes lengths with SplineBase::SegLength method. */
|
||||
void initLengths();
|
||||
|
||||
@@ -177,17 +177,18 @@ void Quest::LoadQuestTemplateAddon(Field* fields)
|
||||
PrevQuestId = fields[4].Get<int32>();
|
||||
NextQuestId = fields[5].Get<uint32>();
|
||||
ExclusiveGroup = fields[6].Get<int32>();
|
||||
RewardMailTemplateId = fields[7].Get<uint32>();
|
||||
RewardMailDelay = fields[8].Get<uint32>();
|
||||
RequiredSkillId = fields[9].Get<uint16>();
|
||||
RequiredSkillPoints = fields[10].Get<uint16>();
|
||||
RequiredMinRepFaction = fields[11].Get<uint16>();
|
||||
RequiredMaxRepFaction = fields[12].Get<uint16>();
|
||||
RequiredMinRepValue = fields[13].Get<int32>();
|
||||
RequiredMaxRepValue = fields[14].Get<int32>();
|
||||
StartItemCount = fields[15].Get<uint8>();
|
||||
RewardMailSenderEntry = fields[16].Get<uint32>();
|
||||
SpecialFlags = fields[17].Get<uint32>();
|
||||
BreadcrumbForQuestId = fields[7].Get<uint32>();
|
||||
RewardMailTemplateId = fields[8].Get<uint32>();
|
||||
RewardMailDelay = fields[9].Get<uint32>();
|
||||
RequiredSkillId = fields[10].Get<uint16>();
|
||||
RequiredSkillPoints = fields[11].Get<uint16>();
|
||||
RequiredMinRepFaction = fields[12].Get<uint16>();
|
||||
RequiredMaxRepFaction = fields[13].Get<uint16>();
|
||||
RequiredMinRepValue = fields[14].Get<int32>();
|
||||
RequiredMaxRepValue = fields[15].Get<int32>();
|
||||
StartItemCount = fields[16].Get<uint8>();
|
||||
RewardMailSenderEntry = fields[17].Get<uint32>();
|
||||
SpecialFlags = fields[18].Get<uint32>();
|
||||
|
||||
if ((SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) && !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT))
|
||||
{
|
||||
|
||||
@@ -249,6 +249,7 @@ public:
|
||||
[[nodiscard]] int32 GetPrevQuestId() const { return PrevQuestId; }
|
||||
[[nodiscard]] uint32 GetNextQuestId() const { return NextQuestId; }
|
||||
[[nodiscard]] int32 GetExclusiveGroup() const { return ExclusiveGroup; }
|
||||
[[nodiscard]] uint32 GetBreadcrumbForQuestId() const { return BreadcrumbForQuestId; }
|
||||
[[nodiscard]] uint32 GetNextQuestInChain() const { return RewardNextQuest; }
|
||||
[[nodiscard]] uint32 GetCharTitleId() const { return RewardTitleId; }
|
||||
[[nodiscard]] uint32 GetPlayersSlain() const { return RequiredPlayerKills; }
|
||||
@@ -390,6 +391,7 @@ protected:
|
||||
int32 PrevQuestId = 0;
|
||||
uint32 NextQuestId = 0;
|
||||
int32 ExclusiveGroup = 0;
|
||||
uint32 BreadcrumbForQuestId = 0;
|
||||
uint32 RewardMailTemplateId = 0;
|
||||
uint32 RewardMailDelay = 0;
|
||||
uint32 RequiredSkillId = 0;
|
||||
|
||||
@@ -89,14 +89,16 @@ struct boss_priestess_delrissa : public BossAI
|
||||
void InitializeAI() override
|
||||
{
|
||||
ScriptedAI::InitializeAI();
|
||||
std::list<uint32> helpersList;
|
||||
for (uint8 i = 0; i < MAX_HELPERS_COUNT; ++i)
|
||||
helpersList.push_back(helpersEntries[i]);
|
||||
Acore::Containers::RandomResize(helpersList, MAX_ACTIVE_HELPERS);
|
||||
|
||||
uint8 j = 0;
|
||||
for (std::list<uint32>::const_iterator itr = helpersList.begin(); itr != helpersList.end(); ++itr, ++j)
|
||||
me->SummonCreature(*itr, helpersLocations[j], TEMPSUMMON_MANUAL_DESPAWN, 0);
|
||||
if (instance->GetBossState(DATA_DELRISSA) != DONE)
|
||||
{
|
||||
std::vector<uint32> helpersList(std::begin(helpersEntries), std::end(helpersEntries));
|
||||
Acore::Containers::RandomResize(helpersList, MAX_ACTIVE_HELPERS);
|
||||
|
||||
uint8 j = 0;
|
||||
for (uint32 entry : helpersList)
|
||||
me->SummonCreature(entry, helpersLocations[j++], TEMPSUMMON_MANUAL_DESPAWN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
|
||||
@@ -52,6 +52,11 @@ DoorData const doorData[] =
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ DATA_KAELTHAS, new RectangleBoundary(118.64f, 178.63f, 125.69f, 210.70f) }
|
||||
};
|
||||
|
||||
Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f };
|
||||
|
||||
class instance_magisters_terrace : public InstanceMapScript
|
||||
@@ -65,6 +70,7 @@ public:
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(MAX_ENCOUNTER);
|
||||
LoadBossBoundaries(boundaries);
|
||||
SetPersistentDataCount(MAX_PERSISTENT_DATA);
|
||||
LoadObjectData(creatureData, gameobjectData);
|
||||
LoadDoorData(doorData);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,7 +46,6 @@ enum NPCs
|
||||
NPC_HOVER_DISK = 30248,
|
||||
NPC_ARCANE_OVERLOAD = 30282,
|
||||
NPC_SURGE_OF_POWER = 30334,
|
||||
NPC_WYRMREST_SKYTALON = 30161,
|
||||
NPC_STATIC_FIELD = 30592,
|
||||
NPC_ALEXSTRASZA = 32295,
|
||||
};
|
||||
@@ -75,6 +74,8 @@ enum eSpells
|
||||
SPELL_HASTE = 57060,
|
||||
|
||||
SPELL_ALEXSTRASZA_GIFT = 61028,
|
||||
SPELL_SUMMON_RED_DRAGON_BUDDY = 56070,
|
||||
SPELL_RIDE_RED_DRAGON = 56072
|
||||
};
|
||||
|
||||
enum eAchiev
|
||||
@@ -104,20 +105,11 @@ const Position Phase2NorthPos = {837.22f, 1301.676f, 296.10f, M_PI};
|
||||
|
||||
const uint32 MalygosIntroIntervals[] = {18000, 19000, 21000, 18000, 15000};
|
||||
|
||||
class EoEDrakeEnterVehicleEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
EoEDrakeEnterVehicleEvent(Creature& owner, ObjectGuid playerGUID) : _owner(owner), _playerGUID(playerGUID) { }
|
||||
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override;
|
||||
private:
|
||||
Creature& _owner;
|
||||
ObjectGuid _playerGUID;
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
inline AI* GetEyeOfEternityAI(T* obj)
|
||||
{
|
||||
return GetInstanceAI<AI>(obj, EyeOfEternityScriptName);
|
||||
}
|
||||
#define RegisterEoECreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetEyeOfEternityAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,18 +21,6 @@
|
||||
#include "Vehicle.h"
|
||||
#include "eye_of_eternity.h"
|
||||
|
||||
bool EoEDrakeEnterVehicleEvent::Execute(uint64 /*eventTime*/, uint32 /*updateTime*/)
|
||||
{
|
||||
if (Player* p = ObjectAccessor::GetPlayer(_owner, _playerGUID))
|
||||
if (p->IsInWorld() && !p->IsDuringRemoveFromWorld() && !p->isBeingLoaded() && p->FindMap() == _owner.FindMap())
|
||||
{
|
||||
p->CastCustomSpell(60683, SPELLVALUE_BASE_POINT0, 1, &_owner, true);
|
||||
return true;
|
||||
}
|
||||
_owner.DespawnOrUnsummon(1ms);
|
||||
return true;
|
||||
}
|
||||
|
||||
class instance_eye_of_eternity : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -68,7 +56,7 @@ public:
|
||||
return EncounterStatus == IN_PROGRESS;
|
||||
}
|
||||
|
||||
void OnPlayerEnter(Player* pPlayer) override
|
||||
void OnPlayerEnter(Player* player) override
|
||||
{
|
||||
if (EncounterStatus == DONE)
|
||||
{
|
||||
@@ -79,18 +67,12 @@ public:
|
||||
go->SetPhaseMask(2, true);
|
||||
|
||||
// no floor, so put players on drakes
|
||||
if (pPlayer)
|
||||
if (player)
|
||||
{
|
||||
if (!pPlayer->IsAlive())
|
||||
if (!player->IsAlive())
|
||||
return;
|
||||
|
||||
if (Creature* c = pPlayer->SummonCreature(NPC_WYRMREST_SKYTALON, pPlayer->GetPositionX(), pPlayer->GetPositionY(), pPlayer->GetPositionZ() - 20.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0))
|
||||
{
|
||||
c->SetCanFly(true);
|
||||
c->SetFaction(pPlayer->GetFaction());
|
||||
//pPlayer->CastCustomSpell(60683, SPELLVALUE_BASE_POINT0, 1, c, true);
|
||||
c->m_Events.AddEventAtOffset(new EoEDrakeEnterVehicleEvent(*c, pPlayer->GetGUID()), 500ms);
|
||||
}
|
||||
player->CastSpell(player, SPELL_SUMMON_RED_DRAGON_BUDDY, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,7 +753,6 @@ public:
|
||||
if (cr)
|
||||
{
|
||||
cr->AI()->AttackStart(me);
|
||||
cr->AddThreat(me, 0.0f);
|
||||
cr->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
@@ -911,6 +910,28 @@ void brann_bronzebeard::brann_bronzebeardAI::WaypointReached(uint32 id)
|
||||
}
|
||||
}
|
||||
|
||||
// 51774 - Taunt
|
||||
class spell_taunt_brann : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_taunt_brann);
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetHitUnit();
|
||||
if (!caster || !target)
|
||||
return;
|
||||
|
||||
uint32 spellId = GetEffectValue(); // 51775
|
||||
target->CastSpell(caster, spellId, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_taunt_brann::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_hos_dark_matter : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_hos_dark_matter);
|
||||
@@ -953,4 +974,5 @@ void AddSC_brann_bronzebeard()
|
||||
new brann_bronzebeard();
|
||||
RegisterSpellScript(spell_hos_dark_matter);
|
||||
RegisterSpellScript(spell_hos_dark_matter_size);
|
||||
RegisterSpellScript(spell_taunt_brann);
|
||||
}
|
||||
|
||||
@@ -558,8 +558,10 @@ public:
|
||||
{
|
||||
uint32 dist = urand(38, 48);
|
||||
float o = rand_norm() * M_PI * 2;
|
||||
float Zplus = (dist - 38) / 6.5f;
|
||||
if (Creature* cr = me->SummonCreature(entry, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
|
||||
float spawnX = me->GetPositionX() + dist * cos(o);
|
||||
float spawnY = me->GetPositionY() + dist * std::sin(o);
|
||||
float spawnZ = me->GetMap()->GetHeight(me->GetPhaseMask(), spawnX, spawnY, 330.0f);
|
||||
if (Creature* cr = me->SummonCreature(entry, spawnX, spawnY, spawnZ, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
|
||||
{
|
||||
cr->CastSpell(cr, SPELL_TENTACLE_ERUPT, true);
|
||||
cr->CastSpell(cr, SPELL_VOID_ZONE_SMALL, true);
|
||||
|
||||
@@ -1472,6 +1472,11 @@ public:
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H);
|
||||
_events.ScheduleEvent(EVENT_THASSARIAN_SCRIPT_1, 2s);
|
||||
}
|
||||
else if (type == POINT_MOTION_TYPE && param == 0)
|
||||
{
|
||||
if (Creature* talbot = ObjectAccessor::GetCreature(*me, _talbotGUID))
|
||||
me->SetFacingToObject(talbot);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -1804,6 +1809,7 @@ public:
|
||||
{
|
||||
if (action == 0)
|
||||
{
|
||||
me->setActive(true);
|
||||
_playerGUID = player->GetGUID();
|
||||
CloseGossipMenuFor(player);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
@@ -291,10 +291,29 @@ class spell_tsh_shoot_flame_arrow : public SpellScript
|
||||
|
||||
unitList.remove_if([&](WorldObject* target) -> bool
|
||||
{
|
||||
return !target->SelectNearestPlayer(15.0f);
|
||||
if (!target)
|
||||
return true;
|
||||
|
||||
if (!target->SelectNearestPlayer(15.0f))
|
||||
return true;
|
||||
|
||||
if (target->FindNearestGameObject(GO_BLAZE, 6.0f))
|
||||
return true;
|
||||
|
||||
// Don't stack arrows on the same target
|
||||
if (InstanceScript* instance = caster->GetInstanceScript())
|
||||
if (target->GetGUID() == instance->GetGuidData(DATA_LAST_FLAME_ARROW))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
Acore::Containers::RandomResize(unitList, 1);
|
||||
|
||||
// Replace last arrow GUID
|
||||
if (!unitList.empty())
|
||||
if (InstanceScript* instance = caster->GetInstanceScript())
|
||||
instance->SetGuidData(DATA_LAST_FLAME_ARROW, unitList.front()->GetGUID());
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex effIndex)
|
||||
|
||||
+15
@@ -117,11 +117,25 @@ public:
|
||||
return PrisonerGUID[data - DATA_PRISONER_1];
|
||||
case DATA_EXECUTIONER:
|
||||
return ExecutionerGUID;
|
||||
case DATA_LAST_FLAME_ARROW:
|
||||
return LastArrowGUID;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
void SetGuidData(uint32 data, ObjectGuid value) override
|
||||
{
|
||||
switch (data)
|
||||
{
|
||||
case DATA_LAST_FLAME_ARROW:
|
||||
LastArrowGUID = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Update(uint32 diff) override
|
||||
{
|
||||
if (RescueTimer && RescueTimer < 100 * MINUTE * IN_MILLISECONDS)
|
||||
@@ -164,6 +178,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectGuid LastArrowGUID;
|
||||
ObjectGuid ExecutionerGUID;
|
||||
ObjectGuid PrisonerGUID[3];
|
||||
uint32 RescueTimer;
|
||||
|
||||
@@ -37,7 +37,8 @@ enum DataTypes
|
||||
DATA_EXECUTIONER = 14,
|
||||
DATA_OMROGG_LEFT_HEAD = 15,
|
||||
DATA_OMROGG_RIGHT_HEAD = 16,
|
||||
DATA_WARCHIEF_PORTAL = 17
|
||||
DATA_WARCHIEF_PORTAL = 17,
|
||||
DATA_LAST_FLAME_ARROW = 18
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
@@ -49,6 +50,7 @@ enum CreatureIds
|
||||
NPC_SH_ZEALOT = 17462,
|
||||
NPC_SH_ARCHER = 17427,
|
||||
NPC_SH_SCOUT = 17693,
|
||||
NPC_SH_FLAME_ARROW = 17687,
|
||||
|
||||
// Warchief Kargath
|
||||
NPC_WARCHIEF_KARGATH = 16808,
|
||||
@@ -76,7 +78,8 @@ enum CreatureIds
|
||||
enum GameobjectIds
|
||||
{
|
||||
GO_GRAND_WARLOCK_CHAMBER_DOOR_1 = 182539,
|
||||
GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540
|
||||
GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540,
|
||||
GO_BLAZE = 181915
|
||||
};
|
||||
|
||||
enum SpellIds
|
||||
|
||||
@@ -146,25 +146,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class spell_the_eye_countercharge_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_the_eye_countercharge_aura);
|
||||
|
||||
bool PrepareProc(ProcEventInfo& /*eventInfo*/)
|
||||
{
|
||||
// xinef: prevent charge drop
|
||||
PreventDefaultAction();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_the_eye_countercharge_aura::PrepareProc);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_the_eye()
|
||||
{
|
||||
new instance_the_eye();
|
||||
RegisterSpellScript(spell_the_eye_countercharge_aura);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user