News
Welcome to NeoRHDN! This place is still a work-in-progress, so pardon the construction...

Chat on Discord
Views: 800,603
Sections: Documents | Utilities | ROM Hacks | Games | Translations | Homebrew | Fonts | Community
Site: Main | Rules/FAQ | Discord | Memberlist | Latest posts | Stats | Ranks | Online users
12-03-24 05:26 PM
Guest: Register | Login

0 users currently in Hacking Discussion | 8 bots

Main - Hacking Discussion - Super Mario Bros. Fixes (3)

Pages: 1 2 3

SMB2J-2Q
Posted on 10-08-24 08:24 PM, in Link | ID: 1061

Red Goomba

Level: 9

Posts: 30/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
Posted by ShaneM
On the original, when Bowser turns to face the player he flips but in an odd way. It makes him go into the ax at times. SMAS fixes this and SMB Deluxe GBC partially fixes this by making him properly turn. I wrote this code from scratch to fix it, it was made with SMB2J in mind but should work on SMB1; credit me if borrowed:


;new RAM addresses
StarMusBWSRFlag = $4c
BowserHTimer = $0788



ResetMDr: lda EnemyFrameTimer,x ;if timer set here expired,
beq GetPRCmp ;branch to next section
jsr PlayerEnemyDiff ;get horizontal difference between player and bowser,
bmi MoveBRght ;and branch if bowser to the right of the player
MoveBLft: lda BowserHTimer ;SM load Bowser's horizontal flip timer
bne DNMB+5 ;SM if Bowser just turned rightward, branch
lda #$02 ;otherwise load value to
sta Enemy_MovingDir,x ;set Bowser to move and face to the left
lda StarMusBWSRFlag ;SM load Bowser's flip flag (note this is only set if Bowser has flipped from left to right)
beq BBoundChk ;SM if not set, branch to continue with Bowser's boundary check
lda Enemy_X_Position,x ;SM get Bowser's front horizontal coordinate
sec ;SM
sbc #$10 ;SM take away ten from it thus giving the illusion of his front and rear flipping
sta Enemy_X_Position,x ;SM then store as Bowser's new front horizontal coordinate
dec StarMusBWSRFlag ;SM clear Bowser's flip flag
lda #$10 ;SM load value to
sta BowserHTimer ;SM set Bowser's horizontal flip timer
bne GetPRCmp ;SM then branch unconditionally
MoveBRght: lda BowserHTimer ;SM load Bowser's horizontal flip timer
bne BBoundChk ;SM if Bowser's horizontal flip timer is still going, branch
lda #$01 ;load value to
sta Enemy_MovingDir,x ;set Bowser to move and face to the right
lda StarMusBWSRFlag ;SM load Bowser's flip flag
bne DNMB ;SM branch if flag already set to avoid wrong enemy placement
lda Enemy_X_Position,x ;SM get Bowser's front horizontal coordinate
clc ;SM
adc #$10 ;SM add ten to horizontal coordinate
sta Enemy_X_Position,x ;SM then store as Bowser's new front horizontal coordinate
inc StarMusBWSRFlag ;SM set Bowser's flip flag (this gets the ball rolling)
lda #$10 ;SM load value to
sta BowserHTimer ;SM set Bowser's horizontal flip timer
DNMB: lda #$02
sta BowserMovementSpeed ;set movement speed
lda #$20
sta EnemyFrameTimer,x ;set timer here
sta BowserFireBreathTimer ;set timer used for bowser's flame
BBoundChk: lda Enemy_X_Position,x
cmp #$bf ;(SM original value #$c8) if bowser to the right past a certain point,
bcs HammerChk ;skip ahead to some other section


I also discovered that on 1-2 of SMB2J if you collect the Starman and run to the sideways warp pipe the SFX will not play most of the time if still invincible. SMB Deluxe and SMAS fixes this. I don't know offhand if Starman + sideways pipe ever occurs in the same room on SMB1. I don't think so hence this oversight. My code is from scratch, credit me if borrowed:


PipeDwnS: ldy StarInvincibleTimer ;SM load invincibility timer
bne PlayPipeDwnS ;SM branch if set to play SFX (fixes SFX not playing on 1-2)
lda Player_SprAttrib ;check player's attributes
bne PlyrPipe ;if already set, branch, do not play sound again
PlayPipeDwnS:
ldy #Sfx_PipeDown_Injury
sty Square1SoundQueue ;otherwise load pipedown/injury sound
PlyrPipe: ora #%00100000


Yes, the Bowser fix does take up a lot of space, but it's worth it IMO. -ShaneM

Hi Shane,

Awesome fixes!

~Ben (SMB2J-2Q)

ShaneM
Posted on 10-09-24 02:33 AM, in (rev. 4 of 10-09-24 05:33 PM by ShaneM) Link | ID: 1070

Micro-Goomba

Level: 6

Posts: 15/19
EXP: 847
Next: 60

Since: 08-21-24

Last post: 36 days
Last view: 36 days
Posted by SMB2J-2Q

Hi Shane,

Awesome fixes!

~Ben (SMB2J-2Q)


Thanks. I tried to make it more dynamic than SMAS. It should be more responsive and better coded than that version. If you try it out do share your thoughts.

EDIT:

I revised the play pipe down SFX routine because A is immediately ORA'd by #$20 and stored as the new player sprite attribute. This sets the background priority bit and whatever else was previously loaded. The new fix corrects any data previously loaded in A to Player_SprAttrib:


PipeDwnS: lda Player_SprAttrib ;check player's attributes
ldy StarInvincibleTimer ;SM load invincibility timer
bne PlayPDwnS ;SM branch if set to play SFX (fixes SFX not playing on 1-2)
cmp #$00 ;SM check to see if any sprite attributes are set
bne PlyrPipe ;if already set, branch, do not play sound again
PlayPDwnS:ldy #Sfx_PipeDown_Injury
sty Square1SoundQueue ;otherwise load pipedown/injury sound
PlyrPipe: ora #%00100000


