Download as rtf, pdf, or txt
Download as rtf, pdf, or txt
You are on page 1of 4

A bit more info about the All Forts Wrong warp:

If we jump to $9057, we end up clearing the ram through $06FF -> $0000,
excluding the stack ($01xx)
We then increment the world number and end up in world 8, but this time
because the ram has been cleared properly, the world map appears
normal, not glitched, and we can’t bypass the autoscroller #1.

So we at least need to jump to $905C, which leaves the ram as it was, and
this is what ends up corrupting the world map and the reason passing
over the autoscroller doesn’t pull you in.

The reason sometimes your inventory is corrupted is because starting at


$905C, there is code there that stores your score from the status bar
within the level, into a different area in ram. There are quite a few things
in SMB3 that have two different RAM addresses, one for "in level", and one
for when you exit the level or die - “out of level". They usually only get set
to one another when you enter the level, or you exit the level normally,
through the normal game code routines.

So the game wants to store the score that you had at the end of the level
the “in level” score, to the “out of level” score Ram address. However,
depending on where we jump to in this section of code, the indexing into
this part of the code so it knows whether to either store mario or luigi’s
score, and where in the ram it should store it, can go very wrong to the
point the inventory gets overwritten with incorrect data. 
Normally, if player is Mario, the X register gets set to 0, and Y gets set to
$#1F. Then at $9080, we load the “in level” score to the Accumulator.
This is done by Loading A indexed with X, at address $0715, then at
$9083 store it to the “out of level” ram at address #$7D9F. This is
achieved via storing to address $7D80 indexed with Y, with Y being #$1F
if player is mario, this yields address $7D9F.  There is then a loop to copy
the next two bytes as well, as the score is 3 bytes next to each other.

Note that in RAM, mario’s Inventory items, Score cards, and Score, are all
stored next to each other in Ram
$7D80 - $7D9B = Mario’s inventory
$7D9C - $7D9E = Mario’s Cards
$7D9F - 7DA1 = Mario’s score

Code starting at $9071:

LDX Player_Current     ;  X=0 if mario, or 1 if Luigi, Player_current is at


$0726
LDA #$1F                    ; correct index for memory offset to Mario’s score
CPX $#00
BEQ $907D                 
CLC
ADC #$23                   ; Basically corrects index if player is Luigi by adding
#$23 to the offset of #$1F

Code at $907D:
TAY                             ; A ->Y,  Y now holds offset to score
LDX #$00                   ; X = 0

