MSXのゲームELELANDが楽しい!

MSXのゲームにELE LANDというBASICで書かれたゲームがあるのだけど、これはゲーム本編で遊ぶだけでなくプログラムを改造しても楽しめる作品となっている。10日ほど前に購入してWEBのMSXエミュレータでゲーム本編を楽しんでから、少しだけ改造をしてみたのでそのメモ。

ELE LANDってどんなゲーム?

簡単に言うとアクションロールプレイングゲーム。
左右移動とジャンプでステージを移動して剣で敵を倒し、宝箱を開けてアイテムを集めラスボスを倒すと言う内容。アイテムがないと行けない場所があるなどのギミックも用意されていてとても面白い!

が、このゲームの凄いところは改造することが推奨されているところ。取扱説明書にはこうある。

ELE LANDは、ゲームそのものを遊んでいただくだけでなく、皆さんがご自由にこのゲームを改造して楽しんで頂く作品です。

ELE LAND取扱説明書より

そして更にすごいのが

改造したものは、ご自由に配布して頂けたら、と思っています。(一緒にMSXを盛り上げましょう^^)SNSや、MSXPen(ご自身のサーバーを用意しなくても配布できます)、ご自身のサーバー上にダウンロードできるようにされるなど配布方法はご自由にどうぞ^^

ELE LAND取扱説明書より

となっていること。改造してあれば配布は自由!

と言うわけで、MSXを盛り上げるためにも自分も改造して公開しなければ!と思ったわけ。

改造箇所

今回改造したのは2箇所。

  • フォントを髭のついた文字に変更
  • ゲーム開始前の画面に簡単なデモ的なものを追加

ゲームの舞台がファンタジーなので文字もそれっぽいものに。オリジナルも普通のフォントを太字に修正して使っているのだけど、自分の場合はセリフ体っていうの?髭の付いた文字に変えてみた。

また、オリジナルのゲーム開始前の画面、中央にプレイヤーキャラが静止画で表示されているのだけれど、最初はそれを歩く動作のアニメーションさせようと思った。でも、やってみたら移動もさせたくなって地面を描いたらUltima IIIを思い出してこんな結果に。

本当はもっとアクション部分やゲーム内のギミックとか凝ったことをしたかったのだけど、正直自分には無理!マジでBASICのコード書くの大変…。
そんなわけで簡単だけど上記2つの改造について以下メモ書き程度の説明。

フォントの変更

ゲームはMSXのスクリーン1.5という特殊なモードで動いているらしい。画面を上中下の3箇所に分けでそれぞれにPattern Generator Table(PCGみたいなもの?)を持っているモードだそうだ。そしてフォントもこのPGTに含まれる。オリジナルでは初期設定で通常のフォントを読み込んで、それを1ドット右にずらした物と組み合わせて太字のフォントを作っている。これが1610行と900行のサブルーチン。

900 VPOKE K*8+I,L:VPOKE &H800+K*8+I,L:VPOKE &H1000+K*8+I,L:RETURN
1610 KO$=">":FOR K=32 TO90:PRINTCHR$(K);:FOR I=0 TO 7:P=VPEEK(K*8+I):L=P OR (P\2):GOSUB900:L=&HF1:GOSUB910:NEXT:NEXT

VPOKEでVRAMに書き込んでいるのが3箇所のPGT。
というわけで、髭文字のA~Zまでのフォントデータを用意してこれを900行のサブルーチンで3箇所のPGTに書き込むようにすれば改造は完了。

1615 RESTORE 2600:FOR K=65 TO 90:READ D$:FOR I=0 TO 7:DT$=MID$(D$,I*2+1,2):L=VAL("&H"+DT$):GOSUB900:NEXT:NEXT

ちなみに、フォントはここを見て目で16進数に変換して用意した。アルファベット大文字分だけなのでサクっと完了。
以下が出来上がった改造バージョンのスタート前画面。

ゲーム開始前の画面にデモを追加

これは先にも書いた通りUltima IIIのアレ!
本当Ultima III/IVのアレを眺めてるの好きだったのでやってみました。

コードは一部オリジナルを削って移動したりしている部分もありますが、基本的にオリジナルは触らずに隙間に新しいコードを入れていく方向で改造しています。以下、加えた部分のコードです。

