メイン | こんにゃく »

2008年04月06日

●かにしの拡張スプライト

脈絡がありませんがかにしのforONSで拡張スプライトに対応しました。
背景の表示倍率が変わります。200801xx以降のONScripterで動作させてください。
スクリプトサイズの削減等も行っているため、以前のセーブデータは使用出来ません(クリアフラグは持ち越し)。

PDAとはあまり関係ないのです。だって『栖香ちゃん』がが


4/8)
ということで保守期間な今日この頃。プレイ中のものを姑息に修正していきます。
今更すぎますが本校系を終えました。リーダさんルート(きっと)やとても良し。健速乙

2007年07月15日

●応用編 で かにしの編  その6 スクリプトサイズ削減

すっかりさぼってしまっていた今日この頃
ONSforPSPでのメモリ不足に泣くのは何処様も同じのようです
特にかにしのは、某エロゲ研究室様(デコードでお世話になりました)調べでは
純粋な表示テキストだけで3.85MB。
1 『僕と僕らの夏完全版』 2 『Fate/stay night』 3 『CLANNAD』
に次ぐ4番目のシナリオサイズを誇っているようです。
(もちろん調査されていないゲームの中に更に大きなものもあるでしょう)
Perlでだらだらっと出力するのが好きだったのですが、さすがに10MBを越えてしまってはどうにも…

