れーすのエグゼ流星Blog

エグゼとゲームと雑記

エグゼ解析したりゲーム作ったりいろいろ。

サイト案内(初めての方はこちらを)

初めまして。れーすです。

ここのブログに訪問したのは「流星のロックマン」や「DSネット対戦」などで検索したのがほとんどだと予想しているため、案内を記しておきます。

 

ニンテンドーDSのネット対戦(熱帯)について

 

exe-race.hateblo.jp

exe-race.hateblo.jp

exe-race.hateblo.jp

exe-race.hateblo.jp

 

 

 

ロックマンエグゼ6 ウイルスやボスのHPテーブルを特定する

大まかな流れ

1.HPを管理しているRAMを知る

2.RAMをブレークポイントにセットする

3.関数を特定する

4.その関数を使ってこつこつ調べる


1.HPを管理しているRAMを知る

GitHub - dism-exe/bn6f: Disassembly of MegaMan Battle Network 6 with Cybeast Falzar as baserom
アセンブルプロジェクトを使用するとROMマップを出力してくれており、そこにRAMがすべて記載している
ただ、こういうのは改造コードが便利
検索「ロックマンエグゼ6 改造コード 敵のHP」
PAR コード掲示板

敵HP全て1()
BA353788 E5E9DF9A
E18A078F E761732A

PAR→VBAに変換してRAMを把握する
VBA/PAR/XTAコード変換

0203A9D4:0001
0203AAAC:0001

この2つがおそらく最大HPを管理するRAMになる

2.RAMをブレークポイントにセットする

column:arm_asmカンペ [FE改造wiki]

[0203AAAC] = 0x28
ここではグレイブヤード2のカーネルRVのHPでテストをする
HP2600 = 0xA28

1バイト目なので0x28をブレークポイントに設定です

f:id:rai17321:20200213002215p:plain

ヒット

3.関数を特定する

r1,r2にA28が入ってるから、A28を入れる処理を辿る
mov r2,r1でr1にA28をいれてる

1つ上のldrh r1,[r0]で0x810920A(ROM)からA28読み込んでいることを確認

f:id:rai17321:20200213002429p:plain

これがHPテーブル

また、読み込み関数はこれ

0800f824 enemy_get_struct1
0800f84c enemy_get_struct2

この関数を使えばHPなどを読み込めるはず、特にenemy_get_struct2

4.その関数を使ってこつこつ調べる

0800f84c enemy_get_struct2

NO$GBAを使って上をブレークポイントに設定する
おそらくウイルスやボスに遭遇する度にブレークするので、その時のr0とr1を見ればいいと思う

BA CrossOverPatch for JP 作業記録 その1【シールドの展開時間】

はじめに

BA CrossOverPatch for JPというものを作っています
BA CrossOverPatchと呼ばれるUSグレイガ向けのハックROMをJPにも移植しようというプロジェクトです

詳しくはこちら
www.youtube.com

自分用のメモとして日々の作業を記録していこうと思います
(こういうのは続けることが一番なので、三日坊主にならないようにラフに書いていきます)

シールドの展開時間を伸ばす

流星のロックマンでお馴染みのシールドは結構展開時間が長いです
一方ロックマンエグゼ6のシールドはかなり短いです、変えていきましょう


NO$GBAというデバッガーを使い、0801BE14にブレークポイントをセット
0801BE14はロックマンのアクションに対して使うブレークポイントです
しかし、ヒットせず。アプローチを変えて、音を鳴らす関数やスプライトをロードする関数にブレークポイントを仕掛けても調査は難航


DiscordでGreigaMasterに助けを乞う


f:id:rai17321:20190807233247p:plain

色々教えてもらうと、結果的に以下がループ処理だとわかりました

