Help our crowdfunding

Dear friends,

I am writing on behalf of the Game Preservation Society, dedicated to the important work of preserving our nation’s classic video games. We are holding a fundraiser to purchase a Fujitsu fi-7600 archival scanner, which will be invaluable in our mission.
This specialized high-end scanner will allow us to create digital copies of aging media such as game magazines, manuals and other documents. The fi-7600 is unmatched in its ability to digitize damaged, faded, or degraded materials while still maintaining precision and detail. For the fragile documents of past decades, this technology is essential.
The classics we strive to preserve defined generations of culture and advancement for Japan. They represent our history as a pioneer in interactive entertainment and technology. It is our solemn duty to maintain accessibility to these landmark works before they are lost forever.
We cannot accomplish this imperative work without support. I humbly request that you consider donating to our fundraiser for this urgently needed scanning equipment. Together, we can ensure that the cherished games which have shaped our society are preserved for future generations. Please join us in protecting our nation’s interactive legacy.

Crowdfunding page: https://www.gamepres.org/en/participate/fundraise/

Sincerely,
Joseph Redon
Game Preservation Society

Latest GPS newsletter is available

*This article was translated from Japanese using machine translation. If you would like to edit or correct it, or help in general with translations please contact us!

This is the Game Preservation Society public relations.

Thank you for always supporting our association.

We have published the latest issue of our Japanese newsletter, GPS News vol.21, so we would like to inform you.
In July 2023, we were able to successfully finish the 2022 fiscal year activities. This newsletter contains the 2022 fiscal year activity report, financial report, and the 2023 fiscal year activity plan.

In fiscal year 2022, in addition to continuing the Archive Project funded by the Agency for Cultural Affairs, our preservation research completed the 8-inch drive adapter for Pauline preservation device, and our awareness activities included the release of the documentary “Geimu” Part 2.

In addition, this issue features how the materials donated to our association are being stored.

Download the PDF of the latest newsletter here
Also, we discovered some incorrect figures in the prior fiscal year’s financial report in GPS News vol.18, so we have replaced it with a corrected version in both Japanese and English.

The newsletter is open for non-members to view as well, so if you know anyone interested or involved in game preservation, please share information about our activities.

We will continue our activities relying on your support, so thank you as always.

 

□Notice of change to newsletter delivery method for supporter members

When registering from Japan, you chose PDF or postal mail/PDF for delivery. If you wish to change the delivery method after registering, please update via “Change personal info” in your member page.

Is Death Force for FM77AV finish-able?

Today we have a special technical article from one of our supporting members going into great detail about Death Force, a classic game for the Fujitsu FM77AV with a hidden mystery, including a partial disassembly, memory analysis and gameplay strategies.

Death Force was released for Fujitsu FM77AV series 8-bit computer in 1987. The FM77AV had advanced graphics hardware, able to display up to 4,096 colors (along with other modes: 8 colors times 4 planes and 8 colors 2 planes + 64 colors). Death Force was one of the first software titles that made use of the color capabilities of FM77AV.

When I visited Game Preservation Society, one of the members raised a question: is it possible to play Death Force through all the way to the ending? The rumor was that the copy protection backfired, making it impossible to finish. According to another rumor, one user complained to the developer, Riverhill Soft, that the game was impossible to complete and was sent a fixed version. I wanted to find out if the rumors were true.

I did not buy Death Force when FM77AV was my primary computer, mainly due to budget reasons. Luckily, I was able to purchase an original copy of Death Force recently. The disks crossed the Pacific ocean with no apparent damage or mold, and I was able to make disk images using my working FM77AV40. The FM-7 series emulator XM7 could emulate the copy protection, and I was able to boot the program with no problem. I began my investigation into the rumors.

The disks used in this test

Both A and B disks had a number 6C184F 2D printed on the back side

Conclusion

I will jump right to the conclusion: we have confirmed that there are at least two versions of Death Force. One version can be completed while the other cannot.

In my version, it was impossible to finish. Not because it was too difficult, but because the entrance to the pathway leading to the last boss chamber is blocked by a wall. The coordinate of the entrance at ($19,$0D) is blocked.

This entrance is on the screen pictured below. Internally, it is identified as MAP $79. The Death Force “world” is made up of a 16×16 matrix of maps. Each map has two layers: above and below ground. The map in the top-left corner is $00, and the ID increments by $01 moving to the right. Moving down the map matrix, the ID increases by $10. So, MAP $79 is 7 maps down, 9 maps right from the top-left corner map.

The stairs are not hidden at all, as you can see, but you cannot enter.

Below is the table of the entrance (stairs) coordinates of the final stage, stage 9.

$7C00~
14
75 05 0C 01 
56 1B 09 04 
77 17 1C 01 
78 07 1F 01 
79 19 0D 01 
85 08 10 04 
77 1C 07 04 
87 1E 0F 04 
58 0E 07 04 
69 1E 13 04 
6B 1E 13 04 
48 0F 0B 01 
89 05 16 04 
6A 0F 14 04 
57 19 0F 04 
88 13 0F 04 
8A 07 1D 01 
7A 07 1D 01 
7B 05 01 04 
8B 05 07 01

The first byte $14 is the number of stairs. There are $14 (20) stairs in the final stage. If you look at the fifth set of stairs, it has four numbers: $79, $19, $0D, and $01. $79 is the map ID. ($19,$0D) is the coordinate of the stairs in map $79. Each map consists of 40×37 smaller blocks. The coordinate ($19,$0D) means $19 (25) blocks to the right, $0D (13) blocks down from the top-left corner. The last $01 tells that you need to move downward to enter the stairs from the field down to the underground level.

The following is the table for collision check. If the bit 0 is 1, the block is solid. Each byte covers 1×2 blocks. The bytes highlighted red are blocking the entrance to the stairs leading to the last-boss chamber. The player can go down no farther than Y=$0A. Since the entrance to the stairs is checked before the wall, if the Y-coordinate of the entrance is $0B, you can enter the stairs. However, the Y-coordinate of the entrance was written as $0D, making it impossible to enter.

$4C00~
00 00 00 00 00 00 00 00 00 00 03 03 03 03 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
01 01 01 01 01 01 01 03 03 03 00 00 00 00 00 00 00 00 03 03 03 03 03 01 01 01 01 01 01 01 01 01 01 01 01 01 01 03 03 03
01 01 01 01 01 01 01 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 01 01 01 01 01 01 01 01 01 01 01 01 01 01 03 03 03
00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 03 03 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03
00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 03 03 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03 00 00 03 03 03 00 01 00 00 00 01 00 00 00 00 00 00 00 00 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03 03 03 03 03 03 00 01 00 00 00 01 00 00 00 00 00 00 00 00 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 00 03 03 03 03 03 00 00 00 00 00 00 00 00 00 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00 01 03 03 03 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03 03 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03 03 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03 03 03 03 03
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 03 03 03
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 03 03 03
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03 03
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 03
03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03

There are two solutions. One is to alter the Y-coordinate of the entrance from $0D to $0B. The problem with this method is that the coordinate is written in the program disk (A disk) track 15, side 0, sector 12. That would require modifying the disk data, so we want to avoid this. (Of course, it’s not a big deal if you are working with disk images, but you shouldn’t modify the few remaining original disks of such a classic game! If something fails, you may permanently destroy your copy. The original disk is a historic artifact. Don’t modify it if you own one.)

