こんにちは。今回はDQ7 TASについてです。 今回、Bizhawkを使用している際にLuaScriptで各種情報の表示をするスクリプトを作成しました。

成果物

こんな感じで画面右下に各種情報が表示されます。 1番上から実時間。これはフレーム数から計算しています。 2番目は乱数。これはゲーム内の現在の乱数値を表示しています。 3番目はエンカウント歩数。エンカウントが発生するマップを歩くとこの値が減っていき、0を下回るとエンカウントが発生します。この値は乱数によって決定されています。 4,5番目は主人公を中心とした現在の位置情報を表示しています。x軸が左右の移動、z軸が上下の移動を表しています。

ソースコード

ソースコードについてはこちらのGithubにて公開しています。

https://github.com/jackjasonb/DQ7-Bizhawk-gui

lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<span class="token comment">--現在の座標を{x,z}で返す</span>
<span class="token keyword">function</span> <span class="token function">getPos</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>x <span class="token operator">=</span> memory<span class="token punctuation">.</span><span class="token function">read_s32_le</span><span class="token punctuation">(</span><span class="token number">0x0C7020</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z <span class="token operator">=</span> memory<span class="token punctuation">.</span><span class="token function">read_s32_le</span><span class="token punctuation">(</span><span class="token number">0x0C7028</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
<span class="token keyword">end</span>

<span class="token comment">--フレームを時間に変換</span>
<span class="token keyword">function</span> <span class="token function">frame2time</span><span class="token punctuation">(</span>frame<span class="token punctuation">)</span>
    <span class="token comment">--hour</span>
    hour <span class="token operator">=</span> math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>frame <span class="token operator">/</span> <span class="token punctuation">(</span><span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    frame <span class="token operator">=</span> frame <span class="token operator">-</span> hour <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span><span class="token punctuation">)</span>
    <span class="token comment">--min</span>
    min <span class="token operator">=</span> math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>frame <span class="token operator">/</span> <span class="token punctuation">(</span><span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    frame <span class="token operator">=</span> frame <span class="token operator">-</span> min <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span><span class="token punctuation">)</span>
    <span class="token comment">--sec</span>
    sec <span class="token operator">=</span> math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>frame <span class="token operator">/</span> <span class="token number">60</span><span class="token punctuation">)</span>
    frame <span class="token operator">=</span> frame <span class="token operator">-</span> sec <span class="token operator">*</span> <span class="token number">60</span>
    <span class="token comment">--msec</span>
    msec <span class="token operator">=</span> math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>frame <span class="token operator">/</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span>

    time <span class="token operator">=</span> string<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"%2d:%2d:%2d:%2d"</span><span class="token punctuation">,</span> hour<span class="token punctuation">,</span> min<span class="token punctuation">,</span> sec<span class="token punctuation">,</span> msec<span class="token punctuation">)</span>
    <span class="token keyword">return</span> time
<span class="token keyword">end</span>

<span class="token comment">-- 出力ファイルのオープン</span>
<span class="token keyword">local</span> file <span class="token operator">=</span> io<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"gui.txt"</span><span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">)</span>

