Craverly Heights in ZIL comparable to Inform 7 and Dialog

Craverly Heights (ZIL)

I’ve recreated this game, Craverly Heights, in ZIL for educational purposes (mostly my own…). @lft has done this before in Dialog and I have tried to stay true to the original disposition of the source code to make it possible to compare the original Inform 7 vs Dialog vs ZIL. The source is heavily annotated and I’ve tried to motivate my coding decisions but feel free to ask questions and report bugs.

The file obviously contains lot of spoilers so be sure to try the original game if you not already done that. There are seven different endings, try finding them all!

The game and its source code is here.

The original can be played online here.

The Inform 7 and Dialog source code are here.

There is also a thread about the Dialog version here.

There is also a podcast where the author with friends plays this game here (I used this for testing!).

One interesting fact is that the original Inform 7 z8-version is 258 kB, the Dialog z5-version 127 kB and this ZIL z5-version 48 kB. Now the game is so small that it fits on all 8-bit platforms!

8 Likes

I have checked in a new version. The changes are:

  1. Corrected a typo that sneaked in.
  2. @vaporware pointed out that you can define “out of world”-objects by don’t specifying a location. You can then MOVE them into the world or REMOVE them from the world. A effect of using this, instead of using the LOCAL-GLOBALS as I did before, is that <LOC [OBJ]> returns false if object is “out of world” and true if it is in the world.
  3. Use LOCAL-GLOBALS as it is intended by specifying the rooms this object should appear with the GLOBAL-property on each room.

I fixed another little bug. When you (as Sid):

> point gun at me then shoot
The wrong message was printed because WINNER was set a CURRENT-TARGET.

I also tried compiling a C64-package with Ozmoo Online to test if my replacement-code for unicode-characters worked. And it worked.

2 Likes

If you build it with a Swedish font+charset, you’ll get Åsman printed correctly as well.

Lol! I even didn’t see that. I was so focused on the “em dash”.

1 Like

Fixed two new bugs:

  1. GIVE didn’t work correctly as a synonym for SHOW.
  2. The other one is a little obscure but I wanted the parser to recognize commands like GET ALL ON TABLE. The required a change to the parser to exclude objects that initially ended up in ALL but no longer are eligable for TAKE with the new scope. The solution is tailored to this game that only contains surfaces (no containers) and not yet general enough for a permanent library change.

At the moment I have one outstanding “bug” (not really a bug). Consider this:

SHOW has two syntax-definitions.

<SYNTAX SHOW OBJECT (TAKE HAVE HELD CARRIED) TO OBJECT (FIND PERSONBIT) = V-SSHOW>
<SYNTAX SHOW OBJECT (FIND PERSONBIT) OBJECT (TAKE HAVE HELD CARRIED) = V-SHOW>

This leads to this exchange:

> show gun to pauline
"Why would a doctor need a gun?" Pauline asks, her eyes clouded with innocence.

"That's a good question, Pauline. But I can't tell you," you say. And then you add: "Yet."

> show pauline gun
"Why would a doctor need a gun?" Pauline asks, her eyes clouded with innocence.

"That's a good question, Pauline. But I can't tell you," you say. And then you add: "Yet."

> show gun
[to Pauline]
"Why would a doctor need a gun?" Pauline asks, her eyes clouded with innocence.

"That's a good question, Pauline. But I can't tell you," you say. And then you add: "Yet."

> show pauline
You aren't holding Pauline.

> 

The first three are correct but I would like the last one to ask “What do you want to show Pauline?”.

What happens is that when the parser decides wich syntax-definition that gives the best match it picks the first one because it gives priority to the match that have a preposition.

What I would like to happen would beto reduce the score for the first one because the noun doesn’t meet the requirements in the hints (HAVE HELD CARRIED). But because the matching of the syntax is called before the nouns are mapped to objects. This becomes a catch 22.

This is pretty obscure and not a big problem (even the old Infocom had this “problem” - I tried it in Trinity) so it is most certainly not worth the trouble but if anyone have a idea for a solution, I’m interested.

Your ZIL version inspired me to make a PunyInform port. See Craverly Heights in PunyInform

2 Likes

Yeaah! I saw that. That’s fantastic! I’m trying it out just now.

I’m gonna add a link to Puny from the ZIL source.

thanks!

And maybe when @lft is finished with building crazy party telephones, he can link both of our projects.

4 Likes

Inspired by the PunyInform version I tried compiling this as a z3-file.

This generated, as expected, a few errors. They fall in a couple of categories that shouldn’t be to hard to fix with compiler options.

  • CHECKU isn’t supported until z5 (2 errors).
  • INPUT isn’t supported until z4. So no “Press any key to continue” (7 errors).
  • You can’t make your own statusline in z3 (3 errors).
  • Bold font isn’t supported in z3 (2 errors).
  • To many synonyms for a couple of objects (5 errors).

