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

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

ボイスについて。

色々見て回った限り、ほうぼうの意見を汲み取って、本稿ではボイスについて、下記のような仕様とします。

ボイスモード

ボイスモードはシングルとマルチの2種類があります。
シングルは従来のものに近いもので、ボイスのチャンネルを一つしか用意しません。
なので、ボイスを再生中であっても、次のボイスが始まれば今のボイス再生は止まると言うものです。
マルチはそうではなく、次々に新しいチャンネルを使って、多重再生します。
(ちなみにこの仕様は、オートモードにも大いに関係してきます)
これはプレイヤーがコンフィグで選択できるようにすべきです。

ボイスボリューム

キャラクター毎に設定できるようにします。
これはコンフィグもしくは好感度確認画面でできるべきです。
デフォルトは50で、0〜100の範囲です。
0にした場合は、ボリュームを0ではなく再生しない、ボイスが存在しないように扱うとします。
また、そのために、キャラクター名とボリュームの結びつけを行います。

どうやって指定するか。

前回でも使ったタグを使います。

[キャラクター名/ボイスファイル名]
「声がついたよ!」\

ボイスはだいたいvoiceファイルに入れ、拡張子は.oggでしょうから、これらはシステムの方で補完するのがいいでしょうね。

[モブの介/v00001]
「モブの俺にセリフが!?」\

この場合、voice\v00001.oggが再生されるとします。

現在のスクリプト

00.txt
;$V2000G1000S800,600L10000
01.txt
*start
	gosub *start_window
	gosub *start_cast
	gosub *start_textwindow
	gosub *start_text
	gosub *start_nameplate
	gosub *start_if
	gosub *start_if1
	gosub *start_if2
	gosub *start_if3
	gosub *start_if4
	gosub *start_if5
	gosub *start_if6
	gosub *start_skip
	gosub *start_sound
	gosub *start_sprite
	gosub *start_global
10.txt
click

[キャラ1/0001]
うぐう。\

名前欄が消えるかな?\

[キャラ2/0002]
が、がお。\

もう一度、消えるかな?\

[キャラ3/0003]
ぶらーぼ\

[キャラ15/0004]

[キャラ4/0006]
あ\

[/0007]
い\

[キャラ6/0008]
う\
え\
お\
か\
き\
く\
け\
こ\
さ\
し\
す\
せ\
そ\
た\
ち\
つ\
て\
と\
98.txt
end
*define
	gosub *define_numalias
	gosub *define_global
	gosub *define_window
	gosub *define_background
	gosub *define_cast
	gosub *define_textwindow
	gosub *define_text
	gosub *define_nameplate
	gosub *define_bexec
	gosub *define_debug
	gosub *define_exec
	gosub *define_fileexist
	gosub *define_if
	gosub *define_newsposition
	gosub *define_skip
	gosub *define_sound
	gosub *define_sprite

game
99.txt
*define_numalias

	; numalias 定義用の一時変数
	mov %0,100 ; 100番から。
	
	; スプライト番号は逆に奥から。
	mov %1,900

return

*define_global

	; グローバル変数を使いますよ。
	globalon
	; グローバル用numaliasの定義変数
	mov %2,1000

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

return

*define_window

	; メニューは全部消す。
	deletemenu
	
	; ウィンドウサイズを保存する変数。
	numalias window_width,%0:inc %0
	numalias window_height,%0:inc %0

return

*start_window

	; これからずっと使う、ウィンドウのサイズを取得しておく
	getwindowsize %window_width,%window_height

return

*define_background

	; 画像の読み込みのログを取る。
	; これがないと、画像鑑賞が面倒になるので。
	filelog

return

*define_cast

	; 立ち絵の処理
	; 立ち絵のスプライト並びでの位置を決めます。
	numalias sp_casts,%1:dec %1
	humanz sp_casts
	
	; キャラクターの総数を設定する。
	numalias cast_max,10 ; とりあえず、10人
	; キャラクターは名前で判別する。
	; キャラクターにはそれぞれ好感度とボイスボリュームを設定できるとする。

	; キャラクター名を番号に変換する命令
	defsub name2number
	numalias n2n_name,%0:inc %0
	numalias n2n_number,%0:inc %0
	numalias n2n_hit,%0:inc %0

return

*start_cast

	; 立ち絵の高さを決めます。
	; 画面サイズを変えてもデフォルトのままなので、
	; 画面サイズを動的に取得してそれに合わせた設定にします。
	underline %window_height-1

return

