jiangzhengwenjz 发表于 2017-1-13 19:41:04

【改版基础教程#1】增加新精灵球

本帖最后由 jiangzhengwenjz 于 2018-2-10 22:44 编辑

由于时间所限,接下来相当长的时间内我都不可能分出精力用在改版上,所以如我之前所说,将会转载一部分国外的优秀教程,当然仅仅是应用的话对改版者的技术要求很低。
不过,虽然都是基础教程,至少也要求读者懂得如何编辑数据,如何使用指针等基础操作,关于这些在教程里都不会多说。如果你阅读这些内容有困难的话,应该先去做一些更简单的尝试以积累经验。当然这些教程不会是对原贴逐句翻译,只是在厘清思路的基础上把各个部分的操作要点讲清楚,这样看起来可能反而更轻松。
此外所转载的教程都由我先测试过,对于其中的一些问题也会加以修正。

原贴:https://www.pokecommunity.com/showthread.php?t=326311
标题:Pokéball hacking guide
作者: Daniils
本帖不得转载,转载英文原贴务必自觉注明网址!

1. 背景介绍
二代和四代、五代特有的精灵球在火红中统统不存在,而之前没有这样一个新增精灵球的帖子。唯一的资料来源是JPAN研究战斗脚本时对球所作的研究。Daniils在此基础上作了修改,现在可以很轻易地做到新增精灵球。

2. 修改步骤
2.1 修改精灵数据加密/解密函数
这一步是为了扩充精灵数据中球数据的空间,这里的做法是把精灵来源数据的一个二进制位让渡给球数据了,这样就不能判别传送自XD/竞技场的精灵。这样修改之后支持球的数量就增加了一倍(准确说不是,因为值0不被使用),或者说可以额外加19个球。
只需在以下地址写入指定数据:080400B6 - 80
080400B8 - 44
080400BE - 0B
08040855 - FC
0804085A - 1F
0804085E - 89
08040862 - 7C不过这样修改的话就不能使用原有的存档了,因为这样会造成球数据读取的混乱,重新开档吧。

2.2 修改各球战斗脚本读取方式
这一步是为了修改各个球的丢球脚本读取方式,这样也就不必每次增加球都进行一次扩充了。
先找空位写入这一段源码:.text
.align 2
.thumb
.thumb_func
.global ballchecker

ballcompare:
      mov r0, #0x2C
      mul r0, r1
      mov r10, r1
      ldr r1, itemdata
      add r1, r0, r1
      add r1, #0x1A
      ldrb r0,
      cmp r0, #0x3
      beq isball
otherstuffcompare:
      mov r1, r10
      cmp r1, #0x50
      beq dolly
      cmp r1, #0x51
      beq dolly
      mov r0, #0xaf
      lsl r0, r0, #0x1
      cmp r1, r0
      beq flute
      ldr r0, return_addr
      bx r0
isball:
      ldr r0, somevar
      add r1, #0x1
      ldrb r1,
      strb r1,
      ldr r0, ball_script
      cmp r1, #0x11      /*If you want to have a second safari ball like the park ball, place its pokeball index here*/
      beq safari      /*Otherwise, remove these two lines*/
      cmp r1, #0x5
      bne preender
safari:
      add r0, #0x28
preender:
      b script_ender
dolly:
      ldr r0, doll_script
      b script_ender
flute:
      ldr r0, flute_script
script_ender:
      ldr r1, script_ptr
      str r0,
      ldr r1, be3_addr
      mov r10, r1
      ldr r0, end_addr
      bx r0

.align 2
      ball_script:                .word 0x081D9A14
      doll_script:                .word 0x081D9B7C
      flute_script:                .word 0x081D9B86
      script_ptr:                .word 0x02023d74
      be3_addr:                .word 0x02023be3
      return_addr:                .word 0x080164e9
      end_addr:                .word 0x0801671f
      itemdata:                .word 0x083DB028
      somevar:                .word 0x0203fe00其中的几个需要注意的点:
