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

Site registration now fixed. Oops!
Views: 434,501
Sections: Documents | Utilities | ROM Hacks | Games | Translations | Homebrew | Fonts
Site: Main | Rules/FAQ | Discord | Memberlist | Latest posts | Stats | Ranks | Online users
09-19-24 11:50 PM
Guest: Register | Login

0 users currently in Hacking Discussion | 9 bots

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

Pages: 1 2

SMB2J-2Q
Posted on 08-23-24 11:01 PM, in (rev. 2 of 08-23-24 11:21 PM by SMB2J-2Q) Link | ID: 429

Goomba

Level: 5

Posts: 3/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Continuing from where we left off in the old RHDN website, I present to you a thread that documents all the various code changes for SMB, SMB2J (or SMBLL) and ANNSMB.

Here's the old thread at RHDN that inspired this one here.
https://www.romhacking.net/forum/index.php?topic=32473.0

And here are the two threads that inspired my original RHDN thread in the first place:
https://forums.nesdev.org/viewtopic.php?t=11576&hilit=sram+mario (ShaneM's bugfixed SMB1 and SMB2J)
https://tcrf.net/Super_Mario_Bros. (SMB entry at The Cutting Room Floor)

In Super Mario All-Stars (SMAS) for the SNES, in the AreaPointer code there appears to be another new chunk of code related to blocking out invalid worlds.

LoadAreaPointer:
jsr FindWorldNumber ;find it and store it here
sta AreaPointer
GetAreaType: and #%01100000 ;mask out all but d6 and d5
asl a
rol a
rol a
rol a ;make %0xx00000 into %000000xx
sta AreaType ;save 2 MSB as area type
rts

FindWorldNumber:
ldy WorldNumber ;load offset from world variable
cpy #World8+1 ;check against max world value + 1
bcc FindAreaPointer ;if world number < 8, branch to do area pointer logic normally
lda #$00
sta AreaNumber ;otherwise clear area and level number variables
sta LevelNumber
tay
sty WorldNumber ;then do same for world variable
FindAreaPointer:
lda WorldAddrOffsets,y
clc ;add area number used to find data
adc AreaNumber
tay
lda AreaAddrOffsets,y ;from there we have our area pointer
rts


~Ben (SMB2J-2Q)

ShaneM
Posted on 08-23-24 11:52 PM, in (rev. 4 of 08-23-24 11:57 PM by ShaneM) Link | ID: 436
Newcomer

Level: 3

Posts: 1/8
EXP: 123
Next: 5

Since: 08-21-24

Last post: 4 days
Last view: 1 hour
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.

SMB2J-2Q
Posted on 08-24-24 01:47 AM, in (rev. 3 of 08-24-24 02:46 AM by SMB2J-2Q) Link | ID: 442

Goomba

Level: 5

Posts: 4/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
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,

Yes, this new code is in the SMAS remake of SMB2J (SMBLL) as well:
https://github.com/Maseya/SMAS-Disassembly/blob/master/Assembly/SMB2J/code/b0E/_b0E.asm

The area data code is also saved to the alternate AreaType address that stores the current BG palette and music ($BA).

It is true about the separate data banks for the FDS original (and ANNSMB), so for SMAS the world number check has been revised to include up to World D. In addition, under 'GetAreaType' for SMBLL a check to see if the player is in world 8-4 or not has been added. Perhaps this last chunk of code might be why the music in World 8-4 doesn't reset during scene changes whenever the player enters a pipe?

LoadAreaPointer:
jsr FindWorldNumber ;find it and store it here
sta AreaPointer
GetAreaType: and #%01100000 ;mask out all but d6 and d5
asl a
rol a
rol a
rol a ;make %0xx00000 into %000000xx
sta AreaType ;save 2 MSB as area type
sta AreaType_Alt ;also save as BG palette and music type
lda WorldNumber ;if not on world 8, skip the rest of this code
cmp #World8
bne NotWorld8
lda AreaNumber ;otherwise check if player is on world 8-4, branch to exit if not
cmp #Level4
bne NotWorld8
lda #$03 ;if so, load BG and music type for castle level
sta AreaType_Alt ;and store to alternate AreaType variable
NotWorld8: rts