-ShaneM



ShaneM
Posted on 10-10-24 03:27 AM, in (rev. 2 of 10-10-24 03:28 AM by ShaneM) Link | ID: 1082

Micro-Goomba

Level: 6

Posts: 16/19
EXP: 847
Next: 60

Since: 08-21-24

Last post: 36 days
Last view: 36 days
Posted by SMB2J-2Q
In SMAS, the "ContinueGame" routine has been slightly changed to this:

ContinueGame:
jsr LoadAreaPointer ;update level pointer with
lda #$01 ;actual world and area numbers, then
sta PlayerSize ;reset player's size, status, and
lsr ;SMAS diff: shift bit right to initialize player status
sta PlayerStatus ;SMAS diff
inc FetchNewGameTimerFlag ;set game timer flag to reload
lda #$00 ;game timer from header
sta TimerControl ;also set flag for timers to count again
sta GameEngineSubroutine ;reset task for game core
sta OperMode_Task ;set modes and leave
lda #$01 ;if in game over mode, switch back to
sta OperMode ;game mode, because game is still on
GameIsOn: rts

I would like to know if it is safe (because of the INC statement) to remove the LDA #$00 before the TimerControl flag because I placed an LSR before the PlayerStatus flag to change 1 to 0?

~Ben


It would be more efficient to just use Y register like this:


ContinueGame:
jsr LoadAreaPointer ;update level pointer with
ldy #$01 ;actual world and area numbers, then
sty PlayerSize ;reset player's size, status, and
dey ;SMAS diff: shift bit right to initialize player status
sty PlayerStatus ;SMAS diff
inc FetchNewGameTimerFlag ;set game timer flag to reload
sty TimerControl ;also set flag for timers to count again
sty GameEngineSubroutine ;reset task for game core
sty OperMode_Task ;set modes and leave
iny ;if in game over mode, switch back to
sty OperMode ;game mode, because game is still on
GameIsOn: rts



But to answer your question, yes - it is safe to remove the LDA #$00. INC affects incrementing memory (RAM), not an immediate value loaded into the accumulator. That instruction also affects the negative and zero flag. INY and INX affects said registers directly though. -ShaneM


SMB2J-2Q
Posted on 10-10-24 04:30 AM, in Link | ID: 1083

Red Goomba

Level: 9

Posts: 31/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
Posted by ShaneM
Posted by SMB2J-2Q
In SMAS, the "ContinueGame" routine has been slightly changed to this:

ContinueGame:
jsr LoadAreaPointer ;update level pointer with
lda #$01 ;actual world and area numbers, then
sta PlayerSize ;reset player's size, status, and
lsr ;SMAS diff: shift bit right to initialize player status
sta PlayerStatus ;SMAS diff
inc FetchNewGameTimerFlag ;set game timer flag to reload
lda #$00 ;game timer from header
sta TimerControl ;also set flag for timers to count again
sta GameEngineSubroutine ;reset task for game core
sta OperMode_Task ;set modes and leave
lda #$01 ;if in game over mode, switch back to
sta OperMode ;game mode, because game is still on
GameIsOn: rts

I would like to know if it is safe (because of the INC statement) to remove the LDA #$00 before the TimerControl flag because I placed an LSR before the PlayerStatus flag to change 1 to 0?

~Ben


It would be more efficient to just use Y register like this:


ContinueGame:
jsr LoadAreaPointer ;update level pointer with
ldy #$01 ;actual world and area numbers, then
sty PlayerSize ;reset player's size, status, and
dey ;SMAS diff: shift bit right to initialize player status
sty PlayerStatus ;SMAS diff
inc FetchNewGameTimerFlag ;set game timer flag to reload
sty TimerControl ;also set flag for timers to count again
sty GameEngineSubroutine ;reset task for game core
sty OperMode_Task ;set modes and leave
iny ;if in game over mode, switch back to
sty OperMode ;game mode, because game is still on
GameIsOn: rts



But to answer your question, yes - it is safe to remove the LDA #$00. INC affects incrementing memory (RAM), not an immediate value loaded into the accumulator. That instruction also affects the negative and zero flag. INY and INX affects said registers directly though. -ShaneM



Shane,

Thank you again; much appreciated!

~Ben

SMB2J-2Q
Posted on 10-18-24 04:57 AM, in (rev. 6 of 10-18-24 05:10 AM by SMB2J-2Q) Link | ID: 1128

Red Goomba

Level: 9

Posts: 33/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
In SMAS, there are two chunks of code dealing with the floatey numbers routine...

The first one, at 03:E084, is used in most cases...

CODE_03E084:
STA $0110,x ; $03:E084: 9D 10 01
LDA #$30 ; $03:E087: A9 30
STA $0138,x ; $03:E089: 9D 38 01
LDA $0238,x ; $03:E08C: BD 38 02
STA $0124,x ; $03:E08F: 9D 24 01
LDA $03AE ; $03:E092: AD AE 03
STA $011A,x ; $03:E095: 9D 1A 01
PHY ; $03:E098: 5A
TXA ; $03:E099: 8A
ASL A ; $03:E09A: 0A
TAY ; $03:E09B: A8
LDA $021A,x ; $03:E09C: BD 1A 02
STA $E4 ; $03:E09F: 85 E4
LDA $79,x ; $03:E0A1: B5 79
STA $E5 ; $03:E0A3: 85 E5
REP #$20 ; $03:E0A5: C2 20
LDA $E4 ; $03:E0A7: A5 E4
SEC ; $03:E0A9: 38
SBC $42 ; $03:E0AA: E5 42
STA $0E50,y ; $03:E0AC: 99 50 0E
SEP #$20 ; $03:E0AF: E2 20
STA $011A,x ; $03:E0B1: 9D 1A 01
PLY ; $03:E0B4: 7A
RTS ; $03:E0B5: 60


