Newb decompiling first game; Convoy No Nazo

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
Venutech
Posts: 11
Joined: Mon Jan 30, 2023 12:13 pm

Newb decompiling first game; Convoy No Nazo

Post by Venutech »

I've been watching NES dev videos on YT for more than a year to satisfy my curiosity on how games actually worked. Once I got some confidence with assembly I started tearing down the famicom game, convoy no nazo.
Basically, I'm learning everything at once and it's going great. Today I'm starting to understand how to load a new column of tiles to the nametable while scrolling.
One thing I'm not sure I understand is I'm finding useless loops happening; is this because it's waiting for the next vblank since there's nothing else to process?

Did you know? You get a 1-Up at 10000, 30000, 50000... points
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Newb decompiling first game; Convoy No Nazo

Post by Oziphantom »

wait for next frame is very common. I.e if you want to slowly fade, or you want to transition the screen, you wait for the next frame. Sometimes you just want to pause the game for a while to let them read the text or something. So you just wait for X vblanks were every 60 = 1 second.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Newb decompiling first game; Convoy No Nazo

Post by pubby »

Waiting each frame ensures a consistent frame-rate. Otherwise the game logic would run as fast as possible, and the action would slow down when more stuff is being calculated.
User avatar
vermiceli
Posts: 12
Joined: Tue Nov 24, 2020 5:07 pm

Re: Newb decompiling first game; Convoy No Nazo

Post by vermiceli »

In Contra, once the game logic is executed and the rti instruction is called to exit from the interrupt, there is a forever loop that repeatedly adds the "frame counter" (a value incremented every frame) to an value used as a random number. By adding the frame counter repeatedly without worrying about any overflow, you essentially have a random number to use in game logic, especially because the number of cpu operations is different each vertical blanking interval.

Code: Select all

RANDOM_NUM = $34
FRAME_COUNTER = $1a

; run between NMI interrupts after interrupt code finishes
; loop forever updating RANDOM_NUM
forever_loop:
    lda FRAME_COUNTER ; load frame counter
    adc RANDOM_NUM    ; add the frame number to RANDOM_NUM
    sta RANDOM_NUM    ; update RANDOM_NUM to new result
    jmp forever_loop

nmi_start:
    ...
    [game code]
    ...

    rti ; return to forever_loop until nmi is triggered again
        ; rti pops the processor flags and then the program counter
        ; then starts executing at that location
User avatar
jeffythedragonslayer
Posts: 344
Joined: Thu Dec 09, 2021 12:29 pm

Re: Newb decompiling first game; Convoy No Nazo

Post by jeffythedragonslayer »

Oziphantom wrote: Mon Jan 30, 2023 10:30 pm wait for next frame is very common. I.e if you want to slowly fade, or you want to transition the screen, you wait for the next frame. Sometimes you just want to pause the game for a while to let them read the text or something. So you just wait for X vblanks were every 60 = 1 second.
Are fades/transitions on the NES usually done in their own little special game-loop-with-nested-wait-for-vblank loop inside it or by special "game mode" enum variables that temporarily disable controller input until the fade/transition is complete?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Newb decompiling first game; Convoy No Nazo

Post by tepples »

Dunno about "usually", but Full Quiet and Garbage Pail Kids put fades in the ordinary game loop using four variables.

1. Current fade level: $00 for fully dark, $40 for normal, $80 for fully light
2. Fade target level: same value domain
3. Fade rate: number of units per frame
4. Dirty things: bitmask of things that need to be redrawn sometime once there's space in the VRAM buffer

Each frame, if the target level is less than the current level, add the fade rate to the current level. Otherwise, if the target level is greater than the current level, subtract the fade rate from the current level. If this causes the high nibble to change, set dirty things to schedule re-uploading the palette. Disregarding controller input is separate. Some actors' state machines wait for the level to reach some target before doing something.
Post Reply