传奇HERO引擎游戏副本脚本编写事例详解

来源: 作者: 点击:
HERO引擎的副本系统核心逻辑并不复杂,主要依靠条件判断、变量控制和地图事件触发三部分配合完成。以下从地图配置开始,逐步拆解一个完整副本脚本的编写过程。

## 副本地图的基础配置

编写副本脚本前,首先要在服务端地图配置文件中注册副本地图。打开Mir200\Envir\MapInfo.txt,添加副本地图条目。单人副本需要为每个玩家分配独立的地图实例,避免玩家之间互相干扰。常见的做法是准备多张相同地图,通过编号区分实例:

```plaintext
[3000 副本地图]
[3001|3000 副本地图]
[3002|3000 副本地图]
[3003|3000 副本地图]
[3004|3000 副本地图]
[3005|3000 副本地图]
```

竖线前面的编号是实例地图号,后面的3000是共享的地图资源文件。玩家进入副本时,脚本会按顺序检测哪个实例地图空闲,然后传送过去。

副本地图通常还需要在MapInfo.txt中限制回城和随机传送,防止玩家中途脱离副本。将地图条目的第5、6个字段设为0即可禁止回城和随机传送。

## 副本进入条件检测与实例分配

副本传送NPC的核心逻辑是先检查进入条件,再分配空闲实例地图。以下脚本根据玩家等级动态分配地图实例,并刷出对应等级的怪物:

```plaintext
[@副本传送]
#IF
#ACT
MOV M0 3000
GOTO @检测地图

[@检测地图]
#IF
CHECKHUM <$STR(M0)> 1
#ACT
INC M0 1
goto @检测地图
#ELSEACT
GOTO @传送

[@传送]
#IF
CHECKLEVELEX = 10
#ACT
MOV S1 半兽勇士
goto @副本刷怪
BREAK
#IF
CHECKLEVELEX = 20
#ACT
MOV S1 骷髅精灵
goto @副本刷怪
BREAK
#IF
CHECKLEVELEX = 25
#ACT
MOV S1 尸王
goto @副本刷怪
BREAK
#IF
CHECKLEVELEX = 30
#ACT
MOV S1 邪恶钳虫
goto @副本刷怪
BREAK

[@副本刷怪]
#ACT
CLEARMAPMON <$STR(M0)>
MAPMOVE <$STR(M0)> 33 47
PARAM1 <$STR(M0)>
PARAM2 40
PARAM3 40
MonGen <$STR(S1)> 1 0
give 回城卷 1
```

这段脚本的执行流程是:先将变量M0设为起始地图号3000,然后进入@检测地图标签。CHECKHUM命令检测当前地图中是否有玩家,如果有人在里面就M0加1继续检测下一张地图,直到找到空闲地图。找到后根据玩家等级确定要刷的怪物名称存入S1,最后跳转到@副本刷怪执行传送和刷怪操作。

CLEARMAPMON命令用于清空目标地图上的所有怪物,防止上次副本残留的怪物影响本次体验。MonGen命令在地图内指定坐标刷出怪物,参数依次为怪物名、数量、范围。发放回城卷是为了给玩家提供退出副本的途径。

## 每日限次进入的控制

很多副本限制每天只能进入一次,需要用到日期变量配合全局变量记录进入状态。HERO引擎提供了dayofweek命令获取当前星期,结合全局变量即可实现每日重置:

```plaintext
[@main]
你好,我这里是副本传送员\
在我这里每天可以进去刷一次副本\
里边可以刷到大量的元宝和赤月装备\
我这里完全免费,你可以放心\
<我今天还没刷呢/@go>\
<不打扰你了,刷过了/@gun>\

[@gun]
#IF
#ACT
close

[@go]
#IF
check [120] 0
dayofweek sun
#ACT
mapmove fuben 13 16
give 回城卷 1
set [120] 1
set [121] 0
set [122] 0
set [123] 0
set [124] 0
set [125] 0
set [126] 0
SETONTIMER 0 1
GuildNoticeMsg 250 252 玩家<%s>进入了副本地图,祝他刷好多元宝回来!
break
```

这段脚本使用7个全局变量[120]到[126]分别对应周一到周日。进入副本时先检查当天对应的变量是否为0,为0说明今天还没进过,允许进入并将该变量设为1。进入时同时将其他6个变量清零,确保第二天的日期对应变量能正常使用。SETONTIMER命令用于启动副本内的倒计时或事件定时器。

## 副本内怪物击杀与通关检测

副本通关的常见检测方式是判断地图内是否还有存活的怪物。HERO引擎提供了CheckRangeMonCountEx命令,可以精确统计指定区域内某种怪物的存活数量:

```plaintext
[@副本进度检测]
#IF
CHECKRANGEMONCOUNTEX fuben 0 100 副本BOSS = 0
#ACT
SET [100] 1
SENDMSG 6 副本BOSS已被击杀,请到NPC处领取通关奖励。
```

该命令的参数依次为地图号、坐标范围、怪物名称、比较运算符和数量。当区域内副本BOSS数量为0时,将个人变量[100]设为1,标记副本已通关。玩家凭此变量回到NPC处领取奖励。

如果需要更精细的控制,比如检测地图内所有怪物而非特定一种,可以将怪物名称参数设为全部怪物或使用不带名称的统计方式。CheckRangeMonCountEx配合坐标范围可以限制只统计副本区域内的怪物,避免地图边界外的怪物干扰检测结果。

## 副本奖励的发放

奖励发放通常放在独立的NPC脚本中,玩家通关后回到NPC处点击领取。发放前需要验证通关标记变量,防止未通关的玩家冒领:

