Emuera 原生游戏运行流程浅析

你暂时逃掉的课,总有一天要补回来。(悲)
参考资料:《官方文档 / フロー図

个人吐槽

我一向是不太看得起 Emuera 内置的所谓「标准游戏流程」的。
(没有考据过,大概也是从 eramaker 时代继承下来的?)

也就是 SHOP / TRAIN 那一套。
这种流程死板而臃肿,让我见到的第一眼就心生不喜。

时间转瞬即逝,我个人接触 era 也快一年了。
我曾经两度壮志雄心想要写一个 era 游戏,两度被劝退,就是因为这套东西。

我自己写当然是从 @SYSTEM_TITLE 就开始接手,自行设计游戏流程了。

每每当我尝试创作的时候,阅读别人的 era 游戏代码以作参考,大多都是用的这套。
然后我就会不由自主地考虑能不能用在我的游戏里。
接着光是想象就被恶心到,遂放弃。周而复始这个过程。

这玩意不是我不想看,我就能不看的。
我也是负责运营社群的一员,有人好声好气来反应 bug 我难道还能晾着人家吗。

在这种无限循环的折磨中,我着实被耗尽了耐心。

但几经波折,兜兜转转还是回到了这里。
毕竟对没有任何编程基础的新手来说,你不能强求他们先去学习枯燥的数据结构。

哪怕你有心深造,我也不建议你零基础直接生啃数据结构。
这种干瘪的工作真的会极大程度上磨灭你的创作激情。

Emuera 自带的标准流程,确实是对新人(开发者)最友好的选择了。
为了完成足够详尽的开发教程,尽管内心仍然抗拒不已,我还是不得不捏着鼻子()去梳理这套玩意。什么恶堕剧情

TITLE 标题界面#

调用方式:

  • 在启动 Emuera 并读取所有 erb 文件后自动运行
  • 使用 BEGIN TITLE 主动调用

使用默认的标题界面#

如果没有定义 @SYSTEM_TITLE 函数,就显示默认的标题界面,如下图所示:

至于这里自动读取并显示的信息可以在 GameBase.csv_Replace.csv 修改。

然后是仅有的两个选项:

  • 选择 [0] 最初からはじめる
    1. 初始化游戏数据(RESETDATA / ADDCHARA 0 等 )
    2. 开始新游戏 BEGIN FIRST
  • 选择 [1] ロードしてはじめる
    • 如果定义了 @TITLE_LOADGAME 直接调用
    • 如果没有定义 @TITLE_LOADGAME 则显示默认的存档加载界面
      (与 LOADGAME 命令加载的界面有微妙的不同)

自定义标题界面#

如果定义了 @SYSTEM_TITLE 函数,则直接调用。
后续的处理自然也由制作者自行决定并实现。

需要注意的是,如果在自定义的 @SYSTEM_TITLE 里没有执行 BEGIN / LOADDATA 命令就 RETURN 终止运行会报错。

因为一个游戏在任何情况下都不应该自行结束。

游戏必须是一个永无止境的循环,当然了,中途肯定可以停下来询问玩家的输入。
征询玩家接下来要怎么做,退出游戏 或者 继续游玩 都是玩家的自由。

但一定是无限的循环运行,一定不能自行其是地退出。

官方流程图#

FIRST 新游戏#

调用方式:

  • 在默认的标题界面选择 [0] 最初からはじめる
  • 使用 BEGIN FIRST 主动调用

一般来说,这里是游戏开始之初,进行初次配置 / 捏人设定角色的步骤。

必须自定义 @EVENTFIRST 函数,未定义会报错。
另外,如果没有执行 BEGIN 命令就结束运行也会报错,理由之前说过了。

官方流程图#

SHOP 商店#

调用方式:

  • LOADDATA 后自动运行
  • 使用 BEGIN SHOP 主动调用

是否自动存档由配置项 オートセーブを行なう:YES 决定。
设置为 YES 自动存档,NO 不会自动存档。

必须自定义 @SHOW_SHOP 函数,未定义会报错。

显示商店界面#

