promotional bannermobile promotional banner

DeathKnightHelper

A World of Warcraft retail addon for Blood Death Knights.
Back to Files

v1.0.0

File nameBloodDeathKnightHelper-v1.0.0.zip
Uploader
ray929ray929
Uploaded
Sep 18, 2026
Downloads
5
Size
117.3 KB
Flavors
Retail
File ID
8909786
Type
R
Release
Supported game versions
  • 12.1.0

What's new

commit 5f4f2c5a4d85453394ad9d7fafe8609fc6e23618
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 15:27:57 2026 +0800

    package.cmd 移出仓库:加进 .gitignore 并解除跟踪

    本地工具脚本没必要占仓库位置(用户要求)。git rm --cached 只解除跟踪,
    本机文件保留,以后仍可正常双击打包。

    - .gitignore 里归到"构建 / 发布产物"段,注明排除口径与 pkgmeta 一致。
    - pkgmeta 的 ignore 里那条 - package.cmd 保留,当"万一 zip 混进仓库"的兜底。
    - AGENTS.md / 记忆同步:新 clone 的机器上没有该文件,取回用
      git show aaa1a37:package.cmd > package.cmd。

commit db913b51be1007bc07c73e181bd140e56871b505
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 15:25:13 2026 +0800

    骨盾:名字改问客户端 + 补注册天赋事件 + 登录核对表

    - 名字不再硬编码:删掉 GATE_NAMES / SKILL_NAMES / L.gateList 三张表,统一走
      SpellName()(C_Spell.GetSpellName 取本地化名,退 _G.GetSpellInfo,兜底 spell:ID),
      整段 pcall + issecretvalue 保护,只缓存成功值。今天三个名字全写错就是硬编码害的。
      /bdk debug 也不再读自己那份 ID 表,改为直接读 GATE_ROWS,消掉两表人肉同步的隐患。
    - 补注册 PLAYER_TALENT_UPDATE / TRAIT_CONFIG_UPDATED / SPELLS_CHANGED /
      PLAYER_REGEN_ENABLED 四个事件(OnEvent 里原有分支但从未注册,是死代码,换天赋
      只能靠驱动循环 5 秒兜底慢半拍跟上),全部 pcall 注册。
    - 新增登录/换天赋后的核对表:打印每个刷新技能与前置天赋的启用状态;
      签名去重避免驱动每 5 秒重读刷屏,战斗中读到 nil 则整张不打。
    - 译名跟随国服客户端:集骨者 / 无餍狂刃 / 憎恶附肢。
    - 测试:smoke 116 → 141(新增核对表 T12 段 + 源码级"不许出现技能名字面量"断言),
      bp 93 / cmd 32 不变;四个变体检验均精确命中。