FindWorldNumber:
ldy WorldNumber ;load offset from world variable
cpy #WorldD+1 ;check against max world value + 1
bcc FindAreaPointer ;if world < D, branch to do area pointer logic normally
lda #$00
sta AreaNumber ;otherwise clear area and level number variables
sta LevelNumber
tay
sty WorldNumber ;then do same for world variable
FindAreaPointer:
lda WorldAddrOffsets,y
clc ;add area number used to find data
adc AreaNumber
tay
lda AreaAddrOffsets,y
rts

~Ben

Rexius55
Posted on 08-24-24 05:16 PM, in Link | ID: 446

Tektite

Level: 9

Posts: 42/58
EXP: 2681
Next: 481

Since: 08-14-24
From: Outset Island, The Great Sea

Last post: 4 days
Last view: 4 days
Interesting look into the code, my apologies for thinkin' you were newer to the community.

____________________
I do requests (reverse-engineering, programming, music, spritework, writing, etc.). I'm always learnin'.

Status: Hands are full.

I post wherever is on my Linktree. If you see my stuff anywhere else, it wasn't me.

SMB2J-2Q
Posted on 08-25-24 10:56 AM, in (rev. 5 of 08-25-24 11:01 AM by SMB2J-2Q) Link | ID: 483

Goomba

Level: 5

Posts: 7/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
I wonder if the code change under 'NoDemote' in both SMB2J (SMBLL) and ANNSMB, which adds new checks for either power-up objects or Goombas (again), was meant to fix the "Koopa Troopa Factory" glitch in the first SMB that involved turning Goombas and Spinys into Koopa shells (either green or red) when hit by bricks above when the player was small?

ChkToStunEnemies:
lda Enemy_ID,x
cmp #$09 ;perform many comparisons on enemy identifier
bcc NoDemote ;if the enemy identifier is identical to the values
cmp #Lakitu ;$0e, $0f or $10 it will be demoted, in practice
bcs NoDemote ;$0e and $10 are values used by green paratroopas
cmp #PiranhaPlant
beq NoDemote ;enemy objects $0a thru $0d will not be demoted
cmp #UpsideDownPiranhaP
beq NoDemote
cmp #$0a ;demote enemy object $09 even though it isn't used
bcc Demote
cmp #PiranhaPlant
bcc NoDemote
Demote: and #%00000001 ;erase all but LSB, essentially turning enemy object
sta Enemy_ID,x ;into green or red koopa troopa to demote them
NoDemote: cmp #PowerUpObject
beq BounceOff ;if power-up object, branch to bounce it
cmp #Goomba
beq BounceOff ;redundant, already checked for goomba
lda #$02
sta Enemy_State,x ;set enemy state to $02 (stunned)
BounceOff: dec Enemy_Y_Position,x ;subtract 2 pixels from enemy's vertical position


~Ben (SMB2J-2Q)

SMB2J-2Q
Posted on 08-26-24 02:08 PM, in (rev. 4 of 08-28-24 02:23 AM by SMB2J-2Q) Link | ID: 514

Goomba

Level: 5

Posts: 8/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Hi Shane,

In Super Mario Bros. 3 there is a data table that lists all the sound effects to be played. It is explained in detail here (and explains why the "extended" 1-UP sound exists):


I wish that we could do a similar sound effects data table check for SMB, SMB2J and ANNSMB, which would help prevent other sounds in the same three queues from overwriting each other. The reason I wish to come up with this data table like the one in SMB3 is so that I can redirect the old commands to it via a new JSR, instead of having to load for each specific routine the relevant queue first to check it for other sounds before loading the sound in question.

The table in question looked like this:

;$A507
SndLev1_SuitLost2:
ldy Sound_QLevel1
cpy #Snd_LevelPoof
bne Try_Unknown ;if not doing poof sound, jump to Try_Unknown

;"Poof" sound
lda #$1f
bne Merge ;jump (technically always) to Merge

;$A512
Try_Unknown:
cpy #Snd_Unknown
bne Try_ShoeLost ;if not doing unknown sound, jump to Try_ShoeLost

;Unknown sound
lda #$00
beq Merge

;$A51A
Try_ShoeLost:
cpy #Snd_ShoeLost
bne Try_Others ;if not doing Kuribo's shoe lost sound, jump to Try_Others
lda #$57
bne Merge

;$A522
Try_Others:
lda SndCur_Level1
bne Sfx_Others ;if any other level 1 sounds are playing, branch back to $A504