There is a better solution. The above wall table (at memory address $4C00) is constructed from 20×10 table when the player moves across maps. The 20×10 table is in the data disk, and it is copied from B disk before you start a new game. The 20×10 table for map $79 is as follows:

$7800~ 
01 01 01 06 03 5B 5B 5B 5B 5B 02 08 01 01 01 01 01 01 06 03 
09 09 09 0E 0A 01 01 06 03 5B 0F 10 09 09 09 09 09 09 0E 0F 
00 00 00 1B 09 09 09 0E 0F 5B 0F 18 00 00 00 00 00 00 16 0F 
00 00 00 00 00 00 00 16 0A 01 0B 18 2D 2E 2F 00 00 00 16 0F 
00 00 00 00 00 00 00 1B 09 09 09 19 46 47 5A 00 1D 02 1E 1F 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 0F 5B 5B 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 0A 06 03 
1E 1E 1E 1E 1E 1E 1E 1E 1E 03 1C 00 00 00 00 00 1B 09 0E 0F 
5B 5B 5B 5B 5B 5B 5B 5B 5B 0F 18 00 00 00 00 00 00 00 16 0F 
5B 5B 5B 5B 5B 5B 5B 5B 5B 20 1E 1E 1E 1E 1E 1E 1E 1E 1E 1F

You can shift the stairs by two blocks by moving the highlighted 6 bytes by one row. The table is written in track 11, side 1, sector 9 of the data disk. By modifying the sector as follows, you can enter the stairs leading to the last-boss chamber.

