Merge pull request #140 from azerothcore/master

Small core update which includes some reverts from the core guys
This commit is contained in:
bashermens
2026-01-08 21:32:38 +01:00
committed by GitHub
23 changed files with 188 additions and 129 deletions

View File

@@ -272,13 +272,6 @@ public:
[[nodiscard]] uint32 GetCount() const { return GetUInt32Value(ITEM_FIELD_STACK_COUNT); }
void SetCount(uint32 value) { SetUInt32Value(ITEM_FIELD_STACK_COUNT, value); }
[[nodiscard]] uint32 GetMaxStackCount() const { return GetTemplate()->GetMaxStackSize(); }
void GetOnEquipSpellIDs(std::vector<uint32>& spellEquipID) const
{
if (ItemTemplate const* proto = GetTemplate())
proto->GetOnEquipSpellIDs(spellEquipID);
else
spellEquipID.clear();
};
// Checks if this item has sockets, whether built-in or added by an upgrade.
[[nodiscard]] bool HasSocket() const;
[[nodiscard]] uint8 GetGemCountWithID(uint32 GemID) const;

View File

@@ -729,14 +729,6 @@ struct ItemTemplate
return (Stackable == 2147483647 || Stackable <= 0) ? uint32(0x7FFFFFFF - 1) : uint32(Stackable);
}
void GetOnEquipSpellIDs(std::vector<uint32>& spellEquipID) const
{
spellEquipID.clear();
for (auto const& spell : Spells)
if (spell.SpellId && spell.SpellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP)
spellEquipID.push_back(spell.SpellId);
}
[[nodiscard]] float getDPS() const
{
if (Delay == 0)

View File

@@ -9086,13 +9086,6 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
if (pet)
{
// xinef: dont save dead pet as current, save him not in slot
if (!pet->IsAlive() && mode == PET_SAVE_AS_CURRENT && pet->getPetType() == HUNTER_PET)
{
mode = PET_SAVE_NOT_IN_SLOT;
m_temporaryUnsummonedPetNumber = 0;
}
LOG_DEBUG("entities.pet", "RemovePet {}, {}, {}", pet->GetEntry(), mode, returnreagent);
if (pet->m_removed)
return;

View File

@@ -319,23 +319,6 @@ void Player::Update(uint32 p_time)
{
m_regenTimer += p_time;
RegenerateAll();
// Apply buffs from items with Apply on Equip trigger if they are not present.
for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
{
if (!m_items[i])
continue;
std::vector<uint32> spellIDs;
m_items[i]->GetOnEquipSpellIDs(spellIDs);
bool apply = false;
for (uint32 spellID : spellIDs)
if (!apply && !HasAura(spellID))
apply = true;
if (apply)
ApplyItemEquipSpell(m_items[i], true, false);
}
}
if (m_deathState == DeathState::JustDied)

View File

@@ -14717,7 +14717,7 @@ void Unit::setDeathState(DeathState s, bool despawn)
}
else if (s == DeathState::JustRespawned)
{
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
}
}

View File