000f3ef6 8a38 ldrh r0, [r7, #16]
000f3ef8 3001 add r0, #1 
000f3efa 8238 strh r0, [r7, #16]
000f3efc 7b39 ldrb r1, [r7, #12]
000f3efe 4288 cmp r0, r1 


よく見るとこれ、ループ処理です
000f3ef6 8a38 ldrh r0, [r7, #16]
RAMから現在のフレームを取得


000f3ef8 3001 add r0, #1
取得した値をインクリメント


000f3efa 8238 strh r0, [r7, #16]
RAMにインクリメントした値を書き込む


000f3efc 7b39 ldrb r1, [r7, #12]
シールド展開時間の設定値をRAMから読み込む


000f3efe 4288 cmp r0, r1
r0とr1の値を比較、r1の値を超えるまで1ずつインクリメントされていく


つまり、000f3efc 7b39 ldrb r1, [r7, #12] が実行されたタイミングのレジスタr1の値を確認し、そこから辿っていけば設定値の格納先がわかるわけです


結論としては下記となります
0001278c 0214 lsl r4, r2, #8 //シールド 展開時間

GBAプログラミング 5日目

取り組んだ内容

Tutorial.6 キー入力とデバッグ
http://akkera102.sakura.ne.jp/gbadev/index.php?tutorial.6

やってみたこと

1.上 下 右 左 Bボタンのキー入力、同時入力の受け取りをVisualBoyAdvanceのloggingを用いて確認してみる

f:id:rai17321:20180606160308j:plain

#include "lib/gba.h"

//---------------------------------------------------------------------------
void WaitForVsync(void)
{
	while(*(vu16*)0x4000006 >= 160) {};
	while(*(vu16*)0x4000006 <  160) {};
}
//---------------------------------------------------------------------------
int main(void)
{
	// モード設定なし

	u32 x = 0;

	for(;;)
	{
		WaitForVsync();

		if( !(REG_KEYINPUT & KEY_UP)  ) TRACEOUT("上ボタン\n");
		if( !(REG_KEYINPUT & KEY_DOWN)) TRACEOUT("下ボタン\n");
		if (!(REG_KEYINPUT & KEY_LEFT)) TRACEOUT("左ボタン\n");
		if (!(REG_KEYINPUT & KEY_RIGHT)) TRACEOUT("右ボタン\n");

		//if (!(REG_KEYINPUT & KEY_UP & KEY_DOWN)) TRACEOUT("上と下\n");
		//if (!(REG_KEYINPUT & KEYIRQ_OR & KEY_RIGHT)) TRACEOUT("テスト\n");

		if( !(REG_KEYINPUT & KEY_A)   ) TRACEOUT("%d回押したよ\n", x++);
	}
}

考察

コメントアウトした部分の動作がうまくいかなかった。
&条件なので上と下を押さないと動作しないはずが、常に動作してしまっている。
KEYIRQ_ORとかを使うみたいなんだけど、使い方がよくわからなかった。

GBAには標準でリセット(A & B & SELECT & START)機能があるので、実装はできるはず。

GBAプログラミング 4日目

取組んだ内容

tutorial.4

mode4

やってみたこと

1.フレームバッファを無限ループでずっと切り替えさせてみる。

 

int main(void)
{
	// モード設定
	// 4bit目(BACKBUFFER)を1にすることで、フレーム2が有効になります
	SetMode(MODE_4 | BG2_ENABLE | BACKBUFFER);

	// 画像と色データの読み込み
	Mode4SetFrame((u8*)&frame1Bitmap, 1);
	Mode4SetFrame((u8*)&frame2Bitmap, 2);

	Mode4SetPalette((u16*)&frame1Pal);

	while(1){
	SetMode(MODE_4 | BG2_ENABLE);
	SetMode(MODE_4 | BG2_ENABLE | BACKBUFFER);
	}
	

	for(;;)
	{
	    WaitForVsync();
	}
}


f:id:rai17321:20180530155500j:plain

考察

 フレームバッファが画面切り替えに使われるのはわかったけど、BACKBUFFERの値をソースコード上で変えたら切り替わるのか?
という考えから、試しに無限ループでやってみたところ見事にヒット。

BACKBUFFERが定義されているのは
#include "lib/gba.h"
#include "res.h"
のどちらなのかな。

そして、助言をいただきはてなブログの記法を見たままからはてな記法にしました。
これでソースコード問題も解決だね!

GBAプログラミング 3日目

取組んだ内容

tutorial.3

ビットマップモード

 

やってみたこと

1.png画像を出力してみる

 

// 画像の読み込み

Mode3DrawImage((u16*)&imageBitmap);

f:id:rai17321:20180524133602j:plain

読み込ませるときの処理がよくわからない。

チュートリアル3のフォルダを流用し、gritで画像をGBA用に変換したものを読み込ませようとしたら、どうやらどこかの処理で画像をGBA用に変換、インポートまでしてくれてるみたいだ。(tut3/res)

楽っちゃ楽だけど、仕組みをきちんと知りたさがある。

 

 

2.四角形の描画をしてみる

f:id:rai17321:20180524142928j:plain

 

#include "lib/gba.h"#include "lib/gba.h"
//---------------------------------------------------------------------------

void WaitForVsync(void)

{ while (*(vu16*)0x4000006 >= 160) {};

while (*(vu16*)0x4000006 <  160) {};}

//---------------------------------------------------------------------------

void Mode3PutPixel(u32 x, u32 y, u16 col){

u16* ScreenBuffer = (u16*)0x6000000; ScreenBuffer[y * 240 + x] = col;}

//---------------------------------------------------------------------------

// モード3で四角形を塗りつぶすvoid Mode3DrawBox(u32 sx, u32 sy, u32 ex, u32 ey, u16 col){ u32 x, y;
for (y = sy; y<ey; y++) { for (x = sx; x<ex; x++) { Mode3PutPixel(x, y, col); } }}int main(void){ // モード設定 SetMode(MODE_3 | BG2_ENABLE);
// ドットの描画 u32 sx = 50; u32 sy = 50; u32 ex = 150; u32 ey = 150; u16 col = RGB5(31, 31, 31);
Mode3DrawBox(sx,sy,ex,ey,col);

for (;;) { WaitForVsync(); }
}

 

はてなソースコードの貼り付けするとインデント消えるのかよ!!!!!!!

 

DXlibでの描画と対して変わらない。

2つの頂点を設定することで描画を実現している。(sx,sy & ex,ey)

 

やってて思いましたが、UnityはDXlibを楽にしたもので、DXlibはこのような古典的なゲームプログラミングを楽にしたもの、このゲームプログラミングもアセンブリを楽にしたものなんじゃないかな。

GBAプログラミング 2日目

取組んだこと

・開発wikiチュートリアル2

tutorial.2

 

学んだこと(印象に残ったこと)

GBAの描画形式がmodeという種類で分けられている。

0-2がタイル

3-5がビットマップ

タイルとビットマップの違いは、このサイトがわかりやすいかも。

画像処理の話の中で、ラスター形式やタイル形式という言葉がでて… - 人力検索はてな

ビットマップが一番細かい描画なのかな?

 

processingのvoid setup()みたいに初期設定で描画設定を行う。

 

SetMode(MODE_3 | BG2_ENABLE);

 

で、この分解していくと

0x04000000~0x04000001

に代入する値によってmodeが切り替わるらしい。

 

f:id:rai17321:20180516162221p:plain