Code at $9080
LDA $0715,X             ; Load players score (“in level”) into A
STA $7D80, Y           ; Store A into memory address $7D80, indexed with
#$1F = $7D9F (Mario’s score “out of level”)
INY                           ; Increment Y (Next byte of Mario’s score)
INX                           ; Increment X (Next byte of players score)
CPX #$03               
BNE $9080               ; While X <> 3, loop back to $9080 (This means it
copies across the three bytes of the player score(in level) into Mario’s
score (out of level)

LDA #$80
STA $04F4               ; Stop Music
INC $0727               ; Increment World_Num, i.e go to next world!
JMP $84A0             ; Jump to $84A0 i.e Initialise the world map.

Note that these last two lines of the code is where the skip to world 8
comes from.

So depending on where we jump to in the code, the Accumulator, the X


register and the Y register could hold completely different values to what
they are meant to have. if we jump a bit further into the loop, the offsets
into memory will contain whatever was previously held in the X and Y
registers, and the Accumulator will hold what ever it had before we
jumped. 
This is why in some of the runs done so far, we have seen glitched items
in both the inventory, the cards, and the score.

One other thing: The reason we end up back as hammer mario (or what
ever powerup we entered 7-1 in)  is because we have skipped the normal
level ending routine. The powerup status in the “out of level” ram is still
set to hammer suit (because we had the hammer suit when we entered 7-
1). Although we end up small mario when we execute the glitch,  because
we skipped the part of the end level routine which sets the "in level"
powerup status to the “out of level” power status, as far as the game
engine is concerned, we never lost the hammer suit! So on the overworld
map when it loads the “out of level” powerup status, it is still set to
hammer suit. Yay for glitches!

Things yet to be worked out: 


• Whether the loop at $9080 can somehow be used to store some clouds to
the inventory
• The most stable point to jump to in the code, which can be achieved
EASILY in 7-1, no one wants to loose 40 minutes of gameplay. We have to
at least jump to $905C, to ensure the glitched map allows the autoscroller
skip. If we jump here, we will not have a glitched up inventory/cards/score,
which could be desirable because this seems to create extra lag for yet
unknown reasons. If we jump to $9080, we will have the glitched
inventory/cards/score. We need to find spots for easy shell kills that give
us good values, that don’t end up crashing because of a KIL opcode or a
jump to byte-misaligned code. I’m currently working on that right now,
probably going to use $9071 or there abouts so no lag is encountered. 

EDIT:
Made a twitch video demonstrating using $9071 as our point to jump to.
We keep our inventory we had before we entered 7-1, keep our hammer
suit, and don’t get any glitched out items, cards, or scores.

-KabAudio 5 October 2019 5.15PM AEST

After a bit more work and research, I have decided to change the jump
address to $908D instead of $9071. The main reason is so the top waling
Koopa can be killed against the left ? block from the left side, setting its
value to #$8D. 
So the values we want are now 20 8D 90. Note that from the code:

Code at $908C
LDA #$80                ; Music value to stop music playing
STA $04F4               ; Store “stop music” value to $04F4 (Sound_QMusic1)
INC $0727               ; Increment World_Num, i.e go to next world!
JMP $84A0             ; Jump to $84A0 i.e Initialise the world map.

If we jump to $908D, then execution starts with the byte $80, which is an
unofficial opcode i.e we are ‘byte misaligned’. 
$80 is a two byte opcode, and has the effect of a two byte NOP
instruction. 
So the next instruction to execute is at $908F, which is $F4, again, an
unofficial opcode. Thankfully, again, this is a two byte opcode, and has the
effect of a two byte NOP instruction. 
This means our next byte to execute is $9091, which is our INC $0727
instruction as in the above code.  Execution then continues normally, next
code to execute being the JMP $84A0, which is a jump to the “initialise the
world map” code. From here the code executes normally, however, due to
the ram between $06FF and $0000 excluding the stack ($01xx) not being
set to zero which should have occurred at $9057:

Code at $9057
LDY #$06                                                       ; Load Y with #$06
JSR Clear_Ram_Through_Zero_Page           ; Jump to subroutine that clears
all RAM between $YYFF and $0000, and skips the stack i.e clear $06FF -
$0200, and $00FF - $0000

Because we skipped this section of code, this is what results in the world
map being all corrupted when we jump there. It is the sole reason that the
autoscroller can be skipped.

Im currently working on a faster setup however the last shell is pixel


perfect. It is easier than the any% fastest setup, because of the alignment
of the shell as it is thrown. 
I will update when I complete another stream and do another highlight.

-KabAudio, 5 October 2019 11PM AEST

1.36

256 IGT

1.39.27easysetup

1.35.21easysetiup
253IGT

I have made a shell throw demonstation setup that saves around 15-17
seconds compared to my last highlight, but the last shell is frame perfect.
thankfully it's not double frame perfect like Kirua's any% world record, in
other worlds, once you enter the pipe holding the shell, you can just
release B and then it comes down to hitting the A button on the correct
frame so the shell that flies through the air passes x position #$90 just as
we hit A (actually i think its the frame before this from memory, cause the
controller is read at the end of the frame)
Realistically I doubt anyone would go for this in a run 40 minutes in, but
hey, may as well demonstrate the concept. Even though my execution of
this was not perfect, after practising for a while I calculated a time save of
around 15 - 17 seconds compared to the consistent setup.

You might also like