;tail wagging sound
lda #$6b

;$A529
Merge:
sta Sfx_Counter2 ;set Sfx_Counter2 accordingly
tya
and #$b0
sty SndCur_Level1 ;here is why the "extended 1-UP" fanfare plays!


~Ben

SMB2J-2Q
Posted on 08-29-24 10:19 AM, in (rev. 3 of 08-29-24 10:38 PM by SMB2J-2Q) Link | ID: 557

Goomba

Level: 5

Posts: 9/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
In SMB2J (SMBLL) there is a penalty for those who like to warp: do not allow world 9 to be activated unless the player completes all 8 worlds first.

In SMB 1 beating World 8 the first time around turns on the hard mode and world selection flags whether the player used warps or not; for those of you who wish to prevent speedrunners from gaining the hard mode too early, here is what you'd do:

$06c9 = CompletedWorlds

GameMenuRoutine:
ldy #$00
lda SavedJoypad1Bits ;check to see if either player pressed
ora SavedJoypad2Bits ;only the start button (either joypad)
cmp #Start_Button
beq StartGame
cmp #A_Button+Start_Button ;check to see if A + start was pressed
bne ChkSelect ;if not, branch to check select button
lda #$00
sta CompletedWorlds ;initialize completed worlds flag
StartGame: jmp ChkContinue ;if either start or A + start, execute here



WorldBits:
.db $01, $02, $04, $08, $10, $20, $40, $80

SetupVictoryMode:
ldx ScreenRight_PageLoc ;get page location of right side of screen
inx ;increment to next page
stx DestinationPageLoc ;store here
ldy WorldNumber
lda WorldBits,y ;set bit according to the world the player is in
ora CompletedWorlds
sta CompletedWorlds
lda #EndOfCastleMusic
sta EventMusicQueue ;play win castle music
jmp IncModeTask_B ;jump to set next major task in victory mode



InitializeGame:
lda #$00
sta CompletedWorlds ;clean slate player's progress
ldy #$6f ;clear all memory as in initialization procedure,
jsr InitializeMemory ;but this time, clear only as far as $076f
ldy #$1f
ClrSndLoop: sta SoundMemory,y ;clear out memory used



EndChkBButton: lda SavedJoypad1Bits
ora SavedJoypad2Bits ;check to see if B button was pressed on
and #B_Button ;either controller
beq EndExitTwo ;branch to leave if not
lda CompletedWorlds ;check if player has finished all 8 worlds
cmp #$ff ;without warping, and branch ahead if not
bne NotDoneYet
lda #$01 ;otherwise set world selection flag
sta WorldSelectEnableFlag
NotDoneYet: lda #$ff ;remove onscreen player's lives
sta NumberofLives
jsr TerminateGame ;do sub to continue other player or end game
EndExitTwo: rts ;leave



SetInitNTHigh: sty CurrentNTAddr_High ;store name table address
ldy #$80
sty CurrentNTAddr_Low
asl ;store LSB of page number in high nybble
asl ;of block buffer column position
asl
asl
sta BlockBufferColumnPos
dec AreaObjectLength ;set area object lengths for all empty
dec AreaObjectLength+1
dec AreaObjectLength+2
lda #$0b ;set value for renderer to update 12 column sets
sta ColumnSets ;12 column sets = 24 metatile columns = 1 1/2 screens
jsr GetAreaDataAddrs ;get enemy and level addresses and load header
lda CompletedWorlds ;check to see if player finished all 8 worlds without warping
cmp #$ff
beq SetSecHard ;if so, set secondary no matter where we're at
lda WorldNumber ;otherwise check world number


~Ben (SMB2J-2Q)

SMB2J-2Q
Posted on 08-30-24 11:12 PM, in (rev. 5 of 08-31-24 05:21 AM by SMB2J-2Q) Link | ID: 591

Goomba

Level: 5

Posts: 10/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
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

MegaFucker man
(post deleted) ID: 610

ShaneM
Posted on 09-02-24 05:38 AM, in (rev. 7 of 09-02-24 05:58 AM by ShaneM) Link | ID: 617
Newcomer

Level: 3

Posts: 2/8
EXP: 123
Next: 5

Since: 08-21-24

