godofcong-1/erark/draw-aa-map

Claude Code and agent skill by godofcong-1/erark

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

创建或调整 erArk 的 AA 地图(data/map/*/Map),包括给区块新增房间、重排整张版面、修正竖墙错位。当需要画地图/改地图/加房间,或玩家反馈地图显示歪掉、排版错乱时使用。

Install

npx vskill@latest install godofcong-1/erark/draw-aa-map

SKILL.md

Skill Instructions

你是 erArk 的 AA 地图排版助手。完整原理说明见 地图系统 的「AA 地图排版」一节。

第零步:先记住这条铁律

AA 地图的排版由字体的实际字宽决定,不是由 `wcwidth.wcswidth` 决定。

MapDrawLine.width 走 Script/Core/text_handle.py:65 get_text_index()(即 wcswidth),但它不参与行内排版。see_map_panel.py:97-109 只用全局 max_width 算出一个所有行共用的居中空格前缀,之后逐段原样输出,不做任何裁剪或补齐。因此行内对齐 100% 由字体字宽决定。

永远不要用"数列数"的方式判断对齐——这正是历史上重画后实机仍然歪掉的原因。必须用 tools/map_aa_check.py 按像素校验。

核心模型:U 单位

在 等距更纱黑体 SC 下字符分成两个互不通约的度量族:

度量族代表字符字号 20 下
框线族═ ║ │ ┃ ┄ ┅ ┆ ┇ ─ ━、▓ ♂ ♀ ¤ ▁、U+200213 px
框线族(全角)汉字、○ ● □ ▣ ♲ ◎ ◇、- ~ ← → ↗ ↘26 px
ASCII 族ASCII 空格、~、-、数字、字母14 px
ASCII 族(双宽)☸ ➷ ➹ ✪28 px

两族在字号 18/22/24/26/30 下碰巧同宽,在 14/16/20/40 下不同宽。当前 config.ini 反算出的字号正好是 20(font_size = int(window_width / text_width) * 2 = int(2000/190)*2),所以每出现一个 ASCII 空格就相对框线漂移 1px。

令 U = 框线字符宽度,只用恒为 1U / 2U 的字符即可在任意字号下对齐:

宽度可用字符
1U框线 ═ ║ │ ┃ ┄ ┅ ┆ ┇ ─ ━、▓ ♂ ♀ ¤ ▁、U+2002 EN SPACE(留白)、≈ ∼ ∽ ⊙ ⊕
2U汉字、○ ● □ ▣ ♲ ◎ ◉ ◍ ◇ ◈、~ 〜 ﹏ ⌒、← → ↗ ↘ ↖ ↙、- _ < >、U+3000
禁用ASCII 空格、~、-、数字字母、☸ ➷ ➹ ✪

留白一律用 U+2002 EN SPACE 替代 ASCII 空格,这是消除大范围错位的关键。

U+2002 与普通空格肉眼完全一样,手抄/复制粘贴极易被静默换回 ASCII 空格。因此这类地图必须由脚本生成,绝不可手改 `Map` 文件。

实施步骤

第一步:摸清现状
bash
python tools/map_aa_check.py <地图名> # 看这张图当前错位多少
python tools/map_aa_check.py --list-bad # 看全部地图的错位排名

同时读一遍目标 data/map/<区块>/Map 与 Map.json,弄清现有房间的相对位置与连通关系。参考画得比较规整的 data/map/仓储/Map、data/map/疗养庭院/Map。

第二步:设计列规划(用 U 数,不是字符数)

先把版面写成一张列规划表再动手,例如:

text
上排 0 ┃ 健身区上 26U ┃27 木桩房 18U ┃46 射击房 8U │55 靶道 32U ┃88
走廊 健身区@11U 走廊@46U 入口0@88U
下排 0 ┃ 健身区下 26U ┃27 模拟对战室 18U ┃46 休息室 12U ┃59 更衣室 8U ┃68 淋浴 6U ┃75 游泳池 12U ┃88

要点:

  • 上下排尽量共用竖墙列位,观感更整齐。
  • 每个房间格的内容宽度 = 该格的 U 数;汉字算 2U,框线/留白算 1U。
  • 门(可通行)用虚线 ┄ / ┆,实墙用 ═ / ║,必须与 `Map.json` 的 `PathEdge` 一致。
  • 总宽必须 ≤ text_width(190),否则 Tk 会按字符软换行、整张图崩坏。
第三步:写生成脚本

不要手写 `Map` 文件。 以 tools/map_aa_build_training.py 为模板新建生成脚本,按 U 数拼装:

python
S = " " # EN SPACE = 1U,替代 ASCII 空格
E = "═"
rest = [ # 休息室 12U
S + "▓¤" + S * 6 + "¤▓" + S, # 1+2+6+2+1 = 12U
S * 12,
S * 3 + "<mapbutton>休息室</mapbutton>" + S * 3, # 3+6+3 = 12U
S * 12,
]
# 整行 = ║ + 26U + ║ + 18U + ║ + 12U + ║ + 8U + 门 + 6U + 门 + 12U + ║ = 89U
open("data/map/<区块>/Map", "wb").write("\r\n".join(lines).encode("utf-8"))

脚本必须在写入前自检三件事,任一不满足就报错退出、不写文件:

  1. 每个含竖墙的行 U 数一致
  2. 全图不含 ASCII 空格
  3. 不含裸 <...>(会被富文本正则吞掉)

文件格式:UTF-8 无 BOM + CRLF + 末尾无换行。

第四步:像素校验(必做)
bash
python tools/map_aa_check.py <地图名> # 容差 0
python tools/map_aa_check.py <地图名> --tol 2 # 明知有小偏差时

它会在 10 个字号下逐字符累加像素位置,检查各竖墙行的总宽与每堵墙的位置是否一致,超差会指出具体哪行哪堵墙差多少,并以非零退出码结束。

期望:每个字号下含竖墙的行总宽只有一个值。

第五步:若同时新增了场景,补两个数据文件
  1. 新建 data/map/<区块>/<房间名>/Scene.json——照抄同类场景,字段含义见 地图系统.md。目录名必须与 <mapbutton> 里的名字完全一致,否则 map_handle.py:363 会无限递归抛 RecursionError。
  2. data/map/<区块>/Map.json 的 PathEdge 加双向边。

通常不需要改任何 CSV、po 或 Python:constant.place_data 由 SceneTag 自动生成。

第六步:重建缓存(必做,否则改动 100% 不生效)

map_config.init_map_data() 只判断四个缓存文件是否全部存在,没有任何 mtime/hash 校验,不删缓存就完全不生效且无任何报错:

bash
rm -f data/SceneData data/MapData data/PlaceData data/ScenePath
python init_data.py # 530 场景 O(N²) 全量寻路,会跑一会儿,产出 ~21MB
第二层缓存:save_handle.py:496-516 只在场景增删或 scene_tag/scene_img/room_area 变化时才刷新存档里的 map_data。只改 AA 图而不动 `Scene.json` 时,老存档读出来仍是旧地图,必须用新档验证。
第七步:收尾
  • update.log 加一行(新增房间记「新增:(地图)…」,重排版面记「调整:(地图)…」)
  • 若改动较大,在 plan/ 下留实施记录,可参考 plan/done/plan_01_训练场新增休息室.md

陷阱速查

陷阱依据
<mapbutton> 标签零宽,只有中间的名字参与排版map_config.py:199
行尾空白被 str.rstrip() 吃掉,包括 U+2002——别靠行尾补齐map_config.py:243
行首公共空格被裁,但只认 ASCII 空格(lstrip(" ")),U+2002 不受影响map_config.py:246
裸 <...> 会被 re.sub(r"<[^>]+>","") 静默吞掉;要画尖括号用全角 <>rich_text.py:233
未闭合的 <mapbutton> 会让该按钮及本行后续文本静默丢失map_config.py:203
按钮名 ≠ 子目录名 → RecursionError,不是友好报错map_handle.py:363
有 Map.json 就必须有同目录 Map,否则 FileNotFoundErrormap_config.py:90
_pad_map_lines_to_max_width() 是死代码,从未被调用map_config.py:345

常见取舍

  • 想保留某个 ASCII 族字符(如 ➷➹ 的观感):可以,但要把它放在最右侧的格子里,这样左侧所有竖墙不受影响,只有该行最右端偏移 2px;然后用 --tol 2 校验并在文档里写明确切代价。
  • 场景名是数字(如入口 0):无法改(是目录名)。把它放在没有竖墙的标签行上即可,不产生可见错位。
  • 想给新房间加等级门禁:Facility_open.csv 是按 `SceneName` 匹配的,加进去会连坐所有同名场景(项目里有 9 个"休息室")。需要单独门禁必须起独立 SceneName。

完成前自查

  • [ ] tools/map_aa_check.py <地图名> 通过(或在已知容差内通过,且代价已写进文档)
  • [ ] 全图无 ASCII 空格
  • [ ] 每个 <mapbutton> 的名字都能对应到同级子目录
  • [ ] Map.json 的 PathEdge 与 AA 图上画的门一一对应,且是双向边
  • [ ] 四个缓存已删除并重建,init_data.py 无报错
  • [ ] 生成脚本已保留在 tools/ 下,便于以后再改

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/godofcong-1/erark/draw-aa-map/badge)](https://verified-skill.com/skills/godofcong-1/erark/draw-aa-map)

Something wrong with this skill or its page? Tell us.