Metrocenter '84 - Inform 6 optimized for 8-bit targets

Inform 6 is amazing but the problem is that in its current form, targeting 8-bit systems and / or the interpreters from Infocom is not possible. Neither does the current compiler version support properly targeting Z3, nor does the library come with the lightness it would need to run performant enough for a satisfying gaming experience on a retro system.

We had the desire to release a contemporary Inform 6 distribution, that focuses on targeting classic computer systems, such as the Commodore 64, the Amstrad CPC or the Atari 8-bit on one hand, while on the other hand retains the typical Inform experience. RetroInform had been released on Saturday. It consists of a forked version of the Inform 6.15 compiler and Metrocenter '84, a library based on mInform.

There is a changelog that keeps track of the path taken since forking mInform. We focused on backporting useful routines and fixing bugs but also added completely new features, such as (optionally) disabling inference or metro_scenery where @fredrik kindly contributed a large chunk of code to it. While the library is still much work in progress (we adapt changes as we need them in the course of developing Hibernated 2), it is usable and stable, so we thought we rather put it out in the wild now and just push new versions as they are created.

There are some convenient features, such as a command line wrapper that triggers compiling to Z-code and dumps an Atari 8-bit disk image in addition, so you can instantly test your code on a proper home computer. But it’s necessary to mention that we only worked actively on the library and the demo files, the rest is pretty much a collection of gathered tools and patches that we now brought to a central virtual haven.

