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

システムカスタマイズについてダラダラやるよーその6.5 - 永字八法の続き。
NScripterのシステムカスタマイズについて、1から話をしてみようと思う。その第7回目。
今回は、発言者欄について。

発言者欄とはなにか

適当にググった画像で説明しますと、
http://9-ly1026.toypark.in/wedding/kanon.jpg
http://9-ly1026.toypark.in/wedding/kanon.jpg
この画像で「アンパン男」と書いてる部分、これですね。これにつきます。

シナリオライターはどうすればよいか

一番簡単な実装方法は、シナリオにいちいち「lsp ":s/22,22,0;#FF0000キャラクター名",20,480」とか書くことですが、それではシナリオライターが音信不通になったとしても文句は言えませんので、簡易な記述方法が必要になります。
そこで、NScripterに用意されているタグを使用することにします。

タグ

タグを使うようにするには、*define節でpretextgosubを実行します。

pretextgosub *pretext_lb

このようにすると、表示文の先頭でpretextgosubで指定したラベルにgosubするようになります。
先のtextgosubと組み合わせると、

  1. *pretext_lb
  2. テキストの表示
  3. *text_lb

の順で実行されるようになります。
一応参考までにこちらも見てください。pretextgosubとgettag - 永字八法手前味噌ですが。
とりあえず、このような書式を採用します。

[キャラクター名] ; 発言者欄をキャラクター名にする。
「セリフ」\ ; テキストウィンドウの中身を消した時、発言者欄も消す。

現在のスクリプト

とりあえず、できた。

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

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

	gosub *initialize_textwindow ; テキストウィンドウの初期設定
	set_window ; テキストウィンドウ表示
	gosub *initialize_nameplate ; 発言者欄の初期設定
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
	pretextgosub *pretext_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 font_sprite,%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_visible,%0:inc %0
	numalias textwindow_alpha,%2:inc %2

	numalias text_before,%0:inc %0
	numalias text_after,%0:inc %0

	; 初期化命令を作成
	defsub set_window
	
	; 上書き
	defsub texton
	defsub textoff
	
	; テキストの表示速度
	numalias textspeed,%2:inc %2
	
	; タグ処理回り
	numalias pretext_arg1,%0:inc %0 ; タグを取得するための変数その1
	numalias pretext_arg2,%0:inc %0
	numalias pretext_arg3,%0:inc %0
	
	; 発言者欄回り
	numalias sp_nameplate_box,%1:dec %1 ; 発言者欄の背景
	; 発言者欄の背景の各値
	numalias nameplate_box_x,%0:inc %0
	numalias nameplate_box_y,%0:inc %0
	numalias nameplate_box_width,%0:inc %0
	numalias nameplate_box_height,%0:inc %0

	; 発言者名の各値
	numalias sp_nameplate,%1:dec %1 ; 発言者欄
	; 発言者欄の各値
	numalias nameplate_x,%0:inc %0
	numalias nameplate_y,%0:inc %0
	numalias nameplate_width,%0:inc %0
	numalias nameplate_height,%0:inc %0
	numalias nameplate,%0:inc %0 ; 実際に表示される文字
	numalias talker,%0:inc %0 ; 現在の発言者番号
	numalias nameplate_visible,%0:inc %0 ; 発言者名を表示するか否か。
	

	; 画面内の位置の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

	; スプライト回りの半汎用変数
	numalias sp_sp,%0:inc %0
	; getspmode専用
	numalias sp_mode,%0:inc %0
	; getspsize専用
	numalias sp_width,%0:inc %0
	numalias sp_height,%0:inc %0
	numalias sp_cellcount,%0:inc %0
	
	; スプライトの位置を調整する。
	defsub adjust_sprite
	numalias ads_sp,%0:inc %0
	numalias ads_x,%0:inc %0
	numalias ads_y,%0:inc %0
	numalias ads_xmode,%0:inc %0
	numalias ads_ymode,%0:inc %0
	
