2015-03-16 | 来源:互联网 | 小编:admin | 人看过
关于FC的手柄控制
当FC的程序需要得到手柄的按键状态时,需要写$4016的最低位为1,将手柄按键的状态载入到一个串行的寄存器中,
接着写$4016的最低位为0,载入完成。读取按键状态时,是1位1位读出来的。读$4016为读取手柄1,读$4017为手柄2
,而且值都在最低位。读取的顺序为A,B,SELECT,START,UP,DOWN,LEFT,RIGHT,也就是说在按键状态载入完成
后,第一次读$4016($4017)最低位得到的是手柄1(2) A键的状态(0为没按下,1为按下),第二次读自动变为 B键的状
态,第三次读为SELECT键的状态,以此类推。
实例分析
ROM:Contra Force (U).nes
工具:FCEUXD SP,UltraCompare Professional
目标:将这个游戏改成可以连跳的版本
下$4016写断点,可以得到附近的程序,如下
$FF97:A2 00 LDX #$00
$FF99:20 C8 FF JSR $FFC8;第一次读按键状态
{
START:
$FFC8:A0 01 LDY #$01
$FFCA:8C 16 40 STY $4016 ;[4016]=1,载入手柄按键状态
$FFCD:88 DEY
$FFCE:8C 16 40 STY $4016 ;[4016]=0,载入结束
$FFD1:A0 08 LDY #$08 ;循环8次
;下面BNE到这里
$FFD3:AD 16 40 LDA $4016 ;A=[4016]
$FFD6:85 04 STA $04 ;[04]=A
$FFD8:4A LSR A ;A>>1
$FFD9:05 04 ORA $04 ;A=A|[04]
$FFDB:4A LSR A ;A>>1
;以下C代表C标志位
;A=[4016]
;C=(A|(A>>1))&1,通过$FFDB处的指令,[4016]的最低位被送到了C标志位
;A=(A|(A>>1))>>1
$FFDC:36 00 ROL $00,X ;9位(加上C标志位)循环左移
; 1位 8位 8位 1位
;(C _ [00+X])->([00+X] _ C)
$FFDE:AD 17 40 LDA $4017 ;手柄2
$FFE1:85 05 STA $05
$FFE3:4A LSR A
$FFE4:05 05 ORA $05
$FFE6:4A LSR A
$FFE7:36 01 ROL $01,X
$FFE9:88 DEY
$FFEA:D0 E7 BNE $FFD3
$FFEC:60 RTS
;结束[00+X]=0 0 0 0 0 0 0 0
; A, B, SELECT, START, UP, DOWN, LEFT, RIGHT
}
$FF9C:A2 02 LDX #$02
$FF9E:20 C8 FF JSR $FFC8;第二次读按键状态
$FFA1:A5 00 LDA $00;[00]为手柄1第一次读出的按键状态
$FFA3:C5 02 CMP $02;[02]为手柄1第二次读出的按键状态
$FFA5:D0 1A BNE $FFC1;跳则说明按键状态不稳定,并让[40]=[41]=0
$FFA7:A5 01 LDA $01
$FFA9:C5 03 CMP $03
$FFAB:D0 14 BNE $FFC1;手柄2
$FFAD:A2 00 LDX #$00
$FFAF:20 B3 FF JSR $FFB3;手柄1和手柄2的按键状态分别传到[40]和[41]
{
$FFB2:E8 INX
$FFB3:B5 00 LDA $00,X
$FFB5:A8 TAY
$FFB6:55 FA EOR $FA,X;此时[FA]为上次调用时手柄的状态
$FFB8:35 00 AND $00,X
;A=(A^[$FA+X])&[00+X] A的某一位为1仅当对应的按键的状态由0变至1时
$FFBA:95 40 STA $40,X; ^
$FFBC:95 F8 STA $F8,X; -|
$FFBE:94 FA STY $FA,X;令[FA+X]为此次调用时,手柄的按键状态
$FFC0:60 RTS;第一次返回到$FFB2,正好令X加1,这段程序被调用了两次
;第一次处理手柄1,第二次处理手柄2
}
$FFC1:A9 00 LDA #$00
$FFC3:85 40 STA $0040
$FFC5:85 41 STA $0041
$FFC7:60 RTS
下$FA读断点,可以来到
$BFEE:A2 01 LDX #$01
$BFF0:B5 FA LDA $FA,X
$BFF2:A8 TAY
$BFF3:3D 71 03 AND $0371,X
$BFF6:95 42 STA $42,X;按键状态被传到了[42+X]
$BFF8:98 TYA
$BFF9:9D 71 03 STA $0371,X
$BFFC:CA DEX
$BFFD:10 F1 BPL $BFF0
$BFFF:60 RTS
下$42读断点可以来到
$A302:B5 42 LDA $42,X
$A304:29 0F AND #$0F
$A306:A8 TAY
$A307:20 38 F3 JSR $F338
$A30A:85 00 STA $00
$A30C:B5 42 LDA $42,X
$A30E:15 40 ORA $40,X
$A310:29 F0 AND #$F0;
$A312:85 01 STA $01;
$A314:20 78 91 JSR $9178
$A317:F0 1D BEQ $A336
$A319:A5 00 LDA $00
$A31B:29 0F AND #$0F
$A31D:D0 08 BNE $A327
$A31F:BD AA 07 LDA $07AA,X
$A322:29 70 AND #$70
$A324:4C 30 A3 JMP $A330
.很
.长 硬看会郁闷的。。。
.的
$A4D6:A5 42 LDA $42
$A4D8:05 43 ORA $43
$A4DA:29 10 AND #$10;手柄1或手柄2按了START键?
$A4DC:F0 02 BEQ $A4E0
$A4DE:E6 5B INC $5B
$A4E0:60 RTS
但应该是这段程序中的某一个跳转决定了是否可以继续往上跳跃,修改只要知道程序走向就可以了,没必要硬看。
对$42下条件读断点,条件为$42==#80,等角色站着时,按A键,就会中断,用Trace Logger,选Browse,存为1.txt,
Start Logging,把$42读条件断点禁用了,然后对$A302下条件执行断点,条件为$42==#0,执行,等再次中断时,点Stop
Logging,将$A302断点也给禁用了。
将角色跳到空中,等角色处于下落阶段时,将$A302条件执行断点启用,用Hex Editor,将$42写80,Trace Logger中,
选Browse,存为2.txt,Start Logging,执行,等再次中断时,点Stop Logging。
用UltraCompare Professional比较1.txt,和2.txt,会发现程序流程的几处不同,其中
$A3A6:95 CD STA $CD,X
$A3A8:A9 20 LDA #$20
$A3AA:1D AA 07 ORA $07AA,X
$A3AD:9D AA 07 STA $07AA,X
$A3B0:29 40 AND #$40
$A3B2:D0 27 BNE $A3DB;这个就是关键跳转,如果跳到A3DB的话,就不能连续跳跃了,故NOP掉
$A3B4:B5 CD LDA $CD,X
$A3B6:29 02 AND #$02
$A3B8:D0 16 BNE $A3D0
$A3BA:A5 01 LDA $01
$A3BC:29 80 AND #$80
让程序在$A302处中断,切换到Hex Editor,找到A3B2,右击,选Go Here In Rom File,然后把D0 27修改为EA EA,点File,选
Save Rom,修改完成。
上一篇:6502基础知识