传奇HERO引擎限时会员脚本:按天计费与到期自动清理

来源: 作者: 点击:
HERO引擎的会员系统本质就是“一个到期时间戳变量 + 登录时比对时间”。不限时会员给永久标记,限时会员给一个具体到期时间,登录时拿当前时间和到期时间比,过了就清标记。多个一月会员能累计,就是“延期 = 取最大值(旧到期时间,当前时间)+ 天数”,而不是直接覆盖。

先确定变量分工
HERO引擎脚本里:
• U 系列变量:玩家私有,可按账号/角色保存,适合存到期时间

• N 系列变量:数字型,配合 SaveVarHUMAN 存盘

• S 系列变量:字符型

会员等级用一个变量,比如 N会员等级:0=普通、1=一天体验、2=一周、3=一月。会员到期时间用另一个变量存时间戳,比如 U会员到期时间(单位秒,或按 HERO 的日期格式)。HERO 里取当前时间常用 <DATE>、<TIME>,或者用脚本命令 GetTime、GetDateTime,具体看你的 HERO 版本命令手册。

核心逻辑:购买即延期
不是“设置会员”,是“计算新的到期时间”:
1. 取当前时间戳 Now
2. 取旧的到期时间 OldExpire(如果已过期就用 Now)
3. NewExpire = Max(OldExpire, Now) + 天数×86400
4. 存 NewExpire,设会员等级

这样买一个月时,不管之前剩多少天,都在“到期时间”上往后加30天,自然就累计了。直接 MOV U$会员到期时间 Now+30天 是错的,会覆盖掉剩余时间。

购买脚本写法(NPC)
Market_Def\会员服务.txt:

(@BuyVip )
[@main]
<会员服务中心>\
一天体验会员:<STR(N体验价格)>元宝\
一周会员:<STR(N周价格)>元宝\
一月会员:<STR(N月价格)>元宝\
你的会员等级:<STR(N会员等级)>\
到期时间:<STR(S到期显示)>\
<购买一天体验/@buy_1>\
<购买一周/@buy_7>\
<购买一月/@buy_30>\
<查询/@check>\
<离开/@exit>\

[@buy_1]
IF

CHECKGAMEGOLD <STR(N体验价格)>
ACT

TAKE 元宝 <STR(N体验价格)>
CALL @AddVip 1
SENDMSG 6 成功开通1天体验会员
GOTO @main
ELSEACT

SENDMSG 6 元宝不足
GOTO @main

[@buy_7]
IF

CHECKGAMEGOLD <STR(N周价格)>
ACT

TAKE 元宝 <STR(N周价格)>
CALL @AddVip 7
SENDMSG 6 成功开通7天会员
GOTO @main
ELSEACT

SENDMSG 6 元宝不足
GOTO @main

[@buy_30]
IF

CHECKGAMEGOLD <STR(N月价格)>
ACT

TAKE 元宝 <STR(N月价格)>
CALL @AddVip 30
SENDMSG 6 成功开通30天会员
GOTO @main
ELSEACT

SENDMSG 6 元宝不足
GOTO @main

[@check]
IF

LARGE N$会员等级 0
ACT

SENDMSG 6 当前会员等级:<STR(N会员等级)>,到期:<STR(S到期显示)>
ELSEACT

SENDMSG 6 你不是会员
GOTO @main

延期子过程(关键)
用 CALL 传参,HERO 里 CALL 可以带参数写在后面,用 $PARAM(0) 接:

[@AddVip]
IF

ACT

MOV D0 $PARAM(0)
CALC U会员到期时间 = U会员到期时间
IF

LARGE U会员到期时间 <NOW>
ACT

MOV U会员到期时间 <NOW>
BREAK
IF

ACT

CalcVar U$会员到期时间 + D0 * 86400
IF

EQUAL D0 1
ACT

MOV N$会员等级 1
IF

EQUAL D0 7
ACT

MOV N$会员等级 2
IF

EQUAL D0 30
ACT

MOV N$会员等级 3
IF

ACT

SaveVarHUMAN U$会员到期时间 ..\QuestDiary\会员\会员数据.txt
SaveVarHUMAN N$会员等级 ..\QuestDiary\会员\会员数据.txt
BREAK

