13674307070 发表于 2026-8-21 08:10:42

杂项工具集是 VV 引擎的 "百宝箱"

一、基础信息读写:一个 ID 通吃所有属性的设计哲学
GetBaseInfo 和 setbaseinfo 是这组工具里最重要的两个接口,也是整个 VV 引擎里使用频率最高的接口之一。它们的设计思路非常统一 —— 用一个数字 ID 来标识要读写的属性,传不同的 ID 就能读写完全不同的信息。

GetBaseInfo 支持的 ID 从 - 1 到 75,覆盖了对象的方方面面:

基础身份类:ID=-1 是否玩家、ID=0 是否死亡、ID=1 对象名称、ID=2 唯一 ID、ID=3 地图 ID、ID=4/5 坐标、ID=6 等级、ID=7 职业、ID=8 性别。这些是最常用的,几乎每个脚本都会用到。

战斗属性类:ID=9/10 血量和上限、ID=11/12 蓝量和上限、ID=13/14 经验和上限、ID=15-24 攻防道的上下限(物防、魔防、物攻、魔攻、道攻各两个)、ID=25 幸运值、ID=26-30 恢复和躲避类属性(HP 恢复、MP 恢复、中毒恢复、毒物躲避、魔法躲避)、ID=32 敏捷。

人物专属类:ID=33 发型、ID=34 背包物品数量、ID=35 队伍成员数量、ID=36 行会名、ID=37 是否会长、ID=38 宠物数量、ID=39 转生等级、ID=40/41 杀怪经验倍数和时间、ID=42 召唤延时、ID=43 爆率倍数、ID=46PK 点、ID=47 是否新人、ID=49 是否摆摊、ID=50 是否交易、ID=53 登录状态、ID=58 时装显示、ID=61 离线挂机、ID=63 背包大小、ID=73 仓库大小、ID=74 宠物背包大小、ID=75 当前称号。

怪物 / 通用类:ID=44 复活时间、ID=45 地图名、ID=48 是否安全区、ID=51 自定义 att 属性值(需要参数 3 传属性 ID)、ID=52 穿人穿怪方式、ID=54 主人 UserId、ID=55Idx、ID=56 颜色、ID=57 最后杀死的怪物 Index、ID=59 主人对象、ID=60 是否攻沙区域、ID=62 怪物表自定义常量、ID=64 身体颜色、ID=65 回城地图、ID=67 攻击对象、ID=68 怪物归属、ID=69 方向、ID=70/71 施毒对象、ID=72 吉运值。

七十五个 ID,覆盖了玩家和怪物几乎所有可读属性。 setbaseinfo 支持的 ID 少一些(大概四十个左右),因为不是所有属性都能设置 —— 比如名称、唯一 ID、坐标这些不能随便改,攻防血蓝这些可以改。

这种 "一个接口 + 数字 ID" 的设计,在 VV 引擎里非常普遍。它的好处是接口数量少、扩展性强—— 不需要为每个属性写一个 get/set 接口,新增属性只需要加一个 ID 号,接口本身不用变。七十五个属性如果每个都写一个接口,那就是一百五十个接口,光记名字就疯了。用 ID 的方式,只需要记两个接口名(GetBaseInfo/setbaseinfo)和常用的 ID 号,其他的查文档就行。

但这种设计也有代价 ——可读性差。看到 GetBaseInfo(actor, 36) 你不知道是取什么,得查文档才知道是行会名。而且 ID 号是纯数字,没有语义,写错了 ID 号不会报错(可能返回 0 或空),排查起来比较麻烦。

实际开发中的心得是:把常用的 ID 号定义成常量或注释。比如在脚本开头写 local GUILD_NAME = 36,后面用 GetBaseInfo(actor, GUILD_NAME),可读性就好多了。或者至少在调用处加注释 -- 36=行会名。不要直接写裸数字,过几个月自己都不记得是什么意思。