关于这2行      cmp r1, #0x11      /*If you want to have a second safari ball like the park ball, place its pokeball index here*/
      beq safari      /*Otherwise, remove these two lines*/是为了四代中的公园球而设定,如果不打算加入的话直接把它们删掉。如果有的话将0x11改为球编号(球编号是在道具数据结构中,后面提到)itemdata:                .word 0x083DB028这是道具表格的地址,如果你有扩充过把它改了就行somevar:                .word 0x0203fe00这是内存空位,不必用JPAN saveblock hack中的内存区域,如果没冲突可以不改。
此外还需要在这些地址写入这个内存指针(看不懂的话只需要看其中的地址就可以):.org 0x802D500
.word balltraceloc
.org 0x802D544
.word balltraceloc
.org 0x802D6A0
.word balltraceloc
.org 0x802D71C
.word balltraceloc
.org 0x802D7B8
.word balltraceloc
.org 0x80EF4B4
.word balltraceloc
.org 0x80EF4DC
.word balltraceloc
.org 0x80EF674
.word balltraceloc
.org 0x80EF9AC
.word balltraceloc
.org 0x80F0368
.word balltraceloc
.org 0x8016B10
.word balltraceloc
.org 0x80EF7C8
.word balltraceloc
.org 0x800E3C4
.word balltraceloc接下来在0x8016460写入00 00 00 00 0B 4A 97 46
并在0x8016494写入上面源码的指针(不需要+1)
关于之前所说的球编号,这是在道具数据结构中偏移量为1b的1字节,这里我们从1开始编,比如这个是大师球的数据:.byte 0x10, 0x39, 0x09, 0x5D, 0x0B, 0x14, 0xFF, 0xBC, 0xBB, 0xC6, 0xC6, 0xFF, 0x00, 0x00 @道具文本内部编码
.hword 0x0001 @道具编号
.hword 0x0000 @价钱
.byte 0x00, 0x00
.word 0x083D4ECC @介绍文本指针
.hword 0x0000
.byte 0x03
.byte 0x01 @球编号
.word 0x00000000
.word 0x00000002
.word 0x080A1E1D
.word 0x00000000关于道具数据结构可以看百科:http://bulbapedia.bulbagarden.ne ... e_in_Generation_III
所以对于原有的球,改为和它的道具编号相同,其他球则是每次按+1方式增长。
完善了所有球的数据后,还需要完善所有球的图片、色板。
关于这些内容的地址、数据结构可以参考Ta之境界的这篇帖子中的相关内容:http://tieba.baidu.com/p/3534467013

2.3 写入捕捉率源码
先在802D52C写入FF,之后重定向在802D54C的表格(这是C语言中switch语句所生成)。
可以认为每个指针都是指向一段捕捉率计算代码。Daniils和kearnseyboy6已经基本完成了要添加球的源码,我稍加修改后在这里放出:
loveball.thumb
.global loveball_rate
loveball_rate:
main:
mov r4, #10
bl decrypt
cmp r0, r4
beq yes
pop {r0-r7}
b ender

yes:
pop {r0-r7}
mov r4, #80
b ender

decrypt:
push {r0-r7}
ldr r0, wildpokelevel
mov r1, #0xB
ldr r2, decryptpoke
bx r2
mov r4, r0
ldr r0, yourpokelevel
ldr r2, decryptpoke
bx r2

ender:
ldr r0, catchratecalcfunction
mov pc, r0

.align 2
wildpokelevel: .word 0x0202402C
catchratecalcfunction: .word 0x0802d62a
decryptpoke:      .word 0x0803FBE9
yourpokelevel: .word 0x02024284friendball.thumb
.global friendball_rate
friendball_rate:
main:
mov r4, #10
bl decrypt
pop {r0-r7}
b ender
ender:
ldr r0, catchratecalcfunction
mov pc, r0

decrypt:
push {r0-r7}
ldr r0, wildpoke
mov r1, #0x20
ldrb r2, ramoff
ldr r3, decryptpoke
bx r3

.align 2
catchratecalcfunction:      .word 0x0802D62A
decryptpoke:      .word 0x0804037D
ramoff:      .word 0x02024098
wildpoke:      .word 0x0202402Clureball.thumb
.global lureball_rate
lureball_rate:
main:
ldr r0, fishingbyte
ldrb r0,
cmp r0, #1
beq fishing
mov r4, #10
b ender

fishing:
mov r4, #30

ender:
ldr r0, catchratecalcfunction
mov pc, r0

