九龍妖魔學園紀

キーワード
ベース
レジスタ
論理積、排他的論理和
テーブル
符号拡張


このソフトはシンボル残りのソフトでして普段は出来ないようなコードも作成可能です。
解析者に優しいソフトですので初心者の練習には最適ではないでしょうか?

内容
感情値変動すると指定値へ変更
プリクラなくてもバディ選択可能
アイテム全種x個
感情値表示


感情値変動すると指定値へ変更

ラベルの中で注目して欲しいものは主にこれらのものです。
St_get〜
St_set〜
コードを作り始めて少し経ってから気がつきましたが、getがロード、setがストアの処理のラベルです。
このラベルに続くものでかなりの数のコードが出来ます。例えば
St_SetEtcCharKanjo
これは見た目通りでキャラの感情値をストアしています。
ロードではなくストアを選んだ理由はロードだとその後の処理で変動した数値分加算や減算がされてしまう為。

00137a80 addiu  sp, sp, $ffc0             St_SetEtcCharKanjo(ラベル)
00137a84 sd   ra, $0030(sp)
00137a88 sq   s2, $0020(sp)
00137a8c sq   s1, $0010(sp)
00137a90 sq   s0, $0000(sp)
00137a94 daddu  s1, a1, zero
00137a98 daddu  s0, a2, zero
00137a9c andi  v1, a0, $ffff
00137aa0 andi  s2, v1, $7fff
00137aa4 slti  v1, s2, $001e
00137aa8 bne   v1, zero, $00137ac4
00137aac nop
00137ab0 lui   a0, $0049        a0=$00490000
00137ab4 addiu  a0, a0, $69e8      a0=$004969e8
00137ab8 addiu  a1, zero, $14ac     a1=$000014ac
00137abc jal   kwlnAssertFunc_     ▼$001b7310
00137ac0 nop
00137ac4 addiu  v1, zero, $001a     v1=$0000001a
00137ac8 bne   s2, v1, $00137ad4
00137acc nop
00137ad0 daddiu s2, zero, $0002     s2=$00000002
00137ad4 dsll32 v1, s0, 16
00137ad8 dsra32 v1, v1, 16
00137adc slti  v1, v1, $270f
00137ae0 bne   v1, zero, $00137aec          
00137ae4 nop
00137ae8 addiu  s0, zero, $270f     s0=$0000270f 
00137aec andi  a0, s2, $ffff
00137af0 sll   v1, a0, 1        v1=$00000004
00137af4 addu  v1, v1, a0        v1=$00000006
00137af8 sll   a0, v1, 2        a0=$00000018
00137afc lui   v1, $0077        v1=$00770000
00137b00 addiu  v1, v1, $6282      v1=$00776282
00137b04 addu  a0, v1, a0
00137b08 dsll32 v1, s1, 16
00137b0c dsra32 v1, v1, 16
00137b10 sll   v1, v1, 1
00137b14 addu  v1, v1, a0
00137b18 sh   s0, $0000(v1)
00137b1c ld   ra, $0030(sp)
00137b20 lq   s2, $0020(sp)
00137b24 lq   s1, $0010(sp)
00137b28 lq   s0, $0000(sp)
00137b2c addiu  sp, sp, $0040
00137b30 jr   ra

目につくものは$270fの比較命令ですこの結果により分岐するかしないかを決めています。
しなければ青いバーの$270fが。分岐した場合は分岐命令を遡ると分かると思いますが
s0レジスタの値が$00137b18でストアされています。この説明は下を見て下さい。
つまり分岐を潰すと最大値である$270fがストアされます。

このサイトに掲載してあるものは最大値固定ですが、
数値を自分で指定できる様なコードを作ります。
分岐を潰し$00137ae8を変える方法もありますがこれだと2行必要になります。
その為今回は違う方法をとりました。

比較しているのは$00137adcのv1レジスタと$270f、
この時点ではv1レジスタに感情値が格納されています。この前の2行を見て下さい。
dsll32 v1,s0,16でs0レジスタを32+16ビット左へシフトし、v1レジスタへ格納
dsra32 v1,v1,16でv1レジスタを32+16ビット右へシフトし、v1レジスタへ格納
という処理をしています。

s0レジスタに感情値が格納されている事が分かりますね。
そうしてs0レジスタがある箇所を上に遡ってみていくと$00137a98で
daddu s0, a2, zero
としている箇所があります。
ここに自分が指定したい数値をs0レジスタへ入れます。