Last post: 4 days
Last view: 1 hour
Posted by SMB2J-2Q
In SMB2J (SMBLL) there is a penalty for those who like to warp: do not allow world 9 to be activated unless the player completes all 8 worlds first.



Actually, that isn't true. SM2DATA3 does a check in the subroutine "BackToNormal" on which it is commented:


lda CompletedWorlds ;if completed all worlds without skipping over any
cmp #$ff ;then branch elsewhere (note warping backwards may
beq GoToWorld9 ;allow player to complete skipped worlds)


But that comment also isn't completely true. Whenever you complete a castle, one of the 8 bits in "CompletedWorlds" ($07FA) is set. (To make this comment correct just remove the word "backwards" from the cmp #$ff line of doppleganger's disassembly though that isn't really important.) This bit is determined in "SetupVictoryMode" subroutine in SM2MAIN:


ldy WorldNumber
lda WorldBits,y
ora CompletedWorlds ;set bit according to the world the player was in
sta CompletedWorlds


The bits in the WorldBits table start with #%00000001 for world 1 and multiplies for each world in table values. So world 8 would set #%10000000. It is ORA'd to save the previous bits hence how "CompletedWorlds" would be #$FF if you complete all 8 worlds. But, the set bits remain set even after taking a warpzone.

I'll put it in layman's terms for you: Say you complete worlds 1 and 2, at the start of world 3 "CompletedWorlds" would have bits #%00000011 set. Let's say you take the negative warp zone on 3-1 back to 1-1, those bits aren't reset. Now, let's say after taking the negative warp you take the warp on 1-2 back to world 3. Well, the bits remain set. So you would still get to world 9 while taking these warps because you completed the first two castles (assuming you complete castles 3-8). The same could be said if you complete up to the start of world 8 (#%01111111 set) and on 8-1 take the negative warp zone back to 5-1 and then on 5-2 warp ahead back to 8-1. Well, after completing 8-4 $07FA would still be set to #$FF, hence even taking a possible 4 warp zones (2 regular and 2 negative) you would still end up on world 9. Does that make sense?

SMB2J-2Q
Posted on 09-03-24 02:37 AM, in (rev. 4 of 09-03-24 02:57 AM by SMB2J-2Q) Link | ID: 655

Goomba

Level: 5

Posts: 11/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Posted by ShaneM
Posted by SMB2J-2Q
In SMB2J (SMBLL) there is a penalty for those who like to warp: do not allow world 9 to be activated unless the player completes all 8 worlds first.



Actually, that isn't true. SM2DATA3 does a check in the subroutine "BackToNormal" on which it is commented:


lda CompletedWorlds ;if completed all worlds without skipping over any
cmp #$ff ;then branch elsewhere (note warping backwards may
beq GoToWorld9 ;allow player to complete skipped worlds)


But that comment also isn't completely true. Whenever you complete a castle, one of the 8 bits in "CompletedWorlds" ($07FA) is set. (To make this comment correct just remove the word "backwards" from the cmp #$ff line of doppleganger's disassembly though that isn't really important.) This bit is determined in "SetupVictoryMode" subroutine in SM2MAIN:


ldy WorldNumber
lda WorldBits,y
ora CompletedWorlds ;set bit according to the world the player was in
sta CompletedWorlds


The bits in the WorldBits table start with #%00000001 for world 1 and multiplies for each world in table values. So world 8 would set #%10000000. It is ORA'd to save the previous bits hence how "CompletedWorlds" would be #$FF if you complete all 8 worlds. But, the set bits remain set even after taking a warpzone.

I'll put it in layman's terms for you: Say you complete worlds 1 and 2, at the start of world 3 "CompletedWorlds" would have bits #%00000011 set. Let's say you take the negative warp zone on 3-1 back to 1-1, those bits aren't reset. Now, let's say after taking the negative warp you take the warp on 1-2 back to world 3. Well, the bits remain set. So you would still get to world 9 while taking these warps because you completed the first two castles (assuming you complete castles 3-8). The same could be said if you complete up to the start of world 8 (#%01111111 set) and on 8-1 take the negative warp zone back to 5-1 and then on 5-2 warp ahead back to 8-1. Well, after completing 8-4 $07FA would still be set to #$FF, hence even taking a possible 4 warp zones (2 regular and 2 negative) you would still end up on world 9. Does that make sense?

