fix(set_controls_keyo): verify the active build's skills, not a hardcoded list

SKILL_KEYS was a fixed Paladin list read via Config().char.get(). Build skills
live in their own sections ([hammerdin], [blizz_sorc], [sorceress]), not [char],
so that lookup returned empty for all of them and they were never checked.

In practice the tool only ever verified 3 keys — teleport, battle_orders and
battle_command — for every build. A hammerdin's blessed_hammer/concentration/
redemption/vigor/conviction/holy_shield went unverified, and a sorc got no
build coverage at all (blizzard, ice_blast, static_field, energy_shield,
telekinesis all silently skipped).

Derive the list from skill_preflight.get_build_skill_checks() instead, which
already resolves each build's skills out of the right config section, and keep
[char]-level keys (teleport, town_portal) alongside. battle_orders/
battle_command are now gated on cta_available so a character without a Call to
Arms doesn't report two permanent false "unbound" entries.

Also print the build alongside the file so it is obvious what is being checked.

Verified against two real .keyo files:
  hammerdin (fistman) — 10/10 keys ok, was reporting only 3
  blizz_sorc (ding)   —  7/7 keys ok, was reporting only 1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
alexpolo1
2026-08-22 08:21:44 +02:00
parent aa48c29df8
commit 28b7c210d8

View File

@@ -29,8 +29,40 @@ from utils.key_detector import VK_MAP
NAME_TO_VK = {v: k for k, v in VK_MAP.items() if k < 256}
SKILL_KEYS = ["blessed_hammer", "concentration", "redemption", "vigor",
"conviction", "holy_shield", "teleport", "battle_orders", "battle_command"]
# Keys that live in [char] for every build. battle_orders/battle_command are
# CTA-only and are skipped unless cta_available is set, so a character without a
# Call to Arms does not report two permanent false "unbound" entries.
COMMON_SKILL_KEYS = ["teleport", "town_portal"]
CTA_SKILL_KEYS = ["battle_orders", "battle_command"]
def wanted_skill_keys() -> dict:
"""Map cfg_key -> key name for every skill the ACTIVE BUILD puts on the bar.
Build-specific skills are taken from skill_preflight, which already resolves
them out of the build's own config section ([hammerdin], [blizz_sorc],
[sorceress], ...). Hardcoding a single build's skill list here meant a sorc
was only ever checked for [char] keys, so blizzard/ice_blast/static_field
were silently never verified.
"""
cfg = Config()
wanted = {}
try:
from utils.skill_preflight import get_build_skill_checks
for check in get_build_skill_checks(cfg):
if check.hotkey:
wanted[check.skill] = check.hotkey
except Exception as exc:
print(f"warning: could not load build skill list ({exc}); checking [char] keys only")
common = list(COMMON_SKILL_KEYS)
if cfg.char.get("cta_available"):
common += CTA_SKILL_KEYS
for cfg_key in common:
key_name = str(cfg.char.get(cfg_key, "")).strip().lower()
if key_name:
wanted.setdefault(cfg_key, key_name)
return wanted
HEADER = 4
ENTRY = 10
@@ -80,13 +112,10 @@ def main():
skill_slot_by_vk = {e[1]: e[4] for e in entries if e[2] == 1 and e[1] != UNBOUND_VK}
free = [i for i, e in enumerate(entries) if e[2] == 1 and e[1] == UNBOUND_VK]
wanted = {}
for cfg_key in SKILL_KEYS:
key_name = str(Config().char.get(cfg_key, "")).strip().lower()
if key_name:
wanted[cfg_key] = key_name
wanted = wanted_skill_keys()
print(f"keyo: {path}")
print(f"build: {Config().char.get('type', '?')}")
missing = []
for cfg_key, key_name in wanted.items():
vk = NAME_TO_VK.get(key_name)