```plaintext
[@领奖]
#IF
check [100] 1
#ACT
GetRandomName ..\QuestDiary\副本奖励.txt S99
GIVE <$STR(S99)> 1
GAMEGOLD + 10000
SET [100] 0
SENDMSG 0 恭喜玩家[%s]通关副本,获得:<$STR(S99)>和10000元宝
MAPMOVE 3 333 333
#ELSESAY
你还没有通关副本,无法领取奖励。\
```

GetRandomName命令从文本文件中随机抽取一行内容存入字符变量S99,然后通过GIVE命令发放。文本文件中每行写一个物品名称,注意名称必须与DB数据库中的物品名完全一致。领取后立即将通关标记[100]清零,防止重复领取。

如果副本奖励包含多种物品,可以在文本文件中按“物品名 数量”的格式逐行写入,发放时使用GIVE命令带上数量参数。也可以多次调用GetRandomName分别抽取不同类别的奖励,比如一次抽取装备,一次抽取材料。

## 变量在副本脚本中的类型与选择

HERO引擎的变量按作用域分为三类,副本脚本中需要根据数据用途正确选择。

临时变量M0-M99仅在脚本单次执行周期内有效,适合用于副本实例地图号的临时计算。个人变量[0]-[99]跟随角色数据保存,玩家下线后重新登录仍保留,适合记录通关标记、每日进入次数等。全局变量G0-G99或A0-A99全服共享,适合控制副本的全局刷新状态或活动开关。

个人变量通过SET命令赋值,通过CHECK命令读取。需要持久化保存时,使用SAVEVAR命令将变量写入角色数据库。HERO引擎中个人变量在玩家登录时会自动加载,但如果脚本中使用了自定义命名的文件存储方式,则需要手动调用读取命令。

变量清零的时机很关键。副本通关标记应该在玩家领取奖励后清零,而不是在击杀BOSS后立即清零,否则玩家可能在回到NPC之前掉线导致无法领奖。每日进入次数的变量应该在次日对应日期到达时自动归零,上述7变量轮换方案就是利用这一原理实现的。

## 组队副本的进入与防跑单

组队副本需要处理队伍成员同步传送和通关后奖励的精准发放。HERO引擎提供了GROUPMAPMOVE命令实现全队传送:

```plaintext
[@GroupLeader]
#IF
ISGROUPMASTER
CHECKGROUPCOUNT > 1
CHECKGAMEGOLD > 999
#ACT
GAMEGOLD - 1000
SET [100] 1
CLEARNAMELIST ..\QuestDiary\防跑单\队伍名单.txt
AddTextListEx ..\QuestDiary\防跑单\队伍名单.txt
GROUPMAPMOVE D5001 50 50
SENDMSG 6 防跑单副本已开启!全员已传送。
#ELSESAY
组队副本需要至少2人组队,且队长需缴纳1000元宝押金。\
```

进入副本前队长缴纳押金并锁定队伍名单。AddTextListEx命令将当前队伍成员的名字逐行写入名单文件。通关后发放奖励时,遍历名单文件逐行比对玩家是否仍在队伍中:

```plaintext
[@GiveReward]
#IF
CheckTextList ..\QuestDiary\防跑单\队伍名单.txt <$USERNAME>
#ACT
CHANGEEXP + 1000000
GIVE 祖玛雕像 1
SENDMSG 6 你获得了通关奖励!
```

CheckTextList命令检测玩家名字是否在名单文件中,只有在名单中的玩家才能领取奖励。这套机制可以防止队员中途退出后仍然冒领奖励,也可以防止队长在BOSS快死时踢人换号。

押金在通关后返还队长,如果副本中途失败或队伍解散,押金则不退还。押金金额和返还逻辑需要根据实际版本需求调整,押金变量[100]在返还后需要清零。

## 副本倒计时与限时机制

限时副本需要用到定时器控制。HERO引擎的SETONTIMER命令可以启动一个定时触发,参数为定时器编号和触发间隔。定时器触发后会跳转到指定的标签执行脚本:

```plaintext
[@进入副本]
#ACT
SETONTIMER 0 1
MAPMOVE fuben 13 16
SENDMSG 6 已进入副本,限时30分钟!

[@Timer0]
#IF
CHECKMAP fuben
#ACT
SENDMSG 6 副本时间剩余5分钟,请尽快通关!
```

定时器编号0到9可用,间隔参数单位为分钟时直接填写数字。定时器触发后,脚本中通过CHECKMAP判断玩家是否还在副本内,如果在则发送倒计时提醒。副本结束时,在定时器脚本中执行传送命令将玩家移出副本,并清理地图怪物。

需要注意的是,SETONTIMER是全局定时器,会对所有在线玩家生效。如果只希望特定玩家触发倒计时,需要配合个人变量在定时器脚本中做过滤判断,只有持有副本标记变量的玩家才会收到提示。

## 副本脚本常见问题排查

副本脚本执行异常时,优先检查以下几个位置。地图编号必须与MapInfo.txt中注册的编号完全一致,编号写错会导致MAPMOVE命令无效,玩家无法传送。变量名的大小写在某些HERO引擎版本中敏感,建议统一使用大写。

怪物名称必须与DB数据库中的名称完全一致,包括括号和空格。如果MonGen命令执行后地图内没有刷出怪物,通常是怪物名不匹配导致的。CheckRangeMonCountEx的坐标范围参数如果超出地图实际范围,检测结果始终为0,通关标记会提前触发。

奖励文本文件的路径需要确保目录存在,GetRandomName读取不存在的文件时不会报错但会返回空值,导致GIVE命令发放空物品。建议在脚本中添加文件存在性检测,或提前创建好所有必要的目录结构。