还有一个细节:ID=1(对象名称)对怪物有特殊处理,param3 参数控制返回哪种名字 ——0/nil 返回显示名(去除尾部数字)、1 返回怪物表默认名、2 返回实际展示名。这个设计是因为怪物可能有重名(比如 "稻草人 1"" 稻草人 2"),不同场景需要不同的名字格式。做怪物相关逻辑时注意选对 param3。

二、对象类型判断:五个 is 接口让你认清对象真身
在传奇脚本里,你拿到一个对象(比如技能目标、攻击来源、附近的单位),经常需要判断它到底是什么 —— 是玩家、怪物、宝宝、还是人形怪?不同的类型处理逻辑完全不同。

VV 引擎给了五个判断接口:

isnotnull 判断对象是否存在。这是最基础的,拿到对象后先判断是否为 null,再做其他操作,不然访问 null 对象的属性会报错。

isplayer 判断是否为玩家。文档里特别注明 "系统对象为 0 号玩家,所以也会返回 true"—— 这个细节很重要,系统对象(比如定时器回调里的 sysobj)用 isplayer 判断也会返回 true,如果你需要区分真实玩家和系统对象,不能只靠 isplayer,还要结合其他判断(比如对象名称、是否有玩家属性等)。

ismon 判断是否为怪物。普通怪物用这个判断。

ismob 判断是否为宝宝。宝宝是被玩家收服的怪物,本质上是怪物但有主人,所以需要单独判断。

isplaymon 判断是否为人形怪。人形怪是一种特殊怪物,长得像玩家,有装备有职业,行为也更接近玩家。人形怪在传奇里很常见(比如假人、守卫、BOSS 人形化),需要和普通怪物区分开。

五个接口的设计思路是分层判断:先判断是否存在(isnotnull),再判断大类别(isplayer/ismon),再判断细分类别(ismob/isplaymon)。宝宝和人形怪都是怪物的子类,所以 ismon 对它们也返回 true,需要用 ismob 和 isplaymon 进一步区分。

实际使用中的心得是:判断顺序要从特殊到一般。如果你要区分玩家、宝宝、人形怪、普通怪物,先判断 isplayer,再判断 ismob,再判断 isplaymon,最后剩下的是普通怪物。不要先判断 ismon—— 因为宝宝和人形怪 ismon 也返回 true,会被误判成普通怪物。

还有一个容易踩的坑:英雄和分身的类型判断。文档里没有明确说英雄和分身用哪个接口判断,可能 isplayer 返回 true(因为它们本质上是玩家类对象),也可能有其他判断方式。实际开发中遇到英雄和分身时,先测试确认它们的类型判断结果,不要想当然。

三、状态系统:中毒、麻痹、冰冻,一套接口管状态生老病死
状态系统是传奇战斗的核心组成部分 —— 绿毒掉血、红毒降防、麻痹不能动、冰冻不能操作,这些状态影响着战斗的节奏和策略。VV 引擎的状态系统有一组接口,覆盖了状态的添加、检测、清除、时间管理。

添加状态用 makeposion,支持的状态 ID 包括:0 = 绿毒、1 = 红毒、3 = 紫毒、5 = 麻痹、12 = 冰冻、13 = 冰封。传对象、状态 ID、持续时间,绿毒还可以传威力和施毒者对象。

这个接口的名字叫 makeposion(poison 的变体),但实际上不只是中毒 —— 麻痹、冰冻这些控制状态也用这个接口添加。说明在引擎的设计里,这些战斗状态都归在 "poison" 这个大类下,统一管理。

检测状态用 checkhumanstate,支持的状态类型更多:1 = 魔法盾、2 = 护体神盾、3 = 无极真气、4 = 幽灵盾、5 = 神圣战甲术、6 = 隐身术、7 = 冰冻、8 = 麻痹、9 = 锁定、10 = 蛛网、11 = 中毒、12 = 禁止行为。

这个接口和 makeposion 的区别是:makeposion 是添加状态的,checkhumanstate 是检测状态的,而且检测的状态种类更多 —— 不仅包括毒和控制,还包括技能 buff(魔法盾、护体神盾等)和禁止行为。

