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

Chat on Discord
Views: 1,283,554
Main | Rules/FAQ | Discord | Memberlist | Latest posts | Stats | Ranks | Online users
04-01-25 09:36 PM
Guest: Register | Login

Main - Posts by ShaneM


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

Micro-Goomba

Level: 7

Posts: 1/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
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.

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

Micro-Goomba

Level: 7

Posts: 2/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
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?

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

Micro-Goomba

Level: 7

Posts: 3/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
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.

ShaneM
Posted on 09-08-24 10:50 PM, in Hi! Just stopping by. (rev. 2 of 09-08-24 10:54 PM by ShaneM) Link | ID: 756

Micro-Goomba

Level: 7

Posts: 4/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
So do y’all think this new site will be the “official” successor to the original RHDN? I guess time will tell.

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

Micro-Goomba

Level: 7

Posts: 5/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
@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.

ShaneM
Posted on 09-11-24 08:44 PM, in Super Mario Bros. Fixes Link | ID: 785

Micro-Goomba

Level: 7

Posts: 6/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
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.

ShaneM
Posted on 09-12-24 12:42 AM, in Super Mario Bros. Fixes (rev. 10 of 09-12-24 03:34 PM by ShaneM) Link | ID: 790

Micro-Goomba

Level: 7

Posts: 7/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
I had you NOP the other stuff for neatness. The code is really only used in the conditional statement in ChkStart. It is only set/cleared in the other two routines. It did exactly what I thought it would. There are a few ways to do that. I’ve coded mine a different way.

Also, $0B7A is not a valid flag on SMB1 NES. I’d use a different one.

ShaneM
Posted on 09-15-24 04:45 PM, in Super Mario Bros. Fixes (rev. 5 of 09-15-24 05:06 PM by ShaneM) Link | ID: 830

Micro-Goomba

Level: 7

Posts: 8/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
Posted by SMB2J-2Q
Hi Shane,

I am curious as to the ChkGERtn routine:

ChkGERtn: lda GameEngineSubroutine ;get number of game engine routine running
cmp #$07
beq ExCSM ;if running player entrance routine or
cmp #$08 ;player control routine, go ahead and branch to leave
bne ExCSM
lda #$02
sta GameEngineSubroutine ;otherwise set sideways pipe entry routine to run
rts ;and leave

Specifically, this checks the GameEngineSubroutine variable for either routine $07 (for player entrance) or $08 (for player control) in action, and to branch to exit (ExCSM) if so. However, when checking for routine $08 it then says BNE (if not equal) and also leave the routine (to ExCSM), so unless they had intended to add additional code after this, then shouldn't that also be a BEQ or else if it is supposed to be a BNE branch, then shouldn't it be to StopPlayerMove? I am going to try that to see if any anomalies happen during the pipe intro scene.

UPDATE: I played the game with the change I applied and so far I have found no outstanding anomalies during Mario's automatic movement during the pipe intro scene.

~Ben


I optimized it and commented it anew. Use this one and credit me if borrowed.


ChkGERtn: lda GameEngineSubroutine ;load number of game engine routine running
cmp #$08 ;compare against the player control routine
bne ExChkGERtn ;if any other routine, branch to leave
lda #$02 ;otherwise load value to
sta GameEngineSubroutine ;set sideways pipe entry routine to run
ExChkGERtn:rts ;leave


Also, in the future could you please ask in a more generalized way instead of specifically calling me in every post for an answer? This is a community thread for everyone to participate in not just me. Thanks. LOL



ShaneM
Posted on 09-20-24 11:05 PM, in Super Mario Bros. Fixes (rev. 16 of 09-21-24 02:00 PM by ShaneM) Link | ID: 898

Micro-Goomba

Level: 7

Posts: 9/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
@SMB2J-2Q great find! I didn't realize SMB Deluxe GBC did that. I optimized it for you. My whole routine is different in SMB2J where it does the modern powerdown so if you're fiery you become super and having multiple powerups on screen at once so I did it from scratch from Doppleganger's SMB1 disassembly. Test it and let me know. It doesn't require new space, actually saves 6 bytes and fixes:

*powerup sound playing with 1-UP mushroom
*powerup sound playing with Starman
*double jump glitch when grabbing a powerup


HandlePowerUpCollision:
jsr EraseEnemyObject ;erase the power-up object
lda #$06
jsr SetupFloateyNumber ;award 1000 points to player by default
lda PowerUpType ;check power-up type
cmp #$02
bcc Shroom_Flower_PUp ;if mushroom or fire flower, branch
cmp #$03
beq SetFor1Up ;if 1-up mushroom, branch
lda #$23 ;otherwise set star mario invincibility
sta StarInvincibleTimer ;timer, and load the star mario music
lda #StarPowerMusic ;into the area music queue, then leave
sta AreaMusicQueue
NoPUp:rts ;(SM label moved here, slightly saves on cycling)

Shroom_Flower_PUp: ;SM let's use Y register
ldy #Sfx_PowerUpGrab ;SM load the power-up sound
sty Square2SoundQueue ;SM and store it to play
ldy PlayerStatus ;if player status = small, branch
beq UpToSuper
cpy #$01 ;if player status not super, leave
bne NoPUp
iny ;set player status to fiery (SM saves 1 byte)
sty PlayerStatus
jsr GetPlayerColors ;run sub to change colors of player
lda #$0c ;set value to be used by subroutine tree (fiery)
bne UpToFiery ;branch to set values accordingly (SM originally was a jmp)

