mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-19 03:45:43 +00:00
Merge pull request #140 from azerothcore/master
Small core update which includes some reverts from the core guys
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user