PokuG stdio.h

ポクジィと読みます

PC-98ノベルゲームエンジン開発:スクリプト命令まとめ

昨今「バイブコーディング」が話題になっているので、乗り遅れないようにチャレンジしてみた成果物です。

今回作っているのは、PC-98で動作するADV(ノベル)ゲームエンジンです。

この記事では、現在実装しているスクリプト仕様を整理してまとめます。
このエンジンでは、script.txt を用意することで、背景表示・立ち絵・会話・選択肢・分岐などを制御できます。

なお本プロジェクトは、ChatGPTやCodexを活用しながら開発しています。
コード生成の大部分(99%以上)はAIに支援してもらっています。
実機での動作確認や仕様の調整だけは自分で行っています。

PC-98という制約のある環境でどこまで作れるか、試行錯誤しながら開発しています。

本記事はネット上からいつでも見れるようにするための管理人のメモ書きです!
バイナリの配布(githubの公開)はそのうち公開予定ですが直近ところはありません。

ちなみに本記事は非常に説明的になっていますが、これはソースコードをChatGPT先生に読んでもらって、「現在の仕様と今後の課題を出して」と頼んだ結果をほぼ未修正でコピペしたためです。

チャレンジしてみた結果

チャレンジしてみた結果です。 こういうの出来ました。


www.youtube.com

開発環境

AIツール

本プロジェクトでは以下のAIツールを活用しています。

  • ChatGPT
  • Codex(CLI)

コード生成や仕様検討の大部分はこれらのAIに支援してもらっています。


開発環境

  • Windows 11(25H2)
  • WSL(Ubuntu)
  • ia16-elf-gcc(MS-DOS 向けクロスコンパイラ)
  • VS Code

主にWSL上で開発し、C言語 (イン アセンブラ) でエンジンを実装しています。

環境構築方法は以下リンクです。
Codexに丸投げでPC-98のHello Worldを実機で動かすまで(WSL+ia16環境構築) - PokuG stdio.h


実行・確認環境

  • エミュレータ:T98-NEXT
  • 実機:PC-9821Ra43、PC-9821V13
  • OS:MS-DOS6.2、MS-DOS5.0A-H

開発中はエミュレータで確認しつつ、最終的な動作は実機で確認しています。

PC-98 ADVエンジン script.txt 命令メモ

自作PC-98 ADVゲームエンジン用の script.txt の書き方メモです。
自分が忘れないための説明書として、現在の仕様をまとめています。


基本ルール

スクリプトは script.txt に書きます。

大きく分けると、行には2種類あります。

#で始まる行  → 命令
[名前]        → 話者名
普通の文章    → メッセージ本文

例:

#bg bg01
#right character01 normal

[美緒]
こんにちは、健一。

[健一]
えっと……呼び出したのは美緒だよね?

こんな感じになります。 www.youtube.com


表示仕様

現在のメッセージ表示は以下の仕様です。

1行:25文字
表示:3行

文章が長い場合は、エンジン側でページ送りされます。
基本操作は Enter キーで進行します。


背景表示:#bg

背景を変更する命令です。

#bg bg01

現在使える背景ID:

スクリプト 読み込むファイル
#bg bg01 bg001.g98
#bg bg02 bg002.g98
#bg bg03 bg003.g98

例:

#bg bg01

[]
教室は静かだった。

#bg bg02

[]
廊下に出ると、夕方の光が差し込んでいた。

背景ファイルは PC-98 / DOS で扱いやすいように、8.3形式のファイル名にしています。

bg001.g98
bg002.g98
bg003.g98

立ち絵表示:#left / #right

左側または右側にキャラクターを表示します。

#left character01 normal
#right character02 happy

書式:

#left  キャラID 表情
#right キャラID 表情

現在使う想定のキャラID:

キャラID
character01
character02
character03

現在使える表情:

表情 意味 ファイル名の記号
normal 通常 n
happy 笑顔 h
angry 怒り a
surprised 驚き s

実際に読み込むファイル名は以下のようになります。

スクリプト 読み込むファイル
#right character01 normal c01_n.spr
#right character01 happy c01_h.spr
#right character01 angry c01_a.spr
#right character01 surprised c01_s.spr
#left character02 normal c02_n.spr
#left character03 happy c03_h.spr

例:

#bg bg01
#right character01 normal

[美緒]
ちょっと聞きたいことがあるんだけど。

#right character01 angry

[美緒]
冷蔵庫のタルト、知らない?

立ち絵を消す:none

立ち絵を消したい場合は、キャラIDに none を指定します。

#left none
#right none

例:

#right character01 normal

[美緒]
またあとでね。

#right none

[]
美緒は教室を出ていった。

話者名:[]

話者名は [] で指定します。

[美緒]
こんにちは。

名前なしの地の文にしたい場合は、空の [] を使います。

[]
誰もいない教室は、妙に静かだった。

選択肢:#choice

2択の選択肢を表示します。

書式:

