mod_layerbutton-emes.hsp

common\ mod_layerbutton-emes.hsp

/* /////////////////////////////////////////////////////////////////////////////
mod_layerbutton-emes モジュール
--------------------------------------------------------------------------------
%dll ; モジュール名
mod_layerbutton-emes
%ver ; バージョン
1.0
%date ; 更新日
2025/10/26
%author ; 著作者
MIZUSHIKI
%note
layerbutton命令を利用した1文字ずつ表示するlayeremesオブジェクトを作成
%type
拡張命令
%url
https://suwa.pupu.jp/HSP/index.html
%port ; 対応環境
Win
*/ /////////////////////////////////////////////////////////////////////////////
#if 0
%index ;========================================================================
layeremes
layerbuttonを利用したlayeremesオブジェクトを作成
%group ;------------------------------------------------------------------------
オブジェクト制御命令
%prm   ;------------------------------------------------------------------------
p1,p2,p3,p4,"string",p5,p6,p7,p8 {}
p1,p2 : layeremesオブジェクトのXYサイズ(ドット単位)
p3=0〜(0) : オプション値
p4=0〜(0) : グループID
"strings" : 表示するメッセージ、または変数
p5=0〜(0) : オプション[mes命令と同様]
p6=(0) : 1文字表示するのに掛けるフレーム数
p7, p8 : アラインメント モード (0, 0)
%inst  ;------------------------------------------------------------------------
layerbuttonを利用した1文字ずつ文字を表示するlayeremesオブジェクトを配置します。
layerbutton命令と同様、命令末尾に {} を記述してサブルーチンを指定する少し特殊な構文を用います。
サブルーチンの最後には必ず return を記述してください。

p1〜p4 は layerbutton と同様のものです。

"string" には表示するメッセージを指定します。
文中に以下の制御記号を挿入できます。
・"~"(チルダ) : 文字送り待機
・"^"(ハット) : ページ送り待機 (行末のみ指定可能)
また、行頭に「;」、文中に「/**/」を書くことで、文字の色やフォントを変更するコマンドコメントを記述できます。
使用可能なコマンドは以下の通りです。
html{
<table border="1" cellpadding="10">
<tr>
  <td scope="col"><b>コマンド</b></td>
  <td scope="col"><b>効果</b></td>
</tr>
<tr>
  <td>font "フォント名",p1,p2,p3</td>
  <td>標準のfont命令に準拠。
  <br>引数を省略した場合は、前回の設定が引き継がれます。</td>
</tr>
<tr>
  <td>rgbcolor p1</td>
  <td>$RRGGBB(または0xRRGGBB)形式での文字色の指定。</td>
</tr>
<tr>
  <td>color p1,p2,p3</td>
  <td>R,G,B輝度形式での文字色の指定。</td>
</tr>
<tr>
  <td>objcolor p1,p2,p3</td>
  <td>layeremesのp5オプションで影付き文字、縁取り文字を指定したときの装飾色をR,G,B輝度形式で指定。</td>
</tr>
<tr>
  <td>mes p1,p2</td>
  <td>p1は必ず無視されます。p2で影付き文字、縁取り文字を指定するためのコマンドです。</td>
</tr>
<tr>
  <td>text p1</td>
  <td>「1文字表示フレーム数」を変更。
  <br>「-1」を指定したときは無視します。(「-1」は、objprmを利用してください。)</td>
</tr>
</table>
}html
コマンドコメントは内部で自力解析を行っているため、単純な値指定のみ対応しています。
計算式や変数の使用はできません。

p6 に 0 以上を指定すると、そのフレーム数ごとに文字が1つずつ表示されます。
負数を指定すると、「1フレームあたりに表示する文字数」を指定できます。
・例: p6 = -3 → 1フレームに3文字ずつ表示
・特殊値 -1 → "^"(ハット)ページ区切りまでを一気に表示。このとき "~"(チルダ) の待機は無視されます。

引数 p7, p8 で、横方向, 縦方向のアラインメントを指定できます。
p7 : 0 = 左寄せ, 1 = 中央寄せ, 2 = 右寄せ
p8 : 0 = 上寄せ, 1 = 中央寄せ, 2 = 下寄せ

サブルーチンは文字が表示される直前に呼び出されます。
背景装飾や、メッセージ表示完了の検知などに利用できます。
・現在の状態はシステム変数 layemes_stat で確認可能です。
・ステータスが変化してからのフレーム数は layemes_cnt に格納されます。
・サブルーチン呼出時には、stat に「表示済み文字数」が代入され、カレントポジションは文末位置になります。
 (ただし カレントポジションの x, y が -1 のときは使用しないでください。)
layerbutton 命令のサブルーチン内で動作しているため、laybtn_ezboxlayerbtn_stat などの命令・変数も利用可能です。

通常、layeremesオブジェクトはメッセージ表示完了後に自動削除されます。
layemes_settings で、メッセージ表示完了後も削除されないようにできます。

layeremesオブジェクトは objprm でパラメータを変更することができます。
・objprm id,"string" : 新たなメッセージ表示を開始
・objprm id,int : 「1文字表示するのに掛けるフレーム数」を変更
%href  ;-----------------------------------------------------------------------
layemes_font
layemes_settings
layemes_frames
layemes_stat
layemes_cnt

%index ;========================================================================
layemes_font
layeremesオブジェクトのフォント設定
%group ;------------------------------------------------------------------------
オブジェクト制御命令
%prm   ;------------------------------------------------------------------------
"fontname",p1,p2,p3,p4,p5,p6
"fontname" : フォント名
p1=1〜(20) : フォントの大きさ
p2=0〜(0) : フォントのスタイル
p3=1〜(1) : フォント修飾の幅
%inst  ;------------------------------------------------------------------------
layemes_font 命令は layeremes サブルーチン{}内の先頭に書いてください。
"fontname", p1〜p3 は font 命令と同じ指定方法です。
"fontname"の初期値は「msgothic」になっています。
%href  ;------------------------------------------------------------------------
layeremes
layemes_settings
layemes_frames
layemes_stat
layemes_cnt

%index ;========================================================================
layemes_settings
layeremesオブジェクトの動作を設定
%group ;------------------------------------------------------------------------
オブジェクト制御命令
%prm   ;------------------------------------------------------------------------
p1,p2,p3,p4,p5,p6
p1=0〜(0) : オプション値
p2=0〜(0) : 文字間の隙間
p3=0〜(0) : 行間の隙間
p4=0〜(-1) : メッセージ表示時の効果音メディアバッファID(mmloadで割り当てたID)
p5=0〜(16|32|256) : ページ送り等の操作キー
p6=0〜(0) : 文字フェードに掛けるフレーム数
%inst  ;------------------------------------------------------------------------
layemes_settings 命令は layeremes サブルーチン{}内の先頭に書いてください。

p1 オプション値では、layeremes の動作設定を変更できます。
複数の設定を同時に有効にする場合は、値を加算して指定します。
html{
<table border="1" cellpadding="10">
<tr>
  <td scope="col"><b>p1</b></td>
  <td scope="col"><b>設定内容</b></td>
</tr>
<tr>
  <td>+1</td>
  <td>メッセージ表示が完了しても削除されなくなります。
  <br>※ 削除は clrobj や laybtn_hide 等を使用してください。</td>
</tr>
<tr>
  <td>+2</td>
  <td>メッセージ表示の途中でキー操作をしても、メッセージをスキップしなくなります。</td>
</tr>
</table>
}html

p2,p3 は、それぞれ文字間と行間の隙間を設定します。
p4 に mmload で読み込んだメディアバッファIDを指定すると、メッセージ表示時に効果音を再生します。
p5 に値を指定すると、ページ送りなどの操作に使用するキーを変更できます。(stick 命令で使用する値と同じ)
キー入力やクリック、タッチ操作を一切受け付けないようにする場合は、0 を指定してください。
また、ゲームパッドなどの入力でページ送り等を操作したい場合は、layerbtn_stickVar グローバル変数を利用してください。  
p6 に値を設定すると、指定フレーム数をかけて文字が徐々にフェード表示されるようになります。(HSP3Dish限定)
%href  ;------------------------------------------------------------------------
layeremes
layemes_font
layemes_frames
layemes_stat
layemes_cnt

%index ;========================================================================
layemes_frames
layeremesオブジェクトにSHOW_IN等のフレーム数を設定
%group ;------------------------------------------------------------------------
オブジェクト制御命令
%prm   ;------------------------------------------------------------------------
p1,p2,p3,p4,p5,p6
p1=0〜(0) : SHOW_IN フレーム数
p2=0〜(0) : FOCUS_IN フレーム数
p3=0〜(0) : PRESS_IN フレーム数
p4=0〜(0) : SHOW_OUT フレーム数
p5=0〜(0) : FOCUS_OUT フレーム数
p6=0〜(0) : PRESS_OUT フレーム数
%inst  ;------------------------------------------------------------------------
layemes_frames 命令は layeremes サブルーチン{}内の先頭に書いてください。