00137a80 addiu  sp, sp, $ffc0             St_SetEtcCharKanjo(ラベル)
00137a84 sd   ra, $0030(sp)
00137a88 sq   s2, $0020(sp)
00137a8c sq   s1, $0010(sp)
00137a90 sq   s0, $0000(sp)
00137a94 daddu  s1, a1, zero
00137a98 addiu  s0, zero, $2328     s0=$00002328 
00137a9c andi  v1, a0, $ffff
00137aa0 andi  s2, v1, $7fff
00137aa4 slti  v1, s2, $001e
00137aa8 bne   v1, zero, $00137ac4
00137aac nop
00137ab0 lui   a0, $0049        a0=$00490000
00137ab4 addiu  a0, a0, $69e8      a0=$004969e8
00137ab8 addiu  a1, zero, $14ac     a1=$000014ac
00137abc jal   kwlnAssertFunc_     ▼$001b7310
00137ac0 nop
00137ac4 addiu  v1, zero, $001a     v1=$0000001a
00137ac8 bne   s2, v1, $00137ad4
00137acc nop
00137ad0 daddiu s2, zero, $0002     s2=$00000002
00137ad4 dsll32 v1, s0, 16
00137ad8 dsra32 v1, v1, 16
00137adc slti  v1, v1, $270f
00137ae0 bne   v1, zero, $00137aec

この例だと$2328。10進数で9000ですから比較した結果v1レジスタに1が入り分岐。
$2328がそのままストアされる様になりました。

プリクラ無くてもバディ選択可能

このコードは苦労しましたが、AR誌でバディ全員のコードが掲載された後に出来た為、
かなり意味が無くなってしまいました
きっかけはアイテム移植コードを作った際にもう1度色々探した事。
しかし今後に役立つのではないかと思うコードでした
探し方は3種類ほどあります
1.パッドから探す
2.バディ選択時の処理を遡る
3.ラベルのChkGameFlagから探す

2,3は後から気がついた方法ですが、1は時間が掛かりすぎる。
3は多数のフラグのチェックをしている為あまりおすすめできません
今回は1を詳しく説明します2、3は1と同じ箇所ですので大まかに。
では始めにやった1から説明していきます。

1.パッドから探す
注目する点はパッド情報でして
これはバディを選択する時に○で選択△で外すSELECTでプリクラを拡大、□で詳細表示、STARTで遺跡へ。
という事を参考にします。
これを選んだ理由はもしプリクラがなければボタンを押しても分岐する事が考えられる為です。

これらのパッド情報は

0010 1000
0020 2000
0080 8000
SELECT 0100 0001
START 0800 0008
この2種類のうちどちらかです。プラス形式である場合は大抵左の数値が使用される為まずはこちらで探します。
16ビットで探しますが、$0010、$0020、$0080これらはプログラムでよく使われていそうな為除外。
残りの$0100、$0800ですが後者の場合もよく使われている様なので$0100で探してみます。
それでも多くヒットしますが$00100000代は今までの経験上あまり無いのでとばします。
探す命令は

andi 〜, 〜, $0100
分岐命令

〜にはそれぞれレジスタが入ります。
動体視力が良ければF4キーを押したままでも見つかると思います。
過ぎてしまってもShift+F4を押せば戻りますので大丈夫です。

見つかったら
andi 〜, 〜, $0100の
$0100(SELECTの値)を$0020(○の値)に変えてみましょう。
こうする事でセレクトを押した場合○の動作をすることが考えられる為です。
念のためその周辺にある
andi 〜, 〜, $0020を$0100(SELECTの値)に変えます。
これでボタンの効果が反対になっていればその処理中にフラグを判定する処理がされているはずです。
正解の箇所を載せますが、本来であれば何カ所もあるところ全てを変えて下さい。
処理1