commit 40b87f540fe00d6ec2c2ad68b8bd01c4ddd3cc43
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 12:06:13 2026 +0800

    骨盾刷新技能加"前置天赋闸门":没点天赋的技能不再重置倒计时

    刷新技能会不会让骨盾涨层,取决于前置天赋点没点:
      符文刃舞 ← 不竭之刃 Insatiable Blade(377637)
      死亡之握 / 血魔之握 / 憎恶之肢 ← 拾骨者 Bone Collector(458572)
    没点却当成刷新,倒计时会被无谓重置 → 该提醒时反而不提醒(漏报)。

    检测走 C_SpellBook.IsSpellKnown(11.2 起替代废弃的 IsPlayerSpell),
    退路依次是 C_Spell.IsSpellKnown、IsPlayerSpell。天赋是静态数据(战斗中
    也改不了),所以只在非战斗时读一次进 gateCache,战斗中一律用缓存值 ——
    天然绕开 12.x「战斗中能问什么」那摊 secret 雷区。刷新时机 = 驱动循环
    5 秒兜底 + PLAYER_TALENT_UPDATE / TRAIT_CONFIG_UPDATED / SPELLS_CHANGED
    (后三个用 pcall 注册:12.x 改过一批事件名,裸注册不认识的会直接抛错)。

    读不到时 fail-open(当作点了):读不到是"我们不知道",不是"玩家没点",
    代价最多是漏一次预警。GateRead 只认真正的 boolean —— secret 值和调用
    失败都算"读不到",继续找下一个 API。/bdk debug 新增天赋闸门状态 + 天赋
    ID 输出,这也是核对 ID 对不对的地方(点了却显示"未点/读不到"就是错了)。

    顺带修正:上一轮把符文刃舞给 5 层的机制归给暗影国度的符文铭刻之力
    Crimson Rune Weapon(那是过时页面);12.x 的来源实际是天赋 Insatiable
    Blade —— wiki 原文 "Dancing Rune Weapon's cooldown is reduced by 30 sec
    and now generates 5 Bone Shield charges"(12.0.0 起)。

    测试:smoke 107 → 116(新增 9 条:关/开天赋后的重置行为、无前置天赋的
    技能不受影响、检测 API 不可用时 fail-open、debug 输出闸门)。bp 93 /
    cmd 32 不受影响。四个变体检验都精确命中:闸门恒开 → 红 3 条、恒关 →
    红 14 条、fail-closed → 恰好红在 fail-open 那条断言上、两个天赋 ID 对调
    → 红 3 条。

    桩:新增 env.__talents[天赋ID] = true(表示已点出)与 env.__noSpellKnownApi
    (模拟 API 全不可用)。注意桩里不设 __talents 就是"没点",闸门全关,
    所有刷新技能断言都会红。

commit 85893ef0ff5933f61b880ea89996bc5b0e8fee2a
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 10:39:38 2026 +0800

    骨盾刷新表修正:符文刃舞 49028 给 5 层,加回白名单

    用户游戏内实测两条新事实:
    - 死亡之握 49576 之后骨盾时长会整体刷新(拾骨者天赋,上一轮已加)
    - 符文刃舞 49028 同样会刷新:它配合 Crimson Rune Weapon 天赋
      "Dancing Rune Weapon generates 5 Bone Shield charges",
      施放后骨盾刷回 30 秒 / 5 层

    上一轮我只看 12.x 的技能描述("mirrors your melee attacks" + 30% 招架,
    完全不提骨盾),据此把 49028 当成"不产骨盾"删掉了 —— 判断错了,加回来。
    教训已写进注释:**技能描述不能当判据**,它不写的效果照样存在。

    同时修正两处中文技能名(ID 都没错,只是名字写错):
      195292 Death's Caress     死亡之攫  → 死神的抚摩
      108199 Gorefiend's Grasp  腐烂之握  → 血魔之握
    README 的"会撤销提醒的技能"列表补齐为五个(含死亡之握),中英同步。

    REFRESH_IDS 最终形态(每条注明依据):
      195182 骨髓打击 / 195292 死神的抚摩(2层) / 49028 符文刃舞(5层) /
      49576 死亡之握 / 108199 血魔之握 / 1263569 憎恶之肢(持续窗口 12s)

    测试:smoke 106 → 107 全绿,bp 93 / cmd 32 不受影响。
    新增/改写 2 条断言:49028 会重置倒计时、且它是瞬时型(不是持续窗口)。
    变体检验:删掉 49028 → 红(12.5 -> 12.5,正好复现"还剩十几秒就喊话");
    把 49028 误标成 12 秒窗口 → 红(24.0 -> 24.0,会一路推迟到漏报)。

commit 494641676d37a1e33c0f8ee364f590dfae3989c0
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 09:55:27 2026 +0800

    骨盾刷新技能表修正:补死亡之握/血魔之握/憎恶之肢,删幻舞与来路不明的 ID

    用户实测:死亡之握(49576)拉怪会 +1 层骨盾并刷新 30 秒时长,但插件没检测到,
    骨盾还剩十几秒就喊话。排查确认 REFRESH_IDS 漏了它。

    依据(逐条在 warcraft.wiki.gg 核实):
    - 骨盾主来源是 Marrowrend(Bone Shield 页明写)+ Death's Caress
      (描述 "generating 2 Bone Shield charges")。
    - 拾骨者天赋(Bone Collector, 458572)"When you would pull an enemy generate
      1 charge of Bone Shield",Affects 列出的正是 Death Grip 与 Gorefiend's Grasp。
    - Abomination Limb(憎恶之肢)也是拉怪技能:它 12.0.0 被重做,2026-03-06 的
      hotfix 专门修过「点拾骨者时它不给骨盾」的问题,说明它同样会产骨盾。

    改动:
    - 新增 49576(死亡之握)、1263569(憎恶之肢,重做后的 ID)。
    - REFRESH_IDS 的值由 true 改成「持续刷新窗口秒数」:0 = 瞬时型,>0 = 持续型。
      憎恶之肢持续 12 秒、每秒拉一次怪,骨盾在整段时间里被反复刷新,只在施放那一拍
      重置不够用 —— 驱动循环新增第 0 步,窗口内每拍把倒计时推迟(state.refreshUntil),
      窗口走完才开始算最后 24 秒。debug 会打出 "refresh window: Xs left (timer held)"。
    - 删掉 49028(符文武器幻舞):12.x 描述只有 "mirrors your melee attacks" + 30% 招架,
      不产骨盾;留着会让倒计时被无谓重置 = 漏报,比漏检更糟。
    - 删掉 439843:wiki 搜索零命中,查无此技能,当初是猜着填的。
    - ClearWindow() 一并清掉 refreshUntil。

    测试:smoke 96 -> 106(新增 10 条:三个技能的重置、窗口内持续推迟、窗口结束后恢复
    倒数、幻舞不再重置、debug 显示窗口)。bp 93 / cmd 32 仍绿。
    三个变体检验:删 49576 -> 目标断言红(13.0 -> 13.0,完全没重置);窗口改 0 ->
    红(掉到 14.0);把 49028 加回 -> 红(12.5 -> 24.0)。

    AGENTS.md 新增硬约束 11:刷新技能表只放真能涨层的技能、每条要有出处、别凭印象加 ID。

commit aaa1a3720865cdd0ef71e13aff701d7a6c87eb9e
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 09:43:38 2026 +0800

    新增 package.cmd:本地打出与 CF 同构的发布 zip

    CF 的打包链路只在发版时跑,本地自测 / 手动装包缺一个离线手段。新增 Windows
    cmd 脚本 package.cmd,把 toc + 三个 lua + Sounds\*.mp3 打进
    BloodDeathKnightHelper.zip,zip 根下只有一个 BloodDeathKnightHelper\ 目录,
    解压直接扔进 Interface\AddOns\。

    排除口径与 .gitignore / pkgmeta.yaml 统一:.git\ .gitignore .gitattributes
    .workbuddy\ AGENTS.md README.md pkgmeta.yaml package.cmd tests\ docs\ build\
    *.zip 都不进包。实现走白名单(*.toc + *.lua + Sounds\),所以根目录多放一个
    文件也不会被误打进发布包。

    流程:xcopy 暂存到 build\BloodDeathKnightHelper\ → 用系统自带的
    %SystemRoot%\System32\tar.exe(bsdtar,-a -c -f 直接写 zip)打包 → 打印 zip
    内容清单 → 清理暂存目录。系统没有 tar(Win10 1803 以下)时退回 PowerShell
    Compress-Archive。用法:package.cmd [-q],-q 跳过末尾 pause 便于脚本调用。

    实测(Win11):LF 版与 CRLF 版均正常;zip 内 9 个条目的大小与源逐一对上、
    解压后 md5 全等;重复运行能覆盖旧 zip;build\ 暂存跑完即清理。

    配套改动:
    - .gitattributes:新增 *.cmd / *.bat 走 CRLF 的例外(仓库内仍存 LF);
      顺手修正已证伪的旧注释 —— 「历史文件是 CRLF、加规则后会产生整文件重写 diff」
      是错的,入库内容本来就是 LF(git ls-files --eol 复核 i/lf w/lf)。
    - pkgmeta.yaml:ignore 补 package.cmd / build / '*.zip',并写明该清单要与
      .gitignore、package.cmd 保持同一口径。