Hi Shane,

I understand and thank you for the heads-up on these!

BTW, I hope you enjoyed my latest SMAS discovery about the Podoboo.

I also found this in SMAS:

SetStPos: lda PlayerStarting_X_Pos,y ;load appropriate horizontal position
sta Player_X_Position ;and vertical positions for the player, using
lda PlayerStarting_Y_Pos,x ;AltEntranceControl as offset for horizontal and either $0710
sta Player_Y_Position ;or value that overwrote $0710 as offset for vertical
lda PlayerBGPriorityData,x
sta Player_SprAttrib ;set player sprite attributes using offset in X
ldx #$00 ;SMAS diff: then clear X
jsr BoundingBoxCore ;SMAS diff: do sub to get player's bounding box coordinates
jsr GetPlayerColors ;get appropriate player palette
ldy GameTimerSetting ;get timer control value from header
beq ChkOverR ;if set to zero, branch (do not use dummy byte for this)
lda FetchNewGameTimerFlag ;do we need to set the game timer? if not, use
beq ChkOverR ;old game timer setting
lda GameTimerData,y ;if game timer is set and game timer flag is also set,
sta GameTimerDisplay ;use value of game timer control for first digit of game timer
lda #$01
sta GameTimerDisplay+2 ;set last digit of game timer to 1
lsr
sta GameTimerDisplay+1 ;set second digit of game timer
sta FetchNewGameTimerFlag ;clear flag for game timer reset
sta StarInvincibleTimer ;clear star mario timer
ChkOverR: ldy JoypadOverride ;if controller bits not set, branch to skip this part

Under SetStPos, after the player's sprite attributes are set up, X is then cleared and a JSR to BoundingBoxCore is performed. I wonder what this was supposed to do in SMAS?

~Ben

SMB2J-2Q
Posted on 09-05-24 02:17 AM, in (rev. 6 of 09-05-24 06:07 AM by SMB2J-2Q) Link | ID: 688

Goomba

Level: 5

Posts: 12/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Hi Shane,

Would you happen to know about why, under ClearVRLoop, SMAS removes the JSR to GetAreaMusic but also saves #$FF to the VRAM buffer?

ClearVRLoop: sta VRAM_Buffer1-1,y ;clear buffer at $0300-$03ff
iny
bne ClearVRLoop
sta GameTimerExpiredFlag ;clear game timer exp flag
sta DisableIntermediate ;clear skip lives display flag
sta BackloadingFlag ;clear value here
lda #$ff
sta BalPlatformAlignment ;initialize balance platform assignment flag
sta VRAM_Buffer1 ;SMAS diff: also save to VRAM buffer
lda ScreenLeft_PageLoc ;get left side page location
lsr Mirror_PPU_CTRL_REG1 ;shift LSB of ppu register #1 mirror out
and #$01 ;mask out all but LSB of page location
ror ;rotate LSB of page location into carry then onto mirror
rol Mirror_PPU_CTRL_REG1 ;this is to set the proper PPU name table
jsr GetAreaMusic ;load proper music into queue (removed in SMAS)
lda #$38 ;load sprite shuffle amounts to be used later
sta SprShuffleAmt+2
lda #$48
sta SprShuffleAmt+1
lda #$58
sta SprShuffleAmt
ldx #$0e ;load default OAM offsets into $06e4-$06f2
ShufAmtLoop: lda DefaultSprOffsets,x


And here's the SMAS version of the same code for reference:

CODE_039EE6:
STA $0300,y ; $03:9EE6: 99 00 03
INY ; $03:9EE9: C8
BNE CODE_039EE6 ; $03:9EEA: D0 FA
STA $0759 ; $03:9EEC: 8D 59 07
STA $0769 ; $03:9EEF: 8D 69 07
STA $0728 ; $03:9EF2: 8D 28 07
LDA #$FF ; $03:9EF5: A9 FF
STA $03A0 ; $03:9EF7: 8D A0 03
STA $1702 ; $03:9EFA: 8D 02 17
LDA $071A ; $03:9EFD: AD 1A 07
LSR $0778 ; $03:9F00: 4E 78 07
AND #$01 ; $03:9F03: 29 01
ROR A ; $03:9F05: 6A
ROL $0778 ; $03:9F06: 2E 78 07
LDA #$38 ; $03:9F09: A9 38
STA $0B43 ; $03:9F0B: 8D 43 0B
LDA #$48 ; $03:9F0E: A9 48
STA $0B42 ; $03:9F10: 8D 42 0B
LDA #$58 ; $03:9F13: A9 58
STA $0B41 ; $03:9F15: 8D 41 0B
LDX #$1C ; $03:9F18: A2 1C


