« 2007年05月 | メイン | 2007年07月 »

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日

●基本編 Nスクの設定とタイトルメニュー

シナリオは無事に変換できても、Nスクの設定(定義)を書かないとまともには動きません。
とはいえNスクの講座サイトは結構多く、私が語るだけの余地も知識もないので
私がONS移植に使いまわしている設定?の紹介のみ

;mode800
*define
nsa
menusetwindow 18,18,2,2,0,1,#BB8866
savenumber 20
rmenu "画像表示",windowerase ,"セーブ",save,"ロード",load,"選択肢まで進む",skip,"回想",lookback,"終了する",reset
effect 2,10,1000
effect 3,3,500
effect 4,10,300
defaultspeed 10,5,1
transmode alpha
effectcut
globalon

…変数定義を除けば define節は基本的にこれだけです
うーむ、これぞNスク!と言わんばかりの主張が込められた簡潔にして王道の以下略
よく考えたら Fate converter のものを流用させてもらっていたような気も…

ちなみにシステムカスタマイズをすればオリジナルゲームは勿論、ONS移植でも
忠実にこだわったセーブ画面やコンフィグ画面を作れるのですが、現状そこまでやれません orz

ただPSP用には、ムービー命令を defsub で自作する必要があります。
大本はすとーむ様のスクリプトなのですが、ほんの少しだけ弄らせて貰いました。

(*define)defsub movie
============================

*movie csp -1 getparam $2,%2 fileexist %3,$2:if %3=0 return saveoff split $2,".",$1:add $1,"-"
mov %1,0:mov %4,7 for %0=0 to 999999 step 100 itoa $0,%0:len %5,$0:mov %6,%4-%5 for %7=1 to %6:mov $0,"0"+$0:next fileexist %3,$1+$0+".jpg" if %3=1 add %1,100 if %3=0 mov %8,%0-100:sub %1,100:break next
for %0=%8 to 999999 itoa $0,%0:len %5,$0:mov %6,%4-%5 for %7=1 to %6:mov $0,"0"+$0:next fileexist %3,$1+$0+".jpg" if %3=1 inc %1 if %3=0 break next
mov %0,0 lr_trap *movie_end bgmonce $2 resettimer for %0=1 to 999999 gettimer %3 itoa $0,%1*%3/%2:len %5,$0:mov %6,%4-%5 for %7=1 to %6:mov $0,"0"+$0:next if %3>=%2 break bg $1+$0+".jpg",1 ;btndef $1+$0+".jpg":blt 0,0,800,600,0,0,800,600 next goto *movie_end2
*movie_end if %0>0 break:next *movie_end2 lr_trap off ;ofscpy bg black,1:stop saveon return

画像チェックの短縮と、saveon、saveoff の修正だけしています。

*あと、今までのONS移植は何となく解像度 640x480 でやっていましたが、
;mode800 でそのままやっても問題ない?ので、今後はそうしようかと。一々座標を4/5してたし

まあdefine節はこのぐらいとして、次はノベルゲームの命とも言えるテキストウィンドウ。
これはちょっぴり気を遣っています。
吉里吉里など表示座標が直接読み取れるものはいいのですが、そうでない場合は
試行錯誤してウィンドウ位置と文字位置を調整しなければなりません。
setwindow 命令は熟読ですね

例)かにしの
setwindow 74,480,28,3,26,26,1,2,10,1,1,":a;image/winbase0.jpg",0,414

で、最後にタイトルメニュー
これも吉里吉里なんかはボタンまで何とか再現していますが、
ボタンやクリッカブルマップを置換スクリプトで再現するのがめんどくさい時は超手抜きだったりします。
タイトルで使われている画像と音楽を持ってきて、左クリック→スタート 右クリック→ロード のみ!

