Like many, I got into programming by making small games. Being a fan of RPGs, I almost immediately wanted to try and make one1, which somehow led me to discover the roguelike genre. Since I sucked at doing anything graphical, those were perfect to mess around without having to actually try and draw stuff. Over the following years, I have started and abandoned about three roguelike games2.
None of those projects were ever intended to become "true" games, or to ever get finished for that matter. I found out that game design seems to interest me about as much as visual work. Rather, I was having fun implementing the various systems and trying to come up with an architecture that made some kind of sense.
It's been a while since I fooled around with some pseudo-game, but lately I've been thinking of a few ideas. Trying my hand at networking. Exploring procedural generation a little more, or trying to run a simple simulation.
I'm not sure what finally decided me, but one of those ideas seemed simple enough that I finally got started on something about three weeks ago.
Well, here's what I've got:
Introducing Questing Quest (working title)
(Click on the image above to play the game and let it respond to input sanely.
Press escape twice to kill it if the music gets on your nerves).3
It's pretty clunky (I'm truly sorry for the awful collision detection) and ugly as hell but hey, it works. There's no win or lose condition, and frankly no real gameplay to speak of.
Oh, and it only responds to keyboard events. So I guess you're out of luck if you're viewuing this on a tablet or a phone.
Enjoy!
I wrote it in C4 and stole a bunch assets from Itch.io, which explains why the art style is so inconsistent.5 A friend of mine sent me unfinished chiptunes he was working on while I was fooling this thing, so I shamelessly put them in to test the audio system. I'm not sure they really fit whatever mood this thing is supposed to have, but I do like them for what they are. So thanks, Tom!
The original goal was simply to try and come up with a way to handle quests. Which led me to implement rudimentary dialog and event systems, so pretty much everything I never got to try my hand at with my previous roguelike attempts.
Obviously, I got distracted along the way and messed with a whole lot of other "gamey" things, to the point that I've barely tested the quest thing even though that was supposed to be the starting point of all this.
So that's the "game". Bump into an npc to activate a quest randomly chosen from a huge pool of... well, 2. Once activated, this quest will spawn either an enemy or an item in a random zone around the one you start in. Getting the item or killing the monster will update the quest.
That's it. Game of the year material, I'm sure.
By the way, if you think the result above is ugly, know that it started looking like this:

It might still suck, but it did come a long way, is what I'm getting at.
Going low level
Unimpressive as it may be, this is the biggest thing I ever done in C,6 and I'm getting a kick out of it. I've been wanting to try my hand at lower level stuff for a while, and somehow I found I enjoyed writing good old C quite a bit, despite all its infuriating quirks.
I dunno. Maybe I just enjoy pretending I'm an old greybeard. But I do think I'm starting to understand the benefits of simplicity, and C shines on that front. Also, managing to have it do what I want without segfaulting each time I change something7 is pretty gratifying, coming from higher level languages like python.
I'm still strugling to truly isolate sub-systems (seems like every module always
need to #include 12 other files that probably should be left alone), but the
code doesn't quite feel like a ball of mud yet.8
Part of that might be due to resisting the urge to try and be clever. Most of the
code is pretty dumb, and therefore quite easy to follow. I didn't try to get
fancy with architecture either: entitites are a single fat struct, and everything
is stored in static arrays (the lib I'm using for hashmaps does some dynamic
allocations, but there's not a single malloc in my own code).
No fancy macros either beyond a few simple shortcuts. The fanciest ones I have are dead simple and still quite useful to simulate varargs functions:
typedef struct {
EventType type;
union {
// generic pointer for event that only need one parameter
void *generic;
// data for event type T
struct {
const char *string;
int number;
};
// ...
}
} Event;
// shortcut to create an event
#define Mk_Event(T, ...) (Event){ .type = (T), __VA_ARGS__}
// Actual event-queuing function
void Event_Emit_impl(Event event);
// Actual interface, allowing multiple arguments that will get dispatched among
// the various union members of the Event struct
#define Event_Emit(T, ...) Event_Emit_impl(Mk_Event(T, __VA_ARGS__))
// Now I can fire event with data relevent to their type as easily as:
Event_Emit(EVENT_TYPE_SOMETHING, some_data);
Event_Emit(EVENT_TYPE_T, .string = "foo", .number = 666);
Event_Emit(EVENT_TYPE_WHATEVER);
Oh, and tagged unions are awesome. I turned almost every data structure I needed into one.
Starting things in the dumbest possible ways means that I inevitably had to rewrite large parts of the program as I realized I needed to handle things differently, but those went pretty well overall. I suspect the simplicity of the original code helped: easier to add complextity to something braindead than to change code that's already trying to be fancy.
What's next ?
So I started out with a pretty simple goal and ended up with a pretty bad "game" that barely exercizes it. And I realize that I'll have to actually try and turn that game into something if I want to see if what I've implemented actually holds out.
The thing is, I can already feel the interest fleeting away. But maybe I'll keep at it for a while. It's kind of weird. Usually when the itch starts scratching, I get obsessed and spend all my time on whatever it is I got into until I get sick of it.
Not so this time. I happened not to have much to do over the last weeks, so I kept at it mostly to keep busy, but at a fairly relaxed pace. Who knows, maybe this will help me hold my interest for longer that unsual ?
There's still about a billion things to do before this thing becomes remotely interesting, but again, I find my fun in implementing systems I'm not familiar with and have them kind of work, so I don't care if it remains weird and clunky.
I'll be away at the end of the month and pretty busy in june, so I don't expect to do a lot on this thing in the near future. But if the bug bites again, I do have a bunch of ideas to try out (assuming I still can understand a single line when (and if) I decide to get back to this project)).
So we'll see if this thing ever gets completed. I know it probably won't ever amount to much as a game, but hopefully I'll manage to at least try my systems in a situation closer to a real life scenario. Most of the stuff I want to fool with is still fairly technical, but who knows, maybe I'll also try to write a stupid little story to build on as well.
I may mention this project again if I manage to make some progress on it. Or maybe I'll just shelve the whole thing and never touch it again. Wait and see, I guess.
In case anyone's interested, the current code is here.
So. I dunno if there's much of interest to this post. But it's all I have to celebrate this blog's first birthday. Let's see if it's still around next year.
See ya until then, interwebs!
-
I never cared about the MMO kind, though. So that's at least one silly overambitious project I never got into. ↩
-
The latest in date being that one.
T remember abandoning at the point I had to re-do the inventory system after about 2 months of obsessing over tha whole project. For some reason, that was the last straw. ↩
-
Compiling to WebAssembly and putting it up on a page is pretty straigthforward, but interacting with it once it's loaded seems to be another can of worms. Sorry for the poor integration, I'll try to fix it as I learn more about WASM. ↩
-
Which I then compiled to WebAssembly to host it on here. ↩
-
No idea where the Darth Vader sprite comes from. I nicked it from the web maybe ten years ago and found it back in some old silly thing I wrote back then.
Also, be thankful I resisted the temptation of grabbing the Wilhelm scream for the spider death sound effect. ↩
-
It's a bit over 2000 lines of code, so still not huge or anything. ↩
-
Or even better, understanding what causes the segfault under 3 hours. ↩
-
Although I can see the event system devolving into callback hell if I'm not careful. ↩