玩家下线以后角色还留在游戏里,这件事靠的是引擎的离线命令再加一个计费循环。等级不同收费不同,经验也不同,三样东西要串在一起写。先把落点、命令、算法分开看,再拼成完整脚本。
热血传奇
挂机脚本落在哪几个文件
服务端的脚本按用途分开放。NPC对话脚本放在 Mir200\Envir\Market_Def 目录下,一个挂机使者就是一个独立的 txt 文件。NPC长什么样、刷在哪张地图哪个坐标,由同目录的 Merchant.txt 登记。角色登录时执行的脚本,以及所有个人定时器,统一放在 Mir200\Envir\MapQuest_def\QManage.txt,定时器的触发段 [@OnTimer编号] 也写在这里。穿戴装备、捡取物品这类动作触发的脚本放在 QFunction-0.txt。需要反复调用的公共段落,建议单独建在 QuestDiary 目录下的文本里,用 #CALL 引过去。
把这几个位置记住,后面改脚本不用满目录乱翻。
离线命令 OFFLINEPLAY 的两种写法
离线挂机不靠玩家开着客户端,靠一条命令把角色留在服务器里。命令名是 OFFLINEPLAY,有两种写法。
第一种只写一个参数:
text
OFFLINEPLAY 100
这个100是分钟数,意思是玩家下线以后角色在游戏内保留100分钟,到点被系统踢下线。这种写法只延时,不给经验。
第二种带两个参数:
text
OFFLINEPLAY 12 5000
第一个参数12是挂机时长,单位分钟。第二个参数5000是每分钟获得的经验。挂满12分钟,每分钟结算5000点经验。这一段的经验由引擎在挂机期间自动发放,不需要额外写定时器。
要注意,这条命令只负责留下来和按分钟给经验,它不扣费。收费要自己在脚本里做。
挂机前先补齐站位检测
离线挂机要求角色停在安全区,还不能和别人叠在一起,否则下线就会掉线或者被怪打死。这两条在脚本里用两个判断卡住。
text
#IF
ISDUPMODE
#SAY
请找一个空位置,不要和别人站在一起。
\
\
#ACT
BREAK
#IF
INSAFEZONE
#ELSEACT
BREAK
#ELSESAY
请在安全区站好,站在安全区外下线会被人杀掉。
\
\
ISDUPMODE 检测当前坐标是不是已经被别的角色占用,返回真就提示换位置。INSAFEZONE 检测角色是否站在安全区,不在安全区就直接返回。这两条写在离线命令之前,能挡掉大部分挂机掉线的投诉。
按等级收费的两条实现路径
收费按等级走,有两种写法:分段定价和公式定价。
分段定价适合等级区间跨度大、每段价格跳跃明显的版本。核心命令是 CHECKLEVELEX,它判断当前等级和给定数值的大小关系。
text
[@按等级定价]
#IF
CHECKLEVELEX > 79
#ACT
CALCVAR HUMAN 挂机费率 = 50
SAVEVAR HUMAN 挂机费率 ..\QuestDiary\挂机\费率.txt
BREAK
#IF
CHECKLEVELEX > 59
#ACT
CALCVAR HUMAN 挂机费率 = 30
SAVEVAR HUMAN 挂机费率 ..\QuestDiary\挂机\费率.txt
BREAK
#IF
CHECKLEVELEX > 39
#ACT
CALCVAR HUMAN 挂机费率 = 15
SAVEVAR HUMAN 挂机费率 ..\QuestDiary\挂机\费率.txt
BREAK
#IF
CHECKLEVELEX > 0
#ACT
CALCVAR HUMAN 挂机费率 = 5
SAVEVAR HUMAN 挂机费率 ..\QuestDiary\挂机\费率.txt
这段把每分钟要扣的元宝数存进一个 HUMAN 变量。HUMAN 变量是人物私有变量,用 CALCVAR 赋值,用 SAVEVAR 落盘到 QuestDiary 下的文本里,下线重上还在。段与段之间必须写 BREAK,否则高等级走到最后一段会被低价覆盖。
公式定价适合要求价格随等级平滑变化的版本,用变量运算代替一堆分段。
text
#ACT
MOV P10 <$LEVEL>
MUL P10 2
DIV P10 10
CALCVAR HUMAN 挂机费率 = <$STR(P10)>
SAVEVAR HUMAN 挂机费率 ..\QuestDiary\挂机\费率.txt
MOV 把当前等级读进临时变量 P10,MUL 乘2,DIV 除10,等于每级0.2元宝。<$LEVEL> 是引擎内置的人物等级变量。DIV 是整数除法,小数部分会被丢掉,费率要保留小数位就得先把数值放大再缩小。
扣元宝和补经验怎么拼
费率算好了,接下来是扣费。扣费靠两条命令:CHECKGAMEGOLD 检测余额,GAMEGOLD - 扣减数字。
text
[@进入挂机]
#IF
CHECKGAMEGOLD > 99
INSAFEZONE
#ACT
#CALL [..\QuestDiary\挂机\按等级定价.txt] @按等级定价
MOV P12 <$HUMAN(挂机费率)>
MUL P12 30
GAMEGOLD - <$STR(P12)>
OFFLINEPLAY 30 10000
SENDMSG 0 玩家[%s]进入离线挂机,已按等级扣除挂机费用
BREAK
#ELSEACT
MESSAGEBOX 元宝不足,无法开启离线挂机
BREAK
逻辑是先按等级把费率算出来,再用费率乘上挂机分钟数得到总价。30分钟挂机,每分钟费率来自等级,一次性扣掉。扣费放在 OFFLINEPLAY 之前,余额不够就拦在门口,不会出现挂了半小时一分钱没扣的情况。
经验部分有两条路。简单的是用 OFFLINEPLAY 自带的第二个参数,引擎按分钟发。想让经验也跟等级挂钩,就改成定时器发放,OFFLINEPLAY 只留时长。
用定时器做按等级给经验
个人定时器是离线场景里发经验的主力。开启用 SETONTIMER,关闭用 SETOFFTIMER,触发段写在 QManage.txt 里的 [@OnTimer编号]。
text
[@开启挂机计时]
#IF
CHECKGAMEGOLD > 9
#ACT
MAPMOVE 0139
SETONTIMER 1 60
SENDMSG 5 挂机计时已开启,每分钟结算一次经验
BREAK
[@OnTimer1]
#IF
ISONMAP 0139
CHECKGAMEGOLD > <$HUMAN(挂机费率)>
#ACT
GAMEGOLD - <$HUMAN(挂机费率)>
MOV P11 <$LEVEL>
MUL P11 10000
CHANGEEXP + <$STR(P11)>
CHANGENGEXP + <$STR(P11)>
BREAK
#ELSEACT
SETOFFTIMER 1
MESSAGEBOX 元宝不足或已离开挂机地图,挂机计时已停止
BREAK
SETONTIMER 1 60 表示编号为1的定时器每60秒触发一次,也就是每分钟结算一次,对应的触发段标签是 [@OnTimer1]。[@OnTimer1] 里的三个动作连在一起:扣掉一分钟的元宝,按当前等级算出经验值,把经验发下去。CHANGEEXP 加的是人物经验,CHANGENGEXP 加的是内功经验,两个命令分开写。
ISONMAP 检测角色是否还在挂机地图内。角色被人拉走或者自己走出去,定时器就要关掉,不然会在地图外白给经验。CHECKGAMEGOLD 卡住余额,钱不够就停表。
定时器编号不是随便定的。QManage.txt 里所有的 [@OnTimer] 共用一批编号,开之前先在文本里搜一遍 @OnTimer,确认要用的编号没被占用。两个功能共用一个编号,后开的会把先开的顶掉。
离线时长和等级的换算
有的版本按分钟收费,有的按次收费,换算逻辑要把等级、时长、单价三样串起来。用变量承接中间结果,别直接写死在命令里。
text
#ACT
MOV P15 <$HUMAN(挂机费率)>
MOV P16 30
MUL P15 <$STR(P16)>
MOV P17 <$LEVEL>
DIV P17 20
INC P15 <$STR(P17)>
GAMEGOLD - <$STR(P15)>
P15 承接单价,P16 是挂机时长,相乘得到基础费用。P17 是等级除以20的额外加价,INC 把加价并进总价。等级越高、挂得越久,总价越高。这套算法改系数就能用,不用重写整段。
不同引擎的写法差异
GOM 和 GEE 引擎走上面这套命令式写法,OFFLINEPLAY、SETONTIMER、CHECKLEVELEX、CHANGEEXP 都是原生命令,兼容性最好。HERO 引擎同样支持这组命令,个人定时器编号范围略有差别,开之前看引擎自带的说明。
BLUE 和 LEG 引擎也是命令式,但变量前缀和调用习惯不同,HUMAN 变量的读写格式要按引擎手册核对。部分老引擎的离线命令只支持单参数,只有时长没有经验,按等级给经验就必须挂定时器。
换引擎时命令名整段替换,不能照抄。同一个功能在 GEE 上能跑,搬到 BLUE 上可能因为标点或者参数个数报错。迁移前先拿一个简单的地图和一条命令试跑,确认命令认得到再整套搬。
调试时反复出现的问题
挂机不扣元宝。先看 CHECKGAMEGOLD 的比较值有没有写错,再看 GAMEGOLD - 后面的数值是不是被引号包错。GAMEGOLD - 后面直接跟数字,用变量就写成 <$STR(变量名)>。
经验不给或者给得不对。检查 CHANGEEXP 后面有没有加号,漏掉加号会把经验设成绝对值而不是增加。检查 MUL、DIV 的运算顺序,临时变量被后面的段覆盖就会算出错值。
等级和费率对不上。CALCVAR 写的是 HUMAN 变量,读取要用 <
𝐻
𝑈
𝑀
𝐴
𝑁
(
变量名
)
>
,写成
<
HUMAN(变量名)>,写成<STR(变量名)> 读出来是空。SAVEVAR 的落盘路径要对,路径写错变量下线就丢,重上又回到默认值。
定时器开了停不下来。SETOFFTIMER 的编号要和 SETONTIMER 一致。在 [@OnTimer编号] 里判断离开地图或者余额不足时,必须补上 SETOFFTIMER,不然定时器会一直空转,引擎日志里能刷出一堆报错。
离线后角色不消失也不掉线。OFFLINEPLAY 的第一个参数设太长,或者 INSAFEZONE 检测没写。挂机时长建议按版本设定上限,配合收费一起放开,避免有人挂着不下线占资源。
NPC点了没反应。Merchant.txt 里登记的脚本文件名和 Market_Def 目录下实际文件名对不上,或者脚本第一行的 [@main] 标签被改过。文件名和标签名保持一致就能解决。
数值怎么定
收费曲线和等级挂钩时,先定一个基线。低等级每分钟几元宝,高等级按倍数往上抬。挂机时长分档,30分钟、60分钟、180分钟,档位越长时间越长,单价可以适当降一点,鼓励长时间挂机。
经验给法也要跟等级走,等级乘一个固定系数,避免高等级玩家挂着不回。挂机地图单独开一张,编号固定,脚本里的 ISONMAP 和 MAPMOVE 都指向它。地图外面不能触发定时器,进图才开,出图就关。
名单和变量文件统一放 QuestDiary 下的独立目录,一个功能一个文本,方便查数据也方便活动时清理。把文件、命令、算法这三层理清楚,离线挂机的收费和经验就能同时跑对。

