Forbidden Lore Design Diary #13: Stop Hey What’s That Sound

I’m actually diverging from the tutorial a bit to try and fill one of the big holes in the game. There’s next to no feedback, aside from the text scrolling by at the bottom of the screen. If you don’t know what’s happening, it’s honestly pretty opaque.

So I managed to get sound effects in place! Or, rather, A sound effect; if somebody gets punched, there’s a “Thwack!” noise that plays. The important thing is that I set up a framework into which I can insert more sound effects. Coming soon: earth-shattering kabooms, death screams, and perhaps a muffled “Thud!” if you go into the wall face-first.

This was remarkably difficult, and the underlying code is still a work in progress. Apparently, pure Python sound code is tough to come by. Unless I’m understanding something — and it’s entirely possible I am — I’m going to need to install something called “ffmpeg” on my machine. (Which might make things difficult when the day comes that I have to package-up Forbidden Lore and share it with a world starved for clumsy amateurish roguelikes, lol.) Until then, I can’t control the volume, and the game basically pauses while the sound effect plays. So, gotta keep them fuckers short and punchy.

I also added a simple text effects mechanism. Right now, when you punch a dude, not only do you get the “Thwack!”, you ALSO see a big red hashmark briefly appear over whoever got punched! This was surprisingly tricky too, but in this case, it was tricky because I didn’t fully understand the nuances of the code I copied. Basically, I had to really dig in there and figure out EXACTLY which lines were responsible for getting the game to update visually. (For the record, they key line is ‘context.present(console)‘.)

So, for any given audio and/or visual cue I want, I need to extend the “Effect” class which handles the sound and the dirt-simple animation, and then stick an instance of that class into an FX queue in the engine. Then way up in the “main” loop, after all the proper events and actions have been dealt with, it checks the engine’s FX queue and, if it sees anything, pulls it off the queue and plays it. Easy-peasy.

I’ve also been getting in my head a bit about how far I want to go down the ASCII rabbit hole, but I’m currently leaning towards “Pretty far, actually.” Most of the things that I’m concerned about are kinda non-problems as long as I’m the only person playing this game. The graphics suck, but so what? It’s going to be hard as hell to present the information on the spells that will someday be the heart of the game, but who cares? As long as I’m the only one playing this game, I’m the only one who NEEDS to understand what’s happening. “How do I make this game accessible to people who aren’t me?” is tomorrow Pete’s problem. Or next year Pete’s problem. Right now, this is all about learning to write a game. And I am indeed learning.

Forbidden Lore Design Diary #12: Leveling Up To Levels

Back to copy-paste mode with Part 11 of the tutorial, which turns the dungeon into a proper dungeon.

Except … kinda not really. I already implemented the code representing the stairs, and I think I like my implementation better. At least, I think I do. Typing at this, I’m not so sure; perhaps implementing the stairs as terrain instead of a specific kind of object might make more logical sense and have some baked-in features I had to figure out for myself. (Namely, once you find the stairs, the stairs should always be visible on your map.) Hmm. May need to come back for some refactoring.

And I actually already had a bunch of this code in place from a prior round of copying code out of the final version of the git repository. Just didn’t have ALL of it, so I wound up commenting most of it out to keep from breaking my own game.

Whatever. Now, you can go to the NEXT level of the dungeon! So now, instead of “winning,” you can do the proper roguelike thing of just plunging deeper and deeper into this hell-spawned hole in the ground until you finally die. So that’s good.

Also, you can level yourself up after you murder enough things! The game I actually want to make will not do this; Forbidden Lore is going to be all about finding, you know, forbidden lore. Want to get better at wizard shit? Find some ancient texts of wizard shit. Blowing up orcs isn’t going to give you any particular insights into the nature of applied thaumaturgy. But, that’s for later-Pete to deal with, as is taking advantage of the space I intentionally set aside for an XP bar. For the time being, murdering shit is indeed your path to power.

The game is already broken — as the developer gladly points out. At second level, you can make yourself completely invulnerable to the game’s orcs, so that’s a bit of a balance thing. Still. Give the tutorial credit, I have the tools I need to address it. Figuring out HOW to address balance issues is my problem — as it should be.

