BUSIN 0 Atlus Best Collection

キーワード
相対アドレス
ベース
ワークアドレス


内容
味方HP最大値維持
宿屋に泊まると魔術師魔法最大・残り使用回数9+α
全AA使用回数xに変更


味方HP最大値維持

このソフトは戦闘中と非戦闘中で共通のプログラムを使用している様で、1つ探すと共に効果があるというソフトでした。
それに加えワークアドレスがそのまま参照箇所になっているところが他のソフトより多く、コードを作りやすかったです。
この事を踏まえまずはワークアドレスを探します。
通常版のコードが多くでており、最大値がわかっているので最大値検索で探していきますが
999だと多数のステータスの最大値ですのでHPの9999を最大値で探します。

以下がLVUPの際の最大値修正処理です。

001c88d8 dsll32 v0, a1, 16
001c88dc dsra32 v0, v0, 16
001c88e0 slti  at, v0, $2710
001c88e4 bne   at, zero, $001c88f0         
001c88e8 nop
001c88ec addiu  a1, zero, $270f     a1=$0000270f
001c88f0 sll   v0, a2, 5
001c88f4 subu  v1, v0, a2
001c88f8 lui   v0, $0056        v0=$00560000
001c88fc sll   s0, v1, 4
001c8900 addiu  v0, v0, $ddda      v0=$0055ddda
001c8904 addu  v0, v0, s0
001c8908 jal   $001c8ef0

灰色の箇所を潰すと最大になり、ストアのベースである$0055dddaが最大HPのワークアドレス
後は通常版のワークアドレスとの差分を出し、ベスト版のワークアドレスを調べます。
最大HPに+2hしたものが現在HPであるので$0055dddcが現在HPです。

最大HPのワークアドレスの参照箇所を探して、頻繁に動作しているものを探します。
例えばメニューや画面下に表示させるためにHPの値をロードしている筈なので、ロード命令の場所を探し、
その箇所を適当な数値に変えます。
例えば、lh v0,$0000(v1)とあった場合addiu v0,zero,$0063と変えてみます。多数ある怪しい箇所を全て変えてみて、
$0063,$0064,$0065等といれ画面に反映されているものが、実際にロードされている箇所になると思います。
(実際には例外もあります)

001c8e78 lui   v0, $0056        v0=$00560000
001c8e7c sll   v1, v1, 4
001c8e80 addiu  v0, v0, $ddda      v0=$0055ddda
001c8e84 addu  v0, v0, v1
001c8e88 lh   v0, $0000(v0)
001c8e8c nop
001c8e90 jr   ra

上がその箇所です。後はこの様に書き換えます。

001c8e78 lui   v0, $0056        v0=$00560000
001c8e7c sll   v1, v1, 4
001c8e80 addiu  v0, v0, $ddda      v0=$0055ddda
001c8e84 addu  t0, v0, v1
001c8e88 lh   v0, $0000(t0)
001c8e8c sh   v0, $0002(t0)            
001c8e90 jr   ra

ベースが$0055dddaですのでp$0000が最大HP、p$0002が現在HPです。
v0からt0に変更したのはベースと格納レジスタが同じだとストアさせる際に格納した数値がベースとなってしまう為です。
これでHP維持のコードが出来ました。

しかし今回はワークアドレスが参照箇所になっているため見つけられましたが、
他のソフトでは最大値をストアしている相対アドレスと同じものを探していく。という形になるかと思います。
但しこれも相対アドレスの数値が良くあるもので実際やってみると見つからないです。
もっと違うやり方でなければ見つからないのかもしれませんが、今の私では技術不足なためわかりません。


宿屋に泊まると魔術師魔法最大・残り使用回数9+α

これも上と同じで、ワークアドレスの参照箇所から探していきます。
ワークアドレスは差分から$0055dd67が残り回数で$0055dd66が最大の回数だとわかっています。
ですので残り使用回数のアドレス$0055dd67から参照箇所移動してそれらしいものを探していきます。
これも多数ある参照箇所で怪しいところを↑のようにストアさせたり、ロードする値を適当な数値に変え、
魔法を使用したり残り使用回数を回復するなどをし、変動させて反映された数値に変えた箇所が
変動した際に通る処理です。そうして宿屋に泊まるとLV1の魔法の残り回数が変わりました。
その処理がこちらです。