layeremes では、layerbuttonで使用される各フレーム数の初期値はすべて 0 に設定されています。
SHOW_IN などのフレーム数を指定することで、layerbutton と同様に、例えばサブルーチン内で描画するメッセージボックスにフェードイン演出を加えること等ができます。
また、SHOW_OUT を指定すると、メッセージ表示が完了して自動削除される際に、メッセージがフェードアウトしながら消えるようになります(HSP3Dish限定)。
ただし、FOCUS や PRESS のフレーム数を設定しても、laybtn_settings 1,1,0 としてキー入力やマウス/タッチ操作が無効化されているため、基本的には効果はありません。
%href  ;------------------------------------------------------------------------
layeremes
layemes_font
layemes_settings
layemes_stat
layemes_cnt

%index ;========================================================================
layemes_stat
layeremesオブジェクトの処理状態が代入される
%group ;------------------------------------------------------------------------
拡張システム変数
%inst  ;------------------------------------------------------------------------
layeremes のサブルーチン内で利用するもので、現在の処理状態が代入されています。
[処理状態]
0 : まだメッセージが設定されていない
1 : メッセージ表示中
2 : 文字送り待機中
3 : ページ送り待機中
4 : メッセージ表示完了 (layemes_settingsで削除されない設定にしたとき)
%href  ;------------------------------------------------------------------------
layeremes
layemes_font
layemes_settings
layemes_frames
layemes_cnt

%index ;========================================================================
layemes_cnt
layeremesオブジェクトの処理状態が変更されてからの経過フレーム数
%group ;------------------------------------------------------------------------
拡張システム変数
%inst  ;------------------------------------------------------------------------
layerbutton のサブルーチン内で利用するもので、処理状態が変更されて何フレーム目かの値が代入されます。
%href  ;------------------------------------------------------------------------
layeremes
layemes_font
layemes_settings
layemes_frames
layemes_stat
% ;=============================================================================
#endif

#include "mod_layerbutton.hsp"

#ifndef layeremes

#module modlayemes
//--------------------------------------
// モジュール内定数
//--------------------------------------
#define FLAGEMES_OPTION_NOSKIP 2

//--------------------------------------
// 未初期化警告避け
//--------------------------------------
lastMmplayTime=0
platform=0
stk=0
emesOption=0
msTime=0
cmds=0
prms=0
prm=0

//--------------------------------------
// layeremes
//--------------------------------------
#define global layeremes(%1,%2,%3=0, %4=0,%5="",%6=0,%7=0,%8=0,%9=0) %tmodlayemes if(1):p2@modlayemes=%2:p3@modlayemes=%3:p4@modlayemes=%4:p5@modlayemes=%5:p6@modlayemes=%6:p7@modlayemes=%7:p8@modlayemes=%8:p9@modlayemes=%9}:layerbutton %1,p2@modlayemes,p3@modlayemes,p4@modlayemes,0,0,0,0,0,0 {  :\
laybtn_settings 1,1,0  :\
if lparam == objlayer_cmdinit {  :\
nowFontName@%i="" : FontName@%p=""  :\
if 0{chardelay@%p=0:charspacing@%p=0:linespacing@%p=0:fadeframe@%p=0:mmindex@%p=0:xx@%p=0:yy@%p=0:stkvalue@%p=0:emesoption@%p=0:startframe@%p=0:startindex@%p=0:mae_startindex@%p=0:analyzedindex@%p=0:lastdrawindex@%p=0:lastdrawindex_formm@%p=0:lastmmplaytime@%p=0:lastdraw_cx@%p=0:lastdraw_cy@%p=0:p_allmesx@%p=0:p_allmesy@%p=0:splitnum@%p=0:nowfontsize@%p=0:nowfontstyle@%p=0:nowfontdecosize@%p=0:nowfontcolor@%p=0:nowfontdecocolor@%p=0:nowmesstyle@%p=0:nowchardelay@%p=0:fontsize@%p=0:fontstyle@%p=0:fontdecosize@%p=0:fontcolor@%p=0:fontdecocolor@%p=0:messtyle@%p=0:state@%p=0:count@%p=0:splitchars@%p=0:splitchars_cmdindex@%p=0:splitchars_cmd@%p=0:splitCharsLineNumY@%p=0:splitcharsmesxSum@%p=0:splitcharsmesx@%p=0:splitcharsmesy@%p=0:splitcharsmesymax@%p=0:splitcharsstartframe@%p=0:splitcharsdelay@%p=0}:\
} :\
dup charDelay@modlayemes, charDelay@%p  :\
dup charSpacing@modlayemes, charSpacing@%p  :\
dup lineSpacing@modlayemes, lineSpacing@%p  :\
dup fadeFrame@modlayemes, fadeFrame@%p  :\
dup mmIndex@modlayemes, mmIndex@%p  :\
dup xx@modlayemes, xx@%p  :\
dup yy@modlayemes, yy@%p  :\
dup stkValue@modlayemes, stkValue@%p  :\
dup emesOption@modlayemes, emesOption@%p  :\
dup startFrame@modlayemes, startFrame@%p  :\
dup startIndex@modlayemes, startIndex@%p  :\
dup mae_startIndex@modlayemes, mae_startIndex@%p  :\
dup analyzedIndex@modlayemes, analyzedIndex@%p  :\
dup lastDrawIndex@modlayemes, lastDrawIndex@%p  :\
dup lastDrawIndex_forMM@modlayemes, lastDrawIndex_forMM@%p  :\
dup lastMmplayTime@modlayemes, lastMmplayTime@%p  :\
dup lastDraw_cx@modlayemes, lastDraw_cx@%p  :\
dup lastDraw_cy@modlayemes, lastDraw_cy@%p  :\
dup p_allmesx@modlayemes, p_allmesx@%p  :\
dup p_allmesy@modlayemes, p_allmesy@%p  :\
dup splitNum@modlayemes, splitNum@%p  :\
dup nowFontName@modlayemes, nowFontName@%p  :\
dup nowFontSize@modlayemes, nowFontSize@%p  :\
dup nowFontStyle@modlayemes, nowFontStyle@%p  :\
dup nowFontDecoSize@modlayemes, nowFontDecoSize@%p  :\
dup nowFontColor@modlayemes, nowFontColor@%p  :\
dup nowFontDecoColor@modlayemes, nowFontDecoColor@%p  :\
dup nowMesStyle@modlayemes, nowMesStyle@%p  :\
dup nowCharDelay@modlayemes, nowCharDelay@%p  :\
dup FontName@modlayemes, FontName@%p  :\
dup FontSize@modlayemes, FontSize@%p  :\
dup FontStyle@modlayemes, FontStyle@%p  :\
dup FontDecoSize@modlayemes, FontDecoSize@%p  :\
dup FontColor@modlayemes, FontColor@%p  :\
dup FontDecoColor@modlayemes, FontDecoColor@%p  :\
dup MesStyle@modlayemes, MesStyle@%p  :\
dup charDelay@modlayemes, charDelay@%p  :\
dup state@modlayemes, state@%p  :\
dup count@modlayemes, count@%p  :\
if lparam == objlayer_cmdinit {  :\
	layeremes_cmdinit@modlayemes p5@modlayemes,p6@modlayemes,p7@modlayemes,p8@modlayemes,p9@modlayemes, splitChars@%p, splitChars_cmdIndex@%p, splitChars_cmd@%p, splitCharsLineNumY@%p, splitCharsMesxSum@%p, splitCharsMesx@%p, splitCharsMesy@%p, splitCharsMesyMax@%p, splitCharsStartFrame@%p, splitCharsDelay@%p  :\
}else: if lparam == objlayer_cmdprmi {  :\
	layeremes_cmdprmi@modlayemes splitChars@%p, splitChars_cmdIndex@%p, splitChars_cmd@%p, splitCharsLineNumY@%p, splitCharsMesxSum@%p, splitCharsMesx@%p, splitCharsMesy@%p, splitCharsMesyMax@%p, splitCharsStartFrame@%p, splitCharsDelay@%p  :\
	return  :\
}else: if lparam == objlayer_cmdprms {  :\
	layeremes_cmdprms@modlayemes splitChars@%p, splitChars_cmdIndex@%p, splitChars_cmd@%p, splitCharsLineNumY@%p, splitCharsMesxSum@%p, splitCharsMesx@%p, splitCharsMesy@%p, splitCharsMesyMax@%p, splitCharsStartFrame@%p, splitCharsDelay@%p  :\
	return  :\
}else: if lparam==objlayer_cmddraw{  :\
	if state@%p{ laybtn_stick stk@modlayemes : stk@modlayemes|=layerbtn_stickVar }  :\
	Set_pos_lastChar@modlayemes splitChars@%p, splitChars_cmdIndex@%p, splitChars_cmd@%p, splitCharsLineNumY@%p, splitCharsMesxSum@%p, splitCharsMesx@%p, splitCharsMesy@%p, splitCharsMesyMax@%p, splitCharsStartFrame@%p, splitCharsDelay@%p  :\
}  :\
gosub *%p  :\
if lparam == objlayer_cmddraw {  :\
	count@%p++  :\
	layeremes_cmddraw@modlayemes splitChars@%p, splitChars_cmdIndex@%p, splitChars_cmd@%p, splitCharsLineNumY@%p, splitCharsMesxSum@%p, splitCharsMesx@%p, splitCharsMesy@%p, splitCharsMesyMax@%p, splitCharsStartFrame@%p, splitCharsDelay@%p  :\
}  :\
return  :\
*%o