というわけで、無駄な部分を"defsub"命令を使ってサイズ節約してみます。
極力変数を使わずに、長いスクリプトをそのまま吐いているあたりがターゲットです。
以前記事にした名前表示のところが一番削減できそうですね。

	}elsif ( $line =~ /^%00%42(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00%00(.*?)%00(.*?)%00/ ){
		$name = $1;
		$dec = $2;
		$name =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$dec =~ s/\{(.*?):(.*?)\}/\($1\/$2\)/gi;
		$dec =~ s/\\n/\n/gi;
		$nalocate = 220 - (length($name))*6;
		print OUT "erasetextwindow 0\n";
		print OUT "lsp 0,\":s/24,24,2;#FFFFFF$name\",$nalocate,431\n";
		print OUT "lsp 1,\"image/nmbase.jpg\",50,424\n";
		print OUT "print 1\n";
		print OUT "$dec\\\n";
		print OUT "csp 0:csp 1:print 1:erasetextwindow 1:dwavestop 0\n";

というPerlスクリプトで

erasetextwindow 0
lsp 0,":s/24,24,2;#FFFFFF少女",196,431
lsp 1,"image/nmbase.jpg",50,424
print 1
「台詞」\
csp 0:csp 1:print 1:erasetextwindow 1:dwavestop 0

こんなNスクのスクリプトを吐いています。
ここで場面によって変化するのは「名前」「名前の表示座標」「台詞」だけで、他は毎回同じです。
ノベルゲームの常として、会話が非常に多いので総計でかなりの容量を使ってしまっています。
そのため必要最低限の引数だけとって、あとは"defsub"でユーザー定義命令にしてしまいましょう。
0.txtに

*define
(略)
defsub name
defsub nend

game
*name getparam $1,%1 ;名前と座標を受け取ります erasetextwindow 0 ;ここからは今まで1.txtに吐いていた部分 lsp 0,":s/24,24,2;#FFFFFF$1",%1,431 lsp 1,"image/nmbase.jpg",50,424 print 1 return ;ユーザー定義命令終了
*nend csp 0:csp 1:print 1:erasetextwindow 1:dwavestop 0 ;ここも長いので4文字にまとめてみた return

これでシナリオ中、名前と座標の引数を自作した"name"命令に渡してやることで
最初の長ったらしいスクリプトと同様の動作をするようになりました。
Perlの方はこんな感じ

	}elsif ( $line =~ /^%00%42(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00%00(.*?)%00(.*?)%00/ ){
		$name = $1;
		$dec = $2;
		$name =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$dec =~ s/\{(.*?):(.*?)\}/\($1\/$2\)/gi;
		$dec =~ s/\\n/\n/gi;
		$nalocate = 220 - (length($name))*6;
		;#print OUT "erasetextwindow 0\n";
		;#print OUT "lsp 0,\":s/24,24,2;#FFFFFF$name\",$nalocate,431\n";
		;#print OUT "lsp 1,\"image/nmbase.jpg\",50,424\n";
		;#print OUT "print 1\n";
		print OUT "name \"$name\",$nalocate\n";
		print OUT "$dec\\\n";
		;#print OUT "csp 0:csp 1:print 1:erasetextwindow 1:dwavestop 0\n";
		print OUT "nend\n";

name "少女",196
「台詞」\
nend

となります。うん、すっきり
変更した結果、全体のスクリプトサイズが7.5MB、分割したものは3MB・4MB程度になりました。
まだまだサイズは大きいですが、多少なりとも余裕ができたんじゃないでしょーか
今後も過去のものを含めてちまちま削っていければと思います。

2007年06月30日

●応用編 で かにしの編  その5 スプライト移動

ちょっと落ち着いたので、一応「応用編」です。
サンプルにすることでかにしの編も兼ねているというあたり、深い意味はなさそうです

前置きとして、Nスクにはスプライトを移動する命令が二つあります
"msp"と"amsp"、前者が相対的な増分を取るのに対して、後者は絶対位置での移動指定。
for文で"msp"を使うのが割と楽なのですが、そのままだと移動速度が環境に依存してしまいます。
PCではシュパーと移動しても、遅いマシン、特にPSPだとし、ゆ、う、ぅ、ぱ、ぁ、ぁというように…

そこでタイマーと組み合わせて移動量を調整することで、ほぼ同じ時間で移動させてみます。
原案はNスクスレその8>450です。感謝

とりあえずPerlでの移植は無視して、Nスクでどうすればいいか

lsp 6,"image/G1_AA01S.jpg",800,-40
saveoff
resettimer				#タイマー作動
for %1=1 to 999999			#ひたすら繰り返します
gettimer %2				#経過した時間を取得
if %2>=500 break			#完了時間を超えてたら終了
mov ?1[0],800+(591-(800))*%2/500	#?は配列。x座標を計算してます。
mov ?2[0],-40+(-40-(-40))*%2/500	#y座標(透過度も同じように求められます)
amsp 6,?1[0],?2[0],255			#求めた現在あるべき座標に移動
print 1					#表示
next					#ふりだしに戻る
amsp 6,591,-40,255			#最後に終点で表示
print 1
saveon

このように 始点+(終点-始点)×経過時間÷完了時間 という計算式を立てます。
現時点での絶対位置を求め、そこにスプライトを移動。
あとはタイマーが完了時間を越えるまで、ひたすら上記の処理をぶんまわしてやればおk
そんなに難しくないですね

次に他のスクリプトからの機械的変換を試みます
吉里吉里はデフォルトの"move"タグが都合よく終点と時間を指定しているので、
単純にマッチさせてやればその二つは問題ありません

@move layer=0 path=(-150,0,255) time=2000
↓
$line =~ /^@move layer=(\d*) path=\((.\d*),(.\d*),(\d*)\) time=(\d*)/ ;

少しめんどくさいのが始点の取得です。
Nスクではスプライトの表示座標を得る命令がないので、表示する度にPerlの変数に
入れておくのがいいでしょう。

例:かにしのでの座標管理

;#スプライト表示(始点取得) elsif ( $line =~ /^%00%48%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])(?:%00){5}%[0-9A-Fa-f][0-9A-Fa-f](.*?)%00/ ){ $num = 6 - hex($1); #スプライト番号(Nスクは若い方が上になります) if ( substr($3,0,1) eq "f" ){ #後ろ1バイトが"F"で始まる場合 $left[$num] = hex($2) - (( 256 - hex($3)) * 256); #こういう式のようです }else{ $left[$num] = hex("$3$2"); #x座標。スプライト番号で配列へ } if ( substr($5,0,1) eq "f" ){ $top[$num] = hex($4) - (( 256 - hex($5)) * 256); #同様にy座標 }else{ $top[$num] = hex("$5$4"); } $dec = $6; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; print OUT "lsp $num,\"image/$dec.jpg\",$left[$num],$top[$num]\n"; }
;#移動時の終点取得 elsif ( $line =~ /^%00%4b%([0-A-Fa-f][0-9A-Fa-f])%([0-A-Fa-f][0-9A-Fa-f])%([0-A-Fa-f][0-9A-Fa-f])%([0-A-Fa-f][0-9A-Fa-f])%([0-A-Fa-f][0-9A-Fa-f])%([0-A-Fa-f][0-9A-Fa-f])%([0-A-Fa-f][0-9A-Fa-f])/ ){ if ( $moveon[$num] == 1 ){ $num = 7 - hex($1); #スプライト番号。上とは一つずれてます $mnum[$mn] = $num; #以下、移動する個数"$mn"でそれぞれの値を配列に if ( substr($3,0,1) eq "f" ){ $endleft[$mn] = $left[$num] + ( hex($2) - (( 256 - hex($3)) * 256) ); #データは増分なので、始点+増分で終点を求めます }else{ $endleft[$mn] = $left[$num] + hex("$3$2"); } if ( substr($5,0,1) eq "f" ){ $endtop[$mn] = $top[$num] + ( hex($4) - (( 256 - hex($5)) * 256)); # }else{ $endtop[$mn] = $top[$num] + hex("$5$4"); } $movetime = hex("$7$6"); $mn++; #移動する個数チェック $moveon[$num] = 0; }else{ $moveon[$num] = 1; #何故か同じ移動命令が二回続くので、一回目はスルー } }

上手いことデータをこねくり回して座標その他を取得出来たら、

}elsif ( $line =~ /^%00%4c%/ ){	#00 4b で記述された移動命令を実行します
	&move();
	$mn = 0;	#移動フラグ初期化
}



sub move{ print OUT "saveoff\nresettimer\n"; print OUT "for %1=1 to 999999\n"; print OUT "gettimer %2\n"; for ( $i = 0 ; $i < $mn ; $i++ ){ $num = $mnum[$i]; print OUT "mov \?1\[$i\],$left[$num]+($endleft[$i]-($left[$num]))*%2/$movetime\n"; print OUT "mov \?2\[$i\],$top[$num]+($endtop[$i]-($top[$num]))*%2/$movetime\n"; print OUT "amsp $num,\?1\[$i\],\?2\[$i\],255\n"; } print OUT "print 1\n"; print OUT "if %2>=$movetime break\nnext\n"; for ( $i = 0 ; $i < $mn ; $i++ ){ $num = $mnum[$i]; print OUT "amsp $num,$endleft[$i],$endtop[$i],255\n"; $left[$num] = $endleft[$i]; #最後に、移動の終点を次回の始点として使えるようにします $top[$num] = $endtop[$i]; } print OUT "print 1\nsaveon\n";saveon }

と処理。(いつかスクリプトに※入れます)
サブルーチンに一々引数を渡すのがめんどくさいので、座標類はグローバル変数だったりします。
分けた意味ナス
ちなみに途中にあるfor文で、同時に移動するスプライトの数だけ計算→移動を繰り返します
理論上は何個でも動かせるとは思いますが、サンプルに使ったかにしのでは
立ち絵4つが同時に動くのが最大だったので未検証です。というかそれも体験版だけだったし…!

追記)
よく考えると、わざわざ増分から終点求める必要はないですね
始点+増分×経過時間÷完了時間 で済む話でした。
吉里吉里の場合は値が終点なので上記のようにしたのか。
ちなみに吉里吉里はよーいドンで動き出さないので、複数動かすための判定が難しいかも
breakのポイント変更。行き過ぎちゃってましたね

2007年06月24日

●かにしの編 その4 トランジションと名前表示

トランジション(背景画像切り替え)に白黒のマスク画像を使ったエフェクトを
かけるゲームが一般的です。
幸いにしてNスクにもマスクトランジションがあるので、移植の際に大助かり。
凝った記述をしなくても、 print 命令にマスク画像を渡してあげるだけで原作通りの効果が出せます。
かにしのにはなんと77枚ものトランジション用マスク画像が…

	}elsif ( $line =~ /^%00%54(.*?)%00/ ){
		$efmsk = $1;
		$efmsk =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;

でマスク画像ファイル名を変数(非ローカル)に渡して
}elsif ( $line =~ /^%00%4a%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])/ ){ $time = hex("$3$2"); if ( $time == 0 ) { print OUT "print 1\n"; }elsif ( $1 eq "2a") { print OUT "print 18,$time,\":c;image/$efmsk.jpg\"\n"; }elsif ( $1 eq "1d" ){ print OUT "print 14,$time\n"; }else{ print OUT "print 10,$time\n"; } }