; キャラクター名を番号に変える関数。
; 該当がなければ0が戻ってくる。
*name2number

	getparam i%n2n_number,$n2n_name
	; まずは0に設定する。
	mov %%n2n_number,0 

	; キャラクターの名前や数が変われば、以下の行も適当にコピペしたりして編集してください。
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ1":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ2":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ3":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ4":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ5":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ6":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ7":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ8":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ9":if_int_return %n2n_hit,0
	inc %%n2n_number:cmp %n2n_hit,$n2n_name,"キャラ10":if_int_return %n2n_hit,0

	; 最終的には、やはり0に設定する。
	mov %%n2n_number,0 
return

*define_textwindow

	; テキストウィンドウ用のスプライト番号を定義
	numalias sp_textwindow,%1:dec %1
	
	; 念の為に作っておく。文字スプライト用のスプライト番号
	numalias sp_text,%1:dec %1

	; テキストウィンドウをスプライトの位置まで引っ込ませる。
	windowback

	; テキストウィンドウの画像タグを格納する変数(グローバル変数)
	numalias textwindow_file,%2:inc %2
	; テキストウィンドウの不透明度の変数(グローバル)
	numalias textwindow_alpha,%2:inc %2

	; テキストウィンドウの大きさの変数
	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_color,%0:inc %0
	numalias font_color_clickable,%0:inc %0
	numalias font_color_choose,%0:inc %0
	numalias font_color_choosed,%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

	; 自作のテキストウィンドウ初期化命令の定義
	defsub set_textwindow

return

*start_textwindow

	; テキストウィンドウの画像と不透明度を定義
	if %global_initialize=0 mov $textwindow_file,":c;>600,200,#888888"
	if %global_initialize=0 mov %textwindow_alpha,255

	; 色の設定
	mov $font_color,"#FFFFFF"
	mov $font_color_clickable,"#0000FF"
	mov $font_color_choose,"#FF0000"
	mov $font_color_choosed,"FF00FF"

	; エフェクト中もテキストウィンドウが消えないようにする。
	erasetextwindow 0

	; 念のため、右クリックを殺しておく。
	rmode 0

	; 一度実行しておく。
	set_textwindow

return

; テキストウィンドウを設定した値に変更する。
*set_textwindow

	; テキストウィンドウの画像読み込み
	lsph sp_textwindow,$textwindow_file,0,0,%textwindow_alpha
	
	; テキストウィンドウのサイズを取得
	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
	
	; 実際の表示領域の広さを計算する。
	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

	; テキストウィンドウの位置を設定
	amsp sp_textwindow,%textwindow_x,%textwindow_y

return

; テキストウィンドウを表示する。
*print_textwindow

	vsp sp_textwindow,1
	vsp sp_text,1

return

; テキストウィンドウを非表示にする。
*delete_textwindow

	vsp sp_textwindow,0
	vsp sp_text,0

return

*define_text
	; システムカスタマイズの宣言
	textgosub *text_lb
	pretextgosub *pretext_lb

	; 既読スキップ有りで。
	kidokuskip

	; テキストウィンドウに表示している文字を取得するための変数
	numalias text_pre,%0:inc %0
	numalias text_before,%0:inc %0
	numalias text_after,%0:inc %0

	; テキストスピード(グローバル変数)
	numalias text_speed,%2:inc %2

	; texton/textoffを上書き
	defsub texton
	defsub textoff

	; テキストウィンドウを表示しているかいないかを格納する変数
	numalias text_visible,%0:inc %0
	
	; pretext用タグ取得変数
	numalias gettag1,%0:inc %0
	numalias gettag2,%0:inc %0
	numalias gettag3,%0:inc %0

	; 発言者名
	numalias talker_name,%0:inc %0
	; 実際に表示する名前
	numalias talker_label,%0:inc %0
	; 現在再生しているボイスファイル。
	numalias voice_playing,%0:inc %0
	; 仮の再生ファイル
	numalias voice_temp,%0:inc %0

return

*start_text

	; 文字速度の初期設定
	if %global_initialize=0 mov %text_speed,40
	
	; 文字速度をそれに設定する。
	textspeed %text_speed

return

*pretext_lb

	; タグを取得する。
	gettag $gettag1,$gettag2,$gettag3

	; 現在の表示内容を取得しておく。
	getlogtext $text_pre,0
	len %text_pre,$text_pre

	; $gettag1が空でなければ、ネームプレート処理をする。
	notif_str_gosub $gettag1,"",*pretext_lb_talker

	; 念のため、表示
	texton
	print 1
	
	; 念のため、文字速度を設定
	textspeed %text_speed

	; ボイスがあった時の処理
	notif_str_gosub $gettag2,"",*pretext_lb_voice