~Ben (SMB2J-2Q)

ShaneM
Posted on 09-05-24 05:00 AM, in (rev. 6 of 09-05-24 05:10 AM by ShaneM) Link | ID: 690
Newcomer

Level: 3

Posts: 3/8
EXP: 123
Next: 5

Since: 08-21-24

Last post: 4 days
Last view: 1 hour
Posted by SMB2J-2Q

Under SetStPos, after the player's sprite attributes are set up, X is then cleared and a JSR to BoundingBoxCore is performed. I wonder what this was supposed to do in SMAS?


X is used as the offset for the player object, it is not "cleared" as in clearing a flag or bit but used as the offset for the player. I'll comment it more clearly for you:


SetStPos: lda PlayerStarting_X_Pos,y ;load appropriate horizontal position
sta Player_X_Position ;and vertical positions for the player, using
lda PlayerStarting_Y_Pos,x ;AltEntranceControl as offset for horizontal and either
sta Player_Y_Position ;the original offset from the header or alt offset for vertical
lda PlayerBGPriorityData,x
sta Player_SprAttrib ;set player sprite attributes using offset in X
ldx #$00 ;SMAS set offset for player object
jsr BoundingBoxCore ;SMAS get player's bounding box coordinates
jsr GetPlayerColors ;get appropriate player palette


This isn't a bugfix that needs to be ported to the NES/FDS. The display intermediate screen (lives screen) on the SNES SMB1 and TLL is set up differently, with a picture of the current level being displayed before the level starts. The player's bound box is set during this sequence on SNES but not NES/FDS because the routine isn't called during display intermediate on there.

I NOP'd it on the SNES to see what would happen and it makes no difference. Perhaps this is quite possibly residual code as it may have been meant to be animated at one point including the player in the level intro picture. So not a bugfix or anything like that. -ShaneM

EDIT: Also, the code you posted about castle timer awards has already been in my builds for the past year or so. You're mentioning really old code. I'd prefer you not guessing my code if you don't understand exactly what I did because it's creating false labels or comments to a disassembly that is private. Thanks.

SMB2J-2Q
Posted on 09-05-24 05:32 AM, in (rev. 9 of 09-05-24 05:51 AM by SMB2J-2Q) Link | ID: 691

Goomba

Level: 5

Posts: 13/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Posted by ShaneM
Posted by SMB2J-2Q

Under SetStPos, after the player's sprite attributes are set up, X is then cleared and a JSR to BoundingBoxCore is performed. I wonder what this was supposed to do in SMAS?


X is used as the offset for the player object, it is not "cleared" as in clearing a flag or bit but used as the offset for the player. I'll comment it more clearly for you:


SetStPos: lda PlayerStarting_X_Pos,y ;load appropriate horizontal position
sta Player_X_Position ;and vertical positions for the player, using
lda PlayerStarting_Y_Pos,x ;AltEntranceControl as offset for horizontal and either
sta Player_Y_Position ;the original offset from the header or alt offset for vertical
lda PlayerBGPriorityData,x
sta Player_SprAttrib ;set player sprite attributes using offset in X
ldx #$00 ;SMAS set offset for player object
jsr BoundingBoxCore ;SMAS get player's bounding box coordinates
jsr GetPlayerColors ;get appropriate player palette


This isn't a bugfix that needs to be ported to the NES/FDS. The display intermediate screen (lives screen) on the SNES SMB1 and TLL is set up differently, with a picture of the current level being displayed before the level starts. The player's bound box is set during this sequence on SNES but not NES/FDS because the routine isn't called during display intermediate on there.

I NOP'd it on the SNES to see what would happen and it makes no difference. Perhaps this is quite possibly residual code as it may have been meant to be animated at one point including the player in the level intro picture. So not a bugfix or anything like that. -ShaneM

EDIT: Also, the code you posted about castle timer awards has already been in my builds for the past year or so. You're mentioning really old code. I'd prefer you not guessing my code if you don't understand exactly what I did because it's creating false labels or comments to a disassembly that is private. Thanks.

