先从这个变身程序开始说起吧。比起另一段变身程序,这个就简单多了:如果敌人ID大于等于09,则敌人被踩之后就会变身。两种游鱼的ID分别为$0A(绿鱼)和$0B(红鱼),被踩之后会分别变成00(绿乌龟)和01(红乌龟),颜色正好不变

就这么简单?

对,就这么简单~说到这里,这个bug的原理就已经解释完了。
那你给我解释一下,快乐云($11)、飞鱼($14)和炮台炮弹($33)怎么被踩之后不变身呢?
别急嘛,让我慢慢说

在变身程序之前,还有一段是用来处理“一踩就死”的敌人的:如果敌人ID是$14(飞鱼)、$08(炮弹)、$33(炮台炮弹)、$0C(火球)、$05(锤子龟)、$11(快乐云)、$07(章鱼),那么敌人就会被直接踩死,其中,前4种敌人被踩死的得分都是200分,后3种敌人的得分则依次为1000、800、1000分,这是通过对寄存器Y设置不同的值,达到读取不同得分设置值的目的的(这在上次的帖子中也提到过)。小提示:锤子龟和章鱼对应的Y值不同(分别是1和3),这意味着可以简单地把这两种敌人改成不同的得分。
且慢!火球?你告诉我这种敌人可以踩死?开玩笑呢?明明一踩上去就受伤了!?
嗯,这说明前面肯定还有程序,是用来处理“不能踩”的敌人的

这里就有必要把代码写出来了,因为有些事情需要看着代码才好解释:
LDY $16,X ;读取敌人ID存入寄存器Y
CPY #$2E ;如果是蘑菇等道具类敌人,就转到“吃掉”的程序,跳转代码略
;一些无关代码,从略
CPY #$12 ;刺猬
BEQ #$4E ;跳转到“可以踩”的程序(纳尼?)
CPY #$0D ;食人花
BEQ #$7D ;跳转到“受伤”的程序
CPY #$0C ;火球
BEQ #$79 ;跳转到“受伤”的程序
CPY #$33 ;炮台炮弹
BEQ #$42 ;跳转到“可以踩”的程序
CPY #$15 ;如果ID>=$15(包括火焰、Boss等)
BCS #$71 ;跳转到“受伤”的程序
可以看到,这段程序以$15为分界,将敌人分成了“可以踩”和“不能踩”这样前后两个部分,“可以踩”的部分又排除掉了$0D和$0C,“不能踩”的部分则排除了$2E和$33。由于这里判断敌人“不能踩”之后直接跳转到“受伤”的程序了,因此对于火球,也就没有机会再去执行“踩敌人”的程序了,后面的“可以踩死”的设置就是个摆设。那为什么还要写“火球可以踩死”的判断?这跟本帖说的bug有点关系,先留个悬念,一会解释。
不过……说真的,这个刺猬又是怎么回事?
实际上,看看这部分代码的套路,这里的本意应该是将刺猬也从“可以踩”的敌人中排除的,然而,由于用的是分支跳转指令,刺猬所在指令的位置需要向后跳$81(十进制129)个字节,这超过了向后跳转的$7F(十进制127)的上限了……如果真的写了$81,那就变成向回跳127个字节了(视为负数)

所以,只好改掉了。
那刺猬要怎么设置成“不能踩”呢?没办法,只好在后面补一段代码:如果ID=$12,则跳转到“受伤”的程序……这个程序补在了“踩敌人”程序前面的位置,实际上是把刺猬又从“可以踩”的敌人中重新排除了。
这么写当然没什么问题,不过……前面的那次比较,从“可以踩”的敌人中排除出一个“可以踩”的敌人?(12<15)这不是多此一举么?
嗯,看来这次修复工作的指令空间已经确定了,由刺猬提供一部分可以删除的指令,然后就可以修bug了。