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

@@ -10,7 +10,14 @@ on:
- synchronize
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:

View File

@@ -10,7 +10,14 @@ on:
- synchronize
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:

View File

@@ -24,7 +24,14 @@ permissions:
contents: read
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:

View File

@@ -16,7 +16,14 @@ on:
workflow_dispatch:
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:

View File

@@ -9,7 +9,14 @@ on:
- synchronize
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:

View File

@@ -9,7 +9,14 @@ on:
- synchronize
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:

View File

@@ -6,7 +6,14 @@ on:
branches: [ "Playerbot" ]
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:

View File

@@ -0,0 +1,3 @@
-- DB update 2026_01_06_00 -> 2026_01_06_01
-- Bonestripper Vulture, Castflag 0 to 32 "Only casts the spell if the target does not have an aura from the spell"
UPDATE `smart_scripts` SET `action_param2` = `action_param2` | 32 WHERE `entryorguid` = 16973 AND `source_type` = 0 AND `id` = 0;

View File

@@ -0,0 +1,37 @@
-- DB update 2026_01_06_01 -> 2026_01_07_00
--
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 30134);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(30134, 0, 0, 13, 27, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 2, 30134, 0, 0, 500, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Passenger Boarded - Start Waypoint Path 30134'),
(30134, 0, 1, 0, 28, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Passenger Removed - Despawn Instant'),
(30134, 0, 2, 0, 40, 0, 100, 512, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 2 of Path Any Reached - Say Line 0'),
(30134, 0, 3, 0, 40, 0, 100, 512, 8, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 8 of Path Any Reached - Say Line 1'),
(30134, 0, 4, 0, 40, 0, 100, 512, 16, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 16 of Path Any Reached - Say Line 2'),
(30134, 0, 5, 0, 40, 0, 100, 512, 22, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 22 of Path Any Reached - Say Line 3'),
(30134, 0, 6, 0, 40, 0, 100, 512, 37, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 37 of Path Any Reached - Say Line 4'),
(30134, 0, 7, 0, 40, 0, 100, 512, 47, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 47 of Path Any Reached - Say Line 5'),
(30134, 0, 8, 0, 40, 0, 100, 512, 53, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 53 of Path Any Reached - Say Line 6'),
(30134, 0, 9, 0, 40, 0, 100, 512, 57, 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 57 of Path Any Reached - Say Line 7'),
(30134, 0, 10, 0, 40, 0, 100, 512, 65, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 19, 30107, 5, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 65 of Path Any Reached - Say Line 8'),
(30134, 0, 11, 12, 40, 0, 100, 512, 72, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 72 of Path Any Reached - Remove Auras'),
(30134, 0, 12, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 56675, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Point 72 of Path Any Reached - Cast \'Summon Brann Bronzebeard\''),
(30134, 0, 13, 14, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 18, 16777216, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Passenger Boarded - Set Flags Player Controlled'),
(30134, 0, 14, 15, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Passenger Boarded - Stop Attacking'),
(30134, 0, 15, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 44, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Passenger Boarded - Set PhaseMask 7'),
(30134, 0, 16, 0, 60, 0, 100, 0, 3600, 3600, 3600, 3600, 0, 0, 86, 55089, 1, 19, 30136, 40, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brann\'s Flying Machine - On Update, Condition: Not Currently Boarded - Cross Cast \'Mount Brann`s Flying Machine\'');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 17) AND (`SourceEntry` = 30134) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 29) AND (`ConditionTarget` = 1) AND (`ConditionValue1` = 30136) AND (`ConditionValue2` = 5) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(22, 17, 30134, 0, 0, 29, 1, 30136, 5, 0, 1, 0, 0, '', 'Only allow boarding if there are no current boarders for quest Bronzebeard Brothers');
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 30136);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(30136, 0, 0, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormforged Soldier - On Just Died - Exit Vehicle'),
(30136, 0, 1, 0, 10, 0, 100, 0, 0, 100, 10000, 10000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormforged Soldier - Within 0-100 Range Out of Combat LoS - Start Attacking'),
(30136, 0, 2, 0, 0, 0, 25, 1, 0, 500, 0, 0, 0, 0, 11, 56621, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormforged Soldier - In Combat - Cast \'Thunder Orb\' Hit (No Repeat)'),
(30136, 0, 3, 0, 0, 0, 100, 0, 3000, 5000, 4000, 6000, 0, 0, 11, 56622, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormforged Soldier - In Combat - Cast \'Thunder Orb\' Miss');
-- DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` = 30134 AND `spell_id` IN (52391, 55089); -- Breaking Brann, I think
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 55089) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 30134) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 1, 55089, 0, 0, 31, 0, 3, 30134, 0, 0, 0, 0, '', '55089 \'Mount Brann\'s Flying Machine\' Targets Brann\'s Flying Machine (30134)');

View File

@@ -0,0 +1,3 @@
-- DB update 2026_01_07_00 -> 2026_01_07_01
--
UPDATE `quest_template_addon` SET `SpecialFlags` = `SpecialFlags`|1 WHERE (`ID` = 13845);

View File

@@ -0,0 +1,9 @@
-- DB update 2026_01_07_01 -> 2026_01_07_02
--
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 7) AND (`SourceEntry` = 54469) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 29333) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 7, 54469, 0, 0, 31, 0, 3, 29333, 0, 0, 0, 0, '', 'Only useful versus Onslaught Gryphon Rider.');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 74541) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 29333) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 1, 74541, 0, 0, 31, 0, 3, 29333, 0, 0, 0, 0, '', 'Only useful versus Onslaught Gryphon Rider.');

View File

@@ -0,0 +1,9 @@
-- DB update 2026_01_07_02 -> 2026_01_08_00
--
UPDATE `creature_summon_groups` SET `summonType` = 6, `summonTime` = 60000 WHERE `summonerId` = 32239 AND `summonerType` = 0 AND `groupId` = 1;
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 32312);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(32312, 0, 0, 0, 0, 0, 100, 0, 3000, 4000, 10000, 10000, 0, 0, 11, 58843, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Highlord Darion Mograine - In Combat - Cast \'Plague Strike\''),
(32312, 0, 1, 0, 0, 0, 100, 0, 7000, 8000, 10000, 10000, 0, 0, 11, 59011, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Highlord Darion Mograine - In Combat - Cast \'Icy Touch\''),
(32312, 0, 2, 0, 1, 0, 100, 512, 3600, 3600, 3600, 3600, 0, 0, 45, 1, 1, 0, 0, 0, 0, 19, 32239, 20, 0, 0, 0, 0, 0, 0, 'Highlord Darion Mograine - Out of Combat - Set Data 1 1');

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)
}
}