return

*pretext_lb_talker

	; $gettag1があれば、それを表示する名前にする。
	mov $talker_name,$gettag1
	mov $talker_label,$gettag1

	; $gettag3があれば、それをネームプレートにするが、内部的には発言者は変わらない。
	len %gettag3,$gettag3
	skip 1 + 1/(%gettag3+1) ; 飛ばす処理
	mov $talker_label,$gettag3
	
	; 表示する。
	putname $talker_label

return

*pretext_lb_voice

	; 仮のファイル名を作成
	mov $voice_temp,voice_folder+$gettag2+voice_extension
	
	; ファイルの存在確認
	fileexist %fileexist,$voice_temp
	
	; なければ何もしない
	if_int_return %fileexist,0

	; 存在するので、ファイルとして登録
	mov $voice_playing,$voice_temp
	
	; 名前も確定しているはずなので、演奏する。
	voice $talker_name,$voice_playing

	; $voice_playing に登録があれば、それはボイスボタンで再生できるとする。

return

*text_lb

	; スキップモードなら、すぐに飛ばす。
	isskip %is_skip
	if_int_goto %is_skip,1,*text_lb_loop3
	; CTRLは例外とする。
	checkkey %checkkey,"CTRL":skip %checkkey+1
	wait_noinput ; キーアップまで待つ。

	*text_lb_loop1

	bclear

	*text_lb_loop2

	bexec $bexec,%bexec
	
	*text_lb_loop3

	; スキップモードの判定と、スキップモードへの変更
	if_str_gosub $bexec,"K",*skipon
	
	; スキップモードを取得
	isskip %is_skip
	; スキップモードなら、飛ばす。
	if_int_goto %is_skip,1,*text_lb_end
	
	; 次に進む処理
	if_str_goto $bexec,"LCLICK",*text_lb_end
	if_str_goto $bexec,"SPACE",*text_lb_end
	if_str_goto $bexec,"RETURN",*text_lb_end
	if_str_goto $bexec,"WHEELDOWN",*text_lb_end
	if_str_goto $bexec,"PAGEDOWN",*text_lb_end
	if_str_goto $bexec,"CTRL",*text_lb_end
	
	; 正しい入力ではなかったので、ループする。再入力待ち
	goto *text_lb_loop2
	
	; 次に進む。
	*text_lb_end
	
	; 現在の表示内容を取得しておく。
	getlogtext $text_before,0
	len %text_before,$text_before
	
	; \マークで来ていたら、テキストウィンドウの中身を消す。
	texec
	
	; 現在の表示内容を取得しておく。
	getlogtext $text_after,0
	len %text_after,$text_after

	; もし、最後の表示内容の長さが0になっていれば、テキストが消去された可能性がある。
	if_int_gosub %text_after,0,*check_textclear

return

; テキストウィンドウの中身が消去されたかどうかを確認するルーチン
*check_textclear

	; texec直前のテキストウィンドウの中身が存在していなければ、変化なしと判断する。
	if_large_goto %text_before,%text_after,*check_textclear_main

return
	
*check_textclear_main

	; ここに来たと言うことは、textclearが実行されたと判断する。
	; やるべきことは、
	; 1.今まで表示していた内容(発言者欄・ボイス・テキスト)のバックログへの追加(未実装)
	; 2.発言者欄の消去
	; 3.現在再生しているボイスファイルの削除
	
	; 発言者欄の消去
	nameclear
	print 1
	
	; ボイスファイルの削除
	mov $voice_playing,""

return

*texton

	; 既に表示状態なら、何もしない。
	if_int_return %text_visible,1

	; 一連の処理その1
	gosub *print_textwindow
	gosub *print_nameplate

	; 画面を更新
	print 1

	; デフォルトの処理をする。
	_texton
	
	; フラグ管理
	mov %text_visible,1

return

*textoff

	; 既に非表示状態なら、何もしない。
	if_int_return %text_visible,0

	; 一連の処理その2
	gosub *delete_textwindow
	gosub *delete_nameplate

	; 画面を更新
	print 1

	; デフォルトの処理をする。
	_textoff

	; フラグ管理
	mov %text_visible,0

return

