|
一、称号的本质:一件穿在头上的特殊装备
理解 VV 引擎称号系统的第一步,是要意识到:称号本质上就是一件装备。
看 DB 字段就明白了。StdMode=70,这是称号物品的类型标识。除了几个称号特有的字段(Shape、Color、Reserved、Anicount、Looks、DuraMax),剩下的 "其他就等同于装备属性"。这句话很关键,它意味着称号可以像武器衣服一样带攻击、防御、血量等属性,引擎底层也是按装备属性那套逻辑来计算的。
把称号做成装备的好处是显而易见的。属性计算不用重新写一套,直接复用装备系统的逻辑;属性叠加、刷新、移除这些操作也和装备走同一个通道。文档里特意写了 "称号改变属性及时刷新",说明引擎在称号变化的时候会自动触发属性重算,不用你手动去调刷新接口。
但做成装备也有局限。装备的属性体系是固定的,攻魔道、防御魔御、血量蓝量这些,如果你想给称号加一些特殊效果(比如打怪经验加成、死亡不掉装备),就得靠其他系统配合,称号本身的 DB 字段里装不下这些。
所以我的理解是:VV 引擎的称号系统定位很明确 —— 就是一个带属性的头顶展示物,不追求做复杂功能,核心需求是显示 + 属性叠加,其他的交给脚本和触发去扩展。
二、显示控制:一个字段搞定三种模式
称号的显示是玩家能直接感受到的部分,VV 引擎用 Reserved 一个字段控制了三种显示模式。
默认是 0,显示称号名字加头顶图标。这是最常见的情况,称号叫 "君临天下",头顶上就显示这四个字,可能还配个图标。
设为 1 的时候,不显示数据库里的称号名字,但图标还在。这个设计的应用场景很明确 —— 有些称号的名字你不想直接显示,而是想用自定义的方式展示(比如通过脚本动态生成名字、或者用特效代替文字),但图标还是要保留的。
设为 2 的时候,名字和图标都不显示。这就是纯属性称号了,玩家拿到之后头顶上什么都不显示,但属性照常加。做隐藏称号、被动 buff 称号的时候用这个。
一个字段三个档位,覆盖了所有显示需求。这个设计不复杂,但很务实。很多引擎称号显示就是一个开关,要么显示要么不显示,想做 "只显示图标不显示名字" 这种效果就得改引擎。VV 引擎提前把这个需求考虑到了。
Color 字段控制称号名字的颜色,0 到 255。这个和人物名字颜色、聊天文字颜色走的是同一套色值体系,做称号的时候直接参考其他地方的颜色值就行,不用重新调色。
Looks 字段指定称号图片的开始位置,图片路径固定在 stab\res\private\title_icon。路径固定意味着称号素材有统一的存放位置,做资源管理的时候方便,不会到处乱放。但反过来,如果你想把称号图标放到别的目录,就做不到,路径是写死的。
三、Anicount:这个字段是整个称号系统最巧妙的设计
说实话,看到 Anicount 这个字段的说明的时候,我愣了一下。这个字段在普通装备里通常是动画计数之类的用途,但在称号系统里,它被赋予了一个完全不同的含义:
大于 0 时,无需设置为当前称号,属性就可以叠加到人物。等于 0 时,需要设置为当前称号,属性才会叠加。
这个设计解决了一个非常实际的问题:称号是只能戴一个,还是可以收集一堆全部生效?
传统的称号系统是单称号制,玩家只能选一个当前称号,只有当前称号的属性生效。但现在很多游戏喜欢做称号收集,每个称号都加属性,收集得越多战力越高。这两种模式需求完全不同。
VV 引擎用 Anicount 一个字段就把两种模式都支持了。
做单称号制的时候,所有称号的 Anicount 都设为 0。玩家只能选一个当前称号,只有选中的那个加属性。这是最传统的做法。
做收集制的时候,把称号的 Anicount 设为大于 0 的值。玩家拿到这个称号之后,不管设不设为当前称号,属性都自动叠加。玩家可以同时拥有几十个称号,属性全部累加。
更妙的是,这两种模式可以混合存在。比如普通称号设为 0(单称号制,选哪个哪个生效),特殊成就称号设为 1(拿到就永久加属性,不需要装备)。这样既有选择的策略性,又有收集的成就感。
这个字段的设计让我印象深刻,因为它不是靠加接口、加系统来实现两种模式,而是复用了一个已有的字段,通过值的含义来切换行为。用最小的改动满足了最大的需求,这就是好的设计。
四、时间系统:限时称号的处理逻辑
称号的时间控制靠 DuraMax 字段,单位是小时。这个字段在普通装备里是耐久上限,在称号里被借用来表示可用时长。
DuraMax 大于 0 的时候,称号有使用时间限制,到点自动失效。DuraMax 等于 0 的时候,称号无限期使用。
第一个细节:赋予新称号时,标注为未使用状态,激活后才开始计时。 这个设计很人性化。玩家通过活动拿到一个限时称号,如果拿到就开始计时,那玩家可能还没来得及用就过期了。改成 "激活后才计时",玩家可以选择什么时候开始用,体验好很多。
对应的, confertitle 接口有个 use 参数,传 1 就是添加时直接激活,不传或者传 0 就是只赋予不激活。这个参数正好对应了 "未使用状态" 的设计 —— 你可以先把称号发给玩家,等玩家自己点激活再开始计时。
第二个细节:时间到了之后称号是消失还是保留? 文档里没有明确说,但从 changetitletime 接口可以反推一些东西。这个接口可以加减时间、也可以直接设置时间戳,说明称号的到期时间是一个可修改的时间戳,存在玩家数据里。
我的推测是:时间到了之后,称号应该是自动取消(属性移除、显示移除),但称号记录可能还在。不然做 "过期称号续费" 功能就没法做了 —— 如果记录都删了,你怎么知道玩家曾经有过这个称号?
实际用的时候,限时称号的到期处理要自己测试确认。比如到期后 checktitle 还返回 true 还是 false, newgettitlelist 里还能不能查到,这些文档没写清楚的地方,一定要自己验证。
五、接口体系:增删查改的完整闭环
添加 用 confertitle,传玩家对象和称号名称,可选是否直接激活。返回 bool 告诉你成功还是失败。这里用名称而不是 ID 来操作,对脚本写作者更友好 —— 你不用去查称号的 ID 是多少,直接写 "君临天下" 就行。
删除 用 deprivetitle,同样是传名称。添加和删除的参数结构一致,学一个就会另一个。
检测 用 checktitle,传玩家和称号名,返回有没有。做称号门槛判断的时候用,比如 "拥有 XX 称号才能进入这个地图"。
获取列表 用 newgettitlelist,返回一个表,key 是称号 ID,value 是到期时间戳。这个接口的设计和前几个不一样 —— 它返回的是 ID 而不是名称,value 是时间戳而不是简单的 bool。
为什么列表用 ID 而不用名称?因为名称可能重复(虽然不应该),而且 ID 是数字,遍历和处理效率更高。拿到 ID 之后可以用 getstditeminfo 去查名称,文档里的示例就是这么做的。
value 是时间戳这个设计也很实用。你拿到列表之后,不仅知道玩家有哪些称号,还知道每个称号什么时候到期。做称号面板的时候,直接显示到期时间,不用再单独查。
修改时间 用 changetitletime,支持加、减、直接设置三种操作。加和减传秒数,直接设置传时间戳。做称号续费、活动延长称号时间、惩罚性扣除称号时长这些功能的时候用。
五个接口覆盖了称号生命周期的全部操作:发称号、收称号、查称号、列称号、改时间。没有遗漏,也没有冗余。
六、触发回调:称号变化的事件钩子
称号系统有两个触发: titlechangedex 和 untitledex,分别在称号改变和取消时触发。
这两个触发的存在,意味着称号系统不是封闭的,你可以在称号变化的时候插入自定义逻辑。
比如玩家获得了一个特殊称号,你想在获得的时候全服公告、给个特效、发个邮件奖励,这些逻辑不用写在 confertitle 调用的地方,而是挂在 titlechangedex 触发里。这样不管称号是通过 NPC 给的、还是活动奖励给的、还是 GM 命令给的,只要称号变了,你的自定义逻辑都会执行。
这就是事件驱动的好处。添加称号的入口可能有很多个,但触发只有一个。把逻辑挂在触发上,就不会漏。
两个触发都传 titleIdx 参数,告诉你是哪个称号变了。注意这里用的是索引(Idx)而不是名称或 ID,这个索引具体指什么文档没说,可能是称号在玩家称号列表里的位置索引,也可能是 DB 的 Shape 编号。实际用的时候要打印出来确认一下,不要想当然。
七、实际使用中的心得与坑
把称号系统从头到尾过了一遍,结合实际可能的使用场景,总结几个心得。
第一,称号命名要规范。 因为添加、删除、检测都是靠名称来操作的,名称就是唯一标识。如果两个称号叫同一个名字,脚本就分不清了。建议称号名称在 DB 里唯一,而且不要用太生僻的字,脚本里写起来方便。
第二,Anicount 的设计要提前规划。 哪些称号是收集制(拿到就加属性),哪些是单称号制(选了才加),要在做 DB 配置的时候就定好。不要一半一半乱设,不然玩家会困惑 —— 为什么有的称号不装备也加属性,有的必须装备?给玩家一个一致的预期很重要。
第三,限时称号的激活时机要想清楚。 confertitle 的 use 参数决定了是立即激活还是先存着。如果是活动奖励的限时称号,建议先不激活,让玩家自己选什么时候开始用。如果是 VIP 之类的持续权益,就直接激活,从获得那一刻开始计时。两种场景用不同的策略。
第四,称号属性变化是自动刷新的,但显示变化不一定。 文档说了 "称号改变属性及时刷新",说明属性计算引擎会自动处理。但头顶上的称号名字、图标、颜色这些显示部分,切换称号的时候客户端会不会自动刷新,要实测。如果不刷新,可能需要手动推一下消息或者让玩家小退。
第五,删除称号和称号到期是两回事。 deprivetitle 是主动删除,到期是系统自动取消。这两种情况会不会都触发 untitledex?文档没说。如果你的逻辑依赖这个触发,就要两种情况都测试,不要假设行为一致。
第六,称号列表的时间戳要注意时区和格式。 newgettitlelist 返回的 value 是时间戳,用 os.date 可以转成可读时间。但要注意服务端的时区设置,转出来的时间可能和玩家本地时间有差异。显示给玩家的时候最好转成当地时间。
第七,称号的图片素材要按规范放。 Looks 字段是图片开始位置,路径固定在 title_icon 目录下。做称号素材的时候,图片编号要连续、要和 Looks 对应,不然显示出来是错的或者空白。建议做一个称号素材对照表,Looks 值和图片一一对应,避免混乱。
|