- Updated button labels for saving configurations to be more concise. - Adjusted layout of panels to improve UI structure and readability. - Introduced new methods for creating DataGridView columns to reduce redundancy. - Enhanced handling of dynamic and static macro entries, including improved row numbering and offset hints. - Removed unnecessary UI elements and streamlined event handling for better performance. - Improved localization support by ensuring state names are correctly categorized and hidden where necessary.
15 KiB
title, language, primary_file, related, purpose
| title | language | primary_file | related | purpose | |||||
|---|---|---|---|---|---|---|---|---|---|
| Fuyutsui core/classmacros.lua:AI 宏规则参考 | zh-CN | core/classmacros.lua |
|
供 AI 理解、审查、新增职业宏时作为单一事实来源;说明 ClassMacros 三表规则、MacroBodies 查表与 CreateMacro 展开逻辑 |
Fuyutsui core/classmacros.lua:AI 宏规则参考
本文描述如何在
ClassMacros里声明职业宏,以及CreateMacro如何把它们展开成 SecureActionButton 覆盖绑定。
改宏只改core/classmacros.lua,不要改class/*.lua,也不要在别处硬编码职业宏列表。
0. 一句话定义
classmacros.lua 提供:
Fuyutsui.MacroBodies:命名宏体查表(药水等)。Fuyutsui.ClassMacros[classFile]:各职业的三份数组列表。
运行时由 main.lua:LoadPlayerMacros() 按 UnitClassBase("player") 取出当前职业,再调用:
Fuyutsui:CreateMacro(m.dynamicSpells, m.staticSpells, m.specialSpells)
真正创建按钮、拼宏文本、绑定热键的逻辑在 core/macro.lua。
创建顺序(依次占键):dynamicSpells(每组 30 键)→ staticSpells → specialSpells。
1. AI 必须遵守的规则
- 键名必须是
UnitClassBase返回值:WARRIOR/PALADIN/HUNTER/ROGUE/PRIEST/DEATHKNIGHT/SHAMAN/MAGE/WARLOCK/MONK/DRUID/DEMONHUNTER/EVOKER。 - 每个职业表必须有三个字段:
dynamicSpells、staticSpells、specialSpells(可为空表{})。字段顺序建议与文件一致:dynamic → static → special。 - 三表一律用数组(
{"牺牲祝福", "代祷", "圣盾术"}),不要再写[n] = "..."稀疏键值表。 - 需要点名队友/团队成员的治疗、驱散、护盾等 → 放
dynamicSpells(数组,顺序敏感)。 - 普通单体施法(目标默认、或条件写在法术名里)→ 放
staticSpells,只写法术/条件字符串,不要自己加/cast。 - 完整宏文本(
/castsequence、/stopcasting、/cancelaura等)→ 可直接写在staticSpells(以/开头)或追加到specialSpells;以/开头的字符串不会再加/cast。 - 药水等复用宏体 → 在列表里写名称(如
"银月城生命药水"),并在Fuyutsui.MacroBodies中登记;创建时用表内值。 - 需要跳过某个槽位但不平移后续键 → 在数组对应位置写
""(占位,不创建按钮)。 - 战斗中
InCombatLockdown()时无法创建/修改安全按钮;改宏后需在脱战后/reload或等下次非战斗加载生效。 - 保持 Lua 5.1 / WoW 兼容;法术名用本地化中文名(与客户端一致),与现有表风格一致。
- 不要格式化整个文件;只改目标职业段落。
2. 加载与消费链路
classmacros.lua
│ MacroBodies(命名宏体)
│ ClassMacros[classFile]
▼
main.lua:LoadPlayerMacros()
│ classFile = UnitClassBase("player")
│ MacrosList = ClassMacros[classFile]
▼
macro.lua:CreateMacro(dynamic, static, special)
│ 1. dynamic:每组 × 30 键
│ 2. static:ipairs 依次占键(resolveMacroBody)
│ 3. special:接在 static 后依次占键(resolveMacroBody)
│ SetOverrideBindingClick + macrotext → 按钮 s1..sN
▼
玩家按覆盖热键 → SecureActionButton 执行宏
触发时机:玩家数据加载路径会调用 LoadPlayerMacros()(见 core/player.lua)。专精切换等场景若重新加载宏,同样走此函数。
3. 热键池(macroKind)
core/macro.lua 用修饰键 × 基础键生成有序列表 macroKind[1..N]。
| 修饰键顺序 | 基础键(每组 39 个) |
|---|---|
CTRL → ALT → SHIFT → ALT-CTRL → ALT-SHIFT → CTRL-SHIFT → ALT-CTRL-SHIFT |
小键盘 0–9 / 小数点 / + / − / × / ÷;F1–F3,F5–F12(无 F4);, . / ; ' [ ] \;7 8 9 0 = |
- 总槽位数 =
7 × 39 = 273。 - 按钮名:
s1、s2、…(与macroKind下标一致)。 - 人读对照表见
Keymap.md(ID 1 =CTRL-NUMPAD1,以此类推)。
AI 改宏时:关心的是 dynamic 占用多少槽、以及 static/special 数组下标对应的全局热键;不必手算,除非要核对外部程序按键映射。
4. 槽位分配算法(核心)
CreateMacro 按顺序推进槽位下标 i(从 1 起),不再用「special 与 static 同序号互斥覆盖」:
i = 1
-- 1. dynamicSpells
for each spell in dynamicSpells:
for raidIdx = 1..30:
按 §5 生成 macroBody(spell 为空则不建按钮)
占用 macroKind[i],i = i + 1
-- 2. staticSpells
for each entry in staticSpells:
macroBody = resolveMacroBody(entry) -- "" → nil,不建按钮但仍占位
占用 macroKind[i],i = i + 1
-- 3. specialSpells
for each entry in specialSpells:
macroBody = resolveMacroBody(entry)
占用 macroKind[i],i = i + 1
因此:
dynamicSpells 长度 |
动态占用槽 | staticSpells[1] 对应全局 i |
|---|---|---|
| 0 | 0 | 1 |
| 1 | 30 | 31 |
| 5 | 150 | 151 |
| 6 | 180 | 181 |
| 7 | 210 | 211 |
新增或删除 dynamicSpells 条目会平移其后所有 static/special 的实际热键。
在 staticSpells 中间插入/删除条目(含 "")同样会平移其后键位。
4.1 resolveMacroBody(spell)
| 情况 | 结果 |
|---|---|
spell 为 nil 或 "" |
不创建宏(槽位仍前进) |
Fuyutsui.MacroBodies[spell] 存在,且值以 / 开头 |
原样使用表内值 |
MacroBodies[spell] 存在,值不以 / 开头 |
"/cast " .. 表内值 |
spell 本身以 / 开头 |
原样使用(完整宏文本) |
| 其他 | "/cast " .. spell |
5. dynamicSpells 规则
5.1 数据结构
dynamicSpells = { "法术A", "法术B", "法术C" } -- 数组,1-based,顺序 = 组号
- 用纯法术名(中文),不要写
/cast,不要写@raid(展开逻辑会加)。 - 每组固定占 30 个连续热键,对应
raid1…raid30。
5.2 单组内 30 键展开
设组内相对位 raidIdx = 1..30,法术名为 spell:
| raidIdx | 生成的 macrotext |
|---|---|
| 1 | /cast [group:raid,@raid1]spell;[group:party,@player]spell;[nogroup,@player]spell |
| 2..5 | /cast [group:raid,@raidN]spell;[group:party,@party(N-1)]spell |
| 6..30 | /cast [group:raid,@raidN]spell |
含义:
- 团队:始终
@raid1…@raid30。 - 小队:仅前 5 键有意义 →
@player、@party1…@party4。 - 单人:仅第 1 键落到
@player。
5.3 何时放入 dynamic
适合:治疗术、驱散、护盾、急救类等必须点名不同队友的技能。
不适合:
- 只打当前目标 / 自身 / 鼠标指向 / 焦点 → 用
staticSpells+ 条件前缀。 - 需要 sequence / stopcasting / cancelaura → 在
staticSpells写以/开头的完整文本,或放入specialSpells。
5.4 现有职业占用(便于估算偏移)
| 职业键 | #dynamicSpells |
动态槽 | static 第 1 项的全局 i |
|---|---|---|---|
| WARRIOR / HUNTER / ROGUE / DEATHKNIGHT / WARLOCK / DEMONHUNTER | 0 | 0 | 1 |
| MAGE | 1 | 30 | 31 |
| DRUID | 5 | 150 | 151 |
| PALADIN / PRIEST / SHAMAN / MONK | 6 | 180 | 181 |
| EVOKER | 7 | 210 | 211 |
6. staticSpells 规则
6.1 数据结构
staticSpells = {
"英勇投掷",
"[@mouseover]保护祝福",
"[spec:2]圣洁鸣钟;[spec:3]灰烬觉醒",
"银月城生命药水", -- 走 MacroBodies
"/castsequence reset=0.3 真言术:耀,x", -- 以 / 开头:完整宏
"", -- 空串:占位跳过,不建按钮
}
- 数组顺序 = 占键顺序(接在 dynamic 区之后)。
- 普通条目是拼在
/cast后面的字符串,不要自带前导/cast。 - 需要完整命令时,直接写以
/开头的字符串。 ""保留槽位但不创建按钮(例如法师历史上空出的位置)。
6.2 常见写法(直接抄现有风格)
| 意图 | staticSpells 值示例 |
最终宏 |
|---|---|---|
| 默认目标施法 | "审判" |
/cast 审判 |
| 自身 | "[@player]荣耀圣令" |
/cast [@player]荣耀圣令 |
| 鼠标指向 | "[@mouseover]破咒祝福" |
/cast [@mouseover]破咒祝福 |
| 光标地面 | "[@cursor]乱射" |
/cast [@cursor]乱射 |
| 焦点优先 | "[target=focus,exists] 窒息;窒息" |
/cast [target=focus,exists] 窒息;窒息 |
| 专精分支 | "[spec:2]圣洁鸣钟;[spec:3]灰烬觉醒" |
/cast [spec:2]... |
| 天赋已知 | "[known:116844,@cursor]平心之环;[known:198898]赤精之歌" |
/cast [known:...]... |
| 姿态/形态 | "[nostance:1]暗影形态" |
/cast [nostance:1]暗影形态 |
| 命名药水 | "银月城生命药水" |
/cast item:241304 + 第二行 /cast item:241305(见 MacroBodies) |
| 完整宏 | "/stopcasting" |
/stopcasting(不加 /cast) |
| 占位跳过 | "" |
不创建 |
7. Fuyutsui.MacroBodies(命名宏体)
7.1 作用
列表里写可读名称,实际宏体集中维护,避免多职业重复粘贴物品 ID。
Fuyutsui.MacroBodies = {
["鲁莽药水"] = "item:241288\n/cast item:241289",
["银月城生命药水"] = "item:241304\n/cast item:241305",
}
在 staticSpells / specialSpells 中写 "银月城生命药水" 即可;resolveMacroBody 会查表并(对非 / 开头的值)自动加 /cast 。
7.2 新增命名宏体
- 在
MacroBodies增加["名称"] = "宏体片段或完整宏"。 - 各职业数组中写
"名称",不要再内联物品 ID。 - 若宏体已是完整命令(以
/开头),查表后原样使用;否则前缀/cast。
8. specialSpells 规则
8.1 数据结构
specialSpells = {
"/castsequence reset=0.5 死亡之握,x",
"/stopcasting",
}
- 同样是数组,接在该职业全部
staticSpells之后依次占键。 - 也走
resolveMacroBody:可用完整/...文本,或 MacroBodies 名称,或普通法术名(会加/cast)。 - 当前仓库多数职业
specialSpells = {};历史上与 static 同槽的特殊宏(sequence / stopcasting 等)已直接写在staticSpells对应位置(以/开头),以保持键位。
8.2 何时用 special 而不是写进 static
| 选择 | 适用 |
|---|---|
写进 staticSpells(/ 开头或 MacroBodies 名) |
需要固定在 static 区某一相对位置 |
追加到 specialSpells |
明确接在 static 末尾之后的额外宏 |
8.3 典型完整宏
| 模式 | 示例(文件中已有) |
|---|---|
| castsequence + 哑元 | "/castsequence reset=0.5 死亡之握,x" |
| 停施法 | "/stopcasting" |
| 取消光环再施法 | "/cancelaura [spec:4]猎豹形态\n/cast 万灵之召" |
castsequence ...,x 中的 x 是占位,用于快速连按重置序列;改此类宏时保持现有 reset 秒数风格,除非有明确需求。
9. 决策树:新技能放哪
需要按队友/团队槽位点名?
├─ 是 → dynamicSpells(纯法术名;注意 +30 偏移)
└─ 否 → 是否已有 MacroBodies 名称?
├─ 是 → staticSpells 写名称
└─ 否 → 能否写成「/cast + 一段条件/法术名」?
├─ 是 → staticSpells 写条件/法术名
└─ 否 → staticSpells 写以 / 开头的完整宏
(或追加到 specialSpells 末尾)
需要跳过某键:在数组该位置写 ""。
10. 修改检查清单(AI 改完自检)
- 职业键是否为正确的
UnitClassBase字符串? - 三个字段是否都在(空也要
{}),且为数组而非[n]=稀疏表? - 若改了
dynamicSpells长度:是否意识到后续热键整体平移? - 若在
staticSpells中间插入/删除(含""):是否评估了后续键位? - 普通 static 值是否没有多余的前导
/cast? - 完整宏是否以
/开头(或走 MacroBodies)? - 药水等是否用 MacroBodies 名称,而不是内联
item:...? - 条件语法是否与现有条目一致(
[@unit]、[spec:N]、[known:id]、[group:...])? - 法术名是否与游戏客户端中文一致?
- 提醒:战斗中不会更新安全按钮;需脱战
/reload验证。
11. 最小示例
11.1 无动态(近战输出职业常见)
WARRIOR = {
dynamicSpells = {},
staticSpells = {
"英勇投掷",
-- ...
"拳击",
"[@focus]拳击",
},
specialSpells = {},
}
- 第 1 项 → 全局
i=1→/cast 英勇投掷 - 最后一项 →
/cast [@focus]拳击
11.2 有动态 + 完整宏 + 命名药水
PRIEST = {
dynamicSpells = { "苦修", "快速治疗", "真言术:盾", "愈合祷言", "纯净术", "圣言术:静" },
-- 动态占 180 槽;static 第 1 项 → 全局 i=181
staticSpells = {
"心灵震爆",
-- ...
"圣言术:静",
"/castsequence reset=0.3 真言术:耀,x", -- 完整宏,占 static 相对第 36 槽
"银月城生命药水", -- MacroBodies
"渐隐术",
"/stopcasting",
},
specialSpells = {},
}
11.3 空槽占位
-- 法师示例:数组中某处写 "",该全局槽不建按钮,后续项仍按顺序占下一键
staticSpells = {
"[@cursor]暴风雪",
"", -- 占位
"奥术智慧",
}
12. 与本文相关、但不要在这里改的东西
| 文件 | 职责 | 改宏时 |
|---|---|---|
core/macro.lua |
热键表、顺序占键、resolveMacroBody、安全按钮 |
仅当要改分配规则/键池时才动 |
main.lua |
LoadPlayerMacros 选职业表 |
一般不动 |
Keymap.md |
人读热键 ID 对照 | 键池变更时同步 |
core/keybinds.lua / config.lua keymap |
动作条扫描 → 像素协议 | 另一套按键编码,与 ClassMacros 覆盖绑定无关 |
class/*.lua |
ClassBlocks 色块 | 不放宏 |
13. 常见错误
| 错误 | 后果 |
|---|---|
普通法术误加 /cast 前缀 |
实际变成 /cast /cast 火球术 |
完整宏未以 / 开头且未进 MacroBodies |
被加上 /cast ,命令错误 |
| 把点名治疗放进 static | 无法按 raid/party 槽位点名 |
仍使用 [36] = "..." 稀疏表 |
与当前 ipairs 顺序占键不兼容,中间空洞行为不符合预期 |
药水内联 item:... 而不用 MacroBodies 名称 |
多职业重复、难统一改 ID |
在 dynamicSpells 或 staticSpells 中间插入却不评估偏移 |
后续所有按键语义错位 |
用错职业键(如 DeathKnight) |
LoadPlayerMacros 取不到表,宏不创建 |
| 假设战斗中改表立即生效 | InCombatLockdown 直接 return,按钮不更新 |
| 误以为 special 与 static 仍按同序号覆盖 | 已改为顺序追加;同槽特殊宏应直接写在 static 对应位置 |