@@ -49,8 +49,8 @@ static const std::vector<HolidayRule> HolidayRules = {
// Pirates' Day: Fixed Sep 19
{ HOLIDAY_PIRATES_DAY, HolidayCalculationType::FIXED_DATE, 9, 19, 0, 0 },
// Brewfest: Oktoberfest rule - first Saturday on/after Sept 15, minus 7 for holidayStage offset
{ HOLIDAY_BREWFEST, HolidayCalculationType::WEEKDAY_ON_OR_AFTER, 9, 15, static_cast<int>(Weekday::SATURDAY), -7 },
// Brewfest: Fixed Sept 20 main event, prep starts Sept 13
{ HOLIDAY_BREWFEST, HolidayCalculationType::FIXED_DATE, 9, 13, 0, 0 },
// Harvest Festival: 2 days before autumn equinox (Sept 20-21)
{ HOLIDAY_HARVEST_FESTIVAL, HolidayCalculationType::AUTUMN_EQUINOX, 0, 0, 0, -2 },

View File

@@ -235,17 +235,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
if (pet->GetVictim() == TargetUnit && pet->GetCharmInfo()->IsCommandAttack())
return;
// Check line of sight either from pet or owner depending if pet is charmed
Unit* seer = pet;
if (Unit* owner = pet->GetOwner())
if (owner->IsPlayer() && owner->ToPlayer()->GetCharm() != pet && owner->ToPlayer()->GetVehicleBase() != pet)
if (sDisableMgr->IsPathfindingEnabled(pet->GetMap()))
seer = owner;
// Fail on LoS
if (seer && !seer->IsWithinLOSInMap(TargetUnit, VMAP::ModelIgnoreFlags::M2))
return;
pet->ClearUnitState(UNIT_STATE_FOLLOW);
// This is true if pet has no target or has target but targets differs.
if (pet->GetVictim() != TargetUnit || (pet->GetVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
@@ -429,8 +418,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
// This is true if pet has no target or has target but targets differs.
if (pet->GetVictim() != unit_target)
{
if (pet->ToCreature()->IsAIEnabled && pet->IsWithinLOSInMap(unit_target, VMAP::ModelIgnoreFlags::M2))
pet->ToCreature()->AI()->AttackStart(unit_target);
pet->ToCreature()->AI()->AttackStart(unit_target);
}
}
@@ -511,8 +499,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsReturning(false);
if (pet->IsWithinLOSInMap(TargetUnit, VMAP::ModelIgnoreFlags::M2))
pet->ToCreature()->AI()->AttackStart(TargetUnit);
pet->ToCreature()->AI()->AttackStart(TargetUnit);
if (pet->IsPet() && pet->ToPet()->getPetType() == SUMMON_PET && pet != TargetUnit && roll_chance_i(10))
pet->SendPetActionSound(PET_ACTION_SPECIAL_SPELL);

View File

@@ -105,11 +105,22 @@ bool ChaseMovementGenerator<T>::DispatchSplineToPosition(T* owner, float x, floa
owner->UpdateAllowedPositionZ(x, y, z);
bool success = i_path->CalculatePath(x, y, z, forceDest);
if (!success || i_path->GetPathType() & PATHFIND_NOPATH)
uint32 pathType = i_path->GetPathType();
bool pathFailed = !success || (pathType & PATHFIND_NOPATH);
// For pets, treat incomplete paths as failures to avoid clipping through geometry
if (cOwner && (cOwner->IsPet() || cOwner->IsControlledByPlayer()))
if (pathType & PATHFIND_INCOMPLETE)
pathFailed = true;
if (pathFailed)
{
if (cOwner)
{
cOwner->SetCannotReachTarget(i_target.getTarget()->GetGUID());
if (cOwner->IsPet() || cOwner->IsControlledByPlayer())
cOwner->AttackStop();
}
owner->StopMoving();

View File

@@ -110,7 +110,7 @@ enum Yells
struct boss_bjarngrim : public npc_escortAI
{
boss_bjarngrim(Creature* creature) : npc_escortAI(creature), summons(creature)
boss_bjarngrim(Creature* creature) : npc_escortAI(creature), summons(creature), m_uiStance(STANCE_BATTLE)
{
m_pInstance = creature->GetInstanceScript();
InitializeWaypoints();
@@ -301,18 +301,19 @@ struct boss_bjarngrim : public npc_escortAI
{
events.Update(diff);
if (uint32 eventId = events.ExecuteEvent())
{
if (eventId == EVENT_CHARGE_UP)
{
me->CastSpell(me, SPELL_CHARGE_UP, true);
me->CastSpell(me, SPELL_TEMPORARY_ELECTRICAL_CHARGE, true);
return;
}
}
if (!me->IsInCombat())
{
// Handle charge-up only when out of combat
if (uint32 eventId = events.ExecuteEvent())
{
if (eventId == EVENT_CHARGE_UP)
{
DoCastSelf(SPELL_CHARGE_UP, true);
DoCastSelf(SPELL_TEMPORARY_ELECTRICAL_CHARGE, true);
}
}
return;
}
// Return since we have no target
if (!UpdateVictim())

View File

@@ -681,23 +681,28 @@ public:
struct npc_tirions_gambit_tirionAI : npc_escortAI
{
npc_tirions_gambit_tirionAI(Creature* creature) : npc_escortAI(creature), summons(me)
npc_tirions_gambit_tirionAI(Creature* creature) : npc_escortAI(creature), summons(me), _eventOver(false)
{
}
EventMap events;
SummonList summons;
bool _eventOver;
void Reset() override
{
me->setActive(false);
me->SetStandState(UNIT_STAND_STATE_STAND);
_eventOver = false;
}
void SetData(uint32 type, uint32 data) override
{
if (type == 1 && data == 1)
if (type == 1 && data == 1 && !_eventOver)
{
events.ScheduleEvent(EVENT_SCENE_0 + 30, 10s);
_eventOver = true;
}
}
void DoAction(int32 param) override
@@ -747,7 +752,7 @@ public:
switch (pointId)
{
case 6:
me->SummonCreature(NPC_INVOKER_BASALEPH, 6130.26f, 2764.83f, 573.92f, 5.19f, TEMPSUMMON_TIMED_DESPAWN, 10 * MINUTE * IN_MILLISECONDS);
me->SummonCreature(NPC_INVOKER_BASALEPH, 6130.26f, 2764.83f, 573.92f, 5.19f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
Talk(1);
break;
case 15:
@@ -812,9 +817,9 @@ public:
Talk(2);
DoSummonAction(NPC_DISGUISED_CRUSADER, ACTION_SUMMON_ORIENTATION, 200);
me->SummonCreature(NPC_CHOSEN_ZEALOT, 6160.74f, 2695.90f, 573.92f, 2.04f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS);
me->SummonCreature(NPC_CHOSEN_ZEALOT, 6164.98f, 2697.90f, 573.92f, 2.04f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS);
me->SummonCreature(NPC_CHOSEN_ZEALOT, 6161.26f, 2700.05f, 573.92f, 2.04f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS);
me->SummonCreature(NPC_CHOSEN_ZEALOT, 6160.74f, 2695.90f, 573.92f, 2.04f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
me->SummonCreature(NPC_CHOSEN_ZEALOT, 6164.98f, 2697.90f, 573.92f, 2.04f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
me->SummonCreature(NPC_CHOSEN_ZEALOT, 6161.26f, 2700.05f, 573.92f, 2.04f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
DoSummonAction(NPC_CHOSEN_ZEALOT, ACTION_SUMMON_MOVE_STRAIGHT, 27);
events.ScheduleEvent(EVENT_SCENE_0, 30s);
@@ -835,7 +840,7 @@ public:
break;
case EVENT_SCENE_0+3:
Talk(3);
if (Creature* cr = me->SummonCreature(NPC_TIRION_LICH_KING, 6161.26f, 2700.05f, 573.92f, 2.04f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS))
if (Creature* cr = me->SummonCreature(NPC_TIRION_LICH_KING, 6161.26f, 2700.05f, 573.92f, 2.04f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000))
cr->GetMotionMaster()->MovePoint(2, 6131.93f, 2756.84f, 573.92f);
events.ScheduleEvent(EVENT_SCENE_0 + 4, 4s);
break;
@@ -976,7 +981,6 @@ public:
if (target)
(*itr)->AI()->AttackStart(target);
}
break;
}
case EVENT_SCENE_0+30:

View File

@@ -397,60 +397,45 @@ TEST_F(HolidayDateCalculatorTest, FixedDateHolidays_ConsistentAcrossYears_1900_2
}
// ============================================================
// Brewfest Tests (Oktoberfest rule)
// First Saturday on or after Sept 15, minus 7 days for holidayStage offset
// Brewfest Tests (Fixed Sept 20 main event)
// ============================================================
TEST_F(HolidayDateCalculatorTest, Brewfest_OktoberfestRule)
TEST_F(HolidayDateCalculatorTest, Brewfest_FixedSept13)
{
// Brewfest follows the Oktoberfest rule:
// Oktoberfest starts the Saturday after Sept 15 (or on Sept 15 if it's Saturday)
// Brewfest holidayStage 1 starts 7 days before that
HolidayRule brewfest = { 372, HolidayCalculationType::WEEKDAY_ON_OR_AFTER, 9, 15, static_cast<int>(Weekday::SATURDAY), -7 };
// Brewfest is now fixed: prep starts Sept 13, main event Sept 20
// This avoids any potential overlap with Pirates' Day (Sept 19)
HolidayRule brewfest = { 372, HolidayCalculationType::FIXED_DATE, 9, 13, 0, 0 };
struct BrewfestTestCase { int year; int expectedMonth; int expectedDay; };
std::vector<BrewfestTestCase> testCases = {
// Sept 15, 2024 is Sunday, first Sat after is Sept 21, minus 7 = Sept 14
{ 2024, 9, 14 },
// Sept 15, 2025 is Monday, first Sat after is Sept 20, minus 7 = Sept 13
{ 2025, 9, 13 },
// Sept 15, 2026 is Tuesday, first Sat after is Sept 19, minus 7 = Sept 12
{ 2026, 9, 12 },
// Sept 15, 2027 is Wednesday, first Sat after is Sept 18, minus 7 = Sept 11
{ 2027, 9, 11 },
// Sept 15, 2028 is Friday, first Sat after is Sept 16, minus 7 = Sept 9
{ 2028, 9, 9 },
// Sept 15, 2029 is Saturday, so Sept 15, minus 7 = Sept 8
{ 2029, 9, 8 },
};
for (auto const& tc : testCases)
{
std::tm date = HolidayDateCalculator::CalculateHolidayDate(brewfest, tc.year);
SCOPED_TRACE("Year: " + std::to_string(tc.year));
EXPECT_EQ(date.tm_year + 1900, tc.year);
EXPECT_EQ(date.tm_mon + 1, tc.expectedMonth);
EXPECT_EQ(date.tm_mday, tc.expectedDay);
}
}
TEST_F(HolidayDateCalculatorTest, Brewfest_AlwaysInSeptember_1900_2200)
{
HolidayRule brewfest = { 372, HolidayCalculationType::WEEKDAY_ON_OR_AFTER, 9, 15, static_cast<int>(Weekday::SATURDAY), -7 };
for (int year = 1900; year <= 2200; ++year)
for (int year = 2000; year <= 2030; ++year)
{
std::tm date = HolidayDateCalculator::CalculateHolidayDate(brewfest, year);
SCOPED_TRACE("Year: " + std::to_string(year));
// Brewfest should always be in September (after -7 offset from Sept 15-21)
EXPECT_EQ(date.tm_mon + 1, 9) << "Brewfest should be in September";
// Should be between Sept 8 and Sept 14 (7 days before Sept 15-21)
EXPECT_GE(date.tm_mday, 8) << "Brewfest should be >= Sept 8";
EXPECT_LE(date.tm_mday, 14) << "Brewfest should be <= Sept 14";
EXPECT_EQ(date.tm_year + 1900, year);
EXPECT_EQ(date.tm_mon + 1, 9); // September
EXPECT_EQ(date.tm_mday, 13); // Always Sept 13
}
}
TEST_F(HolidayDateCalculatorTest, Brewfest_NoPiratesDayConflict)
{
// Brewfest main event (Sept 20) is always after Pirates' Day (Sept 19)
HolidayRule brewfest = { 372, HolidayCalculationType::FIXED_DATE, 9, 13, 0, 0 };
HolidayRule piratesDay = { 398, HolidayCalculationType::FIXED_DATE, 9, 19, 0, 0 };
for (int year = 2000; year <= 2030; ++year)
{
std::tm brewfestDate = HolidayDateCalculator::CalculateHolidayDate(brewfest, year);
std::tm piratesDate = HolidayDateCalculator::CalculateHolidayDate(piratesDay, year);
SCOPED_TRACE("Year: " + std::to_string(year));
// Brewfest prep is Sept 13, main event is Sept 20
// Pirates' Day is Sept 19, which falls between prep and main event
EXPECT_EQ(brewfestDate.tm_mday, 13); // Brewfest prep
EXPECT_EQ(piratesDate.tm_mday, 19); // Pirates' Day
// Main event (Sept 20) > Pirates' Day (Sept 19)
}
}