{$S+} 
PROGRAM ADVENTURE;

CONST
  {$I advxcons.text }
  VERSION = 500;
  KEYS = 1;
  LAMP = 2;
  GRATE = 3;
  CAGE = 4;
  ROD = 5;
  ROD2 = 6;
  STEPS = 7;
  BIRD = 8;
  DOOR = 9;
  PILLOW = 10;
  SNAKE = 11;
  FISSURE = 12;
  TABLET = 13;
  CLAM = 14;
  OYSTER = 15;
  MAGAZINE = 16;
  DWARF = 17;
  KNIFE = 18;
  FOOD = 19;
  BOTTLE = 20;
  WATER = 21;
  OIL = 22;
  MIRROR = 23;
  PLANT = 24;
  PLANT2 = 25;
  AXE = 28;
  DRAGON = 31;
  CHASM = 32;
  TROLL = 33;
  TROLL2 = 34;
  BEAR = 35;
  MESSAGE = 36;
  VEND_MACHINE = 38;
  BATTERY = 39;
  wizard = 41;
  door2 = 42;
  ball = 43;
  
  NUGGET = 50;
  COINS = 54;
  CHEST = 55;
  EGGS = 56;
  TRIDENT = 57;
  VASE = 58;
  EMERALD = 59;
  PYRAMID = 60;
  PEARL = 61;
  RUG = 62;
  SPICES = 63;
  CHAIN = 64;
  jade = 68;
  scroll = 70;
  
  BACK = 8;
  NULL = 21;
  LOOK = 57;
  DEPRESSION = 63;
  ENTRANCE = 64;
  CAVE = 67;
  
  SAY = 3;
  LOCK = 6;
  THROW = 17;
  FIND = 19;
  INVENTORY = 20;
  
  MAXTRS = 73;
  MAXDIE = 3;
  MAXHLD = 6;
  DALTLC = 18;

TYPE
  CH512 = PACKED ARRAY[1..512] OF CHAR;
  CHAR6 = PACKED ARRAY[1..6] OF CHAR;
  ARYS = RECORD
           CASE BOOLEAN OF
             FALSE : (DBLK    : CH512);
             TRUE  : (TRAVEL  : ARRAY[1..trvsiz] OF INTEGER;
                      TRAVEL2 : ARRAY[1..trvsiz] OF INTEGER;
                      TRAVEL3 : ARRAY[1..trvsiz] OF INTEGER;
                      ATAB    : ARRAY[1..tabsiz] OF STRING[5];
                      KTAB    : ARRAY[1..tabsiz] OF INTEGER;
                      LTEXT   : ARRAY[1..locsiz] OF INTEGER;
                      STEXT   : ARRAY[1..locsiz] OF INTEGER;
                      KEY     : ARRAY[1..locsiz] OF INTEGER;
                      PLAC    : ARRAY[1..100] OF INTEGER;
                      FIXD    : ARRAY[1..100] OF INTEGER;
                      PTEXT   : ARRAY[1..100] OF INTEGER;
                      ACTSPK  : ARRAY[1..vrbsiz] OF INTEGER;
                      RTEXT   : ARRAY[1..rtxsiz] OF INTEGER;
                      CTEXT   : ARRAY[1..clsmax] OF INTEGER;
                      CVAL    : ARRAY[1..clsmax] OF INTEGER;
                      HINTS   : ARRAY[1..hntmax, 1..4] OF INTEGER;
                      pad     : packed array [ 1..70 ] of char) {round out
                                                              19 blocks - gws }
         END;
  VARYS = RECORD
            CASE BOOLEAN OF
              FALSE : (DBLK   : CH512);
              TRUE  : (COND   : ARRAY[1..locsiz] OF INTEGER;
                       ABB    : ARRAY[1..locsiz] OF INTEGER;
                       ATLOC  : ARRAY[1..locsiz] OF INTEGER;
                       PLACE  : ARRAY[1..100] OF INTEGER; 
                       FIXED  : ARRAY[1..100] OF INTEGER;
                       LINK   : ARRAY[1..200] OF INTEGER;
                       PROP   : ARRAY[1..100] OF INTEGER;
                       HINTLC : ARRAY[1..hntmax] OF INTEGER;
                       HINTED : ARRAY[1..hntmax] OF BOOLEAN;
                       DSEEN  : ARRAY[1..6] OF BOOLEAN;
                       DLOC   : ARRAY[1..6] OF INTEGER;
                       ODLOC  : ARRAY[1..6] OF INTEGER;
                       TK     : ARRAY[1..20] OF INTEGER;
                       PADDER : PACKED ARRAY [ 1..444 ] OF CHAR) {round out
                                                                5 blocks - gws}
          END;
  VBLS = RECORD
           CASE BOOLEAN OF
             FALSE : (DBLK : CH512);
             TRUE  : (HLDING, LOC, OLDLOC : INTEGER;
                      OLDLC2, CLOCK1, CLOCK2 : INTEGER;
                      CHLOC,CHLOC2, TALLY, TALLY2 : INTEGER;
                      DFLAG, DTOTAL, FOOBAR, TURNS : INTEGER;
                      VERB, OBJ, LIMIT, IWEST, KNFLOC : INTEGER;
                      ABBNUM, DKILL, NUMDIE, DETAIL : INTEGER;
                      PANIC, CLOSING, CLOSED, WZDARK : BOOLEAN;
                      wizflg, stflag, VERSION : INTEGER;
                      PASSWORD : STRING[20])
         END;