Shane,

Thank you for the update; I will discard that then. This also makes me wonder what other residual code bits there are in the SMAS versions of SMB and SMBLL that can be safely removed w/o messing up the game (and I mean besides those code chunks we already know about in the respective NES and FDS originals)? For example, the continue world code from the NES original of SMB could be removed because the world save/continue feature is different in SMAS.

I also edited my last post to remove the code in question you refer to in your last paragraph, and replaced it with something else to have you check out.

~Ben

SMB2J-2Q
Posted on 09-07-24 08:38 AM, in (rev. 2 of 09-11-24 03:15 AM by SMB2J-2Q) Link | ID: 736

Goomba

Level: 5

Posts: 14/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Hi Shane,

I remember having played SMAS and, at one time, in either SMB or SMBLL I remember defeating Bowser in one of the x-4 levels and the victory music strangely did not play (it was silent the whole time Mario walked over to Toad, until the timer counted down).

The question is: what may cause the victory music to glitch out and not cue properly when you destroy Bowser?

~Ben (SMB2J-2Q)

SMB2J-2Q
Posted on 09-11-24 03:38 AM, in (rev. 3 of 09-11-24 03:52 AM by SMB2J-2Q) Link | ID: 776

Goomba

Level: 5

Posts: 15/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
In SMAS, I also found another new flag for the AutoControlPlayer routine, which is at RAM 7E:0B7A. I wonder what it was supposed to have done, please?


$0b7a = AutoCtrlPlyrFlag

AutoControlPlayer:
sta SavedJoypadBits ;override controller bits with contents of A if executing here
lda #$01
sta AutoCtrlPlyrFlag ;set auto control player flag
bra NoClearACP ;then do unconditional branch to avoid clearing it in next routine

PlayerControlRoutine:
stz AutoCtrlPlyrFlag ;if branching here without performing AutoControlPlayer routine above, clear flag
NoClearACP:
lda GameEngineSubroutine ;check task here


This new flag is also checked in the ChkStart routine:

$0b75 = PauseMenuFlag
$0b7a = AutoCtrlPlyrFlag

ChkStart:
lda GameEngineSubroutine ;check if either pipe entry routine is running,
cmp #$02 ;and if so, skip to end this routine to avoid pausing game
beq ExChkStart
cmp #$03
beq ExChkStart
lda AutoCtrlPlyrFlag ;if flag for AutoControlPlayer routine was previously set,
bne ExChkStart ;also disable pause
lda PauseMenuFlag ;check if pause menu has been brought up
cmp #$02
bcs ExChkStart ;if so, exit this routine
lda SavedJoypad1Bits ;check to see if start is pressed
and #Start_Button ;on controller 1
...


The routine just above it, PauseRoutine, is also modified to disallow pausing during the victory mode. What makes me curious is that there are two different RTS branches here. The first one, which occurs if the player has defeated Bowser, branches to the end of the main pause routine, but all the subsequent RTS branches point to the end of the start button check routine.

PauseRoutine:
lda OperMode ;are we in victory mode?
cmp #VictoryModeValue
beq ExitPause ;if so, branch to exit routine
cmp #GameModeValue ;otherwise, are we doing main game mode?
bne ExChkStart ;if not, branch to exit routine
lda OperMode_Task ;if we are in game mode, are we running game engine?
cmp #$03
bne ExChkStart ;if not, branch to exit routine
lda GamePauseTimer ;check if pause timer is still counting down
beq ChkStart
dec GamePauseTimer ;if so, decrement it and leave
ExitPause:
rts


~Ben (SMB2J-2Q)

ShaneM
Posted on 09-11-24 05:10 AM, in (rev. 6 of 09-11-24 05:27 AM by ShaneM) Link | ID: 777
Newcomer

Level: 3

Posts: 5/8
EXP: 123
Next: 5

Since: 08-21-24

Last post: 4 days
Last view: 1 hour
@SMB2J-2Q,

In a hex editor, did you try nopping all occurrences of “ AutoCtrlPlyrFlag” on a backup copy? What happened/what changes did you notice when you did?

It looks like if the player is being autocontrolled it sets a flag to disable pausing in the check start routine and if you’re manually controlling the player it is cleared. I wouldn’t know exactly for what unless I test it.

