Curses! - recreate this almost 30 year old piece of IF

Unfortunately the source to this historical important piece of IF is believed to be lost. This started me thinking that it would be a nice gesture to recreate the source in time for its birthday by decompiling the games z-file.

I started searching on the web and found that this was already done! Allen Garvin has recreated r7 and r16 to compile with Inform 6.31! His effort can be found here. Amazing! I’ve totally missed this.

Has anyone played this version, and how true to the original is it?

I still would love a revamped version of Curses!, preferably written in the new Inform 7 version, much like Anchorhead was revamped a couple of years ago. Unfortunately I’m not myself versed enough in Inform 7…


Cool! I’d had similar thoughts and have a non-released reverse-engineered version of r16 that I was planning to find time to tidy-up and offer to Graham, but I never got around to doing so.

Unlike the linked version it was targeting the library version the original was made with and almost the same compiler, which let me confirm the code produced exactly the same binary (other than the compiler version number) to ensure I didn’t accidentally introduce any new bugs as part of the reverse engineering.


Ok. I played it a bit. On the whole it’s a very faithful version but I’ve found some problems so far (guess I’ll start reporting them on GitHub). I’m about a third into the game.

  1. There are missing synonyms, like FIX, BOARD, HANG.
  2. The mouse maze have a different layout.
  3. There is something funny going on with the magic word. I can’t get LAGACH to work as expected.
  4. You can crash the status line (I think by entering a dark room without light).
  5. You can’t read the letter with the key to the symbols.

If you’re going to remake the game, it might be cool to consider extending or expanding it. And at least fix any bugs :slight_smile:

fix bugs: yes
extenting: no

1 Like

Ever since I found Dialog this year, I have been tentatively looking into porting Curses to it, and figuring things out on the way.

The Reform version is a bit easier to manage than the TXD one, which shows that I should have searched first :grinning:

Should I finish in this century, I would really appreciate anyone having a go at it, to see if it’s as close to the original (r16) as possible. I’m also not opposed to fixing bugs, but I’m not planning to add new content, sorry.


I’m in the process of identifying bugs and finding solutions to them. Currently there’s a couple of game breaking bugs but I now have the fixes for to make it playable all the way to the end (I havn’t reported back yet but I ultimately report it back as issues).

But… When I compile it with the latest Inform6 (6.41) it issues this warning that I want to remove:

.\rods.inf(73): Warning:  Logical expression has no side-effects
>                             j == false;

And I’m not sure exactly what this means. The code snippet look like this:

        parse_name [ i j w len cnt;
            if( parser_action == ##TheSame ) {
                if( parser_one has unidentifed_rod && parser_two has unidentifed_rod ) {
                    return -1;
                return -2;
            len = (self.#name)/2;

            for( w = NextWord() : w : w = NextWord() ) {
                j = false;
                for( i=0: i < len : i++ ) {
                    if( w == 'rods' ) {
                        parser_action = ##PluralFound;
						j = true; }		! r18
                    else if( w == self.&name-->i ) {
                        if( self hasnt unidentifed_rod && w == 'featureless' )
                            j == false;   ! <--- This is line 73
                            j = true;
                if( j == false )
                    return cnt;
            return cnt;

The only thing I can think of is that j already is false when this line is reached and that I should rewrite the logical expression for the case when to set j=true. Is this correct?

The problem that the compiler is trying to warn you about is that a line like “j == false;” compares j with false, then does nothing with the value. There’s no use of the evaluated value, and no side effects, so the whole statement achieves nothing.

This is almost certainly a typo for “j = false;”, which sets j to false.


Of course, now I see it…

Thanks for letting us know.

Since the Reform version makes my life easier compared to the txd output, I’m largely using it to port the game to Dialog, but I’ll be sure to subscribe so I’ll get notified of all the findings. Porting actually goes quicker than I thought, but I have to figure out lots of things that are more idiomatic. For example, the Inform version has a LOCATION >=123 condition in darkness, which is going to be tricky.

Speaking of 123, in the recreated version, in curses.inf:

if( location >= 123 ) 

should be:

if( location >= Dark_Shaft ) 

at least according to infodump.

This is a bit of a hack. The object number is depending on the order the objects are defined in the source and on the compiler which probaly byt not certainly assigns the object the same number and order between differnt compiler versions. I will rewrite the logic here to print the correct message depending on where you are when you stumble around in the dark.

Actually I don’t think this code is ever reached (a bug in the original, r16 version). Because when you are in the “Darkness” the game_section is set to that object and the “Darkness” object doesn’t have a section property. This will mean that whenever you stumble around in the dark you will always die with the first message - “death by bear”.

Yes, that’s one thing that I fixed in the Dialog version. The bear should only appear in non-modern times.

The original r16 bear-infested-attic bug is more complicated than that - you only get the bear part of the wrong DarkToDark behaviour if the “pretty” (two-line) status line has been redrawn (overwriting the global that tracks which zone of the game you’re in) since you first entered the darkness.

So, DROP TORCH. S. SE (as a single command) doesn’t trigger it. PLAIN, DROP TORCH, S, SE (as separate commands) doesn’t trigger it. DROP TORCH, S, SE does.

I guess it is because that the game_section variable only gets set when the statusline is redrawn. If you type it on one line, the statusline doesn’t get updated while your in the “darkness” therefore the message gets right.

Almost - the variable is also set (correctly, taking account of darkness) by NewRoom whenever the player moves room. I think the code in DrawStatusLine that changes the variable was never meant to. Based on the preceding condition, I think it was meant to be updating a (never updated!) variable that would have been used to track what section the player had been in last time the status line got redrawn to avoid unnecessary redrawing.

1 Like

I’m finally have a playable version of the reverse enginered code. I know and found a few bugs from the official release 16. Do anyone know of any additional bugs or a list of known bugs in Curses!?

List of bugs:

  1. The deamon for the ghost of Joshua Meldew stops when you give him something, not only when you give him the correct item. (Fixed).
  2. If you squeeze back up the chimney from the priests hole the text is missing a concluding CR. (Fixed).
  3. The wrong message is often printed if you move around in the dark in the attic or in the cellar. (Fixed).
  4. Even when the bomb is disarmed, the timer keeps on ticking until you leve the ruined castle. (Fixed).
  5. You can ask Old Evans multiple times for the mascot when he is hypnotized. (Fixed).
  6. The tight door in Servant’s Room can’t be closed once its been opened.

  7. The door to the coal bunker can’t be locked with the key you opened it with from the inside.

  8. The turn-counter starts at 1. (Fixed).

I’ve update the GitHub project with the issues I’ve found and suggested fixes.

1 Like

Thanks for all your work, it’s immensely helpful for creating the Dialog port, not to mention finally having the Inform source as well.

Any luck with the location check in curses.inf in darkness?

if( location >= Dark_Shaft )

Dark_shaft aka. 123.

Once I’m done with the port, I’m going to play through both versions to see if I can catch more bugs, if any.

It is a bit of a hack, but I think the order of the objects will remain the same as long you don’t move objects around in the source, or include the files in a different order. The object number is more likely to change, e.g. that would happen if the library creates another object in a new version.