最近書いたファミコンゲーム用スクリプト

ドラクエ3,4およびゼビウスのMesen用スクリプトを最近書いたので残しておきます。Mesenはファミコンエミュレーターでとても機能が豊富なステキなエミュレーターです。

■ドラゴンクエスト3

ドラクエ3用のスクリプトはオートガードスクリプトです。ご存知の方も多いでしょうが、ファミコン版ドラクエ3は戦闘時にガードを選択するとガードフラグが立ちますが、コマンドをキャンセルしてもこのフラグは立ちっぱなしとなってしまいます。そのため、ガードしたまま攻撃や呪文といった、別の行動がとれます。しかし、先頭が勇者だとガードコマンドが呪文になってしまうため、呪文が使えないキャラを先頭にする必要があり、また4番目のキャラもこの技が使えません。このスクリプトでは戦闘になると自動的にガードフラグを立てるため、上記のような制限を受けません。つまりパーティは常にガードしながら戦闘してくれます。ドラクエ3には前期・後期ロムがあり、プログラムも若干異なります。そのためメモリの使い方も若干異なっている可能性があります。このスクリプトは前期ロム向けに書きましたが、後期ロムではチェックしていません。もし動作しなかったら各メモリのアドレスの挙動をチェックしてみてください。

function dq3_AutoGuard()
 
 game_state = emu.read( 0x06F0, emu.memType.cpu, false ) -- gameState
 
 if game_state == 0x21 or game_state == 0x25 then
   -- AutoGuard
   
   for i = 0, 4 do
     lv = emu.read( 0x0700+i, emu.memType.cpu, false ) -- isEnableChar?
     if lv > 0 then
       game_flag = emu.read( 0x07E1+i, emu.memType.cpu, false ) | 0x20
       emu.write( 0x07E1+i, game_flag, emu.memType.cpu )
     end
   end
   
   emu.drawString( 10, 10, "AutoGuard:ON", 0xFF0000, 0xFF000000, 1 )
 end
 
end

--Register some code (printInfo function) that will be run at the end of each frame
emu.addEventCallback(dq3_AutoGuard, emu.eventType.startFrame)

--Display a startup message
emu.displayMessage("Script", "DQ3 auto guard script loaded.")

■ドラゴンクエスト4

ドラクエ4では8回逃げると会心の一撃が毎回でるようになるバグがあります。バグの詳細は内藤寛さんのYouTube動画がとても楽しいのでそちらをご覧になってください。このスクリプトでは戦闘になると自動的に会心の一撃フラグを立て、7回逃げたことにしています。これにより、会心の一撃が毎回でるのはもちろんですが、ボス以外は確実に逃げられます。ドラクエ3同様、前期・後期ロムの違いについては検証してないので動作しなかったらごめんなさい。

function dq4_kaisin()
 
 game_state = emu.read( 0x7200, emu.memType.cpu, false )
 
 if game_state ~= 0 then
   game_flag = emu.read( 0x72E4, emu.memType.cpu, false ) | 0x0F
   emu.write( 0x72E4, game_flag, emu.memType.cpu )
   emu.drawString( 10, 10, "Critical:ON", 0xFF0000, 0xFF000000, 1 )
 end
 
end

--Register some code (printInfo function) that will be run at the end of each frame
emu.addEventCallback(dq4_kaisin, emu.eventType.startFrame)

--Display a startup message
emu.displayMessage("Script", "DQ4 kaisin script loaded.")

■ゼビウス

ハムスターさんのアーケードアーカイブスのように、SPフラグやソルの位置を画面に表示し、敵の強さ情報を表示するスクリプトです。