checkhumanstate 有两个返回值:第一个是是否存在该状态(bool),第二个是剩余时间(秒)。但文档里注明 "禁止行为无法获取剩余时间"——type=12 时只有一个返回值。

中毒检测(type=11)需要额外传毒类型参数:0 = 全毒、1 = 绿毒、2 = 红毒、3 = 脚本绿毒、4 = 脚本红毒。这里区分了 "普通毒" 和 "脚本毒"—— 脚本毒是通过脚本接口添加的毒,和技能毒分开管理。做解毒逻辑时要注意,不要只解普通毒忘了脚本毒。

禁止行为(type=12)是一个很强大的功能,支持 8 种禁止:1 = 禁止走、2 = 禁止跑、3 = 禁止攻击、4 = 禁止施法、5 = 禁止使用物品、6 = 禁止说话、7 = 禁止飞、8 = 锁血。这些禁止行为可以组合使用(应该是位掩码,多个禁止求和),实现精细的行为控制。做特殊场景(比如剧情演出、新手引导、惩罚机制)时非常有用。

解毒 / 清除状态有两个接口: detoxifcation 解除指定状态(支持 - 1 解所有毒、0 绿毒、1 红毒、2 麻痹、3 冰冻、4 蛛网、5 脚本绿毒、6 脚本红毒), clearstate 清除所有状态。

状态时间管理有 setstatetime 和 getstatetime,可以设置和获取指定状态的剩余时间。这两个接口支持的状态 ID 和 detoxifcation 一致(绿毒、红毒、麻痹、冰冻、蛛网、脚本毒)。做状态延长、状态刷新、状态倒计时显示时用这两个接口。

状态系统的设计思路是:添加用 makeposion、检测用 checkhumanstate、清除用 detoxifcation/clearstate、时间用 setstatetime/getstatetime。四个操作各司其职,虽然接口名不统一(有的叫 poison 有的叫 state),但功能覆盖是完整的。

实际使用中的心得是:注意区分 "技能状态" 和 "脚本状态"。技能添加的毒和脚本添加的毒是分开的,检测和清除时要选对类型。还有,makeposion 能添加的状态种类比 checkhumanstate 能检测的少 —— 比如魔法盾、隐身术这些技能 buff 不能用 makeposion 添加,只能通过技能释放来添加。不要试图用 makeposion 添加所有状态,它只支持毒和控制类。

四、文本与常量处理:parsetext 和 GetConst,告别手动拼接
在传奇脚本里,给玩家发消息、显示面板、写日志,经常需要把变量和常量拼接到文本里。传统的写法是用 Lua 的字符串拼接("您的名字是:"..name..",等级是:"..level),变量多了之后拼接又长又乱。

VV 引擎给了两个工具来简化这个问题。

parsetext 可以直接替换传奇脚本里的标记符。传一段包含 <$变量名> 标记的文本和玩家对象,它会自动把标记替换成对应的常量值。比如文本是 "您的名字是:<$Name>,等级是:<$Level>",parsetext 会自动把 <$Name> 换成玩家名字、 <$Level> 换成等级,返回替换后的完整文本。

这个接口的设计思路是:把文本模板和数据分离。你写好带标记的文本模板,parsetext 负责把标记替换成实际数据。这样做的好处是文本可读性好 —— 你能直接看到文本的完整结构,不需要在一堆 .. 拼接里找变量。而且如果需要改文本,只改模板就行,不需要动拼接逻辑。

文档里说 "如果 say 面板里有很多变量需要取,不想自己挨个取,可以直接调用此方法处理文本"—— 这正是 parsetext 的典型使用场景。面板文本里变量多的时候,手动拼接太痛苦,用 parsetext 一行搞定。

GetConst 是获取单个常量的值。传玩家对象和常量名(支持 <$Name> 或 $Name 两种格式),返回常量值。这个接口和 parsetext 的区别是:parsetext 处理整段文本替换所有标记,GetConst 只取一个常量的值。如果你只需要一个常量值,用 GetConst;如果需要把多个变量拼到文本里,用 parsetext。