Also, I now have a “Character Status” window I can pull-up! I’m still a little put-off by the bespoke nature of all the UI elements; I feel like there really ought to be some sort of centralized method I can feed all the relevant variables into. Again, that’s a problem for Future Pete to deal with.

As is the question of how much deeper I wish to delve into the ASCII-game rabbit hole. IS this actually going to be the foundational level of Forbidden Lore, making the very generous assumption that something resembling my version of that game will ever come to exist? Mayyyyyybe. On the plus side, I can see a path to implement a lot of my core ideas using this framework. But I also know that implementing this with, say, Unity would make the final product VASTLY more accessible.

More importantly, the version of Forbidden Lore in my head is going to be all about finding the weak spots in game’s mechanics and exploiting the living shit out of them. To make that work, I’m going to have to make those mechanics as transparent as humanly possible. The game coming out of this tutorial does NOT offer a lot of mechanisms for communicating to the player just WTF is happening and why. I suppose I can address that, if I’m clever enough, but I’ll be swimming against the current.

Still. I have a totally playable game in front of me. It’s not a GOOD game, but it’s totally a game that, as I’m testing features, I still sometimes catch myself having fun with. I think I’ll go as far down this path as feels interesting. If that gives me a game that’s completely opaque to anybody who isn’t me, well, what the hell, the Unity engine will still be right there waiting for me to figure it out.

Still have some tutorial in front of me, though. Onward to the next chapter.

Forbidden Lore Design Diary #11: Back To The Script

It turns out that having a relative die really kicks your side-project productivity squarely in the balls.

However, during my time off, the guy writing the tutorial I was using returned and finished it! Yay!

I’d been trying to do the start-up menu — and was getting bloody nowhere. I asked for some help on /r/roguelikedev, and it turns out that the developer had completely overhauled event handling in a way which would largely solve the problems I was having. He pointed me to the git repository showing the new code, but I was struggling to figure out all the places I’d have to change.

But then the tutorial got updated! Hooray! And it showed all the stuff I needed to refactor!

So I’m back on track, with a loading screen and everything.


I also got to check my savefile mechanism against the recommended version! The recommended version makes smaller files and seems a bit more efficient in general, but honestly, I prefer a lot of elements that I came up with.

Namely, my code for creating a backup of the autosave and restoring it if the save goes awry. I’m keeping that shit.

I also overhauled how monsters and treasure get generated so that it’s a bit easier to twiddle how often something does or doesn’t show up.

I’m back on this thing. I’m going back and forth about how deep I want to go into this once the tutorial is done. I’m a little put off by how difficult some “simple” things are, like creating basic menus or just communicating with the player in general. I’m wondering if I shouldn’t give the Unity engine a try for the product; the end result would wind up being more accessible, I’m sure.

Though I’m equally sure that has its own grab bag of headaches. Still. There are some assets for creating roguelikes in Unity that I could try out.

But for now, what the hell. The ASCII version of the project is moving forward again. May as well see it through to the end of the tutorial, at least.


Forbidden Lore Design Diary #10: The Hard Thing That Turned Out To Be Easy Turns Out To Have Been Hard All Along

Today, I hit an item on my to-do list: is my auto-save only saving after every player turn, or after every mouse action?

Turns out, the answer was “after every mouse action.” So that’s not, you know, great; I’m new to this whole game development thing, but I’m pretty sure saving your game forty times because the user dragged the mouse across the screen is considered sub-optimal design. So I worked to put that autosave command elsewhere.

The input handler seemed like a sensible spot; after I told the engine to handle the enemy turns, I also told it to save. Easy-peasy. However, this introduced me to the concept of “circular dependencies,” which Python finds quite objectionable. Basically, I had to dig into a lot of the weird stuff the tutorial put at the top of many files (like “from __future__ import annotations” and “if TYPE_CHECKING” and other such things) and understand why I needed them. Good news! I now understand why I needed them! Yay learning!

However, I stumbled across a very weird error when I chucked a fireball:

