Thanks all for the comments.
The main intention at the moment is to reverse engineer the various data structures used in the game (e.g. graphics, tile maps, strings, script actions, sprites, etc.) and to provide utilities to change these to make a new ROM. Ultimately, what I would like to create is a full game editor that will let you modify as much of the game as possible via a convenient UI. However, at the moment, things are in more of a proof-of-concept stage - many of the assets that I mentioned previously are compressed with custom routines, so new tools need to be developed in order to extract and re-compress these assets. Speaking of which, I have now added a new tool to extract/compress the tilemaps used to display 2D images (e.g. the Island Map or the game's title sequence). So we should be able to insert fully custom images in place of the originals now (the tile graphics and palette data formats have already been reverse engineered).
One of the nice things about having a disassembly is that this process is made a lot easier. One of the big challenges that can be faced when working with ROMs is how to re-insert new data into an existing ROM. This is very true with Landstalker, where there isn't a lot of free space on the 2MByte ROM - and what free space there is, is usually found in inconvenient locations. "Re-arranging" the ROM can be tricky - moving sections about can break pointers in existing code, and may not yield that much free space. The nice thing about having the disassembled code is that it gives you a lot more flexibility about how the ROM should be structured, thereby overcoming these issues. For instance, it should be possible to make a 4MByte+ ROM that still works without too much difficulty, which would allow users to create a lot more levels, etc. than existed in the original game.
A bonus of having the disassembly is that the game's code can also be expanded without having to worry about finding free space to insert opcodes in the ROM. It will require a certain amount of knowledge of 68k assembler, but, once relevant code sections have been identified, it shouldn't be too difficult to add new behaviour/functionality into the game. An example of this is the game's script. A big chunk of it is written in assembler - see file disassembly\code\script\characters\script_charactertable.asm - this is the code that is responsible for determining what lines each character says, or if any custom actions need to occur (such as the player receiving an item). It also handles the Yes/No prompts you sometimes get as well as setting of certain progress flags in order to move the game on. Having this data as an assembly file (with some custom macros to handle converting script indexes into the weird PC-relative offset format the ROM expects) makes modification a lot easier than just dealing with a block of data.
Of course, the game code could be used for more than this - e.g. as G061 suggested, knowledge of the game's code could be used to make a PC port. I believe a similar approach was taken with Sonic Mania - the code that handles the game physics was adapted from a disassembly of one of the original Sonic games IIRC. That is why the game physics in Mania is so similar to the originals.
June 07, 2020, 06:32:19 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
So, an update.
I've now fully reverse engineered the map compression algorithm. It is a bit of a nasty beast, using a combination of LZ77 using a fixed offset dictionary, RLE of LZ77 commands in the vertical and diagonal directions, and finally more RLE to encode the remaining tiles based off of a tile dictionary. Unfortunately, my version of the compression algorithm isn't as good as the original game's, with my compressed maps being about 6% larger than the originals. This discrepancy adds up to around 30kbytes once all the maps have been decompressed and recompressed (all 642 of them!).
This difference is too large to allow the maps to be nicely inserted back into the ROM without overwriting other data, so I have instead decided to expand the original ROM to 4 megabytes, which leaves a little more than 2MBytes of free space to use.
The nice thing is now it is possible to make your own maps for Landstalker:
This is a screenshot of my first attempt at making a map - I added the new house and changed the bear statue into a tree. So far, I have tested it in the emulator and on the real console without issue. Hopefully, this will lead on to being able to develop more complex maps once proper tools are available.
Making the maps is a bit tricky, as there are a few concepts you need to be aware of. Firstly, the viewable area is divided up into 16x16 "blocks" containing 4 tiles. These blocks are arranged in a staggered format: e.g. for a 3x2 map:
____| #0 |____
| #3 |____| #1 |____
|____| #4 |____| #2 |
|____| #5 |____|
This staggered arrangement is how the game handles the isometric effect. Blocks are defined in a separate data structure, based off of a combination of four tiles plus their attributes (priority, vertical-flip, horizontal-flip).
Secondly, there are in effect three tile layers. The first tile layer is the background - as the name suggests, the background is the layer behind all others. The foreground layer can be effectively split into two parts - background decoration and foreground.
Background decoration includes things like stones, signs, etc. They form an additional part of the background layer. Foreground includes all tiles that can appear in front of the player and other sprites - this is the layer that adds depth perception - i.e. you can be behind or in front of certain parts of the room.
The difference between decoration and foreground is whether the priority bit is set. This bit allows certain tiles to be drawn over sprites that do not have the priority bit set. Again, this is how it is possible for objects to appear in front of or behind objects.
Just to make things more confusing, the foreground layer is not directly on top of the background layer - it is actually shifted 16 pixels to the left. This means that blocks drawn in the foreground layer do not fully cover blocks drawn in the background layer - they will be either be 8 pixels above or 8 pixels below.
Finally, there is the heightmap. This is the data structure that determines what blocks are solid or not and at what height, and whether blocks have any special effects (spikes, etc). This layer is also used by the game to calculate whether a sprite should be behind or in front of the foreground.
At the moment, these three layers exist in their decompressed forms as csv files. Now that the hard work has been done in reverse engineering the decompression routines and coming up with suitable compression routines that work, we won't be too far away from having a full level editor available for Landstalker.