It's a Game, Not an Engine
After completing the prototype, I was busy learning more about QuickBASIC/QBASIC and adding key features based on concept ideas currently swirling around in my head.
In this post, I would like to share some of the sources I have used for my research.
I consider the QB64 Wiki my primary reference. QB64 itself only targets modern platforms and warns occasionally against using certain routines, but those are exactly the ones needed for DOS. Furthermore, the qbasic.net site is super handy. While the tutorials are only useful for beginners, I found myself constantly needing the screen mode overview, which also lists color codes. Reading the chapter on coding style made me laugh when I thought about the style I’m currently using for this project, which is certainly not suited to BASIC. Not a single GOTO has been used so far, haha.
In response to my last post, mastodon user Christian reached out with two great links: The Revolutionary Guide to QBASIC and DirectQB. The latter (published to GitHub just two months ago) gives me some hope of finding assembly optimizations should the need arise. Currently, I’m doing a lot with strings (replace, search, lookup, etc.), which is best kept out of assembly even if some routines get called frequently. The game is simple and already runs smoothly at 3000 DOSBox cycles, but DirectQB is definitely a great resource.
As for the book, I think I could use it to rework my image data handling and solve a problem I don’t have an answer for yet: a status bar with text and a background color that works across different screen modes. Searching through my data structures looks a bit hacky, though I doubt it can be done much better.
' The number of the item with the name wanted$ or 0
FUNCTION FindItem (wanted$)
FindItem = 0
FOR item = 1 TO NITEMS
IF itemName$(item) = wanted$ THEN FindItem = item: EXIT FUNCTION
NEXT
END FUNCTION
' The number of the room with the key wanted$ or 0
FUNCTION FindRoom (wanted$)
FindRoom = 0
FOR room = 1 TO NROOMS
IF roomKey$(room) = wanted$ THEN FindRoom = room: EXIT FUNCTION
NEXT
END FUNCTIONIn general, constantly mutating globals directly inside functions is really killing me. *Rant intensifies* … And on top of that, the current game code consists almost entirely of conditions, switches, and string operations, and it all feels a bit wrong. I would never structure a project like this “in real life”, but because data and code are so tightly coupled, everything is currently grouped by trigger rather than having any form of proper hierarchy or class inheritance.
' Here's an example
' Item placement descriptions are in a single function
SUB DescribePlacement (item)
SELECT CASE item
CASE ITKEY
Say "There's a small key lying in the grass."
CASE ITLAMP
Say "On the floor stands a brass lamp."
END SELECT
END SUBIt might seem strange to embed all the text directly in the code instead of separating it out. But to actually write the game, I need to see the source and what triggered an event right there to know what needs to be said. Keeping the logic and the prose together provides that immediate context, instead of having to bounce between code and external text files. However, the fact that the QB editor/compiler has a maximum line length of 255 characters is going to complicate things. I’d rather not manually track line lengths as I write. I might need to use an external tool for this.
Of course, most adventure games rely on a dedicated scripting language (e.g. Dinky or SCUMM) that’s parsed and executed by an engine. In fact, I looked at tons of ZILF source code (advent.zil), and their stuff (or any Z-Machine really) is deeply inspiring, yet I had to keep telling myself out loud the whole time: You’re not building an engine, you’re building a single game! I wonder how often that sentence has echoed in indie devs’ heads. It’s surely got burn-in by now.
All grumbling aside, it’s actually been a blast. Getting the fundamentals in place has been a lot of fun, and adding new features to the prototype has gone surprisingly smoothly. For instance, I was worried that implementing a “press any key to continue” prompt for long descriptions would wreak havoc, but it turned out to be straightforward (just counting lines and moving the cursor). I was considering switching to font sprites and custom text rendering before this, but working with native text output really paid off. Text mode is QBasic’s forte, after all.