AttributeError: Can't pickle local object 'FireballDamageConsumable.get_action.<locals>.<lambda>'

Baaaah. The code I was using to save the file had beef with the nuances of how some of my stuff works — nuances I barely understood myself. So that looked no damn fun to debug.

But more troubling, I discovered that if I quit the game right after seeing that error, the auto-save file got corrupted and could not be reloaded. Having a game that corrupts its own auto-saves whenever something goes wrong sounds infuriating, so I had to get THAT shit sorted out, too.

Luckily, I had an easy way of generating those corrupted data files on hand.

I posted a question to Stack Overflow, but as one might reasonably expect on a Sunday afternoon, there were no Python nerds willing to lend me a hand. Ah, well.

I researched how to move files around in Python, then whipped-up some code that would move the old auto-save file to a backup and then restore the backup if something went wrong during the save. This code did not work. I spent about an hour tearing you my hair trying to figure out why. I had all these theories; was the filehandle still open? Was I running afoul of an asynchronous race condition? I investigated all that shit only to discover….

A typo. The backup code was looking for the wrong fuckmothering filename.

Once that moment of Software Development was behind me, I started digging into the reasons why the save was fucking-up. Still not sure I know the details why, but the solution turned out to be a package called “dill.” Yes, the code that serializes — “pickles” — the object for me works better when you enhance it with “dill.” Once I figured out how to do that, I was golden.

There’s an old truism in software: for every sufficiently advanced problem, there exists a solution that is simple, elegant, and wrong.

And that’s how my simple, elegant three-line save method turned into something closer to thirty lines, not including blankspace and comments.

I was planning on figuring out some menu stuff today. That’ll have to come next.

Forbidden Lore Design Diary #9: Off the Trail, But With Map In Hand

Latest development session involved getting into the saving & loading tutorial — from the outdated Version 1 of the tutorial. Version 2 still isn’t out.

But that’s okay. I’ve been looking forward to seeing if I can start writing my own code in this thing.

Step 1: Refactoring! The tutorial recommends setting up a “constants” file, for all the key things defining the game and what it looks like. (IE, how large is the map? What are the potential room sizes? Where is the message log located on the screen? Etc.) For this, I did copy-paste the tutorial’s file as my starting point, then set about adapting it to what my code actually looked like.

This proved a bit challenging, as the constants it defined were a bit all over the place. This drove me to do some refactoring, to make the code closer to my version of “tidy.” For instance, why was the code responsible for sending data to the message log defining the log’s x/y coordinates every time it was called? There’s a MessageLog object, after all; why not just tell that thing where it lives when you create it, and then not worry about it?

Eventually, I got the code to a point where the “main” file was the only one that cared about the “constants” file, and acted as the traffic cop responsible for sending that data to the parts of the game that needed it. Seems to work pretty well.

Also wound up having to do some debugging to figure out why my “fireball radius” feature (which I’m inordinately proud of) stopped working. Turned out I’d done something foolish to the order in which things got rendered. It was frustrating, but at the same time, I felt very confident when I managed to track-down and correct that problem.

It turns out that saving the game state to a file is piss easy, even easier than the tutorial suggested. The tutorial was telling me to save all these objects individually, but I quickly realized that the only thing I actually needed to save was the “Engine” object. Had a little trouble installing the Python package used to serialize the object, but the problem turned out to be that Python 3 comes with that package pre-installed. Love it when the solution turns out to be “You never actually had that problem in the first place, dumb-ass.”

So, for proof of concept, I had the game save itself after every action. (On the to-do list: confirm that the game is saving itself ONLY after the player acts, and isn’t saving itself every time the mouse twitches. That would be inefficient.) Then, when the game powers-up, it first checks to see if the save file exists; if it does, it loads it instead of creating a new dungeon.

It works! (After I figured out that the data serializer and the file manager have a difference of opinion on whether one should actually specify a “.dat” extension for the savefile.) It works SO well that, if you get killed, the next game will cheerfully reload the dungeon that has become your tomb, with you still laying there surrounded by the monsters that killed you. So, erm, maybe death should delete the save file.