这里的 <NOW> 要换成你 HERO 引擎取当前秒数的实际命令,有的版本是 <TIME>,有的是 GetTime 存入变量。如果 HERO 不支持 CALC 直接算时间,就用日期拆分算:把当前日期和到期日期都转成“从某天起的天数”,延期就是天数加 N。

到期自动清理:登录时检查
QFunction-0.txt 或 QuestDiary 的 [@Login]:

[@Login]
IF

LARGE N$会员等级 0
ACT

IF

LARGE <NOW> U会员到期时间
ACT

MOV N$会员等级 0
MOV S$到期显示 已过期
SaveVarHUMAN N$会员等级 ..\QuestDiary\会员\会员数据.txt
SENDMSG 6 你的会员已到期,特权已取消
ELSEACT

SENDMSG 6 欢迎回来,会员剩余时间:<STR(S到期显示)>
BREAK

“在线期间到期”也要处理,不能只靠登录。用定时器,HERO 的 RunTick 或 QuestDiary 定时器:

[@RunTick]
IF

LARGE N$会员等级 0
ACT

IF

LARGE <NOW> U会员到期时间
ACT

MOV N$会员等级 0
SaveVarHUMAN N$会员等级 ..\QuestDiary\会员\会员数据.txt
SENDMSG 6 会员到期,特权已取消
BREAK

会员特权判定统一用一个检查
别到处写 LARGE N$会员等级 0,容易漏。写成公共检查:

[@CheckVip]
IF

LARGE N$会员等级 0
ACT

IF

LARGE <NOW> U会员到期时间
ACT

MOV N$会员等级 0
SENDMSG 6 会员已过期
BREAK
ELSEACT

SENDMSG 6 会员有效
BREAK

传送员、泡点、打宝加成这些地方都先 CALL @CheckVip,过了才给特权。这样到期清理一处改,全服生效。

时间显示问题
U会员到期时间 存的是秒数,直接 <STR> 显示成一串数字很难看。显示前转成日期:HERO 有 FormatTime 或把秒数拆成年月日的命令,没有就存两个变量——到期秒数(用于比对)+ 到期日期字符串(用于显示)。每次延期时同时写:
MOV S$到期显示 某年某月某日
具体格式用 HERO 的日期格式化命令,查你版本的 AddDate / FormatDateTime。

按天累计的坑
“一个月”到底是30天还是自然月?按天算就一律 30×86400 秒,简单稳定。按自然月(比如1月15到2月15)要用 AddMonths 类命令,HERO 不一定有,没有就老实用30天。

体验会员一天 = 86400秒;一周 = 7×86400;一月 = 30×86400。闰年、跨夏令时不用管,传奇服务端一般用 UTC+8 固定时区。

防止覆盖剩余时间的完整写法
假设玩家还有10天会员,再买一个月,应该是40天,不是30天。核心就这句:
CalcVar U$会员到期时间 + 天数×86400
前提是“旧到期时间已经大于当前时间”才直接加,否则要从当前时间开始加。所以前面那段:
IF

LARGE U会员到期时间 <NOW>
ACT

MOV U会员到期时间 <NOW>
BREAK
就是把“已过期”的情况修正为从现在算起,没过期就保持原值,然后统一加天数。这个分支不能省。

会员名单自动清理
“清理会员名单”有两层:
1. 玩家自己的会员标记:登录时 LARGE <NOW> U会员到期时间 就清 N$会员等级,上面已经做了。
2. 全服会员列表/排行榜:如果有个全局记录(比如 G$变量或文本文件存的会员名单),需要定期扫描。HERO 不好直接遍历所有玩家变量,最稳的做法是:
• 每个会员登录时走 [@CheckVip],过期就清自己的标记

• 定时器每小时跑一次全服检查(RunTick 配合 ForPlay 或 M2 的“遍历在线玩家”命令)

• 或者干脆不维护名单,需要时实时查 N$会员等级 > 0 的在线玩家

如果你确实要“名单文件自动删行”,用 HERO 的文件操作命令(LineCount、DeleteLine、LoadVarList),在定时器里读名单文件,逐行取对应玩家的到期变量,过期就删该行。但更简单是名单文件只存“在线且是会员”的人,每次登录重新登记,过期当场注销。

