Thursday, March 24, 2016

Asymmetrical rooms

One of the weird quirks of the Atari is that, while there are some registers to control the playfield layout (so you don't have to "chase the beam" to draw the entire background/playfield), there's only enough registers for half the screen, so it repeats the same graphics on both halves of the screen. There's another register that lets you determine whether it should be mirrored or duplicated.

Some games get around this by updating that register in the middle of the screen (which I also do when I'm drawing the subscreen map), but with the other stuff I'm trying to display (multi-colored main character, multiple enemies, missiles, etc), I don't really have time to do that. (as a counter-point, see the game Super Cobra, where they manage to cram that all in along with updating the background, although they have some clever limitations on movement to simplify things very slightly)

I've read bad reviews about this game, but I'm convinced the programmers are geniuses.

ANYWAY, my solution in Anguna is just to force every screen to be symmetrical (other than doors/walls on the far edges, which I fake with the Ball object). This makes for slightly less interesting room layouts, but makes my life a lot easier.  Except that my overall world design called for (at least) 2 rooms that broke that rule, and needed to be asymmetrical.  I had punted thinking through the design of how I was going to make these rooms work, assuming I'd come up with something eventually.

And so I did.

The 2 rooms are mirror images of each other, but not symmetrical themselves. It was a place where the river turned a corner:



How did I accomplish this, you may be asking? (If you are crazy enough to still be reading this)  I cheated.  The first half of the cheating is what you don't see, a grass-colored rectangle "enemy" that's just sitting on the left-hand side, hiding the river from view. Here's a similar picture of the room while I was working on it, and had the enemy colored red for debugging:


That accomplished half of what I needed -- making it look asymmetrical. But the hardware-based collision mechanism still knew I was walking into the playfield when I tried to walk through it. So I had to add a special exception in my general collision-processing code, so that playfield collisions in this particular region of these two particular rooms just didn't get counted.

The biggest drawback of cheating this way is that I can't have other enemies in this room -- I only allow one type of enemy per room, and the grassy overlay is using up the enemy for these two rooms. But that's ok -- I don't mind a few rooms here and there with no enemies in them. And I managed to get my asymmetrical rooms working.

And now, partially because it visually shows off my progress, but mostly because I'm obsessed with maps, here's the world map so far. It's about 1/4 to 1/3 of the total world that I have planned out.



Thursday, March 10, 2016

Compact it, Compress it, Recycle, Make Less of it!

My mission this week was to compress things. To compact it. Make less of it.  I was running out of space, and I needed more.

First pass was to go through my code looking for macros that I could convert to proper subroutines. I found a couple, which freed up a little space, maybe a couple hundred bytes total.

Next pass was to do with enemies what I had previously done with room layouts:  In my room definitions, I had a pointer to the enemy type that would be in that room. Pointers in 6502 are 2 bytes. I have less than 256 enemies, so it made sense to, instead of storing a pointer in each room definition, just use an index.  It took a tiny bit more code, but quite a bit less total space. That saved another couple hundred bytes.

The biggest savings, though, was redoing my room layouts.  Because of how the atari playfield registers work, and 6502 indexing works, it's easiest to store 3 chunks of data for each room layout -- one for the outside edge, one for the middle of each half-screen, and one for the middle of the screen.  So I stored 23 bytes of layout data for each of those chunks, for each room.

Well, it turns out that a lot of room layouts share similar chunks. For example, either they have completely blank outside edges, or nice square doors on the outside, etc. I had quite a few chunks that were repeated throughout my graphics data. So instead of clustering the 3 chunks together, I added yet another lookup table, where for each room layout, I store the indices of the 3 different chunks that make up that room.   That freed up about 400 bytes.

The bonus of this is that now I can make different permutations of my existing chunks, for nearly free. This gives me a lot more options for making different room layouts and keeping the game at least slightly interesting.

So, that's done.  Now back to content.

(Although some of the nice folks on AtariAge have convinced me that I should try to support the SaveKey, a hardware doodad that someone made, which plugs into the player 2 joystick port, and has some flash memory to allow game saves.  I guess it takes between 100 and 200 bytes of code to use it. Now that I've freed this up space, I may try to do it. We'll see)

I'll leave you with this nice picture of things being broken as I tried debugging my new room layout code.


Sunday, March 6, 2016

Darkness, and running out of space

This weekend's work was to add dark rooms. (at least, dark until you have the lantern) Which has been tough. I've given it a ton of thought, and have never been completely happy with what I've come up with. But with a good bit of trial, error, and wasted code, I've got something that works:


Dark rooms are limited to a single enemy. What I do is a trick that dates back to the catacombs from Adventure: I use an enemy sprite (set to 4x width) in yellow as a glowy area around the player. Then I change the background and walls to the same color, but change the rendering priority flag to put the playfield (walls) on top, the sprites 2nd, then the background last. Which means that everything looks black unless the glowy light is there, which gets rendered underneath the walls, showing where the walls are.

Thank you, Warren Robinett, for this awesome idea.



Now because I have other enemies that I want to render as well, I have to have some flicker going, and render the light and the enemies in alternating frames. (I just don't have the code space to do the more complex alternation if I have more enemies).

The one thing I have left with the darkness is that I want to hide the enemies until they get close to you. Which actually should be pretty easy, i believe.

Now the problem that I'm having is that I'm running drastically low on ROM space. I've got about 1K left of my 16K. In that space, I need to add a bunch of room layouts and color schemes, code for the dynamite, a bunch more enemies, and a sequence for winning the game. I also wanted to add support for the SaveKey, a cool doodad that someone made that plugs into the 2nd player controller port, and allows persistent storage for game saves. Adding the code for that takes about 100 bytes, which is about a tenth of what I have left. Ugh.

Thursday, March 3, 2016

Password Entry

It's late. I'm tired.

But by golly, I got the password entry UI working. With 133 bytes to spare. WHEW.


Of course, it doesn't actually let you start the resumed game from here yet, so maybe that's what I'll do with those leftover bytes.....

Wednesday, March 2, 2016

Password

Tonight I started working on what happens when you die, and where you respawn, which ended up getting me excited about trying to make the password system work.  So tonight's project was building a reusable bit of code to both display the current password, as well as display the password UI while the user is entering a password.

I don't really have the UI part of it working yet, but after a couple of hours tonight, displaying the current password is working fine, including a checksum to keep people honest:



As I stare at it, I think the password logic might be a little too obvious, so I may end up obfuscating it just slightly by rearranging some of the graphics for the numbers/letters in the password. We'll see.

Sunday, February 28, 2016

Subscreen Map

Well, I had originally said that I planned to wait and see how much space I had before making the subscreen map that I planned on.  But this past week, after working on the overworld, I realized that with my limited range of different screen layouts, the overworld was going to be a big boring place that's easy to get lost in.

What I really needed was a map.  With a map, at least the overworld becomes a big boring place that's not quite so easy to get lost in.


So I added the map on the subscreen. It took a bit of work to get the colors all lines up the right ways, using the different graphical objects available, but I think it's working now. The white dot tracks where you are on the world.


I did manage to get the kernel all working with my multiple colors, like I mentioned last time. I was even able to animate the water of the river, so the color moves down the screen, which is fun.



I think it's time to post some builds to the Atari homebrew forums to try to get some feedback.  That's scary.

Saturday, February 20, 2016

Squeezing and compacting

I've been plowing away at the game, adding some nicer graphics on the subscreen, fixing a bunch of minor issues, getting some bugs worked out with items, and starting on the overworld.

When I got to the overworld, I realized that my first couple screens were really boring.  Here is the hero standing outside of the cave that leads back to the first dungeon. I want to add some trees or something to the bottom half, but the way my engine works, each room only has 1 wall color.  I stared at this for awhile, but just wasn't happy with it.


Thus I started a new quest to squeeze yet one more thing into my display kernel. This seemed like crazy talk to me, as I already was having trouble getting all my timings right during the kernel. But Atari programming is all about crazy, so I stayed up WAY too late last night trying to find places to slightly tighten up the speed of my kernel code, so that I could squeeze in just a couple more instructions to update the color every few lines.

Turns out, by squeezing part of the calculation on one scanline, and the other half on the next, and by getting my timings just right so that I could eliminate a WSYNC, I got it working. (WSYNC is the instruction where you tell the Atari/TV that you are done with the current scanline, and it should start on the next. It takes 3 clock cycles -- but you can omit it, and the next scanline will just start when it's time. You often use it to force the timing to reset on each line, but if you have everything timed right, you can omit it and just start on the next line).

So now I have the ability to change the playfield color every 4 scanlines. The problem now is that this means that I have to devote 23 bytes of ROM to each different color layout that I want. And my 4k bank where the kernel and graphics live is already getting dangerously full.

Which meant that I started another crazy quest to tighten up the ROM space of the kernel code. Originally I had a lot of loops that were unrolled for the sake of speed, and no subroutines (which waste 12 clock cycles during the jump and return, which I generally can't afford in the kernel)  So now I'm going back and selectively re-rolling loops and moving things around, trying to free up a few bytes here and there. I've managed to free up about 200 so far (which is about 5% of the space of this ROM bank, so that's something), and have some ideas about places I can free up more.

So....progress is slowly happening. Although if I keep thinking of new features, I might no longer be able to squeeze things in anymore! (I'm already down to only 160 bytes of ROM left in my "main" bank, although that's less timing-intensive, so I can jump to other banks for subroutines if necessary)

NES Anguna

Well, I had a little bit of time still, while Frankengraphics is finishing up her game Project Blue, to have a little downtime on Halcyon, s...