Emuera 原生游戏运行流程浅析
你暂时逃掉的课,总有一天要补回来。(悲)
参考资料:《官方文档 / フロー図》
个人吐槽
我一向是不太看得起 Emuera 内置的所谓「标准游戏流程」的。
(没有考据过,大概也是从 eramaker 时代继承下来的?)
也就是 SHOP
/ TRAIN
那一套。
这种流程死板而臃肿,让我见到的第一眼就心生不喜。
时间转瞬即逝,我个人接触 era 也快一年了。
我曾经两度壮志雄心想要写一个 era 游戏,两度被劝退,就是因为这套东西。
我自己写当然是从
@SYSTEM_TITLE
就开始接手,自行设计游戏流程了。
每每当我尝试创作的时候,阅读别人的 era 游戏代码以作参考,大多都是用的这套。
然后我就会不由自主地考虑能不能用在我的游戏里。
接着光是想象就被恶心到,遂放弃。周而复始这个过程。
这玩意不是我不想看,我就能不看的。
我也是负责运营社群的一员,有人好声好气来反应 bug 我难道还能晾着人家吗。
在这种无限循环的折磨中,我着实被耗尽了耐心。
但几经波折,兜兜转转还是回到了这里。
毕竟对没有任何编程基础的新手来说,你不能强求他们先去学习枯燥的数据结构。
哪怕你有心深造,我也不建议你零基础直接生啃数据结构。
这种干瘪的工作真的会极大程度上磨灭你的创作激情。
Emuera 自带的标准流程,确实是对新人(开发者)最友好的选择了。
为了完成足够详尽的开发教程,尽管内心仍然抗拒不已,我还是不得不捏着鼻子()去梳理这套玩意。什么恶堕剧情
TITLE 标题界面#
调用方式:
- 在启动 Emuera 并读取所有 erb 文件后自动运行
- 使用
BEGIN TITLE
主动调用
使用默认的标题界面#
如果没有定义 @SYSTEM_TITLE
函数,就显示默认的标题界面,如下图所示:
至于这里自动读取并显示的信息可以在
GameBase.csv
和_Replace.csv
修改。
然后是仅有的两个选项:
- 选择
[0] 最初からはじめる
- 初始化游戏数据(
RESETDATA
/ADDCHARA 0
等 ) - 开始新游戏
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
,可以通过这个函数将标准的
此外,
PRINT_ITEMSHOP
命令显示ITEMNAME
和ITEMSALES
两个数组中元素数量较小的那个数组的范围(默认为 1000),可以在VariableSize.csv
中修改。
处理购买指令#
处理购买时:
- 检查
ITEMSALES
(有存货)是否在0
以上,MONEY
是否大于ITEMPRICE
。 - 如果购买失败(判定没有通过),要求玩家重新输入。
eramaker 购买失败时会从
@SHOW_SHOP
重新开始。
购买成功时:
BOUGHT
变量(上次购买)赋值为ITEM
的编号。ITEM:BOUGHT
(背包 / 仓库)+1
。MONEY
减去ITEMPRICE:BOUGHT
的值(付费)。- (可选)如果定义了
@EVENTBUY
,则调用@EVENTBUY
函数。 - 最后返回
@SHOW_SHOP
。
除非在某个地方执行 BEGIN
命令,否则永远不会退出 SHOP
流程。
再强调一遍:由于制作者可以接过玩家输入的指令另行处理(@USERSHOP
)、以及「永远自循环」的特性,因此可以把默认的「商店」页面做成别的功能,比如「待机状态主页面」。
事实上很多现有的 era 游戏也确实是这样做的。
官方流程图#
TRAIN 调教#
调用方式:
- 使用
BEGIN TRAIN
主动调用
首先会对一些变量进行初始化:
一、ASSIPLAY:0 = 0
、PREVCOM:0 = -1
、NEXTCOM:0 = -1
手动将
>= 0
的数值赋给NEXTCOM
会导致死循环,此处不讨论。
Emuera 的NEXTCOM
是为了重现(兼容)eramaker 的原有行为,包括上述缺陷。
并没有设计新的用途。
二、TFLAG
全部归零,所有角色的 GOTJUEL
、TEQUIP
、EX
、PALAM
、SOURCE
归零
由于离开
TRAIN
时不会再次初始化,因此存档时会在存档文件中保存这些值。
推荐在@SAVEINFO
函数(存档前的可选函数)中将角色的GOTJUEL
、TEQUIP
、EX
、PALAM
手动重置为 0 以压缩存档文件大小。
三、STAIN:2 = 2
、STAIN:3 = 1
、STAIN:4 = 8
、其他 STAIN
归零(意义不明)
STAIN
数组的初始值可以在_Replace.csv
指定汚れの初期値
来修改。
显示调教界面#
调用 @SHOW_STATUS
后显示可用的 TRAIN
选项。
调教指令数量上限
MAX_TRAIN
可以设置VariableSize.csv
的TRAINNAME
来修改。
根据 TRAINNAME
的内容查找 @COM_ABLExx
函数是否存在:
- 如果
@COM_ABLExx
函数不存在或返回非零值,显示可以执行的TRAINNAME
。 - 如果
@COM_ABLExx
返回 0,则不能执行,也不会显示TRAINNAME
。
这个查询结果(是否可以执行 TRAINNAME
)会被缓存下来。
下次运行时不会再次重复调用 @COM_ABLExx
。
この時に実行可能かどうかを記憶しておく。
(実行時に再度@COM_ABLExx を呼び出すわけではない。)
哟,这不是 Python 3.9 的 @functools.cache
嘛,领先十年怎么说领先十。
显示 TRAINNAME
结束后:
- 调用
@SHOW_USERCOM
。 - 在
@SHOW_USERCOM
运行结束后,初始化UP
、DOWN
、LOSEBASE
。
(以及CUP
、CDOWN
、DOWNBASE
。)
即:在@USERCOM
/@EVENTCOM
函数中才会看到初始化后的效果。 - 要求输入。
处理调教指令#
CALLTRAIN
(重复调教指令 n 次)和DOTRAIN
(强制执行调教指令)这两个命令的用法可以参考 官方文档。
将输入与 @COM_ABLExx
的结果进行比对,如果可以执行,调用对应的 @COMxx
:
- 将
TRAIN番号
赋值给SELECTCOM
变量 - 所有角色的
NOWEX
数组中的所有元素初始化为 0 - (可选)调用
@EVENTCOM
- 调用对应的
@COMxx
- 如果
@COMxx
返回值为 0,返回@SHOW_STATUS
- 如果
@COMxx
返回值不为 0:- 调用
@SOURCE_CHECK
- 如果存在
@EVENTCOMEND
,将所有角色的SOURCE
的所有元素初始化为 0 - 如果不存在
@EVENTCOMEND
或者在@EVENTCOMEND
中从未执行过WAIT
,则生成一个WAIT
- 如果存在
- 返回
@SHOW_STATUS
- 调用
- 如果
如果输入不是可执行(存在 TRAIN番号
)的命令,调用 @USERCOM
后直接返回到 @SHOW_STATUS
。
执行
UPCHECK
会将+ UP - DOWN
结算给PALAM:TARGET
,然后UP
/DOWN
归零。
操作目标 | PALAM 上升量 | PALAM 下降量 | 触发结算 命令 | BASE 损失量 | 临时旗标 |
---|---|---|---|---|---|
TARGET | UP | DOWN | UPCHECK 显示结果 | LOSEBASE | TFLAG |
其他角色 | CUP | CDOWN | CUPCHECK 角色编号 不显示结果 | DOWNBASE | TCVAR |
除非在某个地方执行 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
- 如果没有使用