VAR
  NEWLOC, RESTART, I, J, K, KK, K2 : INTEGER;
  MAXSCORE, TVCOND, ATTACK, STICK : INTEGER;
  FOO, SCORE, HINT, SPK : INTEGER;
  wizbo, BONUS, SEED : INTEGER;
  RESUME, OK, SKIPIT, STEAL : BOOLEAN;
  GAVEUP, YEA, SKIPDWARF, ALLDONE, HE_DIED, PIT : BOOLEAN; 
  NEWLOCSET, LMWARN, SKIPDESCRIBE : BOOLEAN;
  HNTSIZ, CLSSES : INTEGER;
  ARY : ^ARYS;
  VARY : ^VARYS;
  VBL : ^VBLS;
  LINE, TERMWIDTH, TERMHIGHT : INTEGER;
  KKWORD, WD1, WD2 : STRING[5];
  WD1X, WD2X : STRING;
  ACHAR : STRING[1];
  TESTPW : STRING[20];
  NAMEOFUSER : STRING[40];
  INFILE : FILE;
  MSGFILE : FILE OF CHAR6;

  PROCEDURE READINIT(VAR BFR : CH512; NUM : INTEGER); forward;
  
  
  segment PROCEDURE INITIALIZE;

  VAR
    I, J, K, X : INTEGER;
    ININFO : TEXT;


    PROCEDURE INITP2;

    VAR
      I, J : INTEGER;

    BEGIN { INITP2 }
      TIME(I, J);
      IF J = 0 THEN J := I;
      WHILE J = 0 DO
        BEGIN
          WRITELN('No clock.');
          WRITELN('Please enter a number from 1 to 32767 ');
          READ(J);
          WRITELN
        END;
      IF (J MOD 2) = 0 THEN J := J + 1;
      SEED := J;
      LINE := 1;
      VARY^.DLOC[1] := 19;
      VARY^.DLOC[2] := 27; 
      VARY^.DLOC[3] := 33;
      VARY^.DLOC[4] := 44;
      VARY^.DLOC[5] := 64;
      VARY^.DLOC[6] := 114;
      vbl^.wizflg := 0;
      vbl^.stflag := 0;
      VBL^.CHLOC := 86;
      VBL^.CHLOC2 := 140;
      VBL^.ABBNUM := 5;
      BONUS := 0;
      VBL^.OLDLOC := 0;
      VBL^.OLDLC2 := 0;
      RESTART := 0;
      KK := 0;
      VBL^.TALLY := 0;
      VBL^.TALLY2 := 0;
      TVCOND := 0;
      VBL^.DKILL := 0;
      VBL^.DFLAG := 0;
      VBL^.DTOTAL := 0;
      ATTACK := 0;
      STICK := 0;
      VBL^.KNFLOC := 0;
      MAXSCORE := 0;
      VBL^.FOOBAR := 0;
      VBL^.TURNS := 0;
      VBL^.VERB := 0;
      VBL^.OBJ := 0;
      VBL^.IWEST := 0;
      FOO := 0;
      VBL^.NUMDIE := 0;
      SCORE := 0;
      VBL^.DETAIL := 0;
      VBL^.HLDING := 0;
      SPK := 0;
      OK := FALSE;
      SKIPIT := FALSE;
      STEAL := FALSE;
      VBL^.PANIC := FALSE;
      VBL^.CLOSING := FALSE;
      VBL^.CLOSED := FALSE;
      VBL^.WZDARK := FALSE;
      GAVEUP := FALSE;
      SKIPDWARF := FALSE;
      ALLDONE := FALSE;
      LMWARN := FALSE;
      SKIPDESCRIBE := FALSE;
      ALLDONE := FALSE;
      HE_DIED := FALSE;
      PIT := FALSE;
      NEWLOCSET := FALSE;
      KKWORD := '';
      WD1 := '';
      WD2 := '';
      WD1X := '';
      WD2X := '';
      ACHAR := ' '
    END;  { INITP2 }


  BEGIN { INITIALIZE }
    { READ IN ARRAYS }
    {$I-}
    RESET(ININFO, 'ADV.MISCINFO');
    {$I+}
    IF IORESULT = 0 THEN
      BEGIN
        READ(ININFO, TERMHIGHT, TERMWIDTH);
        CLOSE(ININFO)
      END
    ELSE
      BEGIN
        TERMHIGHT := 24;  { DEFAULT FOR APPLE }
        TERMWIDTH := 40
      END;
    RESET(INFILE, 'ADVxDATA');
    RESET(MSGFILE, 'ADVxMSGS');
    NEW(ARY);
    READINIT(ARY^.DBLK, SIZEOF(ARYS));
    NEW(VARY);
    READINIT(VARY^.DBLK, SIZEOF(VARYS));
    CLOSE(INFILE);
    NEW(VBL);
    INITP2;
    CLSSES := 0;
    FOR I := 1 TO clsmax DO IF ARY^.CTEXT[I] <> 0 THEN CLSSES := I;
    FOR I := 4 TO hntmax DO IF ARY^.HINTS[I, 1] <> 0 THEN HNTSIZ := I;
    FOR X := 50 TO 100 DO
      IF ARY^.PTEXT[X] <> 0 THEN VBL^.TALLY := VBL^.TALLY - VARY^.PROP[X];
    FOR I := 1 TO tabsiz DO
      IF ARY^.ATAB[I] = '' THEN
        BEGIN
          ARY^.ATAB[I] := '     ';
          ARY^.ATAB[I, 1] := CHR(255);
          ARY^.ATAB[I, 2] := CHR(I DIV 256);
          ARY^.ATAB[I, 3] := CHR(I MOD 256)
        END
  END;  { INITIALIZE }

  {$I ADVXSEGS  .TEXT }

  SEGMENT PROCEDURE DOWHATHESAYS;

  {$I ADVxVERB.TEXT }

    PROCEDURE ANALANOBJ;


      PROCEDURE ASKWHATTODO;

      BEGIN
        IF WD2 <> '' THEN
          BEGIN
            RESTART := 1;
            EXIT(ANALANOBJ)
          END;
        IF VBL^.VERB <> 0 THEN
          BEGIN
            ANALATVERB;
            EXIT(ANALANOBJ)
          END;
        WRITELN('What do you want to do with the ', WD1, WD1X, '.');
        RESTART := 1;
        EXIT(DOWHATHESAYS)
      END;  { ASKWHATTODO }


    BEGIN { ANALANOBJ }
      VBL^.OBJ := K;
      IF (VARY^.FIXED[K] = VBL^.LOC) OR HERE(K) THEN ASKWHATTODO;
      IF K = GRATE THEN
        BEGIN
          IF (VBL^.LOC = 1) OR (VBL^.LOC = 4) OR (VBL^.LOC = 7) THEN
             K := DEPRESSION;
          IF (VBL^.LOC > 9) AND (VBL^.LOC < 15) THEN K := ENTRANCE;
          IF K <> GRATE THEN
            BEGIN
              SET_NEW_LOC;
              EXIT(ANALANOBJ)
            END
        END;
      IF K = DWARF THEN
        FOR I := 1 TO 5 DO
          IF (VARY^.DLOC[I] = VBL^.LOC) AND (VBL^.DFLAG >= 2) THEN ASKWHATTODO;
      IF ((LIQ = K) AND HERE(BOTTLE)) OR (K = LIQLOC(VBL^.LOC)) THEN
        ASKWHATTODO;
      IF (VBL^.OBJ = PLANT) AND AT(PLANT2) AND (VARY^.PROP[PLANT2] = 0) THEN
        BEGIN
          VBL^.OBJ := PLANT2;
          ASKWHATTODO
        END;
      if ( vbl^.obj = door ) and at ( door2 ) then
         begin
            vbl^.obj := door2;
            askwhattodo;
         end;  
      IF (VBL^.OBJ = KNIFE) AND (VBL^.KNFLOC = VBL^.LOC) THEN
        BEGIN
          VBL^.KNFLOC := -1;
          SPEAK(ARY^.RTEXT[116])
        END
      ELSE
        IF (VBL^.OBJ = ROD) AND HERE(ROD2) THEN
          BEGIN
            VBL^.OBJ := ROD2;
            ASKWHATTODO
          END
        ELSE
          IF ((VBL^.VERB = FIND) OR (VBL^.VERB = INVENTORY)) AND
            (WD2 = '') THEN
            ASKWHATTODO
          ELSE
            WRITELN('I see no ', WD1, WD1X, ' here.');
      SKIPDWARF := TRUE;
      SKIPDESCRIBE := TRUE;
      EXIT(DOWHATHESAYS)
    END;  { ANALANOBJ }


    PROCEDURE ANALAVERB;

    BEGIN
      VBL^.VERB := K;
      SPK := ARY^.ACTSPK[VBL^.VERB];
      IF (WD2 <> '') AND (VBL^.VERB <> SAY) THEN
        BEGIN
          RESTART := 1;
          EXIT(ANALAVERB)
        END;
      IF VBL^.VERB = SAY THEN
        IF WD2 = '' THEN
          ANALANITVERB
        ELSE
          ANALATVERB
      ELSE
        IF VBL^.OBJ = 0 THEN
          ANALANITVERB
        ELSE
          ANALATVERB
    END;  { ANALAVERB }


    PROCEDURE CLOSE1;

    BEGIN 
      VARY^.PROP[GRATE] := 0;
      VARY^.PROP[FISSURE] := 0;
      FOR I := 1 TO 6 DO VARY^.DSEEN[I] := FALSE;
      MOVE(TROLL,0);
      MOVE(TROLL + 100, 0);
      MOVE(TROLL2, ARY^.PLAC[TROLL]);
      MOVE(TROLL2 + 100, VARY^.FIXED[TROLL]);
      JUGGLE(CHASM);
      IF VARY^.PROP[BEAR] <> 3 THEN DESTROY(BEAR);
      VARY^.PROP[CHAIN] := 0;
      VARY^.FIXED[CHAIN] := 0;
      VARY^.PROP[AXE] := 0;
      VARY^.FIXED[AXE] := 0;
      SPEAK(ARY^.RTEXT[129]);
      VBL^.CLOCK1 := -1;
      VBL^.CLOSING := TRUE
    END;  { CLOSE1 }


    PROCEDURE CLOSE2;

    BEGIN
      VARY^.PROP[BOTTLE] := PUT(BOTTLE, 115, 1);
      VARY^.PROP[PLANT] := PUT(PLANT, 115, 0);
      VARY^.PROP[OYSTER] := PUT(OYSTER, 115, 0);
      VARY^.PROP[LAMP] := PUT(LAMP, 115, 0);
      VARY^.PROP[ROD] := PUT(ROD, 115, 0);
      VARY^.PROP[DWARF] := PUT(DWARF, 115, 0);
      VBL^.LOC := 115;
      VBL^.OLDLOC := 115;
      NEWLOC := 115;
      FOO := PUT(GRATE, 116, 0);
      VARY^.PROP[SNAKE] := PUT(SNAKE, 116, 1);
      VARY^.PROP[BIRD] := PUT(BIRD, 116, 1);
      VARY^.PROP[CAGE] := PUT(CAGE, 116, 0);
      VARY^.PROP[ROD2] := PUT(ROD2, 116, 0);
      VARY^.PROP[PILLOW] := PUT(PILLOW, 116, 0);
      VARY^.PROP[MIRROR] := PUT(MIRROR, 115, 0);
      VARY^.FIXED[MIRROR] := 116;
      FOR I := 1 TO 100 DO
        IF TOTING(I) THEN DESTROY(I);
      SPEAK(ARY^.RTEXT[132]);
      VBL^.CLOSED := TRUE;
      EXIT(DOWHATHESAYS)
    END;  { CLOSE2 }


  BEGIN { DOWHATHESAYS }
    IF VBL^.FOOBAR > 0 THEN
      VBL^.FOOBAR := -VBL^.FOOBAR
    ELSE
      VBL^.FOOBAR := 0;
    VBL^.TURNS := VBL^.TURNS + 1;
    if wd1 = 'DESCR' then
      begin
        speak(ary^.ltext[vbl^.loc]);
        restart := 1;
        exit(dowhathesays)
      end;
    K := SAY;
    IF (VBL^.VERB = SAY) AND (WD2 <> '') THEN VBL^.VERB := 0;
    IF VBL^.VERB <> SAY THEN
      BEGIN
        IF (VBL^.TALLY = 0) AND 
           (VBL^.LOC >= 15) AND 
           (VBL^.LOC <> 33) and
           (vbl^.loc <= 140 ) THEN
          VBL^.CLOCK1 := VBL^.CLOCK1 - 1;
        IF VBL^.CLOCK1 = 0 THEN
          CLOSE1
        ELSE
          IF VBL^.CLOCK1 < 0 THEN VBL^.CLOCK2 := VBL^.CLOCK2 - 1;
        IF VBL^.CLOCK2 = 0 THEN
          CLOSE2
        ELSE
          BEGIN
            IF VARY^.PROP[LAMP] = 1 THEN VBL^.LIMIT := VBL^.LIMIT - 1;
            IF (VBL^.LIMIT <= 30) AND HERE(BATTERY) AND
              (VARY^.PROP[BATTERY] = 0) AND HERE(LAMP) THEN
              BEGIN
                SPEAK(ARY^.RTEXT[188]);
                VARY^.PROP[BATTERY] := 1;
                IF TOTING(BATTERY) THEN DROP(BATTERY, VBL^.LOC);
                VBL^.LIMIT := VBL^.LIMIT + 2500;
                LMWARN := FALSE
              END
            ELSE
              IF VBL^.LIMIT = 0 THEN
                BEGIN
                  VBL^.LIMIT := -1;
                  VARY^.PROP[LAMP] := 0;
                  IF HERE(LAMP) THEN SPEAK(ARY^.RTEXT[184])
                END
              ELSE
                IF (VBL^.LIMIT < 0) AND (VBL^.LOC <= 8) THEN
                  BEGIN
                    SPEAK(ARY^.RTEXT[185]);
                    ALLDONE := TRUE;
                    GAVEUP := TRUE;
                    EXIT(DOWHATHESAYS)
                  END
                ELSE
                  IF VBL^.LIMIT <= 30 THEN
                    BEGIN
                      IF NOT LMWARN AND HERE(LAMP) THEN
                        BEGIN
                          LMWARN := TRUE;
                          SPK := 187;
                          IF VARY^.PLACE[BATTERY] = 0 THEN SPK := 183;
                          IF VARY^.PROP[BATTERY] = 1 THEN SPK := 189;
                          SPEAK(ARY^.RTEXT[SPK])
                        END
                    END;
            K := 43;  { WHERE? }
            IF LIQLOC(VBL^.LOC) = WATER THEN K := 70;
            IF (WD1 = 'ENTER') AND ((WD2 = 'STREA') OR (WD2 = 'WATER')) THEN
              BEGIN
                SPEAK(ARY^.RTEXT[K]);
                SKIPDWARF := TRUE;
                SKIPDESCRIBE := TRUE
              END
            ELSE
              REPEAT
                RESTART := 0;
                IF (WD1 = 'ENTER') AND (WD2 <> '') THEN
                  BEGIN
                    WD1 := WD2;
                    WD1X := WD2X;
                    if (wd1 = 'DOOR') and at(door2) then wd1 := 'DOOR2';
                    WD2 := ''
                  END
                ELSE
                  BEGIN
                    IF ((WD1 = 'WATER') OR (WD1 = 'OIL')) AND
                      ((WD2 = 'PLANT') OR (WD2 = 'DOOR')) THEN
                        IF AT(VOCAB(WD2,1)) THEN WD2 := 'POUR'
                  END;
                IF WD1 = 'WEST' THEN
                  BEGIN
                    VBL^.IWEST := VBL^.IWEST + 1;
                    IF VBL^.IWEST = 10 THEN SPEAK(ARY^.RTEXT[17])
                  END;
                I := VOCAB(WD1, -1);
                IF I = -1 THEN
                  BEGIN
                    SPK := 60;
                    IF PERCENT(20) THEN SPK := 61;
                    IF PERCENT(20) THEN SPK := 13;
                    SPEAK(ARY^.RTEXT[SPK]);
                    RESTART := 1;
                    EXIT(DOWHATHESAYS)
                  END
                ELSE
                  BEGIN
                    K := I MOD 1000;
                    CASE (I DIV 1000) OF
                      0 : SET_NEW_LOC;
                      1 : ANALANOBJ;
                      2 : ANALAVERB;
                      3 : BEGIN
                            SKIPDWARF := TRUE;
                            SKIPDESCRIBE := TRUE;
                            IF K <> 0 THEN SPEAK(ARY^.RTEXT[K])
                          END
                    END;
                    IF RESTART <> 0 THEN
                      BEGIN
                        WD1 := WD2;
                        WD1X := WD2X;
                        WD2 := ''
                      END
                  END
              UNTIL RESTART = 0  { SHORT RESTART }
          END
      END
  END;  { DOWHATHESAYS }

 (*$I ADVXSUBS.TEXT *)

  PROCEDURE REINCARNATION;

  BEGIN
    IF HE_DIED THEN
      BEGIN
        IF PIT THEN
          BEGIN
            SPEAK(ARY^.RTEXT[23]);
            VBL^.OLDLC2 := VBL^.LOC
          END;
        IF VBL^.CLOSING THEN
          BEGIN
            SPEAK(ARY^.RTEXT[131]);
            VBL^.NUMDIE := VBL^.NUMDIE + 1
          END
        ELSE
          BEGIN
            YEA := YES(81 + (VBL^.NUMDIE * 2), 82 + (VBL^.NUMDIE * 2), 54);
            VBL^.NUMDIE := VBL^.NUMDIE + 1;
            IF (VBL^.NUMDIE <> MAXDIE) AND YEA THEN
              BEGIN
                HE_DIED := FALSE;  { SAVED! }
                SKIPDWARF := TRUE;
                VARY^.PLACE[WATER] := 0;
                VARY^.PLACE[OIL] := 0;
                IF TOTING(LAMP) THEN VARY^.PROP[LAMP] := 0;
                FOR J := 100 DOWNTO 1 DO
                  IF TOTING(J) THEN
                    BEGIN
                      K := VBL^.OLDLC2;
                      IF J = LAMP THEN K := 1;
                      DROP(J, K)
                    END;
                VBL^.LOC := 3;
                VBL^.OLDLOC := VBL^.LOC
              END
          END
      END
  END;  { REINCARNATION }


  PROCEDURE ENDGAME;

  BEGIN
    SCORE := GETSCORE(FALSE);
    WRITELN;
    WRITE('You scored ', SCORE, ' out of a possible ', MAXSCORE);
    IF TERMWIDTH < 64 THEN WRITELN;
    IF VBL^.TURNS = 1 THEN
      KKWORD := '.'
    ELSE
      KKWORD := 's.';
    WRITELN(' using ', VBL^.TURNS, ' turn', KKWORD);
    FOR I := 1 TO CLSSES DO
      IF ARY^.CVAL[I] >= SCORE THEN
        BEGIN
          SPEAK(ARY^.CTEXT[I]);
          IF I = CLSSES THEN
            BEGIN
              WRITE('To achieve the next higher rating would ');
              IF TERMWIDTH < 64 THEN WRITELN;
              WRITELN('be a neat trick!');
              WRITELN;
              WRITELN('Congratulations.')
            END
          ELSE
            BEGIN
              K := ARY^.CVAL[I] + 1 - SCORE;
              KKWORD := 's.';
              IF K = 1 THEN KKWORD := '.';
              WRITE('To achieve the next higher rating, you need ');
              IF TERMWIDTH < 64 THEN WRITELN;
              WRITELN(K, ' more point', KKWORD)
            END;
          I := CLSSES  { EXIT THIS MESS }
      END
  END;  { ENDGAME }

  PROCEDURE READINIT{VAR BFR : CH512; NUM : INTEGER};

  BEGIN
    NUM := (NUM + 511) DIV 512;
    IF NUM <> BLOCKREAD(INFILE, BFR, NUM) THEN
      BEGIN
        WRITE('Error reading array file.');
        EXIT(ADVENTURE)
      END
  END;  { READINIT }

  PROCEDURE GETNEWCOMMAND;  

  VAR
    W1FLAG, DONE : BOOLEAN;
    INLINE : STRING;

  BEGIN { GETNEWCOMMAND }
    IF VBL^.CLOSED THEN
      BEGIN
        IF (VARY^.PROP[OYSTER] < 0) AND TOTING(OYSTER) THEN PSPEAK(OYSTER, 1);
        FOR I := 1 TO 100 DO
          IF TOTING(I) AND (VARY^.PROP[I] < 0) THEN
            VARY^.PROP[I] := -1 - VARY^.PROP[I]
      END;
    LINE := 1;
    WD1 := '';
    WD2 := '';
    WD1X := '';
    WD2X := '';
    VBL^.WZDARK := DARK;
    IF (VBL^.KNFLOC > 0) AND (VBL^.KNFLOC <> VBL^.LOC) THEN VBL^.KNFLOC := 0;
    I := RAN(1);
    REPEAT
      repeat
        READLN(INLINE);
      until length ( inline ) > 0;  {no null strings - gws}
      INLINE := CONCAT(INLINE, '  : ');
      WHILE INLINE[1] = ' ' DO DELETE(INLINE, 1, 1)
    UNTIL INLINE <> ' : ';
    W1FLAG := FALSE;
    DONE := FALSE;
    REPEAT
      ACHAR := COPY(INLINE, 1, 1);
      if achar[1] in ['a'..'z'] then achar[1] := chr(ord(achar[1]) - 32);
      DELETE(INLINE, 1, 1);
      IF ACHAR = ' ' THEN
        BEGIN
          DONE := W1FLAG;
          W1FLAG := TRUE
        END
      ELSE
        IF W1FLAG THEN
          IF LENGTH(WD2) = 5 THEN
            WD2X := CONCAT(WD2X, ACHAR)
          ELSE
            WD2 := CONCAT(WD2, ACHAR)
        ELSE
          IF LENGTH(WD1) = 5 THEN
            WD1X := CONCAT(WD1X, ACHAR)
          ELSE
            WD1 := CONCAT(WD1, ACHAR)
    UNTIL DONE
  END;  { GETNEWCOMMAND }



