|
本帖最后由 jiangzhengwenjz 于 2015-2-25 11:37 编辑
由于本人还是个改版新手,平时课业繁忙只有寒暑假有空,知识掌握的不够多,也缺乏经验,不足错漏之处恳请指正。由于是手记,不是教程,为防误人子弟,不得转载。
从上周开始有在学习一些新的技术,现在把它贴出来,可以说是个简单的应用了。这些内存地址仅限于火红。
背景介绍:
说到选择性删除,第一点就是“选择”。查阅JPAN关于special的研究可知,special 0x9F可以呼出选择精灵的效果。不仅如此,其还会把得到的值(0~5)存进变量0x8004,而0x8004的内存地址可以用公式计算,所以我们认为这个方案是简单可行的。其值+1即为精灵编号(1~6)。
然后便是“删除”了。依然是根据JPAN的小程序。当然代码的解释我们等会儿再谈。- .text
- .align 2
- .thumb
- .thumb_func
- Delete_func: Push {r0-r4, lr}
- Ldr r0, .Var_addr
- Ldrh r0, [r0, #0x0]
- Cmp r0, #0x5
- Bgt end
- Ldr r1, .Party_addr
- Mov r2, #0x64
- Mul r2, r0
- Add r1, r2, r1
- Add r3, r1, #0x0
- Add r3, #0x64
- main_loop: mov r2, #0x0
- mov r4, #0x0
- cmp r0, #0x5
- beq delete_loop
- add r0, #0x1
- copy_loop: Ldr r4, [r3, #0x0]
- str r4, [r1, #0x0]
- add r3, #0x4
- add r1, #0x4
- add r2, #0x4
- cmp r2, #0x64
- beq main_loop
- b copy_loop
- delete_loop: str r4, [r1, #0x0]
- add r1, #0x4
- add r2, #0x4
- cmp r2, #0x64
- bne delete_loop
- end: pop {r0-r4, pc}
- .align 2
- .Var_addr: .word 0x020370c0
- .Party_addr: .word 0x02024284
复制代码 当然仅仅这样肯定不够,我们来个简单应用(一段脚本,虽然没有什么实际作用,单纯地选择然后删除精灵):
脚本段:- '---------------
- #org @start
- msgbox @string1 0x2 '"Select a Pokemon. "
- special 0x9F
- waitstate
- callasm 0x875D1B1
- release
- end
- '---------
- ' Strings
- '---------
- #org @string1
- = Select a Pokemon.
复制代码 其中我把thumb码编译于75D1B0,这从脚本上看应该是显然的。
值得注意的是waitstate,必不可少。
显然这段脚本有个bug,那就是就算减到1只精灵还可以继续减。这个问题如何解决呢?利用countpokemon命令即可。当然这样得到的值将被存在0x800D中,而且是1~6,不是0~5。
利用这个命令,配合一些判断和跳转,应该是可以达成一些应用了,这里不多啰嗦了。
然后是对thumb代码的解释了。
解释:
Delete_func只会运行一次,首先检测0x8004中的值是不是在0~5之间,否则直接跳转到end,这是佷容易看出来的。
后面的loop部分也不难看懂,我说说我的理解。
在main_loop,一方面将r4清零,一方面执行检测,看r0是不是5了,如果是,直接删除精灵即可。(跳转到delete_loop)。如果不是,进入copy循环,r2担当计数器的功能,因为每个精灵占有100字节,达成的效果是将后面的精灵数据向前移动。每次r1和r3都会增长4,这样达成的效果是逐次移动,由于有r2的存在,可以确保移动100字节。注意到在main_loop中每次r0不是5时,r0都会+1,因此r0其实也担当了计数器功能,确保移动精灵数量正确。当r0为5时,进入delete_loop,依然是用r2做计数器的老套路,把r1中指向的内存数据逐次写入0即可。在进入copy_loop之后r1的值虽然改变,其实是合理的,本质上是删除重复的那只精灵罢了。
后记:
简单归简单,但对我等改版新手来说并不是那么容易,昨天真心花了好久才搞定。不足之处,还请指出探讨。(如果不想在脚本中执行检测,请参考Hackmew的代码。)
|
|