这两个接口的存在,说明 VV 引擎在文本处理上做了贴心的封装 —— 传奇脚本里常量和标记的使用频率非常高,手动拼接既繁琐又容易出错,封装成接口后开发效率提升很多。

实际使用中的心得是:面板文本和长消息优先用 parsetext,不要手动拼接。短文本只有一两个变量的话拼接也可以,但变量超过三个就建议用 parsetext,可读性和维护性都好很多。另外,parsetext 支持的标记范围要确认 —— 不是所有变量都能通过 <$xxx> 标记获取,只有引擎预定义的常量才行。自定义变量可能需要先设置成常量或者手动拼接。

五、实用小工具:那些看似不起眼但离不了的接口
这一组接口都是单一功能的小工具,每个只做一件事,但在实际开发中使用频率很高。

gohome 把玩家传送到最近经过的城市安全区。这个接口的设计很贴心 —— 不是传送到固定的回城点,而是 "最近经过的城市",意味着引擎会记录玩家经过的城市,回城时回到最近的那个。做回城卷、回城技能时直接调这个接口就行,不需要自己判断玩家在哪个地图该回哪。

setautogetexp 在线泡点经验。这个接口的参数很丰富:间隔时间、每次经验、是否安全区、地图号、聚灵珠是否能获取、总泡点时间、等级限制。基本上泡点功能需要的所有维度都覆盖了 —— 在哪泡、泡多久、给多少经验、什么条件才能泡。做安全区挂机、活动地图泡点、VIP 泡点等功能时,这个接口一个就能搞定,不需要自己写定时器加经验。

PlaySound 播放音乐声音。支持播放给自己、全服、同地图、同屏四种范围,支持循环播放次数。做技能音效、活动背景音乐、BOSS 出场音效时用。声音 ID 对应 SoundConfig.xls 配置表,不是直接传文件名。

stop 停止执行。这个接口比较特殊,它可以停止当前正在执行的某些操作 —— 文档里列了 canopenbox、stdmodefunc、updateguildnotice、getexp、triggerchat、magselffunc(合击技能)。典型用法是在物品使用触发里判断条件,如果不满足就 stop,阻止物品效果生效。这个接口相当于 "中断当前操作",做条件判断拦截时很有用。

md5str MD5 加密。传字符串返回 MD5 值。做密码加密、签名验证、数据校验时用。虽然 MD5 现在不算最安全的加密方式,但在游戏里做简单的校验和签名还是够用的。

randomsplit 等概率或按权重随机获取分割字符串。这个接口功能比较强大 —— 传一个用 | 分隔的字符串,每个选项可以带 #权重,它会按权重随机选一个返回,同时返回剩余的字符串。支持两种随机模式(等概率 / 按权重)和四种返回格式(是否显示权重数字)。做随机抽奖、随机奖励、随机事件时用这个接口,不需要自己写权重随机算法。

mircopy 客户端复制。把文本复制到玩家客户端的剪贴板。做兑换码复制、信息分享时用 —— 玩家点一下按钮就把兑换码复制到剪贴板,不需要手动选中复制,体验好很多。

openwebsite 游戏中打开网站。在游戏客户端里打开指定网页。做官网链接、活动页面、充值页面时用,玩家不需要切出游戏打开浏览器,直接在游戏里就能看。

这些小工具的共同特点是:单一职责、参数简洁、即拿即用。每个接口只做一件事,但做得完整 —— 需要的参数都给了,不需要你自己补逻辑。在开发中遇到对应的需求,直接调就行,不用自己造轮子。

六、扩展库:sqlite 和 iconv,给脚本插上数据库和编码的翅膀
VV 引擎的 Lua 环境默认加载了两个扩展库:sqlite3 和 iconv。这两个库不是引擎自定义的接口,而是标准的 Lua 扩展库,但引擎做了集成,让脚本可以直接使用。