调用 @SHOW_SHOP 之后要求输入购买的商品,需要在 0 ~ 99 之间(这个范围可以在 _Replace.csv 里编辑販売アイテム数 来修改)。

当输入范围外的数值时,会调用 @USERSHOP,可以通过这个函数将标准的 SHOP商店 循环变成其他的游戏界面,比如可以做成游戏的主体(待机)界面。

此外,PRINT_ITEMSHOP 命令显示 ITEMNAMEITEMSALES 两个数组中元素数量较小的那个数组的范围(默认为 1000),可以在 VariableSize.csv 中修改。

处理购买指令#

处理购买时:

  1. 检查 ITEMSALES(有存货)是否在 0 以上,MONEY 是否大于 ITEMPRICE
  2. 如果购买失败(判定没有通过),要求玩家重新输入。

eramaker 购买失败时会从 @SHOW_SHOP 重新开始。

购买成功时:

  1. BOUGHT 变量(上次购买)赋值为 ITEM 的编号。
  2. ITEM:BOUGHT(背包 / 仓库)+1
  3. MONEY 减去 ITEMPRICE:BOUGHT 的值(付费)。
  4. (可选)如果定义了 @EVENTBUY,则调用 @EVENTBUY 函数。
  5. 最后返回 @SHOW_SHOP

除非在某个地方执行 BEGIN 命令,否则永远不会退出 SHOP 流程。

再强调一遍:由于制作者可以接过玩家输入的指令另行处理(@USERSHOP)、以及「永远自循环」的特性,因此可以把默认的「商店」页面做成别的功能,比如「待机状态主页面」。
事实上很多现有的 era 游戏也确实是这样做的。

官方流程图#

TRAIN 调教#

调用方式:

  • 使用 BEGIN TRAIN 主动调用

首先会对一些变量进行初始化:

一、ASSIPLAY:0 = 0PREVCOM:0 = -1NEXTCOM:0 = -1

手动将 >= 0 的数值赋给 NEXTCOM 会导致死循环,此处不讨论。
Emuera 的 NEXTCOM 是为了重现(兼容)eramaker 的原有行为,包括上述缺陷。
并没有设计新的用途。

二、TFLAG 全部归零,所有角色的 GOTJUELTEQUIPEXPALAMSOURCE 归零

由于离开 TRAIN 时不会再次初始化,因此存档时会在存档文件中保存这些值。
推荐在 @SAVEINFO 函数(存档前的可选函数)中将角色的 GOTJUELTEQUIPEXPALAM 手动重置为 0 以压缩存档文件大小。