60.txt
game
70.txt
*text_lb
	texton

	; 今がスキップモードなら、さっさと次に回す。
	isskip %isskip
	itoa $isskip,%isskip:caption $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
	isdown %bexec              :skip (0-%bexec) * 6
	; 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

	; F12キーでスクリーンショットを作成する。
	if_str_gosub $bexec,"F12",*get_and_save_screenshot

	; それ以外の入力であれば、ループする
	goto *text_lb_loop

	; スキップモード開始用
	*text_lb_skip_start
	systemcall skip

	; クリック待ちの終了処理。
	*text_lb_end

	; 現在表示している内容を取得する。
	getlogtext $text_before,0
	len %text_before,$text_before ; 長さを取得。

	texec

	; 現在表示している内容を取得する。
	getlogtext $text_after,0
	len %text_after,$text_after ; 長さを取得。
	; テキストウィンドウの中身を消したなら。発言者欄も消す。
	if %text_before>0 if %text_after=0 if %nameplate_visible=1 gosub *delete_nameplate

return

*texton
	skip 2-%textwindow_visible
	jumpf
	vsp sp_textwindow,1
	vsp sp_nameplate_box,1
	vsp sp_nameplate,1
	print 1
	_texton
	mov %textwindow_visible,1
	~
return

*textoff
	skip %textwindow_visible+1
	jumpf
	vsp sp_textwindow,0
	vsp sp_nameplate_box,0
	vsp sp_nameplate,0
	print 1
	_textoff
	mov %textwindow_visible,0
	~
return
71.txt
*pretext_lb
	; タグを取得する。
	gettag $pretext_arg1,$pretext_arg2,$pretext_arg3
	
	if $pretext_arg1="" return ; 第一引数が空なら、何もしない。

	mov $talker,$pretext_arg1 ; 発言者を設定
	mov $nameplate,$talker ; 表示内容を決定

	len %pretext_arg3,$pretext_arg3 ; 長さを取得
	skip 3-1/(%pretext_arg3+1) ; 振り分け
	mov $nameplate,$pretext_arg3 ; 実際に表示される内容を変更
	
	mov %nameplate_visible,1 ; 表示に設定

	; 実際に表示する。色は後で考える。念のため、最初は非表示にしておく。
	lsph sp_nameplate,$font_sprite+"#FFFFFF"+$nameplate,0,0
	; 作った後、動かす。
	adjust_sprite sp_nameplate,%nameplate_box_x+%nameplate_box_width/2,%nameplate_box_y+%nameplate_box_height/2,0,0
	; 表示する。
	mov %nameplate_visible,1
	vsp sp_nameplate,1
	texton
	print 1
return

; 発言者欄の設定
*initialize_nameplate
	; 発言者欄を読み込み
	lsph sp_nameplate_box,":c;>100,30,#888888",0,0
	; 発言者欄の大きさの取得
	getspsize sp_nameplate_box,%nameplate_box_width,%nameplate_box_height
	; 発言者欄の位置を決定。テキストウィンドウの左上にくっつく形でどうか。
	mov %nameplate_box_x,%textwindow_x
	mov %nameplate_box_y,%textwindow_y-%nameplate_box_height
	amsp sp_nameplate_box,%nameplate_box_x,%nameplate_box_y,%textwindow_alpha ; 不透明度はテキストウィンドウと共通
return

*delete_nameplate
	csp sp_nameplate
	mov %nameplate_visible,0
	print 1
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
	
	; フォントの各値を、文字列スプライトで使えるように文字列化しておく。
	itoa $font_width,%font_width
	itoa $font_height,%font_height
	itoa $font_space,%font_space
	mov $font_sprite,":s/"+$font_width+","+$font_height+","+$font_space+";"
	
	; パディングの設定
	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+%font_ruby_height,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

; スプライトの特殊操作命令群
; amspのラッパー
*adjust_sprite
	getparam %ads_sp,%ads_x,%ads_y,%ads_xmode,%ads_ymode
	getspsize %ads_sp,%sp_width,%sp_height ; スプライトの大きさを取得する。
		skip %ads_xmode+2
		                      :skip 3
		sub %ads_x,%sp_width/2:skip 2
		sub %ads_x,%sp_width
		skip %ads_ymode+2
		                       :skip 3
		sub %ads_y,%sp_height/2:skip 2
		sub %ads_y,%sp_height
	amsp %ads_sp,%ads_x,%ads_y
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
95.txt
*get_and_save_screenshot
	getscreenshot %window_width,%window_height
	savescreenshot "ss.bmp"
	mesbox "スクリーンショットを作成しました。","screenshot"
return
99.txt
return
end