测试步骤
1. 建变量:N会员等级、U会员到期时间、S$到期显示
2. 写购买 NPC,先只测“买一月”
3. 买完后查变量值是否 = Now + 2592000
4. 再买一次,看是否变成 Now + 5184000(累计,不是覆盖)
5. 手动把 U$会员到期时间 改成 0 或一个过去时间,重新登录看是否清成普通玩家
6. 在线挂机,把时间改到到期之后,看 RunTick 是否自动取消特权
7. 查显示:<STR(S到期显示)> 是否正常日期

HERO 命令差异提醒
HERO 不同版本对 CalcVar、CALC、SaveVarHUMAN、<$NOW>、AddDate 的支持不一样。如果你的版本没有 CALC,就用最原始的三段式:
• 取当前天数的变量 DayNow

• 取旧到期天数的变量 DayExpire

• 新到期天数 = Max(DayExpire, DayNow) + 天数

• 存回去

取天数用命令把日期拆成天数,比如从开服基准日算偏移;存盘用 SaveVarHUMAN。逻辑一样,只是时间单位从“秒”换成“天”,对一天/一周/一月这种精度完全够用,还避开了秒级时间戳的命令兼容问题。

一个完整的延期片段(按天,兼容性最好)
[@AddVipDay]
ACT

MOV D0 $PARAM(0)
IF

LARGE U$到期天 0
ACT

IF

LARGE U到期天 <今天天数>
ACT

MOV U到期天 <今天天数>
BREAK
IF

ACT

CalcVar U$到期天 + D0
IF

EQUAL D0 1
ACT

MOV N$会员等级 1
IF

EQUAL D0 7
ACT

MOV N$会员等级 2
IF

EQUAL D0 30
ACT

MOV N$会员等级 3
IF

ACT

SaveVarHUMAN U$到期天 ..\QuestDiary\会员\会员数据.txt
SaveVarHUMAN N$会员等级 ..\QuestDiary\会员\会员数据.txt
BREAK

<$今天天数> 用一个启动脚本或每日定时脚本算好存进全局变量,全服复用。这样完全不依赖秒级时间戳命令,HERO 老版本也能跑。

到期清理用天数版
[@Login]
IF

LARGE N$会员等级 0
ACT

IF

LARGE <今天天数> U到期天
ACT

MOV N$会员等级 0
SaveVarHUMAN N$会员等级 ..\QuestDiary\会员\会员数据.txt
SENDMSG 6 会员已到期
ELSEACT

SENDMSG 6 会员剩余天数:<STR(U到期天 - <$今天天数>)>
BREAK

把“剩余天数”显示出来,玩家体验好很多,也方便你排查累计是否正确。

会员特权示例(传送员判断)
[@go_zuma]
IF

LARGE N$会员等级 0
ACT

MAPMOVE 015 50 50
SENDMSG 6 会员免费传送
BREAK
ELSEACT

IF

CHECKGOLD 1000
ACT

TAKE 金币 1000
MAPMOVE 015 50 50
ELSEACT

SENDMSG 6 非会员需1000金币
BREAK

所有会员特权点都先走 LARGE N$会员等级 0,再 CALL @CheckVip 防过期,结构清晰,后面加特权只改一处。

变量存盘位置
SaveVarHUMAN 的路径要写对,HERO 里一般是相对于 Mir200 目录,比如:
SaveVarHUMAN N$会员等级 ..\QuestDiary\会员数据\会员等级.txt
文件名最好按玩家区分,HERO 会自动加玩家标识。如果存盘失败,重启后会员全丢,测试时第一件事就是改完买会员,重启 M2,看等级还在不在。

一句话结构
购买 → AddVip(天数) → 到期时间 = Max(旧到期, 现在) + 天数 → 存盘
登录 → CheckVip → 现在 > 到期时间 → 清等级、清名单、存盘
在线 → RunTick 定时 CheckVip → 到期当场清理
特权 → 所有入口先判 N$会员等级 > 0 且未过期

这套写法下,买一个月再买一个月就是两个月,到期自动变回普通人,名单靠登录检查 + 定时扫描自动瘦身,不需要手动维护。