SetFor1Up:
lda #$0b ;change 1000 points into 1-up instead
sta FloateyNum_Control,x ;and then leave
rts

UpToSuper:
lda #$01 ;set player status to super
sta PlayerStatus
lda #$09 ;set value to be used by subroutine tree (super)

UpToFiery:
ldy PlayerStatus ;SM set value to be used as new player state
jmp SetPRout ;set values to stop certain things in motion (SM originally was a JSR RTS. Saves on cycling)


Credit me if borrowed. -ShaneM

EDIT: I was able to save another byte by using Y register in "Shroom_Flower_PUp:".




ShaneM
Posted on 09-21-24 01:58 PM, in Super Mario Bros. Fixes (rev. 4 of 09-21-24 02:02 PM by ShaneM) Link | ID: 903

Micro-Goomba

Level: 7

Posts: 10/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
@SMB2J-2Q

Replace with “;SM let's use Y register” to get it to assemble. I added that comment last minute.

Did you find any more changes from SMB Deluxe or SMAS?

ShaneM
Posted on 09-22-24 12:22 AM, in Super Mario Bros. Fixes (rev. 4 of 09-22-24 12:25 AM by ShaneM) Link | ID: 915

Micro-Goomba

Level: 7

Posts: 11/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
I was able to optimize the routine even further. Saving yet another byte:


HandlePowerUpCollision:
jsr EraseEnemyObject ;erase the power-up object
lda #$06
jsr SetupFloateyNumber ;award 1000 points to player by default
lda PowerUpType ;check power-up type
cmp #$02
bcc Shroom_Flower_PUp ;if mushroom or fire flower, branch
cmp #$03
beq SetFor1Up ;if 1-up mushroom, branch
lda #$23 ;otherwise set star mario invincibility
sta StarInvincibleTimer ;timer, and load the star mario music
lda #StarPowerMusic ;into the area music queue, then leave
sta AreaMusicQueue
NoPUp:rts ;(SM label moved here, slightly saves on cycling)

Shroom_Flower_PUp: ;SM let's use Y register
ldy #Sfx_PowerUpGrab ;SM load the power-up sound
sty Square2SoundQueue ;SM and store it to play
ldy PlayerStatus ;if player status = small, branch
beq UpToSuper
cpy #$01 ;if player status not super, leave
bne NoPUp
iny ;set player status to fiery (SM saves 1 byte)
sty PlayerStatus
jsr GetPlayerColors ;run sub to change colors of player
lda #$0c ;set value to be used by subroutine tree (fiery)
bne UpToFiery ;branch to set values accordingly (SM originally was a jmp)

SetFor1Up:
lda #$0b ;change 1000 points into 1-up instead
sta FloateyNum_Control,x ;and then leave
rts

UpToSuper:
iny ;set player status to super
sty PlayerStatus
lda #$09 ;set value to be used by subroutine tree (super)

UpToFiery:
ldy Player_State ;SM set value to be used as new player state
jmp SetPRout ;set values to stop certain things in motion (SM originally was a JSR RTS. Saves on cycling)


What I did was use the Y register in "UpToSuper" instead. That subroutine is only taken if Y=#0. So I just made it INY STY instead of LDA #$01 STA. Also in "UpToFiery" changed it to "ldy Player_State". I meant to do that but it was a typo. -ShaneM


ShaneM
Posted on 09-23-24 05:17 AM, in Super Mario Bros. Fixes (rev. 4 of 09-23-24 03:33 PM by ShaneM) Link | ID: 926

Micro-Goomba

Level: 7

Posts: 12/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
@SMB2J-2Q

I haven’t had time to look into it yet. It doesn’t fix any glitch I’m aware of. I know the music engine is set up differently on SNES. I looked up a Youtube video of the NES version and SNES. I notice that on NES the end of level music doesn’t play until after Mario gets off the flag and there’s a brief sound pause. But on SNES it plays while still on the flag. That lines up with the code’s order. My guess is that is what it does - changes a moment of silence from the NES version to make the transition more fluid. I’ll know more when I test it.

Edit: Yeah; that’s exactly what it does.



ShaneM
Posted on 09-24-24 03:18 AM, in Super Mario Bros. Fixes (rev. 9 of 09-24-24 05:16 AM by ShaneM) Link | ID: 939

Micro-Goomba

Level: 7

Posts: 13/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
SMB2J-2Q,

If you already knew the answer then why did you ask the question? Lol

You could have just shared what it did.

What the SNES does is run the end level music one frame sooner than the NES version does. I do like that change.

Here’s one I noticed: On SNES it just uses big Mario’s jump sound for both size players when jumping.



ShaneM
Posted on 10-08-24 04:27 AM, in Super Mario Bros. Fixes Link | ID: 1051

Micro-Goomba

Level: 7

Posts: 14/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 days
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

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

Micro-Goomba

Level: 7

Posts: 15/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 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 Super Mario Bros. Fixes (rev. 2 of 10-10-24 03:28 AM by ShaneM) Link | ID: 1082

Micro-Goomba

Level: 7

Posts: 16/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 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


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

Micro-Goomba

Level: 7

Posts: 17/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 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


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

Micro-Goomba

Level: 7

Posts: 18/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 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.



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

Micro-Goomba

Level: 7

Posts: 19/19
EXP: 1238
Next: 210

Since: 08-21-24

Last post: 155 days
Last view: 114 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




Main - Posts by ShaneM

Affiliates:


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

Page rendered in 0.141 seconds. (1019KB of memory used)
MySQL - queries: 105, rows: 462/468, time: 0.115 seconds.