C REV. 23 INTEGER FUNCTION LTEXT(N) LTEXT=IDISK(4,1,1,N) RETURN END C INTEGER FUNCTION STEXT(N) STEXT=IDISK(5,1,1,N) RETURN END C INTEGER FUNCTION TRAVEL(M,N) TRAVEL=IDISK(8,3,M,N) RETURN END C INTEGER FUNCTION IDISK(ILUN,IDIM,ISUB1,ISUB2) INTEGER BUF(64) DATA ILAST,NLAST/2*0/ K=64/IDIM J=ISUB2-1 NREC=1+J/K IF (ILAST .EQ. ILUN .AND. NLAST .EQ. NREC) GO TO 1 ILAST=ILUN NLAST=NREC READ(ILUN,REC=NREC) BUF 1 IT=MOD(J,K)*IDIM+ISUB1 IDISK=BUF(IT) RETURN END C INTEGER FUNCTION RTEXT(N) RTEXT=IDISK(10,1,1,N) RETURN END C INTEGER FUNCTION VOCAB2(ID,INIT) INTEGER TABSIZ REAL ID,ATAB COMMON /VOCCOM/ TABSIZ C C WRITE(3,100)ID,INIT C 100 FORMAT(1X,'VOCAB(',A4,',',I3,')') DO 1 I=1,TABSIZ IK=KTAB(I) IF (IK .EQ. -1) GO TO 2 IF (INIT .GE. 0 .AND. IK/1000 .NE. INIT) GO TO 1 IF (ATAB(I) .EQ. ID) GO TO 3 1 CONTINUE CALL BUG(21) C 2 VOCAB2=-1 IF (INIT .LT. 0) RETURN WRITE(3,100) ID 100 FORMAT(1X,'KEYWORD = ',A4) CALL BUG(5) C 3 VOCAB2=IK IF (INIT .GE. 0) VOCAB2=MOD(VOCAB2,1000) RETURN END SUBROUTINE CARRY(OBJECT,WHERE) INTEGER ATLOC,LINK,PLACE,FIXED,HOLDNG,OBJECT,WHERE,TEMP DIMENSION ATLOC(150),LINK(200),PLACE(100),FIXED(100) COMMON /PLACOM/ ATLOC,LINK,PLACE,FIXED,HOLDNG C IF (OBJECT .GT. 100) GO TO 5 IF (PLACE(OBJECT) .EQ. -1) RETURN PLACE(OBJECT)=-1 HOLDNG=HOLDNG+1 5 IF (ATLOC(WHERE) .NE. OBJECT) GO TO 6 ATLOC(WHERE)=LINK(OBJECT) RETURN 6 TEMP=ATLOC(WHERE) 7 IF (LINK(TEMP) .EQ. OBJECT) GO TO 8 TEMP=LINK(TEMP) GO TO 7 8 LINK(TEMP)=LINK(OBJECT) RETURN END C SUBROUTINE DROP(OBJECT,WHERE) INTEGER ATLOC,LINK,PLACE,FIXED,HOLDNG,OBJECT,WHERE DIMENSION ATLOC(150),LINK(200),PLACE(100),FIXED(100) COMMON /PLACOM/ ATLOC,LINK,PLACE,FIXED,HOLDNG C IF (OBJECT .GT. 100) GO TO 1 IF (PLACE(OBJECT) .EQ. -1) HOLDNG=HOLDNG-1 PLACE(OBJECT)=WHERE GO TO 2 1 FIXED(OBJECT-100)=WHERE 2 IF (WHERE .LE. 0) RETURN LINK(OBJECT)=ATLOC(WHERE) ATLOC(WHERE)=OBJECT RETURN END C INTEGER FUNCTION PUT(OBJECT,WHERE,PVAL) INTEGER OBJECT,WHERE,PVAL CALL MOVE(OBJECT,WHERE) PUT=-1-PVAL RETURN END C SUBROUTINE MOVE(OBJECT,WHERE) INTEGER ATLOC,LINK,PLACE,FIXED,OBJECT,WHERE,FROM,HOLDNG DIMENSION ATLOC(150),LINK(200),PLACE(100),FIXED(100) COMMON /PLACOM/ ATLOC,LINK,PLACE,FIXED,HOLDNG C IF (OBJECT .GT. 100) GO TO 1 FROM=PLACE(OBJECT) GO TO 2 1 FROM=FIXED(OBJECT-100) 2 IF (FROM .GT. 0 .AND. FROM .LE. 300) CALL CARRY(OBJECT,FROM) CALL DROP(OBJECT,WHERE) RETURN END C SUBROUTINE JUGGLE(OBJECT) INTEGER ATLOC,LINK,PLACE,FIXED,HOLDNG,OBJECT DIMENSION ATLOC(150),LINK(200),PLACE(100),FIXED(100) COMMON /PLACOM/ ATLOC,LINK,PLACE,FIXED C I=PLACE(OBJECT) J=FIXED(OBJECT) CALL MOVE(OBJECT,I) CALL MOVE(OBJECT+100,J) RETURN END C SUBROUTINE DSTROY(OBJECT) INTEGER OBJECT CALL MOVE(OBJECT,0) RETURN END C INTEGER FUNCTION VOCAB(ID,INIT) INTEGER KTAB,TABSIZ REAL ID,ATAB DIMENSION KTAB(300),ATAB(300) COMMON /VOCCOM/ KTAB,ATAB,TABSIZ C DO 1 I=1,TABSIZ IF (KTAB(I) .EQ. -1) GO TO 2 IF (INIT .GE. 0 .AND. KTAB(I)/1000 .NE. INIT) GO TO 1 IF (ATAB(I) .EQ. ID) GO TO 3 1 CONTINUE CALL BUG(21) C 2 VOCAB=-1 IF (INIT .LT. 0) RETURN WRITE(3,100) ID 100 FORMAT(1X,'KEYWORD = ',A4) CALL BUG(5) C 3 VOCAB=KTAB(I) IF (INIT .GE. 0) VOCAB=MOD(VOCAB,1000) RETURN END C SUBROUTINE A5TOA1(A,B,C,CHARS,LENG) LOGICAL FLG REAL A,B,C,D LOGICAL I,J,K,M LOGICAL CHARS(20),TEST(4),BLANK EQUIVALENCE (D,TEST(1)) DATA BLANK/' '/ C DO 9 I=1,20 9 CHARS(I)=BLANK C D=A DO 1 I=1,4 1 CHARS(I)=TEST(I) C D=B DO 2 I=1,4 2 CHARS(I+4)=TEST(I) C D=C J=9 IF (TEST(1) .GE. 65) J=10 M=1 K=J+3 DO 3 I=J,K CHARS(I)=TEST(M) 3 M=M+1 C DO 10 I=1,19 12 IF (CHARS(I) .NE. BLANK .OR. CHARS(I+1) .NE. BLANK)GOTO 10 FLG=.FALSE. J=I+1 DO 11 K=J,20 IF (CHARS(K) .NE. BLANK) FLG=.TRUE. 11 CHARS(K-1)=CHARS(K) CHARS(20)=BLANK IF (FLG) GO TO 12 10 CONTINUE C DO 4 I=1,20 LENG=21-I IF (CHARS(LENG) .EQ. BLANK) GO TO 4 RETURN 4 CONTINUE CALL BUG(99) END INTEGER FUNCTION RAN(RANGE) C SINCE THE RAN FUNCTION IN LIB40 SEEMS TO BE A REAL LOSE, WE'LL USE ONE OF C OUR OWN. IT'S BEEN RUN THROUGH MANY OF THE TESTS IN KNUTH VOL. 2 AND C SEEMS TO BE QUITE RELIABLE. RAN RETURNS A VALUE UNIFORMLY SELECTED C BETWEEN 0 AND RANGE-1. NOTE RESEMBLANCE TO ALG USED IN WIZARD. INTEGER RANGE,D,R,T DATA R/0/ D=1 IF(R.NE.0)GOTO 1 WRITE(3,3) 3 FORMAT(1X,'Type 3 digits, please. ') READ(3,4) D 4 FORMAT(I3) R=3 D=1000+D 1 DO 2 T=1,D 2 R=R * 81 RAN=RANGE * (FLOAT(IABS(R))/32768.) RETURN END SUBROUTINE BUG(NUM) C THE FOLLOWING CONDITIONS ARE CURRENTLY CONSIDERED FATAL BUGS. NUMBERS < 20 C ARE DETECTED WHILE READING THE DATABASE; THE OTHERS OCCUR AT "RUN TIME". C 0 MESSAGE LINE > 70 CHARACTERS C 1 NULL LINE IN MESSAGE C 2 TOO MANY WORDS OF MESSAGES C 3 TOO MANY TRAVEL OPTIONS C 4 TOO MANY VOCABULARY WORDS C 5 REQUIRED VOCABULARY WORD NOT FOUND C 6 TOO MANY RTEXT OR MTEXT MESSAGES C 7 TOO MANY HINTS C 8 LOCATION HAS COND BIT BEING SET TWICE C 9 INVALID SECTION NUMBER IN DATABASE C 20 SPECIAL TRAVEL (500>L>300) EXCEEDS GOTO LIST C 21 RAN OFF END OF VOCABULARY TABLE C 22 VOCABULARY TYPE (N/1000) NOT BETWEEN 0 AND 3 C 23 INTRANSITIVE ACTION VERB EXCEEDS GOTO LIST C 24 TRANSITIVE ACTION VERB EXCEEDS GOTO LIST C 25 CONDITIONAL TRAVEL ENTRY WITH NO ALTERNATIVE C 26 LOCATION HAS NO TRAVEL ENTRIES C 27 HINT NUMBER EXCEEDS GOTO LIST C 28 INVALID MONTH RETURNED BY DATE FUNCTION WRITE(3,1) NUM 1 FORMAT (' FATAL ERROR, SEE SOURCE CODE FOR INTERPRETATION.'/ 1 ' PROBABLY CAUSE: ERRONEOUS INFO IN DATABASE.'/ 2 ' ERROR CODE =',I2/) STOP END C I/O ROUTINES (SPEAK, PSPEAK, RSPEAK, GETIN, YES, A5TOA1) SUBROUTINE SPEAK(N) C PRINT THE MESSAGE IN RECORD N OF THE RANDOM ACCESS MESSAGE FILE. C PRECEDE IT WITH A BLANK LINE UNLESS BLKLIN IS FALSE. INTEGER*2 RTEXT,ASCVAR,N,OLDLOC,LOC2(2),ASC2,ASC3,OLDASC LOGICAL BLKLIN REAL LINES(15),HNULL,HBLANK,LINES2(15,2) COMMON /TXTCOM/ LINES,ASCVAR COMMON /BLKCOM/ BLKLIN DATA HNULL/'>$< '/,HBLANK/' '/,OLDASC/0/ C ASCVAR=N IF(N.EQ.0)RETURN ASC3=(ASCVAR-1)/2+1 ASC2=MOD((ASCVAR-1),2)+1 IF (OLDASC.NE.ASC3) READ(6,REC=ASC3) LOC2,LINES2 LOC=LOC2(ASC2) DO 10 IJ=1,15 10 LINES(IJ)=LINES2(IJ,ASC2) OLDASC=ASC3 ASCVAR=ASCVAR+1 IF(LINES(1).EQ.HNULL)RETURN IF(BLKLIN) WRITE(3,2) 1 OLDLOC = LOC DO 3 I2=1,15 I=16-I2 L = I IF(LINES(I) .NE. HBLANK) GO TO 5 3 CONTINUE 5 WRITE(3,2) (LINES(I),I=1,L) 2 FORMAT(1X,15A4) ASC3=(ASCVAR-1)/2+1 ASC2=MOD((ASCVAR-1),2)+1 IF (OLDASC.NE.ASC3) READ(6,REC=ASC3) LOC2,LINES2 LOC=LOC2(ASC2) DO 11 IJ=1,15 11 LINES(IJ)=LINES2(IJ,ASC2) OLDASC=ASC3 ASCVAR=ASCVAR+1 IF(LOC .EQ. OLDLOC) GO TO 1 RETURN END SUBROUTINE PSPEAK(MSG,SKIP) C FIND THE SKIP+1ST MESSAGE FROM MSG AND PRINT IT. MSG SHOULD BE THE INDEX OF C THE INVENTORY MESSAGE FOR OBJECT. (INVEN+N+1 MESSAGE IS PROP=N MESSAGE). INTEGER*2 RTEXT,PTEXT,ASCVAR INTEGER SKIP,OLDLOC,ASC2,ASC3,OLDASC,LOC2(2) LOGICAL I,IS1 REAL LINES,LINES2(15,2) DIMENSION LINES(15),PTEXT(100) COMMON /TXTCOM/ LINES,ASCVAR COMMON /PTXCOM/ PTEXT DATA OLDASC/0/ M=PTEXT(MSG) IF(SKIP.LT.0)GOTO 9 IS1=SKIP+2 OLDLOC=-1 DO 3 I=1,IS1 1 ASC3=(M-1)/2+1 ASC2=MOD((M-1),2)+1 IF (OLDASC.NE.ASC3) READ(6,REC=ASC3) LOC2,LINES2 LOC=LOC2(ASC2) DO 11 IJ=1,15 11 LINES(IJ)=LINES2(IJ,ASC2) OLDASC=ASC3 M=M+1 IF (OLDLOC .EQ. LOC) GO TO 1 OLDLOC=LOC 3 CONTINUE M=M-1 9 CALL SPEAK(M) RETURN END SUBROUTINE RSPEAK(I) C PRINT THE I-TH "RANDOM" MESSAGE (SECTION 6 OF DATABASE). INTEGER*2 RTEXT,ASCVAR IF(I.NE.0)CALL SPEAK(RTEXT(I)) RETURN END SUBROUTINE MSPEAK(I) C PRINT THE I-TH "MAGIC" MESSAGE (SECTION 12 OF DATABASE). INTEGER*2 MTEXT,ASCVAR DIMENSION MTEXT(35) COMMON /MTXCOM/ MTEXT IF(I.NE.0)CALL SPEAK(MTEXT(I)) RETURN END SUBROUTINE GETIN(WORD1,WORD1X,WORD2,WORD2X) C GET A COMMAND FROM THE ADVENTURER. SNARF OUT THE FIRST WORD, PAD IT WITH C BLANKS, AND RETURN IT IN WORD1. CHARS 5 THRU 8 ARE RETURNED IN WORD1X, IN C CASE WE NEED TO PRINT OUT THE WHOLE WORD IN AN ERROR MESSAGE. ANY NUMBER OF C BLANKS MAY FOLLOW THE WORD. IF A SECOND WORD APPEARS, IT IS RETURNED IN C WORD2 (CHARS 5 THRU 8 IN WORD2X), ELSE WORD2 IS SET TO ZERO. INTEGER ST2 REAL WORD1,WORD1X,WORD2,WORD2X,A1(2),A2(2) LOGICAL W1(8),W2(8),CR,BL INTEGER IBL(8) LOGICAL BLKLIN LOGICAL IL,LA,LZ LOGICAL*1 FRST(20) COMMON /BLKCOM/ BLKLIN EQUIVALENCE (A1(1),W1(1)), (A2(1),W2(1)) EQUIVALENCE (W1(1),IBL(1)),(W2(1),IBL(5)) EQUIVALENCE (IL,FRST(1)) DATA LA,LZ/'A','Z'/ DATA CR,BL/X'0D',' '/ DO 99 IL=1,8 99 IBL(IL)=' ' IF(BLKLIN) WRITE(3,1) 1 FORMAT(1X) WRITE(3,103) 103 FORMAT(1X,'->') 2 READ(3,3) FRST 3 FORMAT(20A1) DO 2000 I=1,20 IF (FRST(I) .EQ. CR) FRST(I)=BL IF(LA .LE. FRST(I) .AND. FRST(I) .LE. LZ) FRST(I) = 2 FRST(I)+BL 2000 CONTINUE ST2 = 1 IX1 = 0 IX2 = 0 I = 0 10 I = I + 1 IF(I .GT. 20) GO TO 2 IF(FRST(I) .EQ. BL) GO TO 10 15 IX1 = IX1 + 1 IF (IX1 .LE. 8) W1(IX1)=FRST(I) I = I + 1 IF(I .GT. 20) GO TO 500 IF(FRST(I) .NE. BL) GO TO 15 20 I = I + 1 IF(I .GT. 20) GO TO 500 IF(FRST(I) .EQ. BL) GO TO 20 ST2 = I 25 IX2 = IX2 + 1 IF (IX2 .LE. 8) W2(IX2)=FRST(I) I = I + 1 IF(I .GT. 20) GO TO 500 IF(FRST(I) .NE. BL) GO TO 25 500 WORD1=A1(1) WORD1X=A1(2) WORD2 = 0. IF(IX2 .EQ. 0) RETURN WORD2=A2(1) WORD2X=A2(2) RETURN END LOGICAL FUNCTION YES(X,Y,Z) C CALL YESX (BELOW) WITH MESSAGES FROM SECTION 6. INTEGER X,Y,Z EXTERNAL RSPEAK LOGICAL YESX YES=YESX(X,Y,Z,RSPEAK) RETURN END LOGICAL FUNCTION YESM(X,Y,Z) C CALL YESX (BELOW) WITH MESSAGES FROM SECTION 12. INTEGER X,Y,Z EXTERNAL MSPEAK LOGICAL YESX YESM=YESX(X,Y,Z,MSPEAK) RETURN END LOGICAL FUNCTION YESX(X,Y,Z,SPK) C PRINT MESSAGE X, WAIT FOR YES/NO ANSWER. IF YES, PRINT Y AND LEAVE YEA C TRUE; IF NO, PRINT Z AND LEAVE YEA FALSE. SPK IS EITHER RSPEAK OR MSPEAK. INTEGER X,Y,Z REAL REPLY,JUNK1,JUNK2,JUNK3,HY1,HY2,HN1,HN2 DATA HY1,HY2,HN1,HN2/'y ','yes ','n ','no '/ 1 IF(X.NE.0)CALL SPK(X) CALL GETIN(REPLY,JUNK1,JUNK2,JUNK3) IF(REPLY.EQ.HY1.OR.REPLY.EQ.HY2)GOTO 10 IF(REPLY.EQ.HN1.OR.REPLY.EQ.HN2)GOTO 20 WRITE(3,9) 9 FORMAT(/' Please answer the question.') GOTO 1 10 YESX=.TRUE. IF(Y.NE.0)CALL SPK(Y) RETURN 20 YESX=.FALSE. IF(Z.NE.0)CALL SPK(Z) RETURN END REAL FUNCTION ATAB(I) REAL BUF(32) DATA N/0/ J=1+(I-1)/32 K=MOD(I,32) IF (K .EQ. 0) K=32 IF (J .EQ. N) GO TO 1 N=J READ(7,REC=N)BUF 1 ATAB=BUF(K) RETURN END C INTEGER FUNCTION KTAB(N) KTAB=IDISK(9,1,1,N) C WRITE(3,100)N,KTAB C 100 FORMAT(1X,'KTAB(',I3,')=',I4) RETURN END