一応サンプルとしては私の過去のブツでも見てください(ここでも手抜き


うーん、しかし基本編は薄いわ、かにしの編は一般性が無いわと…やっぱり講座じゃないですよ?

●かにしの編 その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月19日

●かにしの編 ラベルとフラグと選択肢、の前に

かにしの、エフェクトは今後ちまちまと追加修正していくとして、
現状でも単純に読み進める分には問題ない感じです。
このままラベルとフラグと選択肢を実装すればとりあえず通してプレイ可能なレベルに?

で、ちょっと先を覗いたところでは選択肢と飛び先ラベル自体は簡単に再現できそうです
けれどフラグ・変数処理の解析というか分析に少し手間取るかも

01 06 … が変数処理かなーとは思いますが、サンプルが少なくて何とも…
攻略サイト見ても、てっきりフラグとかなしなのかと早とちりしちゃったくらいです

2007年06月18日

●基本編 正規表現の初歩

タイトルも簡潔になって、ちょっと先走った感もある前エントリ
一行ずつ置換していくプロセスとゆーほどのものではない、の中身を簡単に書いてみます。
サンプルは例によって吉里吉里でも使おうかと

PerlをPerl-Practical Extraction and Report Language-実用データ取得作成言語 ただし後付
たらしめる正規表現による強力なパターンマッチ。(あと変数とかてきとーに書いても動くいい加減さ
このお陰で文字列=スクリプトを別の法則のスクリプトに変えること等が非常に楽です。
まあ私がやっているのは非常に初歩的なことなのですが、些少のお目汚しをば

$line =~ /hogehogehoge/;

"=~" マッチ演算子 を使って "//" で挟まれた文字列を比較・置換するのが基本です。
また、その際に文字列を "()" で囲むと、後方参照で文字列を取り出すことが出来ます。
例えば

@img layer=1 storage=ev_c_houduki_01 left=800 top=20
@img layer=2 storage=ev_c_eri left=-900 top=180

こんなスクリプトがあったとすると
if ( $line =~ /\@img/ ){ で文を判定。Nスクでいうスプライトかなーと当たりを付け

$line =~ /layer=(\d) storage=(\w*?) left=(\d*) top=(\d*)/;

とマッチさせると
それぞれ スプライト(レイヤ?)番号 $1 、ファイル名 $2、x座標 $3 、y座標 $4 に対応します。

ちなみに
"\w" はアルファベットと数字(use utf8; 等をすると漢字等の多バイト文字にもマッチするので注意)
"\d" は数字。また"*" は直前の文字が任意の回数続くことを意味します。
これらの正規表現は2ch専ブラなどでも使えるので、覚えておいて損はないでしょうか

閑話休題、上記で取り出した文字列を使ってNスクのコマンドを記述します。

print OUT "lsp $1,\"$2.jpg"\",$3,$4";文字列中の " の前には\を付けてエスケープします
↓すると、サンプルが
lsp 1,"ev_c_houduki_01.jpg",800,20


と変換されます。
色々ややこしい処理もありますが、
基本は全てこの応用です。
ということで次回応用編~スプライト移動~
仮定も未定!


ちなみにかにしのでの立ち絵・スプライト?処理は…

$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/ )

orz

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月16日

●PerlでONSへ変換しよう  基本編 ~シナリオ読込~

かにしのが少し特殊になりそうなので、無差別?に基本編

シーン毎にシナリオファイルが別れているものを結合してみます。
まずアレコレを使って /scenario フォルダ等にシナリオファイルを全て展開

open (OUT,">1.txt");
opendir (DIR,"./scenario");
@file1 = readdir(DIR);
closedir(DIR);
@file = grep(/\.ks/,@file1);#※吉里吉里の場合
foreach  $file(@file){
	open (IN,"./scenario/$file");
	print OUT <IN>
	close IN;
}
close OUT;

これで /scenario フォルダの ".ks"ファイルを結合しました。
あとはぼーっと上から下まで眺めて、どんな処理がされているのかひたすら確認
※吉里吉里なら独自マクロを記述したファイルを見た方が早いかも
大体つかめてきたら、上のスクリプト内 print OUT ; の代わりに、
一行ずつ読み込んでひたすら置換する処理を入れます

(前略)
open (OUT,">1.txt");
opendir (DIR,"./scenario");
@file1 = readdir(DIR);
closedir(DIR);
@file = grep(/\.ks/,@file1);#※吉里吉里の場合
foreach  $file(@file){
	open (IN,"./scenario/$file");
	while ( $line = <IN>){

if ( $line =~ /^@play storage=\"(\w*)\"/ ){;#   音楽をならしているのなら… print OUT "bgm \"bgm/$1.ogg\"\n";#   Nスクのbgm命令に
}elsif ( $line =~ /hogehoge/ ){ ~(中略)~ } } close IN; } close OUT;

こうやってひたすら (els)if 命令で置換置換置換置換…
元の処理をどうやってNスクで再現するかが勝負です
リファレンス等を熟読しましょう

とはいえONSで対応していない命令も結構ありますが…orz
もっというなら MSpDraw.dll が欲しい~

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様に感謝致します。
かにしのに限らず、私の活動はほぼ全て他の方のデータ解析・抽出の成果に成り立っているので
全方向に足を向けて眠れません。ありがとうございます。

≪ prev | 1 / 2 |