.align 2
fishingbyte: .word 0x02036E38
catchratecalcfunction: .word 0x0802d62amoonball.thumb
.global moonball_rate
moonball_rate:
main:
mov r4, #10
bl decrypt
cmp r2, #0x1D
beq yes
cmp r2, #0x1E
beq yes
cmp r2, #0x1F
beq yes
cmp r2, #0x20
beq yes
cmp r2, #0x21
beq yes
cmp r2, #0x22
beq yes
cmp r2, #0x23
beq yes
cmp r2, #0x24
beq yes
cmp r2, #0x28
beq yes
cmp r2, #0x29
beq yes
mov r1, #0x13
lsl r1, #0x4
add r1, #0xB
cmp r2, r1
beq yes
add r1, #0x1
cmp r2, r1
beq yes
mov r1, #0x23
lsl r1, #0x4
add r1, #0xA
cmp r2, r1
beq yes
add r1, #0x1
cmp r2, r1
beq yes
beq yes
pop {r0-r7}
b ender

yes:
pop {r0-r7}
mov r4, #40
b ender

decrypt:
push {r0-r7}
ldr r0, wildpokelevel
mov r1, #0xB
ldr r2, decryptpoke
bx r2

ender:
ldr r0, catchratecalcfunction
mov pc, r0

.align 2
wildpokelevel: .word 0x0202402C
catchratecalcfunction: .word 0x0802d62a
decryptpoke:      .word 0x0803FBE9levelball.thumb
.global levelball_rate
levelball_rate:
main:
ldr r0, yourpokelevel
ldrb r0,
ldr r4, wildpokelevel
ldrb r4,
cmp r0, r4
bhi timestwo
mov r4, #10
bne ender

timestwo:
lsl r4, r4, #1
cmp r0, r4
bhi timesfour
mov r4, #20
bne ender

timesfour:
lsl r4, r4, #1
cmp r0, r4
bhi timeseight
mov r4, #40
bne ender

timeseight:
mov r4, #80

ender:
ldr r0, catchratecalcfunction
mov pc, r0

.align 2
yourpokelevel: .word 0x020242D8
wildpokelevel: .word 0x02024080
catchratecalcfunction: .word 0x0802d62afastball.global fastball_rate
.thumb
fastball_rate:
main:
mov r4, #10
bl decrypt
ldr r2, pokemondata
ldr r2,
mov r4, #0x1C
mul r0, r4
add r0, r2, r0
ldrb r1,
cmp r0, #0x64
bge correct
pop {r0-r7}
b ender
correct:
pop {r0-r7}
mov r4, #40
ender:
ldr r0, catchratecalcfunction
mov pc, r0

decrypt:
push {r0-r7}
ldr r0, wildpoke
mov r1, #0xB
ldr r2, decryptpoke
bx r2

.align 2
catchratecalcfunction:      .word 0x0802D62A
decryptpoke:      .word 0x0803FBE9
wildpoke:      .word 0x0202402C
pokemondata:      .word 0x80001BCheavyball.thumb
.global heavyball_rate
heavyball_rate:
main:
ldr r0, pokeindex
ldrh r0,
mov r1, #0x24
mul r0, r1
ldr r1, pokedextable
ldr r1,
add r1, r0, r1
add r1, r1, #0xE
ldrh r1,
mov r2, #0xC8
lsl r2, #0x1
cmp r1, r2
bhi plusforty
sub r2, r2, #0x64
cmp r1, r2
bhi plusthirty
sub r2, r2, #0x64
cmp r1, r2
bhi plustwenty
b minustwenty

plusforty:
add r5, r5, #40
b ender

plusthirty:
add r5, r5, #30
b ender

plustwenty:
add r5, r5, #20
b ender

minustwenty:
sub r5, r5, #20

ender:
mov r4, #10
ldr r0, catchratecalcfunction
mov pc, r0

.align 2
pokeindex: .word 0x0202077E
pokedextable: .word 0x8088e34 @改为图鉴表格地址
catchratecalcfunction: .word 0x0802d62aparkball.thumb
.global parkball_rate

parkball_rate:
main:
      LDR   R0, dword_2023FE8
      LDR   R0,
      ADD   R0, #0x7C
      LDR   R0,
      LSL   R1, R0, #2
      ADD   R1, R1, R0
      LSL   R0, R1, #8
      SUB   R0, R0, R1
      MOV   R1, #0x64
      swi 6
      LSL   R0, R0, #0x18
      LSR   R5, R0, #0x18