// cmdinit
#deffunc layeremes_cmdinit@modlayemes str emes_text, int emes_p2, int _char_delay, int _x_x, int _y_y, array splitChars, array splitChars_cmdIndex, array splitChars_cmd, array splitCharsLineNumY, array splitCharsMesxSum, array splitCharsMesx, array splitCharsMesy, array splitCharsMesyMax, array splitCharsStartFrame, array splitCharsDelay
	charDelay = _char_delay
	charSpacing = 0
	lineSpacing = 0
	fadeFrame = 0
	mmIndex = -1
	xx=_x_x
	yy=_y_y
	stkValue = 16|32|256

	nowFontName = ""+msgothic
	#ifdef _HSP3DISH
		getreq platform, SYSREQ_PLATFORM
		if platform == PLATFORM_WEBGL : nowFontName = "sans-serif"
	#endif
	nowFontSize = 20
	nowFontStyle = 0
	nowFontDecoSize = 1
	nowFontColor = (ginfo_r<<16) | (ginfo_g<<8) | (ginfo_b)
	#ifdef _HSP3DISH
		dupptr bm, objinfo_bmscr(0), 177*4
		nowFontDecoColor = ((bm(176)&$FF)<<16) | (bm(176)&$FF00) | ((bm(176)>>16)&$FF)  ; COLORREF値(0xBBGGRR) → 0xRRGGBBにして格納
	#else
		dupptr bm, objinfo_bmscr(0), 87*4
		nowFontDecoColor = bm(86)&$FFFFFF
	#endif
	nowMesStyle = emes_p2
	nowCharDelay = charDelay

	FontName = nowFontName
	FontSize = nowFontSize
	FontStyle = nowFontStyle
	FontDecoSize = nowFontDecoSize
	FontColor = nowFontColor
	FontDecoColor = nowFontDecoColor
	MesStyle = nowMesStyle
	charDelay = nowCharDelay

	state = 0
	count = 0
	if emes_text != "" : Set_splitChars emes_text, splitChars, splitChars_cmdIndex, splitChars_cmd, splitCharsLineNumY, splitCharsMesxSum, splitCharsMesx, splitCharsMesy, splitCharsMesyMax, splitCharsStartFrame, splitCharsDelay
	return

// (ローカル命令) 文字列を一文字ごとに分けて配列に格納 → 表示スタート[state=1]
#deffunc local Set_splitChars str emes_text, array splitChars, array splitChars_cmdIndex, array splitChars_cmd, array splitCharsLineNumY, array splitCharsMesxSum, array splitCharsMesx, array splitCharsMesy, array splitCharsMesyMax, array splitCharsStartFrame, array splitCharsDelay
	split_char_emes emes_text, splitChars, splitChars_cmdIndex, splitChars_cmd
	if stat > 0 {
		splitNum = stat
		dim splitCharsLineNumY, splitNum
		dim splitCharsMesxSum, splitNum
		dim splitCharsMesx, splitNum
		dim splitCharsMesy, splitNum
		dim splitCharsMesyMax, splitNum
		dim splitCharsStartFrame, splitNum
		dim splitCharsDelay, splitNum  ; ← delay値を残して、何フレームで何文字表示すればいいかを計算できるようにするもの。
		                               ;   - splitCharsMesxSumなどと共に先行して代入される。
		                               ;   - クリック(state==3)したり、<p>や<d>まで来たら、後にstartFrame=iparamするので、そこまでのsplitCharsDelayは0に上書きされる。
		startFrame = -1  ; cmddraw以外ではiparamカウントは取得できないので
		startIndex = 0
		mae_startIndex = -1
		analyzedIndex = -1
		state = 1
		count = 0
		lastDrawIndex = -1
		lastDrawIndex_forMM = -1
		lastDraw_cx = 0
		lastDraw_cy = 0
		p_allmesx = 0
		p_allmesy = 0

		FontName = nowFontName
		FontSize = nowFontSize
		FontStyle = nowFontStyle
		FontDecoSize = nowFontDecoSize
		FontColor = nowFontColor
		FontDecoColor = nowFontDecoColor
		MesStyle = nowMesStyle
		charDelay = nowCharDelay
	}else {
		state = 0
		count = 0
	}
	return

// cmdprmi
#deffunc layeremes_cmdprmi@modlayemes array splitChars, array splitChars_cmdIndex, array splitChars_cmd, array splitCharsLineNumY, array splitCharsMesxSum, array splitCharsMesx, array splitCharsMesy, array splitCharsMesyMax, array splitCharsStartFrame, array splitCharsDelay
	charDelay = iparam  ; 「1文字表示するのに掛けるフレーム数」を変更
	nowCharDelay = charDelay

	anaFontName = nowFontName
	anaFontSize = nowFontSize
	anaFontStyle = nowFontStyle
	anaFontDecoSize = nowFontDecoSize
	anaFontColor = nowFontColor
	anaFontDecoColor = nowFontDecoColor
	anaMesStyle = nowMesStyle
	anaCharDelay = nowCharDelay
	breakReason = 0
	cnt_ = lastDrawIndex+1
	
	// 設定変更をsplitChars_cmdに追記する
	if cnt_ < splitNum {
		if splitChars_cmdIndex(cnt_) != -1 {
			splitChars_cmd(splitChars_cmdIndex(cnt_)) += ":text "+iparam+":"
		}else{
			splitChars_cmdIndex(cnt_) = length(splitChars_cmd)
			splitChars_cmd(splitChars_cmdIndex(cnt_)) = "text "+iparam+":"
		}
	}
	// 既に設定済みのsplitCharsDelayを上書き
	repeat 
		if cnt_ >= splitNum : break
		anapx = 0
		repeat , cnt_
			if cnt >= splitNum : break
			cnt_ = cnt
			if splitChars_cmdIndex(cnt) != -1 {
				_anaCharDelay = anaCharDelay
				execHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt)), anaFontName, anaFontSize, anaFontStyle, anaFontDecoSize, anaFontColor, anaFontDecoColor, anaMesStyle, _anaCharDelay
				if anaCharDelay != -1 : anaCharDelay = _anaCharDelay * (_anaCharDelay!=-1)
			}
			if splitChars(cnt) == "<br>" {break}
			if splitChars(cnt) == "<d>" : continue
			if splitChars(cnt) == "<w>" : continue
			if splitChars(cnt) == "<x>" : continue
			if splitChars(cnt) == "<p>" {breakReason=1:break}
			splitCharsDelay(cnt) = anaCharDelay * (anaCharDelay!=-1)
			if anapx + splitCharsMesxSum(cnt) > objlayer_size_x : break
			anapx += splitCharsMesxSum(cnt) + charSpacing
		loop
		if (xx!=0 || yy!=0) && breakReason==0 :cnt_++: continue
		break
	loop
	return

// cmdprms
#deffunc layeremes_cmdprms@modlayemes array splitChars, array splitChars_cmdIndex, array splitChars_cmd, array splitCharsLineNumY, array splitCharsMesxSum, array splitCharsMesx, array splitCharsMesy, array splitCharsMesyMax, array splitCharsStartFrame, array splitCharsDelay
	Set_splitChars refstr, splitChars, splitChars_cmdIndex, splitChars_cmd, splitCharsLineNumY, splitCharsMesxSum, splitCharsMesx, splitCharsMesy, splitCharsMesyMax, splitCharsStartFrame, splitCharsDelay
	return

