refactor(Core/Scripts): move Northrend gossip handlers to database#25275
refactor(Core/Scripts): move Northrend gossip handlers to database#25275Nyeriah wants to merge 1 commit intoazerothcore:masterfrom
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Refactors several Northrend NPC gossip interactions by removing hardcoded C++ gossip handlers and re-implementing the behavior using database-driven gossip conditions and SmartAI scripts.
Changes:
- Removed C++ gossip scripts/registrations for Iruk, Deathstalker Razael & Dark Ranger Lyana, Roxi Ramrocket, and Avatar of Freya.
- Added a world DB update to gate gossip options via
conditionsand to trigger casts/credits viasmart_scripts. - Updated
creature_templaterows to dropScriptNameusage and enableSmartAIwhere needed.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/server/scripts/Northrend/zone_storm_peaks.cpp | Removes Roxi Ramrocket C++ gossip script and registration. |
| src/server/scripts/Northrend/zone_sholazar_basin.cpp | Removes Avatar of Freya C++ gossip script and registration. |
| src/server/scripts/Northrend/zone_howling_fjord.cpp | Removes Razael/Lyana C++ gossip script and registration. |
| src/server/scripts/Northrend/zone_borean_tundra.cpp | Removes Iruk C++ gossip script and registration. |
| data/sql/updates/pending_db_world/rev_1774590000_gossip_northrend.sql | Adds DB conditions + SmartAI actions to replace removed gossip logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| -- SAI for Razael (23998): on gossip select (menu 8870, option 0) -> quest credit 23998 | ||
| DELETE FROM `smart_scripts` WHERE `entryorguid`=23998 AND `source_type`=0; | ||
| 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 | ||
| (23998, 0, 0, 0, 62, 0, 100, 512, 8870, 0, 0, 0, 0, 0, 33, 23998, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Razael - On Gossip Select - Quest Credit 23998'); | ||
|
|
There was a problem hiding this comment.
SMART_ACTION_CALL_KILLEDMONSTER (33) ultimately calls Player::RewardPlayerAndGroupAtEvent(...), which can grant objective credit to nearby group members as well (and also runs the kill-credit achievement updates). The removed C++ used Player::TalkedToCreature(...), which is per-player and does not share to the group. If you need to preserve the original behavior, this likely needs a small C++ handler (or a new SmartAI action/core hook that calls TalkedToCreature without group sharing) rather than CALL_KILLEDMONSTER.
| -- SAI for Lyana (23778): append gossip handler to existing SAI (id 0 = OOC say already exists) | ||
| DELETE FROM `smart_scripts` WHERE `entryorguid`=23778 AND `source_type`=0 AND `id`=1; | ||
| 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 | ||
| (23778, 0, 1, 0, 62, 0, 100, 512, 8879, 0, 0, 0, 0, 0, 33, 23778, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Lyana - On Gossip Select - Quest Credit 23778'); | ||
|
|
There was a problem hiding this comment.
Same as Razael: SMART_ACTION_CALL_KILLEDMONSTER (33) uses RewardPlayerAndGroupAtEvent, so this can award credit to nearby group members (and update kill-achievement criteria) unlike the previous TalkedToCreature call. If the intention is to keep the gossip credit strictly per-player, consider keeping a minimal C++ gossip select handler (or adding a SmartAI/core support action) instead of using action 33 here.
| -- Condition on vendor option: HasSpell 60866 (Mechano-Hog) OR HasSpell 60867 (Mekgineer's Chopper) | ||
| DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=10210 AND `SourceEntry`=1; | ||
| INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES | ||
| (15, 10210, 1, 0, 0, 16, 0, 60866, 0, 0, 0, 0, 0, '', 'Roxi Ramrocket - Show vendor option if player has Mechano-Hog'), | ||
| (15, 10210, 1, 0, 1, 16, 0, 60867, 0, 0, 0, 0, 0, '', 'Roxi Ramrocket - Show vendor option if player has Mekgineer''s Chopper'); |
There was a problem hiding this comment.
These conditions use ConditionTypeOrReference=16, which in AzerothCore is CONDITION_RACE (not "player has spell"). To gate the vendor option on knowing mount spells 60866/60867, use CONDITION_SPELL (25) with ConditionValue1 set to the spell ID (your ElseGroup setup for OR logic can stay the same).
| -- Condition on menu 9720 option 0: quest 12621 incomplete | ||
| DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9720 AND `SourceEntry`=0; | ||
| INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES | ||
| (15, 9720, 0, 0, 0, 9, 0, 12621, 0, 0, 0, 0, 0, '', 'Avatar of Freya - Show gossip option if quest 12621 is taken'); | ||
|
|
There was a problem hiding this comment.
Like the Iruk condition above, this uses ConditionTypeOrReference=9 (CONDITION_QUESTTAKEN), which stays true even after quest objectives are completed. The removed C++ only offered the first gossip option when quest 12621 was QUEST_STATUS_INCOMPLETE. To match that behavior, use CONDITION_QUESTSTATE (47) with mask 8 (in progress) or add a negative CONDITION_QUEST_COMPLETE (28).
| -- Condition on gossip_menu_option: show option if quest 11961 is taken | ||
| DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9280 AND `SourceEntry`=0; | ||
| INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES | ||
| (15, 9280, 0, 0, 0, 9, 0, 11961, 0, 0, 0, 0, 0, '', 'Iruk - Show option if quest 11961 is taken'); |
There was a problem hiding this comment.
The condition used here is ConditionTypeOrReference=9 (CONDITION_QUESTTAKEN), which is true as long as the quest is in the log (including when objectives are completed but not yet turned in). The removed C++ checked QUEST_STATUS_INCOMPLETE, so the option should disappear once the quest is complete. To match the previous behavior, use CONDITION_QUESTSTATE (47) with state mask 8 (in progress), or combine CONDITION_QUESTTAKEN with a negative CONDITION_QUEST_COMPLETE (28).
| -- Condition on menu 8870 option 0: quest 11221 incomplete | ||
| DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8870 AND `SourceEntry`=0; | ||
| INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES | ||
| (15, 8870, 0, 0, 0, 9, 0, 11221, 0, 0, 0, 0, 0, '', 'Razael - Show gossip option if quest 11221 is taken'); | ||
|
|
||
| -- Condition on menu 8879 option 0: quest 11221 incomplete | ||
| DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8879 AND `SourceEntry`=0; | ||
| INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES | ||
| (15, 8879, 0, 0, 0, 9, 0, 11221, 0, 0, 0, 0, 0, '', 'Lyana - Show gossip option if quest 11221 is taken'); |
There was a problem hiding this comment.
These new conditions are documented as "quest 11221 incomplete", but they use ConditionTypeOrReference=9 (CONDITION_QUESTTAKEN). That will also allow the gossip options after the quest is completed (but before turn-in). If the intent is truly "incomplete" like the removed C++ logic, switch to CONDITION_QUESTSTATE (47) with state mask 8 (in progress) or add a negative CONDITION_QUEST_COMPLETE (28).
Changes Proposed
Move simple gossip handlers from C++ scripts to database conditions + SmartAI for 6 Northrend NPCs:
Minor behavioral note
The original C++ for Razael/Lyana checked
GetReqKillOrCastCurrentCountto hide the gossip option after credit was already given. The DB condition only checks quest incomplete status, so the option remains visible until the quest is turned in. This is cosmetic only — selecting it again harmlessly re-gives credit.How Has This Been Tested?
Requires in-game testing:
Issues Addressed
Continuation of #25207 and #25274 — moving hardcoded gossip handlers to database handling.
AI Usage Disclosure
Generated with Claude Code (Claude Opus 4.6)