Skip to content

Commit c574c0d

Browse files
Merge AzerothCore 3.3.5 to ElunaAzerothcore [skip ci]
2 parents b15d765 + e675151 commit c574c0d

5 files changed

Lines changed: 80 additions & 33 deletions

File tree

src/server/game/Entities/Player/PlayerStorage.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6231,6 +6231,32 @@ Item* Player::_LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint
62316231
return nullptr;
62326232
}
62336233

6234+
// Rehydrate looters for BoP-tradeable mail items; only the LFG mail path writes this flag, gated on the same config.
6235+
if (item->IsBOPTradable() && sWorld->getBoolConfig(CONFIG_SET_BOP_ITEM_TRADEABLE))
6236+
{
6237+
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_BOP_TRADE);
6238+
stmt->SetData(0, item->GetGUID().GetCounter());
6239+
6240+
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
6241+
{
6242+
AllowedLooterSet looters;
6243+
for (std::string_view guidStr : Acore::Tokenize((*result)[0].Get<std::string_view>(), ' ', false))
6244+
{
6245+
if (Optional<ObjectGuid::LowType> guid = Acore::StringTo<ObjectGuid::LowType>(guidStr))
6246+
looters.insert(ObjectGuid::Create<HighGuid::Player>(*guid));
6247+
else
6248+
LOG_WARN("entities.player.loading", "Player::_LoadMailedItem: invalid item_soulbound_trade_data GUID '{}' for item {}. Skipped.", guidStr, item->GetGUID().ToString());
6249+
}
6250+
6251+
if (looters.size() > 1 && proto->GetMaxStackSize() == 1 && item->IsSoulBound())
6252+
item->SetSoulboundTradeable(looters);
6253+
else
6254+
item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE);
6255+
}
6256+
else
6257+
item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE);
6258+
}
6259+
62346260
if (mail)
62356261
{
62366262
mail->AddItem(itemGuid, itemEntry);

src/server/game/Entities/Unit/Unit.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15321,30 +15321,10 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
1532115321

1532215322
if (!sScriptMgr->CanSetPhaseMask(this, newPhaseMask, update))
1532315323
return;
15324-
15325-
// Phase-related threat updates are done AFTER the phase change below
1532615324
}
1532715325

1532815326
WorldObject::SetPhaseMask(newPhaseMask, false);
1532915327

15330-
// Now update threat online states with the new phase mask applied
15331-
if (IsCreature() || (IsPlayer() && !ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout()))
15332-
{
15333-
// Update online state for units that have me on their threat list
15334-
for (auto const& pair : GetThreatMgr().GetThreatenedByMeList())
15335-
{
15336-
if (ThreatReference* ref = pair.second)
15337-
ref->UpdateOffline();
15338-
}
15339-
15340-
// Update online state for units on my threat list
15341-
if (!IsPlayer())
15342-
{
15343-
for (ThreatReference* ref : GetThreatMgr().GetModifiableThreatList())
15344-
ref->UpdateOffline();
15345-
}
15346-
}
15347-
1534815328
if (!IsInWorld())
1534915329
{
1535015330
return;

src/server/game/Groups/Group.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,40 @@ Loot* Roll::getLoot()
6666
return getTarget();
6767
}
6868