Not to bad!

ZILF 0.9 built 2019-08-11 13:30:42
[error ZIL0405] craverlyheights_zil.zil:132: CHECKU is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1383: INPUT is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1398: CHECKU is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1403: INPUT is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1688: INPUT is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1698: INPUT is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1808: INPUT is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1831: INPUT is not supported in this Z-machine version
[error ZIL0405] craverlyheights_zil.zil:1855: INPUT is not supported in this Z-machine version
[error ZIL0207] craverlyheights_zil.zil:2141: undefined global or constant: H-INVERSE
[error ZIL0122] craverlyheights_zil.zil:2142: unrecognized routine or instruction: FAKE-ERASE
[error ZIL0207] craverlyheights_zil.zil:2147: undefined global or constant: H-NORMAL
[error ZIL0103] craverlyheights_zil.zil:2156: bare atom 'H-BOLD' used as operand is not a global variable
[error ZIL0103] craverlyheights_zil.zil:2158: bare atom 'H-NORMAL' used as operand is not a global variable
[error ZIL0301] craverlyheights_zil.zil:315: property 'SYNONYM' is too long (max 8 bytes)
[error ZIL0301] craverlyheights_zil.zil:1216: property 'SYNONYM' is too long (max 8 bytes)
[error ZIL0301] craverlyheights_zil.zil:1254: property 'SYNONYM' is too long (max 8 bytes)
[error ZIL0301] craverlyheights_zil.zil:1279: property 'SYNONYM' is too long (max 8 bytes)
[error ZIL0301] craverlyheights_zil.zil:1572: property 'SYNONYM' is too long (max 8 bytes)
19 errors
2 Likes

Yes, that’s the same problem I found. In PunyInform I can use parse_name to work around the synonym limitation, and use sread instead of aread for input, but the other items can’t be supported so they are dropped when the source is compiled as z3.

1 Like

I’ve modified the file slightly so it can compile to z3, z4, z5 & z8.

In z3 there’s some trade-offs:

  • Fewer synonyms for a couple of objects.
  • No bold or italic text.
  • No unicode characters.
  • The statusline is hardwired to either “score/moves” or “time”. I opted for “time”, it’s a daytime TV-show after all…

The recommended target format is still z5.

I also used better abbreviations and “optimal parse” to see how much it saved. The files now is:

z3  46.852 bytes
z4  48.572 bytes
z5  47.464 bytes
z8  48.248 bytes

(links in first post above.)

2 Likes

I agree that using time is better. I changed the PunyInform version to use it as well (for z3)

Some statistics on the z5-file:

Size without abbreviations        55.832 bytes
     Text size (characters)       41.688 bytes
     Text size (z-chars)          26.055 bytes (62.5% of size in characters, 46.7% of z5-file size)
     Size Z-code                  29.777 bytes (53.3% of z5-file size)
Size with abbreviations           47.464 bytes
     Text size (z-chars + abbrev) 17.687 bytes (42.4% of size in characters, 37.3% of z5-file size)
     Size Z-code                  29.777 bytes (62.7% of z5-file size)
1 Like

Where did you get the number 17687 bytes? It seems unreasonably low, as in about 6 KB too low.

I used your number for characters (41.688) because the text should be identical with the Puny version. This would mean that the text uses about 41.688 * 5 / 8 bytes in memory (26.055). This would mean that the size of everything else should be 55.832 - 26.055 = 29.777 bytes. When I apply abbreviations the size of the file is reduced by 8.368 bytes. The abbreviations only affects the text, so 26.055 - 8.368 = 17.687 bytes.

I agree that it seems a bit low but I don’t see where I miscalculated.

I can see some flaws in this:

  • Since the number of characters also includes all library responses, it won’t be the same for a ZIL game as for a PunyInform game.

  • Not all characters use up 5 bits. Some use 10, 15 or even 20 bits.

  • The string storage algorithm uses one bit per word to say if this is the final word of data for this string.

  • About 2/3 of all strings have wasted space in the final word, e.g. the string “a” takes up 16 bits, and so do “ab” and “abc”.

  • High strings waste an average of 1.5 bytes due to alignment in z5 files.

The text of the PunyInform version, compiled as z5, without abbreviations, takes up 31554 bytes, as reported by the compiler. This number actually includes the abbreviations that were declared in the source, despite the fact that we’re not using them. I’m not sure if it includes the waste due to alignment. Anyway, it’s about 5 KB more than the number you reached by multiplying the number of characters by 5/8.