とマスクを使うかどうかの判別をして、トランジションにかかる時間とともに書き出します。
ちなみに "4a $1" の$1でマスクトランジション以外にも色々エフェクトを指定しているようです。
"1d"だと上にスクロール?なので "print 14,$time"
これはNスクのエフェクト表と照らし合わせたり自作して当てはめます。
さて、ノイズエフェクトとかラスタースクロールはどうしよう、お兄ちゃん…

ということでシステム面に踏み込めない(私の)なんちゃって移植より、栖香ちゃんに期待だ!


お次は名前表示です。
"nmbase.jpg"が名前欄の画像なので、これと文字スプライトを合わせてテキストウインドウに重ねます。

	}elsif ( $line =~ /^%00%42(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00%00(.*?)%00(.*?)%00/ ){
		$name = $1;
		$dec = $2;
		$name =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$dec =~ s/\{(.*?):(.*?)\}/\($1\/$2\)/gi;
		$dec =~ s/\\n/\n/gi;
		$nalocate = 220 - (length($name))*6;
		print OUT "erasetextwindow 0\n";
		print OUT "lsp 0,\":s/24,24,2;#FFFFFF$name\",$nalocate,431\n";
		print OUT "lsp 1,\"image/nmbase.jpg\",50,424\n";
		print OUT "print 1\n";
		print OUT "$dec\\\n";
		print OUT "csp 0:csp 1:print 1:erasetextwindow 1\n";
	}

細かい工夫として文字数によるx座標調整と、表示・非表示の際に
テキストウインドウが消えないようにしています。
もっともここでの苦労は、手探りで表示座標を決めた点が主です。何この半端な数字

ちなみにONSは"windowchip"命令に対応していないのでメニューを出す時などに
名前欄だけ残ってしまうのが難点です。
あと、画像の周りのゴミを手動で消してやると綺麗かな?

これで何とか最低限の見栄えは整ったので、暫定公開へ。
でもReadmeで手順書くのが辛いです…orz

2007年06月23日

●かにしの編 その3 ラベルとフラグと選択肢

ようやっとほぼ読み終えてフラグ実装。
"<="なのか"<"なのか、はたまた">"なのか微妙なところもありますが、
テストプレイしながら直していこうかと。

とりあえず通常のフラグは"flag_xx"、グローバルは"gflag_xx"と置換しました。
1.txtの作成が終わったら、*define節用にシナリオからフラグ(変数)を拾います

open (IN, "1.txt");
open (OUT,">num.txt");
$gloval = 201;
$user = 11;
%flag;
while ( $line = <IN> ){
	if ( $line =~ /\%(g[a-zA-Z_0-9]*)/ ){
		if (( $flag{$1} != 1 ) && ( $1 ne "" )){
			print OUT "numalias $1,$gloval\n";
			$gloval++;
			$flag{$1} = 1;
		}

}elsif( $line =~ /\%([a-zA-z][a-zA-Z_0-9]*)/ ){ if (( $flag{$1} != 1 ) && ( $1 ne "" )){ print OUT "numalias $1,$user\n"; $user++; $flag{$1} = 1; } } } close IN; close OUT;

初出の変数を拾って、通常のものは"11"から、グローバルは"201"から numalias で定義

numalias gflag_c6,201
numalias gflag_f0,202
numalias flag_10,11
numalias flag_0f,12
numalias flag_05,13
numalias flag_11,14
numalias flag_06,15
numalias flag_07,16
numalias flag_01,17
numalias flag_03,18
numalias flag_08,19
numalias flag_09,20
numalias flag_0a,21
numalias gflag_f8,203
numalias flag_12,22
numalias flag_02,23
numalias gflag_f6,204
numalias gflag_f2,205
numalias gflag_f4,206
numalias gflag_f5,207
numalias gflag_f3,208
numalias flag_04,24
numalias gflag_f7,209

これを *define節に貼り付けてやれば完了です。

選択肢は

elsif ( $line =~ /^%00%02%02%00(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}(.*?)%00(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%07(.*?)%00(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}(.*?)%00(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%07(.*?)%00/ ){
		$sel1 = $1;
		$goto1 = $2;
		$sel2 = $3;
		$goto2 = $4;
		$sel1 =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$sel2 =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$goto1 =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		$goto2 =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		print OUT "select \"$sel1\",\*$goto1,\"$sel2\",\*$goto2\n";
	}

こんな感じ。変数の使い方が汚いのはご勘弁。
今はNスクデフォルトの "select" を使ってますが、車輪の国などのように
選択肢ウインドウ+文字スプライトのボタン化をすると原物に近づきます。
でも、車輪は単純な "select" じゃ実装出来なかったんですが、これは別に支障ないからなぁ…

ラベル、これはファイル名(拡張子なし)そのままでいいので楽ちんです

と、いうことで曲がりなりにも通しプレイ可能な状態となりました。
適当に暫定公開して、今後は随時演出強化の方向で行ってみたいと思います。
でもONSじゃ拡大・縮小は無理っぽい。大声とかで文字を大きくする演出も当面難しそうです

6/25追記)
>拡縮
と思ったら、ONSでも"drawbg2"が使える模様。Yu--Sさま感謝
"lsp2"が未対応だから、てっきりこちらもアウトかと…
かにしのタスクリストに追加です。不具合が治れば

2007年06月17日

●PerlでONS -かにしの編 その2 ~Nスクへ置換~

基本編~シナリオ読込~を流用して、かにしののシナリオを読み込みました。
うん、”ました。”で済ませよう
手順としては整形後にデコードせず、一度疑似バイナリダンプしたものを読み込んでいますが、
最終的には直接変換するつもり

あとは一行ずつNスクのコマンドに変換していきます。
ぐちゃぐちゃですが、前回の推測メモと合わせると何をやっているのかおぼろげに?

foreach $file (@file){
	$fn = $file;
	$fn =~ s/.txt//;
	open (IN, "./rio_out/$file");
	binmode IN;
	binmode OUT;
	$/ = "\x0D\x0A";
	while ( $line = <IN> ){
		&convert($line);
	}
	close IN;
}
close OUT;


sub convert{ $line = $_[0]; $line =~ s/%00%86%e6//gi ;#ゴミ?何か意味があるかも $line =~ s/\x0D\x0A//i;
if ( $line =~ /^%21(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%0a(.*)%00/ ){ ;#フェードインにも対応しないと… $dec = $1; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; print OUT "bgm \"bgm/$dec.ogg\"\n";
}elsif ( $line =~ /^%22(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%00/ ){ ;#フェードアウトry print OUT "stop\n";
}elsif ( $line =~ /^%23(?:%[0-9A-Fa-f][0-9A-Fa-f]){6}%00(.*)%00/ ){ $dec = $1; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; print OUT "dwavestop 0:dwave 0,\"voice/$dec.ogg\"\n";
}elsif ( $line =~ /^%25%([0-9A-Fa-f][0-9A-Fa-f])(?:%[0-9A-Fa-f][0-9A-Fa-f]){7}%00(.*)%00/ ){ ;#ループと非ループを判別したい $chn = hex($1); $dec = $2; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; print OUT "dwave $chn,\"se/$dec\"\n";
}elsif ( $line =~ /^%26%([0-9A-Fa-f][0-9A-Fa-f])%00/ ){ $chn = hex($1); if ( $chn == 255 ){ print OUT "dwavestop 0:dwavestop 1:dwavestop 2:dwavestop 3:dwavestop 4\n"; }else{ print OUT "dwavestop $chn\n"; }
}elsif ( $line=~ /^%29%[0-9A-Fa-f][0-9A-Fa-f]%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%00/ ){ $wt = hex("$2$1"); print OUT "wait $wt\n";
}elsif ( $line=~ /^%30%[0-9A-Fa-f][0-9A-Fa-f]%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%00/ ){ ;#この二つ、適当にウェイトにしてます。後で原物と比べないと $wt = hex("$2$1"); print OUT "wait $wt\n";
}elsif ( $line =~ /^%41(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00(.*)%00/ ){ $dec = $1; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; $dec =~ s/\\n/\n/gi; $dec =~ s/\{(.*?):(.*?)\}/\($1\/$2\)/gi; print OUT "$dec\\\n";
}elsif ( $line =~ /^%42(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00%00(.*?)%00(.*)%00/ ){ ;#名前は文字スプライトで対応予定 $name = $1; $dec = $2; $name =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; $dec =~ s/\{(.*?):(.*?)\}/\($1\/$2\)/gi; $dec =~ s/\\n/\n/gi; print OUT "$name\n$dec\\\n";
}elsif ( $line =~ /^%46(?:%00){9}(.*?)%00/ ){ $dec = $1; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; print OUT "bg \"image/$dec.jpg\",0\n";
}elsif ( $line =~ /^%48%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])(?:%00){5}%[0-9A-Fa-f][0-9A-Fa-f](.*?)%00/ ){ $num = 6 - hex($1); $left = hex("$3$2"); $top = hex($4) - hex($5); $dec = $6; $dec =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg; print OUT "lsp $num,\"image/$dec.jpg\",$left,$top\n";
}elsif ( $line =~ /^%49%([0-9A-Fa-f][0-9A-Fa-f])%00/ ){ $num = 6 - hex($1); print OUT "csp $num\n";
}elsif ( $line =~ /^%4a%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])%([0-9A-Fa-f][0-9A-Fa-f])/ ){ ;#今のところ各エフェクトを全て無視しています $time = hex("$3$2"); if ( $time == 0 ){ print OUT "print 1\n;" }else{ print OUT "print 10,$time\n"; } } }


という感じで、とりあえず絵と音と文章が出るようにはなりました。
が、※にもあるように懸案事項が山積みです。
ちなみに画像の変換がかなりめんどい…orz

2007年06月15日

●PerlでONS -かにしの編 その1 ~テキスト整形~

前回でとりあえず日本語に復号はしましたが、テキストとファイル名以外の箇所は
まともに読めません。これは制御コードなので暗号とかそういう以前の問題だそうです。

しょうがないので、プレイしながら地道にバイナリエディタで付き合わせてみる
以下解析推測メモ。不完全且つ誤り多し。随時更新

00 07 [file]	:シナリオジャンプ
00 21 0d xx xx 0A	:BGM -番号,時間
00 22 0d xx xx 00	:BGMストップ -番号,時間
00 23 00 	:ボイス
00 25 0d xx 00	:SE -番号
00 26 0d 00	:SEストップ -番号
00 29 00 xx xx 00	:ウェイト? -時間?
00 41 xx xx 00	:テキスト -通番
00 42 xx xx 00	:テキスト(名前有り) -通番
00 46 00 	:背景
00 48 0d xx xx yy ff 00 :画像読み込み -番号,x座標,y座標(-255?)
00 49 0d 00	:画像消去
00 4a xx yy yy 	:描画 -エフェクト[19 通常,2A マスク,1A ?,1D 上スク],時間
00 4b 0d xx xx yy ff zz zz 00	:画像移動 -番号,x値,y値(-255?),時間
00 4d 01	:振動
00 54 [file]	:マスク読み込み

これがある程度まとまったら、それぞれのところで改行を入れて整形します。
勿論、オリジナルに忠実なものではなく、あくまで私が勝手に処理しやすいよーに

(前略)
	@decode = split( /:/,&plast($char1));
	foreach $decode(@decode){
		$decode =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
		print OUT "\x0D\x0A$decode";
	}
(後略)


sub plast{ $_[0] =~ s/(%00%21(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%0a)/:$1/gi; $_[0] =~ s/(%00%22(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%00)/:$1/gi; $_[0] =~ s/(%00%23%00)/:$1/gi; $_[0] =~ s/(%00%25(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00)/:$1/gi; $_[0] =~ s/(%00%26(?:%[0-9A-Fa-f][0-9A-Fa-f]){1}%00)/:$1/gi; $_[0] =~ s/(%00%29(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%00)/:$1/gi; $_[0] =~ s/(%00%41(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00)/:$1/gi; $_[0] =~ s/(%00%42(?:%[0-9A-Fa-f][0-9A-Fa-f]){2}%00)/:$1/gi; $_[0] =~ s/(%00%46%00)/:$1/gi; $_[0] =~ s/(%00%48(?:%[0-9A-Fa-f][0-9A-Fa-f]){5}%00)/:$1/gi; $_[0] =~ s/(%00%49(?:%[0-9A-Fa-f][0-9A-Fa-f]){1}%00)/:$1/gi; $_[0] =~ s/(%00%4a(?:%[0-9A-Fa-f][0-9A-Fa-f]){3}%00)/:$1/gi; $_[0] =~ s/(%00%4b(?:%[0-9A-Fa-f][0-9A-Fa-f]){7}%00)/:$1/gi; $_[0] =~ s/(%00%4c%00)/:$1/gi; $_[0] =~ s/(%00%4d%01)/:$1/gi; $_[0] =~ s/(%00%54%45%46)/:$1/gi; return $_[0];

}

2007年06月14日

●PerlでONS -かにしの編 その0 ~見まねデコード~

基本編と分けてみました。
どう考えても参考にならない気がするし…最初は吉里吉里とかにすべきだったなぁ

ということで改めてかにしの編その0?

『遥かに仰ぎ、麗しの(体験版)(製品版)』(PULL TOP様)を使わせていただきます。
最終的にはWill系列がある程度動けばいいなぁ…とは思いますが、まあいつものごとく。
さて、アーカイブは色々ばらせますが、シナリオファイルは暗号化されていました。
Perlで日本語(shift-jis)を読める様にしても、そもそも日本語じゃないという罠。
幸い、某所でメッセージローダが見つかったのでこちら様のソースを眺めてみると
シナリオファイルは1byteごとに

tf=(tf%4)*0x40 + tf/4;//暗号解除

とされているようです。なので

@file = ("AL_0101.wsc","AL_0102.wsc");#とりあえず2ファイルだけ
foreach $file(@file){
	open (IN, "$file");
	open (OUT, ">$file\_out.txt");
	binmode IN;
	binmode OUT;
	@line = <IN>;
	my $char1 ="";
	foreach $line(@line){#
		my $bin = unpack("H*",$line);
		my $cha = length($bin)/2;
		for ($i = 0; $i < $cha; $i++){
			my $two = hex(substr($bin,$i*2,2));
			$two2 = ( $two % 4 ) * 64 + int($two / 4) ;#前出の式
			$two3 = sprintf("%x",$two2);
			if ( length($two3) == 1 ){
				$two3 = "0$two3";
			}
				$char1 .= "\%"."$two3";
		}
	}
	$char1 =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1)/eg;
	print OUT $char1;
	close(IN);
	close(OUT);
}

こんな感じにすると一応日本語の文章が出てきました。
解析の解が分かっているので当たり前と言えば当たり前なのですが、結構嬉しい。
ちなみに間違いなくPerlのスクリプトはもっと上手い書き方があるでしょう。

続く?

謝辞 メッセージローダ作者 nota様

10/11)
読み直してみると、謝辞が謝辞になっていませんでした…。
改めて、(勝手に)ソースの転用をさせて頂きましたメッセーローダ作者nota様に感謝致します。
かにしのに限らず、私の活動はほぼ全て他の方のデータ解析・抽出の成果に成り立っているので
全方向に足を向けて眠れません。ありがとうございます。