It has the same problem if you win, though; clear the dungeon of monsters, and your next playthrough will load you into the corpse-filled site of your underground rampage, with nothing to do but wander and contemplate the ultimate futility of violence. So I probably do need to define some formal “You won!” condition just so I don’t have to manually delete the save files.

From there, the tutorial would like me to create a “Main” game screen, from which to ask the user if they would like to start a new game or continue an old one, and … goddamn, that’s actually going to take some effort. Looks like the old version of the tutorial actually made you write some dedicated UI code for stuff like that. The new tutorial lacks that feature. So, I think that’s my next task: centralize all the pop-up menu code into some convenient centralized package that I can use to communicate with the player.

Turns out that saving a game is dirt simple, but asking the player if they’d like to save the game is quite challenging. Roguelikes are fuckin’ weird.

Forbidden Lore Design Diary #8: The Sidewalk Ends with FIREBALLS

Got some worrying personal information tonight. So, I buried myself in programming. Nothing like some scrolls of fireball to distract oneself from loved one suffering over a thousand miles away.

Today’s lesson: ranged attacks! Status effects! Crowd control!

In addition to Potions of Healing, the tutorial has now guided me to create a Scroll of Lightning Bolt, Scroll of Confusion, and Scroll of Fireball. Since magical shenanigans lie at the heart of the game I want to create, I was paying close attention.

Of course, if I’m adding arcane devastation to the mix, I felt like I had to beef-up the monsters a bit. Instead of randomly sticking between zero and two of them in every room, the engine now seeds the room with between zero and five of them. Only seems fair.

I was also not impressed with how the tutorial handled fireballs. To show the area of effect, it presented a simple square — even though the blast radius is very much a RADIUS. You know, a circle. So the beasties in the square may or may not have gotten tagged by the spell depending on how close to the corners they were.

Time to do some off-road coding.

    def highlight_radius(
            center: Tuple[int, int], 
            radius: int,
            console: Console,
            bg_color: Tuple[int, int, int], 
            fg_color: Tuple[int, int, int],
        ) -> None:
        Twiddle the foreground and background colors of all visible tiles within a circle
        x, y = center
        max_x = min(x + radius, self.width)
        max_y = min(y + radius, self.height)
        min_x = max(x - radius, 0)
        min_y = max(y - radius, 0)
        for check_x in range (min_x, max_x + 1, 1):
            for check_y in range (min_y, max_y + 1, 1):
                if (self.distance((x, y), (check_x, check_y)) <= radius 
                        and (self.tiles['walkable'][check_x, check_y])
                        and (self.explored[check_x, check_y])):
                    console.tiles_rgb["bg"][check_x, check_y] = bg_color
                    console.tiles_rgb["fg"][check_x, check_y] = fg_color

    def distance(self, start: Tuple[int, int], end: Tuple[int, int]) -> int:
        Returns the distance between two grid points, rounded up.
        Might someday be enhanced to care about whether or not those two points on the grid
        can actually see each other; for now, just a Pythagorean Theorem wrapper.
        x1, y1 = start
        x2, y2 = end
        return int(round(math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)))

Yup, that’s effectively the first proper Python code I’ve written myself. Results in something that looks like this:


Everything highlighed in red there is gonna get hit by a fireball. How do they feel about it?


They were not fans. Killed the four orcs outright, and definitely took a chunk out of both trolls.

In addition, I figured out how to update the mouseover text to show you the critter’s current health. The game needs more feedback in general, but that’s a first step towards showing you that what you did had an effect even if you foe didn’t drop.

But this iteration of the game marked another milestone. After I took that screenshot, I went back to the code for another round of fiddling. At that point, I should just escape out of the game and restart it … but I wanted to see if I could keep going. After blasting that room, I wanted to see if I could keep going, clear out the dungeon before I got overwhelmed.

And I did it. And I felt kinda like a badass.

This was the first time I had fun with this game as a GAME.

It is still, objectively, kind of a piece of shit. But it’s a piece of shit that has stretches were it’s damned interesting. This is kind of awesome.