sqlite 库提供了轻量级的数据库能力。文档里的示例展示了完整的使用流程:创建环境、连接数据库、建表、插入数据、查询数据、遍历结果、关闭连接。SQL 语句是标准的 SQLite 语法,支持 CREATE TABLE、INSERT、SELECT 等常用操作。

这个库的意义在于:给脚本提供了结构化数据存储能力。之前讲过文本文件操作可以存数据,但文本文件只能存简单的行式数据,查询和修改都不方便。有了 sqlite,你可以建表、建索引、用 SQL 查询,数据管理能力上了一个台阶。

sqlite 的应用场景很多:玩家数据统计(每个玩家一条记录,可查询可排序)、活动排行榜(分数存在表里,SQL 排序取前 N)、日志记录(结构化日志,可按条件查询)、配置缓存(把配置读进数据库,查询比文本文件快)。对于数据量较大、需要复杂查询的场景,sqlite 比文本文件合适得多。

但要注意:sqlite 是文件型数据库,并发写入性能有限,不适合高频写入的场景(比如每秒写很多条)。而且数据库文件需要自己管理路径和备份,不要放在容易被清理的目录里。

iconv 库提供了编码转换能力。文档里的示例展示了 GBK 转 UTF-8 和 UTF-8 转 GBK 两个函数。传奇引擎的文本默认是 GBK 编码,但有时候需要处理 UTF-8 的文本(比如从外部接口获取的数据、玩家输入的特殊字符),这时候就需要 iconv 来转码。

iconv 的应用场景:和外部系统交互(网页 API 返回 UTF-8,需要转成 GBK 才能在游戏里显示)、处理特殊字符(玩家名字里有 UTF-8 字符,需要转码后存储)、生成外部文件(导出数据为 UTF-8 的 CSV 或 JSON,供外部工具读取)。

这两个扩展库的存在,说明 VV 引擎在脚本能力上做了不少扩展 —— 不只是游戏相关的接口,还集成了通用的数据库和编码转换库,让脚本的能力边界大大扩展。开发者不需要自己编译和加载扩展库,引擎已经帮你做好了,直接 require 就能用。

实际使用中的心得是:sqlite 适合中等数据量的结构化存储,大数据量还是要用外部数据库。sqlite 虽然方便,但毕竟是嵌入式数据库,并发和性能有限。如果你的版本数据量很大(比如几万玩家的详细数据),考虑用外部 MySQL 或其他数据库通过接口交互。iconv 使用时注意错误处理 —— 文档里的示例判断了 err,转码失败时返回原字符串,避免因为转码错误导致脚本中断。

七、特效与表现:屏幕特效和屏幕震动,让游戏活起来
游戏体验不只是数值和逻辑,视觉表现同样重要。VV 引擎给了两个和屏幕表现相关的接口。

screffects 播放屏幕特效。传特效编号、特效 ID、屏幕坐标、播放速度、播放次数、播放模式(自己 / 所有人)。这个接口是在玩家的屏幕上播放 2D 特效 —— 不是在地图上的 3D 特效,而是覆盖在屏幕上的 UI 层特效。做技能全屏特效、活动开场动画、伤害数字特效、剧情演出特效时用。

deleffects 关闭屏幕特效。传特效编号和播放模式,停止正在播放的特效。和 screffects 配合使用 —— 特效播完自动消失,但如果需要提前关闭(比如玩家切地图、活动结束),用 deleffects 手动关。

scenevibration 屏幕震动。传模式(自己 / 所有人 / 屏幕范围 / 当前地图 / 指定地图)、震级(1-3)、次数、地图 ID(指定地图模式时需要)。屏幕震动是很经典的表现手法 ——BOSS 出场震一下、大招命中震一下、地震事件震一下,能极大增强打击感和沉浸感。

这三个接口的设计思路是:表现层和逻辑层分离。逻辑层计算伤害和结果,表现层负责播放特效和震动给玩家看。你可以在技能命中、怪物死亡、活动开始等逻辑节点调用这些接口,添加视觉表现,而不影响逻辑本身。