三、STAIN:2 = 2STAIN:3 = 1STAIN:4 = 8、其他 STAIN 归零(意义不明

STAIN 数组的初始值可以在 _Replace.csv 指定 汚れの初期値 来修改。

显示调教界面#

调用 @SHOW_STATUS 后显示可用的 TRAIN 选项。

调教指令数量上限 MAX_TRAIN 可以设置 VariableSize.csvTRAINNAME 来修改。

根据 TRAINNAME 的内容查找 @COM_ABLExx 函数是否存在:

  • 如果 @COM_ABLExx 函数不存在或返回非零值,显示可以执行的 TRAINNAME
  • 如果 @COM_ABLExx 返回 0,则不能执行,也不会显示 TRAINNAME

这个查询结果(是否可以执行 TRAINNAME)会被缓存下来。
下次运行时不会再次重复调用 @COM_ABLExx

この時に実行可能かどうかを記憶しておく。
(実行時に再度@COM_ABLExx を呼び出すわけではない。)

哟,这不是 Python 3.9 的 @functools.cache 嘛,领先十年怎么说领先十

显示 TRAINNAME 结束后:

  1. 调用 @SHOW_USERCOM
  2. @SHOW_USERCOM 运行结束后,初始化 UPDOWNLOSEBASE
    (以及 CUPCDOWNDOWNBASE。)
    即:在 @USERCOM / @EVENTCOM 函数中才会看到初始化后的效果。
  3. 要求输入。

处理调教指令#

CALLTRAIN(重复调教指令 n 次)和 DOTRAIN(强制执行调教指令)这两个命令的用法可以参考 官方文档

将输入与 @COM_ABLExx 的结果进行比对,如果可以执行,调用对应的 @COMxx

  1. TRAIN番号 赋值给 SELECTCOM 变量
  2. 所有角色的 NOWEX 数组中的所有元素初始化为 0
  3. (可选)调用 @EVENTCOM
  4. 调用对应的 @COMxx
    • 如果 @COMxx 返回值为 0,返回 @SHOW_STATUS
    • 如果 @COMxx 返回值不为 0:
      1. 调用 @SOURCE_CHECK
        • 如果存在 @EVENTCOMEND,将所有角色的 SOURCE 的所有元素初始化为 0
        • 如果不存在 @EVENTCOMEND 或者在 @EVENTCOMEND 中从未执行过 WAIT,则生成一个 WAIT
      2. 返回 @SHOW_STATUS

如果输入不是可执行(存在 TRAIN番号)的命令,调用 @USERCOM 后直接返回到 @SHOW_STATUS

执行 UPCHECK 会将 + UP - DOWN 结算给 PALAM:TARGET,然后 UP / DOWN 归零。

操作目标PALAM
上升量
PALAM
下降量
触发结算
命令
BASE
损失量
临时旗标
TARGETUPDOWNUPCHECK
显示结果
LOSEBASETFLAG
其他角色CUPCDOWNCUPCHECK 角色编号
不显示结果
DOWNBASETCVAR

除非在某个地方执行 BEGIN 命令进行跳转,否则永远不会退出 TRAIN 流程。

官方流程图#

AFTERTRAIN 调教结算#

调用方式:

  • 使用 BEGIN AFTERTRAIN 主动调用

  • 如果没有执行 BEGIN 命令就运行结束会报错

ABLUP 能力升级#

调用方式:

  • 使用 BEGIN ABLUP 主动调用

显示升级界面#

依次调用 @SHOW_JUEL@SHOW_ABLUP_SELECT 后要求输入。

处理升级指令#

  • 如果输入在 0 ~ 99 范围内,查找对应的 @ABLUP
    • 如果存在对应的 @ABLUP 函数,调用该函数后返回 @SHOW_JUEL
    • 如果不存在对应的 @ABLUP 函数,要求重新输入
  • 如果输入在范围之外,调用 @USERABLUP 后返回 @SHOW_JUEL

如果是 eramaker 中未定义 @ABLUP 函数,直接返回到 @SHOW_JUEL

除非在某个地方执行 BEGIN 命令,否则永远不会退出 ABLUP 流程。

官方流程图#

TURNEND 结束回合#

调用方式:

  • 使用 BEGIN TURNEND 主动调用

  • 如果没有执行 BEGIN 命令就运行结束会报错

SAVEGAME 保存存档#

调用方式:

  • 执行 SAVEGAME 命令时调用

执行 @SAVEINFO 的时机在写入存档之前。

LOADGAME 读取存档#

调用方式:

  • 执行 LOADGAME 命令时调用

BEGIN 命令自带 RETURN,即 BEGIN 之后的代码永远不会运行(类似 JUMP)。
LOADGAME / SAVEGAME 会和 CALL 一样运行结束时回到调用它的地方。

但如果执行 LOAD,会无视调用它的地方,跳转到 LOADDATAEND

LOADDATAEND 读取数据结束#

调用方式:

  • LOADGAME 函数执行 LOAD 步骤时调用
  • 执行 LOADDATA 命令之后调用

执行 LOAD 时,之前的状态(如调用中的函数)都将被清除。

eramaker 什么都不会做,直接跳转到 @SHOW_SHOP

  • 如果定义了 @SYSTEM_LOADEND,执行 @SYSTEM_LOADEND,并在执行结束前使用 BEGIN 跳转
  • 如果没有定义 @SYSTEM_LOADEND,并且定义了 @EVENTLOAD,执行 @EVENTLOAD,并在执行结束前使用 BEGIN 跳转
    • 如果没有使用 BEGIN 跳转,则像通常情况一样跳转到 @SHOW_SHOP

lackbfun © 2021 - 2024