システムカスタマイズについてダラダラやるよーその4
システムカスタマイズについてダラダラやるよーその3 - 永字八法の続き。
NScripterのシステムカスタマイズについて、1から話をしてみようと思う。その第4回目。
既読ストップ問題
まあ、タイトルは造語なんですけど。
ノベルには、スキップモードがあるのは皆さんよくご存知のはず。例えば特定のキーを押しっぱなしで、あるいはボタンを一つ押して、絶対読めないだろって速さで文字が流れ、立ち絵がパタパタと動くアレです。
そのうち既読スキップモードと言うのが出てきまして、つまり既読、一度読んだ(見た)部分だけをスキップモードで流して、未読の部分が現れたらモードを終了させて普通のクリック待ちになるアレです。
NScripterでもそれは可能でして、するためには、*define節でkidokuskipと書くだけで、既読スキップが使えるようになります。
この既読か未読かは、スクリプトのそれぞれの行に対して実行したしないの情報を保存していく遣り方なのですが、システムカスタマイズをすると頻繁に何故か既読スキップモードが止まってしまう事態に出くわします。
なんでだろうとよくよく調べてみると、どうやら、ifのある行が未読と判定されているようです。
ifはご存知のとおり、条件式を判別して、条件を満たした場合にそれ以降の命令を実行する命令ですが、逆に条件式を満たさなかった場合は素通りするだけではなく、既読にしないと言う性質があったのです。
つまり、if(notifを含む)のある行は、それだけで既読ストップ問題を引き起こす潜在的可能性を持っていた訳です。
前回の最後のスクリプトを見ればわかりますが、やはりifを使っていますので、もしかしたら、既読ストップを起こす可能性があります。
まあこういう場合、問題になるかならないかわからない命令をドキドキしながら使うよりも、問題を起こさないことが保証されている別の命令を使って同じことをするのがセオリーですので、そのようにします。
既読スキップ問題の対処
単純で、既読スキップ問題を起こさない命令を作ることです。
そのため、ifに変わる何かを作成します。
; *define節に書きます。 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
; *define節にも*start節にもないところに書きます。 *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
たとえば、if_str_gotoは、二つの文字列とラベルを引数に取る命令で、二つの文字列が同じだった場合は、引数のラベルにgotoするものです。
同じように、notif_xxx_xxxxは一致しなかった時、xx_int_xxxxは数値を比較し、xx_xxx_gosubはgotoの代わりにgosubを実行します。
実はこんな命令作るよりも、nsluaに投げれば何も問題はないんだけど、まずはNScripterデフォルトでできるところまでやってみようと言うことで。
で、以下が、これを盛り込んだスクリプト。
*start 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 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 ; 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 ; 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
これで、現状Kキーを押すと既読スキップモードに突入するようになった。
ちなみに既読と強制の切り替えは、コンフィグの領域なのでまた後で。
次回予告
さて、これで今後も既読ストップ問題は解決済みと言うことで。
次は、セーブデータの取り扱いについて。