Before modification
Disk:0 Track:11 Side:1 Sector:9
0000  18 00 00 1d 04 05 1c 00 5b 02 08 01 0b 18 00 1b|........[.......
0010  09 09 09 09 19 00 00 16 0c 0d 18 00 5b 0f 10 09|............[...
0020  09 19 00 00 00 00 00 00 00 00 00 1b 09 09 19 00|................
0030  5b 0f 18 00 00 00 00 00 00 1d 02 1e 03 1c 00 00|[...............
0040  00 00 00 00 5b 0f 18 00 00 00 00 1d 02 1e 1f 5b|....[..........[
0050  20 1e 1e 1e 1e 1e 1e 1e 5b 0f 18 2d 2e 2f 00 16| .......[..-./..
0060  0f 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 20 1e 1e|.[[[[[[[[[[[[ ..
0070  1e 1e 1e 1e 1f 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b|.....[[[[[[[[[[[
0080  01 01 01 06 03 5b 5b 5b 5b 5b 02 08 01 01 01 01|.....[[[[[......
0090  01 01 06 03 09 09 09 0e 0a 01 01 06 03 5b 0f 10|.............[..
00a0  09 09 09 09 09 09 0e 0f 00 00 00 1b 09 09 09 0e|................
00b0  0f 5b 0f 18 00 00 00 00 00 00 16 0f 00 00 00 00|.[..............
00c0  00 00 00 16 0a 01 0b 18 2d 2e 2f 00 00 00 16 0f|........-./.....
00d0  00 00 00 00 00 00 00 1b 09 09 09 19 46 47 5a 00|............FGZ.
00e0  1d 02 1e 1f 00 00 00 00 00 00 00 00 00 00 00 00|................
00f0  00 00 00 00 16 0f 5b 5b 00 00 00 00 00 00 00 00|......[[........
After modification
Disk:0 Track:11 Side:1 Sector:9
0000  18 00 00 1d 04 05 1c 00 5b 02 08 01 0b 18 00 1b|........[.......
0010  09 09 09 09 19 00 00 16 0c 0d 18 00 5b 0f 10 09|............[...
0020  09 19 00 00 00 00 00 00 00 00 00 1b 09 09 19 00|................
0030  5b 0f 18 00 00 00 00 00 00 1d 02 1e 03 1c 00 00|[...............
0040  00 00 00 00 5b 0f 18 00 00 00 00 1d 02 1e 1f 5b|....[..........[
0050  20 1e 1e 1e 1e 1e 1e 1e 5b 0f 18 2d 2e 2f 00 16| .......[..-./..
0060  0f 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 20 1e 1e|.[[[[[[[[[[[[ ..
0070  1e 1e 1e 1e 1f 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b 5b|.....[[[[[[[[[[[
0080  01 01 01 06 03 5b 5b 5b 5b 5b 02 08 01 01 01 01|.....[[[[[......
0090  01 01 06 03 09 09 09 0e 0a 01 01 06 03 5b 0f 10|.............[..
00a0  09 09 09 09 09 09 0e 0f 00 00 00 1b 09 09 09 0e|................
00b0  0f 5b 0f 18 00 00 00 00 00 00 16 0f 00 00 00 00|.[..............
00c0  00 00 00 16 0a 01 0b 18 00 00 00 00 00 00 16 0f|................
00d0  00 00 00 00 00 00 00 1b 09 09 09 19 2d 2e 2f 00|............-./.
00e0  1d 02 1e 1f 00 00 00 00 00 00 00 00 00 00 00 00|................
00f0  46 47 5a 00 16 0f 5b 5b 00 00 00 00 00 00 00 00|FGZ...[[........

This change moves down the stairs graphics by two blocks in map $79, as you can see below. This change will allow you to finish the game without altering Disk A.

Well, it’s not very kind to explain how to modify the sector without giving a way to do so. If you have a data disk image of Death Force, and are having a problem finding a way to the last-boss chamber, you can modify the data-disk image by the following Python script. I don’t like Python. I like C++ better, but maybe more people have Python interpreter rather than a C++ compiler.

import sys

inFName=sys.argv[1]
outFName=inFName+"_patched"
print("Input="+inFName)
print("Output="+outFName)

ifp=open(inFName,"rb")
bin=ifp.read()
ifp.close()

print("Python inferiority.")
print("Why do I have to convert an array to a list, edit,")
print("and then convert it back to an array?")
print("Surprisingly poor programming language.")
print("Ditch Python. Use C++.")
lst=[]
for b in bin:
    lst.append(b)

print("Input Length="+str(len(lst))+" bytes")

nFound=0
for i in range(len(lst)-60):
    if lst[i:i+5]==[0x0b,0x18,0x2d,0x2e,0x2f] and lst[i+20:i+25]==[0x09,0x19,0x46,0x47,0x5a]:
        print("Found at 0x"+hex(i))
        lst[i+42]=lst[i+22]
        lst[i+43]=lst[i+23]
        lst[i+44]=lst[i+24]
        lst[i+22]=lst[i+2]
        lst[i+23]=lst[i+3]
        lst[i+24]=lst[i+4]
        lst[i+2]=0
        lst[i+3]=0
        lst[i+4]=0
        nFound+=1

if 1!=nFound:
    print("This should occur only once.\n")
    print("Something is not right.\n")
    quit()

ofp=open(outFName,"wb")
ofp.write(bytearray(lst))
ofp.close()

print("Wrote to "+outFName)
print("Rename the extension before using.")

If the data disk image is DFORCEDATA.D77, and if you saved this script as dforcepatch.py, you can type as:

python dforcepatch.py DFORCEDATA.D77

It will create a file called DFORCEDATA.D77_patched. Please change the extension to D77 and use.

Also I made my data disks near the ending available. I couldn’t go through the violent offence from the enemies in the last stage. I altered the player data in the data disk. Also I used a different method to enter the stairs, so the map hasn’t been modified in these data disks.

[Immediately before the last-boss battle] [Immediately after the last-boss battle]

As discussed in http://fm-7.com/forum/viewtopic.php?f=3&t=71, by killing yourself by bombs after killing the last boss, you can see the ending credits.

Confirming the Presence of the Bug-Fix Version

Another rumor about Death Force is that one user complained to the developer, Riverhill Soft, that the game was unbeatable and was sent a fixed version that could be completed. Is it real or fake?

Based on the above observation, if such a bug-fix version exists, the change from the un-finish-able version most likely be in track 15 side 0 sector 12 of A disk, or track 11 side 1 sector 9 of B disk. If the user who received a bug-fix version disk was able to finish the game, the change should be in A disk because B disk is used only once when the user starts a new game.

This question was solved by a copy of Death Force owned by a member of the Game Preservation Society and also disks in the Game Preservation Society collection. The member’s disk had a serial number 75524X 2D on the back of the disk. My copy has 6C184F 2D. The number probably is the serial number for the batch of the disk, not the serial for Death Force. Nonetheless, since the highest digit of his serial number is 7, and mine is 6, his copy is likely to be a newer version.

Below is the dump of track 15 side 0 sector 12 of his disk.

0000  14 75 05 0C 01 56 1B 09-04 77 17 1C 01 78 07 1F |.u...V...w...x..
0010  01 79 19 0B 01 85 08 10-04 77 1C 07 04 87 1E 0F |.y.......w......
0020  04 58 0E 07 04 69 1E 13-04 6B 1E 13 04 48 0F 0B |.X...i...k...H..
0030  01 89 05 16 04 6A 0F 14-04 57 19 0F 04 88 13 0F |.....j...W......
0040  04 8A 07 1D 01 7A 07 1D-01 7B 05 01 04 8B 05 07 |.....z...{......
0050  01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................
0060  00 00 00 00 00 90 00 02-04 00 00 C0 03 90 02 1E |...........タ....
0070  04 93 00 02 04 00 00 C0-03 90 02 28 06 96 00 04 |.......タ...(....
0080  08 82 03 00 01 8C 0B 32-08 AE 00 04 08 82 03 00 |.......2.ョ......
0090  01 0C 0B 32 0A C6 00 04-08 82 03 00 01 0C 0B 46 |...2.ニ.........F
00A0  0F 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................
00B0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................
00C0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................
00D0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................
00E0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................
00F0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 |................

And below is the same sector of my disk.

0000  14 75 05 0c 01 56 1b 09 04 77 17 1c 01 78 07 1f|.u...V...w...x..
0010  01 79 19 0d 01 85 08 10 04 77 1c 07 04 87 1e 0f|.y.......w......
0020  04 58 0e 07 04 69 1e 13 04 6b 1e 13 04 48 0f 0b|.X...i...k...H..
0030  01 89 05 16 04 6a 0f 14 04 57 19 0f 04 88 13 0f|.....j...W......
0040  04 8a 07 1d 01 7a 07 1d 01 7b 05 01 04 8b 05 07|.....z...{......
0050  01 39 1a 10 cc 0f 2f 8d 41 cc 03 0e f7 fd 16 b7|.9..../.A.......
0060  fd 15 7f fd 15 90 00 02 04 00 00 c0 03 90 02 1e|...............
0070  04 93 00 02 04 00 00 c0 03 90 02 28 06 96 00 04|...........(....
0080  08 82 03 00 01 8c 0b 32 08 ae 00 04 08 82 03 00|.......2........
0090  01 0c 0b 32 0a c6 00 04 08 82 03 00 01 0c 0b 46|...2...........F
00a0  0f 15 7f fd 15 f7 fd 16 4a b7 fd 15 7f fd 15 39|.......J.....9
00b0  34 02 64 e4 24 14 bd 2a cb cc 1d 00 b7 fc 80 f7|4.d.$..*........
00c0  fc a0 96 36 b7 fc a1 7f fd 05 64 e4 24 14 bd 2a|...6.....d.$..*
00d0  cb cc 1d 01 b7 fc 80 f7 fc a0 96 35 b7 fc a1 7f|...........5...
00e0  fd 05 64 e4 24 14 bd 2a cb cc 1d 02 b7 fc 80 f7|..d.$..*........
00f0  fc a0 96 37 b7 fc a1 7f fd 05 64 e4 24 14 bd 2a|...7.....d.$..*

Four bytes from offset $0011 are 79 19 0B 01 in his version and 79 19 0D 01 in my version. This change matches exactly with one of the possible corrections I predicted.

The Game Preservation Society kindly checked three Death Force disks in their collection. Two of the three disks had $0D (bugged version) at offset $0013 of the sector, and one had $0B (fixed). Overall, we have checked six A disks, four of them were bugged and two were fixed. Although we cannot completely exclude the probability that a user somehow figured how to bug-fix the disk and made the change, such a probability is very slim. Most likely Riverhill Soft realized the bug after shipping the first version then published a corrected version.

It was somewhat lucky that I received a bugged version disk from Yahoo auction. If I picked up a corrected version, I would have finished with no problem, and I could have concluded that the rumor was false.

Was it due to the backfire of the copy protection?

Regarding one of the questions, whether it was due to the copy protection gone wrong, I can not conclude for sure. However, I have a feeling that this was not the case. The reason for this is because there was no disk access for any sort of copy-protection check when the player enters the last stage (stage 9) until reaching map $79.

The copy protection of Death Force checks the presence of $F6 and $F7 sectors, then checks the content of the sectors, and also checks that the sectors give for a CRC error. It is a very common copy protection in Fujitsu FM-7 series computers. I have modified the source code of FM-7 emulator called XM7 so that it breaks in the debugger when $F5, $F6, or $F7 is written to the sector register $FD1A. It does break while booting the game, indicating that the emulator is detecting the copy protection check. However, it did not break in the last stage.

From this observation I strongly believe it was not due to a copy protection mistake.

Was it just a plain old bug?

I believe it was a regular old bug:

1. In the fixed version, the player character can enter the stairs leading to the last-boss chamber without doing anything special.

2. The last stage, stage 9, has numerous errors with the stairs coordinates, not just the one leading to the last-boss chamber. Several are inaccessible as they are blocked by a wall. For the same reason, there are many chambers that you can go in but never get out.

3. The game does not have many special tricks or features. As I played through the game, I saw only two special features: one, when all 15 seals are collected the player appearance and the BGM changes, and two, the BGM changes when you kill the last boss. Other than that, the game progresses with the same rules and the same code. I cannot believe the developer wrote special code just for this entrance.

4. If the developer intended to make a special trick for this particular entrance, it would more likely be an invisible stairs at the beginning, which becomes visible when certain conditions are met. It sounds very strange if the developer keep it visible all the time and then move the stairs on a certain condition.

If it was not a bug, there must be a way to enter the stairs without altering the data disk or the program disk. We cannot fully exclude the possibility that the first version had an additional secret that the user needs to discover to enter the last-boss chamber, but it was too difficult and removed in the later versions. Possibilities are:

1. the Y-coordinate of the entrance in map $79 changes from $0D to $0B,

2. the wall in map $79 blocking the entrance moves down by 2 blocks, or

3. the properties of map $79 changes so that the wall moves down by 2 blocks by a KEY, if certain conditions are satisfied.

Possibility 1 is very unlikely because the coordinate of the entrance is written in disk A, which is write protected. Therefore it wouldn’t be saved to the data disk.
Possibility 2 is unlikely, too. If there is a code that alters map $79 somewhere, the alteration must be saved to the data disk once the blockage is removed. I have experimented if the change to the map can be saved. In XM7 debugger, I modified the map data of map $79 and made sure the map appearance has changed. Then I saved the data and examined the disk image to test if the modification was saved. Also I restarted the game from where I saved. In this experiment, I did not observe the changes in the map in the data disk, and the map appeared the same as pre-modification after re-booting and re-loading the data. Changes to the map were not saved, therefore Possibility 2 is unlikely.

There still is a possibility that this particular change remains in one session, and the player needs to re-satisfy the condition if the program is re-booted. However, all other status are saved to the data disk. It is very strange if this only one state is not savable.

I believe that the possibility 3 is most likely among all possibilities. In map-changing code, there is a very interesting piece:

   2812 30 88 13       LEAX  $13,X   Map-properties structure (MAP $79: $A6B0)+$13
   2815 86 06          LDA   #$06    6 counts
   2817 97 13          STA   <$13    Loop counter
   2819 E6 80          LDB   ,X+
   281B C1 FF          CMPB  #$FF
   281D 27 1A          BEQ   $2839
   281F CE 78 00       LDU   #$7800
   2822 4F             CLRA
   2823 33 CB          LEAU  D,U
   2825 A6 80          LDA   ,X+
   2827 D6 20          LDB   <$20
   2829 C4 01          ANDB  #$01
   282B 27 02          BEQ   $282F
   282D 9A 14          ORA   <$14
   282F A7 C4          STA   ,U
   2831 0A 13          DEC   <$13
   2833 26 E4          BNE   $2819

If the properties of a map is configured so that the map consumes a KEY, two temporary changes are made to the map when the player first enters. One is a change when the highest 2 bits match a certain pattern. If they match, the 2 bits will be replaced with a different pattern. However, since the binary code for the stairs has a different highest 2 bits, this change does not help. The second change is applied to overwrite arbitrary six bytes with arbitrary values. Six bytes are just enough to move the stairs.

The properties of map $79 is written in 32 bytes table at physical address $0B6B0. If bit 7 of the byte at offset $1F is 1, the map consumes a KEY. The bytes in offset $14 to $1E defines the six-byte modification to the map.

0B6B0: 04 04 03 08 04 08 0C 04 0B 16 04 12 16 00 00 00 :7C ................
0B6C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 :02 ................
0B6D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :00 ................

By modifying offset $14 to $1F as follows, the entrance to the stairs will be unblocked when the player enters map $79 with at least one key.

0B6B0: 04 04 03 08 04 08 0C 04 0B 16 04 12 16 00 00 00 :7C  ................
0B6C0: 00 00 00 5c 2d 5d 2e 5e 2f 70 46 71 47 72 5a 82 :02  ................
0B6D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :00  ................

Importantly, this change will be saved to the data disk with other status.

With this modification, map $79 will become as following image when you enter with a KEY.

As you can see, the stairs graphics will be stretched unnaturally. Although this modification to the map properties opens the path to the last-boss chamber, and the status is savable, I doubt if the developer could have added such a feature that breaks the appearance of the graphics. Although it is most likely among the above possibilities, I think it is ultimately not the intention.

Again, being unable to find a code that opens the path to the last-boss chamber does not mean it doesn’t exist. I cannot say that there is absolutely no way of entering the chamber without modifying the program or data disk. And there may yet be another method for the player to enter the last-boss chamber that I haven’t considered.

Nonetheless, after considering the above possibilities, my conclusion is that it was just a plain bug that was blocking the pathway to the last-boss chamber.

Invincibility Commands

It is known that if you type “SILVER” (case sensitive) and space while the opening music is playing, the player character becomes invincible until you restart the game. You can play in invincible mode, save, and restart into normal mode. For example, you can force the way through difficult maps in the invincibility mode, save, and then continue in the normal mode. (Reference: http://fm-7.com/museum/database/urawaza/810101300.html)

The code disassembly revealed that two more keywords are checked when the user presses the space key during the opening demo. The keyword is not checked exactly. Instead, it checks the total and XOR of the six characters typed before the space key. Therefore, the order of the letters does not affect the consequence. Also there are multiple set of characters that works for the feature.

The keywords are as follows.

“SILVER” Invincible (Checksum 0x17D5)

“1VKJIC” Zero Life (Checksum 0x6CA8) <- This feature is nullified anyway because Life is then read from the data disk.

“ARKoxo” Invincible + Infinite keys + Continuous shots of the Bomb + ? (Checksum 0x2034)

There might be a meaningful keyword that enables the second and the third features. However, there are too many combinations, and I could not find the one that has a meaning. The following is a C++ source code I used for finding the keywords for the second and the third features. If you are patient, you may be able to find meaningful words among the candidates.

// Copyright 2019 CaptainYS (soji@andrew.cmu.edu)
// Can redistribue free of charge without permission.

#include <stdio.h>
#include <string.h>

unsigned int Sum(const unsigned char buf[6])
{
    unsigned int sum=0;

    unsigned int A=0,B=0;
    for(int i=0; i<6; ++i)
    {
        A=(A^buf[i])&0xff;  // AND is not really necessary.
        B=(B+buf[i])&0xff;
    }

//   236C A8 84          EORA  ,X
//   236E EB 84          ADDB  ,X
//   2370 6F 80          CLR   ,X+
//   2372 31 3F          LEAY  -1,Y
//   2374 26 F6          BNE   $236C
    return A*256+B;
}

inline unsigned char Increment(unsigned char c)
{
    ++c;
    if('9'+1==c)
    {
        c='A';
    }
    else if('Z'+1==c)
    {
        c='a';
    }
    else if('z'<c)
    {
        c='0';
    }
    return c;
}

int main(void)
{
    printf("%02x\n",Sum((const unsigned char *)"SILVER"));

    // 17D5  "SILVER"  Invincible
    // 6CA8            LIF=0 ??
    // 2034            Invincible, Infinite KEY, Simultaneous bomb shots, +???

    char buf[7]="000000";
    while(0!=strcmp(buf,"zzzzzz"))
    {
        buf[5]=Increment(buf[5]);
        for(int i=5; 0<i; --i)
        {
            if('0'==buf[i])
            {
                buf[i-1]=Increment(buf[i-1]);
            }
            else
            {
                break;
            }
        }

        for(int i=0; i<4; ++i)
        {
            // Doesn't take two same key strokes.
            if(buf[i]==buf[i+1])
            {
                goto NEXT;
            }
        }

        auto s=Sum((const unsigned char *)buf);
        if(0x17D5==s || 0x6CA8==s || 0x2034==s)
        {
            printf("%04x: %s\n",s,buf);
        }
    NEXT:
        ;
    }
    printf("%s\n",buf);
    return 0;
}

Last Boss: very similar to one of the other bosses

Ending (spoiler alert!)

Slow-Growth Problem of DUR Max

In this game, the player has four parameters: LIF, DUR, WEP, and MOV. The Maximum value of LIF, WEP, and MOV grows by collecting power-up items. There is no description of the condition that grows DUR Max in the manual, though, and the growth is extremely slow. DUR Max is written in $3C ($003C). I looked for the condition in disassembly that grows DUR Max. It turned out that DUR Max grows once every 128 times the player gets a damage.

The following disassembly is part of the damage routine.

   1BFC 0C 48          INC   <$48
   1BFE 96 48          LDA   <$48
   1C00 84 7F          ANDA  #$7F
   1C02 26 0D          BNE   $1C11    <- $48 is incremented for every damage.
                                         This BNE passes once every 128 times.
   1C04 96 51          LDA   <$51     <- If the damage is from self-inflicting (by bomb) <$51=1.Otherwise 0.
   1C06 26 09          BNE   $1C11
   1C08 96 3C          LDA   <$3C     <- Reading DUR Max.
   1C0A 81 FF          CMPA  #$FF
   1C0C 27 03          BEQ   $1C11    <- Preventing overflow.
   1C0E 4C             INCA           <- Increment DUR Max.
   1C0F 97 3C          STA   <$3C     <- Writing DUR Max.

The game balance should have been adjusted so that DUR Max is reasonably high when the user is close to the last-boss battle. But, if you play this game with no prior knowledge, your DUR Max won’t grow much until the last stage. What is worse is that if you play well and avoid damage, you won’t be rewarded. Good game play should be rewarded. Rather, this game penalizes you if you play well. Back in 1987, we did not have such methodology for adjusting the game-balance.

The present value of DUR (not max) recovers automatically. But the recovery is painfully slow. After killing a few enemies, you will need to wait for 20 to 30 seconds until DUR recovers. I was hoping the recovery may become faster with the growth of the player character, but it was not the case. DUR recovers by 1 every 64 iterations of the main loop. It is hard coded and never changes. Waiting 20 to 30 seconds every few battles is obviously unacceptable with the current standards of gameplay balance. Death Force is a game from 1987 after all.

The following is disassembly of where DUR is incremented by 1 every 64 iterations.

   05E5 96 24          LDA   <$24    <- Counter: incremented every iteration of the main loop.
   05E7 84 3F          ANDA  #$3F
   05E9 26 0E          BNE   $05F9   <- Pass once every 64 iterations.
   05EB 96 38          LDA   <$38    <- Reading DUR current value.
   05ED 91 3C          CMPA  <$3C
   05EF 24 01          BCC   $05F2   <- Passes if there is a room for recovery.
   05F1 4C             INCA          <- Recover by one.
   05F2 97 38          STA   <$38    <- Writing DUR current value.

Death Force World Map

The following maps are created by trimming and stitching screenshots together using 2D Retro Map Tool. I had to add support for transparency to stitch underground map where only passable blocks are visible at one time. I will upload the upgraded version shortly.

Field

Underground

Playing Guide

Beginning

The basic gameplay involves (1) collecting all weapons and seals (I think the developer meant SEAL, but misspelled as SEEL in the game.), (2) killing the last boss, and (3) killing yourself. Aside from some hidden stairs, there are few tricks or secrets you need to find. Locations of the seals, weapons, and stairs are marked in the above maps.

This game is called an RPG, but unlike traditional role-playing games like Wizardry or Ultima, the player character does not grow just by killing enemies. You need to pick up items for increasing LIF, MOV, and WEP attributes, and take damages to increase DUR maximum. Boss characters drop items for increasing LIF, MOV, or WEP. The type of the item is random.

You also need to collect KEYs. You cannot get around without KEYs. One of the biggest nightmares in this game is that you can only carry up to 5 keys at one time. You cannot collect 100 keys before going into long travel. Therefore, you need to spend time on the way to re-supply keys when possible. Since the kind of item an enemy drops is random, you will spend a great deal of time on re-supplying keys. Even taking into account that the game is from 1987, it’s still very painful and takes tremendous patience.

If you play it on XM7 emulator, I suggest keeping a memory dump of the main system from $0000 to $007F always open. There the program keeps main parameters. Some of the parameters that I identified are listed in the Selected Technical Information section. You can carry only up to five keys at one time, but you cannot see how many keys you have. The game will torture you by not telling how many keys in your pocket! But the number of keys is in $003D. You’ll know when you finally have enough keys. Also you need to take damage 128 times to increase the internal value of DUR max by one. Extremely painful, but at least if you know how much more damage for increasing DUR max, it gets slightly more bearable. The damage count is $0048.

When you start a new game, the first thing to do is to collect keys. You need to work on this painfully boring task many times during the game play. What you can do is move to the map to the right from the starting map, and then go down. In there one L-PAC, which recovers your LIF, is hidden behind the wall. It is close to the top-right corner. The item re-appears when you get out and come back in to this map. Therefore you won’t need to worry about exhausting your LIF to death.

In some maps, enemies, items, and bosses never appear again once you kill them and pick them all. In other maps, they do re-appear indefinitely once you walk out and in to the map again. For example, you can quickly recover your LIF in such maps with indefinite L-PACs. One thing to be careful of is if the map consumes a key, you may exhaust your keys by walking in and out of the map many times. Some maps consumes a key but also you can get a key or two indefinitely. In those maps you won’t have to worry about exhausting keys. In a map that a weak boss re-appears indefinitely, you can kill a boss many times to train your L-MAX, W-MAX, and M-MAX.

Once you collect enough keys, go to MAP $21 and get 8-way shot. 8-way shot is very useful. If you kill all small enemies and get the 8-way shot, you will need to fight a boss. If you want to avoid a boss-battle, leave at least one small enemy.

After getting the 8-way shot, go to MAP $03 via underground. There you will see small enemies that drop an item. In this map, enemies and bosses will re-appear indefinitely. By killing enemies and collecting items, you can quickly recover your LIF, WEP, and MOV. If you also kill the bosses, you can train your L-MAX, W-MAX, and M-MAX. The bosses in this map are relatively weak. You can go close to the boss and blaze you 8-way shots. If you shoot from immediately above or below the boss, near the center, 3 of the 8 shots will hit the boss. It’s a good idea to exercise your patience, and spend several hours to train your L-MAX, W-MAX, and M_MAX in this map. You’ll need to do it before going to the last-boss battle. If you do it earlier, the rest of the game play will become easier.

MAP $03

Getting Guided Missile, Bomb, and Fire Thrower

After training in map $03 for several hours, you are ready to go and get three weapons, Guided Missile, Bomb, and Fire Thrower. Go to Stage 8 via underground and come out to the field in map $62. There are two bosses in map $62, but they are easy to defeat.

Then move to the map above (map $52). You will need to fight a relatively strong boss, which I call the “Water Bottle.” Try to blaze 8-way shots and attack physically at the same time. You may take substantial damage, but you should be able to win. Then go underground and get the Guided Missile. Once you have this weapon, it is easy to kill the Water Bottle. All you need to do is hide behind a wall and continue shooting the Guided Missiles. Actually if you have a wall, this strategy works for all the bosses, including the last boss.

Then go back to map $62 and go to the underground level. Walk to the south while re-supplying as needed and go to Stage 7. Go above ground at map $A0. Go down to $B0 and get the Flame Thrower. The boss at $B0 is strong. Therefore, leave one small enemy to avoid the boss battle.

Make sure to walk from map $C1 to $D1 from the right-hand side of the map. You need to kill two very strong bosses that I call “Sunny-Side Up” and “Pierrot” (“clown” in Japanese). Use hover to quickly take cover behind the wall and shoot guided missiles from there. These bosses won’t re-appear once you kill them, so they won’t be an issue in the return trip.

Then go to map $C0, and go underground. One very important thing in the underground level of map $C0 is to make sure you have at least one key when you go in, and then as soon as you go in, get two keys hidden behind the door. Since you can get two keys, you can go between maps $C0 and $B0 to recover your keys to max (five keys).

Once you have at least two keys, go to map $D0 and get the Bomb. This weapon is needed to see the ending roll because you will need to kill yourself after defeating the last boss.

Collecting Seals

Then all you need to do is collect the 15 seals. Locations of the seals are on the maps. You need to collect them in a specific order. I put numbers beside each in the maps so that you can know in what order you need to collect them.

I don’t know if you need to collect all the weapons as well. I have a feeling that you don’t, but I’ve not confirmed it. Maybe it is safe to also collect the Boomerang as well.

Training DUR Max

After collecting all seals, one last painful thing to do before fighting the last boss is to train DUR Max. In this game, DUR Max increases by one for every 128 times damage is taken. (By the way, the number you see on the screen is twice the internal value. It means that you need to take 256 times of damages to increase the number on screen by one.)

In my opinion, the most efficient location to train DUR Max is map $B5. Four small enemies with an item (I call them Shrimps) re-appears indefinitely. Also you can pick up two L-PACs. If you need more L-PAC, there is another one on map $B6. You can go to the secret underground level from a few maps below to recover WEP as well.

To kill these four small enemies, align them nearly horizontally and shoot 8-way shots. If you are lucky enough, four shots will hit them. Once you attack, they shoot you back. So you can get damages and train DUR Max.

You will need to continue this work for several hours. Remember: it’s a game from 1987 with dreadful gameplay balance.

Map $B5

Last Boss Battle

When your DUR grows like 50 on the screen, then you can go for the last-boss battle. I have drawn green lines to tell you how to get to the last-boss.

But, enemies in the last stage will fiercely attack you. You will get substantial damage before getting to the last-boss. The last place to recover is map $7B. There one of the weakest bosses, which I call Green, re-appears indefinitely. If you go down to $8B, you will need to fight a Pierrot, which will give you a good amount of damage. So, instead of going down and come back up, you can save and load to resurrect a Green. Since L-MAX, W-MAX, and M-MAX also recovers LIF, WEP, and MOV, you can easily top-off by repeating saving and loading in map $7B.

Last Supply Point. Map $7B

Then finally the last-boss battle. In the last-boss chamber, there are a bunch of small enemies which I call Blackberries. Blackberries are fast and blaze missiles at you. They move too quickly for guided missiles, so use your 8-way shots, bombs, and direct attacks to quickly kill them before getting too much damage.

Once you kill all Blackberries, you need to fight a normal Pierrot first, and then the last boss, which looks like a Pierrot, but with two eyes open. You can win by hiding behind a wall and shooting guided missiles.

After killing the last-boss, use Bomb to kill yourself to see the ending roll.

The Last Boss. Hide behind a wall and shoot guided missiles to win

Selected Technical Information

Main Loop

$230~$24E  Initialization
$251~$277  Main Loop
$279~$28B  PAUSE loop (runs until ESC key stroke)

   0251 8D 26          BSR   $0279  <- If the user presses the ESC, this loop blocks until another ESC key stroke.
   0253 BD 22 0B       JSR   $220B
   0256 25 D8          BCS   $0230
   0258 8E 00 00       LDX   #$0000
   025B 9F 0E          STX   <$0E
   025D BD 0A 5F       JSR   $0A5F
   0260 BD 02 8E       JSR   $028E
   0263 BD 02 B6       JSR   $02B6  <- Moving: item-acquisition is in this routine.
   0266 BD 15 E4       JSR   $15E4
   0269 BD 14 D4       JSR   $14D4
   026C BD 0A 28       JSR   $0A28
   026F BD 21 29       JSR   $2129
   0272 BD 2A 4C       JSR   $2A4C
   0275 0C 24          INC   <$24
   0277 20 D8          BRA   $0251

Map ID and State ID matching table

Addr   +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F Sum
7D00 : 00 00 00 00 00 00 01 01 01 01 01 02 02 02 02 02 :0F  ................
7D10 : 00 00 00 00 00 00 01 01 01 01 01 02 02 02 02 02 :0F  ................
7D20 : 00 00 00 00 00 00 01 01 01 01 01 01 02 02 02 02 :0E  ................
7D30 : 00 00 00 00 00 00 01 01 01 01 01 01 02 02 02 02 :0E  ................
7D40 : 00 00 00 00 00 00 09 09 09 01 01 01 03 03 03 03 :2A  ................
7D50 : 08 08 08 08 08 08 09 09 09 01 01 01 03 03 03 03 :5A  ................
7D60 : 08 08 08 08 08 08 09 09 09 09 09 09 03 03 03 03 :72  ................
7D70 : 08 08 08 08 08 09 09 09 09 09 09 09 03 03 03 03 :73  ................
7D80 : 07 07 07 08 08 09 09 09 09 09 09 09 03 03 03 03 :70  ................
7D90 : 07 07 07 08 08 09 09 09 09 04 04 04 03 03 03 03 :61  ................
7DA0 : 07 07 07 07 06 06 06 06 04 04 04 04 04 04 03 03 :52  ................
7DB0 : 07 07 07 07 06 06 06 06 04 04 04 04 04 04 04 04 :54  ................
7DC0 : 07 07 07 07 06 06 06 06 05 05 04 04 04 04 04 04 :56  ................
7DD0 : 07 07 07 06 06 06 06 06 05 05 04 04 04 04 04 04 :55  ................
7DE0 : 07 07 07 06 06 06 06 05 05 05 05 05 05 05 05 05 :5A  ................
7DF0 : 07 07 07 06 06 06 06 05 05 05 05 05 05 05 05 05 :5A  ................
----------------------------------------------------------  ----------------
Sum  : 50 50 50 4F 4C 4F 5E 5C 56 41 3F 41 34 34 33 33 :79

It tells rough placements of the stages.

   Stage 0           Stage 1         Stage 2
   Stage 8           Stage 9         Stage 3
   Stage 7           Stage 6         Stage 4
                                     Stage 5

Stage 5 is unreachable.

Basic Variables

Main CPU address space $0000 to $00FF (Physical address $30000 to $300FF)

DP=0x00
+00 Key stroke interpreted as joystick code.
+01 Player character direction (0 is up. 8 directions clockwise.)
+02 Block coordinate X  $25 at the right edge.
+03 Block coordinate Y  $22 at the bottom edge.
+04 Copy of block coordinate X.
+05 Copy of block coordinate Y.
+06 Copy of the joystick code.
+07 Alternate between 0 and <$06 copy.
+08
+09 Sword state. 0 is retracted. 3 is most extended.
+0A
+0B Move counter. The player character moves one step when it is zero. In normal mode it is reset to 3. In hover mode 2.
+0C Alternate 0 and <$0D copy while button is held down. Probably for continuous shooting.
+0D Last button state (for thrust event)
+0E Higher byte of the timer tick count
+0F Lower byte of the timer tick count
+10
+11
+12
+13 General purpose
+14 
+15 Acquired item code
+16
+17 $0A92~$0BE1 loop counter. Probably for moving enemies.
+18
+19
+1A
+1B
+1C
+1D Stage ID
+1E [$7E00+MapID]
+1F
+20 Bit 0 indicates field or underground. Bit 1 is set to 1 when the player moved between the field and underground
    to flag that the map needs to be updated. Bit 1 will be reset to 0 as soon as the map is updated.
+21
+22 Map ID
+23
+24 Incremented every iteration of the main loop
+25 When moving to a next map, [$7800+20*(Y/4)+(X/2)]&0xC0
+26 Pointer to the map properties set in the map-update routine.
+27
+28
+29
+2A
+2B
+2C
+2D Number of remaining enemies in the current map.
+2E Cannot enter the stairs unless it is 0. If bit 7 is set, the player cannot get out of the map until the boss is killed.
+2F Updated when the player moves across a stage border. The meaning is unknown yet.
+30 Updated when the player moves across a stage border. The meaning is unknown yet.
+31
+32
+33
+34 Counter since the last thrust or shooting.
+35 LIF
+36 MOV
+37 WEP
+38 DUR
+39 LIF Max
+3A MOV Max
+3B WEP Max
+3C DUR Max
+3D Remaining Keys
+3E Available weapon flags
+3F
+40 Number of acquired seals. (I believe SEEL in the game is misspelling)
+41
+42 Last-acquired item type for showing a message.
+43 GET ****  I believe it is a counter for showing a message.
+44
+45
+46
+47
+48 Damage counter. DUR Max is incremented when its bit 7 flips.
+49 Updated when the player moves across a stage border. The meaning is unknown yet.
+4A Updated when the player moves across a stage border. The meaning is unknown yet.
+4B Updated when the player moves across a stage border. The meaning is unknown yet.
+4C Updated when the player moves across a stage border. The meaning is unknown yet.
+4D Updated when the player moves across a stage border. The meaning is unknown yet.
+4E Updated when the player moves across a stage border. The meaning is unknown yet.
+4F Updated when the player moves across a stage border. The meaning is unknown yet.

Identified Sub-Routines

$0694         Collision check with enemies and walls.
$0A14         Display message. <$42 is the message code. <$43 is probably the duration.
              A register is probably the number of remaining items for the message.
$0E87         Change stage. Called from $245B (Change map)
$2414         D=20*(Y/4)+(X/2)
$241F         D=$4500+B*#$28+A 
$2429         Change map
$27A0         Update passable blocks after changing the map.

Tables

Entrance-coordinate table from $7C00 was particularly useful.

$2109~  Moving vector table?
$2199~  Moving vector table? $2199+(joystick code & 0x0F)  $FF means unavailable direction.
$3200~  Probably parameter table of enemies.
$328A~  Seal acquisition flags. 1 byte per seal. 0 or 1.
$3299~  I think it is the enemy list. Not confident.
$3330~  Looks to be maps, but too short.
$38C0~  BGM work area?  Some bytes are in sync with the BGM.
$4500~$4B3F  Map for detecting collision between enemies and items.
              '0' is the player character. $FF is an empty block.
              $00~$2F are enemies. $30~$7F are items.
$4C00~$4F1F  Map for detecting collision between the wall.
$7800~       Map.
$7C00~       The first byte is the number of stairs for the current stage.
              Subsequent 4-byte entries mean MapID, X, Y, direction of entry.
$7D00~$7DFF  Map ID to Stage ID table.

Stairs Table

Stage 06

A4 05 0B 01 
A7 1C 07 04 
A7 17 1B 01 
C7 05 17 01 
D6 08 07 01 
D7 05 17 01 
E6 08 07 01 
F6 08 04 01 Isn't this Y-coordinate a bug?

Stage 07

5F 07 0F 01  Obvious bug. Map ID 5F is outside of Stage 7.
82 07 0B 04 
90 0D 15 01 
90 1B 15 01 
92 05 13 04 
A0 05 03 04 
A0 05 16 03 
A3 05 0F 04 
A3 1F 1B 04 
B2 03 0D 01 
C0 05 0F 04 
C1 21 13 04 
C2 17 09 01 
C3 07 08 01 
F0 0F 13 01

Stage 08

70 07 0F 04 
71 13 13 04 
71 23 0F 04 
51 0B 13 04 
52 23 17 04 
62 07 13 04 
72 1B 0B 01 
63 0B 13 04 
53 0B 13 04 
64 17 13 04 
54 19 0B 04 
74 1F 0F 04 
84 03 1B 04 
94 17 13 04 
65 21 0B 01

Stage 09

48 0F 0B 01 
56 1B 09 04 
57 19 0F 04 The entrance overlaps with the wall. Cannot enter.
58 0E 07 04 
69 1E 13 04 Once enter, exit overlaps with the wall, therefore no exit. Is it intentional?
6A 0F 14 04 
6B 1E 13 04 
75 05 0C 01 
77 17 1C 01 
77 1C 07 04 
78 07 1F 01 
79 19 0D 01 Cannot enter. In the finish-able version, it is 79 19 0B 01.
7A 07 1D 01 
7B 05 01 04 
85 08 10 04 Bug?  Intentional?  It is off from the graphics.
87 1E 0F 04 
88 13 0F 04 
89 05 16 04 Once enter, exit overlaps with the wall, therefore no exit. Is it intentional?
8A 07 1D 01 
8B 05 07 01

Item Acquisition

Item acquisition is processed in the routine from $0694. The same routine is used for collision check against enemies. The player does not get damage from the collision with an enemy, but cannot walk through an enemy.

JSR $15A8 will return the code of the item acquired. If it is greater than $0B (11), it is a seal, otherwise a regular item. Seals can only acquired in a specific order. The player can know that a seal is missed in an earlier stage if the player cannot pick up a new seal. The game is torturing the player with DUR, but this point was somewhat kind to the player.

If the player acquired a regular item, the program jumps to the address in the jump table $076B~.

   06A9 BD 15 A8       JSR   $15A8  <- Identify what item is acquired.
   06AC 81 0B          CMPA  #$0B
   06AE 22 22          BHI   $06D2  <- Is a seal if the code is greater than $0B
   06B0 C6 01          LDB   #$01
   06B2 96 15          LDA   <$15
   06B4 BD 15 A8       JSR   $15A8  <- I think this sub-routine erases the item graphics.
   06B7 97 15          STA   <$15
   06B9 8E 07 6B       LDX   #$076B
   06BC 48             LSLA
   06BD AD 96          JSR   [A,X]

Below is the jump table.

	0  0783  KEY
	1  0790  WEAPON 0 8-Shot
	2  0790  WEAPON 1 Guided
	3  0790  WEAPON 2 Framethrower
	4  0790  WEAPON 3 Boomerang
	5  0790  WEAPON 4 BOMB
	6  079D  L-PAC
	7  079D  M-PAC
	8  079D  W-PAC
	9  07CD  L-MAX
	10 07CD  M-MAX
	11 07CD  W-MAX

The following disassembly is for acquiring a seal.

   06D2 8E 32 8A       LDX   #$328A  <- Seals already acquire.
   06D5 80 0C          SUBA  #$0C    <- Item code 12 is seal 0. Therefore, subtract 12 from the item code.
   06D7 27 08          BEQ   $06E1   <- If it is seal 0, always pass.
   06D9 4A             DECA          <- To test if the previous seal is already acquired, A=A-1
   06DA E6 86          LDB   A,X
   06DC 10 27 00 28    LBEQ  $0708   <- Is seal[A] already acquired?
   06E0 4C             INCA          <- Bring the value of A back to previous.
   06E1 6C 86          INC   A,X     <- Raise the seal-acquired flag.
   06E3 0C 40          INC   <$40    <- Increment the seal count.

Changing the Stage

By monitoring $7C00 to $7CFF, you can see that the player moved across a stage border. The same routine is called after a boss battle.

The stairs table from $7C00 is extremely important. If the copy-protection backfire theory is correct, most likely this routine checks the copy protection, and will correct the location of the stairs in map $79 if the check passes.

However, the stairs table is read at the bottom of this routine, and the routine returns by PULS B,PC. Therefore, the stairs table is unaltered in this routine.

Of course, there is a possibility that the table is corrected somewhere totally different. For example, the developer expected someone may look into the code, the developer could have separated the routine for reading the stairs table, and the routine for correcting the table.

But, I think that is very unlikely.

   0E87 34 04          PSHS  B        <- B register is stage ID.
   0E89 86 02          LDA   #$02
   0E8B B7 FD 90       STA   $FD90
   0E8E 8E 0F 31       LDX   #$0F31
   0E91 E6 85          LDB   B,X
   0E93 8E 30 C3       LDX   #$30C3
   0E96 58             LSLB
   0E97 EC 85          LDD   B,X
   0E99 10 8E 00 60    LDY   #$0060
   0E9D 8E 90 00       LDX   #$9000
   0EA0 BD 29 91       JSR   $2991
   0EA3 E6 E4          LDB   ,S
   0EA5 58             LSLB
   0EA6 58             LSLB
   0EA7 58             LSLB
   0EA8 EB E4          ADDB  ,S       <- B=stage ID * 9
   0EAA 8E 0E D7       LDX   #$0ED7   <- [0ED7~] looks to be a table 9 bytes per row.
   0EAD 3A             ABX
   0EAE EC 84          LDD   ,X
   0EB0 DD 49          STD   <$49
   0EB2 EC 02          LDD   2,X
   0EB4 DD 4B          STD   <$4B
   0EB6 EC 04          LDD   4,X
   0EB8 DD 4D          STD   <$4D
   0EBA EC 06          LDD   6,X
   0EBC 97 4F          STA   <$4F
   0EBE D7 2F          STB   <$2F
   0EC0 A6 08          LDA   8,X
   0EC2 97 30          STA   <$30
   0EC4 8E 31 06       LDX   #$3106
   0EC7 EC 84          LDD   ,X
   0EC9 EB E4          ADDB  ,S        <- D register has track and sector numbers.
   0ECB 10 8E 00 01    LDY   #$0001
   0ECF 8E 7C 00       LDX   #$7C00    <- Location of the stairs table buffer.
   0ED2 BD 29 91       JSR   $2991     <- Read sector.
   0ED5 35 84          PULS  B,PC

[0ED7~]
02 02 03 03 03 04 05 00 00 
02 02 03 03 03 04 05 01 00 
03 02 03 03 03 05 05 01 01 
03 02 03 03 04 05 06 01 01 
03 03 03 04 04 05 06 02 01 
04 03 04 04 04 05 06 02 02 
04 03 04 04 05 06 07 03 02 
05 04 04 05 05 06 07 03 03 
06 05 05 05 06 07 09 04 03 
07 06 06 06 06 07 0A 06 05

Boss Battle

Boss-battle mode shares the main loop with the normal mode. Once the player kills all small enemies in the map in which a boss or two exist, the player cannot get out of the map until all the bosses are killed. The conditions for a boss to appear are for all small enemies to be killed and no more items to exist in the map.

The boss number (2 bosses per map maximum) is written in <$2E. If bit 7 of <$2E is 1, the player cannot get out of the map until all the bosses are killed. If small enemies are still alive, but a boss exists in the map, <$2E is 1. The player can get out of the map, but cannot enter stairs.

Following addresses are controlling <$2E.

0F61 LDA #$80   STA <$2E               Take all items->cannot escape boss fight.

0FDF LDA #$81   STA <$2E               When boss appears, $80->$81

106B LDA #$01   STA <$32    STA <$2E   Can escape the boss but cannot use the stairs.

11D5 LDA #$82   STA <$2E               Looks like the second boss.

11FE CLRA       STA <$2E    STA <$32   <$32 and <$2E works together? Couldn't find the meaning of<$32 yet.

Boss-generation routine is from $0F69.

   0F69 96 2E          LDA   <$2E
   0F6B 10 2A 01 19    LBPL  $1088      <- Skip if no boss exists.
   0F6F 81 80          CMPA  #$80
   0F71 10 22 00 6E    LBHI  $0FE3      <- Already in the boss-battle mode?
   0F75 96 23          LDA   <$23
   0F77 9B 2B          ADDA  <$2B
   0F79 9B 52          ADDA  <$52
  >0F7B 10 26 FC 66    LBNE  $0BE5      <- The boss won't materialize if the sum of <$23, <$2B, <$52 is non zero
                                           Meaning not identified yet
   0F7F F6 32 99       LDB   $3299      <- Boss ID
                                           0: Mint
                                           1: Green brain
                                           2: Silver brain
                                           3: Sunny side up
                                           4: Canteen
                                           5: Robot
                                           6: Octopus
                                           7: Pierrot (or Clown)
                                           8: Lady bug
                                           9: Pierrot (or Clown)
                                           A: Pierrot (as Last Boss)
   0F82 D7 13          STB   <$13

These names are my own; I don’t know the official names. What is interesting is that you can control which boss appears by stopping XM7 at $0F82 and modifying the value of B register.

The graphics corrupted when I set B=$0B. Also, the length of the boss table is 11. I believe there are no more than 11 kinds of bosses in total. There are two Pierrot types, aside from the last boss. One may be unused. Or perhaps both are used and I simply could not identify which was which.

Boss properties looks to be described in two tables below. I haven’t yet figured out the meanings of the tables.

$30CF
0 1F 01 16 
1 20 07 16 
2 21 0D 16 
3 43 02 24 
4 45 06 16 
5 46 0C 24 
6 48 10 24 
7 4B 04 16 
8 4D 0A 24 
9 4B 04 16 
A 14 03 16

$30F0
0 3C 0B 
1 46 1B 
2 64 1B 
3 78 05 
4 96 0F 
5 AA 05 
6 BE 05 
7 C8 0F
8 BE 05 
9 D2 1B 
A E6 1F

*Game images belong to the original copyright holder.

NPO Game Preservation SocietyNPO Game Preservation Society
Author: Sōji YAMAKAWA(Supporter Member)
Home Page: http://www.ysflight.com