Showing posts with label bugs. Show all posts
Showing posts with label bugs. Show all posts

Friday, October 11, 2013

How to Enhance an SNES Game With the MSU-1 - Part 2: Slow Progress in the Face of Adversity

When last we left off, everything was terrible and there was no documentation anywhere. Well, there's still very little in the way of documentation, but not everything is terrible any more!

Update: Part 3, the climatic conclusion to this series is now available.

And thus, progress was made.

Let's get right to the good stuff that I really want to show off: MUSIC!


The biggest development since the last post is that I now have music playing in the game and it sounds pretty frickin' sweet! I have about half the soundtrack replaced in the game right now and the only tracks I have that aren't in the game are the epilogue and credit scroll. So you can't play from start to finish without noticing that things are missing, but you can wander around much of the game and not notice!

How did this happen?

This is a great question and not one I can entirely answer. I was working with my patch code and trying to figure out why nothing was working when it just started working! There's very little in the way of helpful documentation out there and I've been largely unsuccessful in getting help in forums (though admittedly I haven't tried as hard as I absolutely can... yet) but I think that the reason it began working has something to do with getting my assembler to write with 8-bit registers instead of 16-bit registers. I'm not 100% sure on this though, but I've been thoroughly avoiding looking this gift horse in the mouth for the time being and just focusing on getting everything else working before going back and fixing this.

At the end of this adventure, whether it ends in success or I give up out of frustration, I'd like to post what code I've got online in the hopes of helping others somehow. Perhaps when they come looking for a way to program for the MSU-1 on Google!

Why isn't this done yet?

There are, of course, problems still. The music doesn't play in the latest version of Higan and it doesn't play in bSNES v060 (which is the oldest version I can find online and the one that has debugging tools). Instead, it only plays in bSNES v075. I have no explanation for why this is, though I'm sure it relates to why my code suddenly started playing music. Time will tell on this one.

Another problem is that although I've got about half the soundtrack inserted into the game, I don't even have the other half of the soundtrack! As you can hear in the video above, I've been using the Zelda ReOrchestrated album for A Link to the Past as a source for the music. The main reasons I've done this is because these songs sound great and they're pretty close to the in game tracks in terms of pacing and such, so they match up with cut scenes and events in-game well. Though perhaps the most important reason I chose to use ZREO's soundtrack is because it's free to download. Anyone can download the soundtrack, convert the music via an application (WAV2MSU) and a batch file I can distribute with my patch and then just have everything work together in the same folder. I could die happy if Blake Robinson did the entire soundtrack to this game so that I could just use that, but then people would have to pay for the soundtrack, and I'd like to have a freely distributable version to go with the patch. The ZREO soundtrack is not complete though, and missing tracks are things such as the Guessing Game House theme which people don't cover very often since they aren't as memorable as, say, the Dark World theme. So not having half the music in the game is a big problem.

Then there's still a handful of programming problems to tackle, with the main one right now being fading the music out. In Zelda 3 when you transition between areas and the game tells the music to change, the SPC code gently fades out the currently playing music for about a second as the screen changes, then the new music kicks in. Since I'm bypassing the SPC almost entirely now, I don't get this and there are sharp transitions between pieces of music as you can see in the above video with the transition from the church to the light world theme or the transition into Kakariko Village towards the end.

Things are looking up

The good news is that all of the above problems are being dealt with. Where the last blog post on this ended in despair and uncertainty, this new one ends with hope.

Byuu, the guy who made bSNES/higan, is pretty active on his own forums so figuring out why the rom plays music in one version of his program and not another is probably just a matter of getting his attention for about five minutes so he can point out what I'm doing wrong. Then I can go and correct it. Even if I can't flag him down though, things are at a point where it works SOMEWHERE which is a lot better than when it didn't work at all anywhere!

A music major friend of mine, Shane Johnson, has agreed to help fill out the soundtrack! So there won't be any sudden silences or shifts to the original soundtrack. This is fantastic news and is much better than my fallback plan (learn to compose).

Finally, I've been trying to get the fade out loop to work with varying degrees of failure. In theory it should be pretty simple, just check to see if we're fading out and if so decrease the volume by a smidge and do this once per frame. The problem is finding the right way to do this without throwing off the rest of the program. For example, I would think that the NMI function would be the place to do this, but when I do, I get something like this:

Which is not ideal. I'm confident that I can fix this if I just spend more time experimenting and studying the code, but it might take a while.

If you know anything about any of this or would like to offer your help in general, please feel free to get in touch with me!

Sunday, February 3, 2013

January in Reflection

I wanted to take a moment and reflect on what I learned from January's RPG.

Things That Worked

Random dungeons worked well. They aren't always perfect, but they're fairly flexible and reliable for reproducing the same layout given a seed number. The only downside is that without a large varieties of rooms with a combination of edge types, the dungeons look a bit samey since the same rooms are repeated over and over. Overall though, this was a great success I feel. I'll definitely be looking into using this in the future.

Using default assets was amazing. Not having to worry about making my own art or finding someone else to make art for me was wonderful if not a bit limiting. I'm not an artist even on my best day, so having the RTP at my disposal was a blessing.

RPG Maker VX Ace was fantastic to work with. Despite having messed around with the program for years in my childhood, I had avoided using RPG Maker to make "serious" games. I felt like there was a stigma attached to it and that I would be better off writing my own game engine in XNA or C++ or whatever. However, the engine has turned out to be more than flexible enough for my needs this past month and that was a pleasant surprise. Perhaps even more surprising though was...

Ruby, and specifically RGSS3, the scripting framework that ties RPG Maker VX Ace together. Before January I had no experience with Ruby at all (though I did have some experience with Python) so it was nice to find that Ruby was easy to use. I'm not really clear on a lot of minuta still and my coding style with it is still a bit too Java/C++ judging by the samples I've seen around the web, but I'm getting there.

Cutting content I didn't have time for. More on this below.

Things That Didn't Work

Doing all the balancing on the last day. I was so focused on getting the dungeons generating well that I ignored any semblance of balancing equipment and monster stats against the player. The result was a frantic five hours as February slowly approached. I think I did an okay job in the end, but the difficulty curve is still a bit too steep especially at the beginning of the game. I did my best to compensate for this by letting you easily run past enemies and growing in power very quickly but it's something that should be improved upon later. Ultimately, I think I can improve upon this by planning out my month better.

Bugs. I say that these are prototypes in part because I anticipated not spending as much time on these as I would if I was going to call it a full game (or even think about charging money for it). There's quite a few bugs I noticed while doing a final pass for January. Chests would spawn when they shouldn't, they would spawn on top of each other and a few enemies spawned in walls pretty consistently. But to the best of my knowledge, there aren't any show-stopping bugs. The few story sequences all play out just fine in my testing and the game plays fine. If anything, the game is broken in the player's favor.

Infinite dungeon mode. This was the thing that I really wanted to get in for January. I envisioned the game's real value in being able to get a high score in this mode and then challenge a friend to try to one up you using your password. In my head, the password would seed the RNG so that everything spawned the same way on both playthroughs. Unfortunately, this mode only partly works. It was thrown together at the very last minute, maybe two hours before my self-imposed deadline. There are a couple problems with it, but the two biggest problems are that the monster spawns are always slightly different even given the same password, and the adaptive difficulty is a bit too hard. Unfortunately these were both things that were notice right before midnight so... they got pushed out of the way and I just had to release with them.

Worst of all in Infinite dungeon mode, it doesn't work! Trying it out in the initial release just generated a screenshot of the dungeon generation! Argh! This has since been fixed and anyone who downloads it from the previous blog post after 2/2/13 will get the fixed version. But still: argh!

Cut Content

I wanted to just quickly list a bunch of stuff that I had cut for time constraints:
10 floors instead of just 8
More random floors
More bosses
More room variety
Optional ally partners
Optional rivals
More floors in infinite mode (currently it cycles through three sizes)
More monsters
Better balancing
Generated puzzles (like the room rotation and gate sections)
Different kinds of generation methods on different floors

Looking Ahead

I'm feeling good about February. Aside from some games coming out that are going to eat a lot of my free time, I've got a better handle on my workflow and I have more experience with the tools now. I've even figured out a way around balancing issues for this month (spoiler: no battles). There'll be some new challenges and I'm taking my time this month and will be using today and tomorrow to plan everything out so I don't have to cut as much. Tuesday will see the start of a new game though, and the theme for this month will be "Romance."

Friday, January 11, 2013

Making Semi-Random Dungeons in RPG Maker Part 2

So to quickly recap, my last post outlined how to quickly get a semi-random dungeon generator going in RPG Maker VX Ace that was reproducible (thanks to using a seed for the RNG) and also felt a bit handmade (thanks to actually making each 10x10 room). This fulfills two of my four goals for the random dungeon generator, the full list reproduced below:

  1. Easily reproducible
  2. Feel hand crafted
  3. At least reasonably interesting to move through
  4. Always has a path to all pre-placed events on the map
Finally, this is a screenshot of what we had when we left off:

A few observations about the above photograph, then. First of all the exits to the starting room are not exits as they do not align properly with the exits from adjacent rooms. Second of all, the borders between the rooms are quite clear and ugly. These two problems must be dealt with because they conflict with 2-4 of my dungeon generation goals. 

The second issue is the easiest to deal with and explain. In RPG Maker VX Ace there's heavy use of autotiling. This means that when you place a tile it will change depending on what tiles are around it. It's easier to show how this works than it is to explain with words, so I'll do that now:
Placing a single block yields the top part of the above picture.
Placing another block of the same type next to it yields the bottom part of the image.
None of the placed tiles in the image above have the same id. Three different tiles, three ids, even though we never placed a different looking block from the selector section of the editor.


When we create a room for the generator to place, the room is in the upper left corner of the screen and any wall or ceiling tiles act as if there is another tile of the same type above and to the left of it, just off screen. However, any tiles that are next to a blank tile, will act as if they are a border which is a problem when we place them down next to each other in a level. You'll get nice thick lines between rooms like you can see in the first picture posted in this post.

Thankfully, this is relatively easy to fix by placing additional tiles down on each room map that will not be copied over when the dungeon floor is generated. In other words, we're taking maps like this:


and turning them into this:
Everything inside the rectangle is what will actually appear in the game. Everything outside is for auto-tiling.


This works because it cheats the autotiling system but we don't copy those extra tiles over later anyways.

The other issue, of the exits to the starting room not lining up, is much more of a problem. In order to solve it properly, we need to know what edges a room we are trying to place has and what edges are surrounding the area we are trying to place a room. In my first attempt to solve this problem, I created a method which looked at the tiles along a given edge and checked to see which tiles matched the floor tile id I've been using, then returned a number representing the edge type as noted below.
Each of the edge types, shown here from left to right as 1 - 5.
The red squares indicate tiles that the player cannot pass through.
The magenta tiles indicate tiles that the player can move through to travel to another room.


This worked for a while (and was in fact used for all of the screenshots from the last part), but had some big disadvantages. First of all, it's a method that is limited to the tileset used. If I changed to a different tileset, or even just had a different floor tile id, then my function would not work. This actually happened when I noticed that anywhere that edge type 5 appeared, it was being matched to edge type 1 because the square floor tiles were being read as not walkable! Another disadvantage that this method had was that it was difficult to add more edge types in the future. The function would have to be entirely re-written if I ever wanted to move it to a new project.

A new, simpler method was needed. What I ended up doing was pretty hacky, but it works well. Since the rooms I'm copying from are all their own individual maps, the player will never visit those maps and thus there's no need for encounter groups to be specified. So I specified encounter groups whose ids matched the  edge types for the rooms, since those can be read from scripts. Now my function can reliably return the correct edge type (and do so faster).

However, this still isn't ideal since any pre-placed bits of a dungeon won't be accounted for and we have no way of knowing what their edge types are. In order to account for this, I needed to keep track of where rooms were placed, and what locations had pre-placed sections and what their edge types were. I used a three dimensional array (with the third dimension being five items deep for room id and then the four edges) to take care of this since the room sizes are all necessarily a standardized size, tracking the map ids of rooms that are placed in each location with any pre-placed locations marked as -1 (their edge types are stored below their id on the table).

At this point, we've almost got a well working dungeon generator, but we still a big problem to deal with. Sometimes when creating your dungeon layout, the generator will find a combination of edge types where there isn't a room already created that matches all the surrounding edge types. For example, there's a type 2 above the location, type 3 to the left and a type 5 to the right and bottom, but you haven't made a room with that edge type combination in that order. Previously, I used the four way intersection for this, but that isn't ideal, especially with more than two edge types.

I can think of two ways to avoid this problem. Either create a room with every combination of edge types or find a way to create rooms on the fly. Creating a room for every combination of edges is not a great option because of the large number of rooms that must be hand crafted. To create every combination of edges for our game, which has five different edge types you would need to create 5^4 = 625 rooms! That's a bit much for me, but I suppose if you were dedicated, you could make it work. Instead, I'll be making a function that returns a top, left, right or bottom part of a room for a specific edge type.

We need to get the data for the pieces from somewhere, and while we could store this in a script somewhere, it's much easier to edit if we allocate a map to the purpose. Below, you can see that I've got a bunch of 10x10 rooms (since that's the size I've been working with, we could change the size if I wanted to) of each edge type. You can see in the next picture how each room is divided into pieces.
Edge types with their ID numbers below them.

Each region here represents a different section for the merged room.



Keep in mind though, that this method is difficult to get just right on its own. Various combinations of edges can bring up ugly tile inconsistencies where there looks like there should be a border somewhere and there isn't, for example. As a result, these Frankenstein rooms still don't look entirely right. I'm still in the process of fixing it (though they work just fine functionally) so I even have an area set up to generate a random (or specific) combination of the pieces. Here's some pictures of that.




That's where we are now. There's still a few more things to be done which I'll cover later (since this post is already long enough), such as ensuring there's a path from the start to the exit and adding in random items and other events. Finally, of course, there is always polish that needs to be added. Please let me know if there's anything I can explain further (or fail to explain further) and any sort of screenshots that might be interesting.