#choice ラベル1 ラベル2
選択肢1の文章
選択肢2の文章

例:

#choice ask help
素直に手伝う
少しだけ断ってみる

選択肢1を選ぶと #label ask へ移動します。
選択肢2を選ぶと #label help へ移動します。

操作:

↑ / ↓ キー
W / S キー
8 / 2 キー
Enterで決定

ラベル:#label

ジャンプ先の目印です。

#label start

#label 自体は画面には表示されません。

例:

#label ask
[健一]
わかった。僕でよければ手伝うよ。

ジャンプ:#jump

指定したラベルへ移動します。

#jump ラベル名

例:

#jump common_route

選択肢のあとに共通ルートへ戻すときに使います。

#choice route_a route_b
手伝う
断る

#label route_a
[健一]
わかった。手伝うよ。
#jump common

#label route_b
[健一]
ごめん、今は少し難しいかも。
#jump common

#label common
[]
こうして、放課後の調査が始まった。

フラグを立てる:#set

フラグをONにします。

#set flag_name

例:

#set helped_mio

フラグを消す:#reset

フラグをOFFにします。

#reset flag_name

例:

#reset helped_mio

条件分岐:#if

フラグがONのときだけ、指定したラベルへジャンプします。

#if フラグ名 ラベル名

例:

#if helped_mio good_route

helped_mio がONなら #label good_route へ移動します。
OFFなら、そのまま次の行へ進みます。


条件分岐:#ifnot

フラグがOFFのときだけ、指定したラベルへジャンプします。

#ifnot フラグ名 ラベル名

例:

#ifnot helped_mio normal_route

helped_mio がOFFなら #label normal_route へ移動します。


パレット変更:#pal

外部パレットファイルを読み込みます。

#pal adv.pal

基本的にはゲーム開始時に adv.pal を読む想定です。
演出用に途中でパレットを変えることもできます。

例:

#pal adv.pal
#bg bg01

ファイル名ルール

PC-98 / DOSでは、基本的にファイル名は8.3形式です。

ファイル名:8文字まで
拡張子:3文字まで

そのため、以下のような長い名前は避けます。

stand_character01_normal.spr  ← 長すぎるのでNG

現在の推奨ルール:

背景

bg001.g98
bg002.g98
bg003.g98

立ち絵

c01_n.spr
c01_h.spr
c01_a.spr
c01_s.spr

c02_n.spr
c02_h.spr
c02_a.spr
c02_s.spr

c03_n.spr
c03_h.spr
c03_a.spr
c03_s.spr

画像サイズの現在仕様

背景

640 x 400

背景は .g98 形式です。

立ち絵

最大 256 x 290

現在の立ち絵読み込み処理では、横幅256pxまでが安全です。
横幅280pxなどにすると読み込みエラーになります。


スクリプト例:基本

#pal adv.pal
#bg bg01
#right character01 normal

[美緒]
健一、ちょっといい?

[健一]
どうしたんだ?

#right character01 angry

[美緒]
冷蔵庫のタルト、知らない?

[健一]
えっ、僕は知らないよ。

スクリプト例:選択肢と分岐

#bg bg01
#right character01 normal

[美緒]
犯人探し、手伝ってくれる?

#choice help refuse
手伝う
断る

#label help
#set helped_mio

[健一]
わかった。僕でよければ手伝うよ。

#jump after_choice

#label refuse
#reset helped_mio

[健一]
ごめん、今はちょっと難しいかも。

#jump after_choice

#label after_choice

#if helped_mio good
#ifnot helped_mio normal

#label good
[美緒]
ありがとう。助かるよ。
#jump end

#label normal
[美緒]
そっか……わかった。
#jump end

#label end
[]
こうして放課後の時間が過ぎていった。

選択肢「YES」の場合
www.youtube.com

選択肢「NO」の場合
www.youtube.com


現在の命令一覧

命令 用途
#bg 背景変更
#left 左立ち絵変更
#right 右立ち絵変更
#choice 2択選択肢
#label ジャンプ先ラベル
#jump ラベルへ移動
#set フラグON
#reset フラグOFF
#if フラグONならジャンプ
#ifnot フラグOFFならジャンプ
#pal パレット読み込み

注意点

  • ファイル名は8.3形式にする。
  • 背景は bg001.g98 のような短い名前にする。
  • 立ち絵は c01_n.spr のような短い名前にする。
  • 立ち絵の幅は最大256pxまで。
  • #choice は2択専用。
  • #choice の直後2行が選択肢文になる。
  • #label は画面には表示されない。
  • #jump#if のラベル名には #label は付けず、名前だけを書く。

追記 -BGM関連

PMD.COM 常駐環境での BGM 再生に対応しています。

対応コマンド

コマンド 内容
#bgm opening.m BGMファイルを読み込み再生
#bgmstart 現在ロード済みBGMを再生
#bgmstop BGMを即停止
#bgmfade BGMをフェードアウト停止

使用例

#bg classroom
#bgm school.m