Grab it from here: RetroInform | Metrocenter `84

Extra dose of motivation: if you have written an Infocom style adventure game and you have the desire to share it with the retro community, get in touch with me. After the massive success of my games Hibernated and Rabenstein, my publisher is searching for more interactive fiction to release. You’re not getting rich with it but the retro community is more vibrant than ever these days. It’s a massive target audience and it is wonderful when your games get physical. Examples: Hibernated and The Curse of Rabenstein. Note that Hibernated 2 will be my first Z-machine game and way more sophisticated than the previous efforts, which can be compared to classic adventures released in Europe mid-80s. They were created with DAAD.

We also have new interpreters for Commodore 8-bit machines: C64, C128, VIC-20, Plus/4 and PET available. But these will be released at a later date. Teaser pictures (Commodore 64 and VIC-20) below. Anyway, keep those retro games coming. Imagine worlds!

9 Likes

(girlfriend meme with ZIL in the background)

3 Likes

What are the differences between Inform 6.15 and 6.3x that benefit you for this goal?

(I’m not saying it was a bad decision – I really don’t remember the differences and I’m curious.)

2 Likes

The problem is that all versions of the compiler after 6.15 are not able to properly target Z3 anymore. In fact I don’t get Z3 compiling at all with these. The << x y z >> problem has recently been fixed, which is a good start. I’ve seen the pull request being merged today. I discussed that particular issue with @fredrik, who was the person who found it, and I wasn’t aware of it so we made the comparsion to 6.15 where I confirmed said bug absent. Let me see… what else… At least five Veneer routines are not compatible with Z3, using opcodes for example that are not available in Z3. I tried to compile Cloak of Darkness with Inform 6.34 freshly grabbed from Github and the result can be seen on the picture below

Where 6.15 just works. It’s a shame that we cannot build upon a later compiler version but I have no idea what issues else may be hiding under the surface. There likely are more. And it is pretty much understandable. I talked with @fredrik about that matter the other day. Z3 was not high on the priority list. You can look at how many Z3 games were released per year while Inform had full support for Z3. Close to zero. Now the times have changed though. A vibrant retro community has emerged, obsolete systems find their way again into man-caves and publishers release new games for these. 8-bit made a strong comeback and the community is lounging for new Infocom style adventures they can play on real hardware. And out of a sudden, Z3 does matter again, as strange as this may be :slight_smile:

2 Likes

Another important thing to mention (which I forgot): for some weird reason 6.15 creates much smaller Z-code files, which is not trivial in a constrained environment. When I compile Cloak of Darkness (to Z5) with 6.34 it results in 32244 bytes used in Z-machine. 6.15 produces a Z5 file that has 21968 bytes used in Z-machine. That makes one wonder what makes the file 10k(!) bigger when only a different compiler version is used. Both files attached as a reference. Both notably work.

cloak_615.z5 (21.5 KB) cloak_634.z5 (31.5 KB)

1 Like

It’s not “some weird reason”, it’s that you haven’t asked the reason. :) I think this difference boils down to Inform’s “strict mode”, which is the default in the current compiler. Try compiling with the -~S flag (dash tilde S) and see how much of the size difference goes away.

True, but you haven’t removed those veneer routines from your Inform compiler, have you? When you compile with an older library, those veneer routines aren’t a problem because they’re never invoked.

If you try a head-to-head comparison – compiling cloak.inf with your metro84 library – Inform 6.34 only generates one error when compiling v3:

“<veneer routine ‘RV__Pr’>”, line 1: Error: A function may be called with at most 3 arguments

Please file this as a bug report and we can get I634 back to generating v3 games.

It may not generate small v3 games, even with the -~S switch, but we can restore the basic capability.

6 Likes

That’s a Z-Machine limit, there’s no 8-operand call opcodes in v3. It could be worked around with some global variables (or an array) though.

Given the Z-machine limits on globals, I like the idea of using an array (or the stack) better, but I don’t see any way to accomplish this without extra veneer both at the call site and at the head of every function. Does I6 currently have any veneer around routine calls?

No, no, it’s not that big a deal. We just need to adjust the RV__Pr() veneer routine to do something different when compiling for z3.

1 Like

In the case of RV__PR it’s just calling RT__Err, so a less detailed error message should be an acceptable tradeoff.

A feature to handle more arguments could be worth considering, but it can also just be done manually if it’s really needed. A shame that there’s no macros in Inform, it’d probably help with something like this.

1 Like

Right, that’s what I was thinking. Easy fix if anyone thinks it’s worthwhile.

2 Likes

Good point, thanks. I will file this as a bug report. BTW: these are the routines in Veneer that cause issues when targeting Z3. Reported to me by @fredrik, who encountered these issues while working on PunyInform.

FindIndivPropValue - not sure why.

RV__Pr - as seen in my compilation screenshot in this thread

CA__Pr - This routine can take up to 7 arguments, but a routine call can only have 0 to 3 arguments in z3, so it can’t really do everything it’s supposed to do in z3. Also, it uses the instruction @check_arg_count to see how many arguments it was called with. This instruction doesn’t exist in z3, and there is actually no way of doing that in z3. Among other things, this routine handles create, destroy etc for classes, and we decided to not support those operations for z3 since there was no obvious way of doing it. This routine also supports sending generic messages to objects with up to five arguments. For z3, this is reduced to one argument. The routine could be rewritten to not allow for 2+ arguments in z3 mode.

Cl__Ms - this routine is also built for more arguments than z3 can handle. In any case, it’s only used by CA__Pr

Regarding compilation using -~S flag: I confirm that this changed the size of the resulting Z-code significantly. There is still a difference though. 6.34 with ~S flag being set resulted in 23672 bytes used in Z-machine. Using 6.15 resulted in 21968 bytes used in Z-machine. So that’s still 1.7k difference but it is definitely something one could live with, provided that the gap between old compiler and new compiler stays the same no matter how big the game is, as Cloak of Darkness is tiny in code compared to the usual things you do with the Z-machine.

2 Likes

BTW: these are the routines in Veneer that cause issues when targeting Z3.

Most of these are irrelevant, because they are only used when strict mode (-S) is on. z3 defaults to non-strict (-~S) so they are never compiled in.

I’ve submitted a simple fix (https://github.com/DavidKinder/Inform6/pull/21) which allows the current I6 to compile a z3 game using the metro84 library.

The result is still 1694 bytes larger than using your I615 compiler. The difference is mostly extra code in veneer routines. RT__Err() is larger due to extra error messages which can never be reached in z3; there’s a new Print__PName() routine; Z__Region() has an extra couple of lines. There’s also a few extra instructions in compiled code due to fiddly changes that went in when strict mode was implemented. (Even though it’s not used in z3.)

If you suppress run-time error messages entirely by including the line

[ RT__Err; ];

in your source, then the difference between Inform 6.34 and 6.15 drops to 244 bytes.

5 Likes

now with another simple fix (ifdef V3 around RT_err) current inform can again compile .z3 story files. Kudos !

Best regards from Italy,
dott. Piergiorgio.

Wow, that’s fantastic! Thank you so much for your support Andrew! I will push a new release that defaults to the current compiler once this has been merged into master.

I’ve tested your changes this morning by compiling the game I’m currently developing. It has around 35 rooms and the difference upon compilation between 6.15 and 6.34 was 462 bytes. That’s more than the 244 bytes with Cloak, but that’s a sacrifice one definitely can make for the sake of working with the current compiler generation, where lots of work (and bugfixes) made its way into the codebase.

2 Likes

Metrocenter '84 v1.1 is out! It uses the current Inform compiler v6.34 (or newer versions). The 6.15 fork has been removed from the repo as it is obsolete now.

https://github.com/ByteProject/Metrocenter84

Thanks to the one and only @zarf for the bugfixes making the compiler properly target Z-machine v3 again, also for the static array feature, which is highly benefitial on 8-bit machines.

Inheritance of RT_Err is disabled by default, you may enable it with Constant ENABLE_INFORM_RT_ERR.

5 Likes

You might want to consider having at least a minimal RT_Err that (say) prints “Something went wrong” so that you at least know there is some error to investigate.

When RT_Err inheritance is disabled, the library provides its own, minimal set of runtime error cases. Sorry for the confusion David, I only stated this in the wiki and not in my announcement.

2 Likes

Very good news. I have an operational C64. It will be interesting to write IF that will work on one of the most common retro platforms.

fos1

3 Likes

I just installed v1.1 on my RPi 4. I have I6 installed for “standard” I6 development.

I had installed the previous Metrocenter 84. The command inform compiled with I6 6.15. inform6 compiles with version 6.33.

I downloaded the latest I6 compiler source into “src” as indicated in the readme.md

make and make install ran without error.

However, the command inform still compiles with 6.15. (inform6 still compiles with 6.33)

Have the github repositories been updated to the latest version? Github indicates that both repositories were updated 5 hours ago.

Thank you,
v/r
Jeff