システムカスタマイズについてダラダラやるよーその6.5

システムカスタマイズについてダラダラやるよーその6 - 永字八法の続き。
ちょっと寄り道して、ソースを整理します。

NScripterでのスクリプトの書き方について私見

NScripterスクリプトで、最低限エラーが出ずに終了するパターンは、以下のようなものです。

*define
game
*start
end

また、これらは一行ずつ別々のファイルに書いても問題ありません。nscr.exeは起動時に00.txt〜99.txtまでを全て読み込んで一つのファイルにしてからパースするからです。
それと、ラベルは指定さえしっかりしていれば、順番を入れ替えても問題が少ないです。
ですので、以下の様なスクリプト構造を提案します。

*start
シナリオをここに書く
end
*define
game
*other_routine
return
end

また、これを拡張のしやすいようにバラけた番号のファイルに書き込むのがいいでしょう。
結果、スクリプトは下記のようになりました。

現在のスクリプト

00.txt
;$V2000G1000S800,600L10000
*start
	saveoff ; 完全手動セーブ宣言!
	kidokumode 1 ; 既読スキップモードを使用可能にする。
	gosub *if_in_advance ; 一度は実行しておく。
	gosub *text_lb_skip_start ; 一度は実行しておく。
	gosub *initialize_global ; グローバル変数の初期設定

	; 画面サイズを取得しておく、
	getwindowsize %window_width,%window_height

	gosub *initialize_textwindow ; テキストウィンドウの初期設定
	set_window ; テキストウィンドウ表示
10.txt
(阿頼耶/あらや)(識/しき)@
あ\
い\
う\
え\
お\
50.txt
end
*define

	; メニューバーを全消し
	deletemenu

	mov %0,100 ; numalias定義用一時変数
	mov %1,900 ; スプライト番号定義用の一時変数
	mov %2,1000 ; グローバル変数用

	; グローバル変数を使用
	globalon

	numalias global_first,%2:inc %2 ; グローバル変数の初期設定をしたかしていないかのフラグ。

	; 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

	; 画面サイズ回り
	numalias window_width,%0:inc %0
	numalias window_height,%0:inc %0

	; setwindow回り
	numalias sp_textwindow,%1:dec %1 ; テキストウィンドウ用のスプライト番号
	humanz sp_textwindow ; 立ち絵の位置を設定
	windowback ; テキストウィンドウをスプライトの位置まで引っ込ませる。
	numalias textwindow_width,%0:inc %0
	numalias textwindow_height,%0:inc %0
	numalias textwindow_x,%0:inc %0
	numalias textwindow_y,%0:inc %0
	numalias font_width,%0:inc %0
	numalias font_height,%0:inc %0
	numalias font_space,%0:inc %0
	numalias line_space,%0:inc %0
	numalias font_bold,%0:inc %0
	numalias font_shadow,%0:inc %0
	numalias font_ruby_width,%0:inc %0
	numalias font_ruby_height,%0:inc %0
	numalias textwindow_padding_top,%0:inc %0
	numalias textwindow_padding_bottom,%0:inc %0
	numalias textwindow_padding_left,%0:inc %0
	numalias textwindow_padding_right,%0:inc %0
	
	numalias textwindow_area_width,%0:inc %0
	numalias textwindow_area_height,%0:inc %0
	numalias textwindow_col,%0:inc %0
	numalias textwindow_row,%0:inc %0
	
	numalias textwindow_alpha,%2:inc %2

	defsub set_window
	
	; テキストの表示速度
	numalias textspeed,%2:inc %2

	; 画面内の位置のNEWS指定
	defsub news_position
	numalias news_ax,%0:inc %0
	numalias news_ay,%0:inc %0
	numalias news_x,%0:inc %0
	numalias news_y,%0:inc %0
	numalias parent_width,%0:inc %0
	numalias parent_height,%0:inc %0
	numalias child_width,%0:inc %0
	numalias child_height,%0:inc %0
60.txt
game
70.txt
*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
75.txt
*initialize_global
	if %global_first=1 return

	; グローバル変数の初期設定
	
	; テキストウィンドウの不透明度
	mov %textwindow_alpha,255
	; テキストの表示速度(一文字表示にかけるミリ秒数)を格納する変数
	mov %textspeed,40

	; フラグを立てる。
	mov %global_first,1
return

*initialize_textwindow
	; テキストウィンドウの画像読み込み
	lsph sp_textwindow,":c;>600,200,#888888",0,0
	; テキストウィンドウのサイズを取得
	getspsize sp_textwindow,%textwindow_width,%textwindow_height
	; テキストウィンドウの配置場所の決定(左下にしている)
	news_position %textwindow_x,%textwindow_y,%window_width,%window_height,%textwindow_width,%textwindow_height,-1,1
	; フォントの設定
	mov %font_width,22
	mov %font_height,22
	mov %font_space,2
	mov %line_space,2
	mov %font_bold,0
	mov %font_shadow,1
	mov %font_ruby_width,11
	mov %font_ruby_height,11
	; パディングの設定
	mov %textwindow_padding_top,8
	mov %textwindow_padding_bottom,8
	mov %textwindow_padding_left,12
	mov %textwindow_padding_right,12
	
	; エフェクト中もテキストウィンドウが消えないようにする。
	erasetextwindow 0
	; 念のため、右クリックを殺しておく。
	rmode 0
return

; 実際にテキストウィンドウを設定する。
*set_window
	; 実際の表示領域の広さを計算する。
	mov %textwindow_area_width,%textwindow_width-%textwindow_padding_left-%textwindow_padding_right
	mov %textwindow_area_height,%textwindow_height-%textwindow_padding_top-%textwindow_padding_bottom
	; 表示領域の広さから、行数や文字数を計算する。
	mov %textwindow_col,%textwindow_area_width/(%font_width+%font_space)
	mov %textwindow_row,%textwindow_area_height/(%font_height+%line_space+%font_ruby_height)
	; 数値を反映した値にする。
	setwindow %textwindow_x+%textwindow_padding_top,%textwindow_y+%textwindow_padding_left,%textwindow_col,1+%textwindow_row,%font_width,%font_height,%font_space,%line_space,0,%font_bold,%font_shadow,#000000,%textwindow_x,%textwindow_y,%window_width,%window_height
	rubyon %font_ruby_width,%font_ruby_height
	textspeed %textspeed
	amsp sp_textwindow,%textwindow_x,%textwindow_y,%textwindow_alpha
	vsp sp_textwindow,1
return

; ある領域の中で、小さな領域を配置する時のための座標を計算する。
*news_position
	getparam i%news_x,i%news_y,%parent_width,%parent_height,%child_width,%child_height,%news_ax,%news_ay
	mov %%news_x,%parent_width-%child_width
	if %news_ax=-1 mov %%news_x,0
	if %news_ax=0 div %%news_x,2
	mov %%news_y,%parent_height-%child_height
	if %news_ay=-1 mov %%news_y,0
	if %news_ay=0 div %%news_y,2
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
99.txt
return
end

次回予告

今度こそ、発言者欄を……。