0015f3c4 andi  v0, v1, $0020             
0015f3c8 beq   v0, zero, $0015fac0
0015f3cc nop
0015f3d0 daddu  s2, zero, zero
0015f3d4 lh   v1, $00be(s0)
0015f3d8 addiu  v0, zero, $0001
0015f3dc bne   v1, v0, $00160c30
0015f3e0 nop
0015f3e4 lh   v0, $00ba(s0)
0015f3e8 sll   a0, v0, 3
0015f3ec dsll32 v1, s5, 16
0015f3f0 dsra32 v1, v1, 16
0015f3f4 addu  v0, v1, a0
0015f3f8 sll   v0, v0, 2
0015f3fc addu  v0, v0, s0
0015f400 lw   v0, $00e0(v0)
0015f404 beq   v0, zero, $00162168
0015f408 nop
0015f40c addiu  v0, a0, $01f5
0015f410 addu  v0, v1, v0
0015f414 andi  a0, v0, $ffff
0015f418 lui   a1, $004b        a1=$004b0000
0015f41c addiu  a1, a1, $8248      a1="h_buddy.c"
0015f420 addiu  a2, zero, $0186     a2=$00000186
0015f424 jal   ChkGameFlag       ▲$0012bc90
0015f428 nop
0015f42c beq   v0, zero, $00162168

処理2
0015f228 lh   s5, $00bc(s0)
0015f22c lui   at, $0075        at=$00750000
0015f230 lhu   v1, $744e(at)      v1=$0075744e
0015f234 andi  v0, v1, $0100             
0015f238 beq   v0, zero, $0015f294
0015f23c nop
0015f240 lh   v0, $00ba(s0)
0015f244 sll   v0, v0, 3
0015f248 addiu  v1, v0, $01f5
0015f24c dsll32 v0, s5, 16
0015f250 dsra32 v0, v0, 16
0015f254 addu  v0, v0, v1
0015f258 andi  a0, v0, $ffff
0015f25c lui   a1, $004b        a1=$004b0000
0015f260 addiu  a1, a1, $8248      a1="h_buddy.c"
0015f264 addiu  a2, zero, $016a     a2=$0000016a
0015f268 jal   ChkGameFlag       ▲$0012bc90
0015f26c nop
0015f270 beq   v0, zero, $00162168

変更する箇所はそれぞれ青いバーの位置です。これを
andi v0, v1, $0100
andi v0, v1, $0020
へ変えます。結果ボタン操作が入れ替わっています
ここで注目すべき点は○を押した時の処理1の処理です
○を押した場合のパッド情報は$0020。ビットですと
100000
この1の部分がv1レジスタと一致すると後は何が入っても
100000となります
100000 $0020
111111 v1レジスタ
結果
100000 v0レジスタ
ビットの説明ですがうまくできてませんね。
論理積はかけ算、排他的論理和は足し算(同じ場合は0)だと思って下さい
論理和、論理積を調べると何が言いたいのか分かるかと思います

ビットの説明はここで終えて、続きに入ります。
簡単に言うと○を押した時にv0レジスタに$0020が入るという事です。
そうすると○ボタンを押している時は分岐しません。この後を見ていくと
$0015f424にChkGameFlagへジャンプする命令がありますので→キーを押しジャンプしてみましょう

0012bc90 andi  v0, a0, $ffff             ChkGameFlag(ラベル)
0012bc94 andi  v1, v0, $001f
0012bc98 bgez  v0, $0012bcac
0012bc9c nop
0012bca0 beq   v1, zero, $0012bcac
0012bca4 nop
0012bca8 addiu  v1, v1, $ffe0
0012bcac addiu  v0, zero, $0001     v0=$00000001
0012bcb0 sllv  a1, v0, v1
0012bcb4 andi  v0, a0, $ffff
0012bcb8 srl   v0, v0, 5
0012bcbc sll   v1, v0, 2
0012bcc0 lui   v0, $0077        v0=$00770000
0012bcc4 addiu  v0, v0, $6900      v0=_GameFlag
0012bcc8 addu  v0, v0, v1
0012bccc lw   v0, $0000(v0)
0012bcd0 and   v0, a1, v0
0012bcd4 sltu  v0, zero, v0             
0012bcd8 jr   ra

その名の通りフラグをチェックしているようです。
青いバーを見ると、jr raで戻る前に比較命令でv0レジスタに0もしくは1が入ります。
戻ると$0015f42cでv0が0の場合分岐。1の場合分岐しない様になっていますね。
という事は上の方で書いた通り「プリクラがなければボタンを押しても分岐する事が考えられる」が
あっているようで、フラグが立っている。1であれば分岐しない筈なのでこの分岐命令を潰して
プラグが立っていなくても分岐させなければ良い訳です。

2.バディ選択時の処理を遡る
バディ選択はSt_GetBuddyでデータをロードしSt_SetBuddyでストアしています。
ではまず最初にSt_GetBuddyの処理の先頭の$0012f900をスペースキーでマークし
F3キーで参照箇所へ

