One time when I was jamming in my old band Slow Intentional Damage, someone told me that I was like a little kid in a candy store while talking about the songs that we were writing. I showed all kinds of excitement when we were talking about what we could do at *such-and-such* part, or what we could do on the third stanza of *such-and-such* part. There have always been things that get me going like that, and NES development happens to be one of those things. Coming up with new ideas, even if I don’t make them happen on a game, makes my mind wander. I think it’s creating things that really grip my imagination. I probably get that from my father, who used to do things such as create his own armor for the Society of Creative Anachronism.
After finishing a game, every now-and-then shortly thereafter, I like to hit Google and see if there are any new things that turn up about the game on the web. I was pretty much done doing that, as I didn’t expect to find anything else on what was going to be the last time I did such a search. I released it at the end of April, so it’s getting close to six-months out, and there won’t be much new to read about what people might have to say about it. So you can imagine my surprise (and excitement) when I actually found something new on a blog called Irish Nintendo Fan (love the name of the site!):
One of the featured homebrew reviews [in Retro Gamer Magazine issue #93] I like was NES Virus Cleaner. I tried it for myself and it’s quite addictive but tough, avoiding things like you would in say, Frogger and collecting all the bits to complete a level.
Ah, good ol’ Retro Gamer Magazine! My game prior to NES Virus Cleaner, that being Pegs, actually appeared in there as well. It had a fair review from a guy named Jason Kelk, and though I can’t tell for sure, I believe he did the write-up this time around, too (the initials J.K. appear at the beginning of the article).
Once again, it is a solid write-up, and I’m grateful to have appeared in a magazine! It’s a cool feeling for sure. I’m definitely going to look into getting my hands on this issue, as I failed to get the Pegs issue last time. Here is a pic of it that a friend of mine, and also one of the lead testers of NES Virus Cleaner, took for me. Click to read it:
The new phonebook is here!
I don’t know if you still lurk around here, but I’d like to once again thank you, Jason, for the opportunity to be in the magazine! Oh, and you can rest easy knowing that I don’t hit the coffee as hard as I used to ; )
Yesterday I decided to try and implement an intro for the story of Ardent Assault. I kind of wanted that Star Wars-esque scrolling the words up dealy. The only problem was, I have never scrolled more than one screen at a time! I thought it would be fairly easy to implement, and had hoped it would take only an hour. Unfortunately, it took up my entire day yesterday, plus a little time after I got home from work to get it to behave properly. Ugh.
But the way I have the scrolling now feels… I don’t know. Like I’m not doing something properly. I can’t seem to comprehend the relationship between $2000, $2005, and $2006 that I’m always hearing about. Anyway, here is the code that I came up with after all kinds of time spent, and some guidance in IRC:
intro_nmi:
lda time_write_count ; Check if we should write words to background
beq :+ ; if so, jump over a couple instructions
dec time_write_count ; if not, decrement time_write_count
jmp @scroll ; and continue to scroll the screen
: ldx offset_x_reg ; Use RAM register for our X offset
lda intro_ppu_addy_hi, x ; and check if #$ff is loaded from the table
cmp #$ff ; if it isn't, jump over an instruction
bne :+ ; if it is #$ff, jump to the end of NMI,
jmp end_nmi ; effectively freezing the program
: ldy offset_y_reg ; Load the RAM register for Y offset
lda intro_lo, y ; and use it to setup the pointer. The pointer
sta pointer1 ; points to words to be printed to the
lda intro_hi, y ; background
sta pointer1+1 ;
lda intro_ppu_addy_hi, x ; Use X to select from a table of background
sta $2006 ; addresses to which to write to. Hi and lo,
lda intro_ppu_addy_lo, x ; of course
sta $2006 ;
ldy #$00 ; Use Y _without_ the RAM register offset,
: lda (pointer1), y ; and use it to grab the letters of the words
sta $2007 ; and write them to the background
iny ; increment Y
cpy #$1a ; and check it against #$1a (the number of
bne :- ; letters in each row). Branch back if needed
inx ; Increment X and store it back in the RAM
stx offset_x_reg ; X offset
inc offset_y_reg ; Increment the Y RAM offset
lda #$38 ; Use #$38 as the amount of time that needs to
sta time_write_count ; countdown before writing to the background
lda reg2006hi ; Select the base nametable. In this routine,
sta $2006 ; reg2006hi will be either #$20 or #$28
lda #$00 ;
sta $2006 ;
@scroll:
bit $2002
lda scroll_x_hi ; scroll_x_hi will never be anything but zero
sta $2005 ; in this routine
lda scroll_y_lo ; We want to scroll slower than 1 pixel per
clc ; frame, so we have a hi and lo value for
adc #<intro_scroll_speed ; the Y scroll. intro_scroll_speed is set
sta scroll_y_lo ; at $0040 in the declarations
lda scroll_y_hi ;
adc #>intro_scroll_speed ;
sta scroll_y_hi ;
cmp #$ef ; Check if the scroll has reached #$ef
bne @store_scroll ; branch and store scroll_y_hi in 2005 if not
lda reg2006hi ; If it did reach #$ef, check if reg2006hi is
cmp #$20 ; #$20, and if it is...
bne :+ ;
lda #$28 ; ... stick #$28 in there
sta reg2006hi ; to use as the base nametable next time
jmp :++ ; then jump two instructions
: lda #$20 ; If reg2006hi was NOT #$20, then make it that
sta reg2006hi ; number
: lda reg2000save ; Load the $2000 register we made in RAM, and
eor #%00000010 ; flip the bit for which nametable to scroll
sta reg2000save ; on. Be sure to save it in both reg2000save
sta $2000 ; and the $2000 register itself
lda #$00 ; Reset the scroll_y_hi to zero
sta scroll_y_hi ;
@store_scroll:
sta $2005 ; The second and final write to the scroll
jmp end_nmi
I know there is some clean-up that can be done, like the inx/stx thing, followed by an inc, but whatever. Anywheres, the main loop of the program does nothing but keep waiting for another NMI to fire.
But yeah, I’m feeling like it’s just not right. It works, but feels wrong. If anyone has a better approach for this, please let me know! If you just want to see the end result of this, here is a vid (ignore the font, it’s just a placeholder).
So I was at work thinking to myself. I said to myself, I says, “Self, what was it that you had heard about that one time… you know, about preserving a hi score on NES in the 700 page of RAM?”
What I’m babbling about, is this. You know how you play some game that has a hi score feature in it, but if you press reset, the hi score is still there? Well, oddly enough I never put much thought into it. But tonight it popped into my head, and I figured out how to do it. I remember someone telling me that the way you can do it is by having a space in RAM set aside that you don’t erase at the reset routine, and fill it with specific bytes. When it gets reset after those bytes are fed into it, you test them against the same bytes in ROM, and if they match, you don’t zero out the hi score. I don’t know if that sounds confusing, but here’s the code I came up with:
; in the declarations, of course
ram_check = $700
hi_ten = $706
hi_hundreds = $707
hi_thousands = $708
hi_ten_thousands = $709
hi_hun_thousands = $70a
; this is in ROM
rom_check: ; The string that gets put in RAM for
.byte "SLYDOG" ; the hi score check
; and the actual subroutine that happens at reset
slydog_ram_check:
ldx #$00
@start_ram_check:
lda ram_check, x ; compare the RAM starting at $700 to
cmp rom_check, x ; the ROM at rom_check
beq @fill_ram_check ; if one of the bytes don't match
ldx #$00 ; throw zero back in the X register
@write_rom_ram:
lda rom_check, x ; load a byte from rom_check
sta ram_check, x ; store it in ram_check
inx ; increment X and repeat until
cpx #$06 ; X is 6
bne @write_rom_ram
lda #$00 ; Now throw a zero in all of the
sta hi_ten ; hi score bytes. This means it
sta hi_hundreds ; was a hard power up, so there is
sta hi_thousands ; no hi score saved. If we don't do
sta hi_ten_thousands ; this, the NES will print garbage
sta hi_hun_thousands ; on-screen as the hi score
jmp @done_check ; routine is done
@fill_ram_check:
inx ; if the original comparison matched
cpx #$06 ; then we increment X six times
bne @start_ram_check ; to be sure the whole string matches
@done_check:
rts ; and we're outta here
It seems to work for me fairly well. It can also be used in other pages of RAM. I had heard that the 700 page was for stuff that needed to be saved, but it works in other places I tested. Anyway, I just thought it was cool and that I’d share : )