Anyway. I’ve hit the end of this version of the tutorial. The tutorial is an update of an older version that just hasn’t gotten to all the chapters the author wanted to cover. So I can keep going, but I won’t be able to copy-paste like I used to. Now, I’m going to have to figure out a lot of the details on my own.

That feels manageable. That feels like a good exercise at this stage, really.

So, next step: figuring out how to save the game.

I wanna take a BIG ol’ detour into laying down an initial version of the magic system, one that doesn’t rely on one-shot items. But, no, saving and loading the game is super important, and I should probably figure out how that works sooner rather than later.

Forbidden Lore Design Diary #7: Talk To Me Over A Drink

Banged-out two episodes of the tutorial today: creating the interface, and items & inventory.

Basically, I can now communicate with the player AND give the player shit to pick up. Whoo-hoo!

HP bar! A healing potion just lying on the ground! Text to tell me WTF is going on! So much game!

I’m starting to get a little judgy about how the code is architected, though. I was curious to know if the toolset I was using had in built-in tools for pop-up interfaces, and the answer is … kinda?

I now have pop-up windows for both message history and for my inventory. I was expecting those to each be part of a new class of some sort, but nah, each of them is a bespoke entity crammed into the code which processes commands and figures out what to do next. That just seems sloppy to me; I would have expected those windows to be their own thing, somehow.

That HP bar WAS its own thing, but I know that I’m going to want a mana pool of some sort to power the player’s spellcasting. So I’ve already refactored that into a more generic component so I could get the mana-point bar in there. (Right now, it’s purely for show; I definitely haven’t implemented spells yet.) They’ll likely be joined by an XP bar at some point. For the final game, I don’t think I want to use an experience-point-based progression system, but for the early going, it’ll do.

I’m also a bit confused by the decision to make all items default to being “consumable.” I’m hoping that’ll get rolled back later in the tutorial.

So, yeah, I’m seeing a whole bunch of shit I think I’m going to refactor after I get to the end but before I get into my own version of the game hot and heavy.

But, still. This game is coming together, and that’s really cool.

Forbidden Lore Design Diary #6: Let The Beatings Commence

Holy shit, you guys. It’s a game now.


I mean, don’t get me wrong, it’s a fucking TERRIBLE game. If I came across it during my bundle playthrough, I’d pimp-slap the bejesus out of it for completely wasting my goddamn time. Tactics are simplistic and obvious, there’s no mechanism for healing yourself or upgrading your abilities, there’s next to no on-screen feedback for what’s happening, the win state is boring, the lose state is even more boring … this game is shit.

But, nevertheless, after this tutorial, I can now roam the dungeon and punch orcs! And punch trolls! And they hit back! And can kill me, which only seems fair! Trolls hit harder.

The code that makes this stuff happen is, by and large, comprehensible to me. I don’t get every nuance. (And it doesn’t help that this edition of the tutorial begins with “Okay, this is how we’re going to totally reorganize the code, because this way is better.” The author is probably right, but still … grr. Would have appreciated if they’d go back and retrofit the existing tutorials. Eh, it’s free learning, I can only bitch so much.)

Even if I don’t get every nuance, though, I can see where stuff goes. When I think about “Okay, how am I going to tweak this to handle an action-point-based mechanism instead of strict turn-taking?”, I have a really good notion of what needs to happen where. It’s pretty dope. I’m probably wrong in several important respects, but I know where to start.

Even more fun, I got to do a little debugging!

The latest version of the code knocked-out the feature by which you could hit “Escape” and quit the game — but only if you were still alive. Once you were dead, you could escape-out just fine.

Trollums McGee has killed me, and is now just standing over my corpse. Apparently, my existence was the only thing giving his meaning.

I thought it was due to some nuances I wasn’t understanding in terms of how the event handlers were firing, but naw, there was just a block of code that hadn’t been copied over, but should have been. So MY code is actually infinitesimally better than the canonical code at this stage of the tutorial!

AND I figured out how to dump objects to the console for debugging purposes, which is super valuable. Also inadvertently got a sniff of just how many events get fired every time the mouse twitches on-screen. Spoiler: several.

