ロポコの作り方!
何だか無性にMZ-700の凄さを語りたい気分……というわけで、今回は以前同人誌に寄稿した『ロポコの作り方』という記事を加筆修正して掲載したいと思います。決して今月のネタがないからとか、そういうことではありません! 決して……。
この記事では、これまであまり語ってこなかったMZ-700版ロポコのプログラム面について簡単に解説をしてみたいと思います。時間と労力の関係で各機能の細かい部分までは書けないため、プログラムの主要部分である「メモリマップ」「メインルーチン」「タイマ割り込み」に絞ってご紹介します。もしも用語の説明などで間違っているところがあれば、遠慮なくご指摘いただければと思います。
MZ-700のハードウェア情報やプログラミング技法についてより詳しく知りたい方は、紅茶羊羹さんのサイト「We Love MZ-700」をご覧ください🙇

主な使用ツール
・Z80AS(アセンブラ)
・CGE7(キャラグラ制作)
・mz0c、zx0(圧縮ツール)
・DumpListEditor(MZT→WAV変換)
・MZ700WIN改造版、EmuZ700/1500(エミュレータ)
・MZ-700、MZ-1500(実機)
メモリマップ

ワークエリア
通常、メモリ上のアドレス0000h-0FFFhにはモニタROMが置かれていますが、ロポコではモニタのサブルーチンはテープのセーブ/ロードを除いて使用しないため、バンク切り替えをしてワークエリア用のDRAMとして使用します。このワークエリアにはアドレスが若い順に以下のデータが書き込まれます。
・編集中の文章データ
・背景用仮想テキストVRAM
・前景用仮想テキストVRAM
・背景用仮想アトリビュートVRAM
・前景用仮想アトリビュートVRAM
ご存知のように(?)、MZ-700はVRAMへデータを書き込む際に大きなウェイトが発生します。そのため、あらかじめ仮想VRAM上で背景と前景(主にロポコ)を合成してから、まとめてVRAMへ書き込むようにしています。速さを出すコツは、ロポコ以外のオブジェクトを一切動かさないことですね。ADVなのでいいんです。
【モニタROM】
プログラムを動かす上で便利なサブルーチン(≒関数)がいっぱい入っているROM。ROMなので書き換えはできない。
【DRAM】
RAMの一種だが、ここではユーザーが自由に使用できるメモリの意。
【VRAM】
映像出力用のメモリ。ここにデータを書き込むと画面に文字が表示される。
【仮想VRAM】
VRAMに書き込むデータをフリーエリア上で再現したもの。もちろん正式名称ではない。ここで出力したいデータを編集した後、VRAMに一括で転送する。
【バンク切り替え】
使用するROMやRAMをユーザーが選択することができる機能。例えば、0000h〜0FFFhの区間を「セーブ/ロードをするときはモニタROMバンク、それ以外はDRAMバンク」と随時切り替えることで、フリーエリアを増やすことができる。

共通データ・共通テキストデータ
共通データと共通テキストデータは「プログラムテープ(ROPOKO-P.mzt)」に収録されています。モニタからデータをロードしたのち、バンク切り替えでD000h以降のメモリをDRAMに切り替え、そこに共通テキストデータを移動させます。ちなみに、このテキストデータはすべてキャラクターのセリフです。A面B面でデータを共有することにより、地下階からも電話でキャラクターと会話をすることができます。
実は、ロポコ内でもっとも容量を食っているのはこのテキストデータなんです。グラフィックデータと違って規則性がないため、たとえ圧縮しても全然容量が減りません……。
シナリオデータ
A面とB面のシナリオデータは「シナリオテープ(ROPOKO-A/B.mzt)」にそれぞれ収録されており、元々共通テキストデータがあったスペースにデータをロードします。途中でテープを切り替える際は、このシナリオデータの部分だけを差し替えます。
また「ROPOKO-P/A/B.mzt」は、ロード時間短縮のためにそれぞれmz0cで圧縮されており、シナリオデータを差し替える際は、ロード後に圧縮データを展開する必要があります。ただ、この処理がトラブルの元になりやすいのも確かでして、ロポコの重大なバグのほとんどは、テープチェンジとバンク切り替え、そしてタイマ割り込みによって引き起こされていたと言っても過言ではないでしょう……。