<span class="token comment">-- ウィンドウサイズの計測</span>
<span class="token keyword">local</span> window_height <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">bufferheight</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">local</span> window_width <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">bufferwidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">while</span> <span class="token keyword">true</span> <span class="token keyword">do</span>
    <span class="token comment">-- 表示データの取得</span>
    <span class="token comment">-- フレーム数</span>
    frame <span class="token operator">=</span> emu<span class="token punctuation">.</span><span class="token function">framecount</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token comment">-- 実時間</span>
    time <span class="token operator">=</span> <span class="token function">frame2time</span><span class="token punctuation">(</span>frame<span class="token punctuation">)</span>
    <span class="token comment">-- 乱数</span>
    random_number <span class="token operator">=</span> string<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"%x"</span><span class="token punctuation">,</span> memory<span class="token punctuation">.</span><span class="token function">read_u32_le</span><span class="token punctuation">(</span><span class="token number">0x0F9BA0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">-- エンカウント歩数</span>
    encount_walk <span class="token operator">=</span> memory<span class="token punctuation">.</span><span class="token function">read_u16_le</span><span class="token punctuation">(</span><span class="token number">0x0F78DC</span><span class="token punctuation">)</span>
    <span class="token comment">-- 位置</span>
    position <span class="token operator">=</span> <span class="token function">getPos</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token comment">-- 画面表示部分</span>
    gui<span class="token punctuation">.</span><span class="token function">drawText</span><span class="token punctuation">(</span>
        window_width<span class="token punctuation">,</span>
        window_height <span class="token operator">-</span> <span class="token number">10</span><span class="token punctuation">,</span>
        time <span class="token operator">..</span>
            <span class="token string">"\n"</span> <span class="token operator">..</span> random_number <span class="token operator">..</span> <span class="token string">"\n"</span> <span class="token operator">..</span> encount_walk <span class="token operator">..</span> <span class="token string">"\n"</span> <span class="token operator">..</span> <span class="token string">"x:"</span> <span class="token operator">..</span> position<span class="token punctuation">[</span><span class="token string">"x"</span><span class="token punctuation">]</span> <span class="token operator">..</span> <span class="token string">"\nz:"</span> <span class="token operator">..</span> position<span class="token punctuation">[</span><span class="token string">"z"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token keyword">nil</span><span class="token punctuation">,</span>
        <span class="token keyword">nil</span><span class="token punctuation">,</span>
        <span class="token number">15</span><span class="token punctuation">,</span>
        <span class="token keyword">nil</span><span class="token punctuation">,</span>
        <span class="token keyword">nil</span><span class="token punctuation">,</span>
        <span class="token string">"right"</span><span class="token punctuation">,</span>
        <span class="token string">"bottom"</span>
    <span class="token punctuation">)</span>
    <span class="token comment">-- ファイル出力部分</span>
    file<span class="token punctuation">:</span><span class="token function">write</span><span class="token punctuation">(</span>
        frame <span class="token operator">..</span>
            <span class="token string">","</span> <span class="token operator">..</span>
                time <span class="token operator">..</span>
                    <span class="token string">","</span> <span class="token operator">..</span> random_number <span class="token operator">..</span> <span class="token string">","</span> <span class="token operator">..</span> encount_walk <span class="token operator">..</span> <span class="token string">","</span> <span class="token operator">..</span> position<span class="token punctuation">[</span><span class="token string">"x"</span><span class="token punctuation">]</span> <span class="token operator">..</span> <span class="token string">","</span> <span class="token operator">..</span> position<span class="token punctuation">[</span><span class="token string">"z"</span><span class="token punctuation">]</span> <span class="token operator">..</span> <span class="token string">"\n"</span>
    <span class="token punctuation">)</span>
    emu<span class="token punctuation">.</span><span class="token function">frameadvance</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">end</span>
Lua

BizhawkでのLuaの関数

以下今回使用したBizhawkに実装されている関数について解説します。

lua
1
void emu<span class="token punctuation">.</span><span class="token function">frameadvance</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
Lua

エミュレータのフレームを1フレーム進める関数。ゲームを動かしながらLuaを動かす際にはこちらをループさせて適宜フレームを進めてやる必要があります。

lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
memory<span class="token punctuation">.</span><span class="token function">readbyte</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s8</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u8</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s16_le</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s16_be</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u16_le</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u16_be</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s24_le</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s24_be</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u24_le</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u24_be</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s32_le</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

int memory<span class="token punctuation">.</span><span class="token function">read_s32_be</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u32_le</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>

uint memory<span class="token punctuation">.</span><span class="token function">read_u32_be</span><span class="token punctuation">(</span>int addr<span class="token punctuation">,</span> <span class="token punctuation">[</span>string domain <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>
Lua

こちらはゲームのメモリの値を各形式で読み込む関数です。1byteから4byteの間で、符号付きか符号なし、リトルインディアンかビックインディアンの形式の値を取得できます。上記のLuaScriptではこれを用いて乱数値やエンカウント歩数、座標をメモリから取得しています。上記のreadの部分をwriteにすることで、メモリの読み込みではなく書き込みを行うことができます。

lua
1
int emu<span class="token punctuation">.</span><span class="token function">framecount</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
Lua

現在のフレーム数を返す関数。上記のLuaScriptではこのフレーム数を元に時間を算出して画面に表示しています。

lua
1
void gui<span class="token punctuation">.</span><span class="token function">drawText</span><span class="token punctuation">(</span>int x<span class="token punctuation">,</span> int y<span class="token punctuation">,</span> string message<span class="token punctuation">,</span> <span class="token punctuation">[</span>color? forecolor <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>color? backcolor <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>int? fontsize <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>string fontfamily <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>string fontstyle <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>string horizalign <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>string vertalign <span class="token operator">=</span> null<span class="token punctuation">]</span><span class="token punctuation">)</span>
Lua

Draws the given message in the emulator screen space (like all draw functions) at the given x,y coordinates and the given color. The default color is white. A fontfamily can be specified and is monospace generic if none is specified (font family options are the same as the .NET FontFamily class). The fontsize default is 12. The default font style is regular. Font style options are regular, bold, italic, strikethrough, underline. Horizontal alignment options are left (default), center, or right. Vertical alignment options are bottom (default), middle, or top. Alignment options specify which ends of the text will be drawn at the x and y coordinates.(TASVideosより引用)

画面に指定のテキストを描画する関数。引数は順番に、「表示するx座標、y座標、表示するメッセージ、フォントの色、背景の色、フォントのサイズ、フォント、フォントのスタイル(ボールドとかイタリックとか)、テキストの表示位置(x,y座標)を決めるときに左右中央どこを基準とするか、同様に上下中央どこを基準とするか」です。上記の[]で囲まれている部分は必須項目ではなく、予めデフォルト値が設定されています。

lua
1
2
int client<span class="token punctuation">.</span><span class="token function">bufferheight</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
int client<span class="token punctuation">.</span><span class="token function">bufferwidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
Lua

エミュレータの描画領域の高さと幅を返す関数。上記のLuaScriptでは右下に各種情報を表示したかったので、この値を用いてdrawText()に値を渡しています。

Bizhawkに実装されている関数は以下のTAS Videosのサイトから参照することができます。(英語) http://tasvideos.org/Bizhawk/LuaFunctions.html

メリット

この関数のメリットとして、Bizhawkに予め備わっているRamWatchと言うメモリの内容を表示する機能よりも高速であるという点があります。このLuaScriptもRamWatchもメモリの内容を表示するという点では同じなのですが前者のほうが柔軟性もあり、高速です。また、各フレームで表示した値を外部ファイルに保存しておくことで、動画作成などに用いることもできます。

というわけで今回は以上です。そもそもTASを始める前にこういうことを勉強しておくべきだった気もしますが…….。この記事の内容とかは他のゲームにも利用できるので是非参考にしてみてください。 以上です。お読み頂き有難う御座いました。また宜しくお願いします。


2019.11.04 11:35  2020.04.17 18:52