But, a similar chunk of code at address 03:E04F is used for the floatey numbers when a power-up is collected. This address is only ever used within the HandlePowerUpCollision routine.

CODE_03E04F:
STA $0110,x ; $03:E04F: 9D 10 01
LDA #$30 ; $03:E052: A9 30
STA $0138,x ; $03:E054: 9D 38 01
LDA $0238,x ; $03:E057: BD 38 02
STA $0124,x ; $03:E05A: 9D 24 01
LDA $03AE ; $03:E05D: AD AE 03
STA $011A,x ; $03:E060: 9D 1A 01
LDA $021A,x ; $03:E063: BD 1A 02
STA $ED ; $03:E066: 85 ED
LDA $79,x ; $03:E068: B5 79
STA $EE ; $03:E06A: 85 EE
PHX ; $03:E06C: DA
TXA ; $03:E06D: 8A
ASL A ; $03:E06E: 0A
TAX ; $03:E06F: AA
REP #$20 ; $03:E070: C2 20
LDA $ED ; $03:E072: A5 ED
SEC ; $03:E074: 38
SBC $42 ; $03:E075: E5 42
STA $0E50,x ; $03:E077: 9D 50 0E
SEP #$20 ; $03:E07A: E2 20
PLX ; $03:E07C: FA

CODE_03E07D:
RTS ; $03:E07D: 60

Why was it done this way for the power-up collection, and how effective was it? As far as I know, in the original floatey number code at 03:E084, there is one instance of the Y offset being used and also both the X and Y registers being stored to the stack (the Y register was never used in the original NES code), but for the same code at 03:E04F the X offset is always used (the X register is also stored to the stack).

Because of how similar these code chunks are, I wonder if the original NES SMB floatey number code can be tweaked for when dealing with power-ups being collected?

~Ben

ShaneM
Posted on 10-24-24 12:02 AM, in (rev. 7 of 10-24-24 06:58 AM by ShaneM) Link | ID: 1188

Micro-Goomba

Level: 6

Posts: 17/19
EXP: 847
Next: 60

Since: 08-21-24

Last post: 36 days
Last view: 36 days
Posted by SMB2J-2Q
Posted by ShaneM
Cool find, SMB2J-2Q!

Is that limited to SMB1 or The Lost Levels as well? I know the FDS SMB2J has a check for that under "CheckInvalidWorldNum:". On that version, it cannot be done after "FindAreaPointer:" because sm2data4.asm is loaded over that old code be it identical.

Hi Shane,

Time for a new hack question.

In Super Mario All-Stars, in the x-4 levels, the Podoboo moves up higher than in the NES original but only up to the bottom edge of the status bar. May I ask you what I'd do to fix this, so that the Podoboo goes up high but only to the status bar's bottom edge?

So far, I remember you re-coded this:

MovePodoboo:
lda EnemyIntervalTimer,x ;check enemy timer
bne PdbM ;branch to move enemy if not expired
jsr InitPodoboo ;otherwise set up podoboo again
lda PseudoRandomBitReg+1,x ;get part of LSFR
ora #%10000000 ;set d7
sta Enemy_Y_MoveForce,x ;store as movement force
and #%00001111 ;mask out high nybble
ora #$07 ;SM FIX set for at least seven intervals
sta EnemyIntervalTimer,x ;store as new enemy timer
lda #$f8 ;SM FIX podoboo moves higher up in SMAS
sta Enemy_Y_Speed,x ;set vertical speed to move podoboo upwards
PdbM: jmp MoveJ_EnemyVertically ;branch to impose gravity on podoboo


I also wanted to share this from SMAS:

InitPodoboo:
lda #$d0 ;set enemy position to below
sta Enemy_Y_Position,x ;the bottom (at 208th pixel) of the screen (why was it $02?)
lda #$01
sta Enemy_Y_HighPos,x
sta EnemyIntervalTimer,x ;set high vertical byte and timer for enemy
lsr
sta Enemy_State,x ;initialize state for enemy
jmp SmallBBox

UPDATE: SUCCESS! The Podoboos now rise up to the edge of the status bar before going back down, with the original unaltered attributes for MovePodoboo.

In the NES SMB, both the Podoboo's Y position and high Y position were checked first and both set to $02 before the enemy interval timer was set to $01 via the LSR. But in SMAS this was changed so the Podoboo's Y position was explicitly checked first, now set to $d0 (208th pixel) before the high Y position and enemy interval timer were set, now both set to $01.

Here's a screenshot of the result of this fix:


~Ben


Actually, your code is inaccurate. The SNES version actually adds more code at the end to check Podoboo's vertical position to determine if to launch him anew. Also, SNES Podoboo jumps up inside the status bar at times and has SFX. I wrote this code from scratch to emluate SMAS' behavior on this 6502 program, credit me if borrowed:


MovePodoboo: lda EnemyIntervalTimer,x ;check enemy timer
bne MoveJ_EnemyVertically ;branch to move enemy if not expired
lda Enemy_Y_HighPos,x ;SM obtain Podoboo's vertical high byte
lsr ;SM compare it to visibly highest offscreen value
bne PodobooJump ;SM branch if greater than 1 or less than to reinitiate Podoboo
lda Enemy_Y_Position,x ;SM get Podoboo's vertical low byte coordinate
cmp #$e4 ;SM check against if it's right at the bottom of the screen
bcc MoveJ_EnemyVertically ;SM branch if less than to continue moving enemy to prevent disappearing object
PodobooJump: lda #Sfx_EnemyStomp ;SM otherwise load value to play smack enemy sound
sta Square1SoundQueue ;SM and store it here
jsr InitPodoboo ;set up Podoboo again
lda PseudoRandomBitReg+1,x ;get part of LSFR
ora #%10000000 ;set d7
sta Enemy_Y_MoveForce,x ;store as movement force
and #%00001111 ;mask out high nybble
ora #$06 ;set for at least six intervals
sta EnemyIntervalTimer,x ;store as new enemy timer
lda #$f8 ;SM original value was #$f9
sta Enemy_Y_Speed,x ;set vertical speed to move podoboo upwards and impose gravity on podoboo
MoveJ_EnemyVertically:
ldy #$1c ;set movement amount for podoboo/other objects


