News:

Look at this spiffy theme!

 

Akalabeth Stuff (Ultima 0)

Started by RT-55J, Wed, 2025 - 09 - 24, 11:37 PM

Previous topic - Next topic

RT-55J

Posting some links here for future reference:

Wikipedia article:
https://en.wikipedia.org/wiki/Akalabeth:_World_of_Doom

MobyGames link:
https://www.mobygames.com/game/1256/akalabeth-world-of-doom/

1980 release of Akalabeth (full BASIC source is in the comments):
https://archive.org/details/a2_Akalabeth_1980_California_Pacific_Computer_a

1983 (?) rerelease (has pre-game instructions that were probably printed in the first edition)
https://archive.org/details/a2_Akalabeth_1980_California_Pacific_Computer

source code for the second disk:
https://gist.github.com/jtauber/9863811

Commented tour of the disk contents:
https://jtauber.github.io/game-hacking/akalabeth/

Port to GW-Basic and other platforms:
https://nanochess.org/akalabeth.html

Cleaned up source code (broke up one-liners, added label names, comments):
https://qb64phoenix.com/forum/showthread.php?tid=2570

Python port (seems quite faithful):
https://gitlab.com/promi1/pyakalabeth/-/tree/main/src/akalabeth

StrategyWiki guide
https://strategywiki.org/wiki/Akalabeth:_World_of_Doom

Part of me wants to make a consolized version of this for the Sega Master System, but another part of me just wants all these goshdang tabs closed. This non-public thread is my brain's compromise.

RT-55J

oh, and i can't forget the video that sparked my recent interest:


RT-55J

There's a really funny coding mishap in in the "draw enemy" subroutine.

On line 270 there's this jump table:

270  ON MC GOTO 300,310,320,330,340,350,360,370,380,390
Depending on the value of "MC", it jumps to one of those target lines. It's basically equivalent to a switch statement in C.

Each of the jump destinations is simply a bunch of HPLOT statements to draw each monster (as a buncha vector lines). They all end the same way:

GOTO 490
Line 490 just closes up the drawing function then returns.

HOWEVER, one of the enemies does this instead:

387  GOTO 3087
Hmmm... what's so special about this code that it has to jump there... ?

Oh, it's just some more plotting instructions, ending with the standard "GOTO 490"

Now, the thing about many classic BASIC dialects is that you didn't type in programs as a whole text file. You would type them in line-by-line, and the interpreter would add each line to the program. However, the placement of the lines in the actual program would depend on the line numbers you manually assigned to the lines when typing them in.

Thus, say if you typed these lines into the interpreter:

10 PRINT "BEANS"
20 PRINT "TOAST"
15 PRINT "ON"

The actual BASIC code would end up being:

10 PRINT "BEANS"
15 PRINT "ON"
20 PRINT "TOAST"

With this in mind, there are two possible explanations for the "GOTO 3087" (one is funny and the other is practical):

(a) Lord British meant to type this line:

387 HPLOT [a buncha code]
but he fat-fingered that line as he was typing it in and wrote "3087 HPLOT", putting that line thousands of lines ahead. Rather than retype that (very long) line, he rolled with it and patched the code together with a couple of GOTOs.

(b) Lord British was afraid that he would run out of lines between line 380 and the next enemy at line 390, so towards the end of writing that branch he shuffled some code off to regions unknown. The problem with this theory is that the code would have fit regardless, and there's a high likelihood that he would have written his code on paper first.

I just thought this was neat.

RT-55J

Line 90 appears to be unused:

90  FOR X = 0 TO 9: FOR Y = 0 TO 5: PRINT LD%(X,Y);" ";: NEXT : PRINT : NEXT : GET Q$
Cleaned up, it looks like this:

FOR X = 0 TO 9
   FOR Y = 0 TO 5
      PRINT LD%(X,Y);" ";
   NEXT
   PRINT
NEXT
GET Q$

I need to get an Apple II emulator working, but this appears to be a debug printout for a perspective-related table, followed by an empty wait for a keypress.

neen

what are you waiting for? go get Q$

RT-55J

you gotta keep in mind this was programmed in 1979 -- there's no telling how expensive it is to GET Q$ in today's economy

RT-55J

This bit is really funny:

; Subroutine - Render Overworld
100 HGR
    FOR Y =  - 1 TO 1
        FOR X =  - 1 TO 1
105         HPLOT 138,75 TO 142,75: HPLOT 140,73 TO 140,77
110-170     [draw each of the overworld tiles]
190     NEXT
    NEXT
    RETURN

On the overworld, the player is represented as an X in the middle of the screen, as plotted by line 105. Since that HPLOT command is in the middle of the loop, the player ends up being drawn 9 times (just to be sure).

Unfortunately, this idiosyncrasy of the original code is not reflected in pyakalabeth :pensive:

RT-55J

I haven't written any code yet, but I am having three different thoughts (from simplest to most complex):

(a) Port the game to CVBasic (a compiled Basic language for several 8-bit platforms)
https://github.com/nanochess/CVBasic

(b) Port the game to C using devkitSMS:
https://github.com/sverx/devkitSMS

(c) Rewrite the whole game in Z80 assembly.

Much to consider.

RT-55J

The ASCII "bell" character ␇ is used 28 times in the code to Akalabeth, such as in this instance:

7950  PRINT
      PRINT "...CALL CALIFORNIA PACIFIC COMPUTER"
      PRINT "AT (415)-569-9126 TO REPORT THIS"
      PRINT "AMAZING FEAT!␇␇␇␇␇"

It makes the computer make a little beep.

More information: https://en.wikipedia.org/wiki/Bell_character

On a completely different note, this project has made me learn that many early BASIC dialects had floating point math support, even back in the 70s. Wild stuff (that would also explain some of the performance issues...)

RT-55J

#9
been doing a clean-up of the BASIC code on a private repo to gain my own understanding of the code

the most frudged up thing i've learned is that for the dungeon map array, the monster ID occupying a given square is encoded in the hundredths and thousandths place

neen

aw yee things r happening (maybe)

RT-55J

gonna go with CVBasic for now. Its differences from classic Applesoft BASIC (e.g. no line numbers, no inter-procedure GOTOs) will be helpful in properly restructuring the program.

https://github.com/nanochess/CVBasic


RT-55J

Rudiments of world generation.

Note that CVBasic does not have floating point types, nor an exponentiation operator, so instead of going "INT(RND(1)^5 * 4.5)" I'm just going "RANDOM(5)", which produces a more even distribution (rather than the bottom-heavy distribution of the original). I think I'm gonna have to do something like "RANDOM(256)" followed by a bunch of IF-ELSEs to produce something resembling the original game (read: there are too many towns and dungeons (3s and 4s)).

RT-55J

Anyhow, the most unhinged thing about CVBasic is that it does not support multidimensional arrays --- it's gonna drive me nuts.

RT-55J

okay this looks a bit more visible