feat(Core/DB/Scripts): add creature_text_options engine for data-driven talk conditions#25188
feat(Core/DB/Scripts): add creature_text_options engine for data-driven talk conditions#25188Nyeriah wants to merge 7 commits intoazerothcore:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a data-driven “creature text options” layer so CreatureTextMgr::SendChat() can enforce per-(CreatureID, GroupID) talk rules (cooldown, proc chance, player-only) via DB configuration, allowing many boss scripts to remove custom talk-throttling logic.
Changes:
- Core: introduce
CreatureTextOptions, load options from new DB tables, and enforce them insideSendChat(). - Core: add per-creature text cooldown tracking in
Creature. - Scripts/DB: remove per-script kill-yell throttling/chance code and add SQL schema + mappings for affected bosses.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp | Removes local slay talk throttling in favor of text options engine |
| src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp | Removes local slay talk throttling in favor of text options engine |
| src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp | Removes local slay talk throttling in favor of text options engine |
| src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Outland/BlackTemple/boss_illidan.cpp | Removes local kill yell cooldown logic in favor of text options engine |
| src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp | Removes local 30% roll; relies on options for proc chance |
| src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp | Removes local kill-yell cooldown timestamp; relies on options |
| src/server/scripts/Northrend/Gundrak/boss_slad_ran.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/Gundrak/boss_gal_darah.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/DraktharonKeep/boss_trollgore.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp | Removes local player-only + kill-talk gating in favor of text options engine |
| src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp | Removes local kill yell cooldown logic in favor of text options engine |
| src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp | Removes local kill-talk event gating in favor of text options engine |
| src/server/game/World/World.cpp | Adds startup loading call for creature text options |
| src/server/game/Texts/CreatureTextMgr.h | Adds CreatureTextOptions types and APIs |
| src/server/game/Texts/CreatureTextMgr.cpp | Implements options loader + enforces options inside SendChat() |
| src/server/game/Entities/Creature/Creature.h | Adds text cooldown tracking fields/APIs |
| src/server/game/Entities/Creature/Creature.cpp | Implements text cooldown tracking |
| src/server/database/Database/Implementation/WorldDatabase.h | Adds prepared statement id for options query |
| src/server/database/Database/Implementation/WorldDatabase.cpp | Adds prepared query joining options to option sets |
| data/sql/updates/pending_db_world/creature_text_options.sql | Adds schema + data mapping bosses to option sets |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| _lastTalkTimeKill = GameTime::GetGameTime().count(); | ||
| Talk(SAY_LK_KILL); | ||
| } | ||
| if (!me->IsInEvadeMode() && _phase != PHASE_OUTRO) |
There was a problem hiding this comment.
This change removes the script-side victim->IsPlayer() and cooldown gating and relies entirely on creature_text_options being present and successfully loaded. If the DB update isn’t applied (or the options query fails / returns empty), this will regress to yelling on non-player kills (pets/guardians) and can spam without cooldown. To keep behavior correct under partial deployments/misconfigured DBs, consider retaining the minimal victim->IsPlayer() guard in scripts where it previously existed (while still letting the engine handle cooldown/chance), or make options loading a hard requirement (clear startup failure/logging and/or disable affected groups when options are unavailable).
| if (!me->IsInEvadeMode() && _phase != PHASE_OUTRO) | |
| if (victim->IsPlayer() && !me->IsInEvadeMode() && _phase != PHASE_OUTRO) |
There was a problem hiding this comment.
Dismissed — the DB update is part of this PR and AzerothCore's update system applies pending SQL files atomically during startup. If the SQL hasn't run, the server wouldn't have the updated binaries either. The system is designed to be transparent: no options row = no filtering, so a missing DB entry doesn't break anything — it just means no throttling (which is the same behavior as before this PR for any creature without an entry).
…en talk conditions Introduces creature_text_option_sets and creature_text_options tables that let SendChat() enforce cooldown, trigger chance, and player-only filtering without per-script boilerplate. Removes manual _canTalk booleans, EVENT_KILL_TALK scheduling, GameTime timestamps, and roll_chance_i wrappers from 21 boss scripts across Black Temple, Azjol-Nerub, ICC, Ruby Sanctum, Drak'Tharon Keep, Gundrak, Nexus, and Naxxramas. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Migrates 22 more boss scripts to the creature_text_options engine: - 16 _recentlySpoken pattern scripts (Karazhan, Hyjal, SSC, Gruul's, Magtheridon, TK Eye, Black Temple) - 6 roll_chance_i KilledUnit scripts (Molten Core, Sunwell, TK Eye) - Removes dead _recentlySpoken variable from Leotheras Adds 3 new option sets (5s standard, 25% chance, 50% chance) and 26 new creature_text_options assignments. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Use ceiling division for cooldown to avoid truncating sub-second values - Clarify log message for empty/failed options query - Cache options pointer in SendChat() to avoid duplicate hash lookup Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
e9790ec to
443935a
Compare
BossAI base class already sets this validator. These were left over from the creature_text_options refactor and conflict with the cleanup done in PR azerothcore#25189. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Changes Proposed:
This PR proposes changes to:
AI-assisted Pull Requests
Important
While the use of AI tools when preparing pull requests is not prohibited, contributors must clearly disclose when such tools have been used and specify the model involved.
Contributors are also expected to fully understand the changes they are submitting and must be able to explain and justify those changes when requested by maintainers.
Summary
Introduces a data-driven
creature_text_optionsengine that allowsSendChat()to automatically enforce cooldown, trigger chance, and player-only filtering for creature text groups — without requiring per-script boilerplate.Core changes:
CreatureTextOptionsstruct and loader inCreatureTextMgrthat reads from two new DB tablesSendChat()checks options (PlayerOnly, TriggerChance, Cooldown) before sending and sets cooldown afterCreatureclass gains cooldown tracking (IsTextOnCooldown,SetTextCooldown)DB schema (two-table ruleset design to avoid data duplication):
creature_text_option_sets: Defines reusable rulesets (e.g. "6s cooldown, 100% chance, no player filter")creature_text_options: Assigns a ruleset to a specific (CreatureID, GroupID) pairScript cleanup (21 files):
Removes manual talk-throttling boilerplate from boss scripts across Black Temple, Azjol-Nerub, ICC, Ruby Sanctum, Drak'Tharon Keep, Gundrak, Nexus, and Naxxramas. Patterns removed include:
_canTalkboolean flags withScheduleUniqueTimedEvent/AddEventAtOffsetEVENT_KILL_TALKwithHasTimeUntilEvent/ScheduleEvent_lastTalkTimeKillGameTime timestamp comparisonsroll_chance_i()wrappersIssues Addressed:
SOURCE:
The changes have been validated through:
All cooldown values (5-6s) and trigger chances (30% for Razuvious) match the original hand-coded values in each script.
Tests Performed:
This PR has been:
How to Test the Changes:
Loading Creature Text Options...log line with correct row countKnown Issues and TODO List:
How to Test AzerothCore PRs
When a PR is ready to be tested, it will be marked as [WAITING TO BE TESTED].
You can help by testing PRs and writing your feedback here on the PR's page on GitHub. Follow the instructions here:
http://www.azerothcore.org/wiki/How-to-test-a-PR
REMEMBER: when testing a PR that changes something generic (i.e. a part of code that handles more than one specific thing), the tester should not only check that the PR does its job (e.g. fixing spell XXX) but especially check that the PR does not cause any regression (i.e. introducing new bugs).
For example: if a PR fixes spell X by changing a part of code that handles spells X, Y, and Z, we should not only test X, but we should test Y and Z as well.