;--------------------------------------------------------------------------------------------------
; PutMsg ver.2
; カラーモード前提
; アトリビュートは正常にソートされている前提
; 次の行に影響が出ないようにきちんと後始末が行われている前提
;
; 同じ座標の色と装飾では色を優先する. 両方適用した文字列の終端で何の処置もしない場合、文字列後の 1 文字に装飾が残る.
; 行頭では『明示しない場合』%E8,%00(白字ノーマル）がデフォルトで指定される.
; ex) F418,F419=$00,$02 ここに "%48abc" を行頭から書くと x=0 から赤字ノーマルが適用され、x=1 から赤字点滅が適用される.
;
;bit7: 色 G
;bit6: 色 R
;bit5: 色 B
;      装飾指定のときアンダーライン
;bit4: 色指定のときセミグラフィック 装飾指定のときアッパーライン
;bit3: 1=色指定 0=装飾指定
;bit2: 装飾 リバース
;bit1: 装飾 ブリンク
;bit0: 装飾 シークレット
;
;d=y e=x
;hl=msg_src
;
;ld   hl,MSG_STR ;0 終端文字列の先頭
;ld   de,5*256+1 ;(1,5)から表示
;call PutMsg
;
;MSG_STR: db "%A8Hello, %04world!%00 %F8",$5A,0
;
;%xx で現在の座標からアトリビュート適用.
;%xx%yy のように連続して書くこと（=同じ座標から適用）が出来るが、仕様により装飾と色では色が優先される.
;%xx%FF と書くと装飾が優先されるが不具合が出る可能性あり.
;$F8 は特殊文字で何も書かずに右に移動する. アトリビュートだけ書きたいときなど.
PutMsg:
	push		ix
	push		bc
	push		de
	push		hl

	ld			a,d						;d=y
	add			a,a
	add			a,a
	add			a,a						;*8(0-192)
	ld			b,0
	ld			c,a
	ld			h,d
	ld			l,b
	srl			h
	rr			l						;y*128
	sbc			hl,bc
	ld			bc,TVRAM
	add			hl,bc					;hl = TVRAM + y * 120
	ld			b,0
	ld			c,e						;c=x
	pop			de						;de <- hl(msg_src)
	push		hl						;実 TVRAM へのアトリビュート書き戻しの為に push しておく

	call		Atrb_Unroll				;該当行のアトリビュートを展開. 裏レジスタを使うので退避不要.

	add			hl,bc

	ld			ix,TmpAtrb
	add			ix,bc
	ld			c,(ix+0)				;継続するアトリビュート
	ld			b,(ix+80)

	ex			de,hl					;de=TVRAM + y * 120 + x / hl=msg_src

.loop:
	ld			a,(hl)
	inc			hl
	or			a
	jr			z,.exit					;0=終端
	cp			"%"
	jr			z,.atr
	cp			$F8						;特別 $1C- は使用中なので使えない.
	jr			z,.skip2				;$F8=何も書かずにカーソルを右に. アトリビュートは適用する.

.skip:
	ld			(de),a					;1文字書き込み
.skip2:
	inc			de
	ld			(ix+0),c				;継続して適用するアトリビュート
	ld			(ix+80),b
	inc			ix

	jr			.loop
.atr:
	ld			a,(hl)
	inc			hl
	cp			"%"
	jr			z,.skip					;%% は "%"
	cp			"A"
	jr			nc,.atr2
	add			a,$37-$30				;"0"-"9" -> 0-9
.atr2:
	sub			$37						;"A"-"F" -> 10-15
	add			a,a
	add			a,a
	add			a,a
	add			a,a
	ld			(.atr4+1),a

	ld			a,(hl)
	inc			hl
	cp			"A"
	jr			nc,.atr3
	add			a,$37-$30
.atr3:
	sub			$37
.atr4:
	or			0						;ここ書き換え

	bit			3,a
	jr			nz,.color
	ld			c,a
	jr			.loop
.color:
	ld			b,a
	jr			.loop

.exit:									;hl=msg_src 終端は維持する
	exx
	pop			hl						;hl=実 TVRAM 先頭アドレス
	call		Atrb_Pack				;実 TVRAM にアトリビュートを書き戻す
	exx

	pop			de
	pop			bc
	pop			ix
	ret

;--------------------------------------------------------------------------------------------------
;TmpAtrb に展開する
;色,装飾の属性をまとめて 1byte 内におさめるには 9ビット必要なので 2byte/1桁 とし、80*2byte 使用する。
;例えばセミグラに限定して色だけにすればもっと簡潔かつ高速にできる。アンダー／アッパーラインなしなど応用は効く

