Merge branch 'master' into Playerbot
This commit is contained in:
@@ -79,7 +79,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_REP_REALM_CHARACTERS, "REPLACE INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, reg_mail, email, joindate) VALUES(?, ?, ?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
|
||||
|
||||
@@ -191,8 +191,26 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
|
||||
{
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
|
||||
{
|
||||
bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER);
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, spellInfo->GetMaxRange(false), playerOnly);
|
||||
DefaultTargetSelector targetSelector(me, spellInfo->GetMaxRange(false), false, true, 0);
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* target) {
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer())
|
||||
return false;
|
||||
}
|
||||
return targetSelector(target);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -206,12 +224,30 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
|
||||
{
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
|
||||
{
|
||||
bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER);
|
||||
float range = spellInfo->GetMaxRange(false);
|
||||
|
||||
DefaultTargetSelector targetSelector(me, range, playerOnly, true, -(int32)spellId);
|
||||
if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM)
|
||||
&& targetSelector(me->GetVictim()))
|
||||
DefaultTargetSelector defaultTargetSelector(me, range, false, true, -(int32)spellId);
|
||||
auto targetSelector = [&](Unit* target) {
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer())
|
||||
return false;
|
||||
}
|
||||
return defaultTargetSelector(target);
|
||||
};
|
||||
|
||||
if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) && targetSelector(me->GetVictim()))
|
||||
target = me->GetVictim();
|
||||
else
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, targetSelector);
|
||||
|
||||
@@ -165,9 +165,10 @@ struct PowerUsersSelector : public Acore::unary_function<Unit*, bool>
|
||||
}
|
||||
};
|
||||
|
||||
struct FarthestTargetSelector : public Acore::unary_function<Unit*, bool>
|
||||
// Simple selector based on range and Los
|
||||
struct RangeSelector : public Acore::unary_function<Unit*, bool>
|
||||
{
|
||||
FarthestTargetSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
RangeSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
|
||||
@@ -2506,12 +2506,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT:
|
||||
{
|
||||
std::vector<uint32> waypoints;
|
||||
std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(),
|
||||
std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
|
||||
|
||||
float distanceToClosest = std::numeric_limits<float>::max();
|
||||
WayPoint* closestWp = nullptr;
|
||||
uint32 closestWpId = 0;
|
||||
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
@@ -2519,29 +2515,34 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
if (IsSmart(creature))
|
||||
{
|
||||
for (uint32 wp : waypoints)
|
||||
for (uint32 wp = e.action.startClosestWaypoint.pathId1; wp <= e.action.startClosestWaypoint.pathId2; ++wp)
|
||||
{
|
||||
WPPath* path = sSmartWaypointMgr->GetPath(wp);
|
||||
if (!path || path->empty())
|
||||
continue;
|
||||
|
||||
auto itrWp = path->find(0);
|
||||
auto itrWp = path->find(1);
|
||||
if (itrWp != path->end())
|
||||
{
|
||||
if (WayPoint* wp = itrWp->second)
|
||||
if (WayPoint* wpData = itrWp->second)
|
||||
{
|
||||
float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z);
|
||||
float distToThisPath = creature->GetExactDistSq(wpData->x, wpData->y, wpData->z);
|
||||
if (distToThisPath < distanceToClosest)
|
||||
{
|
||||
distanceToClosest = distToThisPath;
|
||||
closestWp = wp;
|
||||
closestWpId = wp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closestWp)
|
||||
CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true);
|
||||
if (closestWpId)
|
||||
{
|
||||
bool repeat = e.action.startClosestWaypoint.repeat;
|
||||
bool run = e.action.startClosestWaypoint.run;
|
||||
|
||||
CAST_AI(SmartAI, creature->AI())->StartPath(repeat, closestWpId, run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3303,10 +3304,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (e.link && e.link != e.event_id)
|
||||
{
|
||||
auto linked = FindLinkedEvent(e.link);
|
||||
if (linked.has_value() && linked.value().get().GetEventType() == SMART_EVENT_LINK)
|
||||
executionStack.emplace_back(SmartScriptFrame{ linked.value(), unit, var0, var1, bvar, spell, gob });
|
||||
if (linked.has_value())
|
||||
{
|
||||
auto& linkedEvent = linked.value().get();
|
||||
if (linkedEvent.GetEventType() == SMART_EVENT_LINK)
|
||||
executionStack.emplace_back(SmartScriptFrame{ linkedEvent, unit, var0, var1, bvar, spell, gob });
|
||||
else
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} found but has wrong type (should be 61, is {}).", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link, linkedEvent.GetEventType());
|
||||
}
|
||||
else
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3509,7 +3516,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
case SMART_TARGET_FARTHEST:
|
||||
if (me)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3701,10 +3708,12 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
|
||||
if (!units.empty() && baseObject)
|
||||
for (WorldObject* unit : units)
|
||||
if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
|
||||
if (IsPlayer(unit) && !unit->ToPlayer()->IsGameMaster() && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
|
||||
targets.push_back(unit);
|
||||
|
||||
if (e.target.playerRange.maxCount)
|
||||
Acore::Containers::RandomResize(targets, e.target.playerRange.maxCount);
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_PLAYER_DISTANCE:
|
||||
@@ -4658,12 +4667,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (!targets.empty())
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (IsPlayer(target))
|
||||
if (IsPlayer(target) && !target->ToPlayer()->IsGameMaster())
|
||||
playerCount++;
|
||||
}
|
||||
if (playerCount >= e.event.nearPlayer.minCount)
|
||||
ProcessAction(e, unit);
|
||||
|
||||
if (playerCount >= e.event.nearPlayer.minCount)
|
||||
ProcessAction(e, unit);
|
||||
}
|
||||
RecalcTimer(e, e.event.nearPlayer.repeatMin, e.event.nearPlayer.repeatMax);
|
||||
break;
|
||||
@@ -4677,10 +4685,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (!targets.empty())
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (IsPlayer(target))
|
||||
if (IsPlayer(target) && !target->ToPlayer()->IsGameMaster())
|
||||
playerCount++;
|
||||
}
|
||||
|
||||
if (playerCount < e.event.nearPlayerNegation.maxCount)
|
||||
ProcessAction(e, unit);
|
||||
|
||||
@@ -806,7 +806,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_REMOVE_POWER: return sizeof(SmartAction::power);
|
||||
case SMART_ACTION_GAME_EVENT_STOP: return sizeof(SmartAction::gameEventStop);
|
||||
case SMART_ACTION_GAME_EVENT_START: return sizeof(SmartAction::gameEventStart);
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::closestWaypointFromList);
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::startClosestWaypoint);
|
||||
case SMART_ACTION_RISE_UP: return sizeof(SmartAction::moveRandom);
|
||||
case SMART_ACTION_RANDOM_SOUND: return sizeof(SmartAction::randomSound);
|
||||
case SMART_ACTION_SET_CORPSE_DELAY: return sizeof(SmartAction::corpseDelay);
|
||||
@@ -1536,15 +1536,22 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT:
|
||||
{
|
||||
if (e.action.startClosestWaypoint.pathId1 == 0 || e.action.startClosestWaypoint.pathId2 == 0 || e.action.startClosestWaypoint.pathId2 < e.action.startClosestWaypoint.pathId1)
|
||||
{
|
||||
if (std::all_of(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), [](uint32 wp) { return wp == 0; }))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid pathId1 or pathId2, it must be greater than 0 and pathId1 > pathId2",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
if (e.action.startClosestWaypoint.repeat > 1 || e.action.startClosestWaypoint.run > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid run ({}) or repeat ({}) parameter, must be 0 or 1.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(),
|
||||
e.action.startClosestWaypoint.repeat, e.action.startClosestWaypoint.run);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_INVOKER_CAST:
|
||||
if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type))
|
||||
{
|
||||
|
||||
@@ -1284,8 +1284,11 @@ struct SmartAction
|
||||
|
||||
struct
|
||||
{
|
||||
std::array<uint32, SMART_ACTION_PARAM_COUNT> wps;
|
||||
} closestWaypointFromList;
|
||||
uint32 pathId1;
|
||||
uint32 pathId2;
|
||||
uint32 repeat;
|
||||
uint32 run;
|
||||
} startClosestWaypoint;
|
||||
|
||||
struct
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace AccountMgr
|
||||
{
|
||||
|
||||
AccountOpResult CreateAccount(std::string username, std::string password)
|
||||
AccountOpResult CreateAccount(std::string username, std::string password, std::string email /*= ""*/)
|
||||
{
|
||||
if (utf8length(username) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG; // username's too long
|
||||
@@ -35,8 +35,12 @@ namespace AccountMgr
|
||||
if (utf8length(password) > MAX_PASS_STR)
|
||||
return AOR_PASS_TOO_LONG; // password's too long
|
||||
|
||||
if (utf8length(email) > MAX_EMAIL_STR)
|
||||
return AOR_EMAIL_TOO_LONG; // email is too long
|
||||
|
||||
Utf8ToUpperOnlyLatin(username);
|
||||
Utf8ToUpperOnlyLatin(password);
|
||||
Utf8ToUpperOnlyLatin(email);
|
||||
|
||||
if (GetId(username))
|
||||
return AOR_NAME_ALREADY_EXIST; // username does already exist
|
||||
@@ -48,6 +52,8 @@ namespace AccountMgr
|
||||
stmt->SetData(1, salt);
|
||||
stmt->SetData(2, verifier);
|
||||
stmt->SetData(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION)));
|
||||
stmt->SetData(4, email);
|
||||
stmt->SetData(5, email);
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ enum AccountOpResult
|
||||
|
||||
namespace AccountMgr
|
||||
{
|
||||
AccountOpResult CreateAccount(std::string username, std::string password);
|
||||
AccountOpResult CreateAccount(std::string username, std::string password, std::string email = "");
|
||||
AccountOpResult DeleteAccount(uint32 accountId);
|
||||
AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
|
||||
AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
|
||||
|
||||
@@ -788,9 +788,7 @@ void Creature::Update(uint32 diff)
|
||||
m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime -= diff;
|
||||
}
|
||||
|
||||
// Circling the target
|
||||
if (diff >= m_moveCircleMovementTime)
|
||||
@@ -799,9 +797,17 @@ void Creature::Update(uint32 diff)
|
||||
m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveCircleMovementTime -= diff;
|
||||
|
||||
// Periodically check if able to move, if not, extend leash timer
|
||||
if (diff >= m_extendLeashTime)
|
||||
{
|
||||
if (!CanFreeMove())
|
||||
UpdateLeashExtensionTime();
|
||||
m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL;
|
||||
}
|
||||
else
|
||||
m_extendLeashTime -= diff;
|
||||
}
|
||||
|
||||
// Call for assistance if not disabled
|
||||
|
||||
@@ -396,8 +396,10 @@ public:
|
||||
bool IsFreeToMove();
|
||||
static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;
|
||||
static constexpr uint32 MOVE_BACKWARDS_CHECK_INTERVAL = 2000;
|
||||
static constexpr uint32 EXTEND_LEASH_CHECK_INTERVAL = 3000;
|
||||
uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
|
||||
uint32 m_moveBackwardsMovementTime = MOVE_BACKWARDS_CHECK_INTERVAL;
|
||||
uint32 m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL;
|
||||
|
||||
[[nodiscard]] bool HasSwimmingFlagOutOfCombat() const
|
||||
{
|
||||
|
||||
@@ -13642,7 +13642,11 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass());
|
||||
if (!rcEntry)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character {} has skill {} that does not exist.", GetGUID().ToString(), skill);
|
||||
LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) that is invalid for the race/class combination (Race: {}, Class: {}). Will be deleted.",
|
||||
GetName(), GetGUID().GetCounter(), skill, getRace(), getClass());
|
||||
|
||||
// Mark skill for deletion in the database
|
||||
mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(0, SKILL_DELETED)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -13663,7 +13667,8 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character {} has skill {} with value 0. Will be deleted.", GetGUID().ToString(), skill);
|
||||
LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) with value 0. Will be deleted.",
|
||||
GetName(), GetGUID().GetCounter(), skill);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL);
|
||||
|
||||
|
||||
@@ -65,6 +65,9 @@ public:
|
||||
[[nodiscard]] uint32 GetCurrentTaxiPath() const;
|
||||
uint32 NextTaxiDestination()
|
||||
{
|
||||
if (m_TaxiDestinations.empty())
|
||||
return 0;
|
||||
|
||||
m_TaxiDestinations.pop_front();
|
||||
return GetTaxiDestination();
|
||||
}
|
||||
|
||||
@@ -20114,6 +20114,24 @@ private:
|
||||
AuraType _auraType;
|
||||
};
|
||||
|
||||
class ResetToHomeOrientation : public BasicEvent
|
||||
{
|
||||
public:
|
||||
ResetToHomeOrientation(Creature& self) : _self(self) { }
|
||||
|
||||
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
|
||||
{
|
||||
if (_self.IsInWorld() && _self.FindMap() && _self.IsAlive() && !_self.IsInCombat())
|
||||
{
|
||||
_self.SetFacingTo(_self.GetHomePosition().GetOrientation());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
Creature& _self;
|
||||
};
|
||||
|
||||
void Unit::CastDelayedSpellWithPeriodicAmount(Unit* caster, uint32 spellId, AuraType auraType, int32 addAmount, uint8 effectIndex)
|
||||
{
|
||||
AuraEffect* aurEff = nullptr;
|
||||
@@ -20360,6 +20378,24 @@ void Unit::SetFacingToObject(WorldObject* object)
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
void Unit::SetTimedFacingToObject(WorldObject* object, uint32 time)
|
||||
{
|
||||
// never face when already moving
|
||||
if (!IsStopped() || !time)
|
||||
return;
|
||||
|
||||
/// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is.
|
||||
Movement::MoveSplineInit init(this);
|
||||
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
init.SetFacing(GetAngle(object)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming
|
||||
init.Launch();
|
||||
|
||||
if (Creature* c = ToCreature())
|
||||
c->m_Events.AddEvent(new ResetToHomeOrientation(*c), c->m_Events.CalculateTime(time));
|
||||
else
|
||||
LOG_ERROR("entities.unit", "Unit::SetTimedFacingToObject called on non-creature unit {}. This should never happen.", GetEntry());
|
||||
}
|
||||
|
||||
bool Unit::SetWalk(bool enable)
|
||||
{
|
||||
if (enable == IsWalking())
|
||||
|
||||
@@ -1894,6 +1894,7 @@ public:
|
||||
void SetInFront(WorldObject const* target);
|
||||
void SetFacingTo(float ori);
|
||||
void SetFacingToObject(WorldObject* object);
|
||||
void SetTimedFacingToObject(WorldObject* object, uint32 time); // Reset to home orientation after given time
|
||||
|
||||
bool isInAccessiblePlaceFor(Creature const* c) const;
|
||||
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
|
||||
|
||||
@@ -512,7 +512,7 @@ void GameEventMgr::LoadEventCreatureData()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
ObjectGuid::LowType guid = fields[0].Get<uint32>();
|
||||
int16 eventId = fields[1].Get<int8>();
|
||||
int16 eventId = fields[1].Get<int16>();
|
||||
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(guid);
|
||||
if (!data)
|
||||
@@ -562,7 +562,7 @@ void GameEventMgr::LoadEventGameObjectData()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
ObjectGuid::LowType guid = fields[0].Get<uint32>();
|
||||
int16 eventId = fields[1].Get<int8>();
|
||||
int16 eventId = fields[1].Get<int16>();
|
||||
|
||||
int32 internal_event_id = _gameEvent.size() + eventId - 1;
|
||||
|
||||
@@ -1020,7 +1020,7 @@ void GameEventMgr::LoadEventPoolData()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 entry = fields[0].Get<uint32>();
|
||||
int16 eventId = fields[1].Get<int8>();
|
||||
int16 eventId = fields[1].Get<int16>();
|
||||
|
||||
int32 internal_event_id = _gameEvent.size() + eventId - 1;
|
||||
|
||||
|
||||
@@ -2317,7 +2317,7 @@ void ObjectMgr::LoadCreatures()
|
||||
data.movementType = fields[15].Get<uint8>();
|
||||
data.spawnMask = fields[16].Get<uint8>();
|
||||
data.phaseMask = fields[17].Get<uint32>();
|
||||
int16 gameEvent = fields[18].Get<int8>();
|
||||
int16 gameEvent = fields[18].Get<int16>();
|
||||
uint32 PoolId = fields[19].Get<uint32>();
|
||||
data.npcflag = fields[20].Get<uint32>();
|
||||
data.unit_flags = fields[21].Get<uint32>();
|
||||
@@ -2709,7 +2709,7 @@ void ObjectMgr::LoadGameobjects()
|
||||
LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) that has wrong spawn mask {} including not supported difficulty modes for map (Id: {}), skip", guid, data.id, data.spawnMask, data.mapid);
|
||||
|
||||
data.phaseMask = fields[15].Get<uint32>();
|
||||
int16 gameEvent = fields[16].Get<int8>();
|
||||
int16 gameEvent = fields[16].Get<int16>();
|
||||
uint32 PoolId = fields[17].Get<uint32>();
|
||||
|
||||
if (data.rotation.x < -1.0f || data.rotation.x > 1.0f)
|
||||
|
||||
@@ -172,8 +172,8 @@ namespace Acore
|
||||
template<class RET_TYPE, int CENTER_VAL>
|
||||
inline RET_TYPE Compute(float x, float y, float size)
|
||||
{
|
||||
int gx = (int)(CENTER_VAL - x / size);
|
||||
int gy = (int)(CENTER_VAL - y / size);
|
||||
int gx = std::max<int>(0, (CENTER_VAL - x / size));
|
||||
int gy = std::max<int>(0, (CENTER_VAL - y / size));
|
||||
|
||||
return RET_TYPE(gx, gy);
|
||||
}
|
||||
|
||||
@@ -331,7 +331,8 @@ enum AcoreStrings
|
||||
LANG_COMMAND_WHISPERON = 285,
|
||||
LANG_COMMAND_WHISPEROFF = 286,
|
||||
LANG_COMMAND_CREATGUIDNOTFOUND = 287,
|
||||
// TICKET STRINGS NEED REWRITE // 288-296 FREE
|
||||
LANG_COMMAND_GONOTENOUGHSPAWNS = 288,
|
||||
// TICKET STRINGS NEED REWRITE // 289-296 FREE
|
||||
|
||||
// END
|
||||
LANG_COMMAND_WANDER_DISTANCE = 297,
|
||||
|
||||
@@ -153,18 +153,20 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
MovementInform(owner);
|
||||
}
|
||||
|
||||
if (owner->movespline->Finalized())
|
||||
{ // Mobs should chase you infinitely if you stop and wait every few seconds.
|
||||
i_leashExtensionTimer.Update(time_diff);
|
||||
if (i_leashExtensionTimer.Passed())
|
||||
{
|
||||
i_leashExtensionTimer.Reset(5000);
|
||||
if (cOwner)
|
||||
if (cOwner)
|
||||
{
|
||||
if (owner->movespline->Finalized() && cOwner->IsWithinMeleeRange(target))
|
||||
{ // Mobs should chase you infinitely if you stop and wait every few seconds.
|
||||
i_leashExtensionTimer.Update(time_diff);
|
||||
if (i_leashExtensionTimer.Passed())
|
||||
{
|
||||
i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK));
|
||||
cOwner->UpdateLeashExtensionTime();
|
||||
}
|
||||
}
|
||||
else if (i_recalculateTravel)
|
||||
i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK));
|
||||
}
|
||||
else if (i_recalculateTravel)
|
||||
i_leashExtensionTimer.Reset(5000);
|
||||
|
||||
// if the target moved, we have to consider whether to adjust
|
||||
if (!_lastTargetPosition || target->GetPosition() != _lastTargetPosition.value() || mutualChase != _mutualChase || !owner->IsWithinLOSInMap(target))
|
||||
@@ -298,6 +300,7 @@ void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
|
||||
i_path = nullptr;
|
||||
_lastTargetPosition.reset();
|
||||
i_recheckDistance.Reset(0);
|
||||
i_leashExtensionTimer.Reset(owner->GetAttackTime(BASE_ATTACK));
|
||||
owner->SetWalk(false);
|
||||
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
class AchievementGlobalMgr;
|
||||
class AchievementMgr;
|
||||
class ArenaTeam;
|
||||
class AuctionEntry;
|
||||
class AuctionHouseMgr;
|
||||
class AuctionHouseObject;
|
||||
class Aura;
|
||||
@@ -98,6 +97,7 @@ enum WeatherState : uint32;
|
||||
struct AchievementCriteriaEntry;
|
||||
struct AchievementEntry;
|
||||
struct AreaTrigger;
|
||||
struct AuctionEntry;
|
||||
struct CompletedAchievementData;
|
||||
struct Condition;
|
||||
struct ConditionSourceInfo;
|
||||
|
||||
@@ -110,6 +110,7 @@ public:
|
||||
uint8 GetCasterLevel() const { return m_casterLevel; }
|
||||
bool CanApplyResilience() const { return m_applyResilience; }
|
||||
float GetPctMods() const { return m_pctMods; }
|
||||
void SetPctMods(float pctMods) { m_pctMods = pctMods; }
|
||||
|
||||
// xinef: stacking
|
||||
uint32 GetAuraGroup() const { return m_auraGroup; }
|
||||
|
||||
@@ -2147,6 +2147,8 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList*
|
||||
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_GHOSTS))
|
||||
retMask &= GRID_MAP_TYPE_MASK_PLAYER;
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
|
||||
|
||||
if (condList)
|
||||
retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
|
||||
|
||||
@@ -1863,8 +1863,19 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
else return SPELL_CAST_OK;
|
||||
|
||||
// corpseOwner and unit specific target checks
|
||||
if (AttributesEx3 & SPELL_ATTR3_ONLY_ON_PLAYER && !unitTarget->ToPlayer())
|
||||
return SPELL_FAILED_TARGET_NOT_PLAYER;
|
||||
if (unitTarget->IsPlayer())
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
return SPELL_FAILED_TARGET_IS_PLAYER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
|
||||
return SPELL_FAILED_TARGET_NOT_PLAYER;
|
||||
|
||||
if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && unitTarget->IsControlledByPlayer())
|
||||
return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED;
|
||||
}
|
||||
|
||||
if (!IsAllowingDeadTarget() && !unitTarget->IsAlive())
|
||||
return SPELL_FAILED_TARGETS_DEAD;
|
||||
|
||||
@@ -271,10 +271,15 @@ public:
|
||||
///- %Parse the command line arguments
|
||||
char* accountName = strtok((char*)args, " ");
|
||||
char* password = strtok(nullptr, " ");
|
||||
char* email = strtok(nullptr, " ");
|
||||
|
||||
if (!accountName || !password)
|
||||
return false;
|
||||
|
||||
AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password));
|
||||
// if email is not specified, use empty string
|
||||
std::string emailStr = email ? email : "";
|
||||
|
||||
AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password), emailStr);
|
||||
switch (result)
|
||||
{
|
||||
case AOR_OK:
|
||||
|
||||
@@ -86,16 +86,35 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId)
|
||||
static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId, Optional<uint32> _pos)
|
||||
{
|
||||
CreatureData const* spawnpoint = GetCreatureData(handler, *cId);
|
||||
uint32 pos = 1;
|
||||
if (_pos)
|
||||
{
|
||||
pos = *_pos;
|
||||
if (pos < 1)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spawnpoint)
|
||||
std::vector<CreatureData const*> spawnpoints = GetCreatureDataList(*cId);
|
||||
|
||||
if (spawnpoints.empty())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spawnpoints.size() < pos)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureData const* spawnpoint = spawnpoints[--pos];
|
||||
|
||||
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
|
||||
}
|
||||
|
||||
@@ -153,16 +172,35 @@ public:
|
||||
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
|
||||
}
|
||||
|
||||
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId)
|
||||
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId, Optional<uint32> _pos)
|
||||
{
|
||||
GameObjectData const* spawnpoint = GetGameObjectData(handler, goId);
|
||||
uint32 pos = 1;
|
||||
if (_pos)
|
||||
{
|
||||
pos = *_pos;
|
||||
if (pos < 1)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spawnpoint)
|
||||
std::vector<GameObjectData const*> spawnpoints = GetGameObjectDataList(goId);
|
||||
|
||||
if (spawnpoints.empty())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GOOBJNOTFOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spawnpoints.size() < pos)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObjectData const* spawnpoint = spawnpoints[--pos];
|
||||
|
||||
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
|
||||
}
|
||||
|
||||
@@ -509,6 +547,22 @@ public:
|
||||
return spawnpoint;
|
||||
}
|
||||
|
||||
static std::vector<CreatureData const*> GetCreatureDataList(uint32 entry)
|
||||
{
|
||||
std::vector<CreatureData const*> spawnpoints;
|
||||
for (auto const& pair : sObjectMgr->GetAllCreatureData())
|
||||
{
|
||||
if (pair.second.id1 != entry)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
spawnpoints.emplace_back(&pair.second);
|
||||
}
|
||||
|
||||
return spawnpoints;
|
||||
}
|
||||
|
||||
static GameObjectData const* GetGameObjectData(ChatHandler* handler, uint32 entry)
|
||||
{
|
||||
GameObjectData const* spawnpoint = nullptr;
|
||||
@@ -532,6 +586,22 @@ public:
|
||||
|
||||
return spawnpoint;
|
||||
}
|
||||
|
||||
static std::vector<GameObjectData const*> GetGameObjectDataList(uint32 entry)
|
||||
{
|
||||
std::vector<GameObjectData const*> spawnpoints;
|
||||
for (auto const& pair : sObjectMgr->GetAllGOData())
|
||||
{
|
||||
if (pair.second.id != entry)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
spawnpoints.emplace_back(&pair.second);
|
||||
}
|
||||
|
||||
return spawnpoints;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_go_commandscript()
|
||||
|
||||
@@ -74,7 +74,7 @@ struct boss_servant_quarters : public BossAI
|
||||
context.Repeat(12s, 18s);
|
||||
}).Schedule(10s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, 40.0f, false, true)))
|
||||
{
|
||||
me->CastSpell(target, SPELL_DIVE);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "CombatAI.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedEscortAI.h"
|
||||
@@ -185,16 +186,23 @@ public:
|
||||
|
||||
enum Koltira
|
||||
{
|
||||
SAY_BREAKOUT1 = 0,
|
||||
SAY_BREAKOUT2 = 1,
|
||||
SAY_BREAKOUT3 = 2,
|
||||
SAY_BREAKOUT4 = 3,
|
||||
SAY_BREAKOUT5 = 4,
|
||||
SAY_BREAKOUT6 = 5,
|
||||
SAY_BREAKOUT7 = 6,
|
||||
SAY_BREAKOUT8 = 7,
|
||||
SAY_BREAKOUT9 = 8,
|
||||
SAY_BREAKOUT10 = 9,
|
||||
SAY_BREAKOUT0 = 0,
|
||||
SAY_BREAKOUT1 = 1,
|
||||
SAY_BREAKOUT2 = 2,
|
||||
SAY_BREAKOUT3 = 3,
|
||||
SAY_BREAKOUT4 = 4,
|
||||
SAY_BREAKOUT5 = 5,
|
||||
SAY_BREAKOUT6 = 6,
|
||||
SAY_BREAKOUT7 = 7,
|
||||
SAY_BREAKOUT8 = 8,
|
||||
SAY_BREAKOUT9 = 9,
|
||||
SAY_BREAKOUT10 = 10,
|
||||
EMOTE_KOLTIRA_COLLAPSES = 11,
|
||||
|
||||
SAY_VALROTH_WAVE3 = 0,
|
||||
SAY_VALROTH_AGGRO = 1,
|
||||
SAY_VALROTH_WAVE1 = 4,
|
||||
SAY_VALROTH_WAVE2 = 5,
|
||||
|
||||
SPELL_KOLTIRA_TRANSFORM = 52899,
|
||||
SPELL_ANTI_MAGIC_ZONE = 52894,
|
||||
@@ -206,7 +214,14 @@ enum Koltira
|
||||
|
||||
//not sure about this id
|
||||
//NPC_DEATH_KNIGHT_MOUNT = 29201,
|
||||
MODEL_DEATH_KNIGHT_MOUNT = 25278
|
||||
MODEL_DEATH_KNIGHT_MOUNT = 25278,
|
||||
|
||||
POINT_STAND_UP = 0,
|
||||
POINT_BOX = 1,
|
||||
POINT_ANTI_MAGIC_ZONE = 2,
|
||||
|
||||
POINT_MOUNT = 0,
|
||||
POINT_DESPAWN = 1
|
||||
};
|
||||
|
||||
class npc_koltira_deathweaver : public CreatureScript
|
||||
@@ -214,205 +229,203 @@ class npc_koltira_deathweaver : public CreatureScript
|
||||
public:
|
||||
npc_koltira_deathweaver() : CreatureScript("npc_koltira_deathweaver") { }
|
||||
|
||||
bool OnQuestAccept(Player* player, Creature* creature, const Quest* quest) override
|
||||
{
|
||||
if (quest->GetQuestId() == QUEST_BREAKOUT)
|
||||
{
|
||||
creature->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
creature->setActive(true);
|
||||
|
||||
if (npc_escortAI* pEscortAI = CAST_AI(npc_koltira_deathweaver::npc_koltira_deathweaverAI, creature->AI()))
|
||||
pEscortAI->Start(false, false, player->GetGUID());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_koltira_deathweaverAI(creature);
|
||||
}
|
||||
|
||||
struct npc_koltira_deathweaverAI : public npc_escortAI
|
||||
struct npc_koltira_deathweaverAI : public ScriptedAI
|
||||
{
|
||||
npc_koltira_deathweaverAI(Creature* creature) : npc_escortAI(creature), summons(me)
|
||||
{
|
||||
me->SetReactState(REACT_DEFENSIVE);
|
||||
}
|
||||
|
||||
uint32 m_uiWave;
|
||||
uint32 m_uiWave_Timer;
|
||||
ObjectGuid m_uiValrothGUID;
|
||||
SummonList summons;
|
||||
npc_koltira_deathweaverAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
if (!HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
m_uiWave = 0;
|
||||
m_uiWave_Timer = 3000;
|
||||
m_uiValrothGUID.Clear();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->LoadEquipment(0, true);
|
||||
me->RemoveAllAuras();
|
||||
summons.DespawnAll();
|
||||
}
|
||||
scheduler.CancelAll();
|
||||
me->m_Events.KillAllEvents(false);
|
||||
me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
me->setActive(false);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
void StartEvent()
|
||||
{
|
||||
me->GetThreatMgr().ClearAllThreat();
|
||||
me->CombatStop(false);
|
||||
me->SetLootRecipient(nullptr);
|
||||
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
AddEscortState(STATE_ESCORT_RETURNING);
|
||||
ReturnToLastPoint();
|
||||
LOG_DEBUG("scripts.ai", "EscortAI has left combat and is now returning to last point");
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
me->SetImmuneToNPC(true);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (HasEscortState(STATE_ESCORT_PAUSED))
|
||||
if (!me->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP)) // Already in progress
|
||||
return;
|
||||
|
||||
npc_escortAI::AttackStart(who);
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
me->setActive(true);
|
||||
|
||||
Talk(SAY_BREAKOUT0);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
|
||||
}, 5s);
|
||||
}
|
||||
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
void sQuestAccept(Player* /*player*/, Quest const* quest) override
|
||||
{
|
||||
switch (waypointId)
|
||||
if (quest->GetQuestId() == QUEST_BREAKOUT)
|
||||
StartEvent();
|
||||
}
|
||||
|
||||
void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_BREAKOUT) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
case 0:
|
||||
Talk(SAY_BREAKOUT1);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
break;
|
||||
case 1:
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
break;
|
||||
case 2:
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
//me->UpdateEntry(NPC_KOLTIRA_ALT); //unclear if we must update or not
|
||||
DoCast(me, SPELL_KOLTIRA_TRANSFORM);
|
||||
me->LoadEquipment();
|
||||
break;
|
||||
case 3:
|
||||
SetEscortPaused(true);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
Talk(SAY_BREAKOUT2);
|
||||
DoCast(me, SPELL_ANTI_MAGIC_ZONE); // cast again that makes bubble up
|
||||
break;
|
||||
case 4:
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false);
|
||||
SetRun(true);
|
||||
break;
|
||||
case 9:
|
||||
me->Mount(MODEL_DEATH_KNIGHT_MOUNT);
|
||||
break;
|
||||
case 10:
|
||||
me->Dismount();
|
||||
break;
|
||||
CloseGossipMenuFor(player);
|
||||
StartEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summoned) override
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
summoned->AI()->AttackStart(player);
|
||||
if (type != WAYPOINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (summoned->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH)
|
||||
m_uiValrothGUID = summoned->GetGUID();
|
||||
|
||||
summoned->AddThreat(me, 0.0f);
|
||||
summoned->SetImmuneToPC(false);
|
||||
summons.Summon(summoned);
|
||||
}
|
||||
|
||||
void SummonAcolyte(uint32 uiAmount)
|
||||
{
|
||||
for (uint32 i = 0; i < uiAmount; ++i)
|
||||
me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 uiDiff) override
|
||||
{
|
||||
npc_escortAI::UpdateAI(uiDiff);
|
||||
|
||||
if (HasEscortState(STATE_ESCORT_PAUSED))
|
||||
if (!me->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC))
|
||||
{
|
||||
if (m_uiWave_Timer <= uiDiff)
|
||||
if (id == POINT_MOUNT)
|
||||
me->Mount(MODEL_DEATH_KNIGHT_MOUNT);
|
||||
else if (id == POINT_DESPAWN)
|
||||
{
|
||||
switch (m_uiWave)
|
||||
me->Dismount();
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case POINT_STAND_UP:
|
||||
Talk(SAY_BREAKOUT1);
|
||||
break;
|
||||
case POINT_BOX:
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
|
||||
scheduler.Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
switch (context.GetRepeatCounter())
|
||||
{
|
||||
case 0:
|
||||
Talk(SAY_BREAKOUT3);
|
||||
SummonAcolyte(3);
|
||||
m_uiWave_Timer = 20000;
|
||||
|
||||
// Shouldn't actually be spawned at this point, but no way to send his yells otherwise?
|
||||
if (Creature* valroth = me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1640.8596f, -6030.834f, 134.82211f, 4.606426715850830078f, TEMPSUMMON_MANUAL_DESPAWN))
|
||||
{
|
||||
_valrothGUID = valroth->GetGUID();
|
||||
valroth->AI()->Talk(SAY_VALROTH_WAVE1);
|
||||
valroth->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.6724f, -6032.0527f, 134.82213f, 4.654973506927490234f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath(NPC_CRIMSON_ACOLYTE * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.0055f, -6031.893f, 134.82211f, 0.401425719261169433f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 1) * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1639.7053f, -6031.7373f, 134.82213f, 2.443460941314697265f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 2) * 10, false);
|
||||
break;
|
||||
case 1:
|
||||
Talk(SAY_BREAKOUT4);
|
||||
SummonAcolyte(3);
|
||||
m_uiWave_Timer = 20000;
|
||||
|
||||
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
|
||||
valroth->AI()->Talk(SAY_VALROTH_WAVE2);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.7958f, -6030.307f, 134.82211f, 4.65355682373046875f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 3) * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.7305f, -6030.751f, 134.82211f, 6.143558979034423828f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 4) * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1639.4657f, -6030.404f, 134.82211f, 4.502949237823486328f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 5) * 10, false);
|
||||
break;
|
||||
case 2:
|
||||
Talk(SAY_BREAKOUT5);
|
||||
SummonAcolyte(4);
|
||||
m_uiWave_Timer = 20000;
|
||||
|
||||
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
|
||||
valroth->AI()->Talk(SAY_VALROTH_WAVE3);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.3405f, -6031.436f, 134.82211f, 4.612849712371826171f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 6) * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.0404f, -6030.3843f, 134.82211f, 1.378810048103332519f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 7) * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.1162f, -6029.7817f, 134.82211f, 5.707226753234863281f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 8) * 10, false);
|
||||
|
||||
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.9948f, -6029.8027f, 134.82211f, 1.605702877044677734f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
|
||||
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 9) * 10, false);
|
||||
break;
|
||||
case 3:
|
||||
Talk(SAY_BREAKOUT6);
|
||||
me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000);
|
||||
m_uiWave_Timer = 1000;
|
||||
break;
|
||||
case 4:
|
||||
me->m_Events.AddEventAtOffset([this]
|
||||
{
|
||||
Creature* temp = ObjectAccessor::GetCreature(*me, m_uiValrothGUID);
|
||||
Talk(EMOTE_KOLTIRA_COLLAPSES, me);
|
||||
me->KillSelf();
|
||||
|
||||
if (!temp || !temp->IsAlive())
|
||||
{
|
||||
Talk(SAY_BREAKOUT8);
|
||||
m_uiWave_Timer = 5000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// xinef: despawn check
|
||||
Player* player = GetPlayerForEscort();
|
||||
if (!player || me->GetDistance(player) > 60.0f)
|
||||
{
|
||||
me->DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
|
||||
valroth->DespawnOrUnsummon();
|
||||
}, 2min);
|
||||
|
||||
m_uiWave_Timer = 2500;
|
||||
return; //return, we don't want m_uiWave to increment now
|
||||
}
|
||||
break;
|
||||
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
|
||||
{
|
||||
valroth->AI()->Talk(SAY_VALROTH_AGGRO);
|
||||
valroth->SetReactState(REACT_AGGRESSIVE);
|
||||
valroth->GetMotionMaster()->MovePath(NPC_HIGH_INQUISITOR_VALROTH * 10, false);
|
||||
}
|
||||
case 5:
|
||||
Talk(SAY_BREAKOUT9);
|
||||
me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE);
|
||||
// i do not know why the armor will also be removed
|
||||
m_uiWave_Timer = 2500;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
case 6:
|
||||
Talk(SAY_BREAKOUT10);
|
||||
SetEscortPaused(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++m_uiWave;
|
||||
}
|
||||
else
|
||||
m_uiWave_Timer -= uiDiff;
|
||||
context.Repeat(20s);
|
||||
});
|
||||
|
||||
scheduler.Schedule(3s, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_KOLTIRA_TRANSFORM);
|
||||
me->LoadEquipment();
|
||||
});
|
||||
break;
|
||||
case POINT_ANTI_MAGIC_ZONE:
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
Talk(SAY_BREAKOUT2);
|
||||
DoCastSelf(SPELL_ANTI_MAGIC_ZONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit*) override
|
||||
{
|
||||
if (summon->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH)
|
||||
{
|
||||
me->m_Events.KillAllEvents(false);
|
||||
me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
Talk(SAY_BREAKOUT8, 3s);
|
||||
Talk(SAY_BREAKOUT9, 8s);
|
||||
scheduler.Schedule(11s, [this](TaskContext)
|
||||
{
|
||||
Talk(SAY_BREAKOUT10);
|
||||
SetInvincibility(true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
me->GetMotionMaster()->MovePath((me->GetEntry() + 1) * 10, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _valrothGUID;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -504,98 +517,6 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
//Koltira & Valroth- Breakout
|
||||
|
||||
enum valroth
|
||||
{
|
||||
//SAY_VALROTH1 = 0, Unused
|
||||
SAY_VALROTH_AGGRO = 1,
|
||||
SAY_VALROTH_RAND = 2,
|
||||
SAY_VALROTH_DEATH = 3,
|
||||
SPELL_RENEW = 38210,
|
||||
SPELL_INQUISITOR_PENANCE = 52922,
|
||||
SPELL_VALROTH_SMITE = 52926,
|
||||
SPELL_SUMMON_VALROTH_REMAINS = 52929
|
||||
};
|
||||
|
||||
class npc_high_inquisitor_valroth : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_high_inquisitor_valroth() : CreatureScript("npc_high_inquisitor_valroth") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_high_inquisitor_valrothAI(creature);
|
||||
}
|
||||
|
||||
struct npc_high_inquisitor_valrothAI : public ScriptedAI
|
||||
{
|
||||
npc_high_inquisitor_valrothAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 uiRenew_timer;
|
||||
uint32 uiInquisitor_Penance_timer;
|
||||
uint32 uiValroth_Smite_timer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
uiRenew_timer = 1000;
|
||||
uiInquisitor_Penance_timer = 2000;
|
||||
uiValroth_Smite_timer = 1000;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
Talk(SAY_VALROTH_AGGRO);
|
||||
DoCast(who, SPELL_VALROTH_SMITE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (uiRenew_timer <= diff)
|
||||
{
|
||||
Shout();
|
||||
DoCast(me, SPELL_RENEW);
|
||||
uiRenew_timer = urand(1000, 6000);
|
||||
}
|
||||
else uiRenew_timer -= diff;
|
||||
|
||||
if (uiInquisitor_Penance_timer <= diff)
|
||||
{
|
||||
Shout();
|
||||
DoCastVictim(SPELL_INQUISITOR_PENANCE);
|
||||
uiInquisitor_Penance_timer = urand(2000, 7000);
|
||||
}
|
||||
else uiInquisitor_Penance_timer -= diff;
|
||||
|
||||
if (uiValroth_Smite_timer <= diff)
|
||||
{
|
||||
Shout();
|
||||
DoCastVictim(SPELL_VALROTH_SMITE);
|
||||
uiValroth_Smite_timer = urand(1000, 6000);
|
||||
}
|
||||
else uiValroth_Smite_timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void Shout()
|
||||
{
|
||||
if (rand() % 100 < 15)
|
||||
Talk(SAY_VALROTH_RAND);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_VALROTH_DEATH);
|
||||
|
||||
if (killer)
|
||||
{
|
||||
killer->CastSpell(me, SPELL_SUMMON_VALROTH_REMAINS, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_a_special_surprise
|
||||
######*/
|
||||
@@ -785,6 +706,5 @@ void AddSC_the_scarlet_enclave_c2()
|
||||
new npc_crusade_persuaded();
|
||||
new npc_scarlet_courier();
|
||||
new npc_koltira_deathweaver();
|
||||
new npc_high_inquisitor_valroth();
|
||||
new npc_a_special_surprise();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ enum LightOfDawnEncounter
|
||||
EVENT_SPELL_DEATH_STRIKE,
|
||||
EVENT_SPELL_DEATH_EMBRACE,
|
||||
EVENT_SPELL_UNHOLY_BLIGHT,
|
||||
EVENT_SPELL_TALK,
|
||||
EVENT_SPELL_DARION_MOD_DAMAGE,
|
||||
// Positioning
|
||||
EVENT_FINISH_FIGHT_1,
|
||||
EVENT_FINISH_FIGHT_2,
|
||||
@@ -253,6 +253,7 @@ enum LightOfDawnSpells
|
||||
SPELL_DEATH_EMBRACE = 53635,
|
||||
SPELL_ICY_TOUCH1 = 49723,
|
||||
SPELL_UNHOLY_BLIGHT = 53640,
|
||||
SPELL_DARION_MOD_DAMAGE = 53645,
|
||||
|
||||
// Outro
|
||||
SPELL_THE_LIGHT_OF_DAWN = 53658,
|
||||
@@ -524,7 +525,7 @@ public:
|
||||
events.RescheduleEvent(EVENT_SPELL_DEATH_STRIKE, 8000);
|
||||
events.RescheduleEvent(EVENT_SPELL_DEATH_EMBRACE, 5000);
|
||||
events.RescheduleEvent(EVENT_SPELL_UNHOLY_BLIGHT, 10000);
|
||||
events.RescheduleEvent(EVENT_SPELL_TALK, 10000);
|
||||
events.RescheduleEvent(EVENT_SPELL_DARION_MOD_DAMAGE, 500);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
@@ -661,7 +662,7 @@ public:
|
||||
me->SetHomePosition(pos);
|
||||
me->SetWalk(false);
|
||||
me->GetMotionMaster()->MovePoint(1, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, true);
|
||||
me->CastSpell(me, SPELL_THE_MIGHT_OF_MOGRAINE, true);
|
||||
DoCastSelf(SPELL_THE_MIGHT_OF_MOGRAINE, true);
|
||||
break;
|
||||
}
|
||||
case EVENT_START_COUNTDOWN_14:
|
||||
@@ -1146,23 +1147,24 @@ public:
|
||||
{
|
||||
case EVENT_SPELL_ANTI_MAGIC_ZONE:
|
||||
DoCast(me, SPELL_ANTI_MAGIC_ZONE1);
|
||||
events.RescheduleEvent(eventId, 25s, 30s);
|
||||
events.RescheduleEvent(eventId, 30s, 45s);
|
||||
break;
|
||||
case EVENT_SPELL_DEATH_STRIKE:
|
||||
DoCastVictim(SPELL_DEATH_STRIKE);
|
||||
events.RescheduleEvent(eventId, 5s, 10s);
|
||||
events.RescheduleEvent(eventId, 5s, 35s);
|
||||
break;
|
||||
case EVENT_SPELL_DEATH_EMBRACE:
|
||||
DoCastVictim(SPELL_DEATH_EMBRACE);
|
||||
events.RescheduleEvent(eventId, 15s, 20s);
|
||||
events.RescheduleEvent(eventId, 45s, 60s);
|
||||
break;
|
||||
case EVENT_SPELL_UNHOLY_BLIGHT:
|
||||
DoCast(me, SPELL_UNHOLY_BLIGHT);
|
||||
events.RescheduleEvent(eventId, 60s);
|
||||
break;
|
||||
case EVENT_SPELL_TALK:
|
||||
case EVENT_SPELL_DARION_MOD_DAMAGE:
|
||||
DoCast(me, SPELL_DARION_MOD_DAMAGE);
|
||||
Talk(SAY_LIGHT_OF_DAWN09);
|
||||
events.RescheduleEvent(eventId, 15s, 20s);
|
||||
events.RescheduleEvent(eventId, 15s, 25s);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1215,9 +1217,106 @@ class spell_chapter5_rebuke : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 58552 - Return to Orgrimmar
|
||||
// 58533 - Return to Stormwind
|
||||
enum ReturnToCapital
|
||||
{
|
||||
SPELL_RETURN_TO_ORGRIMMAR_APPLE = 58509,
|
||||
SPELL_RETURN_TO_ORGRIMMAR_BANANA = 58513,
|
||||
SPELL_RETURN_TO_ORGRIMMAR_SPIT = 58520,
|
||||
|
||||
EMOTE_THROW_APPLE = 2,
|
||||
EMOTE_THROW_BANANA = 3,
|
||||
EMOTE_THROW_SPIT = 4,
|
||||
SAY_INSULT_TO_DK = 5,
|
||||
|
||||
NPC_SW_GUARD = 68,
|
||||
NPC_ROYAL_GUARD = 1756,
|
||||
NPC_CITY_PATROLLER = 1976,
|
||||
NPC_OG_GUARD = 3296,
|
||||
NPC_KOR_ELITE = 14304,
|
||||
|
||||
TEXT_BROADCAST_COWER = 31670 // "%s cowers in fear."
|
||||
};
|
||||
|
||||
uint32 ReturnToCapitalSpells[3] =
|
||||
{
|
||||
58509, // Apple
|
||||
58513, // Banana
|
||||
58520 // Spit
|
||||
};
|
||||
|
||||
class spell_chapter5_return_to_capital : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_chapter5_return_to_capital);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_RETURN_TO_ORGRIMMAR_APPLE, SPELL_RETURN_TO_ORGRIMMAR_BANANA, SPELL_RETURN_TO_ORGRIMMAR_SPIT});
|
||||
}
|
||||
|
||||
void HandleHit(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Creature* creature = GetHitUnit()->ToCreature();
|
||||
Player* player = GetCaster()->ToPlayer();
|
||||
uint32 spellId = GetSpellInfo()->Id;
|
||||
|
||||
if (!spellId || !creature || !player || player->IsGameMaster() || !player->IsAlive() || !creature->IsAlive() || creature->IsInCombat())
|
||||
return;
|
||||
|
||||
if (creature->HasSpellCooldown(spellId))
|
||||
return;
|
||||
|
||||
if (creature->GetEntry() == NPC_SW_GUARD || creature->GetEntry() == NPC_ROYAL_GUARD || creature->GetEntry() == NPC_CITY_PATROLLER || creature->GetEntry() == NPC_OG_GUARD || creature->GetEntry() == NPC_KOR_ELITE)
|
||||
{
|
||||
_emote = urand(2,4);
|
||||
if (creature)
|
||||
{
|
||||
creature->PauseMovement(5000);
|
||||
creature->SetTimedFacingToObject(player, 30000);
|
||||
|
||||
if (roll_chance_i(30))
|
||||
{
|
||||
creature->AI()->Talk(_emote, player);
|
||||
creature->CastSpell(player, ReturnToCapitalSpells[_emote - 2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
creature->AI()->Talk(SAY_INSULT_TO_DK, player);
|
||||
creature->HandleEmoteCommand(RAND(EMOTE_ONESHOT_POINT,EMOTE_ONESHOT_RUDE));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*/// @todo: This needs to be further investigated as there are some "guard" npcs, that have civilian flags and non guard npcs should also insult the dk.
|
||||
else
|
||||
if (creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN)
|
||||
{
|
||||
creature->HandleEmoteCommand(EMOTE_STATE_COWER); // from sniff, emote 431 for a while, then reset (with "%s cowers in fear." text)
|
||||
creature->PlayDirectSound(14556); // from sniff
|
||||
if (player)
|
||||
{
|
||||
LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
|
||||
if (BroadcastText const* bct = sObjectMgr->GetBroadcastText(TEXT_BROADCAST_COWER))
|
||||
creature->TextEmote(bct->GetText(loc_idx, creature->getGender()), creature);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
creature->AddSpellCooldown(spellId, 0, 30000);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_chapter5_return_to_capital::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
private:
|
||||
uint8 _emote;
|
||||
};
|
||||
|
||||
void AddSC_the_scarlet_enclave_c5()
|
||||
{
|
||||
new npc_highlord_darion_mograine();
|
||||
RegisterSpellScript(spell_chapter5_light_of_dawn_aura);
|
||||
RegisterSpellScript(spell_chapter5_rebuke);
|
||||
RegisterSpellScript(spell_chapter5_return_to_capital);
|
||||
}
|
||||
|
||||
@@ -381,14 +381,8 @@ struct boss_kiljaeden : public BossAI
|
||||
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
|
||||
{
|
||||
anveena->RemoveAllAuras();
|
||||
anveena->DespawnOrUnsummon(3500);
|
||||
}
|
||||
}, 34s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
|
||||
{
|
||||
anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true);
|
||||
anveena->DespawnOrUnsummon(1500);
|
||||
DoCastSelf(SPELL_CUSTOM_08_STATE, true);
|
||||
me->SetUnitFlag(UNIT_FLAG_PACIFIED);
|
||||
scheduler.CancelAll();
|
||||
|
||||
@@ -213,7 +213,7 @@ struct npc_dark_fiend : public ScriptedAI
|
||||
Unit* target = nullptr;
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* muru = instance->GetCreature(DATA_MURU))
|
||||
target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, FarthestTargetSelector(me, 50.0f, true, true));
|
||||
target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, RangeSelector(me, 50.0f, true, true));
|
||||
|
||||
if (target)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "CreatureScript.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "halls_of_lightning.h"
|
||||
|
||||
@@ -27,6 +29,7 @@ enum IonarSpells
|
||||
SPELL_BALL_LIGHTNING_H = 59800,
|
||||
SPELL_STATIC_OVERLOAD_N = 52658,
|
||||
SPELL_STATIC_OVERLOAD_H = 59795,
|
||||
SPELL_STATIC_OVERLOAD_KNOCK = 53337,
|
||||
|
||||
SPELL_DISPERSE = 52770,
|
||||
SPELL_SUMMON_SPARK = 52746,
|
||||
@@ -272,8 +275,34 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
// 52658, 59795 - Static Overload
|
||||
class spell_ionar_static_overload : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_ionar_static_overload);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_STATIC_OVERLOAD_KNOCK });
|
||||
}
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
|
||||
return;
|
||||
|
||||
if (Unit* target = GetTarget())
|
||||
target->CastSpell(target, SPELL_STATIC_OVERLOAD_KNOCK, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_ionar_static_overload::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_ionar()
|
||||
{
|
||||
new boss_ionar();
|
||||
new npc_spark_of_ionar();
|
||||
RegisterSpellScript(spell_ionar_static_overload);
|
||||
}
|
||||
|
||||
@@ -819,54 +819,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum StormCloud
|
||||
{
|
||||
STORM_COULD = 29939,
|
||||
HEALING_WINDS = 55549,
|
||||
STORM_VISUAL = 55708,
|
||||
GYMERS_GRAB = 55516,
|
||||
RIDE_VEHICLE = 43671
|
||||
};
|
||||
|
||||
class npc_storm_cloud : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_storm_cloud() : CreatureScript("npc_storm_cloud") { }
|
||||
|
||||
struct npc_storm_cloudAI : public ScriptedAI
|
||||
{
|
||||
npc_storm_cloudAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, STORM_VISUAL, true);
|
||||
}
|
||||
|
||||
void JustRespawned() override
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id != GYMERS_GRAB)
|
||||
return;
|
||||
|
||||
if (Vehicle* veh = caster->GetVehicleKit())
|
||||
if (veh->GetAvailableSeatCount() != 0)
|
||||
{
|
||||
me->CastSpell(caster, RIDE_VEHICLE, true);
|
||||
me->CastSpell(caster, HEALING_WINDS, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_storm_cloudAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
enum ScourgeDisguiseInstability
|
||||
{
|
||||
SCOURGE_DISGUISE_FAILING_MESSAGE_1 = 28552, // Scourge Disguise Failing! Find a safe place!
|
||||
@@ -922,7 +874,6 @@ void AddSC_zuldrak()
|
||||
new npc_released_offspring_harkoa();
|
||||
new npc_crusade_recruit();
|
||||
new go_scourge_enclosure();
|
||||
new npc_storm_cloud();
|
||||
|
||||
RegisterSpellScript(spell_scourge_disguise_instability);
|
||||
}
|
||||
|
||||
@@ -1727,6 +1727,16 @@ class spell_dk_pestilence : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_dk_pestilence);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_DK_GLYPH_OF_DISEASE,
|
||||
SPELL_DK_BLOOD_PLAGUE,
|
||||
SPELL_DK_FROST_FEVER
|
||||
});
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
@@ -1743,11 +1753,38 @@ class spell_dk_pestilence : public SpellScript
|
||||
|
||||
// And spread them on target
|
||||
// Blood Plague
|
||||
if (target->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID()))
|
||||
caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true);
|
||||
if (Aura* disOld = target->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID()))
|
||||
if (AuraEffect* effOld = disOld->GetEffect(EFFECT_0))
|
||||
{
|
||||
float pctMods = effOld->GetPctMods();
|
||||
float crit = effOld->GetCritChance();
|
||||
caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true);
|
||||
|
||||
if (Aura* disNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID()))
|
||||
if (AuraEffect* effNew = disNew->GetEffect(EFFECT_0))
|
||||
{
|
||||
effNew->SetPctMods(pctMods);
|
||||
effNew->SetCritChance(crit);
|
||||
effNew->SetAmount(effNew->CalculateAmount(effNew->GetCaster()));
|
||||
}
|
||||
}
|
||||
|
||||
// Frost Fever
|
||||
if (target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
|
||||
caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true);
|
||||
if (Aura* disOld = target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
|
||||
if (AuraEffect* effOld = disOld->GetEffect(EFFECT_0))
|
||||
{
|
||||
float pctMods = effOld->GetPctMods();
|
||||
float crit = effOld->GetCritChance();
|
||||
caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true);
|
||||
|
||||
if (Aura* disNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
|
||||
if (AuraEffect* effNew = disNew->GetEffect(EFFECT_0))
|
||||
{
|
||||
effNew->SetPctMods(pctMods);
|
||||
effNew->SetCritChance(crit);
|
||||
effNew->SetAmount(effNew->CalculateAmount(effNew->GetCaster()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -606,7 +606,6 @@ class spell_gen_black_magic_enchant : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 53642 - The Might of Mograine
|
||||
// 64174 - Protective Gaze
|
||||
class spell_gen_area_aura_select_players : public AuraScript
|
||||
{
|
||||
@@ -622,6 +621,7 @@ class spell_gen_area_aura_select_players : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 53642 - The Might of Mograine
|
||||
// 62650 - Fortitude of Frost
|
||||
// 62670 - Resilience of Nature
|
||||
// 62671 - Speed of Invention
|
||||
|
||||
@@ -4187,6 +4187,28 @@ class spell_item_multiphase_goggles : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 60244 - Blood Parrot Despawn Aura (Item: 12185 - Bloodsail Admiral's Hat)
|
||||
enum BloodsailAdmiralHat
|
||||
{
|
||||
NPC_ADMIRAL_HAT_PARROT = 11236, // Blood Parrot
|
||||
};
|
||||
|
||||
class spell_item_bloodsail_admiral_hat : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_item_bloodsail_admiral_hat);
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
player->RemoveAllMinionsByEntry(NPC_ADMIRAL_HAT_PARROT);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_item_bloodsail_admiral_hat::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_item_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_item_massive_seaforium_charge);
|
||||
@@ -4315,4 +4337,5 @@ void AddSC_item_spell_scripts()
|
||||
RegisterSpellScript(spell_item_luffa);
|
||||
RegisterSpellScript(spell_item_spell_reflectors);
|
||||
RegisterSpellScript(spell_item_multiphase_goggles);
|
||||
RegisterSpellScript(spell_item_bloodsail_admiral_hat);
|
||||
}
|
||||
|
||||
@@ -2269,7 +2269,10 @@ class spell_q12619_emblazon_runeblade_effect : public SpellScript
|
||||
enum Quest_The_Storm_King
|
||||
{
|
||||
SPELL_RIDE_GYMER = 43671,
|
||||
SPELL_GRABBED = 55424
|
||||
SPELL_GRABBED = 55424,
|
||||
SPELL_HEALING_WINDS = 55549,
|
||||
|
||||
NPC_STORM_CLOUD = 29939
|
||||
};
|
||||
|
||||
class spell_q12919_gymers_grab : public SpellScript
|
||||
@@ -2284,10 +2287,14 @@ class spell_q12919_gymers_grab : public SpellScript
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
int8 seatId = 2;
|
||||
if (!GetHitCreature())
|
||||
return;
|
||||
GetHitCreature()->CastCustomSpell(SPELL_RIDE_GYMER, SPELLVALUE_BASE_POINT0, seatId, GetCaster(), true);
|
||||
GetHitCreature()->CastSpell(GetHitCreature(), SPELL_GRABBED, true);
|
||||
if (Creature* creature = GetHitCreature())
|
||||
{
|
||||
creature->CastCustomSpell(SPELL_RIDE_GYMER, SPELLVALUE_BASE_POINT0, seatId, GetCaster(), true);
|
||||
creature->CastSpell(creature, SPELL_GRABBED, true);
|
||||
|
||||
if (creature->GetEntry() == NPC_STORM_CLOUD)
|
||||
creature->CastSpell(GetCaster(), SPELL_HEALING_WINDS, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -391,8 +391,8 @@ enum SpellAttr0 : uint32
|
||||
SPELL_ATTR0_HELD_ITEM_ONLY = 0x00000200, // TITLE Auto-target mainhand item (client only) DESCRIPTION Client will automatically select main-hand item as cast target
|
||||
SPELL_ATTR0_ON_NEXT_SWING = 0x00000400, // TITLE On next melee (type 2) DESCRIPTION Both "on next swing" attributes have identical handling in server & client
|
||||
SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER = 0x00000800, // TITLE Unknown attribute 11@Attr0
|
||||
SPELL_ATTR0_SERVER_ONLY = 0x00001000, // TITLE Only usable during daytime (unused)
|
||||
SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP = 0x00002000, // TITLE Only usable during nighttime (unused)
|
||||
SPELL_ATTR0_SERVER_ONLY = 0x00001000, // TITLE Unused attribute 12@Attr0 DESCRIPTION not set in 3.3.5a
|
||||
SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP = 0x00002000, // TITLE Only usable during nighttime
|
||||
SPELL_ATTR0_ONLY_INDOORS = 0x00004000, // TITLE Only usable indoors
|
||||
SPELL_ATTR0_ONLY_OUTDOORS = 0x00008000, // TITLE Only usable outdoors
|
||||
SPELL_ATTR0_NOT_SHAPESHIFTED = 0x00010000, // TITLE Not usable while shapeshifted
|
||||
@@ -461,14 +461,14 @@ enum SpellAttr2 : uint32
|
||||
SPELL_ATTR2_AUTO_REPEAT = 0x00000020, // TITLE Ranged auto-attack spell
|
||||
SPELL_ATTR2_CANNOT_CAST_ON_TAPPED = 0x00000040, // TITLE Cannot target others' tapped units DESCRIPTION Can only target untapped units, or those tapped by caster
|
||||
SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE = 0x00000080, // TITLE Unknown attribute 7@Attr2
|
||||
SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG = 0x00000100, // TITLE Unknown attribute 8@Attr2 DESCRIPTION not set in 3.0.3
|
||||
SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG = 0x00000100, // TITLE Unused attribute 8@Attr2 DESCRIPTION not set in 3.3.5a
|
||||
SPELL_ATTR2_ALWAYS_CAST_AS_UNIT = 0x00000200, // TITLE Unknown attribute 9@Attr2
|
||||
SPELL_ATTR2_SPECIAL_TAMING_FLAG = 0x00000400, // TITLE Unknown attribute 10@Attr2 DESCRIPTION Related to taming?
|
||||
SPELL_ATTR2_NO_TARGET_PER_SECOND_COST = 0x00000800, // TITLE Health Funnel
|
||||
SPELL_ATTR2_CHAIN_FROM_CASTER = 0x00001000, // TITLE Unknown attribute 12@Attr2 DESCRIPTION Cleave, Heart Strike, Maul, Sunder Armor, Swipe
|
||||
SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY = 0x00002000, // TITLE Enchant persists when entering arena
|
||||
SPELL_ATTR2_ALLOW_WHILE_INVISIBLE = 0x00004000, // TITLE Unknown attribute 14@Attr2
|
||||
SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST = 0x00008000, // TITLE Unknown attribute 15@Attr2 DESCRIPTION not set in 3.0.3
|
||||
SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST = 0x00008000, // TITLE Unused attribute 15@Attr2 DESCRIPTION not set in 3.3.5a
|
||||
SPELL_ATTR2_NO_ACTIVE_PETS = 0x00010000, // TITLE Tame Beast
|
||||
SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS = 0x00020000, // TITLE Don't reset swing timer DESCRIPTION Does not reset melee/ranged autoattack timer on cast
|
||||
SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING = 0x00040000, // TITLE Requires dead pet
|
||||
@@ -511,8 +511,8 @@ enum SpellAttr3 : uint32
|
||||
SPELL_ATTR3_ALWAYS_HIT = 0x00040000, // TITLE Ignore hit result DESCRIPTION Spell cannot miss, or be dodged/parried/blocked
|
||||
SPELL_ATTR3_INSTANT_TARGET_PROCS = 0x00080000, // TITLE Cannot trigger spells during aura proc
|
||||
SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD = 0x00100000, // TITLE Persists through death
|
||||
SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unknown attribute 21@Attr3
|
||||
SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Requires equipped Wand (Mainline: Do Not Trigger Target Stand)
|
||||
SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unused attribute 21@Attr3 DESCRIPTION Not set in 3.3.5a
|
||||
SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Unused attribute 22@Attr3 DESCRIPTION Not set in 3.3.5a
|
||||
SPELL_ATTR3_NO_DAMAGE_HISTORY = 0x00800000, // TITLE Unknown attribute 23@Attr3
|
||||
SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON = 0x01000000, // TITLE Requires offhand weapon
|
||||
SPELL_ATTR3_TREAT_AS_PERIODIC = 0x02000000, // TITLE Treat as periodic effect
|
||||
@@ -571,7 +571,7 @@ enum SpellAttr5 : uint32
|
||||
SPELL_ATTR5_TRIGGERS_CHANNELING = 0x00000010, // TITLE Unknown attribute 4@Attr5
|
||||
SPELL_ATTR5_LIMIT_N = 0x00000020, // TITLE Single-target aura DESCRIPTION Remove previous application to another unit if applied
|
||||
SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK = 0x00000040, // TITLE Unknown attribute 6@Attr5
|
||||
SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Unknown attribute 7@Attr5
|
||||
SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Cannot target players
|
||||
SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC = 0x00000100, // TITLE Cannot target player controlled units but can target players
|
||||
SPELL_ATTR5_EXTRA_INITIAL_PERIOD = 0x00000200, // TITLE Immediately do periodic tick on apply
|
||||
SPELL_ATTR5_DO_NOT_DISPLAY_DURATION = 0x00000400, // TITLE Do not send aura duration to client
|
||||
@@ -650,8 +650,8 @@ enum SpellAttr7 : uint32
|
||||
SPELL_ATTR7_ALLIANCE_SPECIFIC_SPELL = 0x00000200, // TITLE Alliance only
|
||||
SPELL_ATTR7_DISPEL_REMOVES_CHARGES = 0x00000400, // TITLE Dispel/Spellsteal remove individual charges
|
||||
SPELL_ATTR7_CAN_CAUSE_INTERRUPT = 0x00000800, // TITLE Only interrupt non-player casting
|
||||
SPELL_ATTR7_CAN_CAUSE_SILENCE = 0x00001000, // TITLE Unknown attribute 12@Attr7 DESCRIPTION Not set in 3.2.2a.
|
||||
SPELL_ATTR7_NO_UI_NOT_INTERRUPTIBLE = 0x00002000, // TITLE Unknown attribute 13@Attr7 DESCRIPTION Not set in 3.2.2a.
|
||||
SPELL_ATTR7_CAN_CAUSE_SILENCE = 0x00001000, // TITLE Unused attribute 12@Attr7 DESCRIPTION Not set in 3.3.5a.
|
||||
SPELL_ATTR7_NO_UI_NOT_INTERRUPTIBLE = 0x00002000, // TITLE Unused attribute 13@Attr7 DESCRIPTION Not set in 3.3.5a.
|
||||
SPELL_ATTR7_RECAST_ON_RESUMMON = 0x00004000, // TITLE Unknown attribute 14@Attr7 DESCRIPTION Only 52150 (Raise Dead - Pet) spell.
|
||||
SPELL_ATTR7_RESET_SWING_TIMER_AT_SPELL_START = 0x00008000, // TITLE Unknown attribute 15@Attr7 DESCRIPTION Exorcism - guaranteed crit vs families?
|
||||
SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED = 0x00010000, // TITLE Can restore secondary power DESCRIPTION Only spells with this attribute can replenish a non-active power type
|
||||
@@ -659,7 +659,7 @@ enum SpellAttr7 : uint32
|
||||
SPELL_ATTR7_ATTACK_ON_CHARGE_TO_UNIT = 0x00040000, // TITLE Has charge effect
|
||||
SPELL_ATTR7_REPORT_SPELL_FAILURE_TO_UNIT_TARGET = 0x00080000, // TITLE Is zone teleport
|
||||
SPELL_ATTR7_NO_CLIENT_FAIL_WHILE_STUNNED_FLEEING_CONFUSED = 0x00100000, // TITLE Unknown attribute 20@Attr7 DESCRIPTION Invulnerability related?
|
||||
SPELL_ATTR7_RETAIN_COOLDOWN_THROUGH_LOAD = 0x00200000, // TITLE Unknown attribute 21@Attr7
|
||||
SPELL_ATTR7_RETAIN_COOLDOWN_THROUGH_LOAD = 0x00200000, // TITLE Unused attribute 21@Attr7 DESCRPIPTION Not set in 3.3.5a
|
||||
SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT = 0x00400000, // TITLE Ignore cold weather flying restriction DESCRIPTION Set for loaner mounts, allows them to be used despite lacking required flight skill
|
||||
SPELL_ATTR7_NO_ATTACK_DODGE = 0x00800000, // TITLE Spell cannot be dodged 23@Attr7 DESCRIPTION Motivate, Mutilate, Shattering Throw
|
||||
SPELL_ATTR7_NO_ATTACK_PARRY = 0x01000000, // TITLE Spell cannot be parried 24@Attr7 DESCRIPTION Motivate, Mutilate, Perform Speech, Shattering Throw
|
||||
|
||||
Reference in New Issue
Block a user