Sunday, May 27, 2012

Cthulhu Saves the World: The Shifted Screen Bug

I've found myself a hobby recently: I buy games written in C#/XNA, and port them over to Linux.

I initially got the idea from Terraria -- there was already a port of an older version and I decided to help out in porting the newer version, with Linaria as the result.  I'm still doing some bugfixing and have some features in mind, although those are on indefinite hold for now.

Currently, my main project is Cthulhu Saves the World, a hilarious old-style RPG.  Porting it turned out to be a good deal easier than Terraria -- no networking makes for much easier work.  After fixing the decompiling errors andsome simple bugs, I could get the game to start and go through the initial text -- however, the music didn't work and game world wasn't being drawn (although one could still move, and battle worked fine).

The solution to the sound problem was actually pretty simple: the game had WMA files, they just needed to be decoded into WAV files and then their extension changed to mp3.

The solution to the graphics problem was much more interesting.

First of all, I forced the game to think it was playing in widescreen mode no matter what was actually set.  This made the game mostly playable -- the only problem was that the resolution was stuck at something weird (900x480, if I remember correctly) and there was a little bit of the game world drawn to the bottom and the right, which the dialogue screens didn't cover.  All in all, it looked like the dialogue was shifted a little to the top-left.

This had me stuck for quite a while.  The code that was originally used to set the graphics settings wasn't being run at all (MonoGame hasn't implemented that event fully), but pasting the same code elsewhere wasn't helping.  There was nothing set in that code that would force such a shift.  There didn't seem to be any shift like that in the code at all.

The first step to solving this was finding a bit of code that drew the black background during conversations. If I added 32 to each coordinate then it would work fine -- however, it just didn't seem right that changing all calls to be something like Draw(32, 32, 1280+32, 720+32) was the way to fix this thing.

This did hint at another issue, though -- apparently, the game was scaling everything down inside the Draw calls, which made sense.  Forcing it to draw at a ratio of 1 made things a little clearer: the game drew everything correctly and ran at 1280x752.  The problem was fairly obvious now -- the ratio was the only thing broken, and I could safely ignore the extra area because it was meant to be drawn: the only reason I saw it was that I use a tiling window manager, which made the window bigger than strictly necessary.

The code for calculating the ratio was using some properties of the GraphicsDevice which I had previously tried to set, but was unsuccessful.  That was a fairly easy thing to fix -- I was calling it before the LoadContent method finished, so it was being reset.

The problems started again when I tried to use the existing method for setting the graphics settings.  The first thing the method would do was try to load the settings from the disk -- asynchronously.  For some reason, I couldn't find a simple way to wait for the loading to complete before continuing (WaitOne did not work, surprisingly).  I solved this with a semaphore -- to be honest, I don't like the solution, but it seems to be working correctly now.  With that in place, the game started listening to the graphics settings fully.

Lessons learned?  Fixing this stuff requires less reading of code and more experimentation, and temporarily hardcoding everything reasonable is a good first step.  Had I started out with making sure nothing was up with the ratio, I'd probably have fixed this a while ago.

The game still isn't working quite as well as I'd like, although there aren't any gamebreaking bugs: there's a level that seems to lag a lot, and the developer commentary hints at why that may be (the way the terrain is drawn is a little more complicated than in other levels).

I've contacted Zeboyd Games about this and was very happy about the reaction -- I'm not sure how much I should say, so I'll just refer to this tweet for if anyone can help.

Once I wrap this up, I've already got the next game chosen: Dwarfs!?.  The game looks like a lot of fun, and the lack of a Wine AppDB page hints that this kind of port may be the only way to run it.

No comments:

Post a Comment