CREATING THE 1-SIDE FILE-BASED VERSION OF CONAN ON THE APPLE II. (June 2015) from http://pferrie.host22.com/misc/lowlevel/lowlevel16.htm INTRODUCTION 31 years later, here is the first ever file-based version of Conan, compressed to the point that it fits on one side of a floppy disk! The retail version of the Apple II version of Conan came on two sides of a single disk. Recently, there was a request to make a ProDOS version, so that it could be played from a hard disk on real hardware, so I set to work. To convert Conan to files, first we have to extract all of the data. SEEK AND YE SHALL FIND The initial reads look like this: t00s00...t00s09 to B600...BF00 This is the RWTS. It's not interesting, we can discard it. t00s0A...t00s0F to B000...B500 This is the music that is played during the credits. t01s00 to 0200 t01s01 to 0300 This is the disk driver. We will replace this. t0As00...t0As0F to 6000...6F00 This is the compressed title screen with the trees, and its mask screen. t0Bs00...t0Fs0F to 6000...AF00 t04s00 to 1000 This is the credits code. Now, t00s00 is the boot sector. It is read to $B600. Nothing strange about that - the standard DOS boot sector does the same thing, and Conan's RWTS is the one from DOS. However, during the credits display, we reach this point: $89BD: JMP $B6F0 That one is strange. At $B6F0, we see this: $B6F0: LDA #$01 $B6F2: STA $8FF9 $B6F5: STA $06 $B6F7: JSR $AE00 $B6FA: JMP $B000 Hmm, looks like someone forgot to initialise something, and had to cram it in later. That's an essential routine to update the screen and, most importantly, to make the music play. If you let the music finish playing, then Conan will ride his horse along the bottom of the screen. The most commonly-distributed crack doesn't play the music, because frankly, it's not very good, and the crackers liked the riding Conan better. We must keep it, though, because it's there. Continuing... t03s00...t03s0f to a700...b600 t04s01...t04s0C to 0400...0F00 t05s00...t05s0F to 1000...1F00 t06s00...t09s0F to 4000...7F00 This is the game engine. At this point, we see the prompt to turn over the disk. Not much on side A. t00s01...t00s07 to 7600...7C00 This is the compressed title screen with the fountain and the castle. t00s08...t00s0B to 7500...7800 t00s0C to 7900 t00s0D...t02s0E to 7A00...9B00 t02s0F...t03s0A to A000...AB00 t03s0B...t03s0C to AC00...AD00 This is the data for the intro, the animation of Conan jumping the fountain and entering the castle. However, before it starts, we see this: $1094: JSR $B731 Ah, this is the copy-protection routine that triggers before you get to play the game. It's the one that's designed to embarass any cracker who managed to copy the disk but didn't try to play it. The protection routine performs a dummy read of t10s0d to AE00 (it's identical to the one that was loaded earlier), and then attempts to find two sectors with identical prologue information, followed by a different byte to distinguish between them. If the two sectors are found, then control branches to $A000. So by replacing the $B731 with $A000, we have a more elegant bypass than overwriting the code at $B731. t03s0D...t04s04 to 7500...7C00 This is the compressed level 1 screen. t04s05 to 7500 t04s06 to 7900 t04s07...t04s0E to 7A00...8100 t04s0F...t05s07 to A000...A800 t05s08...t05s09 to AC00...AD00 This is the level 1 code. I'm sure that everyone knows about the extra life that's hidden in the tree. Here's the code that's responsible for it: $A008: LDX $7902 ;zero until bat is killed $A00B: BNE $A016 ... $A013: JSR $A1B0 ;unreachable if bat is killed ... $A1B0: LDX $0300 $A1B3: CPX #$7A ;X position, far to the right of the screen, specifically inside the tree $A1B5: BCC $A1D1 $A1B7: LDX $0309 ;non-zero if starting to climb ladder $A1BA: BEQ $A1D1 ... $A1C1: INC $034B ;extra life ... $A1C9: LDX #$60 ;RTS $A1CB: STX $A1B0 ;disable routine Back to the game. t05s0A...t06s03 to 7500...7E00 This is the compressed level 2 screen. t06s04 to 7500 t06s05 to 7900 t06s06...t07s05 to 7A00...8900 t07s06...t07s0B to a000...A500 t07s0c...t07s0D to AC00...AD00 This is the level 2 code. t07s0E...t08s06 to 7500...7D00 This is the compressed level 3 screen. t08s07...t08s08 to 7500...7600 t08s09 to 7900 t08s0A...t0As02 to 7A00...9200 t0As03...t0As0D to A000...AA00 t0As0E...t0As0F to AC00...AD00 This is the level 3 code. t0Bs00...t0Bs08 to 7500...7D00 This is the compressed level 4 screen. t0Bs09...t0Bs0A to 7500...7600 t0Bs0B to 7900 t0Bs0C...t0Ds07 to 7A00...9500 t0Ds08...t0Es03 to A000...AB00 t0Es04...t0Es05 to AC00...AD00 This is the level 4 code. t0Es06...t0Es0F to 7500...7E00 This is the compressed level 5 screen. t0Fs00...t0Fs01 to 7500...7600 t0Fs02 to 7900 t0Fs03...t11s00 to 7A00...9700 t11s01...t11s0C to A000...AB00 t11s0D...t11s0E to AC00...AD00 This is the level 5 code. t11s0F...t12s08 to 7500...7E00 This is the compressed level 6 screen. t12s09...t12s0B to 7500...7700 t12s0C to 7900 t12s0D...t14s07 to 7A00...9400 t14s08...t15s03 to A000...AB00 t15s04...t15s05 to AC00...AD00 This is the level 6 code. CRASH AND BURN There is a fatal bug in the code for level 6. If the chandelier hits the machine at the exact moment that the first frame of the electric arc is being drawn, the code accesses a bad pointer and overwrites memory until the game crashes. The authors were clearly aware of the issue, and placed a check in the one other place where it can occur, but missed this one. The fix requires two bytes, but finding more than one byte requires some fairly extensive surgery. t15s06...t16s01 to 7500...8000 This is the compressed level 7 screen. t16s02...t16s05 to 7500...7800 t16s06 to 7900 t16s07...t18s0C to 7A00...9F00 t18s0D...t19s08 to A000...AB00 t19s09...t19s0A to AC00...AD00 This is the level 7 code. t22s00...t220A to 9F00...A900 This is the bird animation. t19s0B...t1As05 to 7500...7F00 This is the compressed "level 8" (epilogue) screen. t1As06 to 7500 t1As07 to 7900 t1As08...t1As0A to 7A00...7C00 t1As0B to A000 t1As0C...t1As0D to AC00...AD00 This is the "bonus" code. EVEN DEATH MAY DIE It looks like we're done, and we stop at track #$1A, sector #$0D, but wait! Since I had a lot of practice at the game nearly 30 years ago, I remember all of the safe places to stand, and I can complete it without dying. I almost forgot about the "death" screens. Here's how that works: $1C7C: JSR $1EA8 ;rand $1C7F: AND #$03 $1C81: ASL $1C82: ASL ;multiply by 4 $1C83: STA $B7ED ;sector (4 sectors per graphic, 4 graphics per track) $1C86: LDA $034C ;level, 1-based $1C89: CLC $1C8A: ADC #$1A ;base track (#$1B) $1C8C: STA $B7EC ;track The routine that is called reads from the current sector until the end of the track. It means that the graphics load faster, the closer they are to the end of the track, and lots of sectors are read for no reason. It uses tracks #$1B-#$21 entirely. Surprise. The side B is really full. When looking at the read patterns, we can see one thing immediately: they are really not efficient. Rather than having one file per read, we can consolidate some of the reads to reduce significantly the number of files. In any case, the first file is the music and the title screen. We load these, and display the title, while loading the credits code, which is the second file. As for the music hack, we can copy just the required bytes to their required location to make that work. Since the "flip disk" prompt won't be needed anymore, we'll have to run the score display code manually, but that's not a big problem. Then it's time for the game engine, which is our third file. It contains our first read consolidation, and some significant trimming. Recall this: t04s01...t04s0C to 0400...0F00 t05s00...t05s0F to 1000...1F00 We can combine those into a single block of data, 0400...1F00, but the first text screen is entirely blank and never displayed. We can discard that, so we have 0800...1F00. Next, we have t06s00...t09s0F to 4000...7F00 which is followed immediately by t00s01...t00s07 to 7500...7C00 from side B, which is the compressed title screen, and our fourth file. So what's with the ...7F00 in the first case? Nothing, just a legacy of the read-to-end-of-track routine, for someone thinking that some of the early 7xxx was needed. So, it's just junk that we can discard. We can reduce it to 4000...6F00, which is nice. Now we're dealing with side B, and this monstrosity: t00s08...t00s0B to 7500...7800 t00s0C to 7900 t00s0D...t02s0E to 7A00...9B00 t02s0F...t03s0A to A000...AB00 t03s0B...t03s0C to AC00...AD00 which is the intro, and our fifth file. It can be consolidated into this: 7500...9B00 and A000...AD00. We've reached the level data. Each level consists of three files - the compressed level screen, the code, and the "death" screens. Level 7 is one exception to that, because of the additional bird animation; and level 8 is the other exception to that, because there are no "death" screens. That brings us to 29 files, and quite a lot of data. Let's see about compressing it. The problem with compressing the data is that the decompression cannot be done in-place, because the last few bytes of compressed data will be overwritten by the uncompressed data, before they can be fetched and decoded. To solve that, we have to find a region that is large enough to hold the last few bytes of compressed data along with the entire decompressed data. Coming back to this: t06s00...t09s0F to 4000...7F00 which we reduced to 4000...6F00. It turns out that we can reduce it further, to 4000...6C00. This is enormously helpful, because it leaves us plenty of room to unpack without overwriting ourselves. We can load the level data to $6D00 and there's no problem. But what about the 4000...6C00 region itself, or the 6000...6F00 of the title screen, or the 6000...AF00 of the credits code? We solve that with two powerful words: screen holes. By simply shifting the compressed data to $3FF8 or $5FF8 respectively, the dispayed graphics screen will not show any corruption because the last eight bytes of the memory that holds the last line in particular (and all of other lines, in general) are not visible. With that problem solved, we can compress the data to the point that it fits on a single side of a floppy disk. Imagine what other levels the authors could have included with a whole other side of the disk... Copyright (c) 2015 Peter Ferrie All rights reserved