Thursday, September 23, 2021

Maybe It's Time to Retro Program

You know, all these nostalgia of computing feelings have started to manifest itself into some kind of idea in my head. But hold on to that thought for the moment.

Here are some screen shots of an old, old game that I wrote back in the day using QuickBASIC: LED(II). What is LED(II)? It's the second program after the first (now lost) one called LED, which was a circle-shooting game using a circle cross hair controlled with the keyboard over a screen. And why is that called LED? I don't know, my best guess was that it was just some quick random-ish of text when I had to quickly save the file in the old 8.3 format... I did eventually backronym it as ``Legendary Enemy Destroyer'' for LED(II). In the header information in the source file, I even had this back story written:
The Legendary Enemy Destroyer (LED) of Earth is on a hunt, to hone its skills. Little did it know that at the very moment, waves of extraterrestrial objects come hurtling towards Earth. The nations are caught with their pants down, and so it's all up to LED to deal with the invasion.

You are the LED. Using the keyboard, you control the LED's direction of movement, acceleration and weapons. The LED has an arsenal of powerful energy based weapons, but choose the most efficient one for use.

Survive the waves to save Earth from impending doom.

Good luck!
Eh, the story's corny, but that's fifteen-year-old me talking. I'm gonna give past-me some slack.

Anyway, here's the title screen:
Here's a typical ``wave'':
And here's the game over screen on dying:
It's a very simple 320×200×16-colour game that mimics the side-scrolling things, except it was done by a fifteen-year-old me during my spare time. The old program logs said that I started on the sources for LED(II) in 2000-03-05, and finished the first playable version in 2000-03-15, followed by on-and-off changes and updates up to 2000-12-30. The next time that I updated it on and off was in the later half of 2002, and added some super minor cheats into the source while attempting to tweak it to work better with faster machines.