commit 666f7f8b10531a513119ec0b7939275677ead299
Author: ray929 <pager9@outlook.com>
Date:   Fri Sep 18 09:14:44 2026 +0800

    三条判据各配独立语音与文案:骨盾没了 / 层数不够 / 快没了

    - BoneShield.lua:把「一条文案 + 两条语音」换成 L.kinds 三选一(text + voice + reason):
        bsGone  骨盾没了     → voice-cn-1.mp3
        ossGone 骨盾层数不够 → voice-cn-2.mp3
        warn    骨盾快没了   → voice-cn-3.mp3(倒计时到点)
      `KindOf(kind)` 兜底退到 warn;英文三条共用 voice-en.mp3(文案仍是三条)。
      退役的 voice-cn.mp3 已不再被任何代码引用(文件先留着,未删)。
    - `/bdk bs test 1|2|3` 逐条试听(不带参数 = 第 1 条);`/bdk debug` 的「上次提醒」
      按 kind 报出是哪一条。
    - 去重语义收紧:2 秒内仍只发一次声,但**红字换成最新那条判据的文案**(原先三条共用一句话)。
    - 测试:smoke 90 → 96(新增/改写 16 条断言,钉死每条判据的语音文件 + 红字);
      三个变体(固定语音 / 固定文案 / 对调 2·3 号音)分别红 4 / 5 / 4 条。
    - README:命令表补 1|2|3、功能介绍补「三条提醒各有各的说法」。
    - Sounds/:新增 voice-cn-2.mp3、voice-cn-3.mp3(都是 ID3v2.4 头,与 cn-1 一致)。

commit 85590ba7544577c78d535be9c4313e0afeba964c
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 23:33:45 2026 +0800

    发布改按 CF 直接拉取 GitHub:去掉 .github 依赖

    - pkgmeta.yaml:ignore 里删掉 `.github`(CF 的打包器不看 .github,也不需要
      GitHub Action);补注释写明发布靠仓库 webhook + 打 tag,且点开头的路径
      CF 本来就会自动忽略
    - AGENTS.md:第 6 节发布流程重写 —— webhook URL 形态、tag 与文件类型
      (release / alpha / beta)的对应、CF 读的是 pkgmeta.yaml
    - toc:注释补一句「CF 从 GitHub 直接拉取打包,不需要 GitHub Action」

commit 347268355cfb44a4843933161fa5547e24bf358c
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 23:28:53 2026 +0800

    新增 README.md(面向玩家:功能介绍 + 斜杠命令,英中双语)

    对外只致谢 KiraUI-Plugin 一条;ActionbarEnhanced 的参考只记在 AGENTS.md。

commit f880026608176b8aea3847b65d03a4ad18541959
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 23:28:42 2026 +0800

    改名 BloodDeathKnightHelper:命令表独立成文件,新增血沸模块,骨盾语音拆两条

    - 文件夹 / toc 文件名 / package-as 三者统一为 BloodDeathKnightHelper
      (全局标识符前缀仍是 BloodDeathKnight,不动);toc 的版本号与作者
      改由打包器代入(@project-version@ / @project-author@),不再硬编码
    - 新增 .gitattributes 统一 LF,.gitignore 扩到 AI 指令 / 编辑器 / 构建产物
    - 命令表独立成 Commands.lua,唯一入口 /bdk(旧别名 /bsr 移除)
    - 新增 BoilingPoint.lua:血沸回声 3 秒倒计时条(移植自 KiraUI-Plugin)
    - 骨盾语音拆成两条:倒计时到点用 voice-cn.mp3,骨盾/埋骨之所掉了用
      voice-cn-1.mp3(英文沿用 voice-en.mp3);/bdk bs test [2] 分别试听
    - 测试桩补齐(bp_smoke / cmd_smoke / wowstub),smoke 90、bp 93、cmd 32 全绿