*define_nameplate

	; スプライト設定
	; 発言者欄
	numalias sp_nameplate,%1:dec %1
	; 発言者欄のスプライトファイル
	numalias nameplate_file,%0:inc %0

	; 発言者欄の各値
	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 sp_name,%1:dec %1
	; 発言者欄の各値
	numalias name_x,%0:inc %0
	numalias name_y,%0:inc %0
	numalias name_width,%0:inc %0
	numalias name_height,%0:inc %0
	
	; 表示する発言者名
	numalias name_string,%0:inc %0
	
	; 現在、発言者名が設定されているかいないか。
	numalias name_exist,%0:inc %0

	; 発言者欄の初期化命令
	defsub set_nameplate
	
	; 発言者名に文字を出力
	defsub putname
	; 発言者名を削除する命令
	defsub nameclear

return

*start_nameplate

	; ファイルの設定
	if $nameplate_file="" mov $nameplate_file,":c;>100,30,#888888"

	; 初期化
	set_nameplate

return

; ネームプレートの初期化
*set_nameplate
	
	; ネームプレートのファイルの読み込み。不透明度はテキストウィンドウと同じ。
	lsph sp_nameplate,$nameplate_file,0,0,%textwindow_alpha
	csp sp_name ; 念のため、今表示している名前は削除
	mov %name_exist,0
	
	; サイズの取得
	getspsize sp_nameplate,%nameplate_width,%nameplate_height
	
	; 位置を決定
	; テキストウィンドウの左上にくっつける。
	mov %nameplate_x,%textwindow_x
	mov %nameplate_y,%textwindow_y-%nameplate_height
	
	; 位置を操作
	amsp sp_nameplate,%nameplate_x,%nameplate_y
	
return

; ネームプレートに文字を表示する。
*putname

	; 表示する文字列を取得する。
	getparam $name_string
	
	; 文字列をスプライト化する。不透明度は255で固定
	lsph sp_name,$font_sprite+$font_color+$name_string,0,0,255
	
	; 大きさを取得
	getspsize sp_name,%name_width,%name_height
	
	; 正しい位置を計算
	mov %name_x,%nameplate_x+%nameplate_width/2-%name_width/2
	mov %name_y,%nameplate_y+%nameplate_height/2-%name_height/2
	
	; 正しい位置に移動
	amsp sp_name,%name_x,%name_y
	vsp sp_name,1

	; フラグ管理
	mov %name_exist,1

return

*nameclear

	; スプライトを削除
	csp sp_name
	; フラグ管理
	mov %name_exist,0

return

; ネームプレートを表示する。
*print_nameplate

	vsp sp_nameplate,1
	vsp sp_name,%name_exist

return

; ネームプレートを非表示にする。
*delete_nameplate

	vsp sp_nameplate,0
	vsp sp_name,0

return


*define_bexec

	; bexec回りの定義

	; 専用変数
	numalias bexec,%0:inc %0

	; 何も入力がない状態まで待つ関数
	defsub wait_noinput

	; checkkey用専用変数
	numalias checkkey,%0:inc %0

return

*wait_noinput

	bclear

	; 時間待ちをする。
	btime 10
	
	; 入力待ち
	bexec $bexec,%bexec
	
	; 入力がタイムアウトでなければ何もしない。
	if_str_return $bexec,"TIMEOUT"

goto *wait_noinput

*define_debug

	; デバッグログを有効にする。
	debuglog 1

return

*define_exec

	; exec_dll関係

	; 命令群を作成
	defsub exec_clear
	defsub exec_setdll
	defsub exec_arg
	defsub exec_arg_int
	defsub execute
	
	stralias exec_slush,"/"
	stralias exec_comma,","
	
	; 実行する文字列全体
	numalias exec_string,%0:inc %0

	; 実行するdll名
	numalias exec_dllname,%0:inc %0
	
	; 引数
	numalias exec_arg,%0:inc %0
	; 引数の数
	numalias exec_arg_count,%0:inc %0

	; 結果を受け取る専用変数
	numalias getret,%0:inc %0
return

*exec_clear

	; 初期化
	mov $exec_dllname,""
	mov %exec_arg_count,0
	mov $exec_string,""

return

*exec_setdll

	exec_clear
	getparam $exec_dllname
	mov $exec_string,$exec_dllname
	add $exec_string,exec_slush

return

*exec_arg

	getparam $exec_arg
	skip 2-1/(1+%exec_arg_count)
	add $exec_string,exec_comma
	add $exec_string,$exec_arg
	inc %exec_arg_count

return

*execute

	exec_dll $exec_string

	; 結果を先に受け取っておく。
	getret $getret
	getret %getret

	exec_setdll $exec_dllname