park:
      mov r4, #0xff
      ldr r0, catchratecalcfunction
      mov pc, r0


.align 2
      catchratecalcfunction:      .word 0x0802D62A
      dword_2023FE8:                .word 0x02023FE8quickball.thumb
.global quickball_rate
quickball_rate:
main:
      mov r4, #10
      ldr r0, battleturncounter
      ldrb r0,
      cmp r0, #0x0
      bne ender
firstturn:
      add r4, #30
ender:
      ldr r0, catchratecalcfunction
      mov pc, r0


.align 2
      battleturncounter:      .word 0x03004fa3
      catchratecalcfunction:      .word 0x0802d62ahealball.thumb
.global healball_rate
healball_rate:
mov r4, #10
ldr r0, =0x802D62A
mov r15, r0
.ltorgduskball.thumb
.global duskball_rate
duskball_rate:
main:
      ldr r0, time
      ldrb r0,
      cmp r0, #0x6
      blt night
      cmp r0, #0x15
      bge night
day:
      mov r4, #10
      ldr r0, maptype
      ldrb r0,
      cmp r0, #0x4
      bne ender
night:
      mov r4, #35
ender:
      ldr r0, catchratecalcfunction
      mov pc, r0


.align 2
      time:                        .word 0x03005542
      maptype:                .word 0x02036e13
      catchratecalcfunction:      .word 0x0802d62asportball.thumb
.global sportball_rate

sportball_rate:
mov r4, #15
ldr r0, =0x802D62A
mov r15, r0
.ltorg统统找空位写入将它们的指针加到重定向后表格的末端(无需+1),就像这样:ball_routine_table:
.long 0x802D568
.long 0x802D598
.long 0x802D5AA
.long 0x802D5D8
.long 0x802D608
.long 0x802D5CA
.long 0x802D5CA
.long levelball_rate
.long moonball_rate
.long lureball_rate
.long friendball_rate
.long loveball_rate
.long fastball_rate
.long heavyball_rate
.long sportball_rate
.long duskball_rate
.long healball_rate
.long quickball_rate
.long healball_rate
.long parkball_rate值得注意的一点是,healball和cherishball直接公用同一个源码了,因为他们都没什么实际的捕捉率计算需求...

2.4 扩充扔球动画图片
2.4.1 变更球-素材对应方式
原版用了一个函数来转换,这里直接改为读取表格
在0x80EF53C编译并写入下面源码:.text
.align 2
.thumb
.thumb_func
.global ballchecker

main:
      push {lr}
      ldr r1, throwtablepositionstable
      add r0, r0, r1
      ldrb r0,
      pop {pc}

.align 2
      throwtablepositionstable:      .word 0x080EF53C应该一共是16字节,那么我们在0x80ef53c(就是紧跟在源码数据后)写入一张转换表。他的结构是类似于:00 04 03 01 00 02 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10........前面的不变,后面的按球编号添加。比如加入上面的那些所有球,就应该是:00 04 03 01 00 02 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19当然理论上说不按顺序也是可以的,只是这样厘清其他表格的顺序实在有点麻烦,所以一般就按上面的做法就可以。
最后别忘在80EF972和80F02D6分别写入00 00。