commit 4dfe95456067185f7f62f75f72a9c03e7f4aa1b2
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 14:10:19 2026 +0800

    T11 再补两项:埋骨之所先报、骨盾 1.5 秒后也掉

    推导出来的第三种对齐 —— 两条判据来自不同的触发点(埋骨之所掉线 / 骨盾掉线),
    间隔 1.5 秒(1.0 秒去抖 + 一拍),打出来是同一句话,同样只该响一次。

    顺手把 T11 全部三项对齐都用变体检验过(ALERT_GAP 临时改成 0 = 改前行为):
    三处各报 2 次,而"骨盾真到期再报一次"仍然通过 —— 证明去重没有过度吞。
    53/53 通过。

commit 2ae99092c9d79badb1e84e2bd0b2a5615236f6f4
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 14:08:40 2026 +0800

    去重:同一窗口的重复提醒不重复发声(修 0~1 秒内的连报)

    用户问"有没有可能会 1 秒内连续报两次骨盾"。查下来有,而且两条路径都复现了。

    能触发提醒的地方一共三处:
      1. 驱动循环第 1 步:倒计时到点(约剩 5 秒)
      2. UpdateCdmState:骨盾"读到不在场"满 1 秒去抖(战斗中)
      3. UpdateCdmState:埋骨之所掉线去抖成立且骨盾仍在场

    去重原来只靠 state.alerted(本窗口只响一次)。问题出在骨盾掉线那条路:
    它是**先 ClearWindow() 再 TriggerAlert()** —— ClearWindow 把 alerted 复位了,
    于是同一拍里"倒计时到点"报过之后,它还能再报一次。

    对齐条件(0.5 秒驱动,1.0 秒去抖):
      * 掉盾起始点落在倒计时到点前 1.0 秒 → 两个判据落在**同一拍**,间隔 0 秒
      * 落在到点前 0.5 秒 → 到点响一次,半秒后去抖成立再响一次
      * 埋骨之所先报、骨盾随后也掉 → 间隔约 1.5 秒

    三处判据打出来的是**同一句话**(同一行红字、同一段语音),所以重复发声是纯噪音。
    加 ALERT_GAP = 2.0:state.lastAlertAt 记录上次真正发声的时刻,被触发时若间隔不足
    就只吞掉声音 —— 但视觉要补回来(ShowText + SetFlash(true)):掉盾那条路刚
    ClearWindow() 撤过红字和蒙版,不补的话玩家刚听到一声"补骨盾",字和蒙版就同时没了。
    同时把窗口标成已提醒,否则下一拍这条判据又来一次,变成 2 秒后补一枪。

    为什么是 2 秒:要 > 0.5 秒的对齐窗口,又要 < "到点提醒 → 骨盾真到期 → 再报"的
    6 秒(实际约 7.5 秒)。测试里专门锁住后者不被误吞。

    state.lastAlertAt 刻意不被 ResetWindow / ClearWindow 清掉 —— 去重要挡的正是
    "窗口刚被清掉、下一条判据立刻又成立"这个情形。

    测试:新增 T11 五项(同一拍只响一次、半秒内不重复响、去重后红字仍在屏幕上、
    去重后蒙版仍在闪、骨盾随后真消失仍能再报)。改之前前两项失败(间隔 0 秒 / 0.5 秒
    各报 2 次),后两项用"裸 return"变体验证过有牙齿。51/51 通过。

commit 2c6ba7991d0ca047d816b6667adc2a85378c1e1d
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 13:47:19 2026 +0800

    骨盾提醒时机:把倒计时从 25s 改到 24s,让玩家真正看到"还剩 5 秒"

    原来 WARN_AFTER = 25,按名义算术是"骨盾 30 秒 - 25 秒 = 剩 5 秒提醒",
    但实际看到的是 4 秒。原因是驱动是 0.5 秒一拍,两头都吃延迟:
    发现骨盾亮起最多晚 0.5 秒(倒计时起点晚),到点又最多晚 0.5 秒触发,
    平均合计约 0.5 秒。25 秒倒计时实际落在剩 4.5 秒左右,落在界面上就是 4。

    改成提前 6 秒(WARN_AFTER = 24):平均落在剩 5.5 秒,玩家看到的是 5。

    顺带把常量改成"正着说":原来 WARN_AFTER 是"骨盾存在多少秒后提醒",
    要反推剩余时间得在脑子里做减法,而且 30 秒这个前提写死在注释里。
    现在拆成 BONE_SHIELD_TIME = 30 / WARN_LEAD = 6(含延迟补偿),
    WARN_AFTER 由两者相减得出。想调早晚只改 WARN_LEAD 一个数。

    注释同步:文件头、技术约束段、state.timerEnd、驱动循环第 1 步、
    事件处理里的 ResetWindow 调用点,都去掉了写死的"25 秒"。

    测试:T1 增加"到点前不提醒"这一拍的边界断言(累计 23.5s 不响、
    累计 25.5s 响),T5 的期望值同步为 24。44/44 通过。