BEGIN { ADVENTURE }
  INITIALIZE;
  VARY^.HINTED[3] := YES(65, 1, 0);
  IF VARY^.HINTED[3] THEN
    RESUME := FALSE
  ELSE
    RESUME := YES(201, 0, 0);
  IF RESUME THEN
    BEGIN
      NAMEANDPW;
      {$I-}
      RESET(INFILE, NAMEOFUSER);
      {$I+}
      IF IORESULT <> 0 THEN
        BEGIN
          WRITELN('Sorry, you do not have a saved game.');
          RESUME := FALSE
        END
      ELSE
        BEGIN
          READINIT(VARY^.DBLK, SIZEOF(VARYS));
          READINIT(VBL^.DBLK, SIZEOF(VBLS)); 
          CLOSE(INFILE);
          IF TESTPW <> VBL^.PASSWORD THEN
            BEGIN
              WRITE('Incorrect password.');
              EXIT(ADVENTURE)
            END;
          IF VERSION <> VBL^.VERSION THEN
            BEGIN
              IF VERSION > VBL^.VERSION THEN
                WRITE('Old save file - new')
              ELSE
                WRITE('New save file - old');
              WRITE(' Adventure.  Sorry.');
              EXIT(ADVENTURE)
            END
        END;
      VBL^.LIMIT := MAX(VBL^.LIMIT, 150);  { GIVE HIM SOME TIME }
    END;
  IF NOT RESUME THEN
    BEGIN
      VBL^.LOC := 1;
      VBL^.CLOCK1 := 30;
      VBL^.CLOCK2 := 25;
      IF VARY^.HINTED[3] THEN
        VBL^.LIMIT := 1000
      ELSE
        VBL^.LIMIT := 330
    END;
  NEWLOC := VBL^.LOC;
  REPEAT
    REPEAT
      IF SKIPDWARF THEN
        SKIPDWARF := FALSE
      ELSE
        BEGIN
          TESTCLOSE;
          VBL^.LOC := NEWLOC;
          if (vbl^.loc = 149) and (vary^.prop[wizard] <> 1) then
            begin
              wizbo := ran(100);
              if wizbo <= 76 then
                begin
                  speak(ary^.rtext[211]);
                  if (wizbo >= 50) and (vbl^.wizflg <> 0) then
                    begin
                      speak(ary^.rtext[53]);
                      vbl^.oldlc2 := vbl^.loc;
                      he_died := true
                    end
                  else
                    begin
                      speak(ary^.rtext[52]); 
                      vbl^.wizflg := 1
                    end
                end
            end;
          IF not he_died and (VBL^.LOC <> 0) THEN
            IF NOT FORCED(VBL^.LOC) AND NOT BITSET(NEWLOC, 3) THEN
              IF VBL^.DFLAG = 0 THEN
                IF VBL^.LOC >= 15 THEN
                  VBL^.DFLAG := 1
                ELSE
              ELSE
                DWARFSTUFF
        END;
      NEWLOCSET := FALSE;
      IF NOT HE_DIED THEN
        BEGIN
          IF SKIPDESCRIBE THEN
            SKIPDESCRIBE := FALSE
          ELSE
            BEGIN
              WRITELN;
              DESCRIBE_CURRENT_LOCATION
            END;
          IF NOT HE_DIED AND NOT NEWLOCSET THEN
            BEGIN
              VBL^.VERB := 0;
              VBL^.OBJ := 0;
              RESTART := 0;
              REPEAT
                IF RESTART <> 2 THEN
                  BEGIN
                    CHECKHINTS;
                    GETNEWCOMMAND
                  END;
                RESTART := 0;
                DOWHATHESAYS
              UNTIL RESTART = 0;  { LONG RESTART }
            END
        END
    UNTIL HE_DIED OR ALLDONE;  { MAIN LOOP }
    REINCARNATION
  UNTIL HE_DIED OR ALLDONE;  { NO MORE RE-INCARNATIONS }
  ENDGAME
END.

