How to bring
ZILCH back to life again.
Since I was a teenager, I wanted to know the internal secrets of Infocom adventures and the software and hardware systems used to build them. (My fascination was only the slowed down by the language. I had to learn English first.)
Best known are the articles
- Lebling, Blank and Anderson, "Special Feature Zork: A Computerized Fantasy Simulation Game", in Computer, vol. 12, no. 4, pp. 51-59, April 1979, doi: 10.1109/MC.1979.1658697.
- Marc S. Blank und S. W. Galley, "How to Fit a Large Program Into a Small Machine or How to fit the Great Underground Empire on your desk-top" in Creative Computing, vol 6 no 7, pp. 80-88, July 1980, and
- P. David Lebling, "Zork and the Future of Computerized Fantasy Simulations" BYTE Magazine, pp. 172-182 December 1980.
And then there is "Down From the Top of Its Game - The Story of Infocom, Inc."
Much was written, but the exact workings of the tools used, remained vague and for many years it was thought the tools Infocom used to create their legendary interactive fiction works was lost forever.
Then 2008 Andy Baio made public details (What a lose!) from the legendary Infocom Drive. An anonymous source close to the company gave him a complete backup of Infocom's shared network drive from 1989.
At PAX East 2010 someone "lost" some USB Drives, which - after some puzzle solving - revealed interesting internal Infocom development documents:
|Vocabulary and syntax compaction||compact.txt|
|What should (or may) be in your
|WRITER'S GUIDELINES FOR ZIL||guidelines.text|
|About "support in ZILCH for shared code libraries"||libraries.txt|
|Accessing low core locations||lowcore.txt|
|New xzip instructions ... required for multi-player games||multi-player.txt|
|"EXTENDED ZIPTEST" [of Multiplayer Functionality]||multi-player.zil|
|INTERLOGIC WRITER'S GUIDELINES||newguide.mss|
|EZIP: Z-language Interpreter Program (Expanded)||spec-ezip.fwf|
|ZAP: Z-language Assembly Program||spec-zap.fwf|
|ZIP: Z-language Interpreter Program||spec-zip.rno|
|ZIP: Z-language Interpreter Program||xzip.txt|
|YZIP is ZIP version 6||yzip.txt|
|The Zork Implementation Language||zil.doc|
|Changes to ZILCH||zilch.new|
In addition Learning ZIL or Everything You Always Wanted to Know About Writing Interactive Fiction But Couldn't Find Anyone Still Working Here to Ask by Steven Eric Meretzky could be found on the Internet Archive for quite some time.
At the Game Developers Conference 2014 Dave Lebling gave a talk with the title "Classic Game Postmortem: Zork" where near minute 24 he shows some interesting slides, the first one reveals the names of the tools used and the machines the tool chain was running at:
The second one shows a code snippet which illustrates the
translation process from
ZAP accomplished by
ZIL Compiler. The slide compares the
in source and compiled form. This was the first time I saw a direct comparison
The third slide shows the difference between Muddle code used in the original mainframe Muddle Zork and the ZIL Zork objects.
I was especially interested in the source code of
Zork II packed in
because the archive contains the complete compiled
ZAP files as well.
Jesse McGrew created the
open source ZIL Compiler ZILF many
years ago, so we don't need
ZILCH for creating new interactive fiction
stories. Nevertheless my motivation is to bring back to life the really lost
masterpieces of Infocom, first of all
Apr 30, 2019 Lars Brinkhoff made a single commit to the https://github.com/PDP-10/zil GitHub repository. Lars Brinkhoff is the researcher who helped identifying and extracting the original Muddle Zork files from the MIT Tapes of Tech Square (ToTS) collection.
Here are the contents of the https://github.com/PDP-10/zil repository:
<ZORK.Z>APPLY.MUD.1 Mar 5 1981 <ZORK.Z>GETSTR.MUD.2 Nov 5 1979 <ZORK.Z>IBYTES.MUD.2 Oct 26 1979 <ZORK.Z>ZAC.MUD.18 Nov 13 1979 <ZORK.Z>ZAP.MUD.171 Jan 18 1980 <ZORK.Z>ZIL.MUD.176 Oct 29 1980 <ZORK.Z>ZILCH.MUD.188 Nov 3 1980 <ZORK.Z>ZIP.MUD.96 Dec 15 1979 <ZORK.Z>ZIPOUT.MUD.2 Feb 29 1980 <ZORK.Z>ZIPUTIL.MUD.3 Dec 15 1979 <ZORK.Z>ZOPS.MUD.18 Jan 17 1980 <ZORK.Z>ZSTR.MUD.2 Sep 3 1979 <ZORK.ZFTP>ZFTP.MUD.12 Jun 7 1980
So I can safely say that April 2019 was one of the most exciting months of my life.
Sep 01, 2020 I asked him on the IRC channel #pdp-10 on freenode
<ZoBoRf> larsb: Where did the files in https://github.com/PDP-10/zil originally come from? <larsb> I think from the Infocom drive. <larsb> No, that's not right. <larsb> That's from a MIT TOPS-20 machine. <larsb> It's from ToTS, same as the ITS files. <larsb> I like the ring of that, "ITS files". <larsb> The truth is out there! <ZoBoRf> larsb: I wanted say something about the origin of the files in my zilch writeup. <ZoBoRf> But as I see it is better to be fuzzy about the truth? May I quote your info verbatim? <larsb> I don't think it's a secret it's from ToTS. <larsb> Yes, you may quote me or rewrite the text as you like <larsb> We had help from "Mr X" who helped get the files. I believe CSAIL was aware what was going on. Even a senior professor helped me get one particular file. <larsb> http://people.csail.mit.edu/devon/archive/ <larsb> There's some public information.
Distant Goal: Literate Version of ZILCH: The Program
Now, that I know there is a
ZILCH compiler available,
my idea is to document it in a literate programming style,
introduced by Donald E. Knuth
in which a computer program is given an explanation of its
logic in a natural language,
such as English, interspersed with snippets of macros and
traditional source code, from which compilable source
code can be generated. Knuth used literate programming to write
and document his famous typesetting program TeX still in wide use today.
I'm going to do that with Nuweb
which I made some small changes to.
But before I do something like this, I should be sure that the work is not in vain.
The best is to let the compiler translate some code
and compare the code with some code we know is generated by
ZILCH compiler in the eighties.
To do this I take the
Zork II sources mentioned above
and unpack them:
| File Name | Size | | -------------- | ------- | | actions.cmp | 1576 | | actions.zap | 103567 | | actions.zil | 120560 | | clock.zap | 1042 | | clock.zil | 1618 | | crufty.xzap | 495 | | crufty.zil | 635 | | demons.zap | 1128 | | demons.zil | 1303 | | dungeon.cmp | 1300 | | dungeon.zap | 8 | | dungeon.zil | 69088 | | macros.zap | 220 | | macros.zil | 2324 | | main.zap | 3185 | | main.zil | 3918 | | parser.zap | 21007 | | parser.zil | 29701 | | syntax.zap | 8 | | syntax.zil | 14584 | | verbs.zap | 39896 | | verbs.zil | 45454 | | zork2.errors | 585 | | zork2.xzap | 294 | | zork2.zap | 273 | | zork2.zil | 915 | | zork2dat.zap | 180229 | | zork2freq.xzap | 3908 | | zork2str.zap | 36686 | | -------------- | ------- | | Bytes | 685507 | | Files | 29 |
All we have to do is to let
ZILCH compile the
and check the generated
ZAP files against the given ones.
Let me group and rearrange the files:
zork2.errors zork2.zil zork2.zap zork2.xzap zork2freq.xzap zork2dat.zap dungeon.zil dungeon.zap syntax.zil syntax.zap macros.zil macros.zap clock.zil clock.zap main.zil main.zap parser.zil parser.zap demons.zil demons.zap crufty.zil crufty.xzap verbs.zil verbs.zap actions.zil actions.zap zork2str.zap actions.cmp dungeon.cmp
zork2.errorsis the transcript of the
Assembling ZORK2.XZAP.10 Inserting ZORK2FREQ.XZAP.5 ( 616 bytes) Inserting ZORK2DAT.ZAP.1 (17170 bytes) Inserting DUNGEON.ZAP.1 ( 0 bytes) Inserting SYNTAX.ZAP.1 ( 0 bytes) Inserting MACROS.ZAP.1 ( 42 bytes) Inserting CLOCK.ZAP.1 ( 197 bytes) Inserting MAIN.ZAP.1 ( 628 bytes) Inserting PARSER.ZAP.1 ( 4076 bytes) Inserting DEMONS.ZAP.1 ( 277 bytes) Inserting CRUFTY.XZAP.7 ( 89 bytes) Inserting VERBS.ZAP.1 ( 9969 bytes) Inserting ACTIONS.ZAP.1 (32301 bytes) Inserting ZORK2STR.ZAP.1 (17699 bytes) 17850 bytes of preload. 83128 bytes (82K). 244 objects. 147 globals.
XZAP assembles the
zork2.xzap file (version 10).
The given size 83128 equals 64 bytes header plus the sum of 616, 17170, up to 17699 bytes.
The filenames are in
TOPS-20 naming convention (see CHAPTER 4, "FILE SPECIFICATIONS" of the TOPS-20 User's Guide).
In my GitHub repository
MEM2TeX are PDF versions of the TOPS-20 User's Guide
and TOPS-20 Commands Reference Manual.
When we look into
zork2.xzap we can see
it just includes all the other
.INSERT "ZORK2FREQ" .INSERT "ZORK2DAT" ; DATA IS IN THIS FILE .INSERT "DUNGEON" .INSERT "SYNTAX" .INSERT "MACROS" .INSERT "CLOCK" .INSERT "MAIN" .INSERT "PARSER" .INSERT "DEMONS" .INSERT "CRUFTY" .INSERT "VERBS" .INSERT "ACTIONS" .INSERT "ZORK2STR" .END
zork2.zap the only difference to
the missing first line:
The frequent words file defines the word frequency table with the 96 most common words:
.FSTR FSTR?1,"the " ;1642 821 .FSTR FSTR?2,"The " ;1122 374 .FSTR FSTR?3,"You " ;573 191 .FSTR FSTR?4,"and " ;548 274 .FSTR FSTR?5,"There " ;545 109 .FSTR FSTR?6,", " ;498 498 ... .FSTR FSTR?51,"balloon " ;84 14 .FSTR FSTR?52,"Frobozz " ;84 12 .FSTR FSTR?53,"I " ;83 83 .FSTR FSTR?54,"it " ;80 80 ... .FSTR FSTR?92,"Nothing " ;63 9 .FSTR FSTR?93,"as " ;60 60 .FSTR FSTR?94,"south " ;60 15 .FSTR FSTR?95,"wooden " ;60 12 .FSTR FSTR?96,"narrow " ;60 12 ;word frequency table of 96 most common words WORDS:: .TABLE FSTR?1 FSTR?2 FSTR?3 ... FSTR?94 FSTR?95 FSTR?96 .ENDT .ENDI
In ZAP: Z-language Assembly Program
Joel M. Berez explains in section 3.3 "String Handling Pseudo-ops" the
.FSTR <string> pseudo operation:
Generates a string for the frequently used word table (
FWORDS). First does a
.STR <string>, except that
<string>is not searched for fword substrings. Then adds the string to the table of fword substrings. All
.FSTRs should be in the 32-word table following
The difference to our table is the name is
it's size was extended to 96 words.
Later we will see, how
ZILCH is called to compile
zork2.zil identifies itself with
<PRINC "Loader/ ZORK II: The Wizard of Frobozz ">
as the loader of the other files the story consists of.
It defines the
IFILE which includes
and compiles the given file and creates the corresponding
ZAP file, and calls
IFILE for each
ZIL file to include.
"ZORK2 for Zork: The Wizard of Frobozz The Great Underground Empire (Part 2) (c) Copyright 1981 Infocom, Inc. All Rights Reserved. " ... <OR <GASSIGNED? INSERT-CRUFTY> <DEFINE INSERT-CRUFTY (STR) <IFILE .STR T>>> <DEFINE IFILE (STR "OPTIONAL" (FLOAD? <>) "AUX" (TIM <TIME>)) <INSERT-FILE .STR .FLOAD?>> ... <IFILE "DUNGEON" T> <PROPDEF SIZE 5> <PROPDEF CAPACITY 0> <PROPDEF VALUE 0> <IFILE "SYNTAX" T> <ENDLOAD> <IFILE "MACROS" T> <IFILE "CLOCK" T> <IFILE "MAIN" T> <IFILE "PARSER" T> <IFILE "DEMONS" T> <INSERT-CRUFTY "CRUFTY"> <IFILE "VERBS" T> <IFILE "ACTIONS" T> ...
INSERT-CRUFTY is used to handle some files in a special way.
If it is not overwritten (re-defined) then it behaves as a normal
crufty.zil contains routines (
which should be compiled with the
extended (or debugged) version of
Later when we compare the given
crufty.xzap with the file
ZILCH generates we will see (so the hope) why.
To understand the
ZAP output one must understand, how
ZIL is translated
ZIL or the Zork Implementation Language is
implemented by the
ZILCH program written in
ZIL is documented in Learning ZIL (by Steven Eric Meretzky) and A "ZIL Course" by Marc S. Blank (October 1982). Muddle is documented in "The MDL Programming Language" by S. W. Galley and Greg Pfister.
Here is how Marc Blank describes "The Z System" in his ZIL Course:
At the highest level is Z Implementation Language (ZIL), which is an interpreted language running under MDL. Since ZIL is a MDL subsystem, all of the debugging features of MDL itself can be used in the creation and debugging of INTERLOGIC games. ZIL code is run through the ZIL Compiler (ZILCH) producing Z Assembly Language code which is, in turn, assembled by the Z Assembler Program (ZAP) into machine-independent Z-codes. These Z-codes can be run on any target machine which sports[sic!] a Z-machine emulator (ZIP).
ZIL defines on one side some structure building only forms, like
SYNTAX and on the other side the code creating
ROUTINE (look up the term
FORM in "The MDL Programming Language").
When we look at the following
we will only see data structure building forms.
The data structures appear as tables in the output.
The structures built and variables used are output
into the file
This is the reason why
syntax.zap only looks like this:
All the other
ZAP files contains the compiled
.FUNCT GO START:: ?FCN: CALL QUEUE,I-WIZARD,4 PUT STACK,0,1 CALL QUEUE,I-LANTERN,200 PUTP BALLOON,P?VTYPE,RAIRBIT PUTP BUCKET,P?VTYPE,RBUCKBIT PUTP SEWL,P?SIZE,P?EAST PUTP SWWL,P?SIZE,P?WEST PUTP SSWL,P?SIZE,P?SOUTH PUTP SNWL,P?SIZE,P?NORTH SET 'LIT,1 SET 'WINNER,ADVENTURER SET 'HERE,INSIDE-BARROW SET 'P-IT-LOC,HERE SET 'P-IT-OBJECT,0 FSET? HERE,TOUCHBIT /?CND1 CALL V-VERSION CRLF ?CND1: MOVE WINNER,HERE CALL V-LOOK CALL MAIN-LOOP JUMP ?FCN .FUNCT MAIN-LOOP,ICNT,OCNT,NUM,CNT,OBJ,TBL,V,PTBL,OBJ1,TMP,?TMP1 ?PRG1: SET 'CNT,0 SET 'OBJ,0 SET 'PTBL,1 CALL PARSER >P-WON ZERO? P-WON /?ELS5 ...
ZIP specification describing all Z machine instructions
is here: https://github.com/heasm66/YZIP-Specifications/blob/master/source/spec-yzip.pdf.
Henrik Åsman has a nice new PDF version here:
The two compare files
dungeon.cmp are not needed for
the compilation, but they allow a glimpse into the directory naming
and system used for the work on this story.
;COMPARISON OF SS:<ZORK2.R22MAC>ACTIONS.ZIL.524 AND SS:<ZORK2.R22MAC>ACTIONS.ZIL.526 ...
;COMPARISON OF SS:<ZORK2.R22MAC>DUNGEON.ZIL.297 AND SS:<ZORK2.R22MAC>DUNGEON.ZIL.299 ...
We can say the system used was probably
TOPS-20, the logical name was
and the files were in the directory
ZORK2 and subdirectory
Now we know which files we need feed
zork2.zil includes | +- dungeon.zil +- syntax.zil +- macros.zil +- clock.zil +- main.zil +- parser.zil +- demons.zil +- crufty.zil +- verbs.zil +- actions.zil
Muddle is needed
ZILCH we need a
Muddle interpreter or a
Unfortunately there is no running real Muddle on current platforms
(Linux, Mac, Windows).
A year ago I tried to run
ZILCH on top of
ZILF 0.8, the Zork Implementation Language of the Future with deactivated
ZILstuff to use the
Muddlepart only and also tried the
- 'Confusion', a MDL interpreter Matthew T. Russotto wrote to run the mainframe
Zork. Quoting from Matthew's description:
For those poor souls still stuck in dawn of IF history, I present "Confusion" -- a MDL interpreter which works just well enough to play the original Zork all the way through.
Unfortunately both interpreters have some incompatibilities so I got stuck.
PDP-10 is needed
To check the (in)compatibilities of some constructs between the interpreters I used the original mainframe Muddle, which appeared on my radar in the meantime.
The problem was this Muddle has no working
<SORT ... and
ZILCH uses it at
# grep -n SORT zilch.mud.188 430: <SORT ,L? .V 2> 901: <SORT <> .ZSTRS 1 0 .WORDS> 1276: <MAPF <> ,LIST-ATOM <SORT <> <REST .UVEC>>>> 1286: <MAPF <> ,LIST-ATOM <SORT <> .UVEC>>>
Muddle wants to load an external
which simply is not preserved.
:muddle MUDDLE 56 IN OPERATION. LISTENING-AT-LEVEL 1 PROCESS 1 <SORT <> [sort me now]>$ *ERROR* UNASSIGNED-VARIABLE SORTX GVAL LISTENING-AT-LEVEL 2 PROCESS 1
On summer holiday A.D. 2020 I wanted
to implement an own version of
<SORT ..., but the specification is
rather complicated (cf. section 184.108.40.206 SORT in "The MDL Programming Language" by S. W. Galley and Greg Pfister) and while scanning the current
repositories at https://github.com/PDP-10/muddle for additional clues
I found this: https://github.com/PDP-10/muddle/blob/master/mim/development/mim/vax/mimlib/sortx.mud
ITS Muddle 56 does not understand the
<PACKAGE ... concept,
so I deleted the corresponding lines and renamed the subroutine
<SORTEX ... and changed the calls to
<SORT ... in
It didn't work at first, so I took the opportunity to use one debugging
tool described in The MDL Programming Environment by P. David Lebling:
Section 3.6. "Execution Tracing".
After I found the implementation for
pprint.mud from an older
FLOADed the files in the file
z2.mud (the bootstrap file which calls
<FLOAD "PPRINT MUD"> <FLOAD "NSTRUC MUD"> <FLOAD "TRACE MUD"> ... <FLOAD "SORT MUD">
Then I activated the tracing for some constructs
<TRACE NTH> <TRACE SORTEX> <TRACE CHECKUP> <TRACE PRINC> <TRACE OPEN> <TRACE CLOSE>
and could so fix some problems in the stolen
Preparing Virtual Linux Host(s)
ITS runs on different
I chose the
klh10 because it has a more or less
FTP access into
FTP transfers are not very stable. Sometimes
I had to try several times to
GET a file.
I use to two Linux distibutions in a VMWare-Workstation.
Normally I work on
Ubuntu, but the
ITS build failed for me,
so I used
Debian to compile the emulators and build
and transferred the directory to
rob@ubuntu:~$ uname -a Linux ubuntu 5.3.0-64-generic #58-Ubuntu SMP Fri Jul 10 19:33:51 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux rob@ubuntu:~$ screenfetch ... OS: Ubuntu 19.10 eoan Kernel: x86_64 Linux 5.3.0-64-generic ... using for build pi@debbie:~/itsnew$ uname -a Linux debbie 3.16.0-10-amd64 #1 SMP Debian 3.16.70-1 (2019-07-22) x86_64 GNU/Linux pi@debbie:~/itsnew$ screenfetch ... OS: Debian 8.11 jessie Kernel: x86_64 Linux 3.16.0-10-amd64 ...
Cloning the ITS Repo
rob@debian:~$ cd ~rob rob@debian:~$ git clone https://github.com/PDP-10/its itsnew
Compiling the Emulator and Building
ITS from Source
rob@debian:~$ cd itsnew rob@debian:~/itsnew$ make EMULATOR=klh10 rob@debian:~/itsnew$ cd .. rob@debian:~$ tar czvf itsnew.tgz itsnew
itsnew.tgz to ubuntu.
rob@ubuntu:~$ tar zxvf itsnew.tgz rob@ubuntu:~$ cd itsnew rob@ubuntu:~/itsnew$ ./start
Starting and Stopping ITS
The Incompatible Timsharing System (
ITS) is idiosyncratic and it
takes time to getting used to it.
If you stumble over it in the docs:
ALTMODE key, means pressing the
This will be echoed as a
ITS, login and create a user folder.
KLH10 2.0l (MyITS) built Aug 29 2020 11:40:02 Copyright (c) 2002 Kenneth L. Harrenstien -- All Rights Reserved. This program comes "AS IS" with ABSOLUTELY NO WARRANTY. ... Emulated config: CPU: KS10 SYS: ITS Pager: ITS APRID: 4097 Memory: 512 pages of 1024 words (SHARED) Time interval: INTRP Base: OSGET Quantums: OSVIRT Interval default: 60Hz Internal clock: OSINT Other: CIRC JPC DEBUG PCCACHE CTYINT IMPINT EVHINT Devices: RH11 RPXX(DP) TM03 DZ11 CH11 LHDH(DPIMP) ... KLH10# KLH10# ; Define IMP for PI on ITS.JOSS.COM KLH10# devdef imp ub3 lhdh addr=767600 br=6 vec=250 ipaddr=192.168.1.100 gwaddr=192.168.0.45 KLH10# ... KLH10# [EOF on dskdmp.ini]
Here we type
KLH10# go Starting KN10 at loc 04000... DSKDMP
Now we can load and start
its $G Salvager 261 CRASH has no files, User File Directory DELETED [dpimp: ifc "tun0"] [dpimp: tun 192.168.1.32] [dpimp: GUEST 192.168.1.100] IT IS NOW 2:13:41 PM EDT, SATURDAY, AUG 29,2020 DB ITS 1650 IN OPERATION AT 14:13:41 DB ITS 1650 SYSTEM JOB USING THIS CONSOLE. LOGIN TARAKA 0 14:13:42 DB ITS.1650. DDT.1547. TTY 0 You're all alone, Fair share = 2% Welcome to ITS! For brief information, type ? For a list of colon commands, type :? and press Enter. For the full info system, type :INFO and Enter. Happy hacking!
CTRL-Z and login as
The system says:
DB: ROB; ROB MAIL - NON-EXISTENT DIRECTORY LOGIN ROB 0 14:14:03
I need an user directory, so I create one:
:print rob;..new. (udir) DSK: ROB; ..NEW. (UDIR) - FILE NOT FOUND DSK: DIR ROB CREATED BY ROB HACTRN 14:14:31
Now I set the terminal type and create a
ROB LOGIN file,
which will be executed at next login.
:tctyp aaa page=25 width=79 scroll :cwd rob :emacs rob login :tctyp aaa page=25 width=79 scroll ^X^S ^X^C ^F DB ROB FREE BLOCKS #0=13701 0 ROB LOGIN 1 ! 8/29/2020 14:15:26 *
Now logout and re-login:
$$u LOGOUT ROB 0 15:35:59 DB ITS 1650 SYSTEM JOB USING THIS CONSOLE. 15:35:59 ^Z DB ITS.1650. DDT.1547. TTY 0 You're all alone, Fair share = 1% Welcome to ITS! For brief information, type ? For a list of colon commands, type :? and press Enter. For the full info system, type :INFO and Enter. Happy hacking! rob$u :KILL *
Now shut down
*:lock LOCK.156 _5down DO YOU REALLY WANT THE SYSTEM TO GO DOWN? y ROB LOCK SYS DOWN MAIL WRITE 19:32:52 PLEASE ENTER A BRIEF MESSAGE TO USERS, ENDED BY ^C ^C CULPRIT = ROB LOCK 19:32:54 _ DB ITS going down in 5:00 q :KILL DB ITS going down in 4:55 *$$u DB ITS 1650 NOT IN OPERATION AT 19:33:11 PFTHMG DRAGON CHANNA _DRGN_ TIMES WRITE 19:33:11 PFTHMG DRAGON CHANNA LOGOUT TIMES DELRNM 19:33:11
And wait for
SHUTDOWN COMPLETE PI LEVEL 7 BUGDDT. TYPE <ALTMODE>P TO CONTINUE. YOU ARE NOW IN DDT. BUGPC/ CAIA COFFI4+1 $Q-2/ JRST COFFI7
CTRL-\ to get the emulator console.
BUGPC/ CAIA COFFI4+1 $Q-2/ JRST COFFI7 [HALTED: FE interrupt] KLH10> quit Are you sure you want to quit? [Confirm]y<ENTER> Shutting down...Bye! rob@ubuntu:~/itsnew$
OK, now we can start and stop
we are ready to create a new directory,
FTP all the needed
ZILCH and the
Zork II files into it
ZILCH into life again after all this years.
Learning the ITS Basics
Now is a good time to read some user documentation:
- DDT cheat sheet for Unix users
- Oscar Vermeulen wrote A Turist's Guide to ITS based on his explorations
- A Luser's Guide to ITS
- Basic editing with EMACS
- ITS: intro, primer, Getting Started Computing at the AI Lab
- DDT: manual, commands, colon commands
Preparing ZILCH and ZORK II
The best way to see the changes I made is to look at the diffs, e.g.
kdiff3 origfiles\zork.z.zilch\zilch.mud.188 src\zilch.mud kdiff3 origfiles\mimlib\sortx.mud src\sort.mud kdiff3 origfiles\mimlib\trace.mud src\trace.mud kdiff3 origfiles\zork2-mac-r22.zil\zork2.zil src\zork2.zil
ZILCH I added the missing
... <ADD-OP RESTART 0 0 <> <>> <ADD-OP QUIT 0 0 <> <>> <ADD-OP VERIFY 0 0 T <>> <ADD-OP RSTACK 0 0 <> <>> <ADD-OP FSTACK 0 0 <> <>> ...
Transferring All Files to
Create a new directory
*^F DB ROB FREE BLOCKS #0=13955 0 ROB LOGIN 1 ! 8/29/2020 14:15:26 *:print z2;..new. (udir) DSK: Z2; ..NEW. (UDIR) - FILE NOT FOUND DSK: DIR Z2 CREATED BY ROB HACTRN 14:16:11
and FTP all the prepared files into.
$ ftp 192.168.1.100 Connected to 192.168.1.100. 220- DB-ITS.EXAMPLE.COM ITS 1650, FTP server 336 on 4 SEP 2020 2013 EDT 220 Bugs/gripes to BUG-FTP @ MIT-MC Name (192.168.1.100:rob): z2 230 OK, your user name is Z2 ftp> put "action.zil" "ACTION ZIL" ftp> put "clock.zil" "CLOCK ZIL" ftp> put "crufty.zil" "CRUFTY ZIL" ftp> put "demons.zil" "DEMONS ZIL" ftp> put "dungeo.zil" "DUNGEO ZIL" ftp> put "macros.mud" "MACROS MUD" ftp> put "macros.zil" "MACROS ZIL" ftp> put "main.zil" "MAIN ZIL" ftp> put "nstruc.mud" "NSTRUC MUD" ftp> put "parser.zil" "PARSER ZIL" ftp> put "pprint.mud" "PPRINT MUD" ftp> put "sort.mud" "SORT MUD" ftp> put "syntax.zil" "SYNTAX ZIL" ftp> put "trace.mud" "TRACE MUD" ftp> put "verbs.zil" "VERBS ZIL" ftp> put "z2.mud" "Z2 MUD" ftp> put "z.mud" "Z MUD" ftp> put "zork2.zil" "ZORK2 ZIL" ftp> put "zilch.mud" "ZILCH MUD" ftp> quit
^F DB Z2 FREE BLOCKS #0=13955 * *^F 0 ACTION ZIL 25 ! 8/29/2020 14:16:29 0 CLOCK ZIL 1 ! 8/29/2020 14:17:35 0 CRUFTY ZIL 1 ! 8/29/2020 14:17:50 0 DEMONS ZIL 1 ! 8/29/2020 14:17:51 0 DUNGEO ZIL 15 ! 8/29/2020 14:17:51 0 MACROS MUD 1 ! 8/29/2020 14:18:20 0 MACROS ZIL 1 ! 8/29/2020 14:18:21 0 MAIN ZIL 1 ! 8/29/2020 14:18:21 0 NSTRUC MUD 1 ! 8/29/2020 14:18:23 0 PARSER ZIL 7 ! 8/29/2020 14:18:25 0 PPRINT MUD 3 ! 8/29/2020 14:18:38 0 SORT MUD 1 ! 8/29/2020 14:20:02 0 SYNTAX ZIL 3 ! 8/29/2020 14:20:03 0 TRACE MUD 2 ! 8/29/2020 14:20:08 0 VERBS ZIL 10 ! 8/29/2020 14:20:11 0 Z MUD 1 ! 8/29/2020 14:20:29 0 Z2 MUD 1 ! 8/29/2020 14:20:30 0 ZILCH MUD 16 ! 8/29/2020 14:20:30 0 ZORK2 ZIL 1 ! 8/29/2020 14:21:13
When you use a different directory name,
change the last line in the file
Z MUD to reflect your choice:
<SAVE-IT ("Z" "SAVE" "DSK" "Z2")> ^^
Kill all running background jobs first with
From Save File
The first possibility is to prepare a save file with
restore it and call
We put all we need to make a
Z SAVE file into
:print z mud <SET RECCHN ,OUTCHAN> <SET ZCHN ,OUTCHAN> <NEWTYPE NULL LIST> <SETG NULL #NULL <>> <DEFINE SETUP-EX () <FLOAD "SORT MUD"> <FLOAD "ZILCH MUD"> <FLOAD "MACROS MUD"> <SETG INSERT-CRUFTY T>> <DEFINE SAVE-IT ("OPTIONAL" (FILE '("PUBLIC" "SAVE" "DSK" "GUEST")) "AUX" (SNM "")) <SETUP-EX> <COND (<=? "SAVED" <SAVE !.FILE>> "Saved.") (T <PRINC "ZILCH ready."> <CRLF>)>> <SAVE-IT ("Z" "SAVE" "DSK" "Z2")>
Now make the save file:
*:muddle MUDDLE 56 IN OPERATION. LISTENING-AT-LEVEL 1 PROCESS 1 <FLOAD "Z MUD">$ "DONE" <QUIT>$ *^F DB Z2 FREE BLOCKS #0=13697 ... 0 Z SAVE 61 ! 8/30/2020 19:57:32 ...
Now we can use it to compile
*:muddle MUDDLE 56 IN OPERATION. LISTENING-AT-LEVEL 1 PROCESS 1 <RESTORE "Z SAVE">$ ZILCH ready. "DONE" <ZILCH "ZORK2">$ ZIL Debugging Compiler 4.5 -------------------------- Input file: ZORK2.ZIL Loader/ ZORK II: The Wizard of Frobozz Input file: DUNGEON.ZIL Input file: SYNTAX.ZIL Input file: MACROS.ZIL Compiling routine: ZPROB Global reference: LUCKY Code length: 1 bytes. Compilation time: 0.21781587 seconds. Compiling routine: PICK-ONE Code length: 1 bytes. Compilation time: 0.32100200E-1 seconds. Input file: CLOCK.ZIL ... many lines removed ... Compiling routine: BOTTOM-ETCHINGS-F Code length: 0 bytes. Compilation time: 0.14342880 seconds. Compiling routine: CUBE-F Code length: 0 bytes. Compilation time: 0.15155982 seconds. ** Warning, Undefined Routine: T Vocabulary: 627 Prepositions: 18 ACROSS AROUND AT AWAY BEHIND DOWN FOR FROM IN OFF ON OUT OVER THROUGH TO UNDER UP WITH Objects: 244 ADVENTURER ALICE-TABLE AQUARIUM AQUARIUM-ROOM ARCANA BALLOON ... many lines removed ... WIZARD WIZARD-CASE WIZARDS-QUARTERS WIZARDS-WORKSHOP WORKBENCH WORKBENCH-ROOM ZORK3 ZORKMID Properties: 28 P?ACTION P?ADJECTIVE P?CAPACITY P?CROSS ... many lines removed ... P?TEXT P?UP P?VALUE P?VTYPE P?WEST Globals: 140 ALWAYS-LIT BALLOON-DOWNS BALLOON-FLOATS BALLOON-UPS BANK-SOLVE-FLAG BASE-SCORE ... many lines removed ... WIZQDESCS WIZQLAST WON-FLAG YUKS ZGNOME-FLAG Total code length: 417 bytes. ZILCH finished in 332.92018 seconds.#NULL () <QUIT>$
We can run
ZILCH without a save file, too.
First prepare the file
:print z2 mud <SET RECCHN ,OUTCHAN> <SET ZCHN ,OUTCHAN> <FLOAD "SORT MUD"> <NEWTYPE NULL LIST> <SETG NULL #NULL <>> <FLOAD "ZILCH MUD"> <FLOAD "MACROS MUD"> <SETG INSERT-CRUFTY T> <ZILCH "ZORK2">
and then we FLOAD it:
*:massac *:cwd z2 *:muddle MUDDLE 56 IN OPERATION. LISTENING-AT-LEVEL 1 PROCESS 1 <FLOAD "Z2">$ g <-- here I typed g to suppress the display of **MORE** after each screen of output ZIL Debugging Compiler 4.5 -------------------------- Input file: ZORK2.ZIL Loader/ ZORK II: The Wizard of Frobozz Input file: DUNGEON.ZIL ... many lines removed ... Compiling routine: CUBE-F Code length: 0 bytes. Compilation time: 0.15118408 seconds. ** Warning, Undefined Routine: T Vocabulary: 627 Prepositions: 18 ACROSS AROUND AT AWAY ... many lines removed ... UNDER UP WITH Objects: 244 ADVENTURER ALICE-TABLE AQUARIUM AQUARIUM-ROOM ARCANA BALLOON ... many lines removed ... WIZARD WIZARD-CASE WIZARDS-QUARTERS WIZARDS-WORKSHOP WORKBENCH WORKBENCH-ROOM ZORK3 ZORKMID Properties: 28 P?ACTION P?ADJECTIVE P?CAPACITY P?CROSS ... many lines removed ... P?TEXT P?UP P?VALUE P?VTYPE P?WEST Globals: 140 ALWAYS-LIT BALLOON-DOWNS BALLOON-FLOATS BALLOON-UPS BANK-SOLVE-FLAG BASE-SCORE ... many lines removed ... WINNER WIZ-DOOR-FLAG WIZQDESCS WIZQLAST WON-FLAG YUKS ZGNOME-FLAG Total code length: 417 bytes. ZILCH finished in 332.90143 seconds."DONE" <QUIT>$
Sometimes, using this direct method, I get a Memory Protection Violation:
** Warning, Undefined Routine: T MPV; 723564>>HLRZ 13,-1(1) 13/ -1,,400003 532204/ ??
Then I try one of this two workarounds:
<BLOAT ...line in
<BLOAT 70000 0 0 2700 0 0 0 0 0 256>
<BLOAT 90000 0 0 2900 0 0 0 0 0 256>
put one or more
<GC>calls between the
<IFILE "SYNTAX" T> <ENDLOAD> <IFILE "MACROS" T> <IFILE "CLOCK" T> <IFILE "MAIN" T> <GC> <IFILE "PARSER" T> <GC> <IFILE "DEMONS" T> ;<INSERT-CRUFTY "CRUFTY"> <IFILE "CRUFTY" T> <GC> <IFILE "VERBS" T> <IFILE "ACTIONS" T> <GC 0 T>
At first glance we can see in the
ZILCH output, that the counting
of bytes used by the compiled routine code is broken.
However, this has no effect on the compiled code.
Now we can get all the
ZAP files down from
ITS and compare them
with the given preserved ones.
$ ftp 192.168.1.100 Connected to 192.168.1.100. 220- DB-ITS.EXAMPLE.COM ITS 1650, FTP server 336 on 4 SEP 2020 2236 EDT 220 Bugs/gripes to BUG-FTP @ MIT-MC Name (192.168.1.100:rob): z2
When we login as
z2 we are automatically in subdir
230 OK, your user name is Z2 ftp> mget *
and rename the files afterwards or
ftp> get "ACTION ZAP" "action.zap" ftp> get "ACTION ZIL" "action.zil" ftp> get "CLOCK ZAP" "clock.zap" ftp> get "CLOCK ZIL" "clock.zil" ftp> get "CRUFTY ZAP" "crufty.zap" ftp> get "CRUFTY ZIL" "crufty.zil" ftp> get "DEMONS ZAP" "demons.zap" ftp> get "DEMONS ZIL" "demons.zil" ftp> get "DUNGEO ZAP" "dungeo.zap" ftp> get "DUNGEO ZIL" "dungeo.zil" ftp> get "MACROS MUD" "macros.mud" ftp> get "MACROS ZAP" "macros.zap" ftp> get "MACROS ZIL" "macros.zil" ftp> get "MAIN ZAP" "main.zap" ftp> get "MAIN ZIL" "main.zil" ftp> get "NSTRUC MUD" "nstruc.mud" ftp> get "PARSER ZAP" "parser.zap" ftp> get "PARSER ZIL" "parser.zil" ftp> get "PPRINT MUD" "pprint.mud" ftp> get "SORT MUD" "sort.mud" ftp> get "SYNTAX ZAP" "syntax.zap" ftp> get "SYNTAX ZIL" "syntax.zil" ftp> get "TRACE MUD" "trace.mud" ftp> get "VERBS ZAP" "verbs.zap" ftp> get "VERBS ZIL" "verbs.zil" ftp> get "Z2 MUD" "z2.mud" ftp> get "Z MUD" "z.mud" ftp> get "ZORK2D ZAP" "zork2d.zap" ftp> get "ZORK2S ZAP" "zork2s.zap" ftp> get "ZORK2 ZIL" "zork2.zil" ftp> get "ZILCH MUD" "zilch.mud" ftp> get "ZORK2 ZAP" "zork2.zap" ftp> quit
When we trim the original
ZAP file basenames to 6 characters
and compare them to the generated ones, we notice they are identical
with two exceptions.
This is probably why crufty was compiled in a different way resulting in an
zork2dat.zap: Three missing lines at end of
.ENDT ; END LOAD \ ENDLOD:: > missing lines ; PURE TABLES ARE DEFINED HERE / .ENDI
Let's try to build it with
I use Windows 7 here.
First get and build
cd C:\storage\project\if\ mkdir zilf-0.9 hg clone https://foss.heptapod.net/zilf/zilf cd zilf dotnet msbuild Build.proj -t:PackageAllRids -p:Configuration=Release
ZAP files created by
to out/ directory and rename the following ones from the
six characters to their full length:
># cd C:\storage\project\if\zilch.github\out C:\storage\project\if\zilch.github\out># move ACTION.ZAP ACTIONS.ZAP C:\storage\project\if\zilch.github\out># move DUNGEO.ZAP DUNGEON.ZAP C:\storage\project\if\zilch.github\out># move ZORK2D.ZAP ZORK2DAT.ZAP C:\storage\project\if\zilch.github\out># move ZORK2S.ZAP ZORK2STR.ZAP C:\storage\project\if\zilch.github\out># dir ACTIONS.ZAP CLOCK.ZAP CRUFTY.ZAP DEMONS.ZAP DUNGEON.ZAP MACROS.ZAP MAIN.ZAP PARSER.ZAP SYNTAX.ZAP VERBS.ZAP ZORK2.ZAP ZORK2DAT.ZAP ZORK2STR.ZAP
Try to build with
C:\storage\project\if\zilch.github\out># C:\storage\project\if\zilf-0.9\zilf\Package\Release\Stage\zilf-0.9.0-win-x64\bin\Zapf.exe zork2.zap ZAPF 0.9 Reading zork2.zap Reading ZORK2DAT.zap Reading DUNGEON.zap Reading SYNTAX.zap Reading MACROS.zap Reading CLOCK.zap Reading MAIN.zap Reading PARSER.zap Reading DEMONS.zap Reading CRUFTY.zap Reading VERBS.zap Reading ACTIONS.zap Reading ZORK2STR.zap MeasuringZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 .ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 .ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 error: required global symbol 'WORDS' is missing Failed (1 error)
OK, create an empty frequent words file:
C:\storage\project\if\zilch.github\out># type zork2word.xzap ;word frequency table of 96 most common words WORDS:: .TABLE .ENDT .ENDI
Add a new first line to
Try another time:
C:\storage\project\if\zilch.github\out>C:\storage\project\if\zilf-0.9\zilf\Package\Release\Stage\zilf-0.9.0-win-x64\bin\Zapf.exe zor k2.zap ZAPF 0.9 Reading zork2.zap Reading ZORK2WORD.xzap Reading ZORK2DAT.zap Reading DUNGEON.zap Reading SYNTAX.zap Reading MACROS.zap Reading CLOCK.zap Reading MAIN.zap Reading PARSER.zap Reading DEMONS.zap Reading CRUFTY.zap Reading VERBS.zap Reading ACTIONS.zap Reading ZORK2STR.zap MeasuringZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 .ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 .ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 Assembling ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 Wrote 93630 bytes to zork2.z3
Try the resulting story file
ZORK II: The Wizard of Frobozz Copyright 1981 by Infocom, Inc. All rights reserved. ZORK is a trademark of Infocom, Inc. Release 42 / Serial number 200905 Inside the Barrow You are inside an ancient barrow hidden deep within a dark forest. The barrow opens into a narrow tunnel at its southern end. You can see a faint glow at the far end. A sword of Elvish workmanship is on the ground. A strangely familiar brass lantern is lying on the ground. >zork At your service! >$VERIFY Verifying game... Game correct. >
Let's try the original
zork2freq.xzap. Copy it to out/,
change the first line in zork2.zap to
ZAPF it once more
C:\storage\project\if\zilch.github\out>C:\storage\project\if\zilf-0.9\zilf\Package\Release\Stage\zilf-0.9.0-win-x64\bin\Zapf.exe zor k2.zap ZAPF 0.9 Reading zork2.zap Reading zork2freq.xzap Reading ZORK2DAT.zap Reading DUNGEON.zap Reading SYNTAX.zap Reading MACROS.zap Reading CLOCK.zap Reading MAIN.zap Reading PARSER.zap Reading DEMONS.zap Reading CRUFTY.zap Reading VERBS.zap Reading ACTIONS.zap Reading ZORK2STR.zap MeasuringZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 .ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 .ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 Assembling ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258 Wrote 82932 bytes to zork2.z3
The resulting story file
zork2.z3 is now about 10 kB smaller
93630 bytes with dummy frequent words file 82932 bytes with the original frequent words file 10698 bytes smaller
And it works as well.
ZILCH delivers quite reasonable results,
the work on its documentation is justified
and also with regard to its historical significance.
ZILCH: The Program.
zil.mud.176the "ZIL Interpreter/Table Generator"
zip.mud.96the Zork Interpreter Program
zap.mud.171the Zork Assembler Program
- use Debian only (because of problems with Ubuntu)
- test current Debian distribution
- look for the reason for the
zapfwarning: ZORK2DAT.zap:945: warning: incorrect table size: expected 2357, actual 2258