Tuesday, December 9, 2008

Version 1.02

I made a few bug fixes, and released version 1.02.

Changes include:
  • The save filename was changed from anguna.sav (which conflicts with the R4's autosave feature) to anguna.dat
  • Rearranged where graphics data was stored, to see if it makes a difference in the nasty unreproducible bug where occasionally the main character sprite becomes a giant solid-colored square.
  • Fixed a few sections of the overworld map where edges between rooms didn't transition nicely, allowing the player to get stuck.
Thanks to everyone that submitted bugs about these things!

If you update versions, your old save file will still work, but your character's location will be reset to the first overworld room, outside the prison dungeon.

Tuesday, December 2, 2008

Version 1.01

Sverx reported a couple bugs, so I've posted an updated version (AngunaDS version 1.01).

There was an effect in the main theme xm file that LibXM7 didn't support, so I changed that. Also, there'd been a bug for awhile where occasionally the main character could get covered by a big solid-colored square after you continued from dying. It had been reported before, but I haven't been able to find out how to reproduce it. I finally got enough details from Sverx that, although I still can't reproduce it, I have a pretty good theory about what was causing it, and, if that's the case, I can prevented it from occuring again. Let's see if that holds true...if anyone happens to see that behavior in this 1.01 release, please let me know!

Monday, December 1, 2008

AngunaDS v 1.0

Ok, I'm proud to announce AngunaDS version 1.01. (edit: because I updated to a 1.01 version, I'm changing this link for now to point to the updated version)

Thanks go out to:

Chris Hildenbrand (Daydream)

Jessie Tracer (Electric Keet),
Fred Scalliet (Magic Fred /TFL-TDV)

Audio Engine:
LibXM7 by Sverx (version 0.59 beta)

DS Hardware for testing donated by:
Tim Dudek

Also thanks to:

Refmap project
Additional art

Jasper Vijn (Cearn)
Usenti, Tonc,
Code samples, and general awesomeness

And all you testers:
12th&Saturn,Chris Lomaka, Mukunda Johnson, Sverx, Tim Dudek
Jong Lee, Dennis Tseng, Irashtar,
Eric Chiz, Max Neweklowsky, Stevan Baird, Eric Wells,
Alphanoob, another world, Jeremy Gunkel, John Seabaugh, Spiridow

Unfortunately, there were a few features/fixes that I ended up cutting at the end:
  • You can't use the touchscreen to navigate subscreen menus
  • Sleep mode when closing the lid only partially turns things off, and thus still drains the battery faster than it should
  • The main theme song (Hurtless by Magic Fred) is using a few XM effects that LibXM7 doesn't yet support.
  • I didn't add a cool stairs animation like I would have liked