Edit: If I had to guess that’s what prevents pausing during flagpole slide or castle victory routine. A good way to test it is to NOP it and see if you can pause after touching flagpole, entry to 1-2 or castle victory. Let me know if my guess wasn’t right and I’ll figure it out when I get time if it isn’t.

About the RTS thing, Nintendo is known to do branches to not necessarily the closest RTS. It really doesn’t matter which one except farther branching. If I understood what you’re saying correctly.

SMB2J-2Q
Posted on 09-11-24 07:16 PM, in (rev. 2 of 09-11-24 07:17 PM by SMB2J-2Q) Link | ID: 784

Goomba

Level: 5

Posts: 16/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Posted by ShaneM
@SMB2J-2Q,

In a hex editor, did you try nopping all occurrences of “ AutoCtrlPlyrFlag” on a backup copy? What happened/what changes did you notice when you did?

It looks like if the player is being autocontrolled it sets a flag to disable pausing in the check start routine and if you’re manually controlling the player it is cleared. I wouldn’t know exactly for what unless I test it.

Edit: If I had to guess that’s what prevents pausing during flagpole slide or castle victory routine. A good way to test it is to NOP it and see if you can pause after touching flagpole, entry to 1-2 or castle victory. Let me know if my guess wasn’t right and I’ll figure it out when I get time if it isn’t.

About the RTS thing, Nintendo is known to do branches to not necessarily the closest RTS. It really doesn’t matter which one except farther branching. If I understood what you’re saying correctly.

Shane,

So far (when I NOP'ed the LDA instruction under 'ChkStart'), my test has failed, because it will not let me pause the game at all.

~Ben

ShaneM
Posted on 09-11-24 08:44 PM, in Link | ID: 785
Newcomer

Level: 3

Posts: 6/8
EXP: 123
Next: 5

Since: 08-21-24

Last post: 4 days
Last view: 1 hour
Nop “lda #$01 and sta AutoCtrlPlyrFlag” in AutoControlPlayer and “stz AutoCtrlPlyrFlag” in PlayerControlRoutine and then nop” lda AutoCtrlPlyrFlag bne ExChkStart” in Chkstart. 5 different instructions in total. If not, I’ll get around to it when I can. Thanks.

SMB2J-2Q
Posted on 09-11-24 09:32 PM, in (rev. 6 of 09-11-24 09:55 PM by SMB2J-2Q) Link | ID: 788

Goomba

Level: 5

Posts: 17/21
EXP: 526
Next: 3

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

Last post: 1 day
Last view: 4 hours
Posted by ShaneM
Nop “lda #$01 and sta AutoCtrlPlyrFlag” in AutoControlPlayer and “stz AutoCtrlPlyrFlag” in PlayerControlRoutine and then nop” lda AutoCtrlPlyrFlag bne ExChkStart” in Chkstart. 5 different instructions in total. If not, I’ll get around to it when I can. Thanks.

Hi Shane,

Please forgive me, but I actually got it to behave the old way by also NOP'ing the BNE after it, without having to do the other things you mention.

Image 1 - end of level:


Image 2 - pipe intro:


When I ported the new AutoCtrlPlyrFlag to the NES, it does replicate what happens in SMAS by disallowing pause, except for when the player comes OUT of a pipe. I wonder what SMAS did to disallow pause while the player comes OUT of a pipe? This was the code added in to play the pipe sound coming out:

EntrMode2: lda JoypadOverride ;if controller override bits set here,
bne VineEntr ;branch to enter with vine
lda Player_Y_Position ;SMAS diff: check if player is at 176th pixel when coming out of pipe
cmp #$b0 ;SMAS
bne NoPipeUpSd ;SMAS if not, do not play pipe/injury sound
lda #Sfx_Pipe_Injury ;SMAS
sta Square1SoundQueue ;SMAS
NoPipeUpSd: lda #$ff ;otherwise, set value here then execute sub

In SMAS, there is another new address $0E4E, but again since the disassembly I am using doesn't give labels to any of these RAM addresses yet, this is why I have difficulty pinpointing exactly what they do.

~Ben
Pages: 1 2


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


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

Page rendered in 0.136 seconds. (1032KB of memory used)
MySQL - queries: 122, rows: 499/507, time: 0.109 seconds.