// cmddraw
#deffunc layeremes_cmddraw@modlayemes array splitChars, array splitChars_cmdIndex, array splitChars_cmd, array splitCharsLineNumY, array splitCharsMesxSum, array splitCharsMesx, array splitCharsMesy, array splitCharsMesyMax, array splitCharsStartFrame, array splitCharsDelay
	if startFrame == -1 : startFrame = iparam  ; cmddraw以外ではiparamカウントは取得できないのでここで取得
	if state {
		// キー・マウス入力 処理 (各状態での入力振り分け)
		if stk : laybtn_focus -1: if stat != -1 : stk=0  ; 他のlayerbuttonをクリックやタップしている入力では文字送り等をさせない
		if state == 1 {
			if (emesOption & FLAGEMES_OPTION_NOSKIP)==0 {
				if analyzedIndex != -1 {
					if stk & stkValue {
						state = 5 : count = 0
						if (xx==0 && yy==0) {  ; 寄せ描画している場合は、<p>までの全文を調査済み
							if splitCharsLineNumY(analyzedIndex) == 0 {
								analyzedIndex == -1
							}else {
								temp = analyzedIndex
								anaLineNumY = splitCharsLineNumY(analyzedIndex)
								repeat analyzedIndex
									analyzedIndex--
									if anaLineNumY != splitCharsLineNumY(analyzedIndex) : break
								loop
							}
						}
					}
				}
			}
		}else: if state == 2 {
			if stk & stkValue {
				startFrame = iparam
				state = 1
				count = 0
			}
		}else : if state == 3 {
			if stk & stkValue {
				if lastDrawIndex+1 >= splitNum {  ; 終わり
					if option_keepVisible@_modlaybtn {
						state = 4
						count = 0
					}else {
						_layobjIndex = getLayobjverIndex@modlaybtn(ginfo_sel)
						if _layobjIndex != -1 {
							Add_flagBits_@modlaybtn _layobjIndex,wparam, FLAGBT_SHOWOUT@modlaybtn  ; showoutビットを立ててSHOW_OUT開始
						}else {
							clrobj wparam,wparam
							return
						}
					}
				}else {
					startIndex = lastDrawIndex+1
					startFrame = iparam
					FontName = nowFontName
					FontSize = nowFontSize
					FontStyle = nowFontStyle
					FontDecoSize = nowFontDecoSize
					FontColor = nowFontColor
					FontDecoColor = nowFontDecoColor
					MesStyle = nowMesStyle
					charDelay = nowCharDelay
					state = 1
					count = 0
					lastDraw_cx = 0
					lastDraw_cy = 0
				}
			}
		}
		px = 0 : py = 0
		
		// 文字描画処理
		nowFontName = FontName
		nowFontSize = FontSize
		nowFontStyle = FontStyle
		nowFontDecoSize = FontDecoSize
		nowFontColor = FontColor
		nowFontDecoColor = FontDecoColor
		nowMesStyle = MesStyle
		nowCharDelay = charDelay  ; 文字送りの速度はsplitCharsDelay(cnt)の一文字々々々によって加算されている。splitChars_cmd(index)内のtextによって文章の途中でnowCharDelayを更新する
		font_ nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize
		rgbcolor nowFontColor : objcolor (nowFontDecoColor>>16)&$FF, (nowFontDecoColor>>8)&$FF, (nowFontDecoColor)&$FF
		frm=0.0 : isFading = 0
		tamePx = 0 : resetKuhakuWidth=1 : tameCharsArrayNum = 0
		repeat , startIndex
			if cnt >= splitNum {
				if state!=4 : state=0:count=0 : startIndex = splitNum
				break
			}
			if state!=4 {
				// 次の改行まで解析する
				//  通常 : splitCharsMesyMaxが欲しい。どこで改行するかまでは問わない。
				//  (state == 5 || xx!=0 || yy!=0) : 文字を一気に表示や中央寄せ等にする場合は<p>までの文章全体のXYサイズが必要になるので<p>までの解析が行われる
				if (analyzedIndex < cnt && analyzedIndex < splitNum-1) {
					anaFontName = nowFontName
					anaFontSize = nowFontSize
					anaFontStyle = nowFontStyle
					anaFontDecoSize = nowFontDecoSize
					anaFontColor = nowFontColor
					anaFontDecoColor = nowFontDecoColor
					anaMesStyle = nowMesStyle
					anaCharDelay = nowCharDelay
					breakReason = 0
					cnt_ = cnt
					__cnt = cnt
					if analyzedIndex == -1 {  ; 最初の行
						anaLineNumY = 0
					}else {
						anaLineNumY = splitCharsLineNumY(cnt-1) + 1
					}
					repeat
						anaKitenX = cnt_ : anaKitenChars="" : anaKitenCharsNum=0
						anapx = 0
						anaMesxSum = 0
						takasa = 0
						breakReason = 0
						repeat , cnt_
							if cnt >= splitNum : break
							analyzedIndex = cnt
							__cnt = cnt
							willChangeFont = 0
							if splitChars_cmdIndex(cnt) != -1 {
								_anaCharDelay = anaCharDelay
								preExecHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt)), anaFontName, anaFontSize, anaFontStyle, anaFontDecoSize, anaFontColor, anaFontDecoColor, anaMesStyle, _anaCharDelay
								willChangeFont = stat
								if anaCharDelay != -1 : anaCharDelay = _anaCharDelay * (_anaCharDelay!=-1)  ; -1 も 0 になる
							}
							if splitChars(cnt) == "<br>" {
								if takasa==0 {takasa=anaFontSize}:splitCharsMesxSum(cnt)=-2:splitCharsMesx(cnt)=-1:splitCharsMesy(cnt)=1
								break
							}
							if splitChars(cnt) == "<d>" :splitCharsMesxSum(cnt)=-2:splitCharsMesx(cnt)=-1:splitCharsMesy(cnt)=1: continue
							if splitChars(cnt) == "<w>" :splitCharsMesxSum(cnt)=-2:splitCharsMesx(cnt)=-1:splitCharsMesy(cnt)=1: continue
							if splitChars(cnt) == "<x>" :splitCharsMesxSum(cnt)=-2:splitCharsMesx(cnt)=-1:splitCharsMesy(cnt)=1: continue
							if splitChars(cnt) == "<p>" {
								if takasa==0 {takasa=anaFontSize}:splitCharsMesxSum(cnt)=-2:splitCharsMesx(cnt)=-1:splitCharsMesy(cnt)=1
								breakReason = 2
								break
							}
							;if splitCharsMesy(cnt) == 0 {
								splitCharsDelay(cnt) = anaCharDelay
								if willChangeFont {
									if anaKitenCharsNum > 0 {
										pos -ginfo_sx,-ginfo_sy : mes anaKitenChars, anaMesStyle
										if takasa < ginfo_mesy : takasa = ginfo_mesy
										if anaKitenCharsNum == 1 : splitCharsMesx(cnt) = ginfo_mesx
										if anapx + anaMesxSum + charSpacing*((anapx+anaMesxSum)>0) + ginfo_mesx+charSpacing*(anaKitenCharsNum-1) > objlayer_size_x {
											breakReason = 1
											break
										}
										repeat limit(cnt-anaKitenX,0),anaKitenX
											splitCharsMesxSum(cnt)=-1
											splitCharsMesy(cnt)=ginfo_mesy
										loop
										splitCharsMesxSum(anaKitenX)=-(ginfo_mesx+charSpacing*(anaKitenCharsNum-1))
										anaMesxSum += charSpacing*((anapx+anaMesxSum)>0) + -splitCharsMesxSum(anaKitenX)
										anaKitenChars = "" : anaKitenCharsNum = 0
										anaKitenX = cnt
									}
									execHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt)), anaFontName, anaFontSize, anaFontStyle, anaFontDecoSize, anaFontColor, anaFontDecoColor, anaMesStyle, _anaCharDelay
								}
							;}
							anaKitenChars += splitChars(cnt) : anaKitenCharsNum++
							if cnt+1 < splitNum {
								switch splitChars(cnt+1)
								case "ぁ":case "ぃ":case "ぅ":case "ぇ":case "ぉ":case "ゃ":case "ゅ":case "ょ":case "っ":case "ゎ":
								case "ァ":case "ィ":case "ゥ":case "ェ":case "ォ":case "ャ":case "ュ":case "ョ":case "ッ":case "ヮ":
								anaKitenChars += splitChars(cnt+1) : anaKitenCharsNum++
								continue cnt+2
								swend
							}
						loop
						if anaKitenCharsNum > 0 {
							if breakReason != 1 {
								pos -ginfo_sx,-ginfo_sy : mes anaKitenChars, anaMesStyle
								if takasa < ginfo_mesy : takasa = ginfo_mesy
								if anaKitenCharsNum == 1 : splitCharsMesx(cnt) = ginfo_mesx
							}
							if state == 5 || xx!=0 || yy!=0 || platform == 3 {
								// - クリックスキップや寄せとは別に、Dish.jsでは1行分だけ解析しておく必要がある。(ginfo_mesxが積み立てできない[?])
								if anapx + anaMesxSum + charSpacing*((anapx+anaMesxSum)>0) + ginfo_mesx+charSpacing*(anaKitenCharsNum-1) > objlayer_size_x {
									low = anaKitenX
									high = __cnt
									while low < high
										mid = (low + high + 1) / 2
										anaKitenChars = "" : anaKitenCharsNum=0
										repeat mid-anaKitenX, anaKitenX
											if splitChars(cnt) == "<d>" : continue
											if splitChars(cnt) == "<w>" : continue
											if splitChars(cnt) == "<x>" : continue
											anaKitenChars += splitChars(cnt) : anaKitenCharsNum++
											if cnt+1 < splitNum {
												switch splitChars(cnt+1)
													case "ぁ":case "ぃ":case "ぅ":case "ぇ":case "ぉ":case "ゃ":case "ゅ":case "ょ":case "っ":
													case "ァ":case "ィ":case "ゥ":case "ェ":case "ォ":case "ャ":case "ュ":case "ョ":case "ッ":
													anaKitenChars += splitChars(cnt+1) : anaKitenCharsNum++
													continue cnt+2
												swend
											}
										loop
										pos -ginfo_sx,-ginfo_sy : mes anaKitenChars, anaMesStyle
										if anaKitenCharsNum == 1 : splitCharsMesx(anaKitenX) = ginfo_mesx
										if anapx + anaMesxSum + charSpacing*((anapx+anaMesxSum)>0) + ginfo_mesx+charSpacing*(anaKitenCharsNum-1) < objlayer_size_x {
											low = mid
										}else {
											high = mid -1
										}
									wend
									if low == anaKitenX {
										if ginfo_mesx > objlayer_size_x : low = anaKitenX+1
									}
									anaKitenChars = "" : anaKitenCharsNum=0
									repeat low-anaKitenX, anaKitenX
										if splitChars(cnt) == "<d>" : continue
										if splitChars(cnt) == "<w>" : continue
										if splitChars(cnt) == "<x>" : continue
										anaKitenChars += splitChars(cnt) : anaKitenCharsNum++
									loop
									pos -ginfo_sx,-ginfo_sy : mes anaKitenChars, anaMesStyle
									if anaKitenCharsNum == 1 : splitCharsMesx(anaKitenX) = ginfo_mesx
									__cnt = low-1
								}
								splitCharsMesxSum(anaKitenX)=-(ginfo_mesx+charSpacing*(anaKitenCharsNum-1))
								if takasa < ginfo_mesy : takasa = ginfo_mesy
								repeat limit(__cnt-anaKitenX,0),anaKitenX+1
									splitCharsMesxSum(cnt)=-1
								loop
							}
							repeat limit(__cnt-anaKitenX+1,0),anaKitenX
								splitCharsMesy(cnt)=ginfo_mesy
							loop
						}
						// 設定
						repeat , cnt_
							if cnt >= splitNum : break
							if cnt > __cnt : break
							splitCharsMesyMax(cnt) = takasa
							splitCharsLineNumY(cnt) = anaLineNumY
						loop
						// - Dish.jsの1行分だけ解析した証明を残しておく。(tameKaihouで改行位置を把握するのに使う)
						if platform == 3 {
							if __cnt+1 < splitNum {
								splitCharsLineNumY(__cnt+1) = -1
							}
						}
						if state == 5 || xx!=0 || yy!=0 {
							if __cnt < splitNum && __cnt >= 0 : if splitChars(__cnt) == "<p>" : break
							cnt_ = __cnt + 1
							anaLineNumY += 1
							if cnt_ < splitNum : continue
						}
						break
					loop
					font_ nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize
					rgbcolor nowFontColor : objcolor (nowFontDecoColor>>16)&$FF, (nowFontDecoColor>>8)&$FF, (nowFontDecoColor)&$FF

				}
				// 中央寄せ等にしている場合、<p>までの文章の全体XYサイズが必要なので算出 -> p_allmesx, p_allmesy
				if mae_startIndex != startIndex {
					mae_startIndex = startIndex
					if (xx!=0 || yy!=0) {
						p_allmesx = 0
						p_allmesy = 0
						anapx=0
						anaLineNumY = -1
						repeat , startIndex
							if cnt >= splitNum : break
							if cnt > analyzedIndex : break
							if anaLineNumY != splitCharsLineNumY(cnt) {
								anaLineNumY = splitCharsLineNumY(cnt)
								if p_allmesy > 0 : p_allmesy += lineSpacing
								p_allmesy += splitCharsMesyMax(cnt)
								anapx = 0
							}
							if splitChars(cnt) == "<br>" {
								anapx = 0
								continue
							}
							if splitChars(cnt) == "<d>" : continue
							if splitChars(cnt) == "<w>" : continue
							if splitChars(cnt) == "<x>" : continue
							if splitChars(cnt) == "<p>" : break

							if splitCharsMesxSum(cnt) > 0 {
								mesx = splitCharsMesxSum(cnt)
							}else : if splitCharsMesxSum(cnt) < -2 {
								mesx = -splitCharsMesxSum(cnt)
							}else {
								mesx = 0
							}
							anapx += mesx
							if p_allmesx < anapx : p_allmesx = anapx
							anapx += charSpacing
						loop
					}
				}
				if state == 5 || nowCharDelay == -1 : splitCharsDelay(cnt) = 0 : splitCharsStartFrame(cnt) = -fadeFrame  ; クリックスキップや表示速度-1のとき、delayを0にしたりフェードが255になるようにする
				if splitCharsDelay(cnt)>=0 {
					frm += splitCharsDelay(cnt)
				}else {
					frm += 1.0/-splitCharsDelay(cnt)
				}
				if int(frm)+startFrame > iparam {
					break
				}
				// 最後のインデックス値を控えておく
				if lastDrawIndex < cnt {
					lastDrawIndex = cnt
				}
			}

			// コマンドコメントが付いていた場合、フォント設定等を変更
			if splitChars_cmdIndex(cnt) != -1 {
				_nowCharDelay = nowCharDelay
				execHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt)), nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize, nowFontColor, nowFontDecoColor, nowMesStyle, _nowCharDelay
				resetKuhakuWidth |= stat&1
				if nowCharDelay != -1 : nowCharDelay = _nowCharDelay * (_nowCharDelay!=-1)  ; コメントからのtextでは-1にならない。かつ強制-1されていた場合は-1を継続する。
			}

			// 改行、ページ送り待ち、文字送り待ちのとき
			if splitChars(cnt) == "<br>" {
				px = 0
				py += splitCharsMesyMax(cnt) + lineSpacing
				continue
			}
			if splitChars(cnt) == "<p>" {
				if state!=4 {
					repeat cnt+1
						splitCharsDelay(cnt) = 0
					loop
					lastDrawIndex_forMM = cnt
					if isFading == 0 {
						if state != 3 : count = 0
						state = 3
					}
				}
				break
			}
			if state == 1 && splitChars(cnt) == "<w>" : splitChars(cnt) == "<x>"
			if splitChars(cnt) == "<d>" || splitChars(cnt) == "<w>" {
				if state!=4 {
					if state == 5 || nowCharDelay == -1 {
						splitChars(cnt) == "<x>"
					}else {
						splitChars(cnt) == "<w>"
						repeat cnt+1
							splitCharsDelay(cnt) = 0
						loop
						lastDrawIndex_forMM = cnt
						;if isFading == 0 {
							if state != 2 : count = 0
							state = 2
						;}
						break
					}
				}
			}
			
			// 文字が(簡易調査も含めて)未調査の場合、出力文字のサイズを測っておく(一文字後。二文字後は拗音促音のときのみ)
			if cnt+1 < splitNum {
				if splitCharsMesxSum(cnt+1) == 0 {
					switch splitChars(cnt+1)
					case "<br>" : case "<p>" : case "<w>" : case "<x>" : case "<d>":
						splitCharsMesxSum(cnt+1)=-2 : splitCharsMesy(cnt+1)=1
						splitCharsMesx(cnt+2)=ginfo_mesx
						swbreak
					default
						anaFontName = nowFontName
						anaFontSize = nowFontSize
						anaFontStyle = nowFontStyle
						anaFontDecoSize = nowFontDecoSize
						anaFontColor = nowFontColor
						anaFontDecoColor = nowFontDecoColor
						anaMesStyle = nowMesStyle
						_nowCharDelay = nowCharDelay
						isChangedFontOrColor = 0
						if splitChars_cmdIndex(cnt+1) != -1 {
							execHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt+1)), nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize, nowFontColor, nowFontDecoColor, nowMesStyle, _nowCharDelay
							isChangedFontOrColor |= stat
						}
						pos -ginfo_sx,-ginfo_sy
						mes splitChars(cnt+1),nowMesStyle
						splitCharsMesxSum(cnt+1)=ginfo_mesx : splitCharsMesy(cnt+1)=ginfo_mesy
						splitCharsMesx(cnt+1)=ginfo_mesx
						if cnt+2 < splitNum {
							if splitCharsMesxSum(cnt+2) == 0 {
								switch splitChars(cnt+2)
								case "<br>" : case "<p>" : case "<w>" : case "<x>" : case "<d>":
									splitCharsMesxSum(cnt+2)=-2 : splitCharsMesy(cnt+2)=1
									splitCharsMesx(cnt+2)=-1
									swbreak
								case "ぁ":case "ぃ":case "ぅ":case "ぇ":case "ぉ":case "ゃ":case "ゅ":case "ょ":case "っ":
								case "ァ":case "ィ":case "ゥ":case "ェ":case "ォ":case "ャ":case "ュ":case "ョ":case "ッ":
									if splitChars_cmdIndex(cnt+2) != -1 {
										execHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt+2)), nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize, nowFontColor, nowFontDecoColor, nowMesStyle, _nowCharDelay
										isChangedFontOrColor |= stat
									}
									pos -ginfo_sx,-ginfo_sy
									mes splitChars(cnt+2),nowMesStyle
									splitCharsMesxSum(cnt+2)=ginfo_mesx : splitCharsMesy(cnt+2)=ginfo_mesy
									splitCharsMesx(cnt+2)=ginfo_mesx
									swbreak
								swend
							}
						}
						if isChangedFontOrColor {
							nowFontName = anaFontName
							nowFontSize = anaFontSize
							nowFontStyle = anaFontStyle
							nowFontDecoSize = anaFontDecoSize
							nowFontColor = anaFontColor
							nowFontDecoColor = anaFontDecoColor
							nowMesStyle = anaMesStyle
							font_ nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize
							rgbcolor nowFontColor : objcolor (nowFontDecoColor>>16)&$FF, (nowFontDecoColor>>8)&$FF, (nowFontDecoColor)&$FF
						}
					swend
				}
			}
			// 文字が(簡易調査も含めて)未調査の場合、出力文字のサイズを測っておく
			if splitCharsMesxSum(cnt) == 0 {
				if splitChars(cnt) != "<x>" {  ; <x>だけは貫通させたいので一応分岐
					pos -ginfo_sx,-ginfo_sy
					mes splitChars(cnt),nowMesStyle
					splitCharsMesxSum(cnt)=ginfo_mesx : splitCharsMesy(cnt)=ginfo_mesy
					splitCharsMesx(cnt)=ginfo_mesx
				}else {
					splitCharsMesxSum(cnt)=-1 : splitCharsMesy(cnt)=1
					splitCharsMesx(cnt)=-1
				}
			}
			// 文字描画幅 取り出し。splitCharsMesxSumには次のタイプがある 0以上:一文字の幅、-1未満:複数文字の幅、-1:複数文字に重ねられた文字
			if splitCharsMesxSum(cnt) != 0 {
				if splitCharsMesxSum(cnt) > 0 {
					mesx = splitCharsMesxSum(cnt)
				}else : if splitCharsMesxSum(cnt) < -2 {
					mesx = -splitCharsMesxSum(cnt)
				}else {
					mesx = 0
				}
			}else {
				mesx = 0
			}
			
			// 枠から文字あふれで改行
			if px + mesx > objlayer_size_x {
				px = 0
				if cnt > 0 : py += splitCharsMesyMax(cnt-1) + lineSpacing
			}else : if cnt+1 < splitNum {
				mesx2 = splitCharsMesxSum(cnt+1)  ; マイナス値が入ることがあるが、その場合は拗音促音で改行になることはない
				if px + mesx + charSpacing + mesx2 > objlayer_size_x {
					switch splitChars(cnt+1)
						case "ぁ":case "ぃ":case "ぅ":case "ぇ":case "ぉ":case "ゃ":case "ゅ":case "ょ":case "っ":
						case "ァ":case "ィ":case "ゥ":case "ェ":case "ォ":case "ャ":case "ュ":case "ョ":case "ッ":
						px = 0
						if cnt > 0 : py += splitCharsMesyMax(cnt-1) + lineSpacing
					swend
				}
			}

			// 文字フェード設定
			if splitCharsStartFrame(cnt) == 0 : splitCharsStartFrame(cnt) = iparam
			fd = 255
			#ifdef _HSP3DISH
			if layerbtn_stat & LAYBTN_SHOW_OUT {
				setease 255, 0, ease_quad_out
				fd = getease(layerbtn_cnt, SHOW_OUT_FRAME@modlaybtn)
				gmode 3,,,fd
			}else : if layerbtn_stat & LAYBTN_COMPLETE {
				fd = 0
				gmode 3,,,fd
			}else : if fadeFrame > 0 {
				setease 0, 255, ease_quad_in
				fd = getease(iparam-splitCharsStartFrame(cnt), fadeFrame)
				gmode 3,,,fd
				isFading |= (fd<255)
			}
			#endif

			// 一気に表示できる文字は貯める
			if tameCharsArrayNum == 0 : tamePx = px : tameCharsArray = "" : tameHeadIndex = cnt
			if splitChars(cnt) != "<x>" {
				tameCharsArray(tameCharsArrayNum)=splitChars(cnt)
				tameCharsFades(tameCharsArrayNum)=fd
				tameCharsArrayNum++
			}
			// 貯め開放調査
			tameKaihou = 0
			if cnt+1 < splitNum {
				if platform == 3 {
					if tameKaihou == 0 {
						// - Dish.jsでの1行分だけ解析した証明があれば、そこが改行位置
						if splitCharsLineNumY(cnt+1) == -1 : tameKaihou = 2 : splitCharsLineNumY(cnt+1) = splitCharsLineNumY(cnt)
					}
				}
				if tameKaihou ==0 {
					charSpacing_1 = 0
					if splitCharsMesxSum(cnt+1) > 0 {
						_mesx1 = splitCharsMesxSum(cnt+1)
						charSpacing_1 = charSpacing
					}else: if splitCharsMesxSum(cnt+1) < -2 {
						_mesx1 = -splitCharsMesxSum(cnt+1)
						if cnt+2 < splitNum {
							if splitCharsMesxSum(cnt+1) != -1 && splitCharsLineNumY(cnt+1) == splitCharsLineNumY(cnt+2) : charSpacing_1 = charSpacing  ; 自身が複数文字でサイズ計測したものであれば、次の文字がsplitCharsMesxSum!=-1ときにcharSpacingを追加する。事前に改行だと分かっている場合は
						}
					}else {
						_mesx1 = 0
						if cnt+2 < splitNum {
							if splitCharsMesxSum(cnt+1) != -1 && splitCharsLineNumY(cnt+1) == splitCharsLineNumY(cnt+2) : charSpacing_1 = charSpacing  ; 自身が複数文字でサイズ計測したものであれば、次の文字がsplitCharsMesxSum!=-1ときにcharSpacingを追加する
						}
					}
					if px + mesx + charSpacing_1 + _mesx1 > objlayer_size_x {
						tameKaihou = 2
					}else : if cnt+2 < splitNum {
						_mesx2 = splitCharsMesxSum(cnt+2)  ; マイナス値が入ることがあるが、その場合は拗音促音で改行になることはない
						if px + mesx + charSpacing_1 + _mesx1 + charSpacing + _mesx2 > objlayer_size_x {
							switch splitChars(cnt+2)
								case "ぁ":case "ぃ":case "ぅ":case "ぇ":case "ぉ":case "ゃ":case "ゅ":case "ょ":case "っ":
								case "ァ":case "ィ":case "ゥ":case "ェ":case "ォ":case "ャ":case "ュ":case "ョ":case "ッ":
								tameKaihou = 2
							swend
						}
					}
				}
				if tameKaihou == 0 {
					if splitCharsDelay(cnt+1)>=0 {
						if int(frm + splitCharsDelay(cnt+1))+startFrame > iparam : tameKaihou = 1
					}else {
						if int(frm + 1.0/-splitCharsDelay(cnt+1))+startFrame > iparam : tameKaihou = 1
					}
				}
				if tameKaihou == 0 {
					if splitChars_cmdIndex(cnt+1) != -1 {
						preExecHspEmesCommand splitChars_cmd(splitChars_cmdIndex(cnt+1)), nowFontName, nowFontSize, nowFontStyle, nowFontDecoSize, nowFontColor, nowFontDecoColor, nowMesStyle, nowCharDelay
						if stat : tameKaihou = 1
					}
				}
				if tameKaihou == 0 : if splitChars(cnt+1) == "<br>" : tameKaihou = 3
				if tameKaihou == 0 : if splitChars(cnt+1) == "<p>"  : tameKaihou = 3
				if tameKaihou == 0 : if state != 5 : if splitChars(cnt+1) == "<d>" || splitChars(cnt+1) == "<w>" : tameKaihou = 1
			}else {
				tameKaihou = 1
			}

			if tameKaihou >= 2 {
				// 次のcntは、改行する必要がある行頭の文字。簡易analyzed状態の場合はanalyzedIndexを戻して、再analayzedする。
				if state == 1 : if cnt+2 < splitNum : if splitCharsLineNumY(cnt+(tameKaihou-2)) == splitCharsLineNumY(cnt+(tameKaihou-2)+1) : analyzedIndex = cnt+(tameKaihou-2)
			}
			// 貯め開放して文字描画
			if tameKaihou {
				if resetKuhakuWidth : pos -ginfo_sx,-ginfo_sy : mes " ",nowMesStyle : kuhakuWidth = ginfo_mesx : resetKuhakuWidth=0
				_cnt = cnt : tameChars="" : tameCharsNum=0
				repeat tameCharsArrayNum
					tameChars += tameCharsArray(cnt) : tameCharsNum++
					if platform!=3||fadeFrame==0 : if charSpacing == 0 : if cnt < tameCharsArrayNum-1 : if tameCharsFades(cnt) == tameCharsFades(cnt+1) : continue
					fadeStyle = 0
					#ifdef _HSP3DISH
						if (layerbtn_stat & LAYBTN_SHOW_OUT)!=0 || (layerbtn_stat & LAYBTN_COMPLETE)!=0 || fadeFrame > 0 {
							gmode 3,,,tameCharsFades(cnt) : fadeStyle = 16
						}
					#endif
					pos objlayer_axis_x+(objlayer_size_x-p_allmesx)*limit(xx,0,2)/2 + tamePx, objlayer_axis_y+(objlayer_size_y-p_allmesy)*limit(yy,0,2)/2 + py+splitCharsMesyMax(_cnt)-splitCharsMesy(_cnt)
					mes tameChars+" ",nowMesStyle|fadeStyle
					tamePx += ginfo_mesx - kuhakuWidth + charSpacing
					if tameCharsNum == 1 : splitCharsMesx(tameHeadIndex+cnt) = ginfo_mesx - kuhakuWidth
					tameChars = "" : tameCharsNum=0
					lastDraw_cx = (objlayer_size_x-p_allmesx)*limit(xx,0,2)/2 + tamePx - charSpacing
					lastDraw_cy = (objlayer_size_y-p_allmesy)*limit(yy,0,2)/2 + py + splitCharsMesyMax(_cnt)
				loop
				tameCharsArrayNum = 0
			}
			px += mesx
			if cnt+1 < splitNum : if splitCharsMesxSum(cnt+1) != -1 : px += charSpacing

			// テキスト音鳴らし
			if state!=4 {
				if mmIndex >= 0 {
					if lastDrawIndex_forMM < cnt {
						#ifdef _HSP3DISH
							getreq msTime, SYSREQ_TIMER
						#else
							#uselib "winmm.dll"
							#cfunc timeGetTime "timeGetTime"
							msTime = timeGetTime()
						#endif
						if msTime-lastMmplayTime >= 60 {  ; mmplay:最低60ms間隔を空ける
							lastDrawIndex_forMM = cnt
							if splitChars(cnt)!=" " && splitChars(cnt)!=" " : mmplay mmIndex : lastMmplayTime = msTime
						}
					}
				}
			}
		loop
	}
	return