0012f900 andi  v1, a0, $ffff             St_GetBuddy(ラベル)
0012f904 ori   v0, zero, $8000     v0=$00008000
0012f908 bne   v1, v0, $0012f934
0012f90c nop
0012f910 dsll32 v0, a1, 16
0012f914 dsra32 v0, v0, 16
0012f918 sll   v1, v0, 1        v1=$00010000
0012f91c lui   v0, $0078        v0=$00780000
0012f920 addiu  v0, v0, $99c4      v0=$007799c4
0012f924 addu  v0, v0, v1
0012f928 lhu   v0, $0000(v0)
0012f92c beq   zero, zero, $0012f938
0012f930 nop
0012f934 ori   v0, zero, $ffff     v0=$0000ffff
0012f938 jr   ra

するといくつかの参照箇所の中の$0015f490の上を見るとandiと分岐命令があります。
これは前にもあげた様にパッド判定をしている可能性があります。
ここから下へ行くと先ほどと同じ箇所でしてフラグをチェックした後分岐するかしないかになっています。
後は同じように分岐を潰す事でフラグが立っている様に出来ます。

0015f3c4 andi  v0, v1, $0020             
0015f3c8 beq   v0, zero, $0015fac0
0015f3cc nop
0015f3d0 daddu  s2, zero, zero
0015f3d4 lh   v1, $00be(s0)
0015f3d8 addiu  v0, zero, $0001     v0=$00000001
0015f3dc bne   v1, v0, $00160c30
0015f3e0 nop
0015f3e4 lh   v0, $00ba(s0)
0015f3e8 sll   a0, v0, 3
0015f3ec dsll32 v1, s5, 16
0015f3f0 dsra32 v1, v1, 16
0015f3f4 addu  v0, v1, a0
0015f3f8 sll   v0, v0, 2
0015f3fc addu  v0, v0, s0
0015f400 lw   v0, $00e0(v0)
0015f404 beq   v0, zero, $00162168
0015f408 nop
0015f40c addiu  v0, a0, $01f5
0015f410 addu  v0, v1, v0
0015f414 andi  a0, v0, $ffff
0015f418 lui   a1, $004b        a1=$004b0000
0015f41c addiu  a1, a1, $8248      a1="h_buddy.c"
0015f420 addiu  a2, zero, $0186     a2=$00000186
0015f424 jal   ChkGameFlag       ▲$0012bc90
0015f428 nop
0015f42c beq   v0, zero, $00162168
0015f430 nop
0015f434 addiu  a0, zero, $0001     a0=$00000001
0015f438 jal   ReqSe          ▼$001667e0
0015f43c nop
0015f440 lh   v1, $00bc(s0)
0015f444 lh   v0, $00ba(s0)
0015f448 sll   v0, v0, 3
0015f44c addu  v0, v1, v0
0015f450 addiu  v0, v0, $0001
0015f454 andi  s3, v0, $ffff
0015f458 addiu  v0, zero, $0002     v0=$00000002
0015f45c bne   s3, v0, $0015f488
0015f460 nop
0015f464 addiu  a0, zero, $034c     a0=$0000034c
0015f468 lui   a1, $004b        a1=$004b0000
0015f46c addiu  a1, a1, $8248      a1="h_buddy.c"
0015f470 addiu  a2, zero, $018a     a2=$0000018a
0015f474 jal   ChkGameFlag       ▲$0012bc90
0015f478 nop
0015f47c beq   v0, zero, $0015f488
0015f480 nop
0015f484 daddiu s3, zero, $001a     s3=$0000001a
0015f488 ori   a0, zero, $8000     a0=$00008000
0015f48c daddu  a1, zero, zero
0015f490 jal   St_GetBuddy       ▲$0012f900 

3.ラベルのChkGameFlagから探す
これはChkGameFlag処理の先頭から参照箇所探し上の場所を探す。です
しかしこれはあまりにも参照箇所がある為、止めた方がいいです。
ただ多数のフラグをChkGameFlagで処理している為自由行動時会話済みにならない等の
コードを探す場合は役に立ちました。
具体的なフラグは「フラグ色々『副作用あり』(セーブ未反映)」コードの効果を見て下さい。
しかしこれだけではなくほかにも効果があるようですが、どういった物があるのかは未確認です。

2ページ目へ 雑記へ戻る