That's all that needs to be changed. Nothing in "InitPodoboo:"





Posted by SMB2J-2Q
I found SMAS has a new separate enemy slot check just for Piranha Plants, which is a reversed version of the existing FindEmptyEnemySlot routine in that X is loaded with the value pointing to the last enemy slot and is decremented with each loop until it goes to $FF, and also replaces the existing JSR to the FindEmptyEnemySlot routine within the WarpPipe routine.
https://github.com/Maseya/SMAS-Disassembly/blob/master/Assembly/SMB1/code/b03/ParseAreaData.asm

Here is that code:

FindPiranhaPlantSlot:
ldx #$05 ;start at last enemy slot
PPChkLp: clc ;clear carry flag by default
lda Enemy_Flag,x ;check enemy buffer for nonzero
beq ExitPPChk ;if zero, leave
dex
cpx #$ff ;if nonzero, check next value
bne PPChkLp
ExitPPChk: rts ;if all values nonzero, carry is set

For some reason, it disallows Mario from destroying it with fireballs, so what else should I do to make it work with fireballs again (other than removing this new code)?

UPDATE: According to TakuikaNinja at the old RHDN, in the old SMB fixes thread he replied to, he suggested that this new code doesn't have to be used. Instead, under the WarpPipe routine, under the JSR to FindEmptyEnemySlot, let's do this...

WarpPipe:
... jsr FindEmptyEnemySlot ;check for an empty moving buffer space
bcc DrawPPlant ;if found, draw the piranha plant
lda Enemy_Flag,x ;check if the enemy buffer is full
bne DrawPipe ;if so, skip to draw pipe
DrawPPlant:
jsr GetAreaObjXPosition ;get horizontal pixel coordinate


~Ben (SMB2J-2Q)




Change the ldx #$04 to ldx #$05 to get your outcome. I wouldn't recommend it unless you do more ASM work because powerups, vine and flagpole flag share the sixth slot on vanilla SMB1/2J:

adc #$1c ;then add $1c or 28 bytes to it
tay ;to use fireball's bounding box coordinates
ldx #$04

FireballEnemyCDLoop:
stx $01 ;store enemy object offset here


-ShaneM


SMB2J-2Q
Posted on 10-25-24 08:16 PM, in (rev. 5 of 10-25-24 08:44 PM by SMB2J-2Q) Link | ID: 1235

Red Goomba

Level: 9

Posts: 34/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
Posted by ShaneM
Posted by SMB2J-2Q
Posted by ShaneM
Cool find, SMB2J-2Q!

Is that limited to SMB1 or The Lost Levels as well? I know the FDS SMB2J has a check for that under "CheckInvalidWorldNum:". On that version, it cannot be done after "FindAreaPointer:" because sm2data4.asm is loaded over that old code be it identical.

Hi Shane,

Time for a new hack question.

In Super Mario All-Stars, in the x-4 levels, the Podoboo moves up higher than in the NES original but only up to the bottom edge of the status bar. May I ask you what I'd do to fix this, so that the Podoboo goes up high but only to the status bar's bottom edge?

So far, I remember you re-coded this:

MovePodoboo:
lda EnemyIntervalTimer,x ;check enemy timer
bne PdbM ;branch to move enemy if not expired
jsr InitPodoboo ;otherwise set up podoboo again
lda PseudoRandomBitReg+1,x ;get part of LSFR
ora #%10000000 ;set d7
sta Enemy_Y_MoveForce,x ;store as movement force
and #%00001111 ;mask out high nybble
ora #$07 ;SM FIX set for at least seven intervals
sta EnemyIntervalTimer,x ;store as new enemy timer
lda #$f8 ;SM FIX podoboo moves higher up in SMAS
sta Enemy_Y_Speed,x ;set vertical speed to move podoboo upwards
PdbM: jmp MoveJ_EnemyVertically ;branch to impose gravity on podoboo


I also wanted to share this from SMAS:

InitPodoboo:
lda #$d0 ;set enemy position to below
sta Enemy_Y_Position,x ;the bottom (at 208th pixel) of the screen (why was it $02?)
lda #$01
sta Enemy_Y_HighPos,x
sta EnemyIntervalTimer,x ;set high vertical byte and timer for enemy
lsr
sta Enemy_State,x ;initialize state for enemy
jmp SmallBBox

UPDATE: SUCCESS! The Podoboos now rise up to the edge of the status bar before going back down, with the original unaltered attributes for MovePodoboo.

In the NES SMB, both the Podoboo's Y position and high Y position were checked first and both set to $02 before the enemy interval timer was set to $01 via the LSR. But in SMAS this was changed so the Podoboo's Y position was explicitly checked first, now set to $d0 (208th pixel) before the high Y position and enemy interval timer were set, now both set to $01.

Here's a screenshot of the result of this fix:


~Ben


Actually, your code is inaccurate. The SNES version actually adds more code at the end to check Podoboo's vertical position to determine if to launch him anew. Also, SNES Podoboo jumps up inside the status bar at times and has SFX. I wrote this code from scratch to emluate SMAS' behavior on this 6502 program, credit me if borrowed:


