Merge remote-tracking branch 'acore/master' into test-staging

This commit is contained in:
Celandriel
2026-05-08 18:22:10 +00:00
25 changed files with 160 additions and 131 deletions
@@ -4360,14 +4360,6 @@ AllowTwoSide.Interaction.Calendar = 0
AllowTwoSide.Interaction.Chat = 0
#
# AllowTwoSide.Interaction.Emote
# Description: Allow emote messages between factions (e.g. "/e looks into the sky")
# Default: 0 - (Disabled)
# 1 - (Enabled)
AllowTwoSide.Interaction.Emote = 0
#
# AllowTwoSide.Interaction.Channel
# Description: Allow channel chat between factions.
@@ -4409,38 +4401,6 @@ AllowTwoSide.Interaction.Arena = 0
AllowTwoSide.Interaction.Auction = 0
#
# AllowTwoSide.Interaction.Mail
# Description: Allow sending mails between factions.
# Default: 0 - (Disabled)
# 1 - (Enabled)
AllowTwoSide.Interaction.Mail = 0
#
# AllowTwoSide.WhoList
# Description: Show characters from both factions in the /who list.
# Default: 0 - (Disabled)
# 1 - (Enabled)
AllowTwoSide.WhoList = 0
#
# AllowTwoSide.AddFriend
# Description: Allow adding friends from other faction the friends list.
# Default: 0 - (Disabled)
# 1 - (Enabled)
AllowTwoSide.AddFriend = 0
#
# AllowTwoSide.Trade
# Description: Allow trading between factions.
# Default: 0 - (Disabled)
# 1 - (Enabled)
AllowTwoSide.Trade = 0
#
# TalentsInspecting
# Description: Allow inspecting characters from the opposing faction.
@@ -364,6 +364,7 @@ void Battlefield::EndBattle(bool endByTimer)
DoPlaySoundToAll(BF_HORDE_WINS);
OnBattleEnd(endByTimer);
sScriptMgr->OnBattlefieldWarEnd(this, endByTimer);
// Reset battlefield timer
Timer = NoWarBattleTime;
+4 -9
View File
@@ -206,6 +206,10 @@ void ThreatReference::HeapNotifyDecreased()
if (tWho->GetSummonerGUID().IsPlayer())
return false;
// accessories are fully treated as components of the parent and cannot have threat
if (cWho->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
return false;
return true;
}
@@ -396,15 +400,6 @@ void ThreatManager::AddThreat(Unit* target, float amount, SpellInfo const* spell
return;
}
// while riding a vehicle, all threat goes to the vehicle, not the pilot
if (Unit* vehicle = target->GetVehicleBase())
{
AddThreat(vehicle, amount, spell, ignoreModifiers, ignoreRedirects);
if (target->HasUnitTypeMask(UNIT_MASK_ACCESSORY)) // accessories are fully treated as components of the parent and cannot have threat
return;
amount = 0.0f;
}
// if we cannot actually have a threat list, we instead just set combat state and avoid creating threat refs altogether
if (!CanHaveThreatList())
{
@@ -15426,6 +15426,15 @@ void Player::ActivateSpec(uint8 spec)
++iter;
}
// Recheck shapeshift bonus auras: drop and re-apply form-tied passives
// so buffs from talents missing in the new spec (e.g. Master Shapeshifter) go away
Unit::AuraEffectList const& shapeshiftAuras = GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT);
for (AuraEffect* aurEff : shapeshiftAuras)
{
aurEff->HandleShapeshiftBoosts(this, false);
aurEff->HandleShapeshiftBoosts(this, true);
}
sScriptMgr->OnPlayerAfterSpecSlotChanged(this, GetActiveSpec());
}
+5 -2
View File
@@ -313,7 +313,10 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ
if (TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime))
{
if (minion)
{
accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
accessory->GetThreatMgr().Initialize(); // reinitialize CanHaveThreatList cached value
}
if (!_me->HandleSpellClick(accessory, seatId))
{
@@ -455,9 +458,9 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
init.SetTransportEnter();
init.Launch();
// Transfer threat from passenger to vehicle
// Put the vehicle in combat with anything that was threatening the passenger; the threat itself stays on the passenger
for (auto const& [guid, threatRef] : unit->GetThreatMgr().GetThreatenedByMeList())
threatRef->GetOwner()->GetThreatMgr().AddThreat(_me, threatRef->GetThreat(), nullptr, true, true);
threatRef->GetOwner()->GetThreatMgr().AddThreat(_me, 0.0f, nullptr, true, true);
if (_me->IsCreature())
{
+1 -1
View File
@@ -214,7 +214,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : sCharacterCache->GetCharacterAccountIdByGuid(receiverGuid);
if (/*!accountBound*/ GetAccountId() != rc_account && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeamId() != rc_teamId && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL))
if (/*!accountBound*/ GetAccountId() != rc_account && player->GetTeamId() != rc_teamId && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL))
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM);
return;
-1
View File
@@ -293,7 +293,6 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
for (auto const& target : sWhoListCacheMgr->GetWhoList())
{
// player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
if (target.GetTeamId() != team && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_WHO_LIST))
continue;
+1 -1
View File
@@ -64,7 +64,7 @@ void WorldSession::HandleAddFriendOpcode(WorldPacket& recv_data)
{
if (friendGuid == GetPlayer()->GetGUID())
friendResult = FRIEND_SELF;
else if (GetPlayer()->GetTeamId() != teamId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_ADD_FRIEND))
else if (GetPlayer()->GetTeamId() != teamId && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_ADD_FRIEND))
friendResult = FRIEND_ENEMY;
else if (GetPlayer()->GetSocial()->HasFriend(friendGuid))
friendResult = FRIEND_ALREADY;
@@ -723,7 +723,6 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
}
if (pOther->GetTeamId() != _player->GetTeamId() &&
!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) &&
!GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_ALLOW_TWO_SIDE_TRADE))
{
info.Status = TRADE_STATUS_WRONG_FACTION;
@@ -44,6 +44,11 @@ void ScriptMgr::OnBattlefieldBeforeInvitePlayerToWar(Battlefield* bf, Player* pl
CALL_ENABLED_HOOKS(BattlefieldScript, BATTLEFIELDHOOK_BEFORE_INVITE_PLAYER_TO_WAR, script->OnBattlefieldBeforeInvitePlayerToWar(bf, player));
}
void ScriptMgr::OnBattlefieldWarEnd(Battlefield* bf, bool endByTimer)
{
CALL_ENABLED_HOOKS(BattlefieldScript, BATTLEFIELDHOOK_ON_WAR_END, script->OnBattlefieldWarEnd(bf, endByTimer));
}
BattlefieldScript::BattlefieldScript(char const* name, std::vector<uint16> enabledHooks) :
ScriptObject(name, BATTLEFIELDHOOK_END)
{
@@ -28,6 +28,7 @@ enum BattlefieldHook
BATTLEFIELDHOOK_ON_PLAYER_JOIN_WAR, // 2 - fires after player is added to the active war
BATTLEFIELDHOOK_ON_PLAYER_LEAVE_WAR, // 3 - fires after player is removed from the active war
BATTLEFIELDHOOK_BEFORE_INVITE_PLAYER_TO_WAR, // 4 - fires in InvitePlayerToWar before InvitedPlayers insert
BATTLEFIELDHOOK_ON_WAR_END, // 5 - fires in EndBattle after OnBattleEnd(), before timer reset
BATTLEFIELDHOOK_END
};
@@ -87,6 +88,17 @@ public:
* @param player The player being invited to war
*/
virtual void OnBattlefieldBeforeInvitePlayerToWar(Battlefield* /*bf*/, Player* /*player*/) { }
/**
* @brief Called in EndBattle() after OnBattleEnd() completes, before the timer is reset.
* All core PlayersInWar/InvitedPlayers structures have already been cleared.
* Modules that maintain their own per-war player tracking should use this hook
* to perform end-of-war cleanup (e.g. restoring cross-faction disguises).
*
* @param bf The Battlefield instance
* @param endByTimer True if the war ended by the countdown timer expiring
*/
virtual void OnBattlefieldWarEnd(Battlefield* /*bf*/, bool /*endByTimer*/) { }
};
#endif // SCRIPT_OBJECT_BATTLEFIELD_SCRIPT_H_
+1
View File
@@ -608,6 +608,7 @@ public: /* BattlefieldScript */
void OnBattlefieldPlayerJoinWar(Battlefield* bf, Player* player);
void OnBattlefieldPlayerLeaveWar(Battlefield* bf, Player* player);
void OnBattlefieldBeforeInvitePlayerToWar(Battlefield* bf, Player* player);
void OnBattlefieldWarEnd(Battlefield* bf, bool endByTimer);
public: /* BGScript */
void OnBattlegroundStart(Battleground* bg);
+4
View File
@@ -1532,7 +1532,11 @@ void Spell::EffectHeal(SpellEffIndex effIndex)
int32 tickheal = targetAura->GetAmount();
if (Unit* auraCaster = targetAura->GetCaster())
{
// MOD_HEALING_DONE_PERCENT is applied per-tick, not baked into GetAmount.
tickheal = int32(float(tickheal) * auraCaster->GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT));
tickheal = unitTarget->SpellHealingBonusTaken(auraCaster, targetAura->GetSpellInfo(), tickheal, DOT);
}
//int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1;
//It is said that talent bonus should not be included
-5
View File
@@ -204,11 +204,6 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD, "AllowTwoSide.Interaction.Guild", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA, "AllowTwoSide.Interaction.Arena", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION, "AllowTwoSide.Interaction.Auction", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL, "AllowTwoSide.Interaction.Mail", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_WHO_LIST, "AllowTwoSide.WhoList", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND, "AllowTwoSide.AddFriend", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_TRADE, "AllowTwoSide.Trade", false);
SetConfigValue<bool>(CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE, "AllowTwoSide.Interaction.Emote", false);
SetConfigValue<uint32>(CONFIG_MIN_PLAYER_NAME, "MinPlayerName", 2, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value > 0 && value <= MAX_PLAYER_NAME; }, "> 0 && <= MAX_PLAYER_NAME");
SetConfigValue<uint32>(CONFIG_MIN_CHARTER_NAME, "MinCharterName", 2, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value > 0 && value <= MAX_CHARTER_NAME; }, "> 0 && <= MAX_CHARTER_NAME");
-5
View File
@@ -35,10 +35,6 @@ enum ServerConfigs
CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD,
CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA,
CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION,
CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL,
CONFIG_ALLOW_TWO_SIDE_WHO_LIST,
CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND,
CONFIG_ALLOW_TWO_SIDE_TRADE,
CONFIG_ALL_TAXI_PATHS,
CONFIG_INSTANCE_IGNORE_LEVEL,
CONFIG_INSTANCE_IGNORE_RAID,
@@ -119,7 +115,6 @@ enum ServerConfigs
CONFIG_CLOSE_IDLE_CONNECTIONS,
CONFIG_LFG_LOCATION_ALL,
CONFIG_PRELOAD_ALL_NON_INSTANCED_MAP_GRIDS,
CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE,
CONFIG_ITEMDELETE_METHOD,
CONFIG_ITEMDELETE_VENDOR,
CONFIG_DEBUG_BATTLEGROUND,
+3 -1
View File
@@ -74,8 +74,10 @@ public:
static RBACCommandData GetRBACData(uint32 accountId, std::string const& accountName)
{
// session->GetRBACData() can be null after World::ReloadRBAC()
if (WorldSession* session = sWorldSessionMgr->FindSession(accountId))
return { session->GetRBACData(), false };
if (rbac::RBACData* sessionRbac = session->GetRBACData())
return { sessionRbac, false };
rbac::RBACData* rbac = new rbac::RBACData(accountId, accountName, realm.Id.Realm, AccountMgr::GetSecurity(accountId, realm.Id.Realm));
rbac->LoadFromDB();
@@ -60,6 +60,7 @@ public:
case 5:
_owner.SetFacingTo(2.82f);
_owner.SetStandState(UNIT_STAND_STATE_KNEEL);
_owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, 6), 3s);
break;
case 6:
if (InstanceScript* inst = _owner.GetInstanceScript())
@@ -709,11 +709,10 @@ struct boss_malygos : public BossAI
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_MALYGOS, 1);
}
void KilledUnit(Unit* victim) override
@@ -3774,7 +3774,6 @@ private:
29435 - Capture Female Kaliri Hatchling
42268 - Quest - Mindless Abomination Explosion FX Master
51592 - Pickup Primordial Hatchling
51910 - Kickin' Nass: Quest Completion
52267 - Despawn Horse
54420 - Deliver Gryphon */
class spell_gen_despawn_self : public SpellScript
@@ -70,14 +70,14 @@ Player* NPCStaveQuestAI::GetGossipPlayer()
return ObjectAccessor::GetPlayer(*me, gossipPlayerGUID);
}
bool NPCStaveQuestAI::IsAllowedEntry(uint32 entry)
bool NPCStaveQuestAI::IsAllowedEntry(uint32 entry) const
{
uint32 allowedEntries[4] = { 0, 12999, 19833, 19921 }; //player, World Invisible Trigger(traps) and snake trap snakes
bool isAllowed = std::find(std::begin(allowedEntries), std::end(allowedEntries), entry) != std::end(allowedEntries);
return isAllowed;
}
bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit)
bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit) const
{
if (!unit || playerGUID.IsEmpty())
{
@@ -108,7 +108,7 @@ bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit)
return false;
}
bool NPCStaveQuestAI::IsFairFight()
bool NPCStaveQuestAI::IsFairFight() const
{
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
@@ -128,12 +128,10 @@ bool NPCStaveQuestAI::IsFairFight()
return true;
}
bool NPCStaveQuestAI::ValidThreatlist()
bool NPCStaveQuestAI::ValidThreatlist() const
{
if (me->GetThreatMgr().GetThreatListSize() == 1)
{
return true;
}
bool isFair = IsFairFight();
@@ -463,10 +461,10 @@ public:
struct npc_preciousAI : public NPCStaveQuestAI
{
npc_preciousAI(Creature *creature) : NPCStaveQuestAI(creature) { }
explicit npc_preciousAI(Creature *creature) : NPCStaveQuestAI(creature) { }
EventMap events;
bool flaggedForDespawn;
bool flaggedForDespawn{};
void InitializeAI() override
{
@@ -512,6 +510,37 @@ public:
{
flaggedForDespawn = true;
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_SIMONE_VALID_THREATLIST)
return ValidThreatlist() ? 1 : 0;
return 0;
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case DATA_SIMONE_REVEAL:
if (data)
RevealForm();
break;
case DATA_SIMONE_PREPARE_ENCOUNTER:
PrepareForEncounter();
break;
case DATA_SIMONE_SET_HOME:
SetHomePosition();
break;
case DATA_SIMONE_CORPSE_REMOVED:
EnterEvadeMode();
FlagForDespawn();
break;
default:
break;
}
}
};
};
@@ -527,7 +556,7 @@ public:
struct npc_simoneAI : public NPCStaveQuestAI
{
npc_simoneAI(Creature *creature) : NPCStaveQuestAI(creature) { }
explicit npc_simoneAI(Creature *creature) : NPCStaveQuestAI(creature) { }
EventMap events;
ObjectGuid preciousGUID;
@@ -535,39 +564,18 @@ public:
void SetPreciousGUID()
{
if (CreatureGroup* formation = me->GetFormation())
{
const CreatureGroup::CreatureGroupMemberType& members = formation->GetMembers();
for (CreatureGroup::CreatureGroupMemberType::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
if (itr->first && itr->first->GetOriginalEntry() == PRECIOUS_NORMAL_ENTRY)
{
preciousGUID = itr->first->GetGUID();
}
}
}
for ([[maybe_unused]] auto const& [member, info] : formation->GetMembers())
if (member && member->GetOriginalEntry() == PRECIOUS_NORMAL_ENTRY)
preciousGUID = member->GetGUID();
}
Creature* Precious()
{
if (preciousGUID.IsEmpty())
{
SetPreciousGUID();
}
if (!preciousGUID.IsEmpty())
{
return ObjectAccessor::GetCreature(*me, preciousGUID);
}
return nullptr;
}
npc_precious::npc_preciousAI* PreciousAI()
{
if (Precious())
{
return CAST_AI(npc_precious::npc_preciousAI, Precious()->AI());
}
return nullptr;
}
@@ -632,21 +640,20 @@ public:
void CorpseRemoved(uint32& /*respawnDelay*/) override
{
if (!Precious())
{
Creature* creature = Precious();
if (!creature)
return;
}
if (Precious()->IsInCombat())
if (creature->IsInCombat())
{
// If Simone corpse is removed but pet is InCombat, EnterEvadeMode and auto despawn on pet reaching home
PreciousAI()->EnterEvadeMode();
PreciousAI()->FlagForDespawn();
// If Simone corpse is removed but pet is InCombat, ask pet AI to enter evade and flag for despawn
if (creature->AI())
creature->AI()->SetData(DATA_SIMONE_CORPSE_REMOVED, 1);
else
creature->DespawnOrUnsummon(0ms);
}
else
{
Precious()->DespawnOrUnsummon(0ms);
}
creature->DespawnOrUnsummon(0ms);
}
void Reset() override
@@ -704,10 +711,9 @@ public:
break;
case EVENT_REVEAL:
RevealForm();
if (PreciousAI())
{
PreciousAI()->RevealForm();
}
if (Creature* creature = Precious())
if (creature->AI())
creature->AI()->SetData(DATA_SIMONE_REVEAL, 1);
break;
// Prevent hunters from figthing Simone alone
case SIMONE_EVENT_CHECK_PET_STATE:
@@ -721,6 +727,8 @@ public:
events.ScheduleEvent(SIMONE_EVENT_CHECK_PET_STATE, 1s);
}
break;
default:
break;
}
if (UpdateVictim())
@@ -760,23 +768,32 @@ public:
}
break;
case EVENT_UNFAIR_FIGHT:
if (!ValidThreatlist() || (PreciousAI() && !PreciousAI()->ValidThreatlist()))
{
Creature* creature = Precious();
bool isPreciousThreatListValid = creature && creature->AI() && creature->AI()->GetData(DATA_SIMONE_VALID_THREATLIST) == 1;
if (!ValidThreatlist() || !isPreciousThreatListValid)
{
SetHomePosition();
PreciousAI()->SetHomePosition();
Precious()->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
Precious()->SetImmuneToAll(true);
me->DespawnOrUnsummon(5s);
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
me->SetImmuneToAll(true);
Precious()->DespawnOrUnsummon(5s);
if (creature)
{
if (creature->AI())
creature->AI()->SetData(DATA_SIMONE_SET_HOME, 1);
creature->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1);
creature->SetImmuneToAll(true);
creature->DespawnOrUnsummon(5s);
}
me->DespawnOrUnsummon(5s);
break;
}
events.Repeat(2s);
break;
}
case SIMONE_EVENT_CHAIN_LIGHTNING:
me->CastSpell(me->GetVictim(), SIMONE_SPELL_CHAIN_LIGHTNING, false);
events.Repeat(7s);
@@ -785,6 +802,8 @@ public:
me->CastSpell(me->GetVictim(), SIMONE_SPELL_TEMPTRESS_KISS, false);
events.Repeat(45s);
break;
default:
break;
}
DoMeleeAttackIfReady();
@@ -805,10 +824,10 @@ public:
void ScheduleEncounterStart(ObjectGuid playerGUID)
{
PrepareForEncounter();
if (PreciousAI())
{
PreciousAI()->PrepareForEncounter();
}
if (Creature* creature = Precious())
if (creature->AI())
creature->AI()->SetData(DATA_SIMONE_PREPARE_ENCOUNTER, 1);
gossipPlayerGUID = playerGUID;
events.ScheduleEvent(EVENT_ENCOUNTER_START, 1s);
}
@@ -88,6 +88,15 @@ enum NPCPrecious
PRECIOUS_EVIL_ENTRY = 14538
};
enum SimoneAIData
{
DATA_SIMONE_REVEAL = 1,
DATA_SIMONE_PREPARE_ENCOUNTER = 2,
DATA_SIMONE_VALID_THREATLIST = 3,
DATA_SIMONE_SET_HOME = 4,
DATA_SIMONE_CORPSE_REMOVED = 5
};
enum NPCNelson
{
NELSON_EVENT_DREADFUL_FRIGHT = 6,
@@ -189,10 +198,10 @@ struct NPCStaveQuestAI : public ScriptedAI
void RevealForm();
void StorePlayerGUID();
Player* GetGossipPlayer();
bool IsAllowedEntry(uint32 /*entry*/);
bool UnitIsUnfair(Unit* unit);
bool IsFairFight();
bool ValidThreatlist();
bool IsAllowedEntry(uint32 /*entry*/) const;
bool UnitIsUnfair(Unit* unit) const;
bool IsFairFight() const;
bool ValidThreatlist() const;
void SetHomePosition();
void PrepareForEncounter();
void ClearLootIfUnfair(Unit* killer);