So, in that article, I mentioned two future Blasto projects. One is to save my pennies for a custom arcade cabinet to put the board in, though I just spent a cool grand plus on tires which used up a lot of those pennies and I've also got Christmas presents to buy. But the second was to write my own take on TI Blasto and soup it up. This project is the second one from my bucket list that I've completed. It took a couple years of work on it off and on, but it's finally done, with faster action and animation, a massive number of procedurally generated screens, and fully configurable gameplay.
I've christened it Oblast, and it's free to play on your real Commodore 64 or emulator. Let's talk about what's the same and what's different. The antediluvian 1978 Blasto ran on Hustle hardware, which was derived from Gremlin's original (and mercilessly copied) Blockade game as designed by Lane Hauck. Programmer Bill Blewitt managed to squeeze Blasto's entire game code, not counting character graphics, into just 2K of ROM. This code had to generate and draw the maze, handle one or two player inputs, handle their projectiles, check for collisions and trigger the audio and "boom" circuits, all while simultaneously setting off explosions that could trigger other explosions and other collisions. In the upright version it also had free game logic. Given its hardware and software size constraints the arcade game's gameplay limitations, which we'll discuss in a moment, were understandable. When Milton Bradley picked up the license (from Gremlin's new owner Sega) as a developer for the new TI 99/4, they kept the gameplay and basic rules in their home computer port almost identical. Instead, the programmers added music tracks, a colour display, and multiple configuration options. You could set not only the game's speed (I always played Full Tilt) ... ... but also how the maze was drawn, including whether trails existed (areas of the map pre-cleared for motion) and how dense the mines were. Likely as a way to emphasize the TMS9918(A)'s colour capabilities, the MB programmers changed the setting of the game to a green earth-bound landscape with blue (?) mines and reworked the spaceships into tanks. The density option probably had an even greater impact on gameplay than the speed setting because a maze with a lot of mines made for a zippier, more explosive game. You could rig some big bangs this way, though these were sadly were let down by the TMS9919/SN76489's relatively weak noise output. The program also vainly tried to play a simple tune during the game but this was inevitably interrupted and forced to start over by any sound effect (i.e., a tank shooting, mines exploding). As with the original, you have infinite lives but finite time. If you trip on an explosion, or the other player shoots you in two-player mode, you lose valuable seconds until you respawn. However, you respawn at your original spawn point as if you were teleported there, a conceivable failure mode for a fanciful spaceship but an extremely unlikely one for a terrestrial tank, which makes a good segue into some of its other idiosyncrasies:- Each player can only have a single projectile in motion at any time. However, as soon as that projectile impacts, you can immediately fire another one. This is clearly motivated by the limited memory in the original game, but I don't know of any artillery shell in real life that works like that!
- As a related phenomenon, although you can move while an explosion or chain reaction is occurring (with a slight reduction in frame rate), you can't shoot — at least not until the explosions stop, at which point you can once again shoot immediately. This also seems to be a concession to limited available memory as the game can't track multiple chain reactions at once.
- Tanks absolutely can't go over mines or obstacles; they act as completely impassible barriers. I guess that might make sense with spaceships, but it seems like a rather wussy sort of tank.
Now, I want to point out that despite those things, I loved TI Blasto and played quite a bit of it. But we can improve on what is already an awful lot of fun.
It took a while to get the fundamentals laid down, and it was immediately obvious that the most important mechanic in the game had to be the chain reaction since everybody likes to blow %@#$ up. Consequently, the code that handles the explosions was the first part of the game I wrote, as I reasoned the game wouldn't be worth completing if I couldn't get it fast or frantic enough. This very early draft was a simple proof of concept using PETSCII graphic characters to model the algorithm; character graphics were a must because doing this on the high-resolution screen would have played like molasses.The game doesn't track explosions anywhere else but the screen itself: everything it needs to determine the next frame of animation is by looking at what's set on the characters present. It scans the entire playfield each time to do this which necessarily locks the animation to a constant frame rate — even if the whole screen were alive with multiple explosions, it would take nearly exactly as much time as if only one single bomb were being detonated, keeping gameplay speed consistent. I did a lot of code unrolling to make this work as quick as possible and the final draft of the original "screen test" is what's in Oblast now.
The black area is because I already knew I'd be using sprites for the tank and I didn't want to mess around with having to manage the high bit for X coordinates greater than 255, so I reserved the right-hand portion of the screen for an information pane. This also had the nice side effect of reducing how much of the screen must be scanned.
For Oblast, I've concentrated exclusively on the single-player mode in which I played Blasto most, which also simultaneously solved some technical issues. (I may make a two-player version in the future if I figure out good solutions to them.) Although I've kept the spirit of TI Blasto's configurability, I made it extend not just to maze generation but even to the game's core rule set. The configuration portion is largely written as a BASIC stub with some 6502 assembly language helpers for speed, with the bulk of the remainder and the entirety of the main game loop also in assembly language.There are four preset games, the parameters for which I selected after tweaking them during repeated playtesting. The first is the one I consider "typical" for most players to start with (and the one you'll see the computer attempt to play during Oblast's attract mode), the second has an increased number of bombs, the third adds trails and more Blasto-like rules for more classic gameplay, and the fourth is a completely gonzo game mode which has become my personal favourite after a rough day at work.
If you don't like those presets, or want to tweak them further, there is a full game configuration screen letting you set game modes and the starting level/screen. The game supports up to 384 procedurally generated screens and you can start on any of them from 0 to 255. The screens are generated from constant seed data (in this case the 64's BASIC ROM) and thus designed to generate the same screen with the same parameters, facilitating muscle memory for longer play if you get good.Like the two versions of Blasto, Oblast has mines (bombs) and obstacles (trees). You can very precisely control the densities of both. You can also have the game generate Blasto-style trails horizontally, vertically or both, you can set how quickly your tank's fuel is exhausted (i.e., your time limit, the only option which cannot be zero), and you can indicate if your tank is invulnerable to explosions and how quickly to cycle your shells. I'll talk about how that works in a moment. If you press one of the preset function keys in the configuration screen, then its settings are loaded as a starting point for you to modify.
For the presets, where a new player wouldn't know exactly the game conditions they trigger, I pondered various in-game ways of informing them and hit on an easy-to-implement "dot matrix printout" motif where the BASIC stub scrolls a "briefing" before starting play, making asynchronous "printer" noises based on the bit pattern of each line's ASCII codes. This same motif is used for the basic built-in help since I had some extra space available.Once you've got the settings the way you want, or you just want to keep playing the same preset, after a game ends you can bypass the presets and game configuration screens and jump right into a new game with the same settings by pressing the fire button.
Here's two examples of the procedural screen generation at work, both level 0. The top screen is what you'd start at if you chose the "Regular Duty" (F1) preset; the second is "More Like Classic Blasto" (F5). Both have the same seed pointer, and you can see some commonalities in bomb and tree positions, but the second screen has a slightly lower bomb density and a slightly higher tree density plus trails going both horizontally and vertically. Each collection of settings will always generate the same screens on your machine. The game code manually counts the number of bombs and trees at the end of map generation since they may be taken away by trails or in the process of ensuring the tank has a cleared starting position.Although we're using a custom character set for speed, I still wanted the colour flexibility of high resolution where you can have different text and background colours. To do so Oblast is something of a love letter to one of the VIC-II's more underutilized display modes, extended background colour mode (ECM). ECM supports up to four background colours on the same screen and the main game uses two additional colours besides the green background, the most obvious being the black background of the information pane, but also a yellow background as part of animating explosions. The price you pay for this flexibility is that only 64 characters of the standard 256-entry character set can be used; the two high bits instead become a bit pair to select the background colour.
That meant making a lot of careful decisions about what I was going to actually display and getting those shapes into the first 64 character glyphs, shown here in Ultrafont+. You'll notice that I've replaced some of the letters and typographic characters with graphic shapes because I knew I would never actually need to display those letters or symbols. Everything you see on the screen except for the tank and the shells is a character in this custom font. On the bright side, this character limit also means we can reduce the memory needed by the game font by 75 percent. By looking for the bit set for the black background of the (impervious) information pane, as well as the wall character that also has this bit set, the game knows not to propagate explosions into that area. The yellow background comes in for knowing what needs to detonate next frame: the routine uses that bit as a deferred marker so that as it sweeps sequentially through the screen it doesn't update the same bomb twice in the same frame and prematurely snuff it out. Since setting that bit will also cause a different background colour to be used, we use yellow to make the explosion visually interesting as another side effect.Parenthetically, the TMS9918 and TMS9918A also have a feature like this which TI Blasto itself appears to use: each 32 character block of its 256-character fonts can have its own colours. Unlike the VIC-II's ECM which must be specially enabled, this is a standard feature of the 32x24 text mode (which TI calls "Graphic I"), but the character shapes remain unchanged in each block which may require making duplicates (whereas with ECM they are always drawn from the first 64 glyphs).
If there are a lot of bombs on screen, as is the case in the fourth preset and my favourite gameplay mode, nearly the entire screen will be consumed with the explosion which animates around you as you shoot other things. This wasn't possible in either of the original Blastos. Also, instead of trying to play music during game play, all three SID voices are used for noise generation (with a low-pass filter and some resonance smeared on for a woofer-like effect). Voice 1 is triggered when you fire your gun and voice 2 is always running as the tank's engine, with its frequency varying with motion and tank rotation. Voice 3 is used specifically for explosions because it's the only SID voice where you can directly sample both the oscillator waveform output and the current amplitude of the audio envelope. We take these samples, scale them to the activity on screen, and feed the result into the VIC-II's screen fine X scroll. Lots of explosions cause lots of shaking, yet the shaking is always in sync with the audio.Besides the character graphics, the other major screen component are the sprites. The tank is a composite of three sprites: an animated set for the tank tread, the main tank body, and an accent layer. This is sharper than using multicolour sprites where your horizontal resolution is halved. These three sprites move together and the build system automatically precalculates frames to rotate them off a template, which are played back on screen when you turn. Unlike both versions of Blasto where the tank is limited to integral character positions, the tank in Oblast is larger than the bombs and trees and can move in single pixels, though I still limited movement to 90 degree angles so I didn't have to do expensive trig computations to figure out a shell's trajectory.
One sprite being used as the fuel gauge needle left four sprites for the shells. I had earlier considered using character graphics for them too, but animating shells that way would be slower and less smooth than moving sprites. On the other hand, then, without resorting to tricks there can only be four shells onscreen at once which also didn't seem very tank-like. After some thought I came up with a game mechanic to explain it. In the information pane in these two shots, you see the level number, the fuel gauge which acts as your timer, and then four blue shell indicators. Three of these indicators are dark blue, indicating they are reloading (the fourth is a bright cyan, indicating ready). We'll simply define the reloading time for any shell chamber as the maximum length of time it takes a shell to get across the screen in any direction. Thus, no matter how much you fire, you can only ever have four on-screen because the reloading time will lock you out. (Blasto-style fire control where shells recycle immediately as they hit something is preserved for that game mode, or if you turn on "fast cycl[ing] shells" from the configuration screen.)
While propagating explosions is approximately constant-time, other operations in the game may not be, and there's no reason to walk the screen if nothing's marked as needing it. That means we need a timebase to keep frame rates stable. For this purpose I used the Kernal jiffy clock, which on both PAL and NTSC systems is triggered by the Timer A interrupt to tick about every 1/60 second. The game loop locks to this and uses it to know when to move game objects and trigger screen updates. Still, even this isn't fast enough for moving very speedy things like the shells you fire and the game felt too slow. So ... we make the Timer A interrupt even faster, flogging it at 240Hz instead of 60Hz (the game has prescaler values for both PAL and NTSC), making jiffies 1/240 of a second instead and moving objects at that rate.
This does have interesting interactions when the VIC-II is still drawing your screen at either 50 or 60Hz even as you update it four times as quickly, and most of these interactions have to do with collisions because you can move objects faster than the VIC-II can detect they intersect. The bombs are as big as they are because that gives lots of opportunities to detect a shell striking one, but tank collisions remained unreliable with smaller graphics like trees. Fortunately, however, we've already declared we didn't like the fact that trees and bombs (i.e., obstacles and mines) were impassible objects, so we can make this deficiency into a virtue. The game keeps running track of where the tank last was and if a collision is detected immediately moves it back to that position. However, because collisions are detected inconsistently at this rate of motion and the game updates the tank's coordinates faster than the VIC will draw them, it ends up manifesting onscreen as the tank simply slowing down when it has to cross an obstacle. I like that better than just coming to a dead halt.
Explosions, however, are nice big targets and we have no problem detecting when the tank gets nailed by one of those. In the game modes where your tank is vulnerable, we throw your tank into a temporary tailspin, start flashing the border and the information pane (which is just a matter of setting its colour register), turn on voice 1 and voice 3 at the same time for an even bigger boom, and take the envelope and waveform from voice 3 and put it into the fine Y scroll register as well as the X to really throw the screen around. My favourite game mode allows you to blow up the entire playfield with impunity, of course. I also decided to overhaul the scoring with special bonuses silently awarded after completing a screen and detailed cumulatively at the end when your score is added up (total bombs exploded plus total bonuses earned). Don't cheat and look at the source code, but the descriptions of the bonuses should give you a clue as to how you win them. Note that some bonuses are mutually exclusive, and some are explicitly disabled ("n/a") in certain game configurations that make them impossible or unavoidable.Should you beat the default high score, you'll see another use of extended background colour mode for the champion medal (you'll just have to beat it fair and square, no spoiler screenshots). This segment uses FLD to scroll the medal into view and then cycles the ECM registers for a masked multiple colour bar effect without having to split the screen horizontally. It's a simple effect that I threw together in an afternoon but I think it looks nice. While the game configuration screen looks like it might use ECM for the top title, it actually doesn't because I needed lowercase letters, so I employ a much simpler trick for that screen which shouldn't take you long to figure out.
A key goal was to get the entire game in memory at once without additional loading or disk access, meaning you can even run it from cassette tape if you want to. In memory everything is arranged around the two character sets, the bank of sprites and the two hi-res title screens which are in fixed locations to deal with the VIC-II's more constrained view of memory (one of the hi-res screens is slotted under the BASIC ROM so I could free up 8K for something else). I then redistributed the various machine language subroutines and the three music tracks around those assets while also ensuring the BASIC menu stub had enough free memory to maintain its variables. After the core game was done I added two more extras on, the attract mode (which required some reworking to fit) and a really silly credits sequence, which implements a double-buffered screen scroller and takes advantage of the fact that the main music track sounds pretty neat slowed down. The entire mess is then single-parted using my custom cross-linker and optionally compressed.
Oblast is freeware and open source on Github. You can build it with Perl 5, the xa65 cross assembler and optionally the pucrunch compressor. The Perl tools to generate the sprites, the tokenized BASIC code and the uncompressed runnable linked version are all included. Say that you want to change the presets to your own preferred settings: just change the corresponding DATA statement in the BASIC code, do a make and instantly have your modified binary. All I ask is that modified binaries that you provide to others should use a different name so they aren't confused with the original, and note that this game and any derivative works based on it or its components are under the Floodgap Free Software License.If you just want to play it, the Github releases tab provides compressed (for actual floppy disks or tape or other media with limited space) and uncompressed (for fast DMA cartridges and emulators) builds as .prg files you can run directly. You'll need a joystick or equivalent in port 2, and the game should run on any PAL or NTSC Commodore 64. This is hardly the last game, let alone project, on my bucketlist, but it's good to knock another one off it. Also, please don't blow up trees in real life.
If you've enjoyed playing, buy me a coffee Pibb.

























No comments:
Post a Comment
Comments are subject to moderation. Be nice.