メインルーチン
タイトル画面、プチロポコ、エンディングの3つを除き、ゲーム中は以下のメインルーチンが延々とループされています。各項目はコール命令で呼び出されるサブルーチンです。それぞれの処理の最初には条件チェックがあり、条件が満たされていない場合は処理を実行せずにメインルーチンに戻ります。なお、重要度が低いサブルーチンは省略しています。
・プレイ時間の変換
・キー入力チェック
・コマンドの入力
・コマンドの実行
・イベントの実行
・アイテムの表示(F1)
・語彙力の表示(F2)
・セーブ・ロード(F3)
・タイトル・ロード画面への移動(F4)
・ヘルプの表示(F5)
・ロポコの移動
・最前景をセット
・シーンエリアを描画(画面上3/4)
・テキストエリアを描画(画面下1/4)
・画面の振動
・ウェイト
プレイ時間の変換
タイマ割り込み時にカウントしたプレイ時間用の値を「秒・分・時」に変換します。
キー入力チェック
各キーの状態はメモリに保存されており、数値によって状態を判断します。
0:キーが押されていない
1:キーが押された
2:キーが長押しされている
キーが押されている場合、このルーチンが実行されるたびに各キーの数値が「0 → 1 → 2」と増えていきます。つまりキーを「2」の状態にするには、最低でもメインルーチンを2周する必要があるということです。また、IC8255からキー状態を取得するために、DRAM部分をメモリマップドI/O領域へバンク切り替えする必要があります(終わったら戻す)。
ちなみに、アレンジ版である『ロポコ for Steam』『ロポコ for Nintendo Switch』では、これらに加えて【3:キーが一定時間以上長押しされている】という状態も定義しています。単語選択画面でカーソルキーを一定時間押し続けると、カーソルが画面上を移動していきます。
コマンドの入力
コマンドの入力があった場合、ローマ字変換をしたのち、テキストエリアに文字を表示させます。
コマンドの実行
入力されたコマンドが有効かどうかチェックし、有効だった場合はメモリにコマンド番号を保存します。次の「イベントの実行」では、この番号を参照してイベントを分岐させます。
イベントの実行
条件が満たされている場合(接触判定、コマンド、キー入力、フラグなど)部屋番号に応じたイベントを実行します。
F1-F5
ファンクションキーが押された場合、各機能の画面を表示します。
ロポコの移動
カーソルキーが押されている場合、ロポコを移動させます。部屋の端に到達した場合、あるいはドアの前で上下キーが押された場合は部屋移動を行い、新たな背景をセットします。なお、接触判定は水平方向のみです(計算が簡単)。
最前景をセット
物置のカプセルなど、ロポコの手前に重なるオブジェクトがある場合、ロポコのグラフィックの上から上書きします。つまり「壁(背景) - ロポコ(前景) - カプセル(最前景)」のようにロポコがサンドイッチになる形になります。ただし、この処理は動作スピードへの影響が大きいため、ロポコが該当するオブジェクトに接触している時のみ行います。あらかじめ背景に最前景と同じオブジェクトを描き込んでおき、接触していない場合はそちらを表示します。
誤解のないように説明しておくと、MZ-700が持っているグラフィック用の画面はあくまで1画面だけです。背景や前景などというのは、単にこちらでそう定義しているだけなのであしからず……。

