scottfree-1.14.orig/ 40700 1750 1750 0 6505671061 13374 5ustar schizoschizoscottfree-1.14.orig/README100700 1750 1750 15044 5747667001 14406 0ustar schizoschizoThis is my second serious production edition of the Scott Adams game player. It needs curses (or an equivalent - eg pccurses. A non-curses port should be easy too), and an ANSI C compiler. This code has been tested on a SUN3(SunOS 4.1.1) and on a Pyramid 9820 in the att universe. Installation ------------ Type 'make'. You will need a system with curses and an ANSI C compiler (eg gcc). Operation --------- ScottFree reads and executes TRS80 format Scott Adams datafiles. It is possible to run other formats either by writing a loader for that format or a convertor to TRS80 format. Remember the Scott Adams games are still copyright - you need to buy or obtain the games legally for use with this interpreter. Some Scott Adams material is available fairly freely . Dec 1980 Byte contains a game driver and also a program to write a version of Pirate Adventure. A PC-SIG disk contains Adventureland in BASIC with a database in DATA statements. The file 'Definition' in this archive explains the TRS80 format as I believe it exists. Much of this definition comes from P.D.Doherty who provided a lot of information. ScottFree should run all the Scott Adams, Brian Howarth and some other Adventure International games. (Gremlins and Supergran have a compressed action table, Robin Of Sherwood and Seas Of Blood have both a compressed action table and compressed text. Seas Of Blood won't run straight off due to the bizarre Fighting Fantasy (tm) combat system built into it.) Command Options --------------- ScottFree [flags] [save-file] Specifying save-file causes a restore of the save to take place. The flags are -d Debugging info on load -i Generate 'I am' type messages (default) -y Generate 'You are', 'You are carrying' type messages for games that use these instead (eg Robin Of Sherwood) -s Generate authentic Scott Adams driver light messages rather than other driver style ones (Light goes out in %d turns..) -t Generate TRS80 style display (terminal width is 64 characters; a line <-----------------> is displayed after the top stuff; objects have periods after them instead of hyphens Statement Of Copyright/License ------------------------------ This software is supplied subject to the GNU software copyleft (version 2) available from GNU or for FTP from prep.ai.mit.edu. All material in this program was developed by Swansea University Computer Society without disassembly of any other game drivers, only of game databases as permitted by EEC law (for purposes of compatibility). It is your responsibility not to transfer this software to any country where such reverse engineering is not permitted. This software license does not include any rights with regards to the Scott Adams games themselves. These games are copyright and you should obtain them from a legal source. The following information sources were used to produce the game driver: PC-SIG disk of Adventureland: This gives the Adventureland database as well as about 80% of the full interpreter system. The core of the gamedriver was written using this as a reference to the game code. Byte Dec 1980: This contains a good article about Scott and his games, as well as a TRS80 driver and datafile writer for the 'Pirate Adventure' game. This filled in some more answers as well as bits of the TRS80 data format P.D.Doherty: Many thanks go to him for figuring out a load more actions, testing, hunting for games which used unknown actions and for writing a Scott Adams database to readable text convertor. This helped resolve several other actions. Changes 1.14 ------------ o Bit flag 16 support o Lamp behaviour flag '-p' for prehistoric databases which don't use bit 16 o Light out messages don't appear when the lamp is elsewhere. o Automatic get/drop has synonym support. Changes 1.13 ------------ o Darkness is now done like the actual Scott driver seems to do it, using bit flag 15. Fixes problems in The Count o Display problem with 4.4BSD curses fixed (added a wmove() call) o Can't TAKE ALL in a dark room. Changes 1.12a ------------- o Merged in some fixes by Steve Rice (Variables for terminal size, wrong wraparound due to bug in Look(), TRS80 style option) o Updated PC version. Changes 1.12 ------------ o Merged in some fixes by Antoine Sabot-Durand (Redraw in dark rooms, darkness flag testing, Action 74 bug). 'Pirate Adventure' should now work. o Added some comments o Added a makefile o Fixed several missing redraws. Changes 1.11 ------------ o Major bug in file reading routines fixed. This should now read _ALL_ the Scott Adams files without you having to add spaces. o Knows about the use of // in item texts and correctly handles it. o Uses unsigned char for the location of an item so that it correctly behaves like the spectrum editions on wrapping. This makes a lot more of the Brian Howarth material work. o Rewrote the awful OutBuf() function to be a bit neater. o Messed up the neat OutBuf() function by supporting old BSD curses too. Linux people and 386BSD people should now be in luck, as should any old BSD4.x users. o TAKE ALL/DROP ALL. Emulates Brian Howarth driver including the number of moves bug. NOTE:: TAKE ALL/DROP ALL count as one move. In some games that give limited moves for things this makes it easier or enables you to do things you should not be able to. The Brian Howarth games all have this feature and should be fine. o Started work on an Xview version - don't expect it just yet. o Fixed a major cockup in the execution rules for lines. Robin Of Sherwood lets you out of the cell without killing you at last. o Place item -> location failed with some compilers (most), now made portable. o WAIT action refreshes display first o Redraws any pending display changes before the status table o Option flags tidied up. Changes 1.10 ------------ o Action 75 added (dunno how it was missed) o Corrected second Byte year reference Changes 1.9 ----------- o Inventory short cut o Swap room flag/location now fixed. This should make Claymorgue work correctly (ha!). o Corrected Byte reference from 1990 to 1980. Changes 1.8 ----------- o Move location action sets the redraw flag o Driver ignored last line of table (now fixed) o Save/Load implemented. o N,E,S,W,U,D shortcuts added. I will add the item ones once I've loaded a few more fake saves into the genuine Brian Howarth driver to figure out how it works. To Do ----- o Tidy up TAKE ALL/DROP ALL. They match the Spectrum version - which appears to be buggy. Also note that using GET ALL / DROP ALL with older games _MAY_BREAK_THINGS_. Maybe this should be a flagged option. scottfree-1.14.orig/Makefile100700 1750 1750 267 5742565570 15132 0ustar schizoschizo# # Makefile for the thing # CC = gcc # # all : ScottCurses ScottCurses.o: ScottCurses.c Scott.h ScottCurses: ScottCurses.o $(CC) ScottCurses.o -o ScottCurses -lcurses -ltermcap scottfree-1.14.orig/ScottCurses.c100700 1750 1750 64255 5747665757 16203 0ustar schizoschizo/* * ScottFree Revision 1.14 * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * * You must have an ANSI C compiler to build this program. */ #include #include #ifndef PYRAMID #include #endif #include #include #include #include #include "Scott.h" #ifdef AMIGA #define NOGETPID #define NOSTRNCASECMP #endif #ifdef PYRAMID #define NOSTRNCASECMP #endif /* * Configuration Twiddles */ #ifdef NOSTRNCASECMP static int strncasecmp(char *a,char *b, int n) { while(*a&&n>0) { char c=*a; char d=*b; if(islower(c)) c=toupper(c); if(islower(d)) d=toupper(d); if(cd) return(1); a++; b++; n--; if(n==0) return(0); } if(*b) return(1); return(0); } #endif #ifdef NOGETPID #ifndef AMIGA #define getpid() 6031769 #else #define getpid() ((int)FindTask(NULL)) #endif #endif Header GameHeader; Tail GameTail; Item *Items; Room *Rooms; char **Verbs; char **Nouns; char **Messages; Action *Actions; int LightRefill; char NounText[16]; int Counters[16]; /* Range unknown */ int CurrentCounter; int SavedRoom; int RoomSaved[16]; /* Range unknown */ int DisplayUp; /* Curses up */ WINDOW *Top,*Bottom; int Redraw; /* Update item window */ int Options; /* Option flags set */ int Width; /* Terminal width */ int TopHeight; /* Height of top window */ int BottomHeight; /* Height of bottom window */ #define TRS80_LINE "\n<------------------------------------------------------------>\n" #define MyLoc (GameHeader.PlayerRoom) long BitFlags=0; /* Might be >32 flags - I haven't seen >32 yet */ void Fatal(char *x) { if(DisplayUp) endwin(); fprintf(stderr,"%s.\n",x); exit(1); } void Aborted() { Fatal("User exit"); } void ClearScreen(void) { werase(Bottom); wrefresh(Bottom); } void *MemAlloc(int size) { void *t=(void *)malloc(size); if(t==NULL) Fatal("Out of memory"); return(t); } int RandomPercent(int n) { unsigned int rv=rand()<<6; rv%=100; if(rvVocab, &ap->Condition[0], &ap->Condition[1], &ap->Condition[2], &ap->Condition[3], &ap->Condition[4], &ap->Action[0], &ap->Action[1])!=8) { printf("Bad action line (%d)\n",ct); exit(1); } ap++; ct++; } ct=0; if(loud) printf("Reading %d word pairs.\n",nw); while(ctExits[0],&rp->Exits[1],&rp->Exits[2], &rp->Exits[3],&rp->Exits[4],&rp->Exits[5]); rp->Text=ReadString(f); ct++; rp++; } ct=0; if(loud) printf("Reading %d messages.\n",mn); while(ctText=ReadString(f); ip->AutoGet=strchr(ip->Text,'/'); /* Some games use // to mean no auto get/drop word! */ if(ip->AutoGet && strcmp(ip->AutoGet,"//") && strcmp(ip->AutoGet,"/*")) { char *t; *ip->AutoGet++=0; t=strchr(ip->AutoGet,'/'); if(t!=NULL) *t=0; } fscanf(f,"%hd",&lo); ip->Location=(unsigned char)lo; ip->InitialLoc=ip->Location; ip++; ct++; } ct=0; /* Discard Comment Strings */ while(ct(Width-2)) { scroll(Bottom); wmove(Bottom,BottomHeight-1,0); wclrtoeol(Bottom); OutputPos=0; } wprintw(Bottom,word); OutputPos+=strlen(word); if(*buffer==0) return; if(*buffer=='\n') { scroll(Bottom); wmove(Bottom,BottomHeight-1,0); wclrtoeol(Bottom); OutputPos=0; } else { OutputPos++; if(OutputPos<(Width-1)) wprintw(Bottom," "); } buffer++; } } void Output(char *a) { char block[512]; strcpy(block,a); OutBuf(block); } void OutputNumber(int a) { char buf[16]; sprintf(buf,"%d ",a); OutBuf(buf); } void Look() { static char *ExitNames[6]= { "North","South","East","West","Up","Down" }; Room *r; int ct,f; int pos; werase(Top); wmove(Top,0,0); /* Needed by some curses variants */ if((BitFlags&(1<Text=='*') wprintw(Top,"%s\n",r->Text+1); else { if(Options&YOUARE) wprintw(Top,"You are %s\n",r->Text); else wprintw(Top,"I'm in a %s\n",r->Text); } ct=0; f=0; wprintw(Top,"\nObvious exits: "); while(ct<6) { if(r->Exits[ct]!=0) { if(f==0) f=1; else wprintw(Top,", "); wprintw(Top,"%s",ExitNames[ct]); } ct++; } if(f==0) wprintw(Top,"none"); wprintw(Top,".\n"); ct=0; f=0; pos=0; while(ct<=GameHeader.NumItems) { if(Items[ct].Location==MyLoc) { if(f==0) { if(Options&YOUARE) wprintw(Top,"\nYou can also see: "); else wprintw(Top,"\nI can also see: "); pos=16; f++; } else if (!(Options & TRS80_STYLE)) { wprintw(Top," - "); pos+=3; } if(pos+strlen(Items[ct].Text)>(Width-10)) { pos=0; wprintw(Top,"\n"); } wprintw(Top,"%s",Items[ct].Text); pos += strlen(Items[ct].Text); if (Options & TRS80_STYLE) { wprintw(Top,". "); pos+=2; } } ct++; } wprintw(Top,"\n"); if (Options & TRS80_STYLE) wprintw(Top,TRS80_LINE); wrefresh(Top); } int WhichWord(char *word, char **list) { int n=1; int ne=1; char *tp; while(ne<=GameHeader.NumWords) { tp=list[ne]; if(*tp=='*') tp++; else n=ne; if(strncasecmp(word,tp,GameHeader.WordLength)==0) return(n); ne++; } return(-1); } void LineInput(char *buf) { int pos=0; int ch; while(1) { wrefresh(Bottom); ch=wgetch(Bottom); switch(ch) { case 10:; case 13:; buf[pos]=0; scroll(Bottom); wmove(Bottom,BottomHeight,0); return; case 8:; case 127:; if(pos>0) { int y,x; getyx(Bottom,y,x); x--; if(x==-1) { x=Width-1; y--; } mvwaddch(Bottom,y,x,' '); wmove(Bottom,y,x); wrefresh(Bottom); pos--; } break; default: if(ch>=' '&&ch<=126) { buf[pos++]=ch; waddch(Bottom,(char)ch); wrefresh(Bottom); } break; } } } void GetInput(vb,no) int *vb,*no; { char buf[256]; char verb[10],noun[10]; int vc,nc; int num; do { do { Output("\nTell me what to do ? "); wrefresh(Bottom); LineInput(buf); OutReset(); num=sscanf(buf,"%9s %9s",verb,noun); } while(num==0||*buf=='\n'); if(num==1) *noun=0; if(*noun==0 && strlen(verb)==1) { switch(isupper(*verb)?tolower(*verb):*verb) { case 'n':strcpy(verb,"NORTH");break; case 'e':strcpy(verb,"EAST");break; case 's':strcpy(verb,"SOUTH");break; case 'w':strcpy(verb,"WEST");break; case 'u':strcpy(verb,"UP");break; case 'd':strcpy(verb,"DOWN");break; /* Brian Howarth interpreter also supports this */ case 'i':strcpy(verb,"INVENTORY");break; } } nc=WhichWord(verb,Nouns); /* The Scott Adams system has a hack to avoid typing 'go' */ if(nc>=1 && nc <=6) { vc=1; } else { vc=WhichWord(verb,Verbs); nc=WhichWord(noun,Nouns); } *vb=vc; *no=nc; if(vc==-1) { Output("You use word(s) I don't know! "); } } while(vc==-1); strcpy(NounText,noun); /* Needed by GET/DROP hack */ } void SaveGame() { char buf[256]; int ct; FILE *f; Output("Filename: "); LineInput(buf); Output("\n"); f=fopen(buf,"w"); if(f==NULL) { Output("Unable to create save file.\n"); return; } for(ct=0;ct<16;ct++) { fprintf(f,"%d %d\n",Counters[ct],RoomSaved[ct]); } fprintf(f,"%ld %d %hd %d %d %hd\n",BitFlags, (BitFlags&(1<dv) return(0); break; case 16: if(CurrentCounter<=dv) return(0); break; case 17: if(Items[dv].Location!=Items[dv].InitialLoc) return(0); break; case 18: if(Items[dv].Location==Items[dv].InitialLoc) return(0); break; case 19:/* Only seen in Brian Howarth games so far */ if(CurrentCounter!=dv) return(0); break; } cc++; } /* Actions */ act[0]=Actions[ct].Action[0]; act[2]=Actions[ct].Action[1]; act[1]=act[0]%150; act[3]=act[2]%150; act[0]/=150; act[2]/=150; cc=0; pptr=0; while(cc<4) { if(act[cc]>=1 && act[cc]<52) { Output(Messages[act[cc]]); Output("\n"); } else if(act[cc]>101) { Output(Messages[act[cc]-50]); Output("\n"); } else switch(act[cc]) { case 0:/* NOP */ break; case 52: if(CountCarried()==GameHeader.MaxCarry) { if(Options&YOUARE) Output("You are carrying too much. "); else Output("I've too much to carry! "); break; } if(Items[param[pptr]].Location==MyLoc) Redraw=1; Items[param[pptr++]].Location= CARRIED; break; case 53: Redraw=1; Items[param[pptr++]].Location=MyLoc; break; case 54: Redraw=1; MyLoc=param[pptr++]; break; case 55: if(Items[param[pptr]].Location==MyLoc) Redraw=1; Items[param[pptr++]].Location=0; break; case 56: BitFlags|=1<=0) CurrentCounter--; break; case 78: OutputNumber(CurrentCounter); break; case 79: CurrentCounter=param[pptr++]; break; case 80: { int t=MyLoc; MyLoc=SavedRoom; SavedRoom=t; Redraw=1; break; } case 81: { /* This is somewhat guessed. Claymorgue always seems to do select counter n, thing, select counter n, but uses one value that always seems to exist. Trying a few options I found this gave sane results on ageing */ int t=param[pptr++]; int c1=CurrentCounter; CurrentCounter=Counters[t]; Counters[t]=c1; break; } case 82: CurrentCounter+=param[pptr++]; break; case 83: CurrentCounter-=param[pptr++]; if(CurrentCounter< -1) CurrentCounter= -1; /* Note: This seems to be needed. I don't yet know if there is a maximum value to limit too */ break; case 84: Output(NounText); break; case 85: Output(NounText); Output("\n"); break; case 86: Output("\n"); break; case 87: { /* Changed this to swap location<->roomflag[x] not roomflag 0 and x */ int p=param[pptr++]; int sr=MyLoc; MyLoc=RoomSaved[p]; RoomSaved[p]=sr; Redraw=1; break; } case 88: wrefresh(Top); wrefresh(Bottom); sleep(2); /* DOC's say 2 seconds. Spectrum times at 1.5 */ break; case 89: pptr++; /* SAGA draw picture n */ /* Spectrum Seas of Blood - start combat ? */ /* Poking this into older spectrum games causes a crash */ break; default: fprintf(stderr,"Unknown action %d [Param begins %d %d]\n", act[cc],param[pptr],param[pptr+1]); break; } cc++; } return(1+continuation); } int PerformActions(int vb,int no) { static int disable_sysfunc=0; /* Recursion lock */ int d=BitFlags&(1<=1 && no<=6) { int nl; if(Items[LIGHT_SOURCE].Location==MyLoc || Items[LIGHT_SOURCE].Location==CARRIED) d=0; if(d) Output("Dangerous to move in the dark! "); nl=Rooms[MyLoc].Exits[no-1]; if(nl!=0) { MyLoc=nl; Look(); return(0); } if(d) { if(Options&YOUARE) Output("You fell down and broke your neck. "); else Output("I fell down and broke my neck. "); wrefresh(Bottom); sleep(5); endwin(); exit(0); } if(Options&YOUARE) Output("You can't go in that direction. "); else Output("I can't go in that direction. "); return(0); } fl= -1; while(ct<=GameHeader.NumActions) { int vv,nv; vv=Actions[ct].Vocab; /* Think this is now right. If a line we run has an action73 run all following lines with vocab of 0,0 */ if(vb!=0 && (doagain&&vv!=0)) break; /* Oops.. added this minor cockup fix 1.11 */ if(vb!=0 && !doagain && fl== 0) break; nv=vv%150; vv/=150; if((vv==vb)||(doagain&&Actions[ct].Vocab==0)) { if((vv==0 && RandomPercent(nv))||doagain|| (vv!=0 && (nv==no||nv==0))) { int f2; if(fl== -1) fl= -2; if((f2=PerformLine(ct))>0) { /* ahah finally figured it out ! */ fl=0; if(f2==2) doagain=1; if(vb!=0 && doagain==0) return; } } } ct++; if(Actions[ct].Vocab!=0) doagain=0; } if(fl!=0 && disable_sysfunc==0) { int i; if(Items[LIGHT_SOURCE].Location==MyLoc || Items[LIGHT_SOURCE].Location==CARRIED) d=0; if(vb==10 || vb==18) { /* Yes they really _are_ hardcoded values */ if(vb==10) { if(strcasecmp(NounText,"ALL")==0) { int ct=0; int f=0; if(d) { Output("It is dark.\n"); return 0; } while(ct<=GameHeader.NumItems) { if(Items[ct].Location==MyLoc && Items[ct].AutoGet!=NULL && Items[ct].AutoGet[0]!='*') { no=WhichWord(Items[ct].AutoGet,Nouns); disable_sysfunc=1; /* Don't recurse into auto get ! */ PerformActions(vb,no); /* Recursively check each items table code */ disable_sysfunc=0; if(CountCarried()==GameHeader.MaxCarry) { if(Options&YOUARE) Output("You are carrying too much. "); else Output("I've too much to carry. "); return(0); } Items[ct].Location= CARRIED; Redraw=1; OutBuf(Items[ct].Text); Output(": O.K.\n"); f=1; } ct++; } if(f==0) Output("Nothing taken."); return(0); } if(no==-1) { Output("What ? "); return(0); } if(CountCarried()==GameHeader.MaxCarry) { if(Options&YOUARE) Output("You are carrying too much. "); else Output("I've too much to carry. "); return(0); } i=MatchUpItem(NounText,MyLoc); if(i==-1) { if(Options&YOUARE) Output("It is beyond your power to do that. "); else Output("It's beyond my power to do that. "); return(0); } Items[i].Location= CARRIED; Output("O.K. "); Redraw=1; return(0); } if(vb==18) { if(strcasecmp(NounText,"ALL")==0) { int ct=0; int f=0; while(ct<=GameHeader.NumItems) { if(Items[ct].Location==CARRIED && Items[ct].AutoGet && Items[ct].AutoGet[0]!='*') { no=WhichWord(Items[ct].AutoGet,Nouns); disable_sysfunc=1; PerformActions(vb,no); disable_sysfunc=0; Items[ct].Location=MyLoc; OutBuf(Items[ct].Text); Output(": O.K.\n"); Redraw=1; f=1; } ct++; } if(f==0) Output("Nothing dropped.\n"); return(0); } if(no==-1) { Output("What ? "); return(0); } i=MatchUpItem(NounText,CARRIED); if(i==-1) { if(Options&YOUARE) Output("It's beyond your power to do that.\n"); else Output("It's beyond my power to do that.\n"); return(0); } Items[i].Location=MyLoc; Output("O.K. "); Redraw=1; return(0); } } } return(fl); } void main(int argc, char *argv[]) { FILE *f; int vb,no; while(argv[1]) { if(*argv[1]!='-') break; switch(argv[1][1]) { case 'y': Options|=YOUARE; break; case 'i': Options&=~YOUARE; break; case 'd': Options|=DEBUGGING; break; case 's': Options|=SCOTTLIGHT; break; case 't': Options|=TRS80_STYLE; break; case 'p': Options|=PREHISTORIC_LAMP; break; case 'h': default: fprintf(stderr,"%s: [-h] [-y] [-s] [-i] [-t] [-d] [-p] [savedgame].\n", argv[0]); exit(1); } if(argv[1][2]!=0) { fprintf(stderr,"%s: option -%c does not take a parameter.\n", argv[0],argv[1][1]); exit(1); } argv++; argc--; } if(argc!=2 && argc!=3) { fprintf(stderr,"%s .\n",argv[0]); exit(1); } f=fopen(argv[1],"r"); if(f==NULL) { perror(argv[1]); exit(1); } signal(SIGINT,Aborted); /* For BSD curses */ signal(SIGQUIT,SIG_IGN); signal(SIGTSTP,SIG_IGN); if (Options & TRS80_STYLE) { Width = 64; TopHeight = 11; BottomHeight = 13; } else { Width = 80; TopHeight = 10; BottomHeight = 14; } DisplayUp=1; initscr(); Top=newwin(TopHeight,Width,0,0); Bottom=newwin(BottomHeight,Width,TopHeight,0); scrollok(Bottom,TRUE); leaveok(Top,TRUE); leaveok(Bottom,FALSE); idlok(Bottom,TRUE); noecho(); cbreak(); wmove(Bottom,BottomHeight-1,0); OutReset(); OutBuf("\ Scott Free, A Scott Adams game driver in C.\n\ Release 1.14, (c) 1993,1994,1995 Swansea University Computer Society.\n\ Distributed under the GNU software license\n\n"); LoadDatabase(f,(Options&DEBUGGING)?1:0); fclose(f); if(argc==3) LoadGame(argv[2]); srand(time(NULL)^getpid()^getuid()); Look(); while(1) { if(Redraw!=0) { Look(); Redraw=0; } PerformActions(0,0); if(Redraw!=0) { Look(); Redraw=0; } GetInput(&vb,&no); switch(PerformActions(vb,no)) { case -1:Output("I don't understand your command. "); break; case -2:Output("I can't do that yet. "); break; } /* Brian Howarth games seem to use -1 for forever */ if(Items[LIGHT_SOURCE].Location/*==-1*/!=DESTROYED && GameHeader.LightTime!= -1) { GameHeader.LightTime--; if(GameHeader.LightTime<1) { BitFlags|=(1< carried 2 Item in room with player 3 Item carried or in room with player 4 In room 5 Item not in room with player 6 Item not carried 7 Not in room 8 BitFlag is set. 9 BitFlag is cleared 10 Something carried (arg unused) 11 Nothing carried (arg unused) 12 Item not carried nor in room with player 13 Item is in game [not in room 0] 14 Item is not in game [in room 0] 15 CurrentCounter <= 16 CurrentCounter >= 17 Object still in initial room 18 Object not in initial room 19 CurrentCounter = Actions 0 Does nothing 1-51 Print message 0-50. Some drivers add a space some add a newline. 52 Get item . Checks if you can carry it first 53 Drops item 54 Moves to room 55 Item is removed from the game (put in room 0) 56 The darkness flag is set 57 The darkness flag is cleared 58 Bitflag is set 59 The same as 55 (it seems - I'm cautious about this) 60 BitFlag is cleared 61 Death. Dark flag cleared, player moved to last room 62 Item put in room 63 Game over. 64 Describe room 65 Score 66 Inventory 67 BitFlag 0 is set 68 BitFlag 0 is cleared 69 Refill lamp (?) 70 Screen is cleared. This varies by driver from no effect upwards 71 Saves the game. Choices of filename etc depend on the driver alone. 72 Swap item and item locations 73 Continue with next line (the next line starts verb 0 noun 0) 74 Take item - no check is done too see if it can be carried. 75 Put item with item - Not certain seems to do this from examination of Claymorgue 76 Look (same as 64 ?? - check) 77 Decrement current counter. Will not go below 0 78 Print current counter value. Some drivers only cope with 0-99 apparently 79 Set current counter value 80 Swap location with current location-swap flag 81 Select a counter. Current counter is swapped with backup counter 82 Add to current counter 83 Subtract from current counter 84 Echo noun player typed without CR 85 Echo the noun the player typed 86 CR 87 Swap current location value with backup location-swap value 88 Wait 2 seconds 89 SAGA - draw picture (actually , as each Look() draws picture automatically) Older spectrum driver - crashes Spectrum Seas of Blood - seems to start Fighting Fantasy combat mode 90-101 Unused 102+ Print message 51-99 This is followed by the words with verbs and nouns interleaved. A word with a * at the beginning is a synonym for the word above. Verb 1 is GO, verb 10 is GET, verb 18 is DROP (always). Nouns 1-6 are directions. This is followed by the rooms. Each room is 6 exits (north south east west up down) followed by a text string. Then come the messages, stored as a list of strings. Next come the items in the format item text then location. Item text may end with /TEXT/. This text is not printed but means that an automatic get/drop will be done for 'GET/DROP TEXT' on this item. Item names beginning with '*' are treasures. The '*' is printed. If you put all treasures in the treasure room (in the header) and 'SCORE' the game finishes with a well done message. Item location -1 is the inventory (255 on C64 and Spectrum tape games) and 0 means not in play in every game I've looked at. The lamp (always object 9) behaviour supports this belief. A set of strings follow this. In order they match to each line of verb/noun actions, and are comments. The Spectrum and C64 tape system where the database is compiled into the program has no comments. Finally three values follow which are version, adventure number and an unknown magic number.