return

*define_fileexist

	; fileexist専用変数
	numalias fileexist,%0:inc %0

return

*define_if

	; 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
	defsub if_str_return
	defsub if_int_return
	defsub notif_str_return
	defsub notif_int_return
	
	defsub if_large_goto
	defsub if_small_goto
	defsub if_large_gosub
	defsub if_small_gosub
	defsub if_large_return
	defsub if_small_return
	
	numalias if_a,%0:inc %0
	numalias if_b,%0:inc %0
	numalias if_label,%0:inc %0

return

*start_if

	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_return ""," "
	if_int_return 0,1
	notif_str_return "",""
	notif_int_return 0,0

	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

	gosub *start_if1
	gosub *start_if2
	gosub *start_if3
	gosub *start_if4

	if_large_goto 0,0,*if_in_advance_dummy
	if_small_goto 0,0,*if_in_advance_dummy
	if_large_gosub 0,0,*if_in_advance_dummy
	if_small_gosub 0,0,*if_in_advance_dummy
	if_large_return 0,0
	if_small_return 0,0

	if_large_goto 1,0,*if_in_advance5
	*if_in_advance5
	if_large_goto 0,1,*if_in_advance6
	*if_in_advance6

	gosub *start_if5
	gosub *start_if6

return

*start_if1
	if_str_return "",""
return

*start_if2
	if_int_return 0,0
return

*start_if3
	notif_str_return ""," "
return

*start_if4
	notif_int_return 0,1
return

*start_if5
	if_large_return 1,0
return

*start_if6
	if_small_return 0,1
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_int_return
	getparam %if_a,%if_b
	if %if_a=%if_b return *if_in_advance_dummy
return

*if_str_return
	getparam $if_a,$if_b
	if $if_a=$if_b return *if_in_advance_dummy
return

*notif_int_return
	getparam %if_a,%if_b
	notif %if_a=%if_b return *if_in_advance_dummy
return

*notif_str_return
	getparam $if_a,$if_b
	notif $if_a=$if_b return *if_in_advance_dummy
return

*if_large_goto
	getparam %if_a,%if_b,$if_label
	if %if_a>%if_b goto $if_label
return

*if_small_goto
	getparam %if_a,%if_b,$if_label
	if %if_a<%if_b goto $if_label
return

*if_large_gosub
	getparam %if_a,%if_b,$if_label
	if %if_a>%if_b gosub $if_label
return

*if_small_gosub
	getparam %if_a,%if_b,$if_label
	if %if_a<%if_b gosub $if_label
return

*if_large_return
	getparam %if_a,%if_b
	if %if_a>%if_b return *if_in_advance_dummy
return

*if_small_return
	getparam %if_a,%if_b
	if %if_a<%if_b return *if_in_advance_dummy
return

*if_in_advance_dummy
	; 何もしないよ。
return

*define_newsposition

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

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

*define_skip

	; skiponを作成し、skipoffを上書きする。
	defsub skipon
	defsub skipoff
	
	; スキップ状態を格納する変数
	numalias is_skip,%0:inc %0

return

*start_skip

	; 一回実行しておく。
	skipon
	skipoff

return

*skipon

	; スキップ状態にする。
	systemcall skip
	isskip %is_skip

return

*skipoff

	; スキップ状態を解除する。
	_skipoff
	isskip %is_skip

return

*define_sound

	; BGM/BGV/SEの音量(グローバル)
	numalias bgm_vol,%2:inc %2
	numalias bgv_vol,%2:inc %2
	numalias se_vol,%2:inc %2

	; ボイスループ用変数
	numalias voice_loop,%0:inc %0

	; ボイスボリューム
	numalias voice_vol,%0:inc %0
	; 配列にする。
	dim ?voice_vol[cast_max+1]
	for %voice_loop=1 to cast_max
		mov ?voice_vol[%voice_loop],%2:inc %2 ; グローバル変数を割り当てる。
	next

	; ボイスモード(グローバル)
	numalias voice_mode,%2:inc %2
	; ボイスモードの数値の意味
	numalias single,0 ; 単一再生
	numalias mulch,1 ; 多重再生を許す

	; BGM命令を上書きして、自動でボリュームも設定するようにする。
	defsub bgm
	defsub bgmstop
	numalias bgm_file,%0:inc %0

	; BGV命令を作る。
	defsub bgv
	defsub bgvstop
	; チャンネルを49に。(適当)
	numalias bgv_channel,49
	numalias bgv_file,%0:inc %0
	
	; SE命令を作る。単発専用。
	; 空いているチャンネルを自動で選ぶ。
	defsub se
	; 使っていいチャンネルの範囲
	numalias se_channel_first,10
	numalias se_channel_last,45
	numalias se_channel,%0:inc %0
	numalias se_file,%0:inc %0
	defsub se_channel_countup

	; ボイス用命令
	defsub voice
	; キャラクターの名前とファイルを指定する。
	; キャラクターの名前からボリュームを取得してファイルを演奏する。
	; ただし、ボリュームが0の場合、演奏はしない。
	; チャンネルは、ボイスモードがsingleなら0で確定。mulchなら、適当にバラけさせる。
	numalias voice_castname,%0:inc %0
	numalias voice_volume,%0:inc %0
	numalias voice_file,%0:inc %0

	; ボイスを格納するフォルダ
	stralias voice_folder,"voice\"
	; ボイスファイルの拡張子
	stralias voice_extension,".ogg"