シーンエリア・テキストエリアを描画
「シーンエリア or テキストエリア描画の予約」がされていた場合、ここでまとめて仮想VRAMからVRAMへデータを転送し、映像を出力します。ゲーム画面の上3/4をシーンエリア、下1/4をテキストエリアとすることにより、必要な部分のみ描画されるようにしています。こちらのルーチンでもD000h以降をバンク切り替えする必要がありますが、描画中に割り込みが来た場合を考慮し、あらかじめ現在のバンク状態をメモリに保存しておきます(タイマ割り込みの項目で解説)。
画面の振動
「振動の予約」があった場合、VRAM上のデータを直接ずらして上下左右に画面を振動させます。ずれて空いた列には黒い線を描画してそれっぽく見せます。振動の強さや長さも指定可能です。
ウェイト
「ウェイトの予約」があった場合、ここでウェイトを取ってゲームスピードを調整します。ただし、実際にはイベント用ルーチン内で直接ウェイトを取ることも多いです(演出の処理が簡単になるため)。ウェイトの値はタイマ割り込み時にカウントします。
タイマ割り込み
ロポコでは「BGMの演奏」「効果音の演奏」「プレイ時間・ウェイトのカウント」のすべてにタイマ割り込みを使用しているため、割り込みの頻度を一定に保つ必要があります。そのため、全楽曲をBPM 150に固定し、32分音符ごとに割り込みが発生するように設定しています。割り込み時に行う処理は以下の通りです。
・レジスタ退避
・D000h以降をバンク切り替え
・効果音の出力
・BGMの出力
・タイムコードのカウント
・ウェイトのカウント
・プレイ時間のカウント
・DRAMにバンク切り替え
・レジスタ復帰
レジスタ退避・復帰
割り込み中は、レジスタの内容を壊さないように「EXX」と「EX AF,AF'」命令で裏レジスタに切り替えます。一見PUSH・POP命令でもよさそうですが、なぜかその場合は曲のテンポが崩れてしまいます(動けばいいやの精神です……)。
バンク切り替え
カウンタ/タイマ用ICである8253への命令はメモリマップドI/O領域から行うため、はじめにD000h以降をバンク切り替えし、処理がすべて終わったらDRAMに戻します。ただし、映像出力中に割り込みが発生した場合は、タイマ割り込みの前にすでにVRAMになっているため、バンク切り替えは行いません。
効果音・BGMの出力
8253のチャネル0を使用し、32分音符間隔で矩形波を出力します。楽曲データと照らし合わせ、音の発生・停止、音高の決定を行います。なお、MZ-700では複数の音を同時に出力することはできないため、効果音が鳴っている間はBGMの出力はスキップされます。
タイムコード・プレイ時間・ウェイトのカウント
タイムコードのカウントとは、楽曲が現在曲のどの地点まで進んでいるかを記録しておくものです。そのほかは前述の通りです。
【割り込み】
実行中の処理を中断して、一時的に別の処理を割り込ませること。時間の計測や音楽の再生などで使われる。
【タイマ割り込み】
タイマICによる割り込み。あらかじめタイマーの時間を設定しておくことで、割り込みがかかるタイミングを調整できる。BGMの再生には必須の機能。1982年当時はタイマ割り込みの間隔を自由に設定できない機種も多かった。
【レジスタ】
CPU内部にある記憶回路。数値の計算やデータの短期的な保存をするのに使用する。なお、容量が大きいデータや長期的な保存には、レジスタではなくメモリを使う。
【メモリマップドI/O領域】
メモリ上のアドレス「E000h-E00Fh」の部分。各ハードウェアとのデータ転送に使用する。ここで数値を書いたり読んだりすることで、タイマ割り込みの設定やキー情報の取得、サウンドの出力などを行える。
終わりに
やや乱暴な解説になってしまいましたが、以上がロポコのプログラムの概要です。これであなたもMZ-700でロポコが作れるはず!
MZ-700はその特殊な仕様ゆえ、世間ではネタ的な意味で扱われることも多いのですが、実際に触ってみると非常に優れたマシンであることが分かります。ざっと長所を挙げてみると……..。
文字色と背景色を別々に指定できる。豊富なキャラクタセットと併せて、文字だけでリッチな映像表現が可能。
たった2バイトで64ドット(1文字)の表示が可能。ドットベースのグラフィックと比較して、データ量が圧倒的に少なくて済み、非常に高速。
タイマ割り込みの間隔をユーザーが自由に設定できるため、ゲームを止めずにサウンドを鳴らし続けることができる。
バンク切り替えにより、64KBすべてをフリーエリアとして使用可能。
直感的に理解しやすいシンプルなメモリ構成。機械語プログラミングの入門にも最適。
使いやすいS-BASICと高機能なHu-BASIC、2種類のBASICが標準で付属。
テレビ用のコンポジット出力とディスプレイ用のRGB出力の2つを装備。
映像機器がない環境でも、プロッタプリンタで
ガチャガチャ遊べる簡易的なプログラムの作成・実行ができる。安定&高速の内蔵データレコーダ。
持ち運びに便利な専用ハードケース(別売り)。
最安モデルは79800円。プロッタプリンタ付きモデルでも128000円。
とにかく頑丈なハードウェア。修理も簡単。
見た目がポップでかわいい。
改造とかも流行ってる。
好き。
短所は……まあ、いいんじゃないかな!
いかがでしょう……MZ-700が8ビット最強パソコンであることが伝わりましたでしょうか!?(話が大きくなってる) ただ、ネタ抜きに考えても、発売された時代と販売価格を考えれば、十二分の性能なのではないかと思います。
ロポコに関して言えば、もちろん他の8ビット機への移植自体は問題なくできます。ただし、同時代の機種でこれほどの大きなキャラをスムーズに動かすことができるのは、やはりMZ-80K/700/1500の系譜だけではないでしょうか……? それだけMZシリーズのキャラグラ機能は非常にとっても強力なんです! 機会があったらぜひ実機で動かしてみてくださいね♪
ちなみに、MZ-700は今でもときどきヤフオクに修理品が出品されているので、頑張って狙ってみるのもいいかと思います(2〜4万円)。そのついででよいので、拙作のロポコとプチロポコもご購入いただければ嬉しいです✨ お願い……。
それでは、次回は8月8日の東京ゲームダンジョン13でお会いしましょう👋 MZ-1500を持っていきますよ〜!
