Okay, I have loaded an 8 by 16 sprite on my game, and instead of being like 8 pixels vertical, and 16 horizontal, it was the other way around! any explanation?
That's because it's 8x16... not 16x8 (X always first)
Sprites on the NES are always 8 pixels across. The 8x16 bit tells whether sprites are 8 pixels down or 16 pixels down.
Did any arcade games based on the NES chipset use a vertical monitor?
Oh, I always thought it was the other way. Like in Final Fantasy, I always thought the character's were made up of 2 16x8 sprites. Does that game use 8x16 sprites? if you open the game up in like yy-chr, you see there's the top half of the character, and right next to it, there's the bottom half. and I was wondering how they did that, do you know?
Final Fantasy uses 8x8 sprites. How it's arranged on the pattern tables doesn't matter when it comes to how it's displayed on the screen. With 8x8 sprites you can arrange them anyway you want on the screen.
Final Fantasy does 16x8 sprites in software, not in hardware.
However, if you plan to use 8x16 sprites in your games, remember that the bottom tile should always go right after the upper tile, and that usually made the content of the pattern table unundertandible for an human unless you're using Tile Molester that can show directly 8x16 tiles.
Also, the LSB of the sprite tile # is replaced by the pattern table selection when using 8x16 sprites, and the actual tile # is always an even number for the top tile and the odd number just after this one on the bottom tile. (this is pooprly doccumented)
This has the advantage of be able to use both pattern tables for your sprite data. If you don't, use 8x8 sprites.
Okay, this is kind of newbie, but I have a very important question. How do you use CHR RAM? I couldn't ever find any info on it. I need to find out because Bregalad and I have a HUGE project, and I NEED to use CHR RAM, for graphics effects and stuff. Like, where would you put it? Where would you org it? or what would you do to make CHR RAM? I'm very confused...
Firstly... make sure you use a mapper/board which supports CHR-RAM. AFAIK, mapper 0 does not (at least... Kevtris' NROM/RROM docs only mention CHR-ROM.. never CHR-RAM)
Then, the CHR data can be stored anywhere in PRG -- you can .org it anywhere just like any other kind of data in your game (like level data, or object data, or whatever). To load the graphics, you must write each tile to PPU memory via $2007 (ppu$0000-$0FFF is the left pattern table, ppu$1000-$1FFF is the right pattern table). Each 8x8 tile is 16 bytes... so to set a single tile of CHR-RAM you will need to make 16 writes to $2007
Oh man... That's going to be an annoying tedius ROM hog... Yeah, Bregalad and I are using MMC1, so I think it will be okay. Man, that sucks, though. You have to write $2007? that's strange. But thanks for the info, really helped.
Wait... you write each tile VIA $2007? How does that work?
OH! yeah, I was forgetting to write to $2006! I wrote 0f and ff to 2006, and it ended up on pattern table $1000, any clue? Oh, oops, it should probably be at 00 00. Yeah, probably not a good idea to triple post, sorry.
Now for my fourth post... I was wondering if there was a quick way to do CHR RAM? Like could you do it db style? Because I tried to do it like this, just a rough idea:
ldy #16 ; just one 8x8 tile for now
ldx #0
charload:
lda chardata,x ;chardata being well... the character data.
sta $2007
inx
dey
bne charload
I did it like that, but the data was all funky, and instead of diplaying an exclamation mark in the pattern table, it displayed a tile that was half white, half black. My pallete is greyscale from black to white. Any ideas about what to do? or do I have to do a ROM hog 3000k asm file with 4096 writes to 1 pattern table?
Each tile is 16 bytes... so when you set the address to $0FFF before... that wrote one byte of the tile to the left pattern table, and the other 15 to the right pattern table. The actual offset in PPU space of each tile is the tile number * 16 (or tile number left shift 4). Therefore, tile $53 starts at address $0530 for the left pattern table and $1530 for the right pattern table. If you want to change the whole tile you must write all 16 bytes of the CHR data (each row = 2 bytes... one for each bitplane. 2 bitplanes * 8 rows = 16 bytes)
You example code looks like it could have worked if the PPU address was set properly... or it could have not worked if you set the address wrong. If you set the address to something weird like $xxx7, then it'll be off... which will cause graphics to get weird.
I don't know what I did wrong. I have exactly that code, and I set up the PPU like so:
lda #%000001110
sta $2001
and there's nothing in $2000. Any suggestions?
Are you doing this in NMI? if you have BG enabled you must have all this drawing done before VBlank ends. Otherwise... turn the PPU off and leave it off until your drawing is complete, then turn it back on next VBlank.
What PPU address did you set? You didn't put that part in your code above. You are setting the PPU address with $2006 first... right?
Oh! I figured it out. I was orging the char data at $0000, and it was in a different bank, and that probably made it all messed up. But yes, I fixed it. This is a question that has been bothering me for quite some time. How would I load more than 255 bytes at a time? I can only have x go up to ff, and that sucks. Any suggestions?
(Indirect),Y mode is for just that
You load a pointer to somewhere in Zero page and use Y to index it. This way you can change the high byte and address all 64k of space with it.
Code:
; example to read $8000-$9FFF and move it all to $2007
LDA #$00 ; low byte of pointer
STA $10
LDA #$80 ; high byte of pointer
STA $11
LDY #$00
loop:
LDA ($10),Y
STA $2007
INY ;increase Y to index
BNE loop
INC $11 ;Y wrapped to zero, so increment high byte of pointer
LDA $11
CMP #$A0 ; see if we're done
BNE loop
; here, all 8k will have been moved, all done
Except instead of #$00 and #$80 you'd normally use #<label and #>label
Hmm... Why did you say CMP #$A0? I did that, and it went weird, but I did CMP #$FF, and it worked fine.... ???
Okay, memblers, I'm going to send you something. I've redone the nesasm helloworld program by K-ZS, but I've used CHR RAM, and I think this would be useful on the main site, if people are to ask about CHR RAM again, they could be forwarded to that, what to you think? I think it will be newbie friendly, because I've commented on it and stuff. So tell me if you want it on the main site, and I'll send it to you.
Celius wrote:
Hmm... Why did you say CMP #$A0?
Because my example was loading $8000-$9FFF... so it'll stop at $A0xx. Of course you'll have to adjust the code so that it works with your addresses and whatnot.
oh... oops, I forgot.... thanks for telling me.
Ah yeah, can't forget the comparison to end it. I should elaborate my example also.
Code:
lda #<label
sta $10
lda #>label
sta $11
ldy #0
ldx #((label_end-label)/256) ; or just #$20 for an 8kB CHR
loop:
lda ($10),y
sta $2007
iny
bne loop
inc $11
dex
bne loop
label: .incbin "file.chr"
label_end:
Mine is just like Disch's. I have it orged at $8000, and it's 8K. Hey, could you do a combo of incbining and data? like make a tile with code, and put it in a blank space in the chr file? is that possible? i would do it, so I could have constantly changing tiles, like the water tiles on ff2, I think they just lsr the whole time, right? they shift the graphics bits to the right, right? I think they do...
Okay, do you guys know any good methods to update tiles? like the water on ff2? I tried waiting this code:
;#$01 is currently in ab right now
loadstuff:
lda ab
sta $2007
....
routine:
lda vbl_count
cmp #60
bne routine
lda #$02
sta ab
...
Yeah, I tried that, and it didn't really work. and my vbl routine is just fine. Any suggestions?
Well, making such effect is a bit tricky.
I think the best way to do it would be to store the actual tiles in RAM, then modify the RAM and upload it on VBlank if needed.
Doing a such water thing would be :
Code:
lda #>WaterTileNmr*$10
sta $2006
lda #<WaterTileNmr*$10
ldx #WaterIndex
lda WaterBuffer,X
pha
asl A ;Setup the carry in function of the bit 7 of water
pla
rol A ;All bits are rotated, and bit 7 becomes bit 0 (8-bit rotation)
sta WaterBuffer,X
sta $2007
But such code is exclsively for FF-style water... if you want to do anyother effect, you'll have to make a different algoritm, or simply load an alternate tile periodically. However, remember the VBlank limit while loading stuff in $2007. It allows VERY few tiles to be loaded in a single VBlank, in NTSC. (12 in the best case, see "Battletoad's writing to $2007 system" thread in NESDev section). PAL can load much more, however.
I wouldn't run the rotating code during vblank. I'd do that during the frame, then in vblank just copy the buffer to VRAM. Same thing as updating the nametables, just different data to a different address.
It's like fighting a boss that cycles between being dormant and agitated: you equip the proper weapons and heal the party before the boss becomes active again.
Lol, I like your game playing VS game programming comparaison.
But the rotating code is very short, and you'll need to do it only once per frame (if you do it like FF), so doing it in VBlank is okay... scince you have nothing else to upload. I'm pretty sure that FF2, FF3 and Hanjuku Hero does that in VBlank.
Even if you have time to kill in VBlank... I still wouldn't recommend putting that code in VBlank... but rather I'd do it after all my time sensitive code (the stuff that HAS to be done in VBlank) is finished. After all that crap is out of the way, the scroll values are reset, the screen is turned back on, and the thing is ready to draw a frame.... THEN do your water animation, joypad reading, and all the other stuff that needs to be done every frame -- but not necessarily in VBlank.
You never know when you might have to add new things to VBlank.. even if you have time to spare now, you might not in the future. It doesn't make sense to eat up precious VBlank time with something that doesn't need to be there.
Okay, I just had a problem with 8x16 sprites! I load them all in their proper place you know, and for some reason, there's always sprite #0 where it's supposed to be, and a clone of sprite #0 in the upper left corner. It's really dumb! I know for a fact that my code is fine, I don't have any stray sprites that have the value of tile #0 and coordinates for 0,0. I made sure by only having what sprite variables I'm using in RAM, and not random ones that I can use in the future. ?????
Are you making sure to reset all Y positions of unused sprites to $EF?
I would go $F0 or higher -- that way they'll never be in range ($EF will be found to be in range on the last scanline -- however they will never be drawn)
I don't have any unused sprites at the moment, though! I don't know what's wrong. Have you heard of anything like this!? This is dumb. I wish it would work!
You're using all 64 sprites?
Well then either their coord placement is wrong (very likely)... or the Sprram Address is messed somehow (write $00 to $2003 before DMAing!)
In the case of the former... which is almost certainly the problem... double-check to make sure you really ARE moving all your sprites properly... because you obviously aren't if they're being placed at 0,0 when that's not what you wanted.
Oh, I'm sorry, I misunderstood you. I thought you meant like this:
.bss
.org sprites
sy .ds 1
st .ds 1
sa .ds 1
sx .ds 1
s2y .ds 1
s2t .ds 1
s2a .ds 1
s2x .ds 1
And say you were using the first four variables, and s2's variables were just sitting there. Oh, I'm using like 22 sprites. when I make an 8x16 sprite, just 1 , there's a clone of it in the upper left corner. I have no idea why. This has happened before. WHY?
Oh, for some reason, what it did was display tile #0 at coordinates 0,0, it wasn't a specific value assigned to a sprite, it just automaticly did that for whatever reason, it was stupid. I don't know why, but that was what happened.
It does that if you clear out sprite memory with $00 values. Most of the time, programs' init code will just spray $00 all over the 2 KB of RAM at CPU$0000-$07FF. This zero-filled memory generally includes a copy of OAM, which most programs seem to stick at CPU$0200-$02FF. But in 8x16 pixel sprite mode, values of $00 $00 $00 $00 mean "draw a sprite whose upper left corner is at pixel coordinates (0, 1) using tile data at PPU$0000-$001F, not flipped, in front of the background, with colors located at PPU$3F11-$3F13". Use a value between $EF and $FF when clearing out the sprite page, and the PPU will interpret the unused memory as "draw a sprite below the bottom of the screen", hiding the garbage.
I personally like have a routine that I call at the end of the sprite-drawing part of my frame, that will clear all unused sprites.
During the writing part I always have my X indexes where in OAM I'm writing to. You can do it with Y, or store it in a variable, the method itself is irrelevant.
Then, when it's time to write something to $200,X or $200,Y (or anithing else than $200, again, the exact values are irrelevant) check for a variable called SprReady or something, if isn't zero, then don't write anything to SPR RAM (if will be clear anyway cause of VBlank, see below). Once you wrote a single sprite, check for your X or Y or whatever index register to overlaps from $fc to $00 ($fc will be the last sprite possible). If you use another value than $4 to add for sprite cycling, that doesn't change anything scince you sart at zero (see
http://nesdev.com/bbs/viewtopic.php?t=469&sid=61b95cabd1e61841994eedd268078fa1 for more details).
Then, if all 64 sprites are being already mazed, set the SpriteReady variable, so you will never override sprite 0 for hit detection (if you don't have any hit detection, the fact to overlapp from possible 64 sprites won't affect the game, but it is still better to do that).
Then, once all your software sprites are mazed into hardware sprites, call the "ClearRemainingSprites" routine, that will check for the SpriteReady variable, and return immediately if set (all sprites were mazed). Else, take the index variable that was indexing the OAM buffer at $200,X, and clear all remaining adresses with the value $f0 until the whole OAM is full. Then, set the SpriteReady variable.
At VBlank, do sprite DMA only if SpriteReady variable is set, and clear it. So it will be clear anyway once out of VBlank. Now, the whole loop has been presented, and that should setup all your sprites corecly. Did you get it ?
Okay, I have a question that has to do with emulators. My game works very fine and properly on Nintendulator(the best and most accurate emulator ever!), and it doesn't work to well on FCEUXD Ultra, or JNES, or (like anyone cared ever in their whole life)NESticle. In FCE UXD ultra, it loads the sprites improperly, and the left key function doesn't work. In JNES/NESticle, it just shows a black screen. Do you think it will work on real hardware if it works on Nintendulator? Do you think the code is fine if it works on Nintendulator, regardless of how it works on other emus?
I think it's a bad idea to write code which requires any more of the hardware than necessary. If you can change your code slightly and have it work on all emulators, why not? Maybe one could argue that leaving it as-is encourages emulator authors to improve their emulators; if so, I can provide you with simple code that you can insert that will probably prevent your game from running on all emulators, but not on a real NES.
Well, I've downloaded several emus from the "best emulators" section on zophar, and my code actually works on most of them. Okay, I'm making a short program that will simulate the FFVII menu, and I load the portraits as 6 8x16 sprites. There's a glitch with FCEUXD, and I think NEStopia, that makes the first portrait load only 3 or 4 of the 6 sprites. But most emus like virtuanes, nintendulator, nnnesterj, they work fine on. Do you think it's reliable code for the real NES? Because I WILL be putting this demo on the NES if it ends up working in the end.
I don't know what kind of tricks you could be pulling that would cause this issue. I mean unless you're doing very precise timing tricks or relying on weird PPU operations there's no reason why something as simple as displaying sprites to the screen wouldn't work in every emulator around.
Unless you know that the problem is with the emulator... then assume the problem is in your game and try to fix it. Fortunately, FCEUXD is one of the emus which is having a problem... so you can use its debugger to track down the problem.
I 100% agree with Dish. I think that you should track your problem because displaing sprites is something simple, that even Nesticle should emulate right.
- Did you make sure to do sprite DMA during VBlank ?
- Do you make sure to write the good value to $4014, and not increment it, ror it or whatever (I think that you're doing nothing of theese, but that would sure cause many problems)
- Do you do sprite DMA only once in a VBlank ?
- Are you incrementing your sprite index by 4 every sprite, or do you have some kind of sprite cycling incorporated ? If so, did you make sure it works proprely ?
- Is there more than 8 sprites on a single scanline ? Because you can have some emus allowing show more than 8 sprites per scanline, so that would work, and not work with others
- Do you setup palettes proprely during VBlank or during a routine that turns the screen off via $2001 ?
- Do you make sure to not read $2000, $2001, $2003, $2005, $2006 or whatever ? (write-only registers)
- If you use a MMC1, did you make sure to reset the latches (writing $80 to any of the registers) at reset, at least once (this can be done easily by incrementing any value above $80 in PRGROM, so it will write back with bit 7 set), and then write to all registers 5 times bit per bit (and not 4 times because you don't use all bits or something) ?
Well, it's kind of questions to ask when such problems happens. Usually, when my programm doesn't work with an emulator, even Nesticle, I always try to know why. Because it doesn't setup scroll corectly, because it doesn't emulate the mapper you use proprely, etc....
Well, I got my code running in JNES and NESticle, woopdidoo, but still, it means my code is getting somewhere. I realized that I enabled the NMI routine (which does my sprite loading) way too soon. I enabled it on reset, and that was a bad idea. Now I enabled it after writes to variables in sprite dma. It still doesn't work in FCEUXD ultra, but i'll look at the debugger thing.
Effectively, NMI should be off at reset and turned on at least after the 2 waited frames. If you do like I said, and if you clear the RAM at reset, your flag SpriteDMAReady should be clear, so no sprite DMA should happen until something is in set. Also, it would be a good idea to keep the NMI and the sprite bit in $2001 (I don't remember if it's bit 3 or bit 4) off until the whole thing is loaded proprely.
blargg wrote:
I can provide you with simple code that you can insert that will probably prevent your game from running on all emulators, but not on a real NES.
I use something like that but much simpler for detecting nesticle in some of my more recent projects. It just checks to make sure that a CPU$2002 read clears the vblank flag (four instructions), and then it throws up a "warning: compatibility not guaranteed; press start" screen if not.
Okay, this is kind of dumb, but I've always understood that branches in 6502 executed a jsr, am I right? Well, I don't think I'm right, because I have a routine that branches off, and excecutes an rts at the end of it, and it never returns from the subroutine! why?
No, there's no branch to subroutine. RTS pulls the return address off the stack, that only works after a JSR or messing with the stack manually.
A branch will simply continue running either at the next instruction, or the branch location. So replace your RTS with a JMP to where you want it to go at that point. Or if there's nothing else to skip after the branch, you can put your code after the branch and reverse the branch condition.
Okay, thanks. I always thought it was the other way, though. I am wondering if anyone knows of a good "getchar()" style function on 6502. And then I'm wondering if there's a way to do something like this:
getvalue:
ch = getchar()
background:
lda data
sta $2007
data:
.db ch
How would you first, store a number in a variable, and have that number displayed on screen? and how would you do a getchar() style thing, such as naming a character on an FF game? You know, it somehow takes the letters you select, and it stores them in a variable, then it takes that variable and puts it on screen. Do you know how?
Note than with NESHLA, you normally don't have to bother with branches any longer, scince you have basic/C style loops.
But, declaring variable and data bytes (.db) in NESHLA is damn hell ! I can't get this working as I like.
To name your characters... Just make small buffers in RAM that will content a string with the letters of the name the player had choosen. You'll need to make several copies of the same buffer, once for each saved game (I think you sould not bother about saved games right now, so just have a single buffer for each character).
When it's time to show it on the screen, just read it and write the output to $2007. It has to be filled with the letters the player had chossen on the name selection screen... it's up to you to programm an engine for that, but I think it isn't hard at all.
Okay, I need to read that guide to neshla, even though it kind of sucks. Can you even do a .db in neshla? or do you have to do like a "byte" thing? I don't know. I think you can do something like this:
byte [$0,$0,$64,$02,$0...]
in NESHLA to do that. I have been working on a demo in nesasm, and I was going to just convert it to NESHLA, but I realized that I don't know too much about NESHLA. I need to go learn more. It's really different...
Yeah, it is really different. I have been able to input data bytes in PRGROM bank section, but it needs 2 lablels and it rather sucks (or am I doing something wrong ?) There is an example in the gide to NESHLA, and yeah, that guide isn't too much complex and doesnt go in details, but it does the works, not like the guide of XOR-Cyst that is actually unundertandible, at least for me.
I've also been able to inbin a file, but I've been unable to incbin a file and assign it to a label, a variable or anything. It just suck. I ask myself if it is really a good idea to want to use NESHLA... Maybe I should perseverate a bit.
The problem with NESHLA is it's way too confusing and stuff, and there's way too many macros! and I don't really know what I'm doing. You know, I wish that NESASM had more options, because I would really use it if it did. Right now I'm making a demo of the menu, and so far it's turning out really well, I have all the character's portraits there, and I have the hand moving up and down the thing just right, and it stops when it gets to the top, and it will only let you move one menu option down per press, which I think is good and unbuggy. And I took out the "order" option from the menu, because there was not enough space on the name table for it, and you will be able to just press left, and it will allow you to switch positions like it did on FF3. I don't think that's too bad. There is a little glitchybuggyunreliablemethod type thing I use, but it's hardly even noticable, and I think we'll be fine. There's a variable that's called mflag (materia flag) that will go up when a is pressed while the finger is over "materia", and it will start increasing the flag from that point, and since it increases at like 50000 miles an hour, as soon as you press a, it will already have gone from 0 to 3, and if you hold it too long, the hand will go to the first picture and since you're holding a, the flag is still increasing. And when the flag goes past a value of 6, it will load the materia screen. I made it so it will stop on 7 though. But, another problem comes with that. You could tap a when it's over materia really really fast, and select somone's portrait, and tap a again really fast, and it wouldn't load the materia screen because the value might not be 6 yet. You know? Well, I'm just rambling. But yeah I'm doing it in NESASM, and then I'm converting it to another assembler. What I really like about NESASM is that it's somewhat easy to use. Wla-dx is SO CONFUSING! I don't even know how to like assemble anything with it. It's documentation is like CRAP. NESHLA is way too hard to use. I like that NESASM allows an easy set up for an ines header and it's really just easy to use, and I appreciate that. I don't think it would be powerful enough for FFVII, so we're deciding on another assembler. Is there just an assembler that's like NESASM with more options?
Well, WLA DX is not that confusing. It's not too well documented, however it's still decent. I think you have to spend a small amount of time to change your habbits. For example, locals labels are "_label" instead of ".label" that were in NesASM.
You can split all you code in sections, section are a amount of bytes (of code or data) that are packed together in the final rom file, but section between them seems to be assembled in the alphabetical order of theese labels (I'm not sure, but it useless to know that).
There is also ramsections for variables. I think that system is exellent, because you know exacly whitch piece of code/variables can be packed toghether with witch one, and you can force section to a specific adress as you like (vectors for rom sections, or SpriteDMA for ram sections), and you can let it choose where it will be in the bank, but force the bank number/ram slot, or eventually put if in any bank, where there is room.
You can define your system architecture, where ROM slots are swapped in, and where you would define your different RAM slots. This enables you to define your system's architecture, scince the assembler is multi-system compatible. You can do library files, where you store bunch of code, and call it from various projects. Then, only used code will be compiled in the output.
Eventually, WlaDX has more calculations and flexibility possible than NESAsm. If you have a feature request or a bug report, you can post it on Wla-DX forums and the author will fix it or examine your demand.
Eventually, the day where you want to move to GBC dev, SNES dev, or whatever, you can still use Wla-DX.
All that stuff makes me love Wla-DX. The only inconvegniant is the forced .w after word adresses. For example :
lda Buffer.w,X
sta $2006.w
lda Buffer+1.w,X
sta $2006.w
This is not forced, but highly recommanded, and you may have bugs if you don't do it (it is at least needed for word variables, it can be skipped on a sta $xxxx, but not for a stx $xxxx or sty $xxxx) Theese last two were bugging in the original version, and I taught the author, and he fixed it.
PS: I didn't undestand how you load your materia screen at all. I think you just need to load it when the player clicks on a face (with A button), you should turn the screen off for a frame, just like FF1 does. You're trying to load it in the second name table when the player press A ? If you really don't want to turn the screen off, you can load it step-by-step during VBlank like FF2, FF3.
Yeah, I explained that crappy. Now when I say click in this next section, it means press a. I have a flag called mflag, which is short for materia flag. This is a variable that is incremented when you click on materia, which is something I should change. when you click on materia, the hand will go and point to the first character's portrait, where you know, you can move it up and down to select a different portrait if you want. When you click the character's portrait, the mflag variable will increment a little more until it reaches a value of 6, then the materia screen will be loaded. The problem is, you can hold "a" a little too long, and it will just select the first character's portrait, and load that character's materia screen. It's kind of like some SNES games where you can hold the pause button, and it will quick like pause, and unpause, because you have to tap it really really fast to pause. It's like that if you hold "a" too long, but it's not that extreme. But there's also another problem where you can click on materia really really fast, then click on a portrait really really fast, and it may not load it, so you have to press it again, or at least until mflag is 6. Does that make sense?
The problem sounds like you are directly checking the button states to perform your actions, which won't work. You need to detect when a button state CHANGES; fortunately, there is a very convenient way to handle this:
Code:
curctrl: .res 1
lastctrl: .res 1
hitctrl: .res 1
readctrl:
LDX #$09
STX $4016
DEX
STX $4016
: LDA $4016
LSR A
ROL curctrl
DEX
BNE :-
LDA curctrl
EOR lastctrl
AND curctrl
STA hitctrl
RTS
Check bits in 'curctrl' to see which buttons are currently pressed (i.e. for walking and running), and check 'hitctrl' to see which buttons the user JUST pressed (for stuff like menu navigation).