分享到新浪微博 分享到QQ空间 打印

[其他] 如何把ASM技术应用到口袋改版ROM中【09.06.10更新】

如何把ASM技术应用到口袋改版ROM中【09.06.10更新】

ASM代码在脚本中的应用


当我们写的脚本被编译器编译之后,它将转化为游戏能够识别的16进制命令.这些命令都是游戏在设计时本身就默认存在的,凭借这一强大的命令库,我们能够实现很多东西.但假如我们要的命令根本不存在呢?在回答这个问题之前我们需要稍稍了解下ASM了.GBA的运行原理和电脑很类似,它也是由一个处理器来执行各种运算并依靠内存来临时储存数据,同时也有自己的显卡等设备.在电脑上,我们知道处理器最终是在运行机器码,而机器码则是用汇编代码编译的.汇编可以认为是人写的最底层的程序代码.对于GBA也是一样,ROM在运行时也会被解释为机器码.而通过汇编语言,我们同样可以写出机器码.我们通常说的ASM,就是指自己写汇编代码编译成机器码嵌入ROM.
《口袋》的GBA系列作品绝对是被研究最多的GBA游戏,这使得我们能够破译游戏是如何调用原始的机器码.这样,就能够自由的在游戏中调用自己写的汇编程序了.
因为汇编程序是能够访问到GBA底层的,所以我们可以通过对数据的操作创造出新的命令.而在脚本中呼出ASM代码,就能够使用自己创造的命令了.

那么如何在脚本中呼出ASM代码呢?我们通常只需要一个命令:callasm.
格式:
callasm 0x[地址]

这里的地址指的是嵌入ASM代码的ROM地址.
我们假设位于0x80000有一段我们之前写好转换的ASM代码,它实现了"改变对话中字的颜色"这一功能.于是:
复制内容到剪贴板
代码:
#org @1
lock
faceplayer
callasm 0x80000
message @2 MSG_NORMAL
release
end
如上,我们呼叫ASM代码完成了一个功能,表面看来就像special命令一样.

注1:有时需要不止1次呼叫ASM代码以实现特定的过程,比如我们在message命令后再次呼叫另一个ASM代码以换回文字颜色.
注2:ASM代码有两种,其中的THUMB模式最为常见.呼叫THUMB模式的ASM代码需要给ASM地址+1,如callasm 0x80001.这是必须的,否则便会出错.

下面,我们以我写的一个时间读取ASM为例,演示如何把转换好的ASM应用到实际.
首先明确一下时间读取ASM的作用.
我们都知道火叶中没有内置时钟,所以也没有和时间相关的事件.那我们想把事件和时间关联,怎么办呢?这里我提供一个方法:依靠游戏进行时间(即累计游戏时间).
但新的问题出现了,火叶中没有读取累计游戏时间的命令啊.
本次的ASM代码即可实现它,并将小时数存入了变量0x800D中.
小小的看一下源码吧:
复制内容到剪贴板
代码:
.text
.align 2
.thumb
.thumb_func
.global asm1

main:  ;FR_ONLY
  push {r0-r1, lr}
  ldr r0, .PLAYER_DATA ;读取玩家信息
  ldr r0, [r0]
  ldr r1, .VAR1
  ldrh r0, [r0, #0xE] ;找到并读取其中的游戏时间小时数
  strh r0, [r1] ;存入变量
  pop {r0-r1, pc}


.align 2
.PLAYER_DATA:
  .word 0x0300500C
.VAR1:
  .word 0x020270B6 + (0x800D * 2)
编译得到:
复制内容到剪贴板
代码:
03B5034800680349C089088003BDC0460C500003D0700302
通常的ASM代码我们都能得到这种的,所以不必操心如何编译.

现在打开16进制工具载入ROM.

选一处空闲位置,把ASM代码复制进去.复制时要注意两点:

1.复制一定要用覆盖的方式,而不是插入.否则会导致后面的数据整体偏移,游戏运行时必然会出错.我习惯用的是WinHex,大家如果用UE的话也一定注意,如果缺少这项功能的话可以先插入再在其附近删除等量空位,保证没有偏移.
2.由于THUMB模式要求,ASM代码的起始地址末位必须是0,4,8,C之一.如0x80000可以,而0x80003不行(这和前面说的+1不矛盾,这里指的是实际地址而不是呼叫地址)

记下ASM代码的位置.

现在开始编写相应的脚本.
我们依靠ASM代码得到的小时数是存在变量中的,实际使用时可以直接用它做计算.这里为了简明,我们用对话把小时数显示.
不过变量值是无法直接显示出来的,我们需要借助一个buffer系的命令.该组命令是用来将游戏内部信息转换为外部信息的,比如将PM内部编号转化为名称.
复制内容到剪贴板
代码:
#org @1
lock
faceplayer
callasm 0x[地址]+1'注意了,HEX插入的地址必须+1,这是THUMB模式必须的
buffernumber 0x00 0x800D'buffernumber命令可以把HEX换成DEC
message @2 0x2
release
end

#org @2
= You've been playing for [buffer1] hours!' [buffer1] 表示第一个被buffernumber转换的值
现在我们用XSE写入这段脚本,并用一个人物触发脚本:


果然,我们的ASM代码成功的读取了游戏时间!
附件: 您所在的用户组无法下载或查看附件


想死你们了!

TOP

如果玩的时间超过了var的最大值……

TOP

引用:
原帖由 roywillow 于 2009-6-10 20:08 发表
如果玩的时间超过了var的最大值……
你去死吧- -不要把溢出的精神发扬到这上面,我坚信游戏本身也不支持那么长时间的……


想死你们了!

TOP

真的么……它本身不支持这么长时间……如果超出了会怎样???报销掉??那么人家辛辛苦苦的记录…………

TOP

引用:
原帖由 roywillow 于 2009-6-12 17:44 发表
真的么……它本身不支持这么长时间……如果超出了会怎样???报销掉??那么人家辛辛苦苦的记录…………
我记得内存里给小时的位置也只有2byte吧……达到最大值需要连续近7年半每天24小时的不间断游戏啊……


想死你们了!

TOP

我玩不到把他给我儿子……然后给孙子…………



灌水了……

sorry……

再也不敢了……


麻烦来点新东西讨论一下……

TOP