001c6d08 slt   at, a0, v1
001c6d0c beq   at, zero, $001c6d18         
001c6d10 nop
001c6d14 daddu  s2, a0, zero
001c6d18 sll   v1, s1, 5
001c6d1c subu  v1, v1, s1
001c6d20 lui   a0, $0056        a0=$00560000
001c6d24 sll   a1, v1, 4
001c6d28 addiu  a0, a0, $dd67      a0=$0055dd67
001c6d2c sll   v1, s0, 1
001c6d30 addu  a0, a0, a1
001c6d34 addu  v1, v1, s0
001c6d38 sll   v1, v1, 1
001c6d3c addu  v1, v1, a0
001c6d40 sb   s2, $0000(v1)
001c6d44 nop
001c6d48 ld   ra, $0030(sp)

$0055dd67にストアしているs2レジスタを変えると残り使用回数を変えられます。
その際に注目したいことが残り回数-1hが最大の回数であること。
つまり、ベースのv1レジスタから1h引いたアドレスにストアさせれば最大の回数も変わります。
-1ですからsb s2, $ffff(v1)といれることでv1レジスタから-1hのアドレスにs2の値をストアさせる事が出来ます
これがその書き換えた処理です。

001c6d08 slt   at, a0, v1
001c6d0c addiu  a0, zero, $0009     a0=$00000009
001c6d10 nop
001c6d14 daddu  s2, a0, zero       s2=$00000009
001c6d18 sll   v1, s1, 5
001c6d1c subu  v1, v1, s1
001c6d20 lui   a0, $0056        a0=$00560000
001c6d24 sll   a1, v1, 4
001c6d28 addiu  a0, a0, $dd67      a0=$0055dd67
001c6d2c sll   v1, s0, 1
001c6d30 addu  a0, a0, a1
001c6d34 addu  v1, v1, s0
001c6d38 sll   v1, v1, 1
001c6d3c addu  v1, v1, a0
001c6d40 sb   s2, $0000(v1)
001c6d44 sb   s2, $ffff(v1)            
001c6d48 ld   ra, $0030(sp)

a0に$0009をいれているのは分岐を潰した上でa0に$0009を入れておき、その$0009をaddu s2,a0,zeroで
s2に移させそのまま残り回数のsb s2, $0000(v1)と最大の回数のsb s2, $ffff(v1)でストアさせて双方の回数を変更する為
これで終わりです。僧侶魔法もアドレスが違うだけで同じ処理をします。


全AA使用回数xに変更

これは最大値がわからなかったので技LVがUPする回数でデータテーブルを探してみましたが見つかりませんでした。
データテーブルはキーワードのテーブルを参照下さい。つまりHPの様に最大値が1つしかないものではなく、
LVUPに必要な経験値の様にLV毎に変わる数値等をデータ部に並べてあるものです。
今回はこれで技のLVUPに必要な回数を設定していないのか、もしくはどこか別にあるのものを見つけられなかったのか
わかりませんが300等のLVUPに必要な回数が見つかりませんでした。その為まずはワークコードを探していきます。

ところが通常版では技の使用回数のコードがありませんでしたので、自分で探します。
まず今の回数をセーブデータから探します。
そうするとpsu形式のセーブデータでは$43f2cがAAの使用回数のアドレスのようです。
それから他のアドレスとの差分をだし、ワークコードにするのが一般的です。

しかし他のデータとのアドレスがかなり離れている為、そのまま差分をだしても実際とは違う場合があります。
ですのでその近くでワークコードが出来そうなもののデータが無いか探していきます。そうするとすぐ上の$43eceに
合成素材のウジのわいた肉の個数のデータがありました。
この時戦闘後獲得した素材99個というコードが出来ていましたのでその処理を見てストアしているアドレスを探します。
まずはこの処理を見て下さい。

001b80a4 jal   $001b6260
001b80a8 daddu  s0, a1, zero
001b80ac beq   v0, zero, $001b8158
001b80b0 dsll32 a0, s1, 16
001b80b4 dsra32 a0, a0, 16
001b80b8 bltz  a0, $001b80c8
001b80bc slti  v1, a0, $0029
001b80c0 bne   v1, zero, $001b80d0
001b80c4 nop
001b80c8 beq   zero, zero, $001b8158
001b80cc nop
001b80d0 dsll32 v1, s0, 16
001b80d4 dsra32 v1, v1, 16
001b80d8 bgez  v1, $001b80e8
001b80dc nop
001b80e0 daddu  s0, zero, zero
001b80e4 nop
001b80e8 dsll32 v1, s0, 16
001b80ec dsra32 v1, v1, 16
001b80f0 slti  at, v1, $0064
001b80f4 bne   at, zero, $001b8100
001b80f8 nop
001b80fc addiu  s0, zero, $0063     s0=$00000063
001b8100 sll   v1, a0, 1
001b8104 lui   at, $0001        at=$00010000
001b8108 addu  v1, v1, v0             
001b810c ori   at, at, $91ec      at=$000191ec
001b8110 dsll32 v0, s0, 16
001b8114 addu  a0, v1, at
001b8118 dsra32 v0, v0, 16
001b811c lh   v1, $0000(a0)
001b8120 addu  v0, v1, v0
001b8124 slti  at, v0, $0064
001b8128 bne   at, zero, $001b8140
001b812c nop
001b8130 addiu  v0, zero, $0063     v0=$00000063
001b8134 beq   zero, zero, $001b8148
001b8138 sh   v0, $0000(a0)            

