Monday, March 16, 2009

SpaceRL released

I knew ahead of time that it would be next to impossible for me to enter this year's Seven-Day Roguelike Challenge due to my work schedule. When the call for dates went out at the beginning of the year I decided to start immediately on something small in the hopes of having it ready to release to coincide with the Challenge deadline, since deadlines are good to have. The core idea was to try and approximate zero-gravity movement in a turn-based, square-based game, as I outlined in my previous post.

Starting with the engine for ThiefRL, my unreleased stealth-based Roguelike (eh; might as well release it now), I stripped out the sound propagation, guard speech, and various other things. I kept the line-of-sight code, the pathfinding, the map structure, and the basics of the monster type. I added in a random map generator from another experiment I'd done in villa creation, and I created the basic inertia-based movement scheme.

And that is pretty much where it is now.

I spent a huge amount of time thinking about how to do predictable rigid-body dynamics so that you could push collections of objects around (or be pushed by them). In the end I had to abandon all of that in order to get something done. Currently, only you and the monsters move, and the monsters don't obey the zero-gravity movement rules.

I also spent a huge amount of time on the dungeon (a.k.a. starship wreck) generator. I'm happy with the overall shape of the spaceships. Here are some examples (click to enlarge):

The generator starts with a target number of rooms and a horizontal or vertical symmetry axis. It accretes rooms next to existing rooms. Each placed room adds its four neighbor positions (if they're not already in use) to a set of candidate positions. The next position to use is drawn randomly from that set. Thus empty positions become more likely to be used as they acquire more used neighbor positions.

Once the core room layout is created, the walls are randomly offset by up to half a room in either direction. A fixup process ensures that rooms don't overlap by picking horizontal or vertical at each intersection and forcing the walls to align in that dimension at that intersection.

Next is the crazy part. Originally I allowed doors only between rooms that were adjacent in the original grid. However, the wall-shifting can create new adjacencies. At considerable pain I created a system to identify all adjacencies and form a graph of possible room connections (doors). Then I create a simply-connected graph by randomly adding edges between unconnected components until the entire spacecraft is connected. This ensures that you can always get everywhere. After that I add a random fraction of the remaining unused edges, as well as some doors to the outside.

I got partway through cleaning up the door placement. You may notice in the maps above that some doors are placed symmetrically and others aren't. I'd like to have the underlying door structure be symmetric, and then block or destroy doors to satisfy the level connectivity requirements, which would be determined by a system that would take into account locked doors and key placement; that sort of thing. You want to make the player work a bit to get through the level.

I also got partway into implementing air ducts: an alternate movement layer which only the monsters can use. The idea is that they can't open or close the doors, so if you close the doors they will backtrack to the nearest duct and get through to you that way. I think it shows promise but I just didn't get it done in time.

I've got loads of additional feature ideas which I'd like to put in when I get more time.

The ThiefRL game I linked to above is an entirely different experience. It features a single hand-authored map at the moment, which I have been using to test out gameplay features. You can't kill anything in that game, although you do play a threat to society. I'd estimate that it's got 30 minutes to a couple of hours of gameplay in it right now, and is quite a bit more fun (I think) than SpaceRL.


thorbi said...

Does it build against ncurses or anything that would allow you to produce a linux ... er... binary? (source is out of the question I guess)

James McNeill said...

I knew that would come up!

The engine I'm using is something I wrote a couple of years ago. There were a couple of driving principles: to give me input/output capabilities close to the original PC, and to be as widely compatible (on Windows) as possible.

It uses only plain Win32 API functions. The font is actually a bitmap because I wanted it to look exactly like the old computers. (There is an aspect ratio problem there; modern monitors have square pixels and the original PC didn't, so things look a bit squashed. I'd have to use a modified font to regain the original aspect ratio.)

The boundary between the game and the engine is quite simple, but it does assume PC-style attribute bytes, and raw keyboard down/up events.

The engine is something that needs to be replaced at some point. It turns out that the current rendering method is really slow. I also don't have to stick dogmatically to original-PC looks; it was just a good "artistic constraint" to force me to focus on gameplay, which is the primary point of my Roguelike exercises.

If you could try out the game using Wine and let me know if it runs that way, that would be great. I don't have Linux here; I am sadly not much of a hacker in that regard.

Does ncurses return raw key down/up events? The input function I see is called getch() which makes me doubtful... I'm sure there is some way to do that under Linux, though; do you know what it would be?

I'll have to think about whether I'd do a source release.

thorbi said...

I am happy to say that it works like a charm under wine and really looks gorgeous, too (ThiefRL that is. Side note: SpaceRL also works)

ncurses getch() apparently also returns integers for arrow key presses. I have yet to learn programming in C, so I probably can't really help you beyond this point.

You are probably pleased to hear that I can't distinguish its appearance from that of a native, ncurses-based rougue-like

all in all, pretty good job.