diff --git a/.github/workflows/core-build-nopch.yml b/.github/workflows/core-build-nopch.yml index 171159e2e..98eb1f207 100644 --- a/.github/workflows/core-build-nopch.yml +++ b/.github/workflows/core-build-nopch.yml @@ -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//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: diff --git a/.github/workflows/core-build-pch.yml b/.github/workflows/core-build-pch.yml index 05afbfe6f..ad07eaf28 100644 --- a/.github/workflows/core-build-pch.yml +++ b/.github/workflows/core-build-pch.yml @@ -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//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: diff --git a/.github/workflows/core_modules_build.yml b/.github/workflows/core_modules_build.yml index 26528dcb7..3d1943344 100644 --- a/.github/workflows/core_modules_build.yml +++ b/.github/workflows/core_modules_build.yml @@ -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//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: diff --git a/.github/workflows/dashboard-ci.yml b/.github/workflows/dashboard-ci.yml index 9e92a909f..9bd89eced 100644 --- a/.github/workflows/dashboard-ci.yml +++ b/.github/workflows/dashboard-ci.yml @@ -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//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: diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index c3151e067..d6d2f2905 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -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//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: diff --git a/.github/workflows/tools_build.yml b/.github/workflows/tools_build.yml index 8d1906297..d414f233d 100644 --- a/.github/workflows/tools_build.yml +++ b/.github/workflows/tools_build.yml @@ -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//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: diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml index eb3b5999b..d5d095511 100644 --- a/.github/workflows/windows_build.yml +++ b/.github/workflows/windows_build.yml @@ -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//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: diff --git a/data/sql/updates/db_world/2026_01_06_01.sql b/data/sql/updates/db_world/2026_01_06_01.sql new file mode 100644 index 000000000..831089228 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_06_01.sql @@ -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; diff --git a/data/sql/updates/db_world/2026_01_07_00.sql b/data/sql/updates/db_world/2026_01_07_00.sql new file mode 100644 index 000000000..77edcee37 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_07_00.sql @@ -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)'); diff --git a/data/sql/updates/db_world/2026_01_07_01.sql b/data/sql/updates/db_world/2026_01_07_01.sql new file mode 100644 index 000000000..8b9779324 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_07_01.sql @@ -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); diff --git a/data/sql/updates/db_world/2026_01_07_02.sql b/data/sql/updates/db_world/2026_01_07_02.sql new file mode 100644 index 000000000..ae72a8eb7 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_07_02.sql @@ -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.'); diff --git a/data/sql/updates/db_world/2026_01_08_00.sql b/data/sql/updates/db_world/2026_01_08_00.sql new file mode 100644 index 000000000..3d44d30d4 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_08_00.sql @@ -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'); diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index c53867e29..e333a4ba7 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -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& 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; diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index 28378270f..dca51af79 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -729,14 +729,6 @@ struct ItemTemplate return (Stackable == 2147483647 || Stackable <= 0) ? uint32(0x7FFFFFFF - 1) : uint32(Stackable); } - void GetOnEquipSpellIDs(std::vector& 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) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 17268ca43..80e352217 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -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; diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index 96910f4eb..ba8c92576 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -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 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) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 9168e8dd2..c1249c925 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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) } } diff --git a/src/server/game/Events/HolidayDateCalculator.cpp b/src/server/game/Events/HolidayDateCalculator.cpp index 8bb7f39e8..4789d7063 100644 --- a/src/server/game/Events/HolidayDateCalculator.cpp +++ b/src/server/game/Events/HolidayDateCalculator.cpp @@ -49,8 +49,8 @@ static const std::vector 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(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 }, diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 3df8d365a..6433450a4 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -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); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index eff2249da..c64a75b49 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -105,11 +105,22 @@ bool ChaseMovementGenerator::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(); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index 0e352c459..cd8c36c9e 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -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()) diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 06cbe9225..9afba1804 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -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: diff --git a/src/test/server/game/Events/HolidayDateCalculatorTest.cpp b/src/test/server/game/Events/HolidayDateCalculatorTest.cpp index d6d907e8a..2b0cd9e54 100644 --- a/src/test/server/game/Events/HolidayDateCalculatorTest.cpp +++ b/src/test/server/game/Events/HolidayDateCalculatorTest.cpp @@ -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(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 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(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) } }