MovePodoboo: lda EnemyIntervalTimer,x ;check enemy timer
bne MoveJ_EnemyVertically ;branch to move enemy if not expired
lda Enemy_Y_HighPos,x ;SM obtain Podoboo's vertical high byte
lsr ;SM compare it to visibly highest offscreen value
bne PodobooJump ;SM branch if greater than 1 or less than to reinitiate Podoboo
lda Enemy_Y_Position,x ;SM get Podoboo's vertical low byte coordinate
cmp #$e4 ;SM check against if it's right at the bottom of the screen
bcc MoveJ_EnemyVertically ;SM branch if less than to continue moving enemy to prevent disappearing object
PodobooJump: lda #Sfx_EnemyStomp ;SM otherwise load value to play smack enemy sound
sta Square1SoundQueue ;SM and store it here
jsr InitPodoboo ;set up Podoboo again
lda PseudoRandomBitReg+1,x ;get part of LSFR
ora #%10000000 ;set d7
sta Enemy_Y_MoveForce,x ;store as movement force
and #%00001111 ;mask out high nybble
ora #$06 ;set for at least six intervals
sta EnemyIntervalTimer,x ;store as new enemy timer
lda #$f8 ;SM original value was #$f9
sta Enemy_Y_Speed,x ;set vertical speed to move podoboo upwards and impose gravity on podoboo
MoveJ_EnemyVertically:
ldy #$1c ;set movement amount for podoboo/other objects


That's all that needs to be changed. Nothing in "InitPodoboo:"





Posted by SMB2J-2Q
I found SMAS has a new separate enemy slot check just for Piranha Plants, which is a reversed version of the existing FindEmptyEnemySlot routine in that X is loaded with the value pointing to the last enemy slot and is decremented with each loop until it goes to $FF, and also replaces the existing JSR to the FindEmptyEnemySlot routine within the WarpPipe routine.
https://github.com/Maseya/SMAS-Disassembly/blob/master/Assembly/SMB1/code/b03/ParseAreaData.asm

Here is that code:

FindPiranhaPlantSlot:
ldx #$05 ;start at last enemy slot
PPChkLp: clc ;clear carry flag by default
lda Enemy_Flag,x ;check enemy buffer for nonzero
beq ExitPPChk ;if zero, leave
dex
cpx #$ff ;if nonzero, check next value
bne PPChkLp
ExitPPChk: rts ;if all values nonzero, carry is set

For some reason, it disallows Mario from destroying it with fireballs, so what else should I do to make it work with fireballs again (other than removing this new code)?

UPDATE: According to TakuikaNinja at the old RHDN, in the old SMB fixes thread he replied to, he suggested that this new code doesn't have to be used. Instead, under the WarpPipe routine, under the JSR to FindEmptyEnemySlot, let's do this...

WarpPipe:
... jsr FindEmptyEnemySlot ;check for an empty moving buffer space
bcc DrawPPlant ;if found, draw the piranha plant
lda Enemy_Flag,x ;check if the enemy buffer is full
bne DrawPipe ;if so, skip to draw pipe
DrawPPlant:
jsr GetAreaObjXPosition ;get horizontal pixel coordinate


~Ben (SMB2J-2Q)




Change the ldx #$04 to ldx #$05 to get your outcome. I wouldn't recommend it unless you do more ASM work because powerups, vine and flagpole flag share the sixth slot on vanilla SMB1/2J:

adc #$1c ;then add $1c or 28 bytes to it
tay ;to use fireball's bounding box coordinates
ldx #$04

FireballEnemyCDLoop:
stx $01 ;store enemy object offset here


-ShaneM



Shane,

Thank you for the heads-up on the Podoboo and Piranha Plant slot check. I will likely leave these bits of code alone.

I also wanted to let you know that in SMAS, when you die via falling down a hole, the player's size and status are also reset, and inline with your suggested changes of using the Y register in both ContinueGame and Shroom_Flower_PUp, I added these here.

HoleDie: inx ;set flag in X for player death
ldy GameEngineSubroutine
cpy #$0b ;check for some other routine running
beq ChkHoleX ;if so, branch ahead
ldy #$ff ;SM FIX set master timer control
sty TimerControl ;SM FIX to halt timers
ldy DeathMusicLoaded ;check value here
bne HoleBottom ;if already set, branch to next part
iny
sty EventMusicQueue ;otherwise play death music
sty DeathMusicLoaded ;and set value here
sty PlayerSize ;SMAS fix: reset player's size...
dey ;SMAS fix
sty PlayerStatus ;SMAS fix ...and status
HoleBottom: ldy #$06
sty $07 ;change value here
ChkHoleX: cmp $07 ;compare vertical high byte with value set here


Thank you,



Ben (SMB2J-2Q)

ShaneM
Posted on 10-26-24 04:20 AM, in (rev. 2 of 10-26-24 04:20 AM by ShaneM) Link | ID: 1240

Micro-Goomba

Level: 6

Posts: 18/19
EXP: 847
Next: 60

Since: 08-21-24

Last post: 36 days
Last view: 36 days
Posted by SMB2J-2Q


Thank you for the heads-up on the Podoboo and Piranha Plant slot check. I will likely leave these bits of code alone.

I also wanted to let you know that in SMAS, when you die via falling down a hole, the player's size and status are also reset, and inline with your suggested changes of using the Y register in both ContinueGame and Shroom_Flower_PUp, I added these here.

