システムカスタマイズについてダラダラやるよーその5
システムカスタマイズについてダラダラやるよーその4 - 永字八法の続き。
NScripterのシステムカスタマイズについて、1から話をしてみようと思う。その第5回目。
セーブ・ロードの仕組みについて
NScripterでは、あるタイミングで変数の状態などのスナップショットを作成して取っておき、save(or save2)命令でそれをセーブデータとして出力します。このセーブデータはload命令で読み出せます。
いつセーブするか。
これは、*define節で、autosaveoffを実行しているかいないかで変わって来ます。
autosaveoffをしていない時
saveon/saveoff命令が重要になって来ます。
saveon命令を実行すると、その行以降、全ての行でスナップショットが作成されます。for-nextなどでスプライトを動かしていたりしても、それぞれの行でスナップショットが作成されるため、動作が非常に遅くなります。
saveoffを実行すると、その行以降、自動でのスナップショット作成が起こらなくなります。なので、動作は最速になりますが、スクリプトの任意の場所で、savepoint命令を使ってスナップショットを作成しなければなりません。
autosaveoffをしている時
saveon/saveoff命令が無効化します。
そのかわりに、文章表示行の先頭で、自動的にsavepoint命令が(内部的に)呼ばれ、スナップショットを作成します。
どちらのモードがよいのか。
大部分が好みの問題ですが、完全にコントロールしたいのであれば、autosaveoffを使わず、*start節の先頭でsaveoffして、随所でsavepointではないでしょうか。(本稿ではこっちを採用します)
よくわからないと言う人に。
以下、簡単なluaによる検証スクリプトを作成した。
nslua.dllがあるのを確認し、system.luaファイルを作成し、その中に下記のスクリプトをコピペすること。
そうすると、実行時にセーブポイント(自動・手動問わず)に差し掛かる度に、ポップアップが出てセーブポイントに来たことを告げてくれる。
それで、多すぎず少なすぎずにスナップショットが作られていれば、よしとしましょう。
現在のスクリプト
*start ; saveoff ; 完全手動セーブ宣言! kidokumode 1 ; 既読スキップモードを使用可能にする。 gosub *if_in_advance ; 一度は実行しておく。 gosub *text_lb_skip_start ; 一度は実行しておく。 skipoff あ\ い\ う\ え\ お\ end *define ; メニューバーを全消し deletemenu mov %0,100 ; numalias定義用一時変数 ; bexecの結果を受け取る専用変数を宣言 numalias bexec,%0:inc %0 ; システムカスタマイズの宣言 textgosub *text_lb ; 既読スキップ有りで。 kidokuskip ; isskipの結果を受け取る専用変数を宣言 numalias isskip,%0:inc %0 ; ifの代替命令群の定義 defsub if_str_goto defsub if_str_gosub defsub if_int_goto defsub if_int_gosub defsub notif_str_goto defsub notif_str_gosub defsub notif_int_goto defsub notif_int_gosub numalias if_a,%0:inc %0 numalias if_b,%0:inc %0 numalias if_label,%0:inc %0 ; 自動記録なし autosaveoff game *text_lb ; 今がスキップモードなら、さっさと次に回す。 isskip %isskip if_int_goto %isskip,1,*text_lb_end ; 進む機能を持つキーが押されていないことをチェックする。 checkkey %bexec,"LCLICK" :skip (0-%bexec) * 1 checkkey %bexec,"WHEELDOWN":skip (0-%bexec) * 2 checkkey %bexec,"SPACE" :skip (0-%bexec) * 3 checkkey %bexec,"RETURN" :skip (0-%bexec) * 4 checkkey %bexec,"K" :skip (0-%bexec) * 5 ; CTRLは除く。CTRL押しっぱなしで進むのは、最近のエンジンではよくある仕様だから。 *text_lb_init_loop bclear *text_lb_loop bexec $bexec,%bexec ; Sにセーブを、Lにロードを割り当てる。 if_str_goto $bexec,"S",*save_routine if_str_goto $bexec,"L",*load_routine ; Kに既読スキップモードを割り当てる。 if_str_goto $bexec,"K",*text_lb_skip_start ; マウスの左クリックかホイールダウン、キーボードのスペースキーかエンターキーかコントロールキーで次へ。 if_str_goto $bexec,"LCLICK",*text_lb_end if_str_goto $bexec,"WHEELDOWN",*text_lb_end if_str_goto $bexec,"SPACE",*text_lb_end if_str_goto $bexec,"RETURN",*text_lb_end if_str_goto $bexec,"CTRL",*text_lb_end ; それ以外の入力であれば、ループする goto *text_lb_loop ; スキップモード開始用 *text_lb_skip_start systemcall skip ; クリック待ちの終了処理。 *text_lb_end texec return ; セーブルーチン *save_routine savegame 0 mesbox "セーブしました。","save game" goto *text_lb ; ロードルーチン *load_routine loadgame 0 ; if 代替命令群本体ルーチン *if_str_goto getparam $if_a,$if_b,$if_label if $if_a=$if_b return $if_label return *if_str_gosub getparam $if_a,$if_b,$if_label if $if_a=$if_b goto $if_label return *if_int_goto getparam %if_a,%if_b,$if_label if %if_a=%if_b return $if_label return *if_int_gosub getparam %if_a,%if_b,$if_label if %if_a=%if_b goto $if_label return *notif_str_goto getparam $if_a,$if_b,$if_label notif $if_a=$if_b return $if_label return *notif_str_gosub getparam $if_a,$if_b,$if_label notif $if_a=$if_b goto $if_label return *notif_int_goto getparam %if_a,%if_b,$if_label notif %if_a=%if_b return $if_label return *notif_int_gosub getparam %if_a,%if_b,$if_label notif %if_a=%if_b goto $if_label return *if_in_advance ; 定義した命令を、一度は実行しておくためのルーチン。 ; 起動時に一回だけやっておけばよい。 if_str_goto ""," ",*dummy if_str_gosub ""," ",*dummy if_int_goto 0,1,*dummy if_int_gosub 0,1,*dummy notif_str_goto "","",*dummy notif_str_gosub "","",*dummy notif_int_goto 0,0,*dummy notif_int_gosub 0,0,*dummy if_str_gosub "","",*if_in_advance_dummy if_str_goto "","",*if_in_advance1 *if_in_advance1 if_int_gosub 0,0,*if_in_advance_dummy if_int_goto 0,0,*if_in_advance2 *if_in_advance2 notif_str_gosub ""," ",*if_in_advance_dummy notif_str_goto ""," ",*if_in_advance3 *if_in_advance3 notif_int_gosub 0,1,*if_in_advance_dummy notif_int_goto 0,1,*if_in_advance4 *if_in_advance4 return *if_in_advance_dummy ; 何もしないよ。 return
なお、現在のスクリプトでは、実際のセーブとロードは決め打ちで*save_routineと*load_routineに飛ばしているだけです。
リッチ