return

*start_sound

	; 初期設定
	if %global_initialize=1 goto *start_sound2
	
		mov %bgm_vol,50
		mov %bgv_vol,50
		mov %se_vol,50
	
		for %voice_loop=1 to cast_max
			mov %?voice_vol[%voice_loop],50
		next
	
		mov %voice_mode,single
	
	*start_sound2

	; SEのボリュームだけは設定しておく。
	sevol %se_vol

	; 使っていいチャンネルの設定
	mov %se_channel,se_channel_first

return

*bgm

	; 演奏するファイルを取得
	getparam $bgm_file

	; 演奏開始
	_bgm $bgm_file

	; ボリュームを設定
	bgmvol %bgm_vol

return

*bgmstop

	; 演奏停止
	_bgmstop
	
	mov $bgm_file,""

return

*bgv

	; 演奏するファイルを取得
	getparam $bgv_file

	; 演奏開始
	dwaveloop bgv_channel,$bgv_file

	; ボリュームを設定
	chvol bgv_channel,%bgv_vol

return

*bgvstop

	; 演奏停止
	dwavestop bgv_channel
	
	mov $bgv_file,""

return

*se

	; 演奏するファイル名を取得
	getparam $se_file

	; 演奏する。
	dwave %se_channel,$se_file
	chvol %se_channel,%se_vol
	
	; 次のためにチャンネルを変える。
	se_channel_countup

return

*se_channel_countup

	; カウントアップ
	inc %se_channel
	if_large_goto %se_channel,se_channel_last,*se_channel_countup_down

return

*se_channel_countup_down

	; 最低値に戻す
	mov %se_channel,se_channel_first

return

*voice

	getparam $voice_castname,$voice_file
	
	; ボリュームは0にしておく
	mov %voice_volume,0
	
	; 名前を番号に変換
	name2number %voice_castname,$voice_castname
	
	; 登録のない名前なら何もしないで終る。
	if_int_return %voice_castname,0
	
	; ボリュームを取得
	mov %voice_volume,%?voice_vol[%voice_castname]
	
	; ボリュームが0なら、やはり演奏しない。
	if_int_return %voice_volume,0

	; 演奏する(ボイスモードで分岐)
	tablegoto %voice_mode,*voice_single,*voice_mulch

return

*voice_single

	; シングルモードの場合
	dwave 0,$voice_file
	chvol 0,%voice_volume

return

*voice_mulch

	; マルチモードの場合
	dwave %se_channel,$voice_file
	chvol %se_channel,%voice_volume
	se_channel_countup

return


*define_sprite

	; getspsize用汎用変数
	numalias getspsize_width,%0:inc %0
	numalias getspsize_height,%0:inc %0
	
	; 中心部を指定してスプライトを動かすamspラッパー
	defsub camsp
	; それ用の変数
	numalias camsp_sp,%0:inc %0
	numalias camsp_x,%0:inc %0
	numalias camsp_y,%0:inc %0

return

*start_sprite
return

; amspのラッパー
; 点を指定すると、そこが中心点になるようにスプライトを動かす。
*camsp

	getparam %camsp_sp,%camsp_x,%camsp_y
	getspsize %camsp_sp,%getspsize_width,%getspsize_height
	div %getspsize_width,2
	div %getspsize_height,2
	amsp %camsp_sp,%camsp_x-%getspsize_width,%camsp_y-%getspsize_y

return

*start_global

	; グローバル変数の初期化はしたと言う印。
	mov %global_initialize,1

return