//--------------------------------------
// システム変数・拡張命令
//--------------------------------------
// 拡張システム変数
#define global layemes_stat state@modlayemes
#define global layemes_cnt count@modlayemes

// フォント設定
#define global layemes_font(%1="",%2=-1,%3=-1,%4=-1) layemes_font@modlayemes %1,%2,%3,%4
#deffunc layemes_font@modlayemes str ___fontName, int ___fontSize, int ___fontStyle, int ___fontDecoSize, int ___mesStyle
	if lparam != objlayer_cmdinit : return
	if ___fontName != "" : nowFontName = ___fontName
	if ___fontSize != -1 : nowFontSize = ___fontSize
	if ___fontStyle != -1 : nowFontStyle = ___fontStyle
	if ___fontDecoSize != -1 : nowFontDecoSize = ___fontDecoSize
	FontName = nowFontName
	FontSize = nowFontSize
	FontStyle = nowFontStyle
	FontDecoSize = nowFontDecoSize
	return

// 各種設定
#define global layemes_settings(%1=0,%2=0,%3=0,%4=-1,%5=-1,%6=0) layemes_settings@modlayemes %1,%2,%3,%4,%5,%6
#deffunc layemes_settings@modlayemes int _option, int _charSpacing, int _lineSpacing, int _mmId, int _keys, int _fade
	if lparam != objlayer_cmdinit : return
	;;; 表示関係
	// 文章を描画し終わった後に非表示にしない
	if _option & 1 {
		Add_flagBits@_modlaybtn FLAGBT_OPTION_KEEP_VISIBLE@modlaybtn
	}else {
		Clear_flagBits@_modlaybtn FLAGBT_OPTION_KEEP_VISIBLE@modlaybtn
	}
	emesOption = _option
	charSpacing = _charSpacing
	lineSpacing = _lineSpacing
	if _mmId != -1 : mmIndex = _mmId
	if _keys != -1 : stkValue = _keys
	fadeFrame = _fade
	return

