脚本报错之后不要急着重装服务端。绝大多数错误在日志里已经写明了文件、行号和错误类型,按固定顺序排查,修改一到两个具体位置就能恢复。真正耗费时间的往往不是修复本身,而是在没有日志依据的情况下反复试错。
打开Mir200\Log目录,ScriptError.log是首要入口。M2控制台同时会输出格式接近的实时信息,典型写法是“文件名 Line 行号 错误描述”,例如QFunction-0.txt Line 56: Unknown command 'Gvie'。记录三样东西:文件名、行号、错误类型。错误类型通常落在Unknown command(命令拼写或引擎不识别)、Syntax Error(结构或符号问题)、File not found(路径或文件缺失)、变量未定义或类型不匹配这几类。拿到行号之后用Notepad++打开对应文件,开启行号显示,直接跳到该行,不要从文件开头逐行阅读。
语法结构错误占比最高,修法也最机械。检查报错行以及紧邻的上下三行:#IF、#ACT、#SAY是否各自独立成行,标签[@xxx]是否顶格书写,括号和引号是否闭合,中文全角逗号、分号、引号是否混入。命令拼写错误是最隐蔽的一类,GIVE写成GIV、CHECKGAMEGOLD少一个字母,引擎不会提示“拼写建议”,只会报Unknown command。对照当前引擎的命令表逐个字母核对,不要凭记忆。
#CALL路径错误有一个固定的检查点:路径起始不能带反斜杠。写成#CALL[\雇佣兵团\道士\天尊.txt]会直接触发参数格式错误,正确写法是#CALL[雇佣兵团\道士\天尊.txt],从文件夹名直接开头。同时确认#CALL指向的目标文件在对应目录中真实存在,文件名大小写一致。子脚本缺失不会总是给出直观提示,有时只表现为跳转后功能完全不执行,此时用资源管理器逐层进入目录核对比继续改语法更有效。
编码和换行符是“语法看起来全对但引擎就是读不进去”的常见原因。用Notepad++打开脚本,在编码菜单中转为ANSI保存,换行符设为Windows标准的CRLF。UTF-8带BOM的脚本在部分引擎中表现为加载失败或中文乱码,换行符为LF时行号可能与日志标注产生偏移,导致按行号定位反而找不到错误。修改编码后必须重启M2或执行重载,旧编码的缓存不会自动刷新。
变量报错分两种。未定义类报错在日志中通常直接给出变量名,局部变量需要在脚本开头用VAR声明,全局变量要在GlobalVar.txt中定义,临时变量无需声明但赋值格式必须正确。类型冲突类报错更隐蔽:数值变量被赋了字符串,或者字符串变量参与了数值比较,日志可能只写“类型不匹配”而不指出具体表达式。检查报错行附近所有赋值和比较语句,把数字和文本严格分开。变量名不要以P、D、M、N、S、I、G、A等引擎保留前缀开头,这类命名冲突在部分引擎中不报错但变量行为异常。
引擎命令差异在跨版本复制脚本时几乎必然出现。GOM的MAPMOVE在GEE中对应MOVETOMAP,MONSTER对应SPAWNMONSTER,ADDSTATE对应SETBUFF且GEE多一个显示类型参数。从其他版本拿来的脚本,先确认原脚本属于哪个引擎,再逐条对照当前引擎命令表替换。只改报错的那一行通常不够,同一脚本中同类命令往往批量出现,漏改一处就会在下一次触发时再次报错。
死循环不一定有语法报错,表现为服务端CPU占用升高、特定功能卡死或M2自动中断脚本执行。GOTO在两个标签之间反复跳转且没有break或退出条件是最常见的原因。把普通GOTO替换为带延迟的delaygoto,或者在setup.txt中设置ScriptGotoCountLimit限制最大跳转次数,可以阻止单次触发无限循环。更彻底的修法是梳理跳转链,确保每个被跳转的段落在执行完毕后有break断开,而不是依赖引擎的超时中断来兜底。
数据库和资源关联错误不会在语法层面报出来。脚本中GIVE的物品名与StdItems.DB不一致,物品不会进背包但脚本不报错;调用的地图编号在MapInfo.txt中不存在,传送命令静默失败;NPC脚本在MerChant.txt中被引用但Market_Def下没有对应文件,启动时表现为script error, load fail,报错路径会直接指向缺失位置。遇到“语法全对但功能就是不生效”的情况,把脚本中每一个物品名、地图号、NPC标识拿到对应配置文件中逐一比对,比继续修改逻辑更可能找到症结。
修复完成后不要直接在游戏内测试。M2控制台执行重载脚本或重载NPC,必要时先删除Mir200\Log\ScriptCache.dat再重启,避免旧缓存干扰。用新建角色走一遍触发流程,确认报错不再出现且功能行为符合预期。如果重载后同一行仍然报错,回到日志确认行号是否因编码转换或文件编辑发生了偏移,按新行号重新定位。