;実アトリビュートを TmpAtrb に展開
;80 桁すべての色・属性を書き出す
Atrb_UnRoll:
	push		hl						;該当行の TVRAM 先頭アドレス
	exx
	pop			hl
	ld			bc,80
	add			hl,bc					;該当行の TVRAM アトリビュート先頭アドレス

	ld			de,$E800				;現在のアトリビュート

	ld			(hl),0					;最初のアトリビュートは x=0 を強制する
	call		.sub

	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub

	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	call		.sub
	set			7,b
	call		.sub					;b=80 強制. 80 以上は 80 になる.
	exx
	ret

.sub:
	ld			a,(hl)					;開始 x 座標
	inc			hl
	cp			80
	jr			nc,.next

	add			a,TmpAtrb & $FF
	ld			ixl,a
	adc			a,TmpAtrb >> 8
	sub			ixl
	ld			ixu,a					;ix = TmpAtrb + x

	bit			7,b
	jr			nz,.skip
	inc			hl
	ld			b,(hl)					;次の x 
	dec			hl
.skip:

	bit			3,(hl)
	jr			nz,.color
.soushoku:
	ld			e,(hl)					;bit5:アンダーライン bit4:アッパーライン bit3:0 bit2-0:装飾指定
	jr			.unroll
.color:
	ld			d,(hl)					;bit7-5:色指定 bit4:セミグラ bit3:1

.unroll:
	ld			a,b						;x<b までアトリビュート適用
	cp			80
	jr			c,.unroll2
	ld			b,80
.unroll2:
	ld			a,ixl
	sub			TmpAtrb & $FF
	neg
	add			a,b						;b=b-(ix-TmpAtrb)
	ld			b,a
	jr			nz,.loop
	inc 		b						;事故防止

.loop:
	ld			(ix+0),e				;装飾指定
	ld			(ix+80),d				;色指定
	inc			ix
	djnz		.loop

.next:
	inc			hl						;次のアトリビュート開始 x 
	ret


;--------------------------------------------------------------------------------------------------
;展開されたアトリビュートを 実 TVRAM に書き戻す
;hl=書き込み先 TVRAM アトリビュート先頭アドレス
Atrb_Pack:
	ld			bc,80
	add			hl,bc
	ld			a,l
	add			a,40
	ld			c,a

	ld			ix,TmpAtrb
	ld			b,0						;x座標
	ld			de,$FFFF				;現在適用中のアトリビュート 初回 x=0 に必ず適用されるように -1 にしておく
.loop:
;	ld			a,(ix+0)				;装飾指定
;	cp			e
;	jr			nz,.soushoku			;変化したところを調べる
;	ld			a,(ix+80)				;色指定
;	cp			d
;	jr			z,.next

	ld			a,(ix+80)				;色優先の場合
	cp			d
	jr			nz,.color
	ld			a,(ix+0)
	cp			e
	jr			z,.next
	jr			.soushoku

.color:
	ld			(hl),b					;開始 x 座標
	inc			hl

	ld			(hl),a
	ld			d,a						;現在のアトリビュートを更新
	inc			hl
	jr			.next

.soushoku:
	ld			(hl),b					;開始 x 座標
	inc			hl

	ld			(hl),a
	ld			e,a						;現在のアトリビュートを更新
	inc			hl

.next:
	ld			a,l
	cp			c
	ret			z						;アトリビュート領域が尽きたら打ち切り

	inc			ix						;TmpAtrb++
	inc			b						;x++
	ld			a,b
	cp			80
	jr			nz,.loop

.fill:									;以下のアトリビュート設定は表示に反映されない. 座標の自動ソートによる影響が出なければ適当でも良い.
	ld			(hl),80					;残りのアトリビュートは書きつぶしておく
	inc			hl
	ld			(hl),$E8				;色
	inc			hl

	ld			a,l
	cp			c
	ret			z

	ld			(hl),80					;残りのアトリビュートは書きつぶしておく
	inc			hl
	ld			(hl),0					;装飾
	inc			hl

	ld			a,l
	cp			c
	jr			nz,.fill
	ret

;x>79 のアトリビュートは反映されない。
;属性をリセットするためには最低でも x=79 で設定するしかないが、そうすると x=79 のリセット状態が可視化されてしまう.

TmpAtrb:
	ds			80*2