// layerbutton の各種表示フレーム数設定
#deffunc layemes_frames int _p5, int _p6, int _p7, int _p8, int _p9, int _p10
	if lparam != objlayer_cmdinit : return
	p5@_modlaybtn = _p5
	p6@_modlaybtn = _p6
	p7@_modlaybtn = _p7
	p8@_modlaybtn = _p8
	p9@_modlaybtn = _p9
	p10@_modlaybtn = _p10
	return

//--------------------------------------
// モジュール内で使用するローカル命令
//--------------------------------------
// 最後に描画した文字の後ろにカレントポジションを移動させる
#deffunc Set_pos_lastChar@modlayemes array splitChars, array splitChars_cmdIndex, array splitChars_cmd, array splitCharsLineNumY, array splitCharsMesxSum, array splitCharsMesx, array splitCharsMesy, array splitCharsMesyMax, array splitCharsStartFrame, array splitCharsDelay
	// このSet_posは文字が描画される前に呼び出される。残してあるlastDraw_cx(cy)より一文字多いターンかもしれないので確認。多ければ次の文字の分を考慮する。
	_lastDrawIndex=-1
	frm=0.0
	if state == 1 && startFrame != -1 {
		repeat , startIndex
			if cnt >= splitNum : break
			if splitCharsDelay(cnt)>=0 {
				frm += splitCharsDelay(cnt)
			}else {
				frm += 1.0/-splitCharsDelay(cnt)
			}
			if int(frm)+startFrame > iparam : break
			if splitChars(cnt) == "<p>" : break
			if splitChars(cnt) == "<d>" || splitChars(cnt) == "<w>" : break
			if lastDrawIndex < cnt {
				_lastDrawIndex = cnt
			}
		loop
	}
	if lastDrawIndex != -1 && _lastDrawIndex != -1 && lastDrawIndex < _lastDrawIndex && _lastDrawIndex < splitNum && ((_lastDrawIndex-lastDrawIndex)==1 || (charDelay<-1&&(_lastDrawIndex-lastDrawIndex)<=-charDelay)) {
		if splitCharsLineNumY(lastDrawIndex) == splitCharsLineNumY(_lastDrawIndex) {
			plusMesx=0
			repeat _lastDrawIndex-lastDrawIndex, lastDrawIndex+1
				if cnt >= splitNum : break
				if splitCharsMesx(cnt) > 0 : plusMesx += splitCharsMesx(cnt)
			loop
			if (lastDraw_cx+charSpacing + plusMesx) <= objlayer_size_x {
				pos objlayer_axis_x + lastDraw_cx+charSpacing + plusMesx, objlayer_axis_y + lastDraw_cy
			}else {
				if splitCharsMesyMax(_lastDrawIndex) {
					pos objlayer_axis_x + 0, objlayer_axis_y + lastDraw_cy+lineSpacing+splitCharsMesyMax(_lastDrawIndex)
				}else {
					pos objlayer_axis_x + lastDraw_cx, objlayer_axis_y + lastDraw_cy
				}
			}
		}else {
			if splitCharsMesyMax(_lastDrawIndex) {
				pos objlayer_axis_x + 0, objlayer_axis_y + lastDraw_cy+lineSpacing+splitCharsMesyMax(_lastDrawIndex)
			}else {
				pos objlayer_axis_x + lastDraw_cx, objlayer_axis_y + lastDraw_cy
			}
		}
	}else {
		_lastDrawIndex = -1
		pos objlayer_axis_x + lastDraw_cx, objlayer_axis_y + lastDraw_cy
	}
	if state == 0 || (lastDraw_cx == 0 && lastDraw_cy == 0) : pos -1, -1
	if _lastDrawIndex != -1 : return _lastDrawIndex
	return lastDrawIndex