↑が戦闘後獲得した時に通る処理です。一番下が獲得した個数のストアで、このベースの値a0の値が
わかればワークアドレスもわかります。
a0を所持金のワークアドレスにストアさせてアドレスを調べる方法もありますが、それだと手間がかかるのでやめます。

$001b8114でaddu a0, v1, atとatの$000191ecが加算されています。しかしこの値がアドレスとは思えないので更に遡ると
$001b8108でaddu v1, v1, v0となっていますv1はすぐ上で1ビット左シフトですからa0×2つまりは2hずつアドレスを
ずらしているということです。残ったv0を調べていきますがこの部分を見るだけでは見つかりません。
そこで1番上のjalへ飛んでみるとこの様になっていました。

001b6260 lui   v0, $0054        v0=$00540000
001b6264 jr   ra
001b6268 addiu  v0, v0, $2660      v0=$00542660

v0=$00542660+at=$000191ecがアドレスとなります。1ビットシフトを足さないのは通常初期値が0(この場合はa0)から
増えてアドレスに+〜hしていくため。
実際に$0055b84cを暗号化しコードとして使用してみます。
するとアイテム画面で素材の1番上に空欄が出来、指定した個数になっていました。
それに+2hしたアドレスがウジのわいた肉でしたのでセーブデータの差分とワークアドレスの差分をだし、
$0055b8acというAAのワークアドレスが出来ます。
後はこれをそれぞれの技のワークコードにしていけばいいのですが。30種類あるので30行になってしまい
入力が面倒です。ですから自作の処理を作り、それぞれのアドレスに格納させていきます。

まず頻繁に通る処理を探します。HP最大維持の復帰でもいいのですが、今回は別の場所を使用しました。

001c1be0 dsll32 v1, a0, 16
001c1be4 dsra32 v1, v1, 16
001c1be8 bltz  v1, $001c1bf8
001c1bec slti  v0, v1, $001e
001c1bf0 bne   v0, zero, $001c1c00
001c1bf4 nop
001c1bf8 beq   zero, zero, $001c1c20
001c1bfc addiu  v0, zero, $03e7     v0=$000003e7
001c1c00 sll   v0, v1, 5
001c1c04 subu  v1, v0, v1
001c1c08 lui   v0, $0056        v0=$00560000
001c1c0c sll   v1, v1, 4
001c1c10 addiu  v0, v0, $dd38      v0=$0055dd38
001c1c14 addu  v0, v0, v1
001c1c18 lw   v0, $0000(v0)
001c1c1c nop
001c1c20 j    $000f7000              

これはステータス異常があるか無いかのロードをしている箇所で、$0055dd38がステータス異常のワークアドレスです。
この復帰箇所であったものjr raをjに変えて空きメモリへ飛ばします。そうして作った処理がこちらになります。

000f7000 addu  t1, zero, zero
000f7004 addiu  t2, zero, $0003     t2=$00000003
000f7008 addiu  t3, zero, $0514     t3=$00000514
000f700c lui   t4, $0056        t4=$00560000
000f7010 slti  t5, t1, $001d
000f7014 sll   t7, t1, 3
000f7018 addu  t6, t4, t7        t6=$00560000
000f701c sb   t2, $b8a8(t6)      [0055b8a8]
000f7020 sh   t3, $b8ac(t6)      [0055b8ac]
000f7024 addiu  t1, t1, $0001      t1=$00000001
000f7028 bne   t5, zero, $000f7010
000f702c sb   t2, $b9a8(t4)      [0055b9a8]
000f7030 jr   ra
000f7034 sh   t3, $b9ac(t4)      [0055b9ac]

$0055b8a8は習得しているか、装備しているかのフラグ。$0055b8acが使用回数。
t2はフラグt3は使用回数で1300回$0514がLVUPする為に必要な使用回数の一番多かった数値。
最後の方の2つのストア命令は最後の技だけアドレスが離れていたので別に加えたものです。
その為ループ回数は29回$001dにしています。
本当は$000f7014のsll、$000f7024のaddiuは短縮して1行にも出来るのですが、気まぐれでsllを使用し1行多く
なっています。


戻る