|
本帖最后由 yandagui 于 2017-5-19 10:51 编辑 % a; f" f- f% S& s) |: a
2 A- ~6 y9 J& @, E8 a+ N
[FC][按键开关][修改教程]& w/ F) T* M" t7 `' Z
时间:2017.5.18, y0 X( m* `5 o! w3 G. |& d+ P9 s* o
作者:FlameCyclone
2 f8 w, B; J3 a工具:FCEUX 2.2.3,Hxd 1.7.7: Z% O, z6 c7 } I8 ^/ Q' B
ROM一个:魂斗罗(J)_Mapper4.nes
7 \9 I% Q- {1 S9 g0 e2 M. Q! _$ n" W5 z$ Q2 L
+ S0 a( S7 w6 v2 C
修改思路:
( ~/ @8 N6 t* ]2 w) I c2 z9 p1.先在$C000-$FFFF之间找到一段足够写程序的空白空间,通常是一段连续的FF或者00,是在找不到可以切页(切有空间的bank,注意用完切回原bank)或者扩容后再切页。) [+ A0 D+ T/ b
2.再查找一个系统里没有进行读写的内存地址作为开关,一般在$0000-$07FF之间查找。8 |. A9 e, e" q$ }+ k
3.查找暂停地址,一般暂停和运行时内存中有一个地址会变化。
; w- l4 s: n3 d$ [3 e+ H4.查找按键地址,找到单次按键,就是按一次变化一次的按键地址,按键一般有连续按键和单次按键。(如果没有单次可以自己想办法添加)。
8 g, e Q2 S4 h* R7 W0 n5.写按键开关程序,程序思路:当暂停时执行开关程序,非暂停时读取开关的状态,开启就干嘛干嘛,关闭就干嘛干嘛。
0 v/ w z* [8 @4 ?4 `6.写跳转,将按键程序跳转到按键开关程序。5 J- k* `9 P4 F$ ]& z
- _9 W H5 N! i3 p0 h4 t8 K) O0 a( D
程序流程图(假设暂停后,按上键切换无敌锁定的开关):' v/ p- z, k- }+ @3 ?5 k

# }' r$ _" C' y/ _8 `7 B( C; q( \& _8 q# J
接下来开始修改:
6 R% E5 I r- @* R4 J; n用FCEUX打开rom:! ^# v; k |- t* S& M
+ a; _2 n5 ]* C: @2 e
然后查找修改中需要的地址空间:/ B. r! p/ x. a3 B
这里我就不慢慢找了,直接给出:& y' l, x' E& n# L( j
空白空间:$FB30-$FBFF
0 k8 l5 a: y/ V; o7 q
5 m8 B; f$ X( P {+ T开关地址:$07A0:
. D; I, z {3 m; R / X" q' x0 V$ z+ y9 ?, P0 m
暂停地址:$0025;1 W2 P4 q. {3 I: o& R, p2 ?) {" A
单次按键地址:$00F5,X(X=0是为P1的$00F5,X=1是为P2的$00F6);3 x6 K7 \- b; i+ _* P2 n
按键程序断点: ?6 A! l2 W" u" |
打开调试器,设置写断点$00F5:
' W9 a8 u. B( w# p# o9 A 0 } ? n- I" M" V
4 g3 y( r: g P# j: Y( f
$ k- q/ g5 k& \3 i. A2 i' z) U
然后程序暂停了:
& n2 T+ I @$ x: a9 Y4 w
4 u) }( h& q7 N3 o* H0 ^) O# f% S" c9 a
由此知道按键程序断点在$C1EF;
n1 ~# X( a2 a然后开始编写程序:
5 a4 v- F& h. k. Y0 \推荐使用6502 Simulator编写,由于本篇教程需要的程序不算复杂,我就直接写机器码了:
% _6 I' r4 R+ r打开Hxd,新建一个文件:
+ i$ l& t% v& D! N3 d+ V0 I3 @$ ]- g
9 f) S1 k: u* m然后开始写程序:: W. ~9 Z. A9 r5 v" p8 F4 Q
95 F5 94 F1 48 A5 25 C9 01 D0 1F B5 F5 C9 08 D0 19 BD A0 07 29 08 D0 0A BD A0 07 09 08 9D A0 07 D0 08 BD A0 07 29 F7 9D A0 07 BD A0 07 29 08 F0 04 A9 03 95 B0 68 60. s% `6 @4 q) X& Y1 w; m1 J; P- c. }2 M% M

+ Z( i/ h4 A" E( g- l反编译解释:
. ?0 h9 C* s/ H* r+ m8 r' s95 F5 STA $F5,X 送入单次按键
& F& r1 i% z8 U }2 R* z94 F1 STY $F1,X 送入连续按键! P+ [ J; B" E! t" c' {
48 PHA 累加器A入栈
; x; H! V* a" u- kA5 25 LDA $25 读取暂停状态; s- o- w5 x8 b" W0 P. f" U. q
C9 01 CMP #$01 与暂停值#$01比较8 f. L& k( t+ F6 _; g' p- j# q
D0 1F BNE 不同则跳转到 开关读取/ y) a; N' w: _# Z4 s0 G o
; F, C0 s& F* e2 g' b9 A
读取按键值:, [ D2 v6 j& `8 z/ e" J8 c
B5 F5 LDA $F5,X 读取单次按键键值6 U4 L5 ^7 Y( J
C9 08 CMP #$08 与上键键值比较5 m8 @ a* u; ?. `1 S1 E. E/ C
D0 19 BNE不同则跳转到 开关读取- p( E" n& W! z) g* O$ E7 c
}: I, D# S1 L& N+ N: W& R; _( t
读取开关当前状态:
2 Z6 Z1 K( U4 r5 m% B( h+ h$ g: PBD A0 07 LDA $07A0 读取开关数据
. H* E" p1 r' ~) j8 L29 08 AND #$08 判断D4位是否设置
; W% E; _% P' a/ F0 mD0 0A BNE 不同则跳转到 清除开关的D4位
( s& H) p6 b/ M- D
Q7 {2 n4 N. i$ u( @设置开关的D4位:
9 s$ A2 X" v! n6 \: i% {BD A0 07 LDA $07A0,X 读取开关数据
1 Q2 ~# ?3 { ^/ k H" x09 08 ORA #$08 设置D4位
" Y8 K# V, A9 E. Y& X! l4 C0 q3 h9D A0 07 STA $07A0,X 送入开关
! y# w8 ?7 x( ND0 08 BNE 不同则跳转到 开关读取
0 v& X$ U8 F2 A6 G清除开关的D4位:
% w! @6 ]. O; g. PBD A0 07 LDA $07A0,X 读取开关数据# X8 K+ @+ C+ t5 c2 Z# s: m
29 F7 AND #$F7 清除D4位2 ]$ }8 ~# o7 i" n' o
9D A0 07 STA $07A0,X 送入开关- V& S$ d) A! l6 e' l
H7 L9 r. J! B1 Q开关读取:
- b9 O4 a" b, L2 oBD A0 07 LDA $07A0,X 读取开关数据
H" W- E- L; M( k; ]% |29 08 AND #$08 判断D4位是否设置
7 e9 f* e# o# O0 ^6 DF0 04 BEQ 如果未设置则跳转到 出栈并返回
) \$ K! z& T/ o) T
4 w/ O+ ?$ a; k" o无敌锁定:
/ U/ B: K" x1 H% `9 y: E+ I4 [. zA9 03 LDA #$05 取一个立即数#$03
/ e& V! Z# _6 W95 B0 STA $B0,X 送入无敌地址
; \% G9 L: a4 @' f+ g- w2 y2 }5 w, {; G& F& W+ `
出栈并返回:7 {& d, r# C: e
68 PLA 累加器A出栈
5 s& R! P0 q7 R1 M1 F. |60 RTS 子程序返回7 R8 K- f& s/ S6 c H+ t" A* ]
+ s$ L& Q' D3 g" _
8 @! ^& X- s1 Q$ L1 J% n
然后把程序粘贴到NES内存$FB50对应的ROM地址:: o3 c( L5 b) l) S; }: K
单击右键:
2 S9 C5 X2 F$ @2 U! ]# |7 J
' y& G d% w# f9 v! N, X2 K
6 a& }. s x' s! v8 a % T- D- x w; L9 g( T

6 a1 `- C* z5 q4 \: z7 H- W5 [3 ]$ a" T! w
然后跳转到按键程序地址$C1EF对应的ROM地址:
6 [# k& u+ z7 @! C# e- n 2 ?2 r: e1 ?6 P: }9 Z& l4 l
Ctrl+A:+ d3 \. |+ m2 {7 m3 {( s
, ~1 a9 i& z1 W
* X5 p8 a ^0 U

+ W/ R3 X8 t; y$ J3 K. P
9 T! s9 ?' C$ X单击右键:( G2 e( \ g0 J

$ L2 ^ N3 P8 z1 j4 c 9 K5 Q5 T) w4 G
把源指令修改为20 50 FB EA2 N$ U( c; Y2 ^8 k0 M5 S- ~
JSR $FB50 跳转到$FB50# O* G0 c9 Q/ [, A: _. O7 z
NOP 无动作. j" q. U% `0 b3 F
注:) ^* F/ o+ U8 v* ]5 i4 w
如果不修改最后的F1,那么系统会把F1当做操作码来执行,后果不可预知,所以改为NOP才正确。% e8 D. h5 J2 E+ a
6 f* R' W3 ~& l- w& N: f6 e: E
然后双击断点取消断点,再点击运行按钮继续运行:
8 a- b5 F0 R( D% S6 I8 F
9 J; a8 K) i( h1 K0 p. Q暂停后如下:& V5 D3 a1 c% V7 N3 h: h3 w7 S

5 W7 c( w' n/ i% V$ c按一次上键:
r/ _9 Z' C+ b9 l1 `9 ]3 n m无敌马上生效了,取消暂停后也一样保持无敌不会掉:
' X6 o9 N; o% e ! ?% r% d1 n6 M, K P
暂停后然后再按一次上键
' [$ J; S% n% o# W7 y5 b' w! F此时无敌还没有消失,因为暂停时无敌时间不会减,所以不会消失.
! [" m# w; Q: H$ T$ B- e 6 m6 ]+ Z. p ]$ E5 O6 g
按下开始键取消暂停:1 @3 S$ b$ h" t8 i) S
马上无敌就失效了:2 A# a8 r/ |$ x

8 n9 i3 Y2 M2 W4 Z& s0 R( r
) [" l# c# T& N, l8 |( F+ b- h# ?测试成功,没有什么BUG,接下来保存文件:
& J% v n1 e0 t/ @' L4 B
6 p8 s* H6 P0 D5 a* c9 Y5 L
7 J5 @- Z' V' ]( X k/ b2 _到此为止修改结束。2 d, i8 i4 g E
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
评分
-
1
查看全部评分
-
|