// 一文字ずつに分けつつ、コメント部分もコマンドテキストとして配列に格納
#deffunc local split_char_emes str __str, array dst, array dst_cmdIndex, array dst_cmd
	_str = __str
	// 末尾の改行を削除
	repeat
		if strlen(_str)<2 : break
		if wpeek(_str, strlen(_str)-2) != 0x0a0d : break
		poke _str, strlen(_str)-2, 0
	loop
	if strlen(_str) > 0 : if strmid(_str,-1,1) != "$" : _str += "\n^"
    sdim dst, 32
	dst_num = 0
	sdim dst_cmd, 512
	dim dst_cmdIndex
	dst_cmd_num = 0
    len = strlen(_str)
    i = 0 : maeKaigyo = 1 : comment = 0 : commentStr = ""
    repeat
        if i >= len : break
        c = peek(_str, i)
		if hspstat & $20000 {  ; utf8
			if c < $80 {
				bytes = 1
			}else : if c < $E0 {
				bytes = 2
			}else : if c < $F0 {
				bytes = 3
			}else : if c < $F8 {
				bytes = 4
			}else : if c < $FC {
				bytes = 5
			}else {
				bytes = 6
			}
		}else {  ; sjis
			if (c >= $81 && c <= $9F) || (c >= $E0 && c <= $FC) {
				bytes = 2
			} else {
				bytes = 1
			}
		}
        s = strmid(_str, i, bytes)
		if i+1 < len : if wpeek(_str,i) == 0x0a0d : kaigyo=1: bytes=2 : else : kaigyo=0  ; 改行
		if comment == 0 {
			if s == ";" {
				if maeKaigyo == 1 : comment=1: s=""  ; 行末までコメント
			}else: if s == "^" {  ; 行末に「^」は『ページ送り』
				s3 = strmid(_str, i, 3)
				if s3 == "^\n" : bytes=strlen(s3) : kaigyo=1
			}
			if i+1 < len : if wpeek(_str,i) == 0x2a2f : comment=2: bytes=2: s=""  ; コメント開始「/*」
		}
		if comment {
			// コメント
			if comment == 1 && kaigyo {  ; コメントタイプ「;」 : 改行まで来たら処理
				commentStr += ":"
				comment = 0
			}
			if comment == 2 {  ; コメントタイプ「/* ... */」 : 終了まで来たら処理
				if i+1 < len { if wpeek(_str,i) == 0x2f2a {
					commentStr += ":"
					comment = 0
					bytes = 2
				}}
			}
			if comment {
				commentStr += s
			}
		}else {
			// 文字記憶
			if s=="~" {
				dst(dst_num) = "<d>"
			}else: if s=="^" {
				if dst_num>0 : if dst(dst_num-1) == "<br>" : dst_num--  ; 一応、「^」ページ送り直前の改行は削除
				dst(dst_num) = "<p>"
			}else: if kaigyo {
				dst(dst_num) = "<br>"
			}else {
				dst(dst_num) = s
			}
			// コメントがあれば記憶
			if commentStr != "" {
				dst_cmd(dst_cmd_num) = commentStr
				dst_cmdIndex(dst_num) = dst_cmd_num
				dst_cmd_num++
				commentStr = ""
			}else {
				dst_cmdIndex(dst_num) = -1
			}
			dst_num++
		}
        i += bytes : maeKaigyo = kaigyo
    loop
	if dst_num <= 0 : return 0
	if dst(dst_num-1) == "<br>" : dst_num--
	if dst_num <= 0 : return 0
	if dst(dst_num-1) != "<p>" && dst(dst_num-1) != "$" {
		dst(dst_num) = "<p>"
		dst_cmdIndex(dst_num) = -1
		dst_num++
	}
	if dst(dst_num-1) == "$" : dst_num--
	return dst_num