function xevious()
 -- 36 Sol invisible
 -- 3c Sol visible
 -- 35 SPflag visible
 -- 36 SPflag invisible
 for i = 0, 16-1 do
     ofs = i * 8
     type = emu.read( 0x300 + ofs + 0 , emu.memType.cpu, false )
     sp_x = emu.read( 0x300 + ofs + 3 , emu.memType.cpu, false )
     sp_y = emu.read( 0x300 + ofs + 2 , emu.memType.cpu, false )
     -- draw sp flag
     if type == 0x38 then
       emu.drawRectangle( sp_x, sp_y, 16, 16, 0x80FF0000, true, 1 )
     end
     -- draw sol
     if type == 0x36 then
       emu.drawRectangle( sp_x, sp_y, 16, 16, 0x8000FF00, true, 1 )
     end
 end
   
 -- enemy level bar
 ene_lv = emu.read( 0x8F , emu.memType.cpu, false )
 bar_color = 0x8000FFFF
 if ene_lv > 256/3*2 then
   bar_color = 0x80FF0000
 elseif ene_lv > 256/3*1 then
   bar_color = 0x80FFFF00
 end
 emu.drawRectangle( 0, 224-ene_lv, 2, ene_lv, bar_color, true, 1 )
end

--Register some code (printInfo function) that will be run at the end of each frame
emu.addEventCallback(xevious, emu.eventType.endFrame)

--Display a startup message
emu.displayMessage("Script", "xevious script loaded.")

そもそもファミコン版はアーケード版に比べると難度が低めですので、このスクリプトを使うとさらに難度が下がってしまいます。そこで高難度モード的なスクリプトを書いてみました。

function xevious()
 -- 36 Sol invisible
 -- 3c Sol visible
 -- 35 SPflag visible
 -- 36 SPflag invisible
 for i = 0, 16-1 do
     ofs = i * 8
     type = emu.read( 0x300 + ofs + 0 , emu.memType.cpu, false )
     sp_x = emu.read( 0x300 + ofs + 3 , emu.memType.cpu, false )
     sp_y = emu.read( 0x300 + ofs + 2 , emu.memType.cpu, false )
     -- draw sp flag
     if type == 0x38 then
       emu.drawRectangle( sp_x, sp_y, 16, 16, 0x80FF0000, true, 1 )
     end
     -- draw sol
     if type == 0x36 then
       emu.drawRectangle( sp_x, sp_y, 16, 16, 0x8000FF00, true, 1 )
     end
     -- change to mortar
     if type == 0x08 then
       emu.write( 0x300 + ofs, 0x02, emu.memType.cpu )
     end
     if type == 0x06 then
       emu.write( 0x300 + ofs, 0x04, emu.memType.cpu )
     end
     if type == 0x0A then
       emu.write( 0x300 + ofs, 0x0C, emu.memType.cpu )
     end
     if type == 0x28 then
       emu.write( 0x300 + ofs, 0x04, emu.memType.cpu )
       emu.write( 0x300 + ofs + 7, 0x15, emu.memType.cpu )
     end
 end
   
 -- enemy level bar
 ene_lv = emu.read( 0x8F , emu.memType.cpu, false )
 bar_color = 0x8000FFFF
 if ene_lv > 256/3*2 then
   bar_color = 0x80FF0000
 elseif ene_lv > 256/3*1 then
   bar_color = 0x80FFFF00
 end
 emu.drawRectangle( 0, 224-ene_lv, 2, ene_lv, bar_color, true, 1 )
end

--Register some code (printInfo function) that will be run at the end of each frame
emu.addEventCallback(xevious, emu.eventType.endFrame)

--Display a startup message
emu.displayMessage("Script", "xevious script loaded.")

このスクリプトでは、普段弾を撃ってこない地上物も攻撃してくるようになる(バーラ(ピラミッド)→デロータ、ゾルバク(レーダー)→ログラム)うえ、ガル~系(デカイ奴)は2回ブラスターを撃たないと破壊できません(デカいピラミッドはガルデロータと同じ性能になっています)。またレーダーでもあるゾルバクを破壊しても敵の強さが低下しないため、空中物も強めです。ファミコンゼビウスなんて簡単と舐めてかかると苦戦することになりますよ!

スクリプトの使い方については、こちらの記事を参照ください。


この記事が気に入ったらサポートをしてみませんか?