Anyway, as there are most likely still some bugs floating through it, please email me (nathantolbert at google's mail service) if you find any problems.

Enjoy, and thanks for following along!

Thursday, November 20, 2008

Everything seems to be working

Ok, back to the content that I originally started to post before I realized that my audio wasn't working on hardware. Which is: I think I'm pretty much done! (again...didn't I say that before?)

Turns out (for those of you interested in the details) that something somewhere was sending some dummy messages over the IPC FIFO (the mechanism by which the arm9 and arm7 processor communicate). Because the only messages that I send over it were instructions to play songs, I assumed any messages received were instructions to play songs, and it was trying to play a nonexistent song. Better sanity checking on the commands coming through IPC fixed that.

So now I've made a test build. I'll sanity check it over the next day or two, then send it out to anyone interested in helping test. Then call this thing done!

Still working on audio

Well, I finally gave up (for now, at least) waiting on eKid's audio library, and instead used a new library (LIBXM7) that sverx from the gbadev forums recently released. And it works perfectly -- well, on the emulator. I thought it worked right on hardware, but turns out I was using the wrong build. So there's more work to do -- either waiting on eKid, or getting this LIBXM7 to work right on hardware....

Thursday, November 13, 2008

Title screen graphics

I promised a screenshot of the amazing new title screen that Chris made. Of course, the screenshot doesn't capture the alpha-blend fade or anything, but it still looks cool:

Hurry up and Wait

I was on such a roll for awhile, but now everything has slowed down, unfortunately. I added the power-saving features that I mentioned last time, and debugged a whole bunch of minor issues that testers had found for me.

Chris (the artist) sent me an amazing new title screen, which I just finished adding, completely with a cool alpha-blend fade-in of the title. (Which I'd show a picture of, except I forgot to check in one of the source files into subversion, so I can't build it from this computer right now).

Now, I'm just left with replacing the audio engine. One of the people testing for me (ekid) told me he's finishing up a new audio engine that's supposed to be pretty good. Based on one of his test builds, it actually properly plays all 3 of my songs from Anguna (where my current solution completely fails on one of them, and butchers a few notes from one of the others). Hopefully he'll finish that soon, and I can pull it in easily.

So I'm still advancing, slowly. But doing a bit of waiting at this point.

Wednesday, October 22, 2008

Still here

I've been quiet for the past couple weeks. I'm still here, I promise, and still working on Anguna.

I found a few volunteers, who have been incredible in finding lots of little (and some not so little) bugs for me to fix. I've gotten through most of them, but there's still a couple more to go before I call the thing "done." They also brought it to my attention that to play nicely, I should support going to low power mode when the DS lid is closed. I guess that's a pretty standard thing to do (I don't know, about the only thing I use my DS for is developing Anguna, and playing occasional homebrew games for 5 minutes at a time (you can probably guess what else I'm doing during those 5 minutes)), but it doesn't automatically happen...you have to program it in: detect the lid closing, turn off the video, put the ARM9 processor in lower power mode, do the same for the ARM7, set up interrupts so the processors come back on when the lid opens, etc. Bleh.

Also, during testing, I've found that mikmod just isn't reliable enough....I've been getting all sorts of glitches in sound. So I need to replace that with something else. So the hunt is on to find a better XM player.

Ok, that's all. Just wanted to keep the world (both of you) posted, and aware that I'm still working on this!

Tuesday, October 7, 2008

Main development finished?

Wow, I've gotten here faster than I thought.

Today I managed to knock out a bunch of little stuff:
  • cleaning up warnings
  • fixing the enemy database text entries
  • cleaning up game over screens and some transitional screens
  • further testing/cleanup of saving and loading

Which really means that I'm pretty much done!

Although I must tell the story of when I was at this point on the GBA version of Anguna, I told my wife Sara that I was "done with the development" after 3 years of working on it. But when I spent the next month testing, fixing random bugs, and then fixing bugs that other people in internet land found, she started laughing at my concept of "done." So, with that being said, stuff that's left:

1. Update the credits. I'm not using Kusma's awesome Pimpmobile audio player anymore (since there's no DS version), but switched to LibMikMod (which, despite the fact that I'm incredibly happy that it exists, I'm not as impressed with). I also want to mention Electrobee and Tim Dudek in there, for donating hardware stuff to make this thing happen. And I ended up pulling out 1 one my 3 songs that I used, as it didn't work with LibMikMod, so I guess I need to un-credit Magic Fred who composed it. (Sorry Fred! (For those of you who might think I'm blowing off Fred's work, he didn't compose the song for Anguna, but made it freely available for people like me to use)) So if anyone wants to compose a cool intro song for Anguna, feel free!

1.5 Decide if I want to try to actively search for a replacement intro song, or a composer for it. Probably not, but I'll think about it.

2. Updating documentation/readme files, etc. LibMikMod is LGPL, which is a pain, as I have to include all their licensing documentation, make object files available, etc.

3. Chris (the guy who did the graphics) has said that he might want to create some cool new eye-candy splash screen/cut scene type stuff. If he does, I'll need to figure out how and where to add that in.

4. Test. And test. And bug fix. And test some more. And get other people to test for me. At some point soon I'm going to try to recruit some people to playtest for me before I publicly release the thing, so if anyone is interested, please let me know.

5. Test some more.

6. Test.

7. Release AngunaDS, and bask in the glory of being done!

Monday, October 6, 2008

Saving game data

So I recently ventured into the world of saving progress on the DS. And, like sound, it opened up a whole can of worms. (To be fair, I knew this can of worms was coming, but I kept putting it off).

So, the background, for all you people that don't do DS development:

In the olden days, cartridge-based games used battery-backed ram to save data. Which was still the case in certain GBA games. But in some GBA games, and as far as I know, all commercial DS games, save data is stored using EEPROM. The homebrew DS cards, though, from everything I've read, don't properly support EEPROM (at least accessing it via homebrew methods), but instead, we have a file system to work with, for reading and writing data. But it's not quite as simple as that.

All the homebrew cards are slightly different, but most of them adapt between a micro SD card and the DS. BUT the underlying way to read/write the filesystem on the SD card differs between the different homebrew cards. Enter some smart guy called Chishm and his awesome libfat/DLDI. This guy wrote a file access library (libfat) and a fancy system of patching compiled games with drivers for the different cards. So you write your game using libfat, and if somebody wants to play it on card XYZ, they run the patcher with the XYZ driver.

There's all sorts of other crazy and cool ways of dealing with it all, like people have written other utilities that stuff a whole file system into data appended in your executable file, so the whole DS game and save data and whatnot can be shoved into one file.

OK, enough of the 10-second crash course on libfat and DLDI. So I read up on this stuff, got libfat set up, and it all seems to be working. I toyed with using EFS, which does an appended file system like I mentioned above, but eventually decided against it, as I want it to be easy for people to update the main game file (like when I release bug fixes) without losing their save data. The other annoyance is that using basic libfat stuff, it crashes my emulator. It works fine on the actual hardware, so it's not a huge deal, and the emulators always have the ability to save state, so they don't really need a save file, but I need to go in and make sure it at least doesn't crash.

Other than that, and a couple minor bugs (I'm not rebuilding the initial level screen correctly after loading a saved game), saving and loading is working (at least on the M3 that I'm testing on...Electrobee also gave me an Edge card, so I need to make sure the saving/loading works correctly on it as well).

Once I get this done, the only things left are small cosmetic changes: getting the end-of-game splash screens and credits looking all nice, making sure all the transitions between splash screens, game over screens, menus, etc are all good, finding better intro music, fixing the flavor text on enemy portraits, and testing testing testing. Oh, and I've noticed I have a bunch of warnings in my code about improper pointer conversions. I need to go through and fix all those...I'm one of those people that doesn't want to see a single warning in my code when I compile....

Tuesday, September 30, 2008

Better memory copy/set

Once again, Cearn is my hero. The fast assembly routines he sent for doing memory copies and sets are wonderful -- they just worked, and are nice and fast. I don't have to deal with the oddities that come with DMA, and it's a whole lot faster than the simple memory copies implemented in C. This means that transitions in general are a lot smoother -- between splash screens, between game rooms, etc. Good stuff.

Monday, September 29, 2008

Getting stuff done

I finally got inspired to buckle down and get more done tonight. Partially because Chris (The amazing guy who did the graphics for Anguna) asked me today how it was going, which always reminds me to get to work. It sounds like he's interested in possibly doing some new fancier splash/cut scenes and enemy artwork for the DS port, which would be cool.

Sound effects are now completely working. The last little thing I had to do was deal with the fact that my effects needed to be played at different frequencies...on the GBA, my audio player handled that for me somehow, but here I needed to tell it what frequency to play at.

I unfortunately spent an hour or so fighting with MikMod about how it loads song data into memory. I really need to dig into the source of that library and see what it is doing, because it appears that I can overwrite my song data by loading background tiles into vram. That certainly shouldn't be right, but through trial and error, I've determined that if I load tiles at a certain point in my code, the song is corrupted and won't play. If I don't load the tiles, the song is fine. I've got a workaround in place now, but it doesn't make me happy. And I left my microSD writer at work, so I can't test my workaround on the DS until tomorrow.

The other bummer is that MikMod refuses to play the song that I previously used as intro music. (Hurtless by Magic Fred) I'm not sure how much time to spend fiddling with the song file to see if I can get it to play, or ditch the song and just use the 2 other pieces, or if I should try to find a different song to use for opening music. I'll have to think about that.

I also fixed my minimap bug, which turned out to be not one, but two different bugs. One was that I wasn't loading enough graphical data for the overworld minimap. The other was that somewhere along the line of refactoring things, I had a function that infinitely recursively called itself (when it was supposed to be calling something else). Silly me.

I finished up the evening by fiddling with the opening splash screens....putting my "Bite the chili" logo on the top screen while Chris's SpriteAttack logo is on the bottom screen, and getting everything cleaned up to work happily on the DS.

The other fun news is that Cearn sent me some assembly routines for doing fast fill/copies. I mentioned before that I needed to switch to assembly, as DMA was driving me crazy, so this should do the trick. I'll see if I can get those working and integrated next....

Tuesday, September 23, 2008

Sound (mostly) working

Well, I ditched the bin2o rules that came with the devkitPro toolchain, and used a separate bin2o program, and now I can properly access my binary audio data. I'm sure that I was doing something slightly wrong (data alignment? wrong section? wrong arm/thumb compilation?) as it works for other people, and for the examples that I've looked at.

But what I have now works, and that's good enough for me. Sound is almost finished.

Monday, September 22, 2008

Sound and multiple processors

I've been quiet on here...partially because I haven't had a lot of time for Anguna the past week, and partially because I've started on sound, which meant I had to do a bit of reading before proceeding.

Turns out, there's all sorts of funky stuff you learn when you get into sound on the DS. For example, the DS has two processors: an ARM7 and and ARM9. The GBA had an ARM7, so the ARM7 is used when playing GBA games on the DS. And the ARM9 is the "main" processor used by the DS for DS games. But the fun part is that you can use both processors from your DS code. But unlike fancy desktop computer programming, it's not as simple as forking or creating a new thread from your code. You actually have to write it as two separate programs. One runs on the ARM9, and one runs on the ARM7. The DS has facilities for them to communicate with each other, so your two processes can talk to each other. The other oddness is that certain hardware features can or can't be accessed from the different processors. The full range of audio hardware can (as far as I can tell, which may be wrong) only be accessed from the ARM7. The video stuff can only be accessed from the ARM9. Weird.

So far, I've been writing everything on the ARM9, because you can do most "normal" simple stuff from it. But now that I'm diving into the audio stuff, I've had to use the ARM7 as well.

The good news is that I've found an audio library (mikmod for ds) that will do a lot of the audio work for me. So although I'm running on both processors now, I don't have to touch and learn a lot of the nitty-gritty of audio programming and inter-processor communication.

So far, my music (which come from .xm files, which are a type of mod file (which is a file format for sequencing music out of audio samples)) is working quite well. Sound effects are a slightly different story. The code for playing them seems to be fine, but I've been running into problems when I compile and link them in: somehow the start and ending points for them got messed up, so when you try to play one effect, you might get another, or you might hear all 10 of them played back to back. So I'll need to figure out what's going on there. Hopefully the wonderful community at the gbadev.org forums can help out.

Sunday, September 14, 2008

Shopkeer and healer

I managed to get the shopkeeper and healer UIs done tonight. Those should have been really easy, as nothing much has changed from before, BUT I just tonight remembered that they shared a lot of basic UI code with all the subscreen framework....and I changed the subscreen framework to use the bottom screen (forgetting that this stuff would still be on the top screen).

So basically, now, parts of the framework had to work on both screens. So I ended up refactoring things to work with both screens. It was a quick-and-dirty job, so not quite as elegant or clean as I'd really like, but it works. Really, I keep running into the question of whether to proliferate a top-or-bottom-screen parameter through half of my functions, or whether to make two differently named functions that do the same thing, only for each screen. The problem is that there are places where it seems to make sense to do it the first way, and other places where it makes sense the second way. And now I'm mixing and matching, which I'm not really happy about.

On another note, I found a nasty bug with my minimap where some rooms won't draw correctly, and the game will lock up if you try to pause view the minimap details for those rooms. Nice.

Wednesday, September 10, 2008

Darkness and cave backgrounds done

Last night I used my downtime to play video games instead of working on Anguna. But tonight was back to work. I tackled some of the easier items this time.

Darkness/lanterns was easy: like blending, I just had to update register names from my GBA version. I also was using macros to do all the bitwise operations to write the registers, so I changed them into first class functions, which makes me feel less dirty. It worked the first try.

The black space in the backgrounds in caves had decided to be a rather ugly teal color, so that was the other thing that needed fixed. Another easy one...I had two different functions for applying the correct palette to backgrounds: one for dungeons, one for overworlds and caves. And I had only updated the dungeon one. Just needed to make a tiny update to the overworld one, and it was all good.

If only all changes could be this simple. (Actually, it's late and I'm tired, so I haven't tested these on hardware, but after that last mess I got into trusting my emulators, I won't guarantee that this was simple until I know it works on the hardware).

Monday, September 8, 2008

#5 Fixed (or Hot Squash Burn)

I finally, after much anger, figured out the problem. The anger only resulted slightly from the actual problem. It (the anger) started when I got home, and suddenly my laptop (after locking up and being rebooted at least once) would no longer mount my card reader. So I took it to the other windows laptop, which would no longer read it either. So figured the card got corrupted, and tried to reformat it. But that failed also. Then my DS suddenly decided not to turn on anymore. About that time, Sara asked me to come blend the hot boiled squash she was cooking for baby food. Somehow I managed to not have the lid on right, and splattered boiling squash all over everything, including me. So let me just say Nathan wasn't the happiest man around.

Well, I finally dug out another card reader, which is working for now (I assume the other one just gave up the ghost?). Sara "fixed" my DS by waving her hands over it and saying "avada kedavra", so it works again (I still don't know what was up with that). And we even got the hot boiling squash off of everything, including me. And I only suffered mild first degree burns from the whole ordeal.

And now for the actual Anguna-related talk: In retrospect, I'm amazed at how much abuse in the form of wrong code you can throw at the GBA. The problem was a small section of code where I assume that each "map object" (the name I give to scenery sprites) has an array of two pointers to sprite info, and I write changes to both of them. Well, sometimes (like in the case of the small bushes) there's only 1 sprite, not two! Since C doesn't really protect you from your own stupidity, I was reading off the end of the array to some garbage pointer, and writing to a random location in memory. And the game boy was happy with that! (So were all the DS emulators I used). It makes me shudder to think that these few really nasty bugs made it into "production" code of the GBA Anguna, and I never noticed them because it somehow just worked.

Well, now, other than a small glitch in the background tile initialization for a room, (which is probably caused by another stupid instance of memory/pointer abuse), the actual on-hardware version works just like the emulated version. Which means I can go back to getting stuff done off the todo list. But first I'm going to bed.

Sunday, September 7, 2008

#4 and the joy of two screens

Well, I found issue #4: Initialization problems again. This time with bullets, instead of enemies. Adding smarter initialization and better checking for null pointers fixed that. Unfortunately, I found out that there's an issue #5 causing half the problems that I had attributed to issue #4. So there's more to be done.

But I will say, I LOVE having two screens. When doing this type of debugging on the gba, it was ridiculously difficult, as I couldn't print debug messages to the screen a lot of the time, as the failure was somewhere in initialization routines that were clearing the screen or changing a lot of the video settings. But now with two screens, I can write all my debug statements to the 2nd screen while the first one is hard at work, or vice versa. It's wonderful. Being able to do that, I think I'll be able to track down bug #5 quickly.

But I want to say what I HATE: my laptop. It locks up randomly every so often. Mostly when I pick it up and move it (explain that?) I came to my other computer to type this post when it locked up a few minutes ago. I posted, sat back down with the laptop, got ready to work again, and it locked up again right away. So I'm back adding this paragraph while it reboots again. Grr-bah.

Saturday, September 6, 2008

Update on bugs

So I spent a couple hours trying to diagnose what was going on. Turns out that the build/test cycle wasn't QUITE as bad as I feared (but still relatively painful). I still have to pull the card out of the ds, pull the micro SD card out of the DS card, put the micro SD card in the usb card reader, put the usb card reader into the PC, wait for it to mount, copy the file to the card, unmount the device, pull the usb reader back out, pull the micro SD out of the reader, put the micro SD into the DS card, put the card into the DS, power on the DS, navigate through 2 levels of menus, and start the game. But at least I don't have to move the file to my windows machine first, like I thought I may have to.

Well, after some diagnosis, it turns out that almost all of the bugs have to do with the enemies and my sprite management code. Specifically a few things:

1. The DMA and caching issue that I had before. I really need to just write or steal a good fast memory copy written in assembly for the DS (using the ARM's ldmia/stmia instructions), so I can ditch the DMA. There's examples out there for the GBA, which should be really similar, but my assembly is poor enough that it might take me more time than I'd like just to make the minor tweaks to get them working on the DS.

2. Bad initial values. I had a few spots where I was reading an uninitialized value. Somehow on the emulators, and on the same code on the GBA, this worked fine. But blew up on the DS. So I just needed to go through and initialize them.

3. Dereferencing a null pointer. We all know that that's a big no-no. But it looks like somehow it worked before on the GBA. I don't get it. I was dereferencing a null pointer to a sprite object, and copying that to sprite OAM. That seems like a BAD idea. But it's fixed now.

4. Unfortunately, I haven't figured out what #4 is yet. Something in the sprite management for enemies and bullets is making the game freeze up. Not the 30 second freezing up that I saw before, but locking up entirely freezing up. Luckily it's completely reproducible, but I still haven't managed to track it down. I really thought that fixing #2 and #3 would solving the freezing up, but no...they fixed other issues, but not this one. So now I just need to hunt for mysterious #4.

I also managed to solve the sprite fading/blending issues I had that made me decide to retest on hardware in the first place. Turns out the version of the No$gba emulator I'm using doesn't handle blending properly (or at least doesn't when run under wine)....I actually got the blending code right on the first try (which is only not impressive because I lifted it almost directly from the GBA version, with the only exception being the #define'd name of the registers that control it), but I spent forever fighting with the blending because No$gba would render OTHER blends (background with background, etc) correctly, but not sprites with backgrounds.

Friday, September 5, 2008

Testing on hardware

Alas, I knew I shouldn't have waited as long as I did since I last tested on the real DS hardware. I guess I had more faith in No$Gba than I should have. Today I ran Anguna on hardware, which I haven't done in a good while, and had all sorts of bugs that didn't show up in either of the emulators I use.

The worst was that when you move from room to room, it occasionally takes a long time to load the next room. Like 30 seconds long time. Something is SERIOUSLY wrong in that case. It only happens some of the time. But in the world of programming, "some of the time" is worse than "all of the time" because it's a whole lot harder to find the problem and know if you've fixed it.

I've also got issues with rogue sprites appearing. Stuff appearing that never should have appeared, and not disappearing when it was supposed to.

The annoying things about fixing this:
1. There's no debugging tools available. My debugging tools were pretty worthless anyway, since the only emulator I have that has any debug facilities at all is horribly inaccurate. But this'll be worse.
2. The change/build/test cycle takes a whole lot longer, since you have to add the steps of insert the memory card in the PC, copy the file, transfer the memory card to the DS, boot the DS and start the right game, and THEN test.
3. I do all my development on linux. My card writers don't work on linux. Blah. (Edit: turns out one of them works on my laptop, but wouldn't work on my desktop. But I do the majority of the work on the laptop, so it won't be quite as bad as I thought)

Even if they end up being pretty trivial and easy bugs, this will take quite a bit of time.

Wednesday, September 3, 2008

Subscreen on the subscreen

Here and there over the past few days, I've gotten all the subscreen stuff moved to the DS's bottom screen (often confusingly called the "subscreen"). So the map, enemy database, and inventory screens can show down there while you play. You can pause the game and toggle through them like you used to, or just let them sit there and automatically update themselves. I also added the enemy life indicator that my coworker Jong begged for :)

It was all a lot of housekeeping-type work, very little was interesting enough to share the details of technically. The registers that control the bottom screen are almost exactly like the ones on the top screen (at least for this 2d tile-based stuff...I have no idea about the other modes), so I just had to make new functions to operate on the bottom screen, and make some of my old functions be smart enough to know which screen to operate on.

The only tricky parts were that I now needed to update my subscreens during the main loop instead of only when the game is paused and a key is pressed. Knowing how much of the subscreens to update led to some tighter coupling between different major parts of my code (one of these days I want to eventually do a big rant/essay about when is the right time to engineer fancy solutions to reduce coupling, and when instead those fancy solutions have more overhead than they are worth), but nothing too horrible.

The other annoying part is that I'm now saving room at the top of the bottom screen for status messages that used to appear at the bottom of the main screen. Stuff like "Got meat, health restored" and that sort of nonsense. Which means I'm laying out my subscreens slightly differently. Which for most of the cases, is no big deal, since everything is positioned relatively. The annoying part, though, is the text in the enemy database. Because the enemy portraits vary so much in size and shape, I manually positioned the flavor text for each one to make it look decent. But now in many cases, it looks wrong, or bleeds over the portrait (in the picture shown here, you can see a blank space overlapping the portrait). I either need to cheat, and just use another separate layer (which might make the text hard to see if the colors are similar), or do it right, and manually reposition all the text. Which will be annoying. I'll probably end up doing both, but we'll see ;-)

If I get really inspired, I'll use the touch-sensitive feature of the bottom screen to allow you to toggle between subscreens or inventory items by touching it. But I can't imagine people actually using this very often, so that might fall off the feature list near the end when I start getting impatient.

Well, to finish this up, my friend Rob asked the other day how much left there was to do. My remaining todo list, as best I can estimate:

-dark rooms/lantern
-faded sprites (when you or an enemy gets hit)
-fix enemy db entries
-title screen menu needs a little work
-splash screens/etc
-game over stuff
-borders on caves are messed up
-save menu
-actually saving game
-shop/healer screens

Sound and the game saving are the only intimidating ones, as those differ pretty significantly from the GBA. The rest are basically busy-work.

Thursday, August 28, 2008

Typo and my bool

Notice a problem with this?
if (abs(bullet.xSpeed > 0))

It took me a good 10 minutes to find that problem. Alas, I must have added that typo when I was moving some of my utility functions (min, max, abs) to a more logical home. Ah well.

I also got into trouble last night with bools. Fore some reason, most of the controls for the game worked, but L and R would not. Turns out it has to do with switching from my own typedef'd bool, which was just typedef'd from an integer, to using libnds's bool, which is enum'd as true and false (for those of you used to fancy-schmancy modern languages, C doesn't have a built-in bool, (well, sortof. C99 does, but we won't go there)). I was trying to return a bool value of 512, which using my old method, would evaluate as true. Using libnds's method, it's probably undefined behavior (I'm not sure what the C spec says about doing this), but definitely didn't work. But the fact that it worked for a bunch of other values that I threw at it somewhat incorrectly (32, etc), made it harder to track down.

But I did get a lot more stuff finished off last night. There was a renegade sprite that kept showing up at semi-random times, with semi-random contents. I think I fixed it: it hasn't come back since I changed what I think was causing it (I was using a few partially-uninitialized sprites, in my bullet management code). But, like many intermittant problems, it's hard to know for sure. I also got the currently-selected-item sprite to appear up in the upper-right where it's supposed to.

Next up, moving all the menu/map/etc to the bottom DS screen. I got a start on it last night, but there's plenty more to do.

Tuesday, August 26, 2008

On a roll

Wow, I'm getting a lot done this week. Last night, the kids went to bed quickly and easily, and Sara decided to watch the Olympics, giving me a little more than an hour to get stuff done!

I managed to:
  • Fix the priorities, so sprites appear behind the foreground tiles. This was fairly simple -- I just had the priority numbers wrong. Which makes me wonder how it ever worked in the GBA version, but I didn't get around to comparing the codebases to find out why.
  • Add black foreground borders around small dungeon rooms. Before that, it looked weird when you walked off a screen...you could see your character out in the limbo beyond the room as you exited. So now the black space around the outside of rooms is in the foreground. It was a pretty easy fix, as I took a random room tile, and just gave it an all-black palette, to avoid having to add a new tile.
  • Fix a few other minor scrolling glitches
  • Get the overworld tiles to load correctly. Like the priorities, I was doing this dead wrong, so it was an easy fix -- I was loading a fixed amount of tiles for each map, and that fixed amount was completely wrong.
Let's see if I can keep going at this rate.....

Monday, August 25, 2008

Correction and signed/unsigned ints

Well, turns out a few people do read this blog after all! Cearn left a comment on my last post correcting my incorrect understanding of bit-shifts, which if you are interested, you can read for full detail, but the gist is that bit shifting WILL preserve the sign bit if it's declared as a signed integer and not an unsigned integer. So I stand corrected. Thanks Cearn!

Which means, looking back through my code, that the problem resulted less from my willy-nilly bit-shifting, and more from using an unsigned integer in one particular function. (which at the time was reasonable, because my engine never used negative screen positions until now).

I managed to scrape together 30 or 40 minutes this weekend to finish changing all of my screen setup and scrolling functions to be happy with signed numbers, and finished added some special cases to deal with rooms that are smaller than the screen size. And now all the backgrounds seem to be drawing and scrolling correctly! The first major task of porting is complete!

There's still plenty of issues to work though, even with backgrounds -- the priority of the foreground tiles isn't right...sprites still appear in front of them. And the overworld tiles aren't loading completely -- I'm probably just not copying enough tile data in that case. But I'm getting there!

Wednesday, August 20, 2008

More screen size and premature optimization

Donald Knuth was right. Optimizations I had done for the gba are killing me. And it all has to do with screen size.

See, my engine wasn't designed to properly handle rooms that were smaller than the screen. The camera's position in the room is stored by a number that I assumed was always positive, because, being equal to or smaller than the room itself, I never had to go negative, or outside the bounds of the room. But now with the bigger screen, the camera is often outside of the bounds of the room. So I need to handle all these special cases where the rooms are smaller than the screen. Two things need to happen: first, it needs to just work right. Second, smaller rooms should be centered horizontally on the screen, (unlike the picture in my last post, which looks goofy being shoved up to the left), and bottom-aligned with the screen, so there is less overlap between the HUD and the game. So I've got that to do, which I've started on, but is messy.

A big chunk of the problem was because of stupid optimizations that I (needlessly) did. See, the gba and ds don't have floating point units. And can't do divides with any reasonable speed. But in unsigned binary, bit shifting right by 3 is the same as dividing by 8. And because the tiles are all 8 pixels, I'm dividing by 8 all over the place. So instead of telling it to divide, I bit shifted, to make sure it was fast. Now this was stupid, because a good compiler (which gcc most certainly is) will do this optimization for me. But I figured it wouldn't hurt to make it obvious that it was happening, and thus prevent the compiler from randomly deciding NOT to bit shift and do a slow division. BUT that doesn't work if your number is signed, which mine now is. This is because negative numbers are represented in two's complement. You can still do fast divides with clever bit-shifting, but not as simply as just shifting right 3 bits. So now I need to go change all those places where I was trying to be clever back to actually using a normal divide, and let the compiler do the optimization.

Lesson of the day: my compiler is smarter than me. Let it do the clever stuff.

Thursday, August 14, 2008

Screen size

Well, I'm getting closer! As you can see on the right, things look almost normal!

The biggest problem I ran into so far was the difference in size between the DS screen and the GBA screen. I still need to make better use of the full screen real estate (at least to center small rooms like this one), but the bigger problem was in how the graphics engine deals with the screen size.

See, most scrolling tile games on nintendo's handheld use a small tiled background which wraps around as you move. This background is just big enough to have one row and one column of tiles off the screen at a time. So as the screen scrolls, you redraw the off-screen row or off-screen column (or both), and then scroll it onto the screen. A little tricky, but no problem, really.

The problem comes in that the DS screen width is the same size as the default small wrapping background that I had been using. So I suddenly don't have an offscreen column to draw on. The answer, of course, is to make the background bigger. Which is what I did, but there are some tricks with that. For a 32x32 background, the tile indices are layed out linearly, so for any given tile, the index you want to write to is x + y * 32. But for wider backgrounds, it's different..instead of a big wide background, it's two small background stuck together. Which changes us to the slightly trickier system of:
index = x + y *32;
if (x > 31) index = index + 1024;

Not a big deal directly, but a whole lot harder to use pointer math (which I had been doing) to deal with. So I had to go through and change things to not use any optimized pointer math, and instead, compute it the hard way. (Which is probably best -- as Donald Knuth says, "premature optimization is the root of all evil"). Once that was done, things are pretty close to working!

Of course, there were some other gotchas along the way. For example, I had a horribly hackish way of keeping the foreground and background layers synced, which didn't really work the way I wanted it to for the DS, so I had to do it right this time.

Anyway, the game is actually almost playable now. There are lots of little things to do (enemies don't fade when they get hit, your selected item doesn't show up, the foreground tiles appear behind your character, the outdoor graphics are messed up, scrolling southward is glitchy, etc) and I still need to change things so that the 2nd screen is used for subscreen, minimap, enemy stats, etc. (I also just got around in this build to adding text to the 2nd screen...thus the "hi" at the bottom of the screenshot) But it's moving along faster than I expected! (at this rate, maybe I'll be able to start an iPhone port before the thing is obsolete)

Thursday, August 7, 2008

Sprites, DMA, and caching

In the 2nd picture in my last post, you might have noticed the big brown square in the top-right. Strangely enough, that's a sprite that was appearing and disappearing at weird times. What you don't see in a static picture is how weird clones of the main character and enemy sprites would start appearing at semi-random intervals. Yuck.

Well, as usual, it's DS weirdness that I wasn't counting on that caused it. And this is where I launch into technical ramblings that make the eyes of the general public glaze over and start dreaming of Krispy Kremes.

See, the GBA and the DS both have this cool feature called DMA, which basically means they have a piece of hardware that copies memory from one place to another place, quickly (as opposed to the normal methods of loading a chunk of memory into the cpu, then writing it to another place in memory). Well, what I have been doing is setting up all my sprite information for a frame in regular memory, then, between screen updates, using DMA to copy all the sprite information from main memory into that magic vram that I talked about last time. (vram being the place where you tell the DS what your sprites and all other graphics should look like). But the more I debugged stuff, the more it looked like my DMA memory copy just wasn't working in this case. It worked other places on the DS, but not here. My conclusion: My DS hates me. But alas, I knew that chances were small that that was really the problem.

So after much digging (and much hatred directed at Nintendo), I found the issue: the DS has a memory cache, which, in the case of how I'm developing, is used more-or-less automatically. So, thinking I was writing to main memory, I was just writing to the cache, which hadn't been flushed back to main memory yet (the cache and memory were out of sync). The DMA doesn't trigger the cache to write back to main memory, so I was copying out-of-date information into vram. Bah. Easy fix, but like everything else in the land of debugging, took ages to figure out.

Next step: why my background is all wonky.

Tuesday, August 5, 2008

Title screen and vram banks

Well, I've got the title screen working:

But it wasn't without a fair amount of pain. The first step was pretty easy: when I copy the tile data from regular memory to video memory (vram), I needed to make sure I was copying enough -- since I'm using different memory copy routines than I did on the gba.

I did that, ran it in my emulator, and it looked great. Till I ran it on the actual DS, and it was just a blank screen. Bleh. I loaded it up in the No$GBA emulator, which is the most accurate emulator out there, (but you have to pay to get access to most normal debugging features, and unfortunately, the author has disappeared, meaning it's impossible to purchase, so I'm out of luck getting a useful debug version!), and it black screened also. Bother.

So I spent a few hours fiddling around with some DS demos and copying code back and forth, trying to figure out where I went wrong. Turns out it's with DS's funky vram banks.

See, on the gba, your vram is vram. In the DS, there's a few banks of memory that are meant to be used for vram, but aren't assigned to specific memory addresses by default. You have to assign them yourself, depending on what you want to do with your video. If you are doing fancy 3d stuff, you assign them to the 3d texture memory addresses. If you're doing 2d tile graphics, you assign them somewhere else, and so forth. The trick is that there are certain configurations that are valid, and others that are not. And somehow I had been using an incorrect configuration. So changing that all around fixed things. So now it's working. Although I'm still not sure I have my head wrapped around how these vram banks are supposed to work, and why It's working now, but I don't completely understand it....and that's a dangerous place to be (If you want a taste of what the vile documentation looks like, check this out) . Oh well, for the sake of time, I'll move on, and come back to these things if they bite me again.

Next step: get this looking a little more normal:

Saturday, August 2, 2008

Getting Started

After enough pestering from random folk, and donations of hardware from the wonderful people at Electrobee, I've decided to go ahead and port my Gameboy Advance game Anguna to the Nintendo DS. It should be a fairly straightforward port, as the DS's 2d hardware is remarkably similar to the GBA, but the fact that my wife and I have 5 month old twins really slows things down. So, since the development will be slightly slow, I figured it'd be interesting to keep a record of where I'm at, and what progress I am (or am not) making on it.

For starters, I decided my first tasks should be:
  1. Get the GBA code to build on Linux. I did the GBA version working entirely in Windows, but I've recently switched over to mostly using Linux, so the build framework needed to work in Linux.
  2. Clean up the messy/ugly bits. There were plenty of those, and plenty of places where I built in dependencies on gameboy hardware at too high a level. This, I thought, would be the perfect time to fix those.
  3. Change just enough stuff to get it to compile and run, in some fashion, on the DS.
I've managed to get 2 out of the 3 taken care of. Getting it to build on Linux wasn't too hard. The toolchain was all based on gcc and MinGW stuff, so it was perfect for moving to linux. The hardest parts were some stupid places where I had been abusing windows' case insensitivity, some issues with the line break differences between *nix and windows, and a few of the graphics/level conversion tools that had been compiled as windows command line programs. Some of those tools I recompiled in linux, and one (which I could never find the right linux libraries for) I just run under wine.

The cleaning up of messy bits then got started. And after a few hours of starting to move stuff around, my eyes started glazing over, and I realized I could spend forever just on this task. Once you start trying to get something perfect, you could spend years on it. And with the twins, years of development time is something I don't really have at the moment. So after awhile, being the pragmatist that I am, I decided to leave the ugly code alone, and just go on with things.

That left converting it over to run on the DS. This was annoying, but not too bad. After an hour or two with twiddling with my makefile, and a few more hours of doing mass amounts of vim regular expressions to replace the GBA constants, memory locations, and functions with their DS counterparts, the thing compiled and ran. Most of the graphics are completely messed up, and there's no sound, but it runs! Next step: getting the graphics fixed.

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...