Magic Floor

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Magic Floor
by on (#226975)
Nocash's Magic Floor game is the only NES game I know of that works without a CHR chip because it uses half the nametable memory in the Control Deck as CHR RAM. I've been hacking it to work on more widely used mappers, such as a multicart mapper.

FCEUX

  • Doesn't support mapper 218.
  • Editing the header to mapper 7 (AxROM) gets the background to display. This is a good thing, as it shows that Magic Floor isn't relying on tiles $000-$03F being mirrored to $040-$1FF. But as soon as I move, the sprites disappear because it's presumably emulating the NTSC NES's bug when a sprite is rewritten with $2003/$2004 rather than with DMA ($2003/$4014). This one's on nocash to fix. RAM $0200-$07FF is currently unused.
  • Edit it to mapper 0 (NROM) with vertical mirroring, and it works and fails exactly as in mapper 7.

Mesen

  • Emulates mapper 218. The game works.
  • When edited to mapper 7, the background does not appear because the game uses vertical scrolling to center the playfield, and Mesen appears to assume horizontal mirroring until the first mapper write. I imagine that on hardware, whether it powers on with the register set to screen A or screen B, the hardware still outputs the same A10 value for all four nametables. This bug, reported on GitHub, is on Sour to fix after returning from vacation.
  • When edited to mapper 0 with vertical mirroring, the game works.

The game itself

Unlike the reviewer who made this review of the ZX81 port, I was able to get the hang of how to play after a few minutes. The one problem I found was that most maps ended up in a tedious search for the last lousy point.
Re: Magic Floor
by on (#226979)
As I said in 2012
Quote:
I was actually going to make a game for this configuration, and to make it as "normal" as possible, that is it shouldn't have crappy graphics that would make the player immediately think "oh this game is ugly because it has only a single chip".

I won't tell more because it's trade secret

This still holds true to this day.
Re: Magic Floor
by on (#226983)
And I still think we should have a compo based on this mapper.
Re: Magic Floor
by on (#227135)
Might there be a way to make the search for that last lousy point less tedious? Or am I just a scrub who needs to "git gud"?
Re: Magic Floor
by on (#227141)
tepples wrote:
Might there be a way to make the search for that last lousy point less tedious??

Maybe just smaller floor sizes?

I've added a beginners mode with smaller floors when making the AMT630A version. In that version it's storing the number of solved floors in FLASH memory, and unlocks bigger floors after reaching a certain count.
And I am about to add something similar to NES version. There's no SRAM planned in the NES single-chip cart, so it'll be just a counter in RAM. The first floor with only 12-24 possible moves, the next floor allowing the random generator to create floors with about 30-50 moves, and next time allowing up to 60-80 moves. If the large floors are gettimg too difficult: One could simply reset the game to restart with smaller floors. After playing the game (too) often, it's becoming easier to spot the remaining/missing moves.

Another idea would be a hint function that can be used only once per floor (or maybe once every 5 minutes), showing remaining moves for a short moment. But hints are a bit like cheating.

Or the action idea would be a floor scrolling at constant speed, where you just need to keep up with the scroll-spreed (ie. just need to get forward, but don't need to find all possible moves), though that might make things even more difficult for beginners : )

Speaking of more ideas, someday, I want to try to use 6-sided floor cells & triangular floor cells (at least on some system with bitmap mode, and without NES-like restrictions about color attributes for square areas).

To make the game easier to figure out: The introduction/text is a bit lengthy. Maybe it could be replaced by a tutorial mode. Or, when starting with small floor sizes: There would be enough space to display in-game instructions underneath of the floor.
But I don't know if it would be worth doing that - I guess there are a lot of people who can't make sense of the game, and the tutorial might just confirm that the game really doesn't make sense to them ; )

Btw. there are also some "dead-ends" where one could get stuck (eg. on a black field without any dark-gray fields nearby). I have currently solved by opening a black hole in the floor cell, and moving the player back to the starting point.
That's working fine, but I am feeling a bit uneasy about it because it might the game even more confusing. Don't know if that's a real problem. Did anybody play the game far enough to encounter one of those black holes popping up in the floor. And, after seeing that feature, decided to stop playing the game once and forever?
Re: Magic Floor
by on (#227146)
nocash wrote:
I've added a beginners mode with smaller floors
[...]
And I am about to add something similar to NES version. There's no SRAM planned in the NES single-chip cart, so it'll be just a counter in RAM. The first floor with only 12-24 possible moves, the next floor allowing the random generator to create floors with about 30-50 moves, and next time allowing up to 60-80 moves.

That's actually quite similar to what I had in mind: hardcode the sequence of floor sizes, with smaller ones at the start. Concentration Room does the same thing, with 10, 20, 36, 52, and 72 cell boards.

nocash wrote:
Another idea would be a hint function that can be used only once per floor (or maybe once every 5 minutes), showing remaining moves for a short moment. But hints are a bit like cheating.

If a hint function can be integrated into the game's setting, it won't feel quite so much like cheating to the player. Compare to Tetris, where the "hold piece" function was first prototyped in a couple forms before becoming something given out all the time.

  1. Tengen's NES version: Once per 30-line section, the player can enter the Konami code to turn the falling piece into the I Tetrimino.
  2. DOSArena: After clearing 4 or more lines with one piece, the player is given a "magnet" powerup. Using magnet puts the next piece into the powerup box. Using that piece replaces the falling piece (or the next piece? I forget) with that piece.
  3. The New Tetris, Tetris Worlds, and most post-2001 games: At any time, the player can swap the falling piece with the piece in the powerup box. The powerup box is then locked until the falling piece locks down.

nocash wrote:
Or the action idea would be a floor scrolling at constant speed, where you just need to keep up with the scroll-spreed (ie. just need to get forward, but don't need to find all possible moves), though that might make things even more difficult for beginners : )

That might be interesting for an "escape" sequence after having completed enough floors and discovering an enemy of some sort. But this might require saving the levels' seeds to give the player a sense of persistence within a session analogous to that in roguelikes.

nocash wrote:
To make the game easier to figure out: The introduction/text is a bit lengthy. Maybe it could be replaced by a tutorial mode.

It might also be useful to restrict the first couple boards to 2 cells wide to reduce the need to do jump moves at first, though that might result in more discarded floors as they don't meet the score >= area constraint.

Another idea: If a 1-cell move isn't open in a given direction, but the 2-cell move is, make the 2-cell move.

nocash wrote:
Btw. there are also some "dead-ends" where one could get stuck (eg. on a black field without any dark-gray fields nearby). I have currently solved by opening a black hole in the floor cell, and moving the player back to the starting point.

Yeah, I saw those: if there's no path from a cell to the starting point, it's a trap door. There might be ways to modify behavior of such cells, such as bouncing back to the cell that the player was on before. Or the current behavior could be kept with a bit more animation and sound: play a sound effect like a downward slide whistle when landing on a trap door, hide the player for a second, and then play the reverse effect when popping back up on the starting point.

I've been experimenting with changes to constraints on floor generation. In addition to your current constraint that the area of a floor must not exceed its total score, I've thought of a few more constraints to try:

  1. At least half of the cells must be round trip reachable.
  2. At least two cells on the side opposite the starting point must be round trip reachable.
  3. All colors have the same number of cells in that color. This can be done by generating a repeating pattern of [0, 1, 2, 3] and then using a shuffle algorithm analogous to the RC4 cipher.

I'll have to play with these to see their effect on discarded floors, total round trip reachable cells, and total score.
Re: Magic Floor
by on (#227155)
tepples wrote:
Another idea: If a 1-cell move isn't open in a given direction, but the 2-cell move is, make the 2-cell move.

Hmmm, then it could be almost fully played without needing Button A.
The exception would be something like "White-Black-White". Where one might either want to move from White to Black, or jump from White to White.
That could be confusing: Needing Button A in that specific case for jumps, while having automatic jumps in other cases.

tepples wrote:
I'll have to play with these to see their effect on discarded floors, total round trip reachable cells, and total score.

Yeah, might be nice. Most of the time the random floors are quite okay. But some are a bit uncomfortable (eg. only one white field, and you need to travel all the way back to that field for reaching other fields).

On the other hand, sometimes there are even maps without white fields at all, so you'll have plenty of dead-ends (which can be an interesting variation, too). Such floors could get kinda slow if you add animations with 1-second delays on dead-ends.

Oh, and I was planning to add maps with empty fields, eg. instead of solid 8x6 cell maps, also use variations like this:
Code:
  ########   ########    ######    ########   ##    ##
  ########   ########   ########              ########
  ########   ##    ##   ########   ########    ######
  ########   ##    ##   ########   ########    ######
  ########   ########   ########              ########
  ########   ########    ######    ########   ##    ##

Hmmm, the floor_map bytes are currently containing these settings...
Code:
  bit0-1 = cell color
  bit2   = pass1: 1=entered
  bit3   = pass1: 1=entered-and-tried-to-leave, pass2/3: 0=leads-back-home, 1=dead-end
  bit4-7 = arrow bits

If I am not mistaken the combination bit2=0 and bit3=1 isn't used, so one could use that to encode empty fields. With empty being meant that you can't enter that fields.
Re: Magic Floor
by on (#227169)
Results are in:
Code:
Generating 2000 rooms per combination of size and randomizer
2x6 random
  area: 12
  max_score: 5% <= 0, 25% <= 1, 50% <= 3, 75% <= 9, 95% <= 13
  rtr_area: 5% <= 1, 25% <= 1, 50% <= 3, 75% <= 10, 95% <= 12
  rtr_back_row: 5% <= 0, 25% <= 0, 50% <= 0, 75% <= 1, 95% <= 2
  score >= area: 11%
  back reachable: 20%
  2*rtr >= area: 43%
  all: 7%
2x6 even
  area: 12
  max_score: 5% <= 0, 25% <= 1, 50% <= 7, 75% <= 12, 95% <= 15
  rtr_area: 5% <= 1, 25% <= 1, 50% <= 8, 75% <= 11, 95% <= 12
  rtr_back_row: 5% <= 0, 25% <= 0, 50% <= 0, 75% <= 2, 95% <= 2
  score >= area: 25%
  back reachable: 28%
  2*rtr >= area: 55%
  all: 17%
4x4 random
  area: 16
  max_score: 5% <= 0, 25% <= 10, 50% <= 16, 75% <= 18, 95% <= 22
  rtr_area: 5% <= 1, 25% <= 10, 50% <= 14, 75% <= 15, 95% <= 16
  rtr_back_row: 5% <= 0, 25% <= 2, 50% <= 3, 75% <= 4, 95% <= 4
  score >= area: 50%
  back reachable: 76%
  2*rtr >= area: 78%
  all: 49%
4x4 even
  area: 16
  max_score: 5% <= 2, 25% <= 16, 50% <= 18, 75% <= 21, 95% <= 23
  rtr_area: 5% <= 1, 25% <= 14, 50% <= 15, 75% <= 16, 95% <= 16
  rtr_back_row: 5% <= 0, 25% <= 3, 50% <= 4, 75% <= 4, 95% <= 4
  score >= area: 75%
  back reachable: 88%
  2*rtr >= area: 91%
  all: 74%
6x4 random
  area: 24
  max_score: 5% <= 2, 25% <= 23, 50% <= 27, 75% <= 30, 95% <= 35
  rtr_area: 5% <= 2, 25% <= 20, 50% <= 22, 75% <= 23, 95% <= 24
  rtr_back_row: 5% <= 0, 25% <= 4, 50% <= 5, 75% <= 6, 95% <= 6
  score >= area: 70%
  back reachable: 90%
  2*rtr >= area: 89%
  all: 70%
6x4 even
  area: 24
  max_score: 5% <= 18, 25% <= 26, 50% <= 29, 75% <= 32, 95% <= 36
  rtr_area: 5% <= 15, 25% <= 22, 50% <= 23, 75% <= 24, 95% <= 24
  rtr_back_row: 5% <= 2, 25% <= 5, 50% <= 6, 75% <= 6, 95% <= 6
  score >= area: 88%
  back reachable: 95%
  2*rtr >= area: 95%
  all: 88%
6x6 random
  area: 36
  max_score: 5% <= 3, 25% <= 40, 50% <= 45, 75% <= 49, 95% <= 55
  rtr_area: 5% <= 2, 25% <= 32, 50% <= 34, 75% <= 35, 95% <= 36
  rtr_back_row: 5% <= 0, 25% <= 5, 50% <= 6, 75% <= 6, 95% <= 6
  score >= area: 86%
  back reachable: 92%
  2*rtr >= area: 93%
  all: 86%
6x6 even
  area: 36
  max_score: 5% <= 34, 25% <= 44, 50% <= 48, 75% <= 51, 95% <= 56
  rtr_area: 5% <= 27, 25% <= 33, 50% <= 35, 75% <= 35, 95% <= 36
  rtr_back_row: 5% <= 1, 25% <= 5, 50% <= 6, 75% <= 6, 95% <= 6
  score >= area: 94%
  back reachable: 94%
  2*rtr >= area: 95%
  all: 93%
8x6 random
  area: 48
  max_score: 5% <= 38, 25% <= 58, 50% <= 63, 75% <= 68, 95% <= 74
  rtr_area: 5% <= 34, 25% <= 44, 50% <= 46, 75% <= 47, 95% <= 48
  rtr_back_row: 5% <= 3, 25% <= 7, 50% <= 7, 75% <= 8, 95% <= 8
  score >= area: 93%
  back reachable: 95%
  2*rtr >= area: 95%
  all: 93%
8x6 even
  area: 48
  max_score: 5% <= 49, 25% <= 61, 50% <= 66, 75% <= 70, 95% <= 76
  rtr_area: 5% <= 40, 25% <= 45, 50% <= 46, 75% <= 47, 95% <= 48
  rtr_back_row: 5% <= 4, 25% <= 7, 50% <= 8, 75% <= 8, 95% <= 8
  score >= area: 95%
  back reachable: 96%
  2*rtr >= area: 96%
  all: 95%


Key:

  • random and even: Whether the proportions of colors are constrained to be equal.
  • max_score: The sum, over all cells, of the number of distinct directions in which a move from that cell can end up on a cell of the next pattern.
  • rtr_area: The number of cells that have a path to and from the starting point. Greater values mean fewer dead ends.
  • rtr_back_row: The number of cells in the row farthest from the starting point that have a path to and from the starting point. Useful for the concept of a room having an "exit" that opens once a supermajority of points have been found.
  • score >= area: How often max_score is no less than the floor's area. Magic Floor currently requires this and only this constraint before a room opens.
  • back reachable: How often rtr_back_row is no less than 2.
  • 2*rtr >= area: How often at least half the area is reachable.
  • all: How often all three of these constraints are true.

Now about that "supermajority": Not needing to 100% every floor is one thing that we could borrow from Qix.

nocash wrote:
The exception would be something like "White-Black-White". Where one might either want to move from White to Black, or jump from White to White.
That could be confusing: Needing Button A in that specific case for jumps, while having automatic jumps in other cases.

White-White-Black also needs the jump in order to set the arrow from both white cells.

nocash wrote:
Oh, and I was planning to add maps with empty fields, eg. instead of solid 8x6 cell maps, also use variations like this

Interesting, not unlike in the boards in Spot.