Just for giggles, I also tweaked the AI so that the monsters don’t need to see me to bum-rush me; in this version, they all have security cameras and walkie-talkies. Doesn’t take long before the entire dungeon descends upon me. This makes things pretty fuckin’ brutal.

This is really awesome. My little game may be terrible, but it exists, and it’s mine.

Forbidden Lore Design Diary #5: Howdy, Neighbors

I am no longer alone in the dungeon.

Everyone’s maintaining social distancing, as is responsible

There are now trolls (“T”) and orcs (“o”) scattered throughout the dungeon. They really don’t do anything, they just whine to the console about how nice it would be if I coded action handlers for them, too. But, to be fair, I can’t do much to them, either. I can just walk up and kick them. Which is rude, but, pretty harmless, you know?

I’ve also been tinkering with the color palate to make it look more like what I might expect to see in a later product. Yeah, it’s pretty drab, but those shades of gray make it pretty clear what’s happening, at least to me. Color will come from the things you can interact with; I’m fine with the bits defining the environment being kinda dull.

When it comes to coding action handlers, I’m following along pretty well, much more so than I was during dungeon generation. Which is good, because I think that’s going to be one of my major points of deviation from the script when it comes time to start developing the game; I think I want an action-point-based mechanism instead of a strict my-turn/their-turn progression. I feel like it gives me more stuff to play with.

Once the game gets deep into development, I’ll need to implement two different “modes” of travel: combat, which is strictly regulated by the action point mechanic, and non-combat, where you can just wander around and do whatever. That could be tricky — but that’s also a detail that’s going to be WAY down the line.

Next tutorial implements combat, at which point this kinda becomes an actual game. Which is really exciting.

Also still poking through the Python tutorial. Today’s topic: lists! You can do many, many things with them. Most of them are pretty straighforward, but some of the options get really esoteric. Whoever wrote the tutorial has an interesting idea of what constitutes “readable,” but that’s true of any language’s partisans, really. Once you become “fluent,” some really wacky shit becomes perfectly intelligible and you lose sight of how anybody could possibly find it opaque.

Forbidden Lore Design Diary #4: Now With A Point Of View

Nobody who explores a dungeon should have a godlike view of the hellhole into which they have plunged. Restricting the POV to just what you can draw a line to was the focus of today’s tutorial.

Yeah, need to work on that fog-of-war color scheme a bit

It’s one of those things that’s astoundingly simple (and leans heavily on an existing bit of code) if you know what you’re doing, and hard as balls if you don’t. Thanks to the tutorial, I can pretend that I know what I’m doing! Am I gonna keep knowing what I’m doing when I move past the tutorial?

Maaaaaaaaaaybe? The relevant code is powered by a lot of array shenanigans that I can only barely follow along with. Looks like the “numpy” package is a big fuckin’ deal here.

At this point, I feel like if I can iterate out from what the tutorial is showing me, I have a fighting chance of figuring out out. If I have to do something array-powered that’s nothing like anything I’ve yet done, that’s gonna be a fight. But what the hell, that’s what the /r/roguelikedev community is for. I hope.

And it’s possible that this tutorial is gonna cover so much ground that most of what I want to do is just going to be some iterative extension of it. That’d be nice.

Important to note: this version of the tutorial isn’t complete. It’s an updated version of a pre-existing 13-part tutorial, and it only covers up to Part 9. The author meant to have the final four chapters finished by now, but is apparently running behind due to life or something. If I catch up to the end, I may have to branch out on my own and try adapting the lessons of the old tutorial to the new code. That could actually be a really worthwhile challenge.

Also started going through a Python tutorial. Nothing too exciting there, though it is helping provide me with a little formal context for stuff I’ve already figured out. Python has an awful lot of fiddly bits in its method parameter definitions, definitely hitting “Enough rope to hang yourself” territory. Looks like the tutorial is pretty good about documenting any esoteric/inobvious features it’s using, at least.

Still feeling good about this. Looking forward to defining the battle spells by which fools shall be smoked.