实际使用中的心得是:屏幕震动不要滥用。震一下很有感觉,一直震会让玩家头晕恶心。建议只在关键节点(BOSS 出场、大招命中、重大事件)使用,而且震级和次数要适度。屏幕特效同理 —— 全屏特效太频繁会遮挡视野影响操作,关键时候用才有冲击力。

还有一个细节:screffects 的特效 ID 对应客户端的特效配置,不是所有数字都有效,需要确认客户端有对应的特效资源。scenevibration 的震级 1-3,1 最轻 3 最重,根据场景选择 —— 普通技能用 1,大招用 2,BOSS 出场或地震用 3。

八、管理与调试:GM 命令、日志、性能计时、客户端开关
这一组接口主要面向管理和调试,普通游戏逻辑用得少,但运维和开发时离不开。

gmexecute 执行 GM 命令。传玩家对象、GM 命令名和最多 10 个参数。这个接口让脚本可以调用 GM 命令 —— 比如脚本里需要给玩家刷装备、传送到指定地图、调整属性,都可以通过 gmexecute 调用对应的 GM 命令来实现,不需要每个功能都写 Lua 接口。

这个接口的设计思路是复用 GM 命令体系。GM 命令已经覆盖了大量管理功能,脚本通过 gmexecute 就能调用这些功能,不需要引擎为每个 GM 命令单独写 Lua 接口。10 个参数应该能覆盖大部分 GM 命令的需求。

但要注意:gmexecute 执行 GM 命令可能需要玩家有 GM 权限,或者命令本身有权限检查。在普通玩家的脚本逻辑里调用 gmexecute 可能会失败,因为玩家没有权限。这个接口更适合在 GM 脚本、管理后台、活动脚本(有特殊权限上下文)里使用。

logact 自定义日志。传玩家对象、日志 ID(大于等于 10000)、日志内容(支持变量和常量)、最多 5 个整数参数。这个接口是给后台管理系统用的 —— 你定义自己的日志类型(ID>=10000),在脚本里记录关键行为(比如玩家消费、装备获取、活动参与),后台可以按日志类型查询和统计。

文档里还配了后台上传表格格式的图片,说明这些自定义日志会上传到后台管理系统,可以做数据统计和分析。做运营数据分析、玩家行为追踪、异常排查时,自定义日志非常有用 —— 你想记录什么就记录什么,后台统一管理。

senddiymsg 日志上报接口。传玩家对象和 JSON 字符串。这个是更通用的日志上报 —— 你自己组织 JSON 格式的数据上报,比 logact 更灵活但需要自己处理格式。做自定义数据上报、和外部数据分析系统对接时用。

printusetime 打印脚本总耗时(微秒)。传玩家对象和开关(1 = 开始计时,2 = 结束计时并打印)。这个是性能调试工具 —— 在你觉得可能有性能问题的代码段前后调用,就能测出这段代码执行了多少微秒。做性能优化时非常有用,能精确定位哪段代码慢。

文档里注明 "需要角色游戏权限为 10,且需退出管理员模式"—— 说明这个接口只有 GM / 管理员能用,普通玩家调用不了。这是合理的,性能计时是开发调试功能,不应该对普通玩家开放。

clientswitch 前端勾选面板控制命令。传玩家对象、类型(0 = 允许组队、1 = 允许添加好友、2 = 允许交易、3 = 允许挑战、4 = 允许查看、5 = 允许添加为行会成员)、时间(1 = 允许勾选,0 = 不允许)。这个接口可以控制玩家客户端的社交设置勾选状态 —— 比如活动期间强制允许组队,或者惩罚玩家禁止交易。做社交管理、活动规则、惩罚机制时用。

这组管理调试接口的共同特点是:面向运维和开发,普通游戏逻辑用得少,但关键时刻离不了。GM 命令让脚本能调用管理功能,日志让你能记录和分析数据,性能计时让你能优化代码,客户端开关让你能管理社交行为。这些接口不是用来做游戏核心玩法的,而是用来管理、调试、运营游戏的。


页: [1]
查看完整版本: 杂项工具集是 VV 引擎的 "百宝箱"