2.4.2 表格扩容
826056C是图片表,具体图片该是怎样尺寸可以直接到表格里找图片看。
结构:图片指针4字节+大小2字节(都一样,可以直接抄)+标签2字节(这个我是从0x1300开始给新的图片编标签(0x1300,0x1301,....),注意不要和别的可能同时出现的图片标签重复)
82605CC是色板表
结构:色板指针4字节+标签2字节(简单起见可以直接保持与图片标签一致)+00 00 2字节
82606F4是OBJ模板表
结构:图片标签2字节+色板标签2字节+2C 06 26 08 74 06 26 08 00 00 00 00 E0 06 26 08 D5 AB 04 08(只需每个模板的标签都与之前的图片、色板指针对应)
840BF48特效图片表
结构和之前的图片表相同,同样需要自己指定标签。个人建议这里就不要自己加新的图片了,直接用原版的那一张图就可以(可以看到原版所有的都公用一张图...)
840BFA8特效色板表
结构和之前的色板表相同,同样需要自己指定标签。既然前面的图片公用,色板当然也就公用吧。
840C0A4特效OBJ模板表
结构是图片标签2字节+色板标签2字节+C8 C9 3A 08 50 C0 40 08 00 00 00 00 FC 1C 23 08 0D 76 00 08(同样,要和特效图片、色板标签对应)
840C068特效图片编号表
这个表格也就是指定了哪个球对应了哪个特效图片(这里是指具体的小图):.balign 4
.global ball_particle_type
ball_particle_type:
.byte 0, 0, 0, 5, 1, 2, 2, 3, 5, 5, 4, 4, 0, 1, 2, 0, 3, 5, 4, 0, 4, 3, 1, 0, 0编译后也就是00 00 00 05 01 02 02 03 05 05 04 04 00 01 02 00 03 05 04 00 04 03 01 00 000=短线 1=星星 2=水泡 3=爱心 4=绿色叉叉 5=小绿色叉叉
840C074特效控制函数表
结构:函数指针4字节
这个编写起来很麻烦,而且多半也不如原版的来的精巧,不如直接抄原版的函数指针来扩充...

2.5 healball及parkball另外的修改
这2个球要起效仅仅靠计算捕捉率是做不到的,所以需要额外源码
2.5.1 healball
这个就是做出回血的特效。.text
.align 2
.thumb
.thumb_func
.global afterpoketranscalc

main:
      push {lr}
recycle:
      ldr r3, memcpy
      bl bxr3
calc:
      cmp r7, #0x64
      bne ender
      ldr r3, somevar
      ldrb r3,
      cmp r3, #14      /*ball index of heal ball here*/
      bne ender
healstuff:
      ldr r3, poke_quantity
      ldrb r1,
      mov r10, r1
      mov r1, #1
      strb r1,
heal_recycle:
      mov r3, pc
      add r3, #0x1d
      push {r3}
      push {r4-r7}
      mov r7, r10
      mov r6, r9
      mov r5, r8
      push {r5-r7}
      sub sp, sp, #4
      mov r1, #0
      mov r8, r1
      mov r1, r0
      mov r10, r1
      mov r6, sp
      ldr r3, healpoke
      b bxr3
heal_finish:
      ldr r3, poke_quantity
      mov r1, r10
      strb r1,
ender:
      pop {r3}
bxr3:
      bx r3

.align 2
      memcpy:                        .word 0x081e5e78+1
      somevar:                .word 0x0203fe00
      partyadr:                .word 0x02024284
      poke_quantity:                .word 0x02024029
      healpoke:                .word 0x080a0076+1修改一下其中的ball index以及之前所指定的内存空位为你所选用的,找空位写入后再8040B08写入00 4B 9F 46 + 源码指针。

2.5.2 parkball.text
.align 2
.thumb
.thumb_func
.global keepballcheck

main:
      mov r5, r3
      ldr r3, returnadr
      cmp r5, #17
      bne bxr3
      add r3, #4
bxr3:
      bx r3

.align 2
      returnadr:                              .word 0x0802D7A2+1找空位写入后在802D6EE写入40 4B 9F 46 12 F0 EB FD 13 F0 49 FA,并在802D7EE写入70 BD + 源码指针。

3 感谢
JPAN, knizz, gogojjtech, Bela, Jambo51, bond697

4 备注
可能会有人想到球的数量提升,背包容量却未提升显得很奇怪。这个只要用上面提到过的Ta之境界扩容技能机器的帖子中的背包扩容方法就可以,感兴趣可以自己试试(我的改版是预留了球和TM两个口袋的内存空间,不具备普遍性,就不拿出来了)。
下面是仅仅提升球容量的方法by kearnseyboy6:
**** Hidden Message *****



有任何错误请回帖指出

海のLUGIA 发表于 2017-1-14 11:50:40

{:5_doge18:}适合球控的改版生涯

s744865306 发表于 2021-1-9 14:11:53

绿宝石ROM还是火红ROM呢?

喵1喵 发表于 2021-6-21 16:40:49

路过回复一下,谢谢
页: [1]
查看完整版本: 【改版基础教程#1】增加新精灵球