commit f780c5478d5df4c712d5819a6e02e7fc0f05ad51
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 13:42:27 2026 +0800

    诊断修正:CDM 条目按"一条条目一行"打印,并定性埋骨之所两个 ID 的关系

    用户跑 /bdk dump 两份对照(骨盾 <5 层 / >=5 层)后定性:

    1. 埋骨之所是**一条** CDM 条目、携带两个 ID。原来 DumpCdmAuras 是
       "一个 ID 一行",于是一条 spell+linked 的条目看起来像两条独立条目
       (清单里 抽血 374598/454871、枯萎凋零 43265/188290、凝血
       391477/391481、吸血鬼打击 433901/433899 全是这个形态),会被误读成
       "得在两个 ID 之间挑对的那个"。现在按 cdID 去重、一条一行,候选 ID 带
       角色标签摊在同一行:
         [BuffIcon] cdID=2 埋骨之所  (spell=219786 linked=219788)  <- OSSUARY

    2. 据此推翻 KiraUI 关于 ID 归属的推论。它断言 219788 是被动天赋本体、
       拖进去"匹配得上但永远不亮";实测该条目 isActive 随骨盾层数正常翻转
       (false -> true,drawn no -> yes,proven=yes)。所以"该拖哪个 ID"是
       伪问题 —— 两个 ID 同属一条条目。OSSUARY_ALT 的注释(原写"12.1 部分
       环境下实际出现的 ID")理由不成立,已改写;保留双 ID 只为防御未来版本
       只暴露其中一个。

    代码:
    - 新增 CooldownCandidates(cooldownID, want) 按角色取候选 ID +
      JoinCandidates 格式化;抽 FrameCdID(f),FrameIsSpell 改为复用。
    - DumpTracked 输出加 cdID= 便于与上面那张表交叉对照,ids= 替代原来会
      误导的裸 spell=219786,219788。
    - proven 注释去掉"拖错的埋骨之所条目"这个已不成立的用途,只留挡常暗
      诱饵帧(EllesmereUI 那种停在屏外 alpha=0 的帧)。

    测试:fixture 里埋骨之所改成 { spellID = 219786, linkedSpellID = 219788 }
    还原实测形态,新增 T10 四项锁住这个回归。43/43 通过。

commit 1e687d3bd61356730a28b1cddbb569e584a9f8f8
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 13:33:48 2026 +0800

    把离线测试桩并入仓库(tests/),并在打包时忽略

    tests/wowstub.lua 是 WoW API 桩(受控时钟 + CDM viewer/条目帧),
    tests/smoke.lua 是 39 项用例的冒烟测试,跑法:
      cd tests && lua smoke.lua <BoneShield.lua 的绝对路径>

    打包时忽略 tests/,不影响上架的 zip。

commit e43b3b46794aed2b7ed0e4219ecbb54e74848998
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 13:33:22 2026 +0800

    骨盾监控:三态读数 + 掉线去抖 + 帧认证,并给 CDM 骨盾图标加蒙版闪烁

    借鉴 KiraUI-Plugin_BoneShield.lua 的实测结论做四处加固(它踩过的坑:

    1. 读数改三态(known/up)。原来 CdmUp() 是二态,"读不到"被当成"没有
       了" —— CDM 重建帧池、换皮插件重排图标时会凭空造出一次补盾误报。
       现在 known=false 一律不下结论:不触发提醒,也不清除既有状态。

    2. 掉线去抖 DOWN_GRACE=1.0s。"不在场"要连续成立才被承认。刻意大于驱
       动周期(0.5s),否则去抖就等于"一拍读数直接下结论",形同虚设。

    3. 帧认证 proven[]。帧被亲眼看到亮过才允许它说"不在场",用来挡别家插
       件停在幕后的常暗诱饵帧,也挡埋骨之所那两个 ID 里可能拖错的那个(拖
       成被动天赋条目会匹配上但永不亮)。只加在"看图标画没画"这条退路上,
       isActive 读到真值就直接相信、不要求认证。

    4. 帧发现加 GetChildren() 递归。GetItemFrames() == GetLayoutChildren(),
       只收 IsShown() 的子帧,而 CDM 的 ShouldBeShown() 恰在光环不活跃时把
       图标 HIDE 掉 —— 那个帧会在最需要它的一刻从列表里消失。
       注意 Frame:GetChildren() 返回多值不是表,须先打包。
       另修:清理池化帧时先把帧存进局部变量再 remove,否则拿不到被删那一
       个;GetItemFrames 兼容返回表 / 返回迭代器两种形态。

    5. 配置提示判据改为"持续"扫不到(ABSENT_GRACE=3s),瞬态空列表不再弹
       提示;换地图时重置计时,避免刚进本就弹一次。

    新功能:CDM 骨盾图标蒙版闪烁
       提醒窗口打开时在 CDM 里的骨盾图标上盖一层脉冲红蒙版,直到补盾或窗口
       重置(比 3 秒文字更持久)。三条约束照抄对方实测:
       - 蒙版帧永远 Show、只用 alpha 开关(Hide 一个 CDM 条目帧的子帧会让
         CDM 重排帧池);
       - 帧层级取图标自己那一层(图标美术在 ARTWORK 层、层数挂在自动高一层
         的 Applications 子帧上,同层正好盖住图标不盖住数字);
       - 池化帧被回收时停掉它身上的蒙版。
       alpha 只在"没在闪"或"被清成 0"时拉回下限,否则每拍重设会把脉冲打回
       最低点、闪起来一顿一顿。

    其他:/bdk flash on|off(中文别名 闪烁开/关、图标开/关)新增开关;
    /bdk dump 追加 tracked entries,逐帧列出匹配到的 spell ID / isActive 可
    读性 / proven / drawn,用来定性埋骨之所到底该拖哪个 ID;isActive 兼容
    方法、大写字段、小写字段三种形态。

    新增离线测试 .workbuddy/tests/(WoW API 桩 + 受控时钟),39 项用例覆盖
    配置识别、25s 提醒、机密战斗读数、掉线去抖、诱饵帧、帧池重建、施法重置、
    非战斗掉盾静默、非鲜血专精待机,全部通过。

commit 5d49283b81b976fc23934d062ab96f987ae61702
Author: ray929 <pager9@outlook.com>
Date:   Thu Sep 17 13:16:37 2026 +0800

    初始化:鲜血死亡骑士辅助(BloodDeathKnight)

    正式服 12.1(Interface 120100)血 DK 辅助插件,当前实现骨盾 / 埋骨之所监控提醒。

    - 纯 CDM(冷却管理器)实现:不读 C_UnitAuras,骨盾存在性取 CDM 光环图标的
      IsActive() / IsShown()+alpha,规避 12.x 战斗中光环数据为 secret value 的限制
    - 事件驱动 + OnUpdate 0.5s 节流:骨盾 25s 倒计时、骨盾消失、埋骨之所消失三种提醒
    - 提醒方式:屏幕 1/3 处闪烁大字(3 秒)+ 语音
    - 中英双语本地化(ApplyLang + L 表),跟随客户端或手动切换
    - 命令:/bdk(/bsr 兼容别名)test / dump / sound / text / lang / enable

    命名统一为 BloodDeathKnight 前缀:SavedVariables BloodDeathKnightDB、
    帧名 BloodDeathKnightAlert、SLASH_BLOODDEATHKNIGHT1/2、主文件 BloodDeathKnight.lua。

This mod has no additional files