Man, so many things that were wrong are wrong. For instance, see how the sprites are drawn on screen? The short answer is that I was using XOR mode for ease of ``non-destructive'' sprite drawing. Confused? Here's a screenshot of the relevant statement in the QBasic help file:
The correct way is to use two bitmaps---one bitmap for the bitmask to AND with what is on the screen to leave background pixels intact while wiping out pixels that need to be overwritten with those of the sprite, before applying the sprite itself with an OR command. In addition to that obvious problem, there was the other issue of using busy waiting in various forms to simulate appropriate amounts of delay (one was brain-dead do-nothing counter loop, the other was a slightly less brain-dead polling-loop on the TIMER value, which returns the current time of day in seconds with resolution no better than 18.2-1 s (courtesy of the IBM PC clock standard of 18.2 Hz), and a laggy-as-hell handling of input commands because it uses INKEY$ in the delay-driven polling instead of relying on something that was more event-driven.

🤦‍♂️

In short, it was a flaming pile of horribly patched code.

QBasic actually has a pretty useful set of event-driven mechanisms. Some examples include:
  1. ON ERROR GOTO line: used for error handling (I've used this before);
  2. ON COM(n) GOSUB line: for characters that are received from the communications port n (I've not used this ever);
  3. ON KEY(n) GOSUB line: for keystrokes on key n (I've not used this, even though it is interrupt driven!);
  4. ON PEN GOSUB line: lightpen related activity (I've never seen/use one);
  5. ON PLAY(n) GOSUB line: interrupts when the background music buffer has less than n notes in it (I used it in LED(II) for the sound effects);
  6. ON STRIG(n) GOSUB line: activity on joystick trigger n (I've never had a joystick, so I didn't use this); and
  7. ON TIMER(n) GOSUB line: triggers when n seconds have passed since the enabling of the event.
All the ON event GOSUB line statements define the handler when the event in question occurs, with the actual enabling of the event trapping itself triggered with an event ON, queued with event STOP, and completely ignored with event OFF. Since they are effectively interrupt driven, they are likely to be more responsive than the messy-ass main-loop that I had been approximating before.

I think I didn't use them for a couple of reasons. Firstly, I wasn't really familiar with the event-driven paradigm when I was fifteen---recall that I had only written programs for solving algorithmic problems in competitive programming, and even then, it only started when I was thirteen. It was not like those who taught me did any form of ``serious'' programming that would use such paradigms in the first place. ``Event-driven'' without having any GUI elements is something that one is more likely to see when writing servers (I wrote my first server program using the interrupt-like event-driven loop only when I was in university), and not in such console-driven programs. Secondly, there was also a purity-issue at some level: each of the event-driven definitions were more tied to ``old'' BASIC where the target of the GOSUB was a line number or a label, which was something that I didn't understand/like since I was exposed to the newer modular-styled SUB and FUNCTION in QBasic, compared to the ``assembly''-styled linenumber/label sub-routines. It didn't make sense in my head then, and so I avoided it, and explored the complicated world that was returned strings in INKEY$ for keys that were outside of the regular printable characters (like the function keys, and the very important arrow keys). The QBasic help file contained a list of keyboard scan codes that were to be used with the ON KEY(n) GOSUB line statement, but to me then, it seemed irrelevant since I thought that I needed to write a customised assembly-based keyboard handler to use these ``raw'' codes.

Well, it's more than twenty years later. I feel like I can do a much better job than fifteen-year-old me using the same tools, and I think I will actually go about doing it.

In fact, I might see if I can do it in regular QBasic instead of QuickBASIC, keeping the source code small enough to fit into one file (as opposed to the current 2-file monstrosity just to ensure that it can be compiled). Let's see if twenty years of experience can make a difference given the same tools.

Now, going back to the initial statement of nostalgia computing feelings, the thought came to mind. Why not do retro-programming for fun? I mean, there are hobbyists who are building custom ROMs for old game consoles that they grew up with that they loved, while I grew up with MS-DOS and loved it through and through. So why not go back to that as a hobby, building new things using the old tools, especially since now I have the means of publishing what I had done.

I mean, people have made ``fantasy'' virtual machines like the pico-8 which has severe limitations to spur creativity. The venerable IBM PC with its 640 kiB limit is no pico-8, but it is a beloved platform that I am quite intimately aware of, spending my formative years poking at it. Compare that to my beefy modern machine of Eileen-II (32 GiB RAM with 6 Hyperthreaded Cores at a base clock speed of 2.6 GHz means that I can shove 32k memory-instances of the IBM PC, running at least 104× faster than the maximum speed of the 80286), it is as good as being a fantasy machine anyway, since it is very unlikely to have real hardware for it. I mean, I am using DOSBox to run the original LED(II) to get those screenshots.

Right now, I'm thinking that when I release these retro-programs, I might just build them into the traditional DOS executables, relying on DOSBox to supply the emulation layer. If things are in QBasic/QuickBASIC though, I can have the option of using QB64 or FreeBASIC to build something that can run natively in uhhh... Windows, Linux, MacOS.

Screw that, I think I'll just release it for DOS. Windows/Linux builds, I can probably test and might do so for my own personal edification, but I have no way of testing MacOS builds. Moreover, it feels less retro if I'm doing this, and it is likely to eat a stupid amount of space on the web server just to hold on to these files (a quick manual conversion of the original QuickBASIC sources of LED(II) to compile in QB64 yielded a file that was 2.68 MiB large, compared to 151 kiB from the native QuickBASIC compiler).

Between QB64 and FreeBASIC, I've used FreeBASIC before, specifically to build a Windows version of my take of the ``Matrix digital rain'', which itself is an adaptation of my DOS text-mode version of the same thing. I liked that program because it used various VGA routines to change the font and the colour palette to fit the ``Matrix digital rain'', without ever running off into graphics mode. I used it to generate some of the special effects that were needed in the ``scholar's film'' that we needed to create back in the day for the scholarship presentation ceremony.

Ah... so much nostalgia.

Anyway, this entry is getting too damn long. I'll stop here, and go mess more with Minecraft. I've been to the End, demolished a small End City for all the Purpur Blocks, found the End Ship, grabbed the Elytra and Dragon Head there, and amassed some awesome Shulker Boxes that I had sorted out earlier today.

Till the next update.

No comments: