0x00 前言
还记得我最早接触 RO 的时候,国内的版本是「樱之花嫁」,那时就是 SMM 在做代言的,每个城市都有一个 SMM 的 NPC 角色形象帮玩家免费回血。
但后面 SMM 不再代言之后,这个福利也被取消了。
当我想扒拉出来怀旧的时候,却发现即使翻遍现在任何一个官方运营的 GRF,对应的 NPC 图档也被彻底删除了。
机缘巧合之下,我拿到了 SMM 的图档文件 4_f_son.act 和 4_f_son.spr:

本篇就以此为例讲解一下怎么添加自定义的 NPC 。
0x10 在服务端添加 NPC 脚本
首先我们需要实现一个简单的 NPC 脚本,功能其实很简单: 走近 SMM 附近 5x5 的范围内自动回血。
prontera,146,95,6    script    孙燕资#prt    777,5,5,{
    cutin "4_f_son", 2;
    // 和 NPC 对话可额外获得 BUFF(可选)
    callfunc("F_HEALER_PLUS");
    cutin "", 255;
    close;
    end;
// 走近 NPC 5x5 范围内时触发自动回复
OnTouch:
    npctalk "我是音乐精灵孙燕资 ~";
    specialeffect2 EF_HEAL2;            // 治愈效果
    soundeffect "pokemon_heal.wav", 0;    // 治愈音效
    percentheal 100, 100;    // 回复 HP/SP
    healap 200;                // 回复 AP
    sleep2 3000;
    npctalk "我可以用音乐治愈你的心灵哦 ^0^";
    emotion ET_SMILE;
    end;
}代码很简单,而且我做了注释、就不过多解释了,相关语法在 doc/script_commands.txt 都可以找到。
里面涉及 NPC 图档的只有两个地方:
- NPC 图档: 第一行的 777,其实是在 NPC 外观池中声明的自定义 ID
- NPC 立绘(可选): cutin "4_f_son", 2;,其中4_f_son就是立绘文件名
其中针对 NPC ID,在 rAthena 的源码 src/map/npc.hpp 中定义了若干个范围:
#define npcdb_checkid(id) ( ( (id) > NPC_RANGE1_START && (id) < NPC_RANGE1_END ) || (id) == JT_HIDDEN_WARP_NPC || ( (id) > NPC_RANGE2_START && (id) < NPC_RANGE2_END ) || (id) == JT_INVISIBLE || ( (id) > NPC_RANGE3_START && (id) < NPC_RANGE3_END ) )具体数值为:
- 范围一:- NPC_RANGE1_START = 44
- NPC_RANGE1_END = 126
 
- 范围二:- NPC_RANGE2_START = 400
- NPC_RANGE2_END = 1000
 
- 范围三:- NPC_RANGE3_START = 10000
- NPC_RANGE3_END = 20000(rAthena)
- NPC_RANGE3_END = 23001(Pandas)
 
如果自定义 NPC ID 不在这三个范围内,启动时就会报错: status_set_viewdata (NPC): Invalid view data

如果希望增加 ID 范围,需要修改
npc.hpp,然后重新编译服务端
0x20 在客户端添加 NPC 图档
0x21 添加 NPC 图档
参考《客户端目录结构及功能说明(2024 修订)》,NPC 图档目录为 data/sprite/npc。
我们把 4_f_son.act 和 4_f_son.spr 两个文件放进去这个目录下:

然后修改 NPC 外观池:
- 定义「NPC 唯一代码」和「NPC ID」的关系: data/luafiles514/lua files/datainfo/npcidentity.lub
- 定义「NPC 唯一代码」和「NPC 图档名称」的关系: data/luafiles514/lua files/datainfo/jobname.lub
在 npcidentity.lub 中添加一行:
    JT_4_F_SMM = 777在 jobname.lub 中添加一行:
    [jobtbl.JT_4_F_SMM] = "4_f_son",此时进入游戏就可以看到 SMM 了:

看过《添加自定义魔物》的同学应该了解到,NPC 外观池是和魔物外观池共用的。在早期,小于 1000 的 ID 是预留给 NPC 使用的,大于 1000 则都是魔物。但随着官方的 NPC 越来越多,现在基本已经没有这个约定了,你完全可以用魔物 ID 当 NPC 用。
但是特别需要注意的是,如果某一天你发现所有 NPC 的形象都变成波利了,是因为至少存在一个写在 jobname.lub 的 NPC 代码,没有在 npcidentity.lub 中定义:

0x22 添加 NPC 立绘(可选)
所谓的立绘就是和 NPC 对话时、才会出现在画面中的 NPC 形象:

立绘图片的要求很简单:
- 立绘图片可以网上搜索、PS 修改即可
- 格式要求为 bmp
- 希望游戏中显示为透明的部分,可将其设置为粉红色 FF00FF
- 图片要放到 data/texture/蜡历牢磐其捞胶/illust目录下

如这里立绘图档名字为 4_f_son.bmp,只需要在服务端 NPC 脚本中使用 cutin "4_f_son", 2; 即可把立绘召唤出来(2 是召唤立绘的位置,详见 doc/script_commands.txt)。
0x30 效果
至此自定义 NPC 就添加成功了,看一下效果:
 
                     
                     
                     
                        
                        