HoleDie: inx ;set flag in X for player death
ldy GameEngineSubroutine
cpy #$0b ;check for some other routine running
beq ChkHoleX ;if so, branch ahead
ldy #$ff ;SM FIX set master timer control
sty TimerControl ;SM FIX to halt timers
ldy DeathMusicLoaded ;check value here
bne HoleBottom ;if already set, branch to next part
iny
sty EventMusicQueue ;otherwise play death music
sty DeathMusicLoaded ;and set value here
sty PlayerSize ;SMAS fix: reset player's size...
dey ;SMAS fix
sty PlayerStatus ;SMAS fix ...and status
HoleBottom: ldy #$06
sty $07 ;change value here
ChkHoleX: cmp $07 ;compare vertical high byte with value set here


Thank you,



Ben (SMB2J-2Q)


On NES, Player size and status are changed during the lives screen. It does nothing game-wise adding that code there. Sure, it resets the values but the player is already offscreen, hence it makes no difference. SNES must be set up differently to need it for some reason. I would say it's a waste of space and resources, unless you can pinpoint a certain function adding that would do.



SMB2J-2Q
Posted on 10-27-24 03:18 AM, in Link | ID: 1249

Red Goomba

Level: 9

Posts: 35/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
Posted by ShaneM
Posted by SMB2J-2Q


Thank you for the heads-up on the Podoboo and Piranha Plant slot check. I will likely leave these bits of code alone.

I also wanted to let you know that in SMAS, when you die via falling down a hole, the player's size and status are also reset, and inline with your suggested changes of using the Y register in both ContinueGame and Shroom_Flower_PUp, I added these here.

HoleDie: inx ;set flag in X for player death
ldy GameEngineSubroutine
cpy #$0b ;check for some other routine running
beq ChkHoleX ;if so, branch ahead
ldy #$ff ;SM FIX set master timer control
sty TimerControl ;SM FIX to halt timers
ldy DeathMusicLoaded ;check value here
bne HoleBottom ;if already set, branch to next part
iny
sty EventMusicQueue ;otherwise play death music
sty DeathMusicLoaded ;and set value here
sty PlayerSize ;SMAS fix: reset player's size...
dey ;SMAS fix
sty PlayerStatus ;SMAS fix ...and status
HoleBottom: ldy #$06
sty $07 ;change value here
ChkHoleX: cmp $07 ;compare vertical high byte with value set here


Thank you,



Ben (SMB2J-2Q)


On NES, Player size and status are changed during the lives screen. It does nothing game-wise adding that code there. Sure, it resets the values but the player is already offscreen, hence it makes no difference. SNES must be set up differently to need it for some reason. I would say it's a waste of space and resources, unless you can pinpoint a certain function adding that would do.




Shane,

Thank you again for the heads-up; I will remove that code, then.

I tried your new Podoboo fix and it works perfectly!

New question: how were you able to resolve the five-enemy onscreen limit for your SMB1 and SMB2J builds? For example, (1) some enemies not appearing when they really should, or (2) Piranha Plants that disappear when you hit a nearby power-up block?

~Ben (SMB2J-2Q)

ShaneM
Posted on 10-28-24 12:23 AM, in (rev. 4 of 10-28-24 12:48 AM by ShaneM) Link | ID: 1255

Micro-Goomba

Level: 6

Posts: 19/19
EXP: 847
Next: 60

Since: 08-21-24

Last post: 36 days
Last view: 36 days
Posted by SMB2J-2Q


Thank you again for the heads-up; I will remove that code, then.

I tried your new Podoboo fix and it works perfectly!

New question: how were you able to resolve the five-enemy onscreen limit for your SMB1 and SMB2J builds? For example, (1) some enemies not appearing when they really should, or (2) Piranha Plants that disappear when you hit a nearby power-up block?

~Ben (SMB2J-2Q)


The following is with SMB2J in mind. It wasn't one thing in particular but many:

1) I changed how powerups are loaded in the enemy slot from always being in slot 6 to using the first available slot but still preferring slot 6. This is in line with SMB Deluxe GBC and SMB Special. This makes it so multiple powerups can be on screen at once which also fixes disappearing powerups. Reference posts #112 & #113 on the old thread on RHDN (page 6) to see how this was done.

2) I simply moved some enemies over one spot, which isn't noticeable.

3) I did some ASM stuff with springboards to get them to load in the sixth slot at times or specifially an always-free slot on worlds A-D. A-3 was coded differently. Here's what I added in SM2DATA4 with a jump from SM2MAIN:


HWSpringChk:
jsr GetLrgObjAttrib
lda AreaPointer ;SM get pointer for the next area
cmp #$26 ;SM if World C-3
beq C3Chk ;SM then take branch
cmp #$2b ;SM if not on World D-2
bne FindSlot ;SM move on to find empty space in enemy object buffer
D2Chk: lda WorldNumber ;SM fetch the current world number
cmp #$01 ;SM if on World B,
beq B1Chk ;SM branch to do check
cmp #$03 ;SM if not on World D,
bne FindSlot ;SM branch to continue on with normal routine
B1Chk: ldx #$00 ;SM start at first enemy slot
EmptyChkLoop2:
lda Enemy_ID,x ;SM load enemy buffer
cmp #$2f ;SM check for vine
beq ConJSChk ;SM if found, branch to use current X offset
inx ;SM otherwise, increment X offset
cpx #$05 ;SM if under sixth slot,
bne EmptyChkLoop2 ;SM check next value
FindSlot: jsr FindEmptyEnemySlot ;find empty space in enemy object buffer
bcs NoJs ;if none, cancel
ConJSChk: jsr GetAreaObjXPosition ;get horizontal coordinate for jumpspring
sta Enemy_X_Position,x ;and store
lda CurrentPageLoc ;store page location of jumpspring
sta Enemy_PageLoc,x
jsr GetAreaObjYPosition ;get vertical coordinate for jumpspring
sta Enemy_Y_Position,x ;and store
sta Jumpspring_FixedYPos,x ;store as permanent coordinate here
lda #JumpspringObject
sta Enemy_ID,x ;write jumpspring object to enemy object buffer
ldy #$01
sty Enemy_Y_HighPos,x ;store vertical high byte
inc Enemy_Flag,x ;set flag for enemy object buffer
ldx $07
lda #$68 ;draw metatiles in two rows where jumpspring is
sta MetatileBuffer,x
lda #$69
sta MetatileBuffer+1,x
NoJs: rts
C3Chk: lda CurrentPageLoc ;SM load the current page on C-3
cmp #$0a ;SM if on page 10 or greater
bcs FindSlot ;SM continue on with normal routine
ldx #$05 ;SM otherwise load value for sixth enemy slot
bne ConJSChk ;SM and continue on with the normal routine with this specific value