69+
static void SendRollWonItemViaMail(Player* player, LootItem const* lootItem, uint32 itemId)
70+
{
71+
Item* mailItem = Item::CreateItem(itemId, lootItem->count, player, false, lootItem->randomPropertyId);
72+
if (!mailItem)
73+
return;
74+
75+
AllowedLooterSet looters = lootItem->GetAllowedLooters();
76+
ItemTemplate const* proto = mailItem->GetTemplate();
77+
// Preserve the 2-hour group trade window the item would have had if stored directly.
78+
if (looters.size() > 1 && proto->GetMaxStackSize() == 1 &&
79+
(proto->Bonding == BIND_WHEN_PICKED_UP || proto->Bonding == BIND_QUEST_ITEM) &&
80+
sWorld->getBoolConfig(CONFIG_SET_BOP_ITEM_TRADEABLE))
81+
{
82+
mailItem->SetBinding(true);
83+
mailItem->SetSoulboundTradeable(looters);
84+
mailItem->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, player->GetTotalPlayedTime());
85+
86+
std::string lootersStr;
87+
for (ObjectGuid const& guid : looters)
88+
{
89+
if (!lootersStr.empty())
90+
lootersStr += ' ';
91+
lootersStr += std::to_string(guid.GetCounter());
92+
}
93+
94+
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_BOP_TRADE);
95+
stmt->SetData(0, mailItem->GetGUID().GetCounter());
96+
stmt->SetData(1, lootersStr);
97+
CharacterDatabase.Execute(stmt);
98+
}
99+
100+
player->SendItemRetrievalMail(mailItem);
101+
}
102+
69103
Group::Group() : m_leaderName(""), m_groupType(GROUPTYPE_NORMAL),
70104
m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL),
71105
m_bfGroup(nullptr), m_bgGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON),
@@ -1505,8 +1539,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
15051539
roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
15061540
roll->getLoot()->unlootedCount--;
15071541
player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
1508-
if (Item* mailItem = Item::CreateItem(roll->itemid, item->count, player, false, item->randomPropertyId))
1509-
player->SendItemRetrievalMail(mailItem);
1542+
SendRollWonItemViaMail(player, item, roll->itemid);
15101543
}
15111544
else
15121545
{
@@ -1588,8 +1621,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
15881621
roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
15891622
roll->getLoot()->unlootedCount--;
15901623
player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
1591-
if (Item* mailItem = Item::CreateItem(roll->itemid, item->count, player, false, item->randomPropertyId))
1592-
player->SendItemRetrievalMail(mailItem);
1624+
SendRollWonItemViaMail(player, item, roll->itemid);
15931625
}
15941626
else
15951627
{

src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,16 +217,21 @@ struct boss_lord_marrowgar : public BossAI
217217
break;
218218
}
219219
events.Repeat(5s);
220-
Unit* unit = SelectTarget(SelectTargetMethod::Random, 0, BoneStormMoveTargetSelector(me));
221-
if (!unit)
220+
std::list<Unit*> targets;
221+
SelectTargetList(targets, Is25ManRaid() ? 2 : 1, SelectTargetMethod::MaxDistance, 0, BoneStormMoveTargetSelector(me));
222+
223+
Unit* unit = nullptr;
224+
if (!targets.empty())
225+
unit = targets.size() == 1 ? targets.front() : Acore::Containers::SelectRandomContainerElement(targets);
226+
else if ((unit = SelectTarget(SelectTargetMethod::MaxThreat, 0, 175.0f, true)))
222227
{
223-
if ((unit = SelectTarget(SelectTargetMethod::MaxThreat, 0, 175.0f, true)))
224-
if (unit->GetPositionX() > -337.0f)
225-
{
226-
EnterEvadeMode();
227-
return;
228-
}
228+
if (unit->GetPositionX() > -337.0f)
229+
{
230+
EnterEvadeMode();
231+
return;
232+
}
229233
}
234+
230235
if (unit)
231236
me->GetMotionMaster()->MoveCharge(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), 25.0f, 1337);
232237
break;

src/test/server/game/Combat/ThreatManagerTest.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ TEST_F(ThreatManagerIntegrationTest,
734734
}
735735

736736
// ============================================================================
737-
// Phase Change + Threat Offline State Tests (SetPhaseMask order fix)
737+
// Phase Change + Threat Offline State Tests
738738
// ============================================================================
739739

740740
TEST_F(ThreatManagerIntegrationTest,
@@ -748,6 +748,10 @@ TEST_F(ThreatManagerIntegrationTest,
748748
// Move B to a different phase
749749
_creatureB->SetPhase(2);
750750

751+
// Online state is refreshed lazily on the next threat update tick (matches
752+
// TrinityCore - SetPhaseMask itself does not touch threat)
753+
_creatureA->TestGetThreatMgr().Update(ThreatManager::THREAT_UPDATE_INTERVAL);
754+
751755
// B should now be offline on A's threat list (different phases)
752756
// The list is not empty if we include offline, but empty if we don't
753757
EXPECT_TRUE(_creatureA->TestGetThreatMgr().IsThreatenedBy(_creatureB, true)); // includeOffline

0 commit comments

Comments
 (0)