1615 RESTORE 2600:FOR K=65 TO 90:READ D$:FOR I=0 TO 7:DT$=MID$(D$,I*2+1,2):L=VAL("&H"+DT$):GOSUB900:NEXT:NEXT
1735 RESTORE 2500:READ MD$:MC=0:DC=1:DX=20:DG=0:LC=0:MX=228:WC=0:MM=0:MB=11:BC=6
1737 FOR I=0 TO28:VPOKE &H19A2+I,108:VPOKE &H19C2+I,108:VPOKE &H19E2+I,108:VPOKE &H1A02+I,240:NEXT:PUT SPRITE 4,(DX,112),4,0:PUT SPRITE 5,(DX,112),6,4
1745 GOSUB2000
1970 DATA 3078F838F8191B1F3F3F3F1F193070E1030F3F7EF8E080E0F0F6F3F9DD6FE6C0,3078F81838D91B0F1F3F3F1F193070E1030F3F7EF8E080E3F1F1F1F9DD6FE6C0,1F650EB142AC104B0C62A91443AA0457C038865B15E24434C41448D8289010A0
2000 PC=BC:IF LC>0 THEN LC=LC-1:FC=0:GOTO 2020 ELSE FC=1:MV=VAL("&H"+MID$(MD$,MC*2+1,2)):MC=MC+1:IF MC>46 THEN MC=0:DC=1:DX=20:DG=0:LC=0:MX=228:WC=0:MM=0:MB=11:BC=6
2010 IF (MV and &H80)<>0 THEN LC=(MV and &H7F):MV=OC ELSE OC=MV
2020 IF (MV and 1)=1 THEN DX=DX+4:PUT SPRITE 4,(DX,112),4,(DC and 1)*2:PUT SPRITE 5,(DX,112),6,4+(DC and 1)*2:DC=DC+1 ELSE IF (MV and 2)=2 THEN PUT SPRITE 6,(DX+13,112),15,8:PC=9:MM=1:GOSUB 2080 ELSE PUT SPRITE 6,(DX+13,0),0,8
2030 IF (MV and 4)=4 THEN MX=MX-4:MM=1::WC=WC+1 ELSE IF (MV and 8)=8 THEN MM=0:MB=15:MX=228:BC=15:PUT SPRITE 0,(MX,112),0,MB
2040 IF MM=1 THEN PUT SPRITE 0,(MX,112),PC,MB+(WC and 1)*2:MM=0
2050 IF (MV and 16)=16 THEN MB=22:WC=0:MX=224:PUT SPRITE 0,(MX,112),1,22 ELSE IF (MV and 32)=32 THEN GOSUB2300:PUT SPRITE 6,(0,0),0,9:PUT SPRITE 0,(MX,112),1,23:PUT SPRITE 1,(MX-16,112),8,24:PUT SPRITE 4,(DX,112),8,(DC and 1)*2
2060 IF (MV and 64)=64 THEN GOSUB2310:PUT SPRITE 0,(MX,112),1,22:PUT SPRITE 1,(MX-16,0),0,24:DX=20:PUT SPRITE 4,(DX,212),0,0:PUT SPRITE 5,(DX,212),0,4
2070 RETURN
2080 IF FC=1 THEN GOSUB 830
2090 RETURN
2300 B=USR1(0):SOUND13,13:SOUND8,16:SOUND7,247:SOUND6,20:SOUND12,20:RETURN
2310 SOUND13,9:SOUND8,0:B=USR1(0):SOUND9,0:RETURN
2500 DATA 0496058A00880288080088048A058A00880282008202880810019400880284008402840084028400842000904000B0
2600 DATA 7cc6c6fec6c6c600,fc66667c6666fc00,7cc6c0c0c0c67c00,fc6666666666fc00,fe6268786862fe00,fe6268786860f000,7cc6c6c0cec67e00,c6c6c6fec6c6c600,3c18181818183c00,1e0c0c0ccccc7800,e6666c786c66e600,f06060606266fe00,82c6eefed6c6c600,c6e6f6decec6c600
2610 DATA 7cc6c6c6c6c67c00,fc66667c6060f000,7cc6c6d6de7c0600,fc66667c6666e600,7cc6c07c06c67c00,7e5a5a1818183c00,c6c6c6c6c6c67c00,c6c6c6c66c381000,c6c6d6feeec68200,c66c3838386cc600,6666663c18183c00,fec68c183266fe00

簡単に説明します。

1615行がフォントの設定です。オリジナルが太字のフォントを設定した後でA-Zのヒゲ付きフォントのデータを読み込んで設定しています。データ読み込みの画面でA-Zが書き換わる様子が見られます。

1735行がデモ機能の初期設定です。最初はメモリ節約のためにも変数は増やさないほうが良いと思っていたのですが、早い段階でメモリ不足になったためにそんなことはどうでも良くなりました。