4. I hardcoded how Piranha Plants are loaded in certain stages because sometimes it would be impossible even in the sixth slot to load them all. This took a lot of space and is in my current build.

5. Certain levels like 1-2 and 3-1 I had to hardcode because there's a spot on 1-2 for example with 4 powerups, a vine and platforms (treated as enemies) on the same screen and I had to make them all load a specific way.

As you can see, gameplay-wise it's nice, but took a lot of work. And also keep in mind this is SMB2J. I hope it helps. It would probably be easier to wait for a more finalized version to be released when I do. -ShaneM




SMB2J-2Q
Posted on 10-30-24 01:18 AM, in (rev. 2 of 10-30-24 01:18 AM by SMB2J-2Q) Link | ID: 1269

Red Goomba

Level: 9

Posts: 36/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
Posted by ShaneM
Posted by SMB2J-2Q


Thank you again for the heads-up; I will remove that code, then.

I tried your new Podoboo fix and it works perfectly!

New question: how were you able to resolve the five-enemy onscreen limit for your SMB1 and SMB2J builds? For example, (1) some enemies not appearing when they really should, or (2) Piranha Plants that disappear when you hit a nearby power-up block?

~Ben (SMB2J-2Q)


The following is with SMB2J in mind. It wasn't one thing in particular but many:

1) I changed how powerups are loaded in the enemy slot from always being in slot 6 to using the first available slot but still preferring slot 6. This is in line with SMB Deluxe GBC and SMB Special. This makes it so multiple powerups can be on screen at once which also fixes disappearing powerups. Reference posts #112 & #113 on the old thread on RHDN (page 6) to see how this was done.

2) I simply moved some enemies over one spot, which isn't noticeable.

3) I did some ASM stuff with springboards to get them to load in the sixth slot at times or specifially an always-free slot on worlds A-D. A-3 was coded differently. Here's what I added in SM2DATA4 with a jump from SM2MAIN:


HWSpringChk:
jsr GetLrgObjAttrib
lda AreaPointer ;SM get pointer for the next area
cmp #$26 ;SM if World C-3
beq C3Chk ;SM then take branch
cmp #$2b ;SM if not on World D-2
bne FindSlot ;SM move on to find empty space in enemy object buffer
D2Chk: lda WorldNumber ;SM fetch the current world number
cmp #$01 ;SM if on World B,
beq B1Chk ;SM branch to do check
cmp #$03 ;SM if not on World D,
bne FindSlot ;SM branch to continue on with normal routine
B1Chk: ldx #$00 ;SM start at first enemy slot
EmptyChkLoop2:
lda Enemy_ID,x ;SM load enemy buffer
cmp #$2f ;SM check for vine
beq ConJSChk ;SM if found, branch to use current X offset
inx ;SM otherwise, increment X offset
cpx #$05 ;SM if under sixth slot,
bne EmptyChkLoop2 ;SM check next value
FindSlot: jsr FindEmptyEnemySlot ;find empty space in enemy object buffer
bcs NoJs ;if none, cancel
ConJSChk: jsr GetAreaObjXPosition ;get horizontal coordinate for jumpspring
sta Enemy_X_Position,x ;and store
lda CurrentPageLoc ;store page location of jumpspring
sta Enemy_PageLoc,x
jsr GetAreaObjYPosition ;get vertical coordinate for jumpspring
sta Enemy_Y_Position,x ;and store
sta Jumpspring_FixedYPos,x ;store as permanent coordinate here
lda #JumpspringObject
sta Enemy_ID,x ;write jumpspring object to enemy object buffer
ldy #$01
sty Enemy_Y_HighPos,x ;store vertical high byte
inc Enemy_Flag,x ;set flag for enemy object buffer
ldx $07
lda #$68 ;draw metatiles in two rows where jumpspring is
sta MetatileBuffer,x
lda #$69
sta MetatileBuffer+1,x
NoJs: rts
C3Chk: lda CurrentPageLoc ;SM load the current page on C-3
cmp #$0a ;SM if on page 10 or greater
bcs FindSlot ;SM continue on with normal routine
ldx #$05 ;SM otherwise load value for sixth enemy slot
bne ConJSChk ;SM and continue on with the normal routine with this specific value


4. I hardcoded how Piranha Plants are loaded in certain stages because sometimes it would be impossible even in the sixth slot to load them all. This took a lot of space and is in my current build.

5. Certain levels like 1-2 and 3-1 I had to hardcode because there's a spot on 1-2 for example with 4 powerups, a vine and platforms (treated as enemies) on the same screen and I had to make them all load a specific way.

As you can see, gameplay-wise it's nice, but took a lot of work. And also keep in mind this is SMB2J. I hope it helps. It would probably be easier to wait for a more finalized version to be released when I do. -ShaneM





Hi Shane,

I am working on incorporating your revised code for power-ups, and I want to know if what I did for the separate Mushroom and Fire Flower power-ups is correct? See below.


