脚本基础

功能脚本组织

说明 Blue 引擎中功能脚本的组织方式,帮助你把脚本拆成可复用的功能模块,再由入口脚本按需调用。

什么是功能脚本

功能脚本可以简单理解成“组件化的脚本”:把一整套玩法、任务、活动、检测、奖励或公共逻辑拆出来,做成可以重复调用的功能模块。

这样做的目的通常有三个:

  • 把大功能拆开,避免单个脚本越来越长
  • 让多个入口复用同一套逻辑
  • 把“入口脚本”和“功能实现”分层维护

如果你在多个地方都要用同一套判断、发奖或结算流程,就很适合把它整理成功能脚本,而不是每个入口都复制一份。

如果一个功能已经开始出现多个入口、多个标签、多个判断分支,继续全塞在同一个 NPC 文件里,后面会越来越难改。

QuestDiary 是什么

MirServer\Mir200\Envir\QuestDiary\ 是各类自定义游戏功能的脚本目录,里面通常放游戏玩法、任务、功能和数据相关脚本。

这意味着:

  • QuestDiary 不是单一任务目录
  • 它更像“自定义功能脚本总目录”
  • 需要把公共功能抽出来时,优先考虑往这里组织

实际项目里,常见会按功能继续细分子目录,例如活动、排行、登录逻辑、公共模块等。

功能脚本和普通脚本的区别

使用 #CALL 前,最好先把这两类脚本分清。

脚本类型常见位置主要作用常见写法
普通脚本Market_Def、NPC 对应脚本接玩家点击、显示对话、提供按钮入口常直接从 [@Main] 开始
功能脚本QuestDiary 功能目录处理一整套功能逻辑,供多个入口复用常先写一个总入口,再在内部拆多个标签

可以直接这样理解:

  • 普通脚本更像入口层
  • 功能脚本更像实现层

在服务端样本里,Market_Def 下不少 NPC 脚本本身只负责入口,进入后马上用 #CALL 转到 QuestDiary 里的目标脚本。QManage 里也能看到一组连续的 #CALL,把不同功能挂到各自的功能脚本中。

功能脚本里常见的组织方式如下:

[@功能脚本]
{
; 脚本主流程

[@标签1]

[@标签2]
}

这种写法的意思是:

  • 外部通常先调用 @功能脚本 这个总入口
  • 具体判断、发奖、提示、跳转,再继续拆到内部标签里
  • 一个功能脚本文件中,可以集中维护整套功能流程

#CALL 调用功能脚本

#CALL 用来调用 QuestDiary 功能脚本目录中的脚本。

语法

#CALL <脚本路径> <@标签名>

示例

[@Main]
#SAY
<每日奖励/@领取每日奖励>

[@领取每日奖励]
#ACT
#CALL [\每日奖励\每日奖励.txt] @每日奖励

使用这类写法时,可以重点关注这几点:

  • 入口按钮仍然可以写在当前 NPC 脚本里
  • 真正的功能实现放到 QuestDiary 下独立维护
  • 后续其他 NPC、QManage、活动入口也能继续调用同一份脚本

#CALL 的组织约定

下面这类写法,表示执行到当前标签时才触发外部脚本:

[@领取每日奖励]
#ACT
#CALL [\每日奖励\每日奖励.txt] @每日奖励

这类写法更适合按钮点击后才进入的功能,或者满足条件后才继续执行的流程。

下面这类写法,表示把公共脚本集中放到当前脚本的公共加载入口:

[@打开活动面板]
#ACT
GOTO @活动入口

[@领取活动奖励]
#ACT
GOTO @活动入口

[@自动加载]
#CALL [\活动系统\活动入口.txt] @活动入口

这种组织方式更适合公共脚本、公共配置或常量文件。重点不是在多个标签里反复 #CALL 同一目标,而是先集中加载一次,再让各个标签继续走当前脚本自己的流转。

DELAYCALL 延时调用

DELAYCALL 用于延迟一段时间后,再去执行目标标签。

语法

DELAYCALL <毫秒> <@标签名> [参数1] [参数2] [参数3] [参数4] [参数5]

作用

它适合处理“先等待一下,再进入后续逻辑”的场景。

和 DELAYGOTO 一样,DELAYCALL 也支持最多 5 个上下文参数传输。这 5 个参数都是可选的;需要传参时再补上,不需要传参时只写前面的毫秒和标签名即可。传入后的参数可通过 <$STR(S_CONTEXT[0-4])> 读取,避免临时变量被覆盖。

示例

[@Main]
#SAY
1 秒后进入每日奖励结算...

#ACT
DELAYCALL 1000 @每日奖励结算 <$STR(S_奖励类型)> <$USERNAME>

如果你的需求是“延时后跳到当前脚本中的另一个标签继续菜单流转”,优先看 DELAYGOTO。

如果你的需求是“延时后进入一段功能逻辑”,更适合使用 DELAYCALL。

GOTO 和 CALL 怎么区分

使用这两组命令时,最容易混淆的是“当前脚本内跳转”和“跨脚本调用”的边界。

可以直接按下面的方式区分:

  • GOTO / DELAYGOTO:解决当前脚本里的标签流转问题
  • #CALL / DELAYCALL:解决功能拆分和脚本复用问题

如果目标仍然是当前脚本里的其他标签,优先用 GOTO。

如果目标已经是独立功能脚本,尤其是 QuestDiary 目录下的功能模块,优先用 #CALL。

一个常见组织方式

比较稳妥的功能组织方式通常是:

  1. 当前 NPC 脚本只负责入口对话和按钮
  2. 按钮点击后,用 #CALL 进入 QuestDiary 中的功能脚本
  3. 功能脚本内部再继续拆成多个标签
  4. 需要延时执行时,再决定用 DELAYGOTO 还是 DELAYCALL

这种分法能把“入口显示”和“功能实现”拆开,后续维护会轻很多。

使用建议

  • 一个功能只有一个入口、逻辑也很短时,不必强行拆到 QuestDiary
  • 一个功能开始被多个入口复用时,就应尽早拆成功能脚本
  • 跨脚本调用前,先统一目录结构和标签命名,避免后续调用目标越来越乱
  • 需要当前脚本内跳转时,用 GOTO 系列;需要功能模块化时,用 CALL 系列
  • 公共加载入口如果只负责统一 #CALL,通常放在脚本后部会更清晰,便于和前面的流程标签区分开

相关阅读