// テキストのコメント部分のコマンドを抽出実行
#deffunc local preExecHspEmesCommand  str __str, var fontName_, var fontSize_, var fontStyle_, var fontDecoSize_, var fontColor_, var decoColor_, var mesStyle_, var delay_
	execHspEmesCommand  __str, fontName_, fontSize_, fontStyle_, fontDecoSize_, fontColor_, decoColor_, mesStyle_, delay_, 1
	return
#deffunc local execHspEmesCommand str __str, var fontName_, var fontSize_, var fontStyle_, var fontDecoSize_, var fontColor_, var decoColor_, var mesStyle_, var delay_, int pre
	_str = __str
	fontName__ = fontName_
	fontSize__ = fontSize_
	fontStyle__ = fontStyle_
	fontDecoSize__ = fontDecoSize_
	fontColor__ = fontColor_
	decoColor__ = decoColor_
	mesStyle__ = mesStyle_
	delay__ = delay_
	_isChangedFont = 0
	_isChangedFontOrColor = 0
	split _str, ":", cmds : cmdNum = stat
	repeat cmdNum
		split cmds(cnt), ",", prms : prmNum = stat
		cmd = strtrim(prms(0), 0, ' ')
		split cmd, " ", cmd, prm : prms(0) = prm
		switch getpath(cmd,16)
		case "font"
			_isChanged = 0
			if prmNum >= 1 : _fontName = strtrim(prms(0),0,' ') : _fontName = strtrim(_fontName,0,'"') : if _fontName != "" : if _fontName != fontName__ : _isChanged=1 : fontName__ = _fontName : if pre==0 : fontName_ = _fontName
			if prmNum >= 2 : __fontSize = strtrim(prms(1),0,' ') : if __fontSize != "" : _fontSize = int(__fontSize) : if _fontSize != fontSize__ : _isChanged=1 : fontSize__ = _fontSize : if pre==0 : fontSize_ = _fontSize
			if prmNum >= 3 : __fontStyle = strtrim(prms(2),0,' ') : if __fontStyle != "" : _fontStyle = int(__fontStyle) : if _fontStyle != fontStyle__ : _isChanged=1 : fontStyle__ = _fontStyle : if pre==0 : fontStyle_ = _fontStyle
			if prmNum >= 4 : __fontDecoSize = strtrim(prms(3),0,' ') : if __fontDecoSize != "" : _fontDecoSize = int(__fontDecoSize) : if _fontDecoSize != fontDecoSize__ : _isChanged=1 : fontDecoSize__ = _fontDecoSize : if pre==0 : fontDecoSize_ = _fontDecoSize
			if _isChanged {
				if pre == 0 : font_ fontName_, fontSize_, fontStyle_, fontDecoSize_
				_isChangedFont = 1
			}
			swbreak
		case "rgbcolor"
			rgb = 0
			if prmNum >= 1 {
				rgbstr = strtrim(prms(0),0,' ')
				if strmid(rgbstr,0,2) == "0x" {
					rgb = int("$"+strmid(rgbstr,2,32))
				}else : if strmid(rgbstr,0,1) == "#" {
					rgb = int("$"+strmid(rgbstr,1,32))
				}else{
					rgb = int(rgbstr)
				}
			}
			if fontColor__ != rgb {
				fontColor__ = rgb
				if pre == 0 : fontColor_ = rgb : rgbcolor fontColor_
				_isChangedFontOrColor = 2
			}
			swbreak
		case "color"
			r=0 : g=0 : b=0
			if prmNum >= 1 : r = int(strtrim(prms(0),0,' ')) & $FF
			if prmNum >= 2 : g = int(strtrim(prms(1),0,' ')) & $FF
			if prmNum >= 3 : b = int(strtrim(prms(2),0,' ')) & $FF
			rgb = (r<<16) | (g<<8) | b
			if fontColor__ != rgb {
				fontColor__ = rgb
				if pre == 0 : fontColor_ = rgb : rgbcolor fontColor_
				_isChangedFontOrColor = 2
			}
			swbreak
		case "objcolor"
			r=0 : g=0 : b=0
			if prmNum >= 1 : r = int(strtrim(prms(0),0,' ')) & $FF
			if prmNum >= 2 : g = int(strtrim(prms(1),0,' ')) & $FF
			if prmNum >= 3 : b = int(strtrim(prms(2),0,' ')) & $FF
			rgb = (r<<16) | (g<<8) | b
			if decoColor__ != rgb {
				decoColor__ = rgb
				if pre == 0 : decoColor_ = rgb : objcolor (decoColor_>>16)&$FF, (decoColor_>>8)&$FF, (decoColor_)&$FF
				_isChangedFontOrColor = 2
			}
			swbreak
		case "mes"
			if prmNum >= 2 {
				_style = int(strtrim(prms(1),0,' '))
				if _style != mesStyle__ {
					mesStyle__ = _style
					if pre == 0 : mesStyle_ = _style
					_isChangedFontOrColor = 2
				}
			}
			swbreak
		case "text"
			if prmNum >= 1 {
				_delay = int(strtrim(prms(0),0,' '))
				if _delay != delay__ {
					delay__ = _delay : delay_ = _delay
				}
			}
			swbreak
		swend
	loop
	return _isChangedFont + _isChangedFontOrColor

#deffunc local font_ str __fontname, int __p1, int __p2, int __p3
	#ifdef _HSP3DISH
		dupptr bm, objinfo_bmscr(0), 178*4
		dupptr fname, objinfo_bmscr(0)+142*4, 64, 2
		if __p1 != bm(158) || __p2 != bm(159) || __p3 != bm(177) || __fontname != fname {
			font __fontname, __p1, __p2, __p3
		}
	#else
		font __fontname, __p1, __p2, __p3
	#endif
	return
#global
#endif