[美緒]
「おはよう」

■ 画像変換ツール

本エンジンでは、PNG画像をそのまま読み込むことはできないため、専用フォーマット(.g98 / .spr)に変換する必要があります。

なお、PNG画像は aseprite などドットの編集ソフトで作成します。
このとき16色で画像を作成し、キャラ / 背景 / UI を "1画面にに表示する" ので同じ16色で統一する必要があります


■ 背景画像:PNG → G98

背景画像は 001_png_to_g98.py を使用して .g98 に変換します。

● 使い方

python3 tools/001_png_to_g98.py input.png bg001.g98

● 出力ファイル

bg001.g98
bg001_preview.bmp
  • bg001.g98 → ゲームで使用する背景ファイル
  • bg001_preview.bmp → 変換結果の確認用BMP

● 処理内容

  • 画像を 640×400 にリサイズ
  • 固定16色パレットへ減色
  • パレット番号 0〜15 をそのまま使用
  • パレット0は予約色(透過扱い)

● 注意点

・サイズは必ず 640×400 に変換される
・色は16色に減色される
・見える黒は自動で別色に逃がされる

■ キャラ画像:PNG → SPR

立ち絵は 010_png_to_spr.py を使用して .spr に変換します。

● 使い方

python3 tools/010_png_to_spr.py input.png c01_n.spr

● 出力ファイル

c01_n.spr
c01_n_preview.bmp
c01_n_checker.bmp
  • c01_n.spr → ゲームで使用する立ち絵
  • *_preview.bmp → 通常確認用
  • *_checker.bmp → 透明部分確認用(市松模様)

● 処理内容

  • RGBA画像を読み込み
  • 透明部分 → パレット0へ変換
  • RGB → 固定16色パレットへ変換
  • 最近傍色で色を割り当て

● 透明処理の仕様

透明(alpha) → index 0

ただし、

黒 (0,0,0) は透過と衝突するため、
見える黒は index 2 に変換される

● 注意点

・パレット0は必ず透明になる
・黒をそのまま使うと消えるので注意
・画像サイズは自由(ただし描画側に制限あり)

■ ファイル命名ルール(重要)

PC-98のDOS制約により、8.3形式を守る必要があります。

● 背景

bg001.g98
bg002.g98
bg003.g98

● キャラ

c01_n.spr
c01_h.spr
c01_a.spr
c01_s.spr

■ サイズ制限

種類 サイズ
背景 640×400
立ち絵 最大 256×290

※ 立ち絵は横256pxを超えると読み込みエラーになります


■ メモ(重要)

・PNGから直接変換できる
・確認用BMPを必ずチェックする
・色ズレはここで発見できる
・透明処理はindex 0固定

■変換 まとめ

  • 背景 → PNG → G98(640×400固定)
  • キャラ → PNG → SPR(透過対応)
  • どちらも確認用BMPが出力される

この変換ツールを使うことで、PC-98用の画像素材を簡単に作成できます。

未実装・今後の課題

現在のエンジンは基本的な動作はできていますが、 まだ未実装・改善予定の機能があります。


描画の高速化

現状は背景や立ち絵を毎回描画しているため、 シーンによっては描画が遅くなる場合があります。

今後は以下の対応を予定しています。

・同じ背景の場合は再描画しない
・立ち絵の差分再描画(変更部分のみ描画)
・画面更新の最適化

VRAMバッファ未実装

現在はVRAMへ直接描画しているため、 描画の途中経過がそのまま画面に表示されてしまいます。

・背景 → 立ち絵 → テキスト

のように順番に描画されるため、 場合によっては描画のチラつき(フリッカー)が発生します。


今後は以下の対応を予定しています。

・オフスクリーンバッファの導入
・一度メモリ上に描画してからVRAMへ転送
・画面更新の一括処理

これにより、

・描画のチラつき軽減
・見た目の安定化
・高速化

が期待できます。


メモ

現在は「直接VRAM書き込み」方式
将来的には「ダブルバッファ」的な構造にする予定

PC-98のVRAM構造上、実装方法には制約がありますが、 可能な範囲で改善を検討しています。

FM音源未対応

現在は音声機能は未実装です。

・BGM再生(FM音源)
・効果音

PC-98らしさを出すため、将来的には FM音源(OPN系)の対応を検討しています。


セーブ/ロード機能

現状はセーブ機能がありません。

・スクリプト位置の保存
・フラグ状態の保存

テキスト表示機能の拡張

・自動送り(オートモード)
・スキップ機能
・表示速度調整

UI改善

・メッセージウィンドウの強化
・選択肢UIの改善
・名前表示の専用枠

スクリプト機能の拡張

・変数対応
・複雑な条件分岐
・マクロ的な機能

今後について

まずは描画の最適化を優先し、 その後に音やUIなどを順次追加していく予定です。

PC-98という制約のある環境で、 どこまで快適なゲーム体験を作れるかを目標に開発を続けていきます。