Flower_PUp: ;SM use Y register here instead
ldy #Sfx_PowerUpGrab
sty Square2SoundQueue ;play the power-up sound
ldy PlayerStatus ;if player status = small, branch
beq Shroom_PUp
cpy #$02
beq NoPUp ;SM if player status not fiery, leave
ldy #$00 ;SM set player size to large
sty PlayerSize ;SM
ldy #$02 ;SM set player status to fiery
sty PlayerStatus
jsr GetPlayerColors ;run sub to change colors of player
lda #$0c ;set value to be used by subroutine tree (fiery)
bne UpToFiery ;jump to set values accordingly

Shroom_PUp:
ldy PlayerStatus
cpy #$01
beq NoPUp
iny ;set player status to super
sty PlayerStatus
lda #$09 ;set value to be used by subroutine tree (super)

UpToFiery:
ldy Player_State ;set value to be used as new player state
jmp SetPRout ;set values to stop certain things in motion


Thank you,



Ben (SMB2J-2Q)

SMB2J-2Q
Posted on 11-14-24 12:00 AM, in (rev. 7 of 11-14-24 09:17 PM by SMB2J-2Q) Link | ID: 1345

Red Goomba

Level: 9

Posts: 38/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
In SMAS, a new check was added to the FloateyNumbersRoutine routine, to make earning 1-UPs easier. But it also has a flaw: the StompChainCounter does not have the values 5000 and 8000 when doing turtle-tipping, going straight from 4000 to 1-UP.

FloateyNumbersRoutine:
lda FloateyNum_Control,x ;load control for floatey number
beq EndExitOne ;if zero, branch to leave
cmp #$0b ;if less than $0b, branch
bcc ChkNumTimer
lda #$0b ;otherwise set to $0b, thus keeping
sta FloateyNum_Control,x ;it in range
cpx #$05 ;SMAS diff: check for special use item slot
beq ChkNumTimer ;if found (i.e. 1-UP mushroom), branch ahead
sta StompChainCounter ;otherwise store to stomp counter
ChkNumTimer: tay ;use as Y

What this new check does is that it checks if Mario does a shell chain reaction by kicking a Koopa shell toward other enemies and then gets 1-UPs after the shell hits the 9th enemy. It also compares X to the power-up object state, so if Mario happens to get a 1-UP Mushroom, the stomp chain counter will not be incremented. If the stomp or shell chain is successful, if Mario jumps on that same shell or kicks it after initially breaking the chain (i.e. if the shell ricochets against a pipe or stair), another 1-UP is earned.

~Ben

SMB2J-2Q
Posted on 12-01-24 06:32 AM, in Link | ID: 1401

Red Goomba

Level: 9

Posts: 39/39
EXP: 2491
Next: 671

Since: 08-21-24
From: Oak Grove, OR

Last post: 2 days
Last view: 8 hours
In Super Mario All-Stars, I found some new code here:

SprObjectOffscrChk:
ldx ObjectOffset ;get enemy buffer offset
lda Enemy_OffscreenBits ;check offscreen information
lsr
lsr ;shift three times to the right
lsr ;which puts d2 into carry
pha ;save to stack
bcc LcChk ;branch if not set
lda #$04 ;set for right column sprites
jsr MoveESprColOffscreen ;and move them offscreen
LcChk: pla ;get from stack
lsr ;move d3 to carry
pha ;save to stack
bcc Row3C ;branch if not set
lda #$00 ;set for left column sprites,
jsr MoveESprColOffscreen ;move them offscreen
Row3C: pla ;get from stack again
lsr ;move d5 to carry this time
lsr
pha ;save to stack again
bcc Row23C ;branch if carry not set
lda #$10 ;set for third row of sprites
jsr DrawESprRow ;and move them offscreen
Row23C: pla ;get from stack
lsr ;move d6 into carry
pha ;save to stack
bcc AllRowC
lda #$08 ;set for second and third rows
jsr DrawESprRow ;move them offscreen
AllRowC: pla ;get from stack once more
lsr ;move d7 into carry
bcc ExEGHandler
jsr DrawESprRow ;move all sprites offscreen (A should be 0 by now)
lda Enemy_ID,x
cmp #Podoboo ;check enemy identifier for podoboo
beq ExEGHandler ;skip this part if found, we do not want to erase podoboo!
lda Enemy_Y_HighPos,x ;check high byte of vertical position
cmp #$02 ;if not yet past the bottom of the screen, branch
bne ExEGHandler
jsr EraseEnemyObject ;what it says


The specific new chunk of code is here:

DrawESprRow: ;new code in SMAS
stx ObjectOffset ;store to enemy object offset
cpx #$06 ;check against special use slot (this value is $0a in SMAS)
bne MoveESprRowOffscreen ;if not found, branch ahead
dex ;otherwise decrement X


It was also added here:

MoveESprRowOffscreen:
clc ;add A to enemy object OAM data offset
adc Enemy_SprDataOffset,x
tay ;use as offset
lda #$f8
ldx ObjectOffset ;SMAS diff: get enemy object offset
jmp DumpTwoSpr ;move first row of sprites offscreen
stx ObjectOffset ;SMAS diff: save to enemy object offset
cpx #$06 ;SMAS diff: check against special use slot ($0a in SMAS)
bne MoveESprColOffscreen ;SMAS diff: if not in use, branch ahead
dex ;SMAS diff: otherwise decrement X

Does anyone have any insight as to what this new chunk of code (I labeled it 'DrawESprRow') was supposed to fix? The #$0a in the SMAS original referred to there being nine enemy slots + one, but for the NES I changed this value to #$06.

~Ben
Pages: 1 2 3


Main - Hacking Discussion - Super Mario Bros. Fixes (3)

Affiliates:


Acmlmboard v2.5.6+neo (2024-08-13)
© 2005-2024 Acmlm, Emuz, NinCollin, et al.

Page rendered in 0.118 seconds. (992KB of memory used)
MySQL - queries: 93, rows: 462/472, time: 0.095 seconds.