1737行は地面と空の背景を表示しています。

1745行でゲーム開始待ちのループの中からデモ機能のサブルーチンを呼んでいます。

1970行は加えたドラゴンと炎のスプライトのデータです。左向きだけで良いのでスライムやコウモリの後で一緒に読み込んでいます。

2000-2090行がデモ機能のサブルーチンです。思いつきで書いている感じが良くわかります。

2300-2310行がドラゴンの音の部分です。コピペ&パラメータ触っただけの様子が見て取れます。音が止まらなくてMSXPenの画面をクローズしたのは良い思い出。

2500行はデモのコマンドのデータです。

2600-2610行がフォントのデータです。

ちなみにフォントの変更に関しては容量の問題はありませんでしたが、デモの追加はあっという間に「Out of memory」(多分そうだと思います。小文字は地面や空や壁になっていて読めない!)が出ました。というわけで、動作させるために地下2階のステージデータを削除しています。

コマンド実行部分

2000行からのサブルーチンがコマンド実行部になります。処理がそこそこ重たくなるとスペースキーの効きが悪くなります。やっていることはサブルーチンが呼ばれるとコマンドを一つ読み込み実行しているだけです。

コマンドは8bitで構成されていてそれぞれのビットの意味は以下の通り。

0 Player Move プレイヤー移動
1 Player Attack プレイヤー攻撃
2 Enemy Move 敵移動
3 Enemy Clear 敵削除
4 Dragon Appear ドラゴン登場
5 Dragon Fire ドラゴン攻撃
6 Dragon Win ドラゴン勝利
7 Loop ループ

どのbitもその名前の通りのコマンドなのですが、ループは直前のコマンドを続けるコマンドです。移動や攻撃、その他諸々のコマンドを何回も続ける際にループコマンドを使います。プレイヤーが8歩移動するならプレイヤー移動を含むコマンドの後でループコマンドです。その際、bit 0-6でループの回数を指定します。8歩歩くなら01で1歩歩いて、残りの7歩分をループするので、0187がになります。

実行部は各bitを確認してそれに合わせてスプライトを表示・消去しています。この実行部分についてはもう少し書きようがあると思いますがこれが限界…。(ELSE IFがもぉ!ってなって無理!)

ちなみにドラゴンと炎はオリジナルのゲームには出てこないのでELE LANDの説明書で紹介されていたサイトで作成しました。

また音に関してはプレイヤーの攻撃音はオリジナルのもの(830行のサブルーチン)をそのまま使っています。
2300行のドラゴンの炎の音はWEBを検索してSOUND文を調べなんとかオリジナルの音に似たようなものを作れた気がします。あのザザーという音、勇者が灰になる感じ!

というわけで、こちらがデモのムービーです。

実は最初、地面と空を入れたらプレイヤーの鎧が空の色と同じで見えない!というわけで、急遽プレイヤーの鎧を濃い青に、肌を褐色にしました。ゲーム本編と色が違っているのは、プレイヤーの勇者が冒険を始める前に名もなき勇者が挑んで敗れ去った記録という設定でお願いします。

diffファイル

投稿前にこの記事のプレビューを見たらリストの中の”&H”がちゃんと表示されていなくて見辛い…。プラグインの設定を見てもそれらしい箇所がないのでオリジナルと改造したものとのdiffをgistに上げておきました。じっくり見てみたい方はどうぞ。(削除した地下2階のデータ部分はdiffに入っていません。)

https://gist.github.com/paraches/264eb99de7c6fc471eb205b68c04cd35

最後に

何十年ぶりにBASICのプログラムを触りました。N88-BASICで育った身には大して難しくはないかな?と思っていましたがSCREENとかSPRITEとかVDP関係は全然わからない!MSX、そんなに色々なモードがあったのか〜

思い出すとPC9801のμPD7220とかMSXのTMS9918とか、画面を描いてくれるプロセッサが付いてるPCに憧れてたな〜。それに比べてPC8801はRGB3枚のプレーンを切り替えてPUSHで0000H書き込んで画面消したりして頑張ってた。RGBのポート切り替え、OUT命令のポート番号覚えてるのって三つ子の魂…ってやつ?

というわけでとても楽しませていただいたELE LANDだけど、BASICだと容量的に限界に達してしまっている感じなので一先ずは終了。

で、年末にせっかくnand2tetrisを終わらせて俺俺コンパイラを作ってみたくなっているので、まずはMSX用俺俺コンパイラを作って、それができたらELE LANDを動かしてみようと妄想しています。

Leave a Reply

Your email address will not be published. Required fields are marked *

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)