2 (*HEAL, ONUSPLAYER*):
      BEGIN
       PLAYER ^.HITS := MIN(PLAYER ^.MAXHITS, PLAYER ^.HITS + LEVEL * 3);
       WRITELN(PLAYER ^.TRM, 'YOU NOW HAVE ', PLAYER ^.HITS: 0, ' VITALITY POINTS.');
      END (*2*);
     3 (*FIREBALL, ONMONPLAYER*):
      IF 10 + LEVEL > RND(20)  THEN DAMAGE := MIN(INTEL * 2, 3 * (LEVEL + 1));
     4 (*LIGHTNING, ONMONPLAYER*):
      IF 8 + LEVEL > RND(20)
      THEN DAMAGE := MIN(20, 2 * (LEVEL + 1)) + RND(2 * INTEL);
     5 (*HURT, ONMONPLAYER*): DAMAGE := RND(2);
     6 (*CUREPOISON, ONUSPLAYER*):
      BEGIN
       PLAYER ^.POISONED := FALSE;
       WRITELN(PLAYER ^.TRM, 'THE VENOM HAS DISAPPEARED!');
      END (*6*);
     7 (*DISINTEGRATE, ONMONPLAYER*): DAMAGE := RND(5 * INTEL) + LEVEL * 2;
     8 (*BEFUDDLE, ONMON*):
      IF PLAYER <> NIL  THEN PLAYER ^.LASTATK := REALTIME + 30
      ELSE
       BEGIN
        MONSTER ^.MREACT := 4;  WRITELN(TERM, 'IT PAUSES FOR A MOMENT...');
        MONSTER ^.DEFPLAYER := NIL;
       END (*ELSE*);
     9 (*TELEPORT, ONUSPLAYER*):
      BEGIN
       DELETEPLAYER(PLAYER, PLAYER ^.RMCODE);  PLACEPLAYER(PLAYER, RND(570) + 30);
       WRITELN(PLAYER ^.TRM, '**POOF** YOU FIND THAT YOU ARE ELSEWHERE..');
      END (*9*);
     10: BEGIN WDATA := TARGET;  ENTRY := XWISH; END;
     11 (*PASSDOOR, ONOBJ*):
      IF NOT (OBJ ^.OBCLASS IN [DOOR, PORTAL])
      THEN WRITELN(TERM, 'CAN''T BE DONE!')
      ELSE
       IF NOT OBJ ^.MAGIC
       THEN
        BEGIN
         DELETEPLAYER(USER, USER ^.RMCODE);  PLACEPLAYER(USER, OBJ ^.TOWHERE);
         WRITELN(TERM, 'YOU PASS THROUGH THE PORTAL!')
        END (*IF*)
       ELSE WRITELN(TERM, 'A MAGIC BARRIER STOPS YOU FROM PASSING!');
     12 (*ENCHANT, ONOBJ*):
      IF NOT OBJ ^.CARRY  THEN WRITELN(TERM, 'ENCHANTMENT FAILS!')
      ELSE
       BEGIN OBJ ^.MAGIC := TRUE;  WRITELN(TERM, 'OK.  IT STARTS TO GLOW!');
       END (*ELSE*);
     13 (*BLESS, ONUSPLAYER*):
      IF (LVL < PLAYER^.LVL) AND (LVL < 10)
      THEN WRITELN(TERM, 'YOU ARE NOT WORTHY OF BLESSING THIS GREAT PERSON!')
      ELSE
       BEGIN
        PLAYER ^.PTY := MIN(25, PLAYER ^.PTY + 1);
        WRITELN(PLAYER ^.TRM, 'YOU FEEL PURIFIED AND WHOLE.')
       END (*ELSE*);
     14 (*PROTECT, ONUSER*):
      BEGIN
       STOPUSING(USER, USARM);  STOPUSING(USER, USSHIELD);  AC := MAX(8, AC - 1);
       WRITELN(TERM, 'YOU FEEL LIMBER AND STRONG..');
      END (*14*);
     15 (*CURSE,ONPLAYER*):
      BEGIN
       PLAYER ^.PTY := MAX(- 10, PLAYER ^.PTY - 1);
       WRITELN(PLAYER ^.TRM, 'YOU''VE BEEN CURSED!');
      END (*15*);
     16 (*POISON,ONUSPLAYER*):
      BEGIN
       PLAYER ^.POISONED := TRUE;  WRITELN(PLAYER ^.TRM, 'YOU''VE BEEN POISONED!')
      END (*16*);
     17 (*INTOXICATE,ONUSPLAYER*):
      BEGIN
       PLAYER ^.DRUNK := MAX(REALTIME, PLAYER ^.DRUNK) + 60;
       WRITELN(PLAYER ^.TRM, '(HIC) YOU FEEL TIPSY.')
      END (*17*);
    END (*CASE*);
   SPELLCASE := DAMAGE
  END (*SPELLCASE*);


 FUNCTION SPELLMON(SPELLNUM, LVL, INT: INTEGER; PLR: USERPOINT; MON: MONSTERPOINT;
   OBJ: OBJECTPOINT; TARGET: ALFA): INTEGER;

  BEGIN SPELLMON := SPELLCASE(SPELLNUM, LVL, INT, PLR, MON, OBJ, TARGET); END;


 PROCEDURE DOCMD(VAR BUFFER: BUFTYPE; LENBUF: LENBUFTYPE; VAR ROOM: ROOMLIST; VAR
   CMDLIST: CMDTYPELIST);
(* DOCMD RUNS ALL INPUT FROM THE "CMD-?" PROMPT.  THIS IS THE
CRITICAL ROUTINE WHERE ALL COMMANDS ARE EVALUATED AND EXECUTED.
IF THIS WERE A NON-MULTI TASK, THE ACTUAL PROGRAM WOULD START
HERE! *)

  VAR
   CMD, WORD: ALFA (* INPUTTED WORDS *);
   CH: CHAR;
   FOLCOUNT: INTEGER;



  FUNCTION SPELLCOST(USER: USERPOINT; COST, MINLVL, MININT: INTEGER): BOOLEAN;
(* SPELLCOST DEDUCTS MP FROM USERS WHO CAST SPELLS.  THEY MUST
MEET THE MINIMUM LEVEL AND MINIMUM INT QUALIFICATIONS TOO. *)

   BEGIN
    SPELLCOST := FALSE (*DEFAULT*);
    WITH USER ^ DO
     IF INT < MININT
     THEN WRITELN(TERM, 'YOU HAVE NOT THE INTELLIGENCE TO CAST THE SPELL!')
     ELSE
      BEGIN
       CASE CLASS OF
        FIGHTER: MINLVL := MINLVL + 4;
        THIEF: MINLVL := MINLVL + 3;
        CLERIC: MINLVL := MINLVL + 1;
        MAGICUSER:;
       OTHERWISE
        MINLVL := MINLVL + 2;
       END (*CASE*);
       IF MINLVL > LVL
       THEN WRITELN(TERM, 'YOU ARE NOT HIGH ENOUGH LEVEL TO CAST THE SPELL!')
       ELSE
        IF MAGIC - COST < 0
        THEN WRITELN(TERM, 'YOU HAVE NOT ENOUGH MAGIC LEFT TO CAST THE SPELL!')
        ELSE BEGIN MAGIC := MAGIC - COST;  SPELLCOST := TRUE END
      END (*ELSE*)
   END (*SPELLCOST*);


  PROCEDURE DISPDAY(NUM: INTEGER);
(* DUMP *NUM* RECORDS FROM THE GAME DAYFILE *)

   VAR
    CH: CHAR;

   BEGIN
    NUM := MAX(0, NUM);  GETSEG(DAYFILE, - (NUM + 1));
    WHILE NOT EOF(DAYFILE) DO
     BEGIN
      WHILE NOT EOS(DAYFILE) DO
       BEGIN
        WRITE(TERM);
        WHILE NOT EOLN(DAYFILE) DO BEGIN READ(DAYFILE, CH);  WRITE(CH) END;
        READLN(DAYFILE);  WRITELN;
       END (*WHILE*);
      GETSEG(DAYFILE)
     END (*WHILE*);
    ROLLCHECK(TERM);  SETDAYFILE;
   END (*DISPDAY*);




  PROCEDURE PRINTBREG;

   VAR
    B4, B5, B6: INTEGER;

   BEGIN
    BREG(B4, B5, B6);  WRITELN(TERM);  WRITELN(TERM, '   B4= ', B4: 5 OCT);
    WRITELN(TERM, '   B5= ', B5: 5 OCT);  WRITELN(TERM, '   B6= ', B6: 5 OCT);
    WRITELN(TERM);
   END (*PRINTBREG*);


  PROCEDURE GETOBJECT(WORD: ALFA; NUM: INTEGER; RM: RMCODETYPE);
(* *GET* WILL FETCH OBJECTS LAYING ON THE GROUND. WEIGHT IS
CUMULATIVE.  MONSTERS THAT GUARD WILL PROHIBIT PICKING ANYTHING
UP. *)

   VAR
    OBJ2, BOX, OBTAIL, OBJECT: OBJECTPOINT;
    MONSTER: MONSTERPOINT;
    NUM2, ILOOP: INTEGER;
    WORD2: ALFA;
    WHERE:
     (GROUND, CONTAINER, NOWHERE);
    HELD: BOOLEAN;


   FUNCTION GUARDING(MON: MONSTERPOINT): BOOLEAN;
(* GUARDING IS USED BY *MATCHMONSTER* TO CHECK FOR GUARDS *)

    BEGIN GUARDING := (MON ^.GUARD AND NOT HELD) END (*GUARDING*);


   BEGIN (*GETOBJECT*)
    ERRLOC := ' EIGHT    ';  HELD := FALSE;
    WITH ROOM[RM] DO
     BEGIN
      OBTAIL := RMOBJECTTAIL;  BOX := NIL;  WHERE := GROUND;
      OBJECT := FINDOBJECT(WORD, NUM, OBTAIL);
      GETWORD(WORD2, NUM2, BUFFER, LENBUF, LOC);
      IF (WORD2 <> BLANKS)
      THEN
       BEGIN
        BOX := FINDOBJECT(WORD2, NUM2, RMOBJECTTAIL);
        IF BOX = NIL THEN
         BEGIN
          BOX := FINDOBJECT(WORD2, NUM2, USER ^.OBJECTTAIL);
          IF BOX <> NIL  THEN HELD := TRUE
         END (*IF*);
        IF BOX <> NIL
        THEN
         IF BOX ^.OBCLASS = CHEST
         THEN
          IF NOT BOX ^.CLOSED
          THEN BEGIN OBTAIL := BOX ^.OBJECTTAIL;  WHERE := CONTAINER END
          ELSE
           BEGIN WHERE := NOWHERE;  WRITELN(TERM, 'YOU CAN''T.  IT''S CLOSED.'); END
         ELSE BEGIN WHERE := NOWHERE;  WRITELN(TERM, 'THAT IS NOT A CONTAINER.') END
        ELSE
         BEGIN WHERE := NOWHERE;  WRITELN(TERM, 'THAT CONTAINER ISNT HERE.'); END;
        IF WHERE = CONTAINER  THEN OBJECT := FINDOBJECT(WORD, NUM, OBTAIL);
       END (*IF*);
(* POINTER NOW EQUALS THE OBJECT SELECTED BY THE USER *)
      IF (OBJECT <> NIL) AND (WHERE <> NOWHERE)
      THEN
       IF NOT OBJECT ^.CARRY  THEN WRITELN(TERM, 'YOU ARE NOT ABLE TO TAKE THAT!')
       ELSE
        BEGIN
         MONSTER := MATCHMONSTER(RMMONSTERTAIL, GUARDING);
         IF MONSTER <> NIL
         THEN WRITELN(TERM, PM(MONSTER), 'STOPS YOU FROM GETTING IT!')
         ELSE
          IF (USER ^.WEIGHT + OBJECT ^.WEIGHT > USER ^.STR * 10) AND NOT HELD
          THEN WRITELN(TERM, 'IT''S TOO MUCH FOR YOU TO CARRY!')
          ELSE
           BEGIN
            IF DELETEOBJECT(OBJECT, OBTAIL)  THEN OBTAIL := OBTAIL ^.NEXT;
            WRITELN(TERM, 'OK');  OBJECT ^.INVISIBLE := FALSE;
            FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
             BEGIN
              WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' PICKED UP ');
              PRINTOBJ(OBJECT ^, TRUE);
              IF WHERE = CONTAINER
              THEN BEGIN WRITE(' FROM INSIDE ');  PRINTOBJ(BOX ^, TRUE) END;
              WRITELN('.');
             END (*FOR*);
            IF OBJECT ^.OBCLASS = COINS
            THEN
             BEGIN
              USER ^.MONEY := MIN(USER ^.MONEY + OBJECT ^.PRICE, 500000);
              WRITELN(TERM, 'YOU NOW HAVE ', USER ^.MONEY: 0, ' SHILLINGS IN CASH.');
              DISPOSE(OBJECT)
             END (*IF*)
            ELSE
             BEGIN
              IF NOT HELD
              THEN USER ^.WEIGHT := MIN(2500, USER ^.WEIGHT + OBJECT ^.WEIGHT);
              IF USER ^.OBJECTTAIL = NIL
              THEN BEGIN OBJECT ^.NEXT := NIL;  USER ^.OBJECTTAIL := OBJECT; END
              ELSE
               BEGIN
                OBJ2 := USER ^.OBJECTTAIL;
                WHILE OBJ2 ^.NEXT <> NIL DO OBJ2 := OBJ2 ^.NEXT;
                OBJ2 ^.NEXT := OBJECT;  OBJECT ^.NEXT := NIL
               END (*ELSE*);
             END (*ELSE*);
            IF WHERE = CONTAINER
            THEN
             BEGIN
              BOX ^.WEIGHT := MAX(0, BOX ^.WEIGHT - OBJECT ^.WEIGHT);
              BOX ^.NUMINSIDE := MAX(0, BOX ^.NUMINSIDE - 1);
              BOX ^.OBJECTTAIL := OBTAIL
             END (*IF*)
            ELSE RMOBJECTTAIL := OBTAIL;
           END (*ELSE*)
        END (*ELSE*)
      ELSE IF WHERE <> NOWHERE  THEN WRITELN(TERM, 'THAT OBJECT ISN''T HERE.')
     END (* WITH *)
   END (*GETOBJECT*);


  PROCEDURE DROPOBJECT(WORD: ALFA; NUM: INTEGER; RM: RMCODETYPE);

   VAR
    BOX, OBTAIL, OBJECT: OBJECTPOINT;
    NUM2, ILOOP: INTEGER;
    WORD2: ALFA;
    WHERE:
     (GROUND, CONTAINER, NOWHERE);
    HELD: BOOLEAN;

   BEGIN
    HELD := FALSE;  ERRLOC := 'DROPOBJECT';
    OBJECT := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);
    IF OBJECT <> NIL
    THEN
     BEGIN
      OBTAIL := ROOM[RM].RMOBJECTTAIL;  BOX := NIL;  WHERE := GROUND;
      GETWORD(WORD2, NUM2, BUFFER, LENBUF, LOC);
      BOX := FINDOBJECT(WORD2, NUM2, ROOM[RM].RMOBJECTTAIL);
      IF BOX = NIL THEN
       BEGIN
        BOX := FINDOBJECT(WORD2, NUM2, USER ^.OBJECTTAIL);
        IF BOX <> NIL  THEN HELD := TRUE
       END (*IF*);
      IF BOX <> NIL
      THEN
       IF BOX ^.OBCLASS = CHEST
       THEN
        IF NOT BOX ^.CLOSED
        THEN
         BEGIN
          OBTAIL := BOX ^.OBJECTTAIL;
IF (BOX^.NUMINSIDE >= 6) OR (BOX ^.WEIGHT > 200)
          THEN
           BEGIN
            WRITE(TERM, 'THERE IS NO MORE ROOM INSIDE ');  PRINTOBJ(BOX ^, TRUE);
            WRITELN(' FOR MORE OBJECTS!');  WHERE := NOWHERE
           END (*IF*)
          ELSE
           IF BOX = OBJECT
           THEN
            BEGIN WRITELN(TERM, 'CAN''T PUT IT INSIDE ITSELF!');  WHERE := NOWHERE
            END (*IF*)
           ELSE WHERE := CONTAINER
         END (*IF*)
        ELSE
         BEGIN WHERE := NOWHERE;  WRITELN(TERM, 'YOU CAN''T.  IT''S CLOSED!') END
       ELSE BEGIN WHERE := NOWHERE;  WRITELN(TERM, 'IT WON''T FIT IN THAT!') END
      ELSE
       IF WORD2 <> BLANKS THEN
        BEGIN WHERE := NOWHERE;  WRITELN(TERM, 'THAT CONTAINER ISN''T HERE!') END;
      IF WHERE <> NOWHERE
      THEN
       BEGIN (* DROP OBJECT INTO ROOM *)
        IF DELETEOBJECT(OBJECT, USER ^.OBJECTTAIL)
        THEN USER ^.OBJECTTAIL := USER ^.OBJECTTAIL ^.NEXT;
        OBJECT ^.NEXT := OBTAIL;  OBTAIL := OBJECT;
        IF NOT HELD  THEN USER ^.WEIGHT := MAX(0, USER ^.WEIGHT - OBJECT ^.WEIGHT);
        STOPUSING(USER, OBJECT);
        IF WHERE = CONTAINER
        THEN
         BEGIN
          WRITELN(TERM, 'OK.  YOU DROP IT.');
          BOX ^.WEIGHT := MIN(1000, BOX ^.WEIGHT + OBJECT ^.WEIGHT);
          BOX ^.NUMINSIDE := MIN(10, BOX ^.NUMINSIDE + 1);
          BOX ^.OBJECTTAIL := OBTAIL
         END (*IF*)
        ELSE BEGIN ROOM[RM].RMOBJECTTAIL := OBTAIL;  WRITELN(TERM, 'OK') END;
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
         BEGIN
          WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' DROPPED ');
          PRINTOBJ(OBJECT ^, FALSE);
          IF WHERE = CONTAINER
          THEN BEGIN WRITE(' INTO ');  PRINTOBJ(BOX ^, TRUE) END;
          WRITELN('.');
         END (*FOR*)
       END (*IF*)
     END (*IF*)
    ELSE WRITELN(TERM, 'YOU AREN''T CARRYING THAT!');
   END (*DROPOBJECT*);


  PROCEDURE USERS;
(* USERS RETURNS A LIST OF STORED CODENAMES *)

   VAR
    NUM, ILOOP: INTEGER;
    DM: BOOLEAN;

   BEGIN
    DM := USER ^.SSJ;  NUM := 0;  WRITE(TERM, 'LIST OF STORED USERS:');
    FOR ILOOP := 1 TO CURRENTPLINDEX DO
     IF PLAYERINDEX[ILOOP] <> EMPTY
     THEN
      IF DM OR (PLAYERINDEX[ILOOP, 1] <> '*') (* DEAD PLAYER *)
      THEN
       BEGIN
        IF NUM MOD 4 = 0  THEN BEGIN WRITELN;  WRITE(TERM) END;  NUM := NUM + 1;
        WRITE(PLAYERINDEX[ILOOP], '  ')
       END (*IF*);
    WRITELN;  WRITELN(TERM)
   END (*USERS*);


  PROCEDURE TALK(LENBUF: LENBUFTYPE; CMDCODE: INTEGER; WORD: ALFA);
(* *TALK* PROCESSES ALL PLAYER-PLAYER COMMUNICATION.  IT
EXECUTES THE "SAY", "YELL" AND "SEND" COMMANDS.  "SAY" AND
"SEND" MAY HAVE OPTIONAL NAMES SPECIFIED AFTER THEM IN ORDER
TO SIMULATE FLASHING.
*SAY, *YELL AND *SEND  ISSUE NO ID PREFIX *)

   VAR
    PLAYER: USERPOINT;
    NUMHEARING, ILOOP: INTEGER;
    TALKHOW: TALKHOWTYPE;
    MSGSTART, MSGEND: INTEGER;
    NOID: BOOLEAN;
    LOGTERM: ALFA;


   PROCEDURE TEXTLIMITS(VAR MESSTART, MESEND: INTEGER);
(*TEXTLIMITS RETURNS THE STARTING AND ENDING BOUNDARIES FOR
THE MESSAGE IN THE BUFFER.*)

    VAR
     KLOOP: INTEGER;

    BEGIN
     KLOOP := 1;
     WHILE (KLOOP <= LENBUF) AND (BUFFER[KLOOP] <> '"') DO KLOOP := KLOOP + 1;
     IF KLOOP > LENBUF  THEN MESSTART := 0 (* FLAG ERROR *)
     ELSE
      BEGIN
       KLOOP := KLOOP + 1;  MESSTART := KLOOP;
       WHILE (KLOOP <= LENBUF) AND (BUFFER[KLOOP] <> '"') DO
        BEGIN
         IF BUFFER[KLOOP] = ''''  THEN BUFFER[KLOOP] := '"';  KLOOP := KLOOP + 1;
        END (*WHILE*);
       IF KLOOP > LENBUF  THEN MESEND := LENBUF  ELSE MESEND := KLOOP - 1;
       IF MESEND < LENBUF - 2
       THEN WRITELN(TERM, 'TEXT FOLLOWING THE SECOND QUOTATION MARK WAS IGNORED.')
      END (*ELSE*)
    END (*TEXTLIMITS*);


   PROCEDURE SENDMSG(TM: ALFA; VERB: DYNAMIC ALFA; MSTART, MEND: INTEGER; NOID:
     BOOLEAN);
(* SENDMSG PRINTS OUT THE MESSAGE IN THE BUFFER *)

    VAR
     LINELEN, JLOOP: INTEGER;

    BEGIN
     WRITE(TM);
     IF NOT NOID  THEN BEGIN WRITE(PS(USER ^.NAME), VERB, ' "');  LINELEN := 57 END
     ELSE LINELEN := 1000 (* NO LINE LIMIT *);
     FOR JLOOP := MSTART TO MIN(MEND, MSTART + LINELEN) DO
      IF NOID AND (BUFFER[JLOOP] = '\')  THEN BEGIN WRITELN;  WRITE(TM) END
      ELSE WRITE(BUFFER[JLOOP]);
     IF MSTART + LINELEN < MEND
     THEN (* WRITE 2ND LINE *)
      BEGIN
       WRITELN;  WRITE(TM, '     ');
       FOR JLOOP := MSTART + LINELEN + 1 TO MEND DO WRITE(BUFFER[JLOOP])
      END (*IF*);
     IF NOT NOID  THEN WRITE('"');  WRITELN;
    END (*SENDMSG*);


   BEGIN (*TALK*)
    ERRLOC := 'TALK      ';  NOID := (CMDCODE IN [36, 37, 38]) OR (CMDCODE = 82);
    IF WORD = BLANKS  THEN WRITELN(TERM, 'MISSING TEXT TO SEND.')
    ELSE
     BEGIN
      USER ^.HIDDEN := FALSE;  TEXTLIMITS(MSGSTART, MSGEND);
      IF MSGSTART <= 0
      THEN WRITELN(TERM, 'MISSING QUOTATION MARKS.  SEND <WHO> "TEXT"')
      ELSE
       IF WORD[1] <> '"'
       THEN
        CASE CMDCODE OF
         36, 12 (* SAY *):
          BEGIN
           PLAYER := FINDPLAYER(WORD, ROOM[USER ^.RMCODE].RMPLAYERTAIL);
           IF PLAYER <> NIL  THEN IF PLAYER ^.NONEXISTANT  THEN PLAYER := NIL;
           IF PLAYER <> NIL
           THEN
            BEGIN
             IF NOTIMEOUT(PLAYER)
             THEN SENDMSG(PLAYER ^.TRM, ' WHISPERS,', MSGSTART, MSGEND, NOID)
             ELSE WRITELN(TERM, 'PLAYER TIMED OUT - MESSAGE NOT RECEIVED.');
             IF (RND(100) <= 10) AND (CMDCODE <> 36)
             THEN
              FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
               IF TERMLIST[ILOOP] <> PLAYER ^.TRM
               THEN
                BEGIN
                 WRITELN(TERMLIST[ILOOP], 'YOU OVERHEAR ', PS(USER ^.NAME),
                   ' WHISPERING TO ', PS(PLAYER ^.NAME), '!');
                 SENDMSG(TERMLIST[ILOOP], ' IS WHISPERING:', MSGSTART, MSGEND, FALSE)
                END (*IF*)
            END (*IF*)
           ELSE WRITELN(TERM, PS(WORD), ' IS NOT HERE.')
          END (*12*);
         37, 13 (* YELL *):
          WRITELN(TERM, 'YOU CAN''T SELECTIVELY YELL TO JUST ONE PLAYER!');
         82, 38, 14 (* SEND AND *LOGOFF *):
          IF SPELLCOST(USER, 1, - 5, 5)
          THEN
           BEGIN
            PLAYER := FINDUSER(WORD, USERTAIL);
            IF PLAYER <> NIL  THEN IF PLAYER ^.NONEXISTANT  THEN PLAYER := NIL;
            IF PLAYER <> NIL
            THEN
             BEGIN
              IF CMDCODE = 82  THEN WRITELN(PLAYER ^.TRM, ' ');
              IF NOTIMEOUT(PLAYER)
              THEN SENDMSG(PLAYER ^.TRM, '# FLASHES:', MSGSTART, MSGEND, NOID)
              ELSE WRITELN(TERM, 'PLAYER TIMED OUT - MESSAGE NOT RECEIVED.');
              IF CMDCODE = 82 (*LOGOFF*)
              THEN
               BEGIN
                DAYMSG('OFF', PLAYER, USER ^.NAME, 0);  LOGTERM := PLAYER ^.TRM;
                IF PLAYER = USER  THEN USER := NIL;  WRITELN(PLAYER ^.TRM, COL, 'D');
                LOGOFF(PLAYER, TRUE);  WRITECONTROL(MTLO, ZEROPARM, LOGTERM);
                WRITELN;  PLAYER := NIL;
               END (*IF*)
             END (*IF*)
            ELSE WRITELN(TERM, PS(WORD), ' CANNOT BE FOUND.');
           END (*IF*);
        END (*CASE*)
       ELSE (* ALL PLAYERS SENT *)
        CASE CMDCODE OF
         36, 12 (* SAY *):
          BEGIN
           NUMHEARING := MSGTERM(TERMLIST, LOCAL);
           IF NUMHEARING > 0
           THEN
            BEGIN
             IF USER ^.ECHO THEN
              BEGIN
               NUMHEARING := NUMHEARING + 1;  TERMLIST[NUMHEARING] := USER ^.TRM
              END (*IF*);
             FOR ILOOP := 1 TO NUMHEARING DO
              SENDMSG(TERMLIST[ILOOP], ' SAYS,', MSGSTART, MSGEND, NOID)
            END (*IF*)
           ELSE WRITELN(TERM, 'NOBODY IS HERE TO HEAR YOU.')
          END (*36*);
         37, 13 (* YELL *):
          BEGIN
           NUMHEARING := MSGTERM(TERMLIST, YELL);
           IF NUMHEARING > 0
           THEN
            BEGIN
             IF USER ^.ECHO THEN
              BEGIN
               NUMHEARING := NUMHEARING + 1;  TERMLIST[NUMHEARING] := USER ^.TRM
              END (*IF*);
             FOR ILOOP := 1 TO NUMHEARING DO
              SENDMSG(TERMLIST[ILOOP], ' YELLS,', MSGSTART, MSGEND, NOID);
            END (*IF*)
           ELSE WRITELN(TERM, 'NO ONE HEARS YOU.')
          END (*37*);
         38, 14 (* SEND *):
          IF (USER ^.SENDDAY >= MAX(5, USER ^.LVL)) AND NOT NOID
          THEN
           WRITELN(TERM, 'YOU HAVE NO TELEPATHIC POWERS LEFT FOR BROACASTING TODAY!')
          ELSE
           IF SPELLCOST(USER, 2, - 5, 7)
           THEN
            BEGIN
             IF NOID  THEN TALKHOW := OTHERS
             ELSE
              BEGIN TALKHOW := NOBLOCK;  USER ^.SENDDAY := USER ^.SENDDAY + 1 END;
             FOR ILOOP := 1 TO MSGTERM(TERMLIST, TALKHOW) DO
              SENDMSG(TERMLIST[ILOOP], ': ', MSGSTART, MSGEND, NOID);
            END (*IF*);
        END (*CASE*)
     END (*ELSE*)
   END (*TALK*);


  PROCEDURE LOSE(WORD: ALFA);
(* LOSE A FOLLOWING PLAYER *)

   VAR
    FOLLOWPLYR: USERPOINT;

   BEGIN
    FOLLOWPLYR := FINDPLAYER(WORD, ROOM[USER ^.RMCODE].RMPLAYERTAIL);
    IF FOLLOWPLYR = NIL  THEN WRITELN(TERM, 'PLAYER NOT HERE.')
    ELSE
     IF FOLLOWPLYR ^.FOLLOW <> USER
     THEN WRITELN(TERM, 'PLAYER NOT FOLLOWING YOU ANYWAY.')
     ELSE
      IF NOT (FOLLOWPLYR ^.CLASS = RANGER) AND ((RND(3) = 1) OR (USER ^.WEIGHT <
        FOLLOWPLYR ^.WEIGHT))
      THEN
       BEGIN
        FOLLOWPLYR ^.FOLLOW := NIL;
        WRITELN(TERM, 'YOU LOSE ', PRO[FOLLOWPLYR ^.SEX], '!');
        WRITELN(FOLLOWPLYR ^.TRM, PS(USER ^.NAME), ' LOSES YOU!')
       END (*IF*)
      ELSE WRITELN(TERM, 'DIDN''T WORK!')
   END (*LOSE*);


  PROCEDURE FOLLOWPLYR(WORD: ALFA);
(* FOLLOW ANOTHER PLAYER *)

   VAR
    LEADER: USERPOINT;

   BEGIN
    LEADER := FINDPLAYER(WORD, ROOM[USER ^.RMCODE].RMPLAYERTAIL);
    IF LEADER = NIL  THEN WRITELN(TERM, 'PLAYER NOT HERE.')
    ELSE
     BEGIN
      IF LEADER ^.NAME = USER ^.NAME
      THEN WRITELN(TERM, 'YOU CAN''T FOLLOW YOUSELF!')
      ELSE
       BEGIN
        USER ^.FOLLOW := LEADER;  WRITELN(TERM, 'OK');
        IF NOT (USER ^.HIDDEN OR USER ^.INVISIBLE)
        THEN WRITELN(LEADER ^.TRM, PS(USER ^.NAME), ' FOLLOWS YOU!');
       END (*ELSE*);
     END (*IF*)
   END (*FOLLOWPLYR*);


  PROCEDURE HIDE(WORD: ALFA; NUM: INTEGER);
(* HIDE PLAYERS AND OBJECTS *)

   VAR
    ILOOP: INTEGER;
    OBJ: OBJECTPOINT;
    CHANCE: INTEGER;

   BEGIN
    IF WORD = BLANKS
    THEN (* HIDE PLAYER*)
     BEGIN
      CHANCE := USER ^.LVL * 20 + USER ^.DEX;
      IF USER ^.AGUILD OR (USER ^.CLASS = THIEF)  THEN CHANCE := CHANCE * 2;
      IF ROOM[USER ^.RMCODE].RMMONSTERTAIL <> NIL  THEN CHANCE := CHANCE DIV 2;
      IF RND(100) <= MIN(66, CHANCE)  THEN USER ^.HIDDEN := TRUE
      ELSE
       FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
        WRITELN(TERMLIST[ILOOP], 'YOU SPOT ', PS(USER ^.NAME),
          ' TRYING TO HIDE IN THE SHADOWS!');
      WRITELN(TERM, 'YOU HIDE IN THE SHADOWS.');
     END (*IF*)
    ELSE
     BEGIN
      OBJ := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);
      IF OBJ = NIL  THEN WRITELN(TERM, 'YOU AREN''T HOLDING THAT!')
      ELSE
       BEGIN
        STOPUSING(USER, OBJ);
        IF DELETEOBJECT(OBJ, USER ^.OBJECTTAIL)
        THEN USER ^.OBJECTTAIL := USER ^.OBJECTTAIL ^.NEXT;
        USER ^.WEIGHT := USER ^.WEIGHT - OBJ ^.WEIGHT;
        OBJ ^.NEXT := ROOM[USER ^.RMCODE].RMOBJECTTAIL;
        ROOM[USER ^.RMCODE].RMOBJECTTAIL := OBJ;  OBJ ^.INVISIBLE := TRUE;
        WRITE(TERM, 'YOU CAREFULLY HIDE ');  PRINTOBJ(OBJ ^, TRUE);
        WRITELN(' IN THE ROOM.');
        IF RND(4) = 1
        THEN
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
          BEGIN
           WRITE(TERMLIST[ILOOP], 'YOU SEE ', PS(USER ^.NAME), ' TRYING TO HIDE ');
           PRINTOBJ(OBJ ^, FALSE);  WRITELN(' IN THE ROOM.');
          END (*FOR*)
       END (*ELSE*)
     END (*ELSE*)
   END (*HIDE*);


  PROCEDURE SEARCH;
(* SEARCH FOR HIDDEN PLAYERS AND OBJECTS *)

   VAR
    FIND: BOOLEAN;
    HIDPLYR: USERPOINT;
    HIDOBJ: OBJECTPOINT;
    FACTOR, RM: INTEGER;


   FUNCTION PHID(PLYR: USERPOINT): BOOLEAN;

    BEGIN PHID := (PLYR ^.HIDDEN) END;


   FUNCTION OHID(OBJ: OBJECTPOINT): BOOLEAN;

    BEGIN OHID := (OBJ ^.INVISIBLE) END;


   BEGIN (*SEARCH*)
    FIND := FALSE;  RM := USER ^.RMCODE;  FACTOR := 50;
    IF USER ^.CLASS IN [THIEF, RANGER]  THEN FACTOR := FACTOR + 25;
    IF READYCHECK(USER ^.LASTATK)
    THEN
     BEGIN
      USER ^.LASTATK := REALTIME + 10;
      HIDPLYR := MATCHPLAYER(ROOM[RM].RMPLAYERTAIL, PHID);
      WHILE HIDPLYR <> NIL DO
       BEGIN
        IF (HIDPLYR <> USER) AND (RND(100) <= FACTOR)
        THEN
         BEGIN
          HIDPLYR ^.HIDDEN := FALSE;  FIND := TRUE;
          WRITELN(TERM, 'YOU SPOT ', PS(HIDPLYR ^.NAME), ' HIDING IN THE SHADOWS!');
         END (*IF*);
        HIDPLYR := MATCHPLAYER(HIDPLYR ^.NEXT, PHID)
       END (*WHILE*);
      HIDOBJ := MATCHOBJECT(ROOM[RM].RMOBJECTTAIL, OHID);
      WHILE HIDOBJ <> NIL DO
       BEGIN
        IF RND(100) <= FACTOR THEN
         BEGIN
          FIND := TRUE;  WRITE(TERM, 'WHILE SEARCHING YOU DISCOVER ');
          PRINTOBJ(HIDOBJ ^, FALSE);  WRITELN('!')
         END (*IF*);
        HIDOBJ := MATCHOBJECT(HIDOBJ ^.NEXT, OHID)
       END (*WHILE*);
      IF NOT FIND  THEN WRITELN(TERM, 'YOU DIDN''T FIND ANYTHING.');
     END (*IF*)
   END (*SEARCH*);


  PROCEDURE GODIRECTION(WORD: ALFA; NUM: INTEGER; CMDCODE: INTEGER);
(* GODIRECTION LETS PLAYERS MOVE FROM ROOM TO ROOM.  IT MOVES
PLAYERS N,S,E,W,U,D; OR IT CAN MOVE THEM THROUGH A "PORTAL" CLASS
OBJECT, SUCH AS A DOOR.  MOVEMENT IS PROHIBITED IF A MONSTER BLOCKS
EXIT.  MONSTERS WHO HAVE THE *FOLLOW* BIT SET WILL FOLLOW
THE PLAYER INTO THE NEXT ROOM.  (66 CHANCE)   APPROPRIATE MESSAGES
ARE SENT ANNOUNCING ENTRANCE AND EXIT TO OTHER NEARBY PLAYERS. *)

   VAR
    FACTOR, I: INTEGER;
    RM, NEWRM: RMCODETYPE;
    DM, TEMP, FOLLOWPLYR: USERPOINT;
    NEXTMON, MONSTER: MONSTERPOINT;
    OBJECT: OBJECTPOINT;
    FOLLOWING, LEAVE, BLOCKED, FOLLOWED: BOOLEAN;


   FUNCTION LOCDM(DMUSR: USERPOINT): BOOLEAN;

    BEGIN LOCDM := (DMUSR ^.SSJ) END;


   FUNCTION MBLOCKING(MON: MONSTERPOINT): BOOLEAN;

    BEGIN MBLOCKING := (MON ^.BLOCK) END;


   FUNCTION MFOLLOW(MON: MONSTERPOINT): BOOLEAN;

    BEGIN MFOLLOW := (MON ^.FOLLOW AND (MON ^.DEFPLAYER = USER)) END (*MFOLLOW*);


   FUNCTION PFOLLOW(USR: USERPOINT): BOOLEAN;

    BEGIN PFOLLOW := (USR ^.FOLLOW = USER) END;


   BEGIN (*GODIRECTION*)
    ERRLOC := ' TWELVE   ';  BLOCKED := FALSE;  FOLLOWED := FALSE;  LEAVE := FALSE;
    RM := USER ^.RMCODE (* CURRENT ROOM *);
    IF NOT USER ^.ENCOUNTSTOP
    THEN
     BEGIN
      IF CMDCODE <= 6
      THEN (* N,S,E,W,U,D,OUT *)
       IF ROOM[RM].ADJOIN[CMDCODE] <= 0
       THEN WRITELN(TERM, 'THERE IS NO WAY TO GO IN THAT DIRECTION.')
       ELSE
        BEGIN
         IF CMDCODE IN ROOM[RM].THOUSANDS  THEN FACTOR := 1000  ELSE FACTOR := 0;
         LEAVE := TRUE;  NEWRM := ROOM[RM].ADJOIN[CMDCODE] + FACTOR
        END (*ELSE*)
      ELSE
       IF CMDCODE = 7 (* OUT *)
       THEN
        IF ROOM[RM].OUT > 0  THEN BEGIN LEAVE := TRUE;  NEWRM := ROOM[RM].OUT END
        ELSE WRITELN(TERM, 'THERE IS NO OBVIOUS EXIT FROM HERE.')
       ELSE (* CMDCODE = 9. GO THRU DOOR OR PASSAGE *)
        BEGIN
         OBJECT := FINDOBJECT(WORD, NUM, ROOM[RM].RMOBJECTTAIL);
         IF OBJECT = NIL  THEN WRITELN(TERM, 'THAT OBJECT ISN''T HERE!')
         ELSE
          IF NOT (OBJECT ^.OBCLASS IN [PORTAL, DOOR])
          THEN WRITELN(TERM, 'YOU CAN''T GO IN THAT DIRECTION.')
          ELSE
           IF (OBJECT ^.OBCLASS = DOOR) AND OBJECT ^.DCLOSED
           THEN
            BEGIN
             WRITE(TERM, 'CLUNK!  YOU BANG YOUR NOSE AGAINST ');
             PRINTOBJ(OBJECT ^, TRUE);  WRITELN('.')
            END (*IF*)
           ELSE BEGIN LEAVE := TRUE;  NEWRM := OBJECT ^.TOWHERE END
        END (* PASSAGES *);
      IF LEAVE
      THEN
       BEGIN
        MONSTER := ROOM[RM].RMMONSTERTAIL;
        REPEAT (* IF MORE THAN 1 BLOCKING MONSTER *)
         MONSTER := MATCHMONSTER(MONSTER, MBLOCKING);
         IF MONSTER <> NIL
         THEN
          BEGIN
           IF (CMDCODE > 7) OR (MONSTER ^.DEFPLAYER = USER)
           THEN
            IF (RND(100) < 50) OR (CMDCODE > 7) THEN
             BEGIN (* BLOCKS *)
              WRITELN(TERM, PM(MONSTER), 'BLOCKS YOUR WAY!');  BLOCKED := TRUE;
             END (*IF*);
           MONSTER := MONSTER ^.NEXT;
          END (*IF*)
        UNTIL (MONSTER = NIL) OR BLOCKED;
        IF NOT BLOCKED
        THEN
         BEGIN (* CHECK FOR FOLLOWING MONSTERS *)
          MONSTER := ROOM[RM].RMMONSTERTAIL;  I := S(NEWRM);
          IF NOT ROOM[I].SAFE
          THEN
           REPEAT
            MONSTER := MATCHMONSTER(MONSTER, MFOLLOW);
            IF MONSTER <> NIL
            THEN
             IF RND(100) < 70
             THEN
              BEGIN
               NEXTMON := MONSTER ^.NEXT;
               WRITELN(TERM, PM(MONSTER), 'FOLLOWS YOU!');  FOLLOWED := TRUE;
               DELETEMONSTER(MONSTER, RM);  INSERTMONSTER(MONSTER, I);
               MONSTER ^.DEFPLAYER := USER (* CONTINUE MONSTER'S ATTACK*);
               MONSTER := NEXTMON;
              END (*IF*)
             ELSE MONSTER := MONSTER ^.NEXT;
           UNTIL MONSTER = NIL
         END (*IF*);
        IF RND(100) > 50  THEN USER ^.HIDDEN := FALSE;
        FOLLOWPLYR := MATCHPLAYER(ROOM[RM].RMPLAYERTAIL, PFOLLOW);
        IF NOT USER ^.HIDDEN AND ((FOLCOUNT = 0) OR FOLLOWED OR BLOCKED)
        THEN
         FOR I := 1 TO MSGTERM(TERMLIST, LOCAL) DO
          BEGIN
           WRITE(TERMLIST[I], PS(USER ^.NAME));
           IF FOLLOWPLYR <> NIL  THEN WRITE('''S GROUP');
           IF USER ^.DRUNK - REALTIME > 30  THEN WRITE(' JUST STAGGERED')
           ELSE WRITE(' JUST WENT');
           IF CMDCODE = 9  THEN BEGIN WRITE(' TO ');  PRINTOBJ(OBJECT ^, TRUE) END
           ELSE WRITE(' ', PS(DIRLIST[CMDCODE]));
           IF FOLLOWED  THEN WRITELN(', AND SOMETHING FOLLOWED ', PRO[USER^.SEX], '!')
           ELSE
            IF BLOCKED
            THEN WRITELN(', BUT THEN SOMETHING STOPPED ', PRO[USER^.SEX], '!')
            ELSE WRITELN('.')
          END (* MSG *);
        IF NOT BLOCKED
        THEN
         BEGIN
          DELETEPLAYER(USER, RM);  PLACEPLAYER(USER, NEWRM);
          IF CMDCODE <= 7  THEN ROOM[RM].LASTDIR := CMDCODE
          ELSE ROOM[RM].LASTDIR := 8;
          IF NOT USER ^.HIDDEN AND (FOLCOUNT = 0)
          THEN
           FOR I := 1 TO MSGTERM(TERMLIST, LOCAL) DO
            BEGIN
             WRITE(TERMLIST[I], PS(USER ^.NAME));
             IF FOLLOWPLYR <> NIL  THEN WRITE('''S GROUP');
             WRITELN(' JUST ARRIVED.')
            END (*FOR*);
          IF ROOM[USER ^.RMCODE].NOTIFYDM
          THEN
           BEGIN
            DM := MATCHUSER(USERTAIL, LOCDM);
            WHILE DM <> NIL DO
             BEGIN
              WRITELN(DM ^.TRM, '*** ', PS(USER ^.NAME), ' ENTERED ROOM ', NEWRM: 0,
                '.');
              DM := MATCHUSER(DM ^.NEXTUSER, LOCDM);
             END (*WHILE*)
           END (*IF*);
          FOLLOWING := (FOLCOUNT > 0);
          IF (USER ^.RMCODE <> RM) AND (FOLCOUNT < 8)
          THEN
           BEGIN
            WHILE (FOLLOWPLYR <> NIL) AND (FOLCOUNT < 8) DO
             BEGIN
              FOLCOUNT := FOLCOUNT + 1;
              IF FOLCOUNT >= 8
              THEN WRITELN(TERM, 'MIL432 - FOLLOW TABLE OVERFLOW!');
              TEMP := USER;  TERM := FOLLOWPLYR ^.TRM;  USER := FOLLOWPLYR;
              GODIRECTION(WORD, NUM, CMDCODE);
              IF USER ^.RMCODE = TEMP ^.RMCODE  THEN USER ^.FOLLOW := TEMP;
              USER := TEMP;  TERM := USER ^.TRM;
              FOLLOWPLYR := MATCHPLAYER(ROOM[RM].RMPLAYERTAIL, PFOLLOW);
             END (*WHILE*)
           END (*IF*);
          WITH USER ^ DO
           IF NOT FOLLOWING  THEN ROOMDISPLAY(RMCODE, BRIEF)
           ELSE
            IF NOTIMEOUT(USER) THEN
             BEGIN
              WRITE(TERM, 'YOU''RE ');
              PRINTDESC(ROOM[RMCODE].DESCREC, ROOM[RMCODE].DESCCODE, 0, BRIEF);
              WRITELN;
             END (*DISPLAY ROOM*);
          CASE NEWRM OF
           3: WRITELN(TERM, 'BARTENDER SAYS "BUY A DRINK, MAC?"');
           4: WRITELN(TERM, 'PAPERBOY SAYS, "EXTRA! EXTRA! READ ALL ABOUT IT!"');
           8: WRITELN(TERM, 'APPRAISOR ASKS, "WHAT WOULD YOU LIKE TO SELL?"');
           10: WRITELN(TERM, 'MERCHANT ASKS WHAT YOU WOULD LIKE TO BUY.');
           18:
            WRITELN(TERM,
              '"HEE HEE, SO MATEY, YOUR GEAR DONT LOOK TOO GOOD.  NEED FIXIN?"');
          OTHERWISE
          END (*CASE*);
         END (* MOVE *)
       END (* LEAVE *)
     END (*IF*)
   END (*GODIRECTION*);


  PROCEDURE TRACK;

   VAR
    DIR: 0..8;
    OBJ: OBJECTPOINT;


   FUNCTION PORTL(OB: OBJECTPOINT): BOOLEAN;

    BEGIN PORTL := (OB ^.OBCLASS IN [DOOR, PORTAL]) END;


   BEGIN (*TRACK*)
    IF READYCHECK(USER ^.LASTATK)
    THEN
     BEGIN
      DIR := ROOM[USER ^.RMCODE].LASTDIR;
      IF USER ^.CLASS <> RANGER  THEN IF RND(2) > 1  THEN DIR := 0;
      USER ^.LASTATK := REALTIME + 7;
      CASE DIR OF
       0: WRITELN(TERM, 'YOU DONT FIND ANY TRACKS.');
       1, 2, 3, 4, 5, 6:
        BEGIN
         WRITE(TERM, 'YOU SEE SOME TRACKS LEADING ', PS(DIRLIST[DIR]));
         WRITELN('.')
        END (*1*);
       7: WRITELN(TERM, 'YOU SEE SOME TRACKS LEADING OUT.');
       8:
        BEGIN
         OBJ := MATCHOBJECT(ROOM[USER ^.RMCODE].RMOBJECTTAIL, PORTL);
         IF OBJ = NIL  THEN WRITELN(TERM, 'YOU DONT FIND ANY TRACKS.')
         ELSE
          BEGIN
           WRITE(TERM, 'YOU SEE SOME TRACKS LEADING TO ');  PRINTOBJ(OBJ ^, TRUE);
           WRITELN('.')
          END (*ELSE*)
        END (*8*);
      END (*CASE*)
     END (*IF*)
   END (*TRACK*);


  PROCEDURE TRAPCHECK(VAR OBJ: OBJECTPOINT; TRAP: INTEGER);

   VAR
    DMG: INTEGER;

   BEGIN
    DMG := 0;
    IF TRAP > 0
    THEN
     IF USER ^.DEX - RND(6) < TRAP
     THEN
      BEGIN
       WRITE(TERM);
       CASE TRAP OF
        1, 2, 3: WRITE('SPLINTERS ON YOUR HAND!');
        4, 5: WRITE('SPRING DART!');
        6: WRITE('SMALL KNIFE FLIES AT YOU!');
        7: BEGIN USER ^.POISONED := TRUE;  WRITE('POISON DART!') END;
        8: WRITE('SPEAR SHOOTS OUT OF GROUND AT YOU!');
        9: WRITE('DUST SPRAYS IN YOUR EYES!');
        10: WRITE('GRUBS BITE YOU!');
        11: WRITE('STEEL WIRE CUTS YOUR HAND!');
        12: WRITE('NEEDLES STAB YOUR TOES!');
        13: BEGIN USER ^.POISONED := TRUE;  WRITE('POISON NEEDLES!') END;
        14: BEGIN USER ^.POISONED := TRUE;  WRITE('COBRA LUNGES AT YOU!') END;
        15: BEGIN USER ^.POISONED := TRUE;  WRITE('GAS SPORES EXPLODE!'); END;
        16: WRITE('ROCKS FALL FROM THE CEILING!');
        17: WRITE('BLAM! EXPLOSION IN YOUR FACE!');
        18: WRITE('ACID SPLASHES IN YOUR FACE!');
        19: WRITE('FLAMES SHOOT OUT AT YOU!');
        20, 21, 22, 23, 24, 25:
         BEGIN USER ^.FATIGUE := 0;  WRITE('SPEAR IMPALES YOUR STOMACH!') END;
        26, 27, 28, 29, 30: WRITE('BOOOOOOOOOOM!');
        31, 32, 33, 34, 35: WRITE('A RACK OF KNIVES FALLS AND CRUSHES YOU!');
       OTHERWISE
        USER ^.FATIGUE := 0;  WRITE('TONS OF ROCK TUMBLE DOWN UPON YOU!');
       END (*CASE*);
       DMG := MAX(0, TRAP + USER ^.AC - 10);  WRITELN;
       WRITE(TERM, 'IT HITS YOU FOR ');  PRINTDMG(USER, DMG, USER ^.BRIEF);
       IF USER ^.HITS + USER ^.FATIGUE <= DMG
       THEN
        BEGIN
USER^.DEAD := TRUE;
         USER ^.FATIGUE := 0;  USER ^.HITS := 0;  DAYMSG('TRP', USER, BLANKS, 0);
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, ALL) DO
          WRITELN(TERMLIST[ILOOP], '### ', PS(USER ^.NAME),
            ' WAS JUST KILLED BY A DEADLY TRAP.');
        END (*IF*)
       ELSE
        BEGIN
         IF DMG > USER ^.FATIGUE
         THEN USER ^.HITS := USER ^.HITS - DMG + USER ^.FATIGUE;
         USER ^.FATIGUE := MAX(0, USER ^.FATIGUE - DMG)
        END (*ELSE*)
      END (*IF*)
   END (*TRAPCHECK*);


  PROCEDURE OPENCLOSE(CMDCODE: INTEGER; WORD: ALFA; NUM: INTEGER);

   VAR
    OTHRDOOR, KEY, OBJ: OBJECTPOINT;
    OBTRAP: 0..50;
    OBCLOSED: BOOLEAN;
    OBLOCKED: 0..1000;
    NUM2, ILOOP: INTEGER;
    OBTYPE:
     (PORTL, BOX, NEITHER);


   FUNCTION SAMEDOOR(OB: OBJECTPOINT): BOOLEAN;

    BEGIN SAMEDOOR := (OB ^.NAME = OBJ ^.NAME) END;


   BEGIN (*OPENCLOSE*)
    OBTYPE := NEITHER;  OBJ := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);
    IF OBJ = NIL
    THEN OBJ := FINDOBJECT(WORD, NUM, ROOM[USER ^.RMCODE].RMOBJECTTAIL);
    IF OBJ = NIL  THEN WRITELN(TERM, 'THAT OBJECT ISN''T HERE!')
    ELSE
     IF OBJ ^.OBCLASS = CHEST
     THEN
      BEGIN
       OBTRAP := OBJ ^.TRAP;  OBLOCKED := OBJ ^.LOCKED;  OBTYPE := BOX;
       OBCLOSED := OBJ ^.CLOSED
      END (*IF*)
     ELSE
      IF OBJ ^.OBCLASS = DOOR
      THEN
       BEGIN
        OBTRAP := OBJ ^.DTRAP;  OBLOCKED := OBJ ^.DLOCKED;  OBTYPE := PORTL;
        OBCLOSED := OBJ ^.DCLOSED
       END (*IF*)
      ELSE WRITELN(TERM, 'I DON''T KNOW HOW TO DO SUCH A THING.');
    IF OBTYPE <> NEITHER
    THEN
     BEGIN
      IF CMDCODE = 66 (*CLOSE*)
      THEN
       IF OBCLOSED  THEN WRITELN(TERM, 'IT''S ALREADY CLOSED!')
       ELSE
        BEGIN
         OBCLOSED := TRUE;
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
          BEGIN
           WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' JUST CLOSED ');
           PRINTOBJ(OBJ ^, TRUE);  WRITELN('.')
          END (*FOR*);
         WRITELN(TERM, 'OK')
        END (*ELSE*)
      ELSE
       IF (CMDCODE = 67) OR (CMDCODE = 68) (*LOCK/UNLOCK*)
       THEN
        BEGIN
         GETWORD(WORD, NUM2, BUFFER, LENBUF, LOC);
         KEY := FINDOBJECT(WORD, NUM2, USER ^.OBJECTTAIL);
         IF WORD = BLANKS  THEN WRITELN(TERM, 'WITH WHAT?')
         ELSE
          IF KEY = NIL  THEN WRITELN(TERM, 'YOU DON''T HAVE THE RIGHT KEY.')
          ELSE
           IF KEY ^.OBCLASS <> KEYS
           THEN WRITELN(TERM, 'THAT WONT LOCK OR UNLOCK ANYTHING!')
           ELSE
            IF ((KEY ^.UNLOCK MOD 10 = 0) AND (KEY ^.UNLOCK <> OBLOCKED - OBLOCKED
              MOD 10) OR (KEY ^.UNLOCK MOD 10 <> 0) AND (KEY ^.UNLOCK <> OBLOCKED))
              AND (KEY ^.UNLOCK <> 1000)
            THEN
             BEGIN WRITE(TERM);  PRINTOBJ(KEY ^, TRUE);  WRITELN(' DOESN''T WORK!')
             END (*IF*)
            ELSE
             BEGIN
              IF KEY ^.UNLOCK = 1000
              THEN DAYMSG('KEY', USER, BLANKS, W(USER ^.RMCODE));
              IF CMDCODE = 67  THEN OBCLOSED := TRUE  ELSE OBCLOSED := FALSE;
              FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
               BEGIN
                WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' JUST ');
                IF CMDCODE = 67  THEN WRITE('LOCKED ')  ELSE WRITE('UNLOCKED ');
                PRINTOBJ(OBJ ^, TRUE);  WRITE(' WITH ');  PRINTOBJ(KEY ^, FALSE);
                WRITELN('.')
               END (*FOR*);
              WRITELN(TERM, 'OK');
             END (*ELSE*)
        END (*IF*)
       ELSE
        IF CMDCODE = 65 (*OPEN*)
        THEN
         IF NOT OBCLOSED  THEN WRITELN(TERM, 'IT''S ALREADY OPEN!')
         ELSE
          IF OBLOCKED > 0  THEN WRITELN(TERM, 'YOU CAN''T, IT''S LOCKED!')
          ELSE
           BEGIN
            OBCLOSED := FALSE;
            FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
             BEGIN
              WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' JUST OPENED ');
              PRINTOBJ(OBJ ^, TRUE);  WRITELN('.')
             END (*FOR*);
            WRITELN(TERM, 'OK');  TRAPCHECK(OBJ, OBTRAP)
           END (*ELSE*)
        ELSE
         IF CMDCODE = 69 (*PICKLOCK*)
         THEN
BEGIN
          IF USER ^.CLASS <> THIEF
          THEN ILOOP := -10 ELSE ILOOP := 3;
           IF NOT READYCHECK(USER ^.LASTATK)  THEN
           ELSE
            IF ((USER ^.LVL + USER ^.DEX DIV 2 + ILOOP) DIV 3 < OBLOCKED MOD 10) OR (OBLOCKED
              MOD 10 = 0)
            THEN
             BEGIN
              USER ^.LASTATK := REALTIME + 15;
              WRITELN(TERM, 'YOU FAIL TO PICK THE LOCK!')
             END (*IF*)
            ELSE
             BEGIN
              OBCLOSED := FALSE;
              FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
               BEGIN
                WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' PICKS THE LOCK ON ');
                PRINTOBJ(OBJ ^, TRUE);  WRITELN('!')
               END (*FOR*);
              WRITELN(TERM, 'YOU PICKED THE LOCK OPEN!');  TRAPCHECK(OBJ, OBTRAP)
             END (*ELSE*)
END
         ELSE
          IF CMDCODE = 70 (*SMASH*)
          THEN
           IF NOT READYCHECK(USER ^.LASTATK)  THEN
           ELSE
            IF NOT OBCLOSED  THEN WRITELN(TERM, 'IT''S ALREADY OPEN!')
            ELSE
             IF (RND(3) <> 1) OR (USER ^.STR * 10 < OBJ ^.WEIGHT)
             THEN
              BEGIN
               USER ^.LASTATK := REALTIME + 15;
               FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
                BEGIN
                 WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' FAILS TO SMASH ');
                 PRINTOBJ(OBJ ^, TRUE);  WRITELN(' OPEN!')
                END (*FOR*);
               WRITELN(TERM, 'BANG!  YOU FAIL TO SMASH IT OPEN!')
              END (*IF*)
             ELSE
              BEGIN
               FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
                BEGIN
                 WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' SMASHES ');
                 PRINTOBJ(OBJ ^, TRUE);  WRITELN(' OPEN!')
                END (*FOR*);
               OBCLOSED := FALSE;  WRITELN(TERM, 'YOU SMASH IT OPEN!');
               TRAPCHECK(OBJ, OBTRAP)
              END (*ELSE*);
      IF OBTYPE = BOX
      THEN
       BEGIN
        OBJ ^.CLOSED := OBCLOSED;  OBJ ^.TRAP := OBTRAP;  OBJ ^.LOCKED := OBLOCKED
       END (*IF*)
      ELSE
       IF OBTYPE = PORTL
       THEN
        BEGIN
         OBJ ^.DCLOSED := OBCLOSED;  OBJ ^.DTRAP := OBTRAP;
         OBJ ^.DLOCKED := OBLOCKED;
         OTHRDOOR := MATCHOBJECT(ROOM[S(OBJ ^.TOWHERE)].RMOBJECTTAIL, SAMEDOOR);
         IF OTHRDOOR <> NIL THEN
          BEGIN
           OTHRDOOR ^.DCLOSED := OBCLOSED;  OTHRDOOR ^.DTRAP := OBTRAP;
           OTHRDOOR ^.DLOCKED := OBLOCKED
          END (*IF*)
        END (*IF*);
     END (*IF*)
   END (*OPENCLOSE*);


  PROCEDURE SAVECHAR;
(* SAVECHAR WILL UPDATE A PLAYER'S FILE ENTRY TO PROTECT AGAINST PTA. *)

   VAR
    DUMUSR: USERPOINT;

   BEGIN
    IF USER ^.LVL < 2
    THEN
     WRITELN(TERM, 'SORRY, YOU MUST BE AT LEAST 2ND LEVEL TO SAVE YOUR CHARACTER.')
    ELSE
     IF (FINDOPENLOC < 0) AND (SEARCHPLINDEX(USER ^.NAME) <= 0)
     THEN WRITELN(TERM, 'SORRY, FILE FULL.  PLAYER CANNOT BE SAVED.')
     ELSE
      BEGIN
       USER ^.USWEAP := NIL;  STOPUSING(USER, USER ^.USARM);
       STOPUSING(USER, USER ^.USSHIELD);  NEW(DUMUSR);  DUMUSR ^ := USER ^;
       DUMUSR ^.RMCODE := W(USER ^.RMCODE);  WRITEPLAYER(DUMUSR, DUMUSR ^.NAME);
       NEW(DUMUSR);  DUMUSR ^ := PROTOUSER;  READPLAYER(DUMUSR, USER ^.NAME);
       USER ^.WEIGHT := DUMUSR ^.WEIGHT;  USER ^.OBJECTTAIL := DUMUSR ^.OBJECTTAIL;
       DISPOSE(DUMUSR)
      END (*ELSE*);
   END (*SAVECHAR*);


  PROCEDURE KILL;
(* *KILL* WILL REMOVE A PLAYER'S FILE ENTRY, IF IT EXISTS.
HIS *USER* DATA RECORD IS ALSO DESTROYED. *)

   VAR
    NAM: ALFA;

   BEGIN
    DELETEUSER(USER, USERTAIL);
    IF SEARCHPLINDEX(USER ^.NAME) > 0
    THEN
     BEGIN
      WRITELN(TERM, 'PLAYER FILE SPACE RELEASED.');  NAM := USER ^.NAME;
      IF USER ^.LVL < 4  THEN USER ^.NAME := EMPTY  ELSE USER ^.NAME[1] := '*';
      USER ^.LASTACCESS := (31 + TODAY - 9) MOD 31;
(* SET PLAYER TIMEOUT TO 9 DAYS AGO. PLAYER WILL BE ERASED AT 10 DAYS *)
      WRITEPLAYER(USER, NAM);
     END (*IF*)
    ELSE WRITEUSR(USER, FALSE) (* DESTROY USER REC *);
    NUSERS := NUSERS - 1;  IF NUMQUEUED > 0  THEN NEXTLIMBO;
   END (*KILL*);


  PROCEDURE QUIT(CMDCODE: INTEGER);
(* QUIT LOGS OFF THE PLAYER, ISSUSES MSGS, AND ATTEMPTS TO SAVE
HIS FILE *)

   VAR
    WORD: ALFA;
    NUM: INTEGER;
    DELAY, ILOOP: INTEGER;

   BEGIN
    ERRLOC := 'QUIT      ';  DELAY := REALTIME - USER ^.HITATTIME;
    GETWORD(WORD, NUM, BUFFER, LENBUF, LOC);  USER ^.ENTRY := XCMD;
    IF WORD[1] = 'Y'
    THEN
     IF DELAY = 0  THEN WRITELN(TERM, 'NOT WHILE YOU ARE BEING ATTACKED!')
     ELSE
      IF DELAY < QUITWAIT
      THEN
       WRITELN(TERM, 'SORRY, YOU MUST WAIT AT LEAST ', QUITWAIT - DELAY: 0,
         ' MORE SECONDS BEFORE QUITTING.')
      ELSE
       BEGIN
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, ALL) DO
         BEGIN
          WRITE(TERMLIST[ILOOP], '### ', PS(USER ^.NAME));
          IF CMDCODE = 39
          THEN
           WRITELN(' JUST KILLED ', PRO[USER^.SEX], 'SELF.', ' WE SHALL ALL MISS ',
             PRO[USER^.SEX], ' DEARLY.')
          ELSE WRITELN(' HAS QUIT ADVENTURING.');
         END (*FOR*);
        IF CMDCODE = 39
        THEN
         BEGIN IF USER ^.LVL >= 5  THEN DAYMSG('SUI', USER, BLANKS, 0);  KILL END
        ELSE LOGOFF(USER, TRUE);
        WRITELN(TERM, 'END MILIEU.');  WRITECONTROL(MTLO, ZEROPARM, TERM);  WRITELN;
        USER := NIL (* BYE BYE*);
       END (*ELSE*)
   END (*QUIT*);


  PROCEDURE APPEAL;

   VAR
    DM: USERPOINT;
    EXIT, ILOOP: INTEGER;


   FUNCTION FINDDM(DMUSR: USERPOINT): BOOLEAN;

    BEGIN FINDDM := (DMUSR ^.SSJ) AND (DMUSR ^.STATUS = SNORMAL) END;


   BEGIN (*APPEAL*)
    ERRLOC := 'APPEAL    ';
    IF NOT SPELLIMIT
    THEN
     BEGIN
      DM := MATCHUSER(USERTAIL, FINDDM);
      IF DM <> NIL  THEN WRITELN(TERM, 'DING DONG!  YOU WAKE UP THE DM.')
      ELSE WRITELN(TERM, 'SORRY, THE DM IS NOT HERE RIGHT NOW.  TRY AGAIN LATER.');
      EXIT := 0;
      FOR ILOOP := 1 TO 6 DO EXIT := EXIT + ROOM[USER ^.RMCODE].ADJOIN[ILOOP];
      EXIT := EXIT + ROOM[USER ^.RMCODE].OUT;
      IF DM = NIL
      THEN
       IF (EXIT = 0) AND (ROOM[USER ^.RMCODE].RMOBJECTTAIL = NIL)
       THEN
        BEGIN
         WRITELN(TERM, 'SIGH, VERY WELL....');  DELETEPLAYER(USER, USER ^.RMCODE);
         PLACEPLAYER(USER, 1);  WRITELN(TERM, '***POOF*** YOU ARE ELSEWHERE..');
        END (*IF*);
      WHILE DM <> NIL DO
       BEGIN
IF NOT DM^.NONEXISTANT THEN
BEGIN
        WRITELN(DM ^.TRM, '*** ', PS(USER ^.NAME), ' SUMMONS YOUR ASSISTANCE.');
        WRITELN(DM ^.TRM, '*** PIETY RATING = ', USER ^.PTY: 0);
        WRITE(DM ^.TRM, '*** RECOMMENDED REACTION:');
        CASE USER ^.PTY OF
         - 10, - 9, - 8, - 7, - 6, - 5, - 4, - 3:
          WRITELN(' PUT THEM IN A LOT OF TROUBLE.');
         - 2, - 1, 0, 1, 2: WRITELN(' LAUGH IN HIS/HER FACE.');
         3, 4, 5: WRITELN(' MAKE THE SITUATION EVEN WORSE FOR THEM.');
         6, 7, 8: WRITELN(' NEUTRAL.  ASK WHAT IS WRONG. DO NOT REACT.');
         9, 10, 11: WRITELN(' TEPID.  HELP PLAYER, BUT NOT TOO MUCH.');
         12, 13, 14: WRITELN(' POSITIVE.  HELP PLAYER OUT OF SITUATION.');
         15, 16, 17, 18: WRITELN(' VERY POSITIVE.  INTERVENE IMMEDIATELY.');
         19, 20, 21, 22, 23, 24, 25:
          WRITELN(' SAVE PLAYER AND THEN SEND HIM ON A QUEST.');
        END (*CASE*);
END;
        DM := MATCHUSER(DM ^.NEXTUSER, FINDDM)
       END (*WHILE*);
      USER ^.PTY := MAX(- 10, USER ^.PTY - 1);
     END (*IF*)
   END (*APPEAL*);


  PROCEDURE ENTERSPELL(WORD: ALFA; NUM: INTEGER);

   VAR
    DUMMY: ALFA;

   BEGIN
    IF READYCHECK(USER ^.LASTATK)
    THEN
     BEGIN
      IF WORDMATCH(WORD, SPELLEN, SPELLIST) > 0
      THEN GETWORD(WORD, NUM, BUFFER, LENBUF, LOC);
      IF NUM = 0  THEN GETWORD(DUMMY, NUM, BUFFER, LENBUF, LOC);
      USER ^.WDATA := WORD;  USER ^.DATA := NUM;  USER ^.ENTRY := XSPELL;
     END (*IF*)
   END (*ENTERSPELL*);


  PROCEDURE RETURNOBJ(WORD: ALFA; NUM: INTEGER);

   VAR
    OBJECT: OBJECTPOINT;

   BEGIN
    OBJECT := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);
    IF OBJECT = NIL  THEN WRITELN(TERM, 'OBJECT NOT FOUND.')
    ELSE BEGIN STOPUSING(USER, OBJECT);  WRITELN(TERM, 'OK') END
   END (*RETURNOBJ*);


  PROCEDURE STEALOBJ(WORD: ALFA; NUM: INTEGER);

   VAR
    NOTICE: BOOLEAN;
    WORD2: ALFA;
    STEALCHANCE, WGHT, NUM2: INTEGER;
    STEAL: BOOLEAN;
    PLYR: USERPOINT;
    OBJ: OBJECTPOINT;

   BEGIN
    WITH USER ^ DO
     IF NOT (CLASS IN [DM, THIEF])
     THEN WRITELN(TERM, 'ONLY THIEVES CAN STEAL OBJECTS!')
     ELSE
      IF READYCHECK(LASTATK)
      THEN
       BEGIN
        GETWORD(WORD2, NUM2, BUFFER, LENBUF, LOC);
        PLYR := FINDPLAYER(WORD2, ROOM[RMCODE].RMPLAYERTAIL);
        IF WORD2 = BLANKS
        THEN WRITELN(TERM, 'FORMAT IS  STEAL <OBJECT> FROM <PLAYER>')
        ELSE
         IF PLYR = NIL  THEN WRITELN(TERM, 'THAT PLAYER IS NOT HERE!')
         ELSE
IF ROOM[RMCODE].SAFE THEN WRITELN(TERM,'THIS IS A SAFE HAVEN!')
 ELSE
          BEGIN
           LASTATK := REALTIME + 15;
           OBJ := FINDOBJECT(WORD, NUM, PLYR ^.OBJECTTAIL);
           IF OBJ = NIL  THEN WGHT := 0  ELSE WGHT := OBJ ^.WEIGHT;
           STEALCHANCE := 4 * (LVL - PLYR ^.LVL + DEX DIV 2 - 6) - WGHT;
           IF PLYR ^.CLASS = THIEF  THEN STEALCHANCE := STEALCHANCE - 16;
           IF HIDDEN  THEN STEALCHANCE := STEALCHANCE + 16;
           IF PLYR ^.SSJ  THEN STEALCHANCE := - 1;
           NOTICE := RND(100) >= STEALCHANCE;
           IF OBJ = NIL  THEN STEAL := FALSE  ELSE STEAL := RND(100) < STEALCHANCE;
           IF OBJ <> NIL THEN
            WITH PLYR ^ DO
             IF (OBJ = USWEAP) OR (OBJ = USARM) OR (OBJ = USSHIELD)
             THEN BEGIN STEAL := FALSE;  NOTICE := TRUE END;
           DEFPLAYER := PLYR;  DEFMON := NIL;
           IF NOTICE
           THEN
            BEGIN
             WRITE(PLYR ^.TRM, PS(NAME));
             IF STEAL  THEN WRITE(' STEALS ')  ELSE WRITE(' FAILS TO STEAL ');
             IF OBJ <> NIL  THEN PRINTOBJ(OBJ ^, TRUE);  WRITELN(' FROM YOU!')
            END (*IF*);
           IF NOTICE AND (RND(2) = 1)  THEN WRITELN(TERM, 'YOU WERE DISCOVERED!');
           IF NOT STEAL  THEN WRITELN(TERM, 'YOU FAIL TO STEAL IT!')
           ELSE
            BEGIN
             WRITELN(TERM, 'YOU STEAL IT!');  STOPUSING(PLYR, OBJ);
             IF DELETEOBJECT(OBJ, PLYR ^.OBJECTTAIL)
             THEN PLYR ^.OBJECTTAIL := PLYR ^.OBJECTTAIL ^.NEXT;
             PLYR ^.WEIGHT := MAX(0, PLYR ^.WEIGHT - OBJ ^.WEIGHT);
             IF WEIGHT + OBJ ^.WEIGHT > STR * 10
             THEN
              BEGIN
               WRITELN(TERM, 'IT IS TOO HEAVY TO CARRY! YOU DROP IT.');
               OBJ ^.NEXT := ROOM[RMCODE].RMOBJECTTAIL;
               ROOM[RMCODE].RMOBJECTTAIL := OBJ;
              END (*IF*)
             ELSE
              BEGIN
               OBJ ^.INVISIBLE := FALSE;  WEIGHT := MIN(2500, WEIGHT + OBJ ^.WEIGHT);
               OBJ ^.NEXT := OBJECTTAIL;  OBJECTTAIL := OBJ;
              END (*ELSE*)
            END (* STOLE IT*)
          END (*ELSE*)
       END (*ELSE*)
   END (*STEALOBJ*);


  PROCEDURE PARLEY(WORD: ALFA; NUM: INTEGER);
(* PARLEY, OR TALK WITH, A MONSTER *)

   VAR
    OPT, ILOOP, N1, N2: INTEGER;
    OBJ: OBJECTPOINT;
    MON: MONSTERPOINT;

   BEGIN
    MON := FINDMONSTER(WORD, NUM, ROOM[USER ^.RMCODE].RMMONSTERTAIL);
    IF MON = NIL  THEN WRITELN(TERM, 'THAT NON-PLAYER CHARACTER IS NOT HERE.')
    ELSE
     WITH MON ^ DO
      BEGIN
       OPT := MPARLEY;  IF OPT = 9  THEN OPT := RND(8);
       FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
        WRITELN(TERMLIST[ILOOP], PS(USER ^.NAME), ' TALKS WITH ', PM(MON), '.');
       CASE OPT OF
        1:
         BEGIN
          N1 := 0;  MPARLEY := 3 (* NO MORE TO SELL *);
          IF WHICHOBJ > 0  THEN N1 := OBJINDEX[WHICHOBJ, RND(6)];
          IF N1 = 0  THEN WRITELN(TERM, 'I HAVE NOTHING TO SELL YOU, GOOD SIR.')
          ELSE
           BEGIN
USER^.DATA := TRUNC(RANOBJLIST[N1].PRICE * 1.5) - RND(RANOBJLIST[N1].PRICE);
            USER ^.LASTATK := N1;
(* THIS IS A KLUDGE PATCH.  LAST HOLDS THE NUMBER OF THE OBJECT FOR SALE. *)
            WRITE(TERM, PM(MON), 'SAYS, I WILL SELL YOU ');
            PRINTOBJ(RANOBJLIST[N1], FALSE);
            WRITELN(' FOR A MERE ', USER ^.DATA: 0, ' SHILLINGS.');
            USER ^.ENTRY := XPARLEY;
           END (*ELSE*)
         END (*1*);
        2, 3, 4:
         BEGIN
          IF OPT = 2  THEN N1 := 19 + RND(11) (* BAD MESSAGES 20-30 *)
          ELSE
           IF OPT = 3  THEN N1 := 10 + RND(10) (* GOOD MESSAGES 11-20 *)
           ELSE N1 := 10 + RND(20) (* EITHER MESSAGES 11-30 *);
          WRITE(TERM, PM(MON), ' SAYS, ');  PRINTDESC(1, N1, 0, FALSE);  WRITELN;
         END (*2*);
        5, 8:
         IF USER ^.LVL < 5 + LVL  THEN WRITELN(TERM, PM(MON), ' STANDS ITS GROUND!')
         ELSE
          BEGIN
           N1 := 0;
           IF OPT = 8
           THEN
            BEGIN
             MPARLEY := 5 (* NO MORE TREASURE *);
             IF WHICHOBJ > 0  THEN N1 := OBJINDEX[WHICHOBJ, RND(6)];
             IF N1 > 0
             THEN
              BEGIN
               NEW(OBJ);  OBJ ^ := RANOBJLIST[N1];
               OBJ ^.NEXT := ROOM[USER ^.RMCODE].RMOBJECTTAIL;
               ROOM[USER ^.RMCODE].RMOBJECTTAIL := OBJ;  N1 := 1;
              END (*IF*)
            END (*IF*);
           N2 := RND(2) (* MERCY OR RUN? *);  WRITE(TERM, PM(MON), ' ');
           IF N1 > 0 THEN
            BEGIN WRITE('THROWS DOWN ');  PRINTOBJ(OBJ ^, FALSE);  WRITE(' AND ');
            END (*IF*);
           IF N2 = 1  THEN WRITELN('BEGS FOR MERCY!')
           ELSE WRITELN('FLEES FROM YOUR SIGHT!');
           FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
            BEGIN
             WRITE(TERMLIST[ILOOP], PM(MON), ' ');
             IF N1 > 0 THEN
              BEGIN WRITE('THROWS DOWN ');  PRINTOBJ(OBJ ^, FALSE);  WRITE(' AND ')
              END (*IF*);
             IF N2 = 1  THEN WRITELN('BEGS FOR MERCY!')
             ELSE WRITELN('FLEES FROM ', PS(USER ^.NAME), '''S SIGHT!')
            END (*FOR*);
           IF N2 = 2 (* RUN *)
           THEN BEGIN DELETEMONSTER(MON, USER ^.RMCODE);  DESTROY(MON) END;
          END (*ELSE*);
        6:
         IF RND(2) = 2
         THEN WRITELN(TERM, PM(MON), ' SAYS SOMETHING IN A STRANGE TONGUE.')
         ELSE WRITELN(TERM, PM(MON), ' MAKES NO APPARENT RESPONSE.');
        7:
         BEGIN
          DEFPLAYER := USER;  WRITELN(TERM, PM(MON), ' ATTACKS YOU!');
          FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
           WRITELN(TERMLIST[ILOOP], PM(MON), ' ATTACKS ', PS(USER ^.NAME), '!');
         END (*7*);
        10:
         BEGIN
          WRITELN(TERM, '** ZAP **   ', PM(MON), ' TELEPORTS YOU ELSEWHERE!');
          FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
           WRITELN(TERMLIST[ILOOP], PM(MON), ' MAKES ', PS(USER ^.NAME),
             ' VANISH IN A CLOUD OF SMOKE!');
          DELETEPLAYER(USER, USER ^.RMCODE);  PLACEPLAYER(USER, 30 + RND(570))
         END (*10*);
        11, 12, 13, 14, 15:
         BEGIN
          WRITE(TERM, PM(MON), ' SAYS, ');  PRINTDESC(1, OPT + 20, 0, FALSE);
          WRITELN
         END (*11*);
       OTHERWISE
        WRITELN(TERM, PM(MON), ' MAKES NO APPARENT RESPONSE.')
       END (*CASE*);
      END (*WITH*)
   END (*PARLEY*);


  PROCEDURE BUY(WORD: ALFA; NUM, RM: INTEGER);

   VAR
    ILOOP, SECSDK: INTEGER;
    OBJECT: OBJECTPOINT;

   BEGIN
    ERRLOC := ' FIFTEEN  ';
    WITH USER ^ DO
     BEGIN
      CASE W(RM) OF
       3:
        BEGIN
         IF MONEY >= 1
         THEN
          BEGIN
           MONEY := MONEY - 1;  IF DRUNK < REALTIME  THEN DRUNK := REALTIME;
           DRUNK := DRUNK + 30;  SECSDK := DRUNK - REALTIME;  WRITE(TERM);
           IF SECSDK <= 60  THEN WRITELN('THAT WAS GOOD!')
           ELSE
            IF SECSDK <= 120  THEN WRITELN('THAT''S GOOD! (HIC)')
            ELSE
             IF SECSDK <= 180  THEN WRITELN('THASH GUD!')
             ELSE
              BEGIN
               DELETEPLAYER(USER, RM);  RM := RND(10);  PLACEPLAYER(USER, RM);
               WRITELN('YOU SEEM TO HAVE STAGGERED OFF SOMEWHERE... YOU FIND');
               ROOMDISPLAY(RMCODE, FALSE)
              END (*ELSE*)
          END (*IF*)
         ELSE WRITELN(TERM, 'BARTENDER SAYS, "YOUR CREDIT IS NO GOOD HERE!"');
        END (*3*);
       4: (* BUY NEWSPAPER *)
        IF MONEY < 1  THEN WRITELN(TERM, '"SORRY BUDDY, YOU GOT NO MONEY."')
        ELSE
         BEGIN
          MONEY := MONEY - 1;  WRITELN(TERM);
          WRITELN(TERM, '(((  THE COUNTY PRESS.   ISSUE # ', NUMRUN: 0, '.  DAY ', PN
            (TODAY), ' )))');
          WRITELN(TERM);
          FOR ILOOP := 1 TO 5 DO
           IF NEWSBUF[ILOOP, 1] <> COL  THEN WRITELN(TERM, PO(NEWSBUF[ILOOP]));
          WRITELN(TERM);
          FOR ILOOP := 1 TO 3 DO
           IF YLVL[ILOOP] > 0
           THEN
            BEGIN
             WRITE(TERM, PS(YNAME[ILOOP]), ', THE ', PNTH(YLVL[ILOOP]), ' LEVEL ', PS
               (YCLASS[ILOOP]), ', WAS ');
             CASE RND(5) OF
              1: WRITE('UNEXPECTEDLY ');
              2: WRITE('SUDDENLY ');
              3: WRITE('MYSTERIOUSLY ');
              4: WRITE('HORRIBLY ');
              5: WRITE('VICIOUSLY ');
             END (*CASE*);
             CASE RND(5) OF
              1: WRITE('MURDERED ');
              2: WRITE('KILLED ');
              3: WRITE('SLAIN ');
              4: WRITE('BUTCHERED ');
              5: WRITE('"TERMINATED" ');
             END (*CASE*);
             WRITELN('YESTERDAY.');
             IF YBUF[ILOOP, 1] <> COL  THEN WRITELN(TERM, PO(YBUF[ILOOP]));
             WRITELN(TERM);
            END (*IF*);
         END (*ELSE*);
       10: (* BUY ARMAMENTS *)
        BEGIN
         IF (NUM < 1) OR (NUM > MIN(RANOBJLEN, 20))
         THEN WRITELN(TERM, 'ITEM # OUT OF BOUNDS.')
         ELSE
          IF RANOBJLIST[NUM].PRICE > USER ^.MONEY
          THEN WRITELN(TERM, 'YOU DON''T HAVE ENOUGH CASH TO BUY THAT.')
          ELSE
           BEGIN
            USER ^.MONEY := USER ^.MONEY - RANOBJLIST[NUM].PRICE;  NEW(OBJECT);
            OBJECT ^ := RANOBJLIST[NUM];  OBJECT ^.NEXT := ROOM[RMCODE].RMOBJECTTAIL;
            ROOM[RMCODE].RMOBJECTTAIL := OBJECT;
            WRITELN(TERM, '"HERE YOU ARE, SIR.  THANK YOU!');
            WRITELN(TERM, 'OH, BE SURE TO TAKE IT WITH YOU AS YOU LEAVE!"');
           END (*ELSE*)
        END (*10*);
      OTHERWISE
       WRITELN(TERM, 'NOTHING HERE TO PURCHASE.')
      END (*CASE*)
     END (*WITH*)
   END (*BUY*);


  PROCEDURE CATALOG;
(* OBTAIN A LIST OF ARMAMENTS FOR SALE FROM ARMORY *)

   VAR
    ILOOP: INTEGER;

   BEGIN
    ERRLOC := ' SIXTEEN  ';
    IF W(USER ^.RMCODE) <> 10  THEN WRITELN(TERM, 'I DON''T UNDERSTAND.')
    ELSE
     BEGIN
      WRITELN(TERM, 'INVENTORY OF ARMAMENTS FOR SALE');  WRITELN(TERM);
      WRITELN(TERM, 'TO PURCHASE ENTER:   BUY <ITEM NUMBER>');  WRITELN(TERM);
      WRITELN(TERM, '#  TYPE       COST WEIGHT NAME');
      FOR ILOOP := 1 TO MIN(RANOBJLEN, 20) DO
       WITH RANOBJLIST[ILOOP] DO
        BEGIN
         WRITE(TERM, ILOOP: 2, ' ');
         CASE OBCLASS OF
          WEAP: WRITE('WEAPON ');
          SHIELD: WRITE('SHIELD ');
          ARMOR: WRITE('ARMOR  ');
         OTHERWISE
          WRITE('OTHER  ');
         END (*CASE*);
         WRITE(PRICE: 8, ' ');  WRITE(WEIGHT: 5, ' ');
         PRINTOBJ(RANOBJLIST[ILOOP], FALSE);
         IF OBCLASS = WEAP  THEN WRITELN(', ', MINHP: 0, '-', MAXHP: 0, ' HITS.')
         ELSE WRITELN('.');
        END (*WITH*)
     END (*ELSE*)
   END (*CATALOG*);


  PROCEDURE RUN;
(* RUN AWAY LIKE HELL.  WEAPON AND SHIELD DROPPED. *)

   VAR
    DIR: 0..7;
    ROOMNUM, ILOOP: INTEGER;
    GOODIR, DRWEAP, DRSHIELD: BOOLEAN;

   BEGIN
    WITH USER ^ DO
     BEGIN
      ILOOP := 4;  GOODIR := FALSE;  DRWEAP := FALSE;  DRSHIELD := FALSE;  DIR := 0;
      REPEAT
       DIR := RND(7);
       IF DIR < 7  THEN GOODIR := (ROOM[RMCODE].ADJOIN[DIR] > 0)
       ELSE GOODIR := (ROOM[RMCODE].OUT > 0);
       ILOOP := ILOOP - 1;
      UNTIL GOODIR OR (ILOOP = 0);
      IF NOT GOODIR  THEN WRITELN(TERM, 'YOU FAIL TO ESCAPE!')
      ELSE
       BEGIN
        IF USWEAP <> NIL
        THEN
         BEGIN
          IF DELETEOBJECT(USWEAP, OBJECTTAIL)  THEN OBJECTTAIL := OBJECTTAIL ^.NEXT;
          WEIGHT := WEIGHT - USWEAP ^.WEIGHT;
          USWEAP ^.NEXT := ROOM[RMCODE].RMOBJECTTAIL;
          ROOM[RMCODE].RMOBJECTTAIL := USWEAP;  USWEAP := NIL;  DRWEAP := TRUE
         END (*IF*);
        IF USSHIELD <> NIL
        THEN
         BEGIN
          IF DELETEOBJECT(USSHIELD, OBJECTTAIL)
          THEN OBJECTTAIL := OBJECTTAIL ^.NEXT;
          WEIGHT := WEIGHT - USSHIELD ^.WEIGHT;
          USSHIELD ^.NEXT := ROOM[RMCODE].RMOBJECTTAIL;
          ROOM[RMCODE].RMOBJECTTAIL := USSHIELD;  STOPUSING(USER, USSHIELD);
          DRSHIELD := TRUE;
         END (*IF*);
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
         BEGIN
          WRITE(TERMLIST[ILOOP], PS(NAME), ' ');
          IF DRWEAP OR DRSHIELD  THEN WRITE('DROPS HIS ');
          IF DRWEAP  THEN WRITE('WEAPON AND ');
          IF DRSHIELD  THEN WRITE('SHIELD AND ');
          WRITELN('RUNS AWAY LIKE A BLITHERING IDIOT!')
         END (*FOR*);
        WRITELN(TERM, 'AARGGHH!!  YOU RUN LIKE CRAZY!');  DELETEPLAYER(USER, RMCODE);
        ROOM[RMCODE].LASTDIR := DIR;
        IF DIR < 7
        THEN
         BEGIN
          ROOMNUM := ROOM[RMCODE].ADJOIN[DIR];
          IF DIR IN ROOM[RMCODE].THOUSANDS  THEN ROOMNUM := ROOMNUM + 1000;
          PLACEPLAYER(USER, ROOMNUM)
         END (*IF*)
        ELSE PLACEPLAYER(USER, ROOM[RMCODE].OUT);
        ROOMDISPLAY(RMCODE, FALSE)
       END (*ELSE*)
     END (*WITH*)
   END (*RUN*);


  PROCEDURE PRINTEXP;

   BEGIN
    WITH USER ^ DO
     BEGIN
      WRITELN(TERM, 'YOU NEED ', MAX(0, EXPR(LVL + 1) - EXPR(LVL) - EXPERIENCE): 0,
        ' MORE EXPERIENCE POINTS TO REACH THE NEXT LEVEL.');
      WRITELN(TERM, 'YOU HAVE ', MONEY: 0, ' SHILLINGS IN CASH.')
     END (*WITH*)
   END (*PRINTEXP*);


  PROCEDURE PAWN(WORD: ALFA; NUM: INTEGER);
(* CASH IN AN OBJECT FOR MONEY AND EXP *)

   VAR
    AMOUNT: INTEGER;
    OBJECT: OBJECTPOINT;

   BEGIN
    IF W(USER ^.RMCODE) <> 8  THEN WRITELN(TERM, 'GO TO THE PAWN SHOP FIRST.')
    ELSE
     BEGIN
      OBJECT := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);
      IF OBJECT <> NIL
      THEN
       BEGIN
        STOPUSING(USER, OBJECT);  AMOUNT := OBJECT ^.PRICE;
        WITH OBJECT ^ DO
         CASE OBCLASS OF
          WEAP:
           IF STRIKESLEFT < 100
           THEN AMOUNT := ROUND(AMOUNT * (STRIKESLEFT / 100.0) + 1.00);
          SHIELD:
           IF SHHITSLEFT < 50  THEN AMOUNT := ROUND(AMOUNT * (SHHITSLEFT / 50.0));
          ARMOR:
           IF ARMHITSLEFT < 50  THEN AMOUNT := ROUND(AMOUNT * (ARMHITSLEFT / 50.0));
          MAGDEVICE: IF NUMCHARGES = 0  THEN AMOUNT := 5;
         OTHERWISE
         END (*CASE*);
        WRITE(TERM, '"WELL, I''LL GIVE YOU ', AMOUNT: 0, ' SHILLINGS FOR ');
        PRINTOBJ(OBJECT ^, TRUE);  WRITELN('.  IS THIS');
        WRITELN(TERM, 'TO YOUR SATISFACTION?"');  USER ^.ENTRY := XSELL;
        USER ^.DATA := AMOUNT;  USER ^.USWEAP := OBJECT;
       END (*IF*)
      ELSE WRITELN(TERM, 'YOU DON''T OWN THAT ITEM.')
     END (*ELSE*)
   END (*PAWN*);


  FUNCTION LOOK(WORD: ALFA; NUM: INTEGER; CMDCODE: INTEGER): INTEGER;

   VAR
    PLAYER: USERPOINT;
    MONSTER: MONSTERPOINT;
    TOBJ, OBJECT: OBJECTPOINT;
    LEGAL: BOOLEAN;
    LEV: INTEGER;
    DUMMY: ALFA;
    WHERE:
     (GROUND, PERSON);

   BEGIN
    LOOK := 0;  ERRLOC := 'LOOK      ';  LEGAL := TRUE;
    IF CMDCODE = 31 THEN
     BEGIN
      LEGAL := SPELLCOST(USER, 10, 5, 10);
      IF LEGAL  THEN LEGAL := LEGAL AND NOT SPELLIMIT
     END (*IF*);
    IF LEGAL
    THEN
     WITH ROOM[USER ^.RMCODE] DO
      BEGIN
       PLAYER := FINDPLAYER(WORD, RMPLAYERTAIL);
       IF PLAYER <> NIL
       THEN
        WITH PLAYER ^ DO
         BEGIN
          IF USARM = NIL  THEN WRITE(TERM, 'YOU SEE ')  ELSE WRITE(TERM);
          WRITE(PS(NAME), ' THE ', PS(CNAME[CLASS]));
          IF USARM <> NIL
          THEN BEGIN WRITE(' IS WEARING ');  PRINTOBJ(USARM ^, FALSE) END;
          WRITELN('.');
          IF (USWEAP <> NIL) OR (USSHIELD <> NIL)
          THEN
           BEGIN
            WRITE(TERM);
            IF SEX = MALE  THEN WRITE('HE ')
            ELSE  WRITE('SHE ');
            WRITE('IS HOLDING ');
            IF USWEAP <> NIL THEN
             BEGIN
              PRINTOBJ(USWEAP ^, FALSE);  IF USSHIELD <> NIL  THEN WRITE(' AND ')
             END (*IF*);
            IF USSHIELD <> NIL  THEN PRINTOBJ(USSHIELD ^, FALSE);  WRITELN('.');
           END (*IF*);
          IF CMDCODE = 31  THEN PLAYERDISPLAY(PLAYER)
         END (*WITH*)
       ELSE (*OBJECT?*)
        BEGIN
         OBJECT := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);  WHERE := PERSON;
         IF OBJECT = NIL THEN
          BEGIN WHERE := GROUND;  OBJECT := FINDOBJECT(WORD, NUM, RMOBJECTTAIL) END;
         IF OBJECT <> NIL
         THEN
          IF (OBJECT ^.OBCLASS = SCROLL) AND (WHERE = GROUND)
          THEN WRITELN(TERM, 'PICK IT UP FIRST, EAGLE EYES.')
          ELSE
           BEGIN
            IF CMDCODE = 31  THEN OBJDISPLAY(OBJECT)
            ELSE
             BEGIN
              IF (CMDCODE = 64) AND (OBJECT ^.OBCLASS = SCROLL)
              THEN
               BEGIN
                IF READYCHECK(USER ^.LASTATK)
                THEN
                 BEGIN
                  GETWORD(USER ^.WDATA, USER ^.DATA, BUFFER, LENBUF, LOC);
                  LOOK := OBJECT ^.SPELL
                 END (*IF*)
                ELSE CMDCODE := 31 (*KLUDGE PATCH.. INHIBIT SCROLL DISTRUCTION *)
               END (*IF*)
              ELSE
               BEGIN
                WRITE(TERM);
                IF OBJECT ^.DESCREC <> 0
                THEN PRINTDESC(OBJECT ^.DESCREC, OBJECT ^.DESCCODE, 0, FALSE)
                ELSE
                 BEGIN
                  IF WHERE = GROUND  THEN WRITE('IT''S ')
                  ELSE WRITE('YOU ARE HOLDING ');
                  PRINTOBJ(OBJECT ^, FALSE)
                 END (*ELSE*);
WRITELN;
IF OBJECT^.OBCLASS = WEAP THEN
  BEGIN
WRITE(TERM,'THIS IS A ');
CASE OBJECT^.WEAPTYPE OF
SHARP: WRITE('SHARP, BLADED');
THRUST: WRITE('THRUSTING');
BLUNT: WRITE('BLUNTED');
LONG: WRITE('POLE');
END;
WRITELN(' WEAPON.')
END;
                IF OBJECT ^.OBCLASS = CHEST
                THEN
                 IF NOT OBJECT ^.CLOSED
                 THEN
                  IF OBJECT ^.OBJECTTAIL <> NIL
                  THEN
                   BEGIN
                    WRITE(TERM, 'INSIDE ');  PRINTOBJ(OBJECT ^, TRUE);
                    WRITELN(' YOU SEE THE FOLLOWING:');  TOBJ := OBJECT ^.OBJECTTAIL;
                    WHILE TOBJ <> NIL DO
                     BEGIN
                      WRITE(TERM, '   ');  PRINTOBJ(TOBJ ^, FALSE);  WRITELN;
                      TOBJ := TOBJ ^.NEXT
                     END (*WHILE*)
                   END (*IF*)
                  ELSE WRITELN(TERM, 'IT''S EMPTY.')
                 ELSE WRITELN(TERM, 'IT''S CLOSED.');
               END (*ELSE*);
              IF (OBJECT ^.OBCLASS = SCROLL) AND (CMDCODE <> 31)
              THEN
               BEGIN
                WRITE(TERM);  PRINTOBJ(OBJECT ^, TRUE);  WRITELN(' DISINTEGRATES!.');
                IF DELETEOBJECT(OBJECT, USER ^.OBJECTTAIL)
                THEN USER ^.OBJECTTAIL := USER ^.OBJECTTAIL ^.NEXT;
                USER ^.WEIGHT := USER ^.WEIGHT - OBJECT ^.WEIGHT;  DISPOSE(OBJECT);
               END (*IF*);
             END (*ELSE*)
           END (*IF*)
         ELSE (*MONSTER?*)
          BEGIN
           IF NUM = 0  THEN GETWORD(DUMMY, NUM, BUFFER, LENBUF, LOC);
           MONSTER := FINDMONSTER(WORD, NUM, RMMONSTERTAIL);
           IF MONSTER = NIL  THEN WRITELN(TERM, 'I DON''T SEE THAT HERE.')
           ELSE
            IF CMDCODE = 31  THEN MONDISPLAY(MONSTER)
            ELSE
              BEGIN
               LEV := (MONSTER ^.LVL DIV 5) * 5 + 1;
               WRITELN(TERM, 'IT''S A ', PS(MONSTER ^.NAME), ', ', PNTH(LEV), 'TO ',
                 PNTH(LEV + 4), 'LEVEL.');
               IF MONSTER ^.MAGIC  THEN WRITELN(TERM, 'IT LOOKS MAGICAL!');
               IF MONSTER ^.SLOWREACT OR MONSTER ^.FASTREACT
               THEN WRITELN(TERM, 'IT LOOKS HOSTILE!');
              END (*IF*)
          END (*ELSE*)
        END (*ELSE*)
      END (*WITH*)
   END (*LOOK*);


  FUNCTION USEOBJECT(WORD: ALFA; NUM: INTEGER): INTEGER;
(* "USE", "HOLD", "WIELD" OR "DRAW" A WEAPON, SHIELD, OR ARMOR.
IF USER TRIES TO "USE" ANYTHING ELSE, NOTHING HAPPENS. *)

   VAR
    OBJECT: OBJECTPOINT;
    PLYR: USERPOINT;
    ILOOP: INTEGER;

   BEGIN
    USEOBJECT := 0;  ERRLOC := 'USEOBJECT ';
    OBJECT := FINDOBJECT(WORD, NUM, USER ^.OBJECTTAIL);
    IF OBJECT = NIL  THEN WRITELN(TERM, 'BUT YOU AREN''T CARRYING THAT!')
    ELSE
     WITH USER ^ DO
      CASE OBJECT ^.OBCLASS OF
       WEAP:
IF (USER^.CLASS = CLERIC) AND (OBJECT^.WEAPTYPE IN [SHARP,THRUST]) THEN
 WRITELN(TERM,'IT IS AGAINST YOUR FAITH TO USE WEAPONS THAT DRAW BLOOD!')
ELSE
        BEGIN
         STOPUSING(USER, USWEAP);  USWEAP := OBJECT;
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
          BEGIN
           WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' PULLS OUT ');
           PRINTOBJ(OBJECT ^, FALSE);  WRITELN('!')
          END (*FOR*);
         WRITELN(TERM, 'YOU READY YOUR WEAPON!')
        END (*WEAP*);
       ARMOR:
        IF (CLASS = MAGICUSER) AND (OBJECT ^.ARMPLUS > 1)
        THEN WRITELN(TERM, 'MAGIC-USERS CANNOT WEAR SUCH ARMOR!')
        ELSE
         BEGIN
          STOPUSING(USER, USARM);  USARM := OBJECT;
          AC := MAX(- 50, MIN(AC - USARM ^.ARMPLUS, 50));
          WRITELN(TERM, 'YOU PUT ON YOUR ARMOR.')
         END (*ARMOR*);
       SHIELD:
        IF (CLASS = MAGICUSER) AND (OBJECT ^.SHPLUS > 1)
        THEN WRITELN(TERM, 'MAGIC-USERS CANNOT USE SUCH SHIELDS!')
        ELSE
         BEGIN
          STOPUSING(USER, USSHIELD);  USSHIELD := OBJECT;
          AC := MAX(- 50, MIN(AC - USSHIELD ^.SHPLUS, 50));
          WRITELN(TERM, 'YOU READY YOUR SHIELD!')
         END (*SHIELD*);
       MAGDEVICE:
        IF OBJECT ^.NUMCHARGES <= 0
        THEN
         BEGIN
          WRITELN(TERM, 'NOTHING HAPPENS.. IT''S DISCHARGED/EMPTY.');
          OBJECT ^.PERMANENT := FALSE
         END (*IF*)
        ELSE
         IF READYCHECK(USER ^.LASTATK)
         THEN
          BEGIN
           GETWORD(WORD, NUM, BUFFER, LENBUF, LOC);  WDATA := WORD;
           IF NUM = 0  THEN GETWORD(WORD, NUM, BUFFER, LENBUF, LOC);  DATA := NUM;
           OBJECT ^.NUMCHARGES := OBJECT ^.NUMCHARGES - 1;
           USEOBJECT := - (OBJECT ^.SPELL)
          END (*ELSE*);
       TELEPORT:
        IF (OBJECT ^.TACTIVERM <> W(RMCODE)) AND (OBJECT ^.TACTIVERM <> 0)
        THEN WRITELN(TERM, 'YOU FEEL A SLIGHT TINGLE, BUT NOTHING ELSE HAPPENS.')
        ELSE
         BEGIN
          FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
           WRITELN(TERMLIST[ILOOP], PS(NAME),
             ' SUDDENLY VANISHES IN A BLINDING FLASH!');
          DELETEPLAYER(USER, RMCODE);  PLACEPLAYER(USER, OBJECT ^.TOWHERE);
          WRITELN(TERM, 'EVERYTHING SWIRLS AROUND IN A BLINDING FLASH!  YOU FIND...')
           ;
          ROOMDISPLAY(RMCODE, FALSE);
          FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
           WRITELN(TERMLIST[ILOOP], PS(NAME),
             ' SUDDENLY APPEARS IN A BLINDING FLASH OF LIGHT!')
         END (*ELSE*);
       CARD:
        BEGIN
         GETWORD(WORD, NUM, BUFFER, LENBUF, LOC);  PLYR := FINDUSER(WORD, USERTAIL);
         IF PLYR <> NIL
         THEN
          BEGIN
           DELETEPLAYER(USER, RMCODE);  PLACEPLAYER(USER, W(PLYR ^.RMCODE));
           WRITELN(TERM, 'YOU TELEPORT TO PLAYER ', PS(PLYR ^.NAME));
           ROOMDISPLAY(RMCODE, FALSE)
          END (*IF*)
         ELSE WRITELN(TERM, 'PLAYER NOT FOUND.');
        END (*CARD*);
      OTHERWISE
       WRITELN(TERM, 'NOTHING HAPPENS.')
      END (*CASE*);
   END (*USEOBJECT*);
(* THE FOLLOWING ARE PROCEDURES FOR PROCESSING THE ATTACK COMMANDS.
PLAYERS ATTACK WITH THE WEAPON CURRENTLY HELD.  THEY DEFEND THEM-
SELVES WITH SHIELDS AND ARMOR. *)


  PROCEDURE PROTECTNPC(PLAYER: USERPOINT; MONSTER: MONSTERPOINT);

   VAR
    ILOOP: INTEGER;
    TEMP: OBJECTPOINT;

   BEGIN
    ERRLOC := ' NINTEEN  ';  TERM := PLAYER ^.TRM;
    WRITELN(TERM, 'AS YOU STEP FORWARD TO ATTACK, THE ', PS(MONSTER ^.NAME), ' YELLS'
      );
    WRITELN(TERM, '"HELP! HELP!  GUARDS!  GUARDS!"... IN SECONDS SEVERAL');
    WRITELN(TERM, 'BURLY GUARDS GRAB YOU, AND TAKE AWAY YOUR WEAPON!');
    IF PLAYER ^.USWEAP <> NIL
    THEN
     BEGIN
      TEMP := PLAYER ^.USWEAP;  PLAYER ^.USWEAP := NIL;
      IF DELETEOBJECT(TEMP, PLAYER ^.OBJECTTAIL)
      THEN PLAYER ^.OBJECTTAIL := PLAYER ^.OBJECTTAIL ^.NEXT;
      PLAYER ^.WEIGHT := MAX(0, PLAYER ^.WEIGHT - TEMP ^.WEIGHT);  DISPOSE(TEMP);
     END (*IF*);
    IF PLAYER ^.LVL <= 2
    THEN
     BEGIN
      WRITELN(TERM, 'BUT SINCE YOU ARE A YOUNG, INEXPERIENCED ADVENTURER, THEY');
      WRITELN(TERM, 'GIVE YOU A STERN WARNING, AND DECIDE NOT TO THROW YOU IN JAIL.')
       ;
      FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
       WRITELN(TERMLIST[ILOOP], PS(PLAYER ^.NAME), ' ASSAULTS THE ', PS(MONSTER ^.
         NAME), ', BUT THE TOWN GUARDS STOP HIM.');
     END (*IF*)
    ELSE
     BEGIN
      WRITELN(TERM, 'THEN THEY THROW YOU IN JAIL!');
      FOR ILOOP := 1 TO MSGTERM(TERMLIST, ALL) DO
       BEGIN
        WRITELN(TERMLIST[ILOOP], '### ', PS(PLAYER ^.NAME), ' WAS THROWN IN JAIL FOR'
          , ' ASSAULTING THE ', PS(MONSTER ^.NAME), '.');
       END (*FOR*);
      DELETEPLAYER(PLAYER, PLAYER ^.RMCODE);  PLACEPLAYER(PLAYER, 5) (*JAIL*);
      WRITELN(TERM);  ROOMDISPLAY(PLAYER ^.RMCODE, FALSE);
     END (*ELSE*);
    PLAYER ^.DEFMON := NIL;
   END (*PROTECTNPC*);


  FUNCTION SELECTWEAP: OBJECTPOINT;
(* SELECTWEAP CHECKS THAT THE ATTACKING PLAYER ACTUALLY WIELDS
A WEAPON.  THE WEAPON MUST NOT BE BROKEN. *)

   BEGIN
    IF USER ^.USWEAP = NIL  THEN SELECTWEAP := NIL
    ELSE
     IF USER ^.USWEAP ^.STRIKESLEFT = 0
     THEN
      BEGIN
       USER ^.USWEAP ^.PERMANENT := FALSE;  SELECTWEAP := NIL;
       WRITELN(TERM, 'YOUR WEAPON IS BROKEN!')
      END (*IF*)
     ELSE SELECTWEAP := USER ^.USWEAP
   END (*SELECTWEAP*);


  PROCEDURE SHAREEXPERIENCE(MON: MONSTERPOINT; RM: RMCODETYPE);
(* SHAREEXPERIENCE WILL DISTRIBUTE EXPERIENCE POINTS TO  ALL
PLAYERS WHO ARE INVOVLED IN KILLING A MONSTER.  THE ACTUAL
KILLER OF THE MONSTER GETS AN EXTRA SHARE OF EXPERIENCE POINTS.*)

   VAR
    NEWEXP, NUMINVOLVED: INTEGER;
    PLYR: USERPOINT;


   FUNCTION ATKING(OTHR: USERPOINT): BOOLEAN;

    BEGIN ATKING := (OTHR ^.DEFMON = MON) END;


   BEGIN (*SHAREEXPERIENCE*)
    NUMINVOLVED := 0;  PLYR := MATCHPLAYER(ROOM[RM].RMPLAYERTAIL, ATKING);
    WHILE PLYR <> NIL DO
     BEGIN
      NUMINVOLVED := NUMINVOLVED + 1;  PLYR := MATCHPLAYER(PLYR ^.NEXT, ATKING);
     END (*WHILE*);
    NUMINVOLVED := NUMINVOLVED + 1 (* ADD SHARE FOR SLAYER *);
    PLYR := MATCHPLAYER(ROOM[RM].RMPLAYERTAIL, ATKING);
    WHILE PLYR <> NIL DO
     BEGIN
      IF PLYR = USER
      THEN
       PLYR ^.EXPERIENCE := MIN(262000, PLYR ^.EXPERIENCE + MON ^.EXPERIENCE * 2 DIV
         NUMINVOLVED)
      ELSE
       BEGIN
        NEWEXP := MON ^.EXPERIENCE DIV NUMINVOLVED;
        IF NOTIMEOUT(PLYR) THEN
         WRITELN(PLYR ^.TRM, 'YOU EARNED ', NEWEXP: 0,
           ' EXPERIENCE POINTS FOR THE MELEE.');
        PLYR ^.EXPERIENCE := MIN(262000, PLYR ^.EXPERIENCE + NEWEXP)
       END (*ELSE*);
      PLYR := MATCHPLAYER(PLYR ^.NEXT, ATKING)
     END (*WHILE*);
   END (*SHAREEXPERIENCE*);


  PROCEDURE MAKETREASURE(MONSTER: MONSTERPOINT; RM: INTEGER);

   VAR
    NOTHING: BOOLEAN;
    OBJ, LASTOBJ: OBJECTPOINT;
    ILOOP, NUMOBJS, OBNUM: INTEGER;
    FACTOR: REAL;

   BEGIN
    ERRLOC := ' TWENTY   ';  NOTHING := TRUE;
    WRITELN(TERM, 'ON ', PM(MONSTER), ' YOU FIND:');
    WITH MONSTER ^ DO
     BEGIN
      IF OBJECTTAIL <> NIL
      THEN
       BEGIN
        NOTHING := FALSE;  LASTOBJ := OBJECTTAIL;
        WHILE LASTOBJ ^.NEXT <> NIL DO LASTOBJ := LASTOBJ ^.NEXT;
        LASTOBJ ^.NEXT := ROOM[RM].RMOBJECTTAIL (*INSERT INTO ROOM*);
        LASTOBJ := LASTOBJ ^.NEXT (* POINT TO LAST OBJ + 1 *);
        ROOM[RM].RMOBJECTTAIL := OBJECTTAIL;  OBJECTTAIL := NIL;
       END (*IF*)
      ELSE LASTOBJ := ROOM[RM].RMOBJECTTAIL;
      IF WHICHOBJ > OBJLISTLEN THEN
       BEGIN
        WRITELN(TERM, 'MIL105 - OBJECT LIST INDEX OUT OF BOUNDS!');  WHICHOBJ := 0
       END (*IF*);
      IF WHICHOBJ > 0
      THEN
       BEGIN
        IF RND(4) = 1  THEN NUMOBJS := RND(4)  ELSE NUMOBJS := 1;
        FOR ILOOP := 1 TO NUMOBJS DO
         BEGIN
          OBNUM := OBJINDEX[WHICHOBJ, RND(6)];
          IF OBNUM > 0
          THEN
           BEGIN
            NOTHING := FALSE;  NEW(OBJ);  OBJ ^ := RANOBJLIST[OBNUM];
            FACTOR := (RND(40) + 80) / 100;
            OBJ ^.PRICE := ROUND(OBJ ^.PRICE * FACTOR);
            OBJ ^.NEXT := ROOM[RM].RMOBJECTTAIL;  ROOM[RM].RMOBJECTTAIL := OBJ
           END (*IF*)
         END (*FOR*)
       END (*IF*);
      IF NOTHING  THEN WRITELN(TERM, '    NOTHING.')
      ELSE
       BEGIN
        OBJ := ROOM[RM].RMOBJECTTAIL;
        REPEAT
         WRITE(TERM, '    ');  PRINTOBJ(OBJ ^, FALSE);  WRITELN;  OBJ := OBJ ^.NEXT
        UNTIL OBJ = LASTOBJ
       END (*ELSE*)
     END (*WITH*)
   END (*MAKETREASURE*);


  PROCEDURE HITPLAYER(DAMAGE: INTEGER);
(* HURTPLAYER INFLICTS DAMAGE AGAINST A PLAYER.   MESSAGES ARE
SENT TO ALL CONCERNED.  EXCESSIVE DAMAGE CAUSES DEATH, WITH A
COLORFUL MESSAGE FLASHED TO ALL USERS ABOUT THE EVENT. *)

   VAR
    I: INTEGER;
    PLAYER: USERPOINT;
    REVENENT: MONSTERPOINT;
    MERC, COLD: BOOLEAN;

   BEGIN
    ERRLOC := 'HITPLAYER ';  PLAYER := USER ^.DEFPLAYER;  HITSHARMOR(PLAYER, DAMAGE);
    WRITE(TERM, 'YOU HIT ', PS(PLAYER ^.NAME), ' FOR ');
    PRINTDMG(PLAYER, DAMAGE, USER ^.BRIEF);
    IF NOTIMEOUT(PLAYER) THEN
     BEGIN
      WRITE(PLAYER ^.TRM, PS(USER ^.NAME), ' HITS YOU FOR ');
      PRINTDMG(PLAYER, DAMAGE, PLAYER ^.BRIEF);
     END (*IF*);
    IF PLAYER ^.HITS + PLAYER ^.FATIGUE <= DAMAGE
    THEN
     IF REALTIME - PLAYER ^.HITATTIME <= 30
     THEN
      BEGIN
       WRITELN(TERM, 'YOU KILLED ', PRO[PLAYER^.SEX], '!');
       WRITELN(PLAYER ^.TRM, 'YOU''RE DEAD, ', PS(PLAYER ^.NAME), '!');
       MERC := (USER ^.LVL - PLAYER ^.LVL > 3);  COLD := (PLAYER ^.DEFPLAYER = NIL);
       IF PLAYER ^.LVL > 5  THEN DAYMSG('KIL', PLAYER, USER ^.NAME, USER ^.LVL);
       FOR I := 1 TO MSGTERM(TERMLIST, ALL) DO
        BEGIN
         WRITE(TERMLIST[I], '### ', PS(USER ^.NAME), ' JUST KILLED ', PS(PLAYER ^.
           NAME));
         IF MERC  THEN WRITE(' MERCILESSLY');
         IF COLD  THEN WRITELN(' IN COLD BLOOD!')  ELSE WRITELN('!');
        END (*FOR*);
       IF MERC  THEN USER ^.PTY := MAX(- 10, USER ^.PTY - 1);
       IF COLD  THEN USER ^.PTY := MAX(- 10, USER ^.PTY - 1);
       IF (USER ^.CLASS = PALADIN) AND (MERC OR COLD) AND (PLAYER ^.CLASS <> THIEF)
       THEN USER ^.CLASS := FIGHTER;
       IF USER ^.AGUILD  THEN USER ^.PTY := MAX(0, USER ^.PTY - 1);
       IF (PLAYER ^.CON >= 18)
       THEN
        BEGIN (*REVENENT*)
         NEW(REVENENT);  REVENENT ^ := RANMONLIST[1];
         INSERTMONSTER(REVENENT, USER ^.RMCODE);
         WITH REVENENT ^ DO
          BEGIN
           HITS := PLAYER ^.MAXHITS;  LVL := PLAYER ^.LVL;  DEFPLAYER := USER;
           MAXHITS := HITS;
          END (*WITH*);
         WRITELN(TERM, 'FROM THE DEAD BODY YOU SEE A GASEOUS SHAPE FORM...');
        END (*IF*);
PLAYER ^.DEAD := TRUE;
       PLAYER ^.FATIGUE := 0;  PLAYER ^.HITS := 0 (* KILL PLAYER..AW... *);
       IF (- (USER ^.PTY * 10) > RND(100)) AND (MERC OR COLD)
       THEN (*TO THE GALLOWS!*)
        BEGIN
         WRITELN(TERM,
           'ENOUGH IS ENOUGH!  THE PEOPLE RISE UP AGAINST YOU IN AN ANGRY MOB!');
         WRITELN(TERM, 'YOU HAVE BEEN LYNCHED!');  DAYMSG('LYN', USER, BLANKS, 0);
         FOR I := 1 TO MSGTERM(TERMLIST, ALL) DO
          WRITELN(TERMLIST[I], '### ', PS(USER ^.NAME), ', THE ', PS(CNAME[USER ^.
            CLASS]), ', WAS JUST LYNCHED BY AN ANGRY MOB.');
USER ^.DEAD := TRUE;
         USER ^.HITS := 0;  USER ^.FATIGUE := 0
        END (*IF*)
      END (*IF*)
     ELSE
      BEGIN
       PLAYER ^.FATIGUE := 0;  PLAYER ^.HITS := 1;
       WRITELN(PLAYER ^.TRM, 'YOU HEAR A VOICE CRY OUT, "RUN, FOOL, RUN!"')
      END (*ELSE*)
    ELSE
     BEGIN
      IF DAMAGE > PLAYER ^.FATIGUE
      THEN PLAYER ^.HITS := MAX(0, PLAYER ^.HITS - DAMAGE + PLAYER ^.FATIGUE);
      PLAYER ^.FATIGUE := MAX(0, PLAYER ^.FATIGUE - DAMAGE);
     END (*ELSE*)
   END (*HURTPLAYER*);


  PROCEDURE HITMONSTER(DAMAGE: INTEGER);
(* *HITMONSTER* STRIKES MONSTERS FOR DAMAGE.  ENOUGH DAMAGE WILL
KILL THEM.  MESSAGES ARE SENT TO ALL INVOLVED PLAYERS, PLUS ANY
EXPERIENCE AND/OR TREASURE GAINED.  MONSTER-PERSONALITY BITS
USED HERE ARE *FLEE*, *DEFEND*, AND *ATKLASTAGGR*. *)

   VAR
    MONSTER: MONSTERPOINT;
    RM: RMCODETYPE;
    I: INTEGER;

   BEGIN
    ERRLOC := 'HITMONSTER';  RM := USER ^.RMCODE;  MONSTER := USER ^.DEFMON;
    IF MONSTER ^.HITS - DAMAGE <= 0
    THEN
     BEGIN
      WRITELN(TERM, 'YOU KILLED THE ', PS(MONSTER ^.NAME), '!');
      FOR I := 1 TO MSGTERM(TERMLIST, LOCAL) DO
       WRITELN(TERMLIST[I], PS(USER ^.NAME), ' JUST KILLED ', PM(MONSTER), '!');
      SHAREEXPERIENCE(MONSTER, RM);  MAKETREASURE(MONSTER, RM);
      DELETEMONSTER(MONSTER, RM);  DESTROY(MONSTER);  USER ^.DEFMON := NIL
     END (* KILL MONSTER *)
    ELSE
     BEGIN
      IF MONSTER ^.MPARLEY IN [1, 3, 4]
      THEN IF NOT MONSTER ^.PERMANENT  THEN MONSTER ^.MPARLEY := 2;
      MONSTER ^.HITS := MONSTER ^.HITS - DAMAGE;
      IF USER ^.BRIEF
      THEN WRITELN(TERM, 'YOU HIT IT FOR ', DAMAGE: 1, ' HIT POINTS!')
      ELSE
       WRITELN(TERM, 'YOU HIT THE ', PS(MONSTER ^.NAME), ' FOR ', DAMAGE: 0,
         ' HIT POINTS!');
      IF MONSTER ^.FLEE OR (USER ^.LVL >= 5 + MONSTER ^.LVL)
      THEN
       IF MONSTER ^.HITS / MONSTER ^.MAXHITS < 0.01 * RND(40)
       THEN
        BEGIN
         FOR I := 1 TO MSGTERM(TERMLIST, LOCAL) DO
          BEGIN
           WRITELN(TERMLIST[I], PM(MONSTER), 'FLEES FROM ', PS(USER ^.NAME),
             '''S ATTACK!');
          END (*FOR*);
         WRITELN(TERM, 'THE ', PS(MONSTER ^.NAME), ' FLEES FROM YOUR ATTACK!');
         MONSTER ^.EXPERIENCE := MONSTER ^.EXPERIENCE DIV 2;
         IF (USER ^.LVL < 5 + MONSTER ^.LVL)  THEN SHAREEXPERIENCE(MONSTER, RM);
         DELETEMONSTER(MONSTER, RM);  DESTROY(MONSTER);  USER ^.DEFMON := NIL
        END (*IF*)
     END (* HIT, BUT NOT KILL *)
   END (*HITMONSTER*);


  PROCEDURE HITATMONSTER(WEAPON: OBJECTPOINT; PLUS: INTEGER);
(* THIS PROCEDURE "ROLLS THE DICE" TO SEE IF A PLAYER HIT A MONSTER. *)

   VAR
    DAMAGE: INTEGER;
    WITHFIST: BOOLEAN;

   BEGIN
    ERRLOC := 'HITATMONST';  WITHFIST := FALSE;
    IF WEAPON = NIL
    THEN BEGIN WITHFIST := TRUE;  NEW(WEAPON);  WEAPON ^ := FIST END;
    WITH USER ^ DO
     BEGIN
      WITH WEAPON ^ DO
       IF DEFMON ^.MAGIC AND NOT MAGIC
       THEN WRITELN(TERM, 'YOUR WEAPON STRIKES WITH NO EFFECT!!')
       ELSE
        BEGIN
         IF CLASS = PALADIN
         THEN IF DEFMON ^.SLOWREACT OR DEFMON ^.FASTREACT  THEN PLUS := PLUS + 1;
         IF CLASS = FIGHTER  THEN PLUS := PLUS + 1;
         IF LVL = 1  THEN PLUS := PLUS + 2;
         IF DEFMON ^.INVISIBLE  THEN PLUS := PLUS - 4 (*-4 TO HIT*);
         IF DEFMON ^.DEFEND AND (DEFMON ^.DEFPLAYER = NIL) OR DEFMON^.ATKLASTAGGR
AND (DEFMON^.DEFPLAYER <> USER)
         THEN BEGIN DEFMON ^.DEFPLAYER := USER (* ATTACK BACK *);
IF DEFMON^.MREACT >= 5 THEN DEFMON^.MREACT := 0
END;
         IF NOT DEFMON ^.PERMANENT
         THEN IF DEFMON ^.MPARLEY IN [1, 3, 4]  THEN DEFMON ^.MPARLEY := 2;
         IF (RND(20) <> 20) AND (RND(20) < 14 + DEFMON ^.LVL - LVL - WEAPLUS - STR
           DIV 6 - PLUS)
         THEN
          IF WITHFIST  THEN WRITELN(TERM, 'YOUR FIST MISSES!')
          ELSE WRITELN(TERM, 'YOU MISSED!')
         ELSE
          BEGIN (* HIT *)
           STRIKESLEFT := STRIKESLEFT - 1;
           DAMAGE := MAX(0, MINHP + RND(MAXHP - MINHP + 1) + WEAPLUS + PLUS);
           IF WITHFIST  THEN WRITELN(TERM, 'PUNCH!');
           CASE RND(100 - LVL) OF
            1, 2, 3, 4:
             BEGIN WRITELN(TERM, 'DOUBLE DAMAGE!');  DAMAGE := DAMAGE * 2 END;
            90:
             BEGIN WRITELN(TERM, 'YOU FUMBLED!');  DAMAGE := 0;  USWEAP := NIL END;
           OTHERWISE
           END (*CASE*);
           IF DAMAGE >= DEFMON ^.HITS
           THEN
            IF ((DEFMON ^.LVL - LVL ) * 5 > RND(25)) AND NOT SKILLNEW
            THEN
              BEGIN
               SKILLNEW := TRUE;
               CASE WEAPON ^.WEAPTYPE OF
                SHARP: IF RND(SSHARP) = 1 THEN SSHARP := MIN(7, SSHARP + 1);
                THRUST: IF RND(STHRUST) = 1 THEN STHRUST := MIN(7, STHRUST + 1);
                BLUNT: IF RND(SBLUNT) = 1 THEN SBLUNT := MIN(7, SBLUNT + 1);
                LONG: IF RND(SLONG) = 1 THEN SLONG := MIN(7, SLONG + 1);
               END (*CASE*);
              END (*IF*);
           HITMONSTER(DAMAGE) (* WHAM! *)
          END (*ELSE*)
        END (*ELSE*)
     END (*WITH USER*);
    IF WITHFIST  THEN DISPOSE(WEAPON);
   END (*HITATMONSTER*);


  PROCEDURE HITATPLAYER(WEAPON: OBJECTPOINT; PLUS: INTEGER);
(* HITATPLAYER LETS ONE PLAYER ATTACK ANOTHER *)

   VAR
    DAMAGE: INTEGER;
    WITHFIST: BOOLEAN;

   BEGIN
    ERRLOC := ' T-TWO-B  ';  WITHFIST := FALSE;
    IF WEAPON = NIL
    THEN BEGIN WITHFIST := TRUE;  NEW(WEAPON);  WEAPON ^ := FIST END;
    WITH USER ^ DO
     BEGIN
      WITH WEAPON ^ DO
       IF (RND(20) <> 20) AND (RND(20) < 24 + DEFPLAYER ^.LVL - LVL - WEAPLUS - STR
         DIV 6 - DEFPLAYER ^.AC + DEFPLAYER ^.DEX DIV 6 - PLUS) OR (DEFPLAYER ^.HITS
         = 0)
       THEN
        BEGIN
         IF WITHFIST  THEN WRITELN(TERM, 'WOOSH! YOUR FIST MISSES!')
         ELSE WRITELN(TERM, 'YOU MISSED!');
         IF NOTIMEOUT(DEFPLAYER)
         THEN WRITELN(DEFPLAYER ^.TRM, PS(USER ^.NAME), ' MISSES YOU!')
        END (*IF*)
       ELSE
        BEGIN
         WEAPON ^.STRIKESLEFT := WEAPON ^.STRIKESLEFT - 1;
         DAMAGE := MAX(0, MINHP + RND(MAXHP - MINHP + 1) + WEAPLUS + PLUS);
         IF WITHFIST  THEN WRITELN(TERM, 'POW!');  HITPLAYER(DAMAGE)
        END (*ELSE*);
      IF DEFPLAYER <> NIL  THEN DEFPLAYER ^.HITATTIME := REALTIME;
     END (*WITH USER*);
    IF WITHFIST  THEN DISPOSE(WEAPON);
   END (*HITATPLAYER*);


  PROCEDURE ATTACK(CMDCODE: INTEGER; WORD: ALFA; RM: RMCODETYPE);
(* THIS IS THE MAIN ATTACK PROCESSOR.  IT CALLS ALL THE ABOVE ROUTINES
IN ORDER TO PROCESS PLAYER-MONSTER ATTACKS AND PLAYER-PLAYER ATTACKS.
EXAMPLE: "ATTACK POOTWADDLE", "ATTACK RAT/3", "STRIKE HAROLD"
*)

   TYPE
    TOWHATTYPE =
     (TONONE, TOMONSTER, TOPLAYER);

   VAR
    WEAPON: OBJECTPOINT;
    TOWHAT: TOWHATTYPE;
    PLUS: INTEGER;


   FUNCTION ATTACKWHAT(WORD: ALFA): TOWHATTYPE;
(* ATTACKWHAT SCANS TO SEE IF THE TARGET IS A PLAYER OR A MONSTER.
THE APPROPRIATE *DEFMON* AND *DEFPLAYER* POINTERS ARE SET, AND
MESSAGES ARE SENT TO ALL PLAYERS IN THE ROOM ABOUT THE ATTACK. *)

    VAR
     OLDDEFPLAYER: USERPOINT;
     OLDDEFMON: MONSTERPOINT;
     I: INTEGER;
     DUMMY: ALFA;

    BEGIN
     ERRLOC := ' T-THREE  ';
     WITH USER ^ DO
      BEGIN
       OLDDEFPLAYER := DEFPLAYER;
       DEFPLAYER := FINDPLAYER(WORD, ROOM[RM].RMPLAYERTAIL);
       IF DEFPLAYER = USER  THEN DEFPLAYER := NIL;
       IF DEFPLAYER = NIL
       THEN
        BEGIN
         OLDDEFMON := DEFMON;
         IF NUM = 0  THEN GETWORD(DUMMY, NUM, BUFFER, LENBUF, LOC);
(*GET MONSTER #, IF ANY*)
         DEFMON := FINDMONSTER(WORD, NUM, ROOM[RM].RMMONSTERTAIL);
(* CHECK FOR A MONSTER FIRST *)
         IF DEFMON = NIL
         THEN
          BEGIN
           ATTACKWHAT := TONONE;
           IF FINDOBJECT(WORD, NUM, ROOM[RM].RMOBJECTTAIL) <> NIL
           THEN WRITELN(TERM, 'USE THE COMMAND "SMASH" INSTEAD.')
           ELSE WRITELN(TERM, PS(WORD), ' ISN''T HERE.')
          END (*IF*)
         ELSE
          BEGIN
           ATTACKWHAT := TOMONSTER;
           IF OLDDEFMON <> DEFMON THEN
            FOR I := 1 TO MSGTERM(TERMLIST, LOCAL) DO
             WRITELN(TERMLIST[I], PS(NAME), ' ATTACKS ', PM(DEFMON), '!');
          END (*ELSE*)
        END (*IF*)
       ELSE
        BEGIN
         ATTACKWHAT := TOPLAYER;
         IF OLDDEFPLAYER <> DEFPLAYER
         THEN
          BEGIN
           IF NOTIMEOUT(DEFPLAYER)
           THEN WRITELN(DEFPLAYER ^.TRM, PS(NAME), ' IS ATTACKING YOU!');
           FOR I := 1 TO MSGTERM(TERMLIST, LOCAL) DO
            IF TERMLIST[I] <> DEFPLAYER ^.TRM THEN
             WRITELN(TERMLIST[I], PS(NAME), ' ATTACKS ', PS(DEFPLAYER ^.NAME), '!');
          END (*IF*)
        END (*ELSE*)
      END (*WITH*)
    END (*ATTACKWHAT*);


   BEGIN (*ATTACK*)
    ERRLOC := 'ATTACK    ';
    WITH USER ^ DO
     BEGIN
      TOWHAT := TONONE;  WEAPON := SELECTWEAP;
      IF READYCHECK(LASTATK) AND ((WEAPON <> NIL) OR (USER ^.USWEAP = NIL))
      THEN
       BEGIN
        IF ROOM[RMCODE].SAFE  THEN WRITELN(TERM, 'THIS IS A SAFE HAVEN.')
        ELSE
         IF WORD = BLANKS
         THEN
          IF (DEFMON <> NIL) OR (DEFPLAYER <> NIL)
          THEN IF DEFMON <> NIL  THEN TOWHAT := TOMONSTER  ELSE TOWHAT := TOPLAYER
          ELSE WRITELN(TERM, 'SPECIFY TARGET, PLEASE!')
         ELSE TOWHAT := ATTACKWHAT(WORD);
        IF (TOWHAT <> TONONE)
        THEN
         IF (CMDCODE = 42) OR (FATIGUE > 0)
         THEN
          BEGIN
           CASE CMDCODE OF
            11: BEGIN PLUS := 0;  FATIGUE := MAX(0, FATIGUE - RND(2) + 1); END;
            42 (*PARRY*):
             BEGIN
              PLUS := - (LVL DIV 2 + 1);
              IF TOWHAT = TOMONSTER  THEN DEFMON ^.MREACT := 5 (*HALF DAMAGE*)
             END (*42*);
            43 (*THRUST*):
             BEGIN
              PLUS := LVL;  FATIGUE := MAX(0, FATIGUE - LVL);
              IF TOWHAT = TOMONSTER THEN
               IF RND(4) = 4 THEN
                BEGIN
                 DEFMON ^.MREACT := 6 (*DOUBLE DAMAGE*);
                 WRITELN(TERM, 'YOU ARE VULNERABLE!')
                END (*IF*);
             END (*43*);
            85 (* FEINT *):
             BEGIN
              WRITELN(TERM, 'OK');
              IF DEX > RND(30)
              THEN
               IF TOWHAT = TOMONSTER  THEN DEFMON ^.MREACT := 3
               ELSE
                BEGIN
                 DEFPLAYER ^.LASTATK := REALTIME + 10;
                 WRITELN(DEFPLAYER ^.TRM, PS(NAME), ' FEINTS AT YOU!');
                 WRITELN(TERM, PS(DEFPLAYER ^.NAME), ' FALLS BACK!')
                END (*ELSE*)
              ELSE WRITELN(TERM, 'DIDN''T WORK!');
              TOWHAT := TONONE;
             END (*85*);
            86 (* CIRCLE *):
             BEGIN
              WRITELN(TERM, 'OK');
              IF DEX > RND(20)
              THEN
               IF TOWHAT = TOMONSTER  THEN DEFMON ^.MREACT := 2
               ELSE
                BEGIN
                 DEFPLAYER ^.LASTATK := REALTIME + 8;
                 WRITELN(DEFPLAYER ^.TRM, PS(NAME), ' CIRCLES YOU!');
                 WRITELN(TERM, 'YOU CIRCLE ', PRO[DEFPLAYER^.SEX], '!');
                END (*ELSE*)
              ELSE WRITELN(TERM, 'DIDNT''T WORK!');
              TOWHAT := TONONE;
             END (*86*);
            72:
             IF HIDDEN  THEN PLUS := 5
             ELSE
              BEGIN
               PLUS := - 5;  WRITELN(TERM, 'YOU ARE DISCOVERED!');
               IF TOWHAT = TOMONSTER  THEN DEFMON ^.MREACT := 6 (*DOUBLE DAMAGE*)
              END (*ELSE*);
           END (*CASE*);
           IF WEAPON <> NIL
           THEN
            CASE WEAPON ^.WEAPTYPE OF
             SHARP: PLUS := PLUS + SSHARP;
             THRUST: PLUS := PLUS + STHRUST;
             BLUNT: PLUS := PLUS + SBLUNT;
             LONG: PLUS := PLUS + SLONG;
            END (*CASE*);
           IF TOWHAT = TOPLAYER  THEN LASTATK := REALTIME + 8
           ELSE LASTATK := REALTIME + 5;
           HIDDEN := FALSE;
           IF TOWHAT = TOMONSTER
           THEN
            IF DEFMON ^.ASSISTANCE  THEN PROTECTNPC(USER, USER ^.DEFMON)
            ELSE HITATMONSTER(WEAPON, PLUS)
           ELSE IF TOWHAT = TOPLAYER  THEN HITATPLAYER(WEAPON, PLUS)
          END (*IF*)
         ELSE WRITELN(TERM, 'YOU''RE TOO EXHAUSTED TO STRIKE!')
       END (*IF*)
     END (*WITH*)
   END (*ATTACK*);


  PROCEDURE SPELL(SPELLCODE: INTEGER);
(* CAST SPELL ON A PLAYER, MONSTER, OR USER HIMSELF *)

   VAR
    OBJ: OBJECTPOINT;
    PLAYER: USERPOINT;
    MONSTER: MONSTERPOINT;
    TARGET, DUMMY: ALFA;
    GOODSPL: BOOLEAN;
    MAGTYPE:
     (CHANT, SCRL, DEVICE);
    LENCHANT, DAMAGE, SUM, LVLNEEDED, MPNEEDED, ILOOP: INTEGER;
    INNEEDED: INTEGER;

   BEGIN
    USER ^.HIDDEN := FALSE;  MAGTYPE := CHANT;  ERRLOC := 'SPELL     ';
    GOODSPL := FALSE;  PLAYER := NIL;  MONSTER := NIL;  OBJ := NIL;
    IF SPELLCODE = 0
    THEN
     BEGIN
      ILOOP := 1;  SUM := 0;  USER ^.ENTRY := XCMD;  LENCHANT := 0;
      WHILE ILOOP <= LENBUF DO
       BEGIN
        IF BUFFER[ILOOP] IN ['A' .. 'Z']
        THEN BEGIN SUM := SUM + ORD(BUFFER[ILOOP]);  LENCHANT := LENCHANT + 1 END;
        ILOOP := ILOOP + 1
       END (*WHILE*);
      SPELLCODE := 0;
      WHILE (SPELLCODE < SPELLEN) AND NOT GOODSPL DO
       BEGIN
        SPELLCODE := SPELLCODE + 1;
        GOODSPL := (SPELLCLASS[SPELLCODE].SPLHASH = SUM) AND (LENCHANT = SPELLCLASS[
          SPELLCODE].SPLLEN);
       END (*WHILE*)
     END (*IF*)
    ELSE
     BEGIN
      GOODSPL := TRUE;
      IF SPELLCODE < 0
      THEN BEGIN SPELLCODE := ABS(SPELLCODE);  MAGTYPE := DEVICE END
      ELSE MAGTYPE := SCRL;
     END (*ELSE*);
    IF NOT GOODSPL  THEN WRITELN(TERM, 'YOU MISPRONOUNCED THE SPELL!')
    ELSE
     WITH SPELLCLASS[SPELLCODE] DO
      BEGIN
       TARGET := USER ^.WDATA;  NUM := USER ^.DATA;
       CASE SPLTYPE OF
        ONUSER, ONPLAYER, ONUSPLAYER:
         BEGIN
          IF TARGET = BLANKS  THEN PLAYER := USER
          ELSE PLAYER := FINDPLAYER(TARGET, ROOM[USER ^.RMCODE].RMPLAYERTAIL);
          IF (SPLTYPE = ONPLAYER) AND ((TARGET = BLANKS) OR (PLAYER = USER)) OR (
            TARGET <> BLANKS) AND ((PLAYER = NIL) OR (SPLTYPE = ONUSER))
          THEN
           BEGIN
            GOODSPL := FALSE;
            IF TARGET <> BLANKS  THEN WRITELN(TERM, 'THAT SPELL TARGET IS ILLEGAL!')
            ELSE WRITELN(TERM, 'THE SPELL TARGET WAS NOT SPECIFIED!')
           END (*IF*)
         END (*ONUSER*);
        ONMON, ONMONPLAYER:
         BEGIN
          PLAYER := FINDPLAYER(TARGET, ROOM[USER ^.RMCODE].RMPLAYERTAIL);
          MONSTER := FINDMONSTER(TARGET, NUM, ROOM[USER ^.RMCODE].RMMONSTERTAIL);
          IF (MONSTER = NIL) AND ((PLAYER = NIL) OR (SPLTYPE = ONMON)) OR (PLAYER =
            USER)
          THEN
           BEGIN
            GOODSPL := FALSE;
            IF TARGET <> BLANKS  THEN WRITELN(TERM, 'THE SPELL TARGET IS ILLEGAL!')
            ELSE WRITELN(TERM, 'THE SPELL TARGET WAS NOT SPECIFIED!')
           END (*IF*)
         END (*ONMON*);
        ONOBJECT:
         BEGIN
          OBJ := FINDOBJECT(TARGET, NUM, USER ^.OBJECTTAIL);
          IF OBJ = NIL
          THEN OBJ := FINDOBJECT(TARGET, NUM, ROOM[USER ^.RMCODE].RMOBJECTTAIL);
          IF OBJ = NIL
          THEN BEGIN GOODSPL := FALSE;  WRITELN(TERM, 'OBJECT NOT HERE!') END
         END (*ONOBJECT*);
       END (*CASE*);
       IF ROOM[USER ^.RMCODE].SAFE
       THEN
        IF NOT (SPELLCODE IN [1, 2, 6, 13]) THEN
         BEGIN
          GOODSPL := FALSE;
          WRITELN(TERM, 'SUCH MAGIC DOES NOT WORK HERE.  SPELL FAILS.')
         END (*IF*);
       IF (MONSTER <> NIL) AND (PLAYER <> NIL)  THEN PLAYER := NIL;
       IF MONSTER <> NIL THEN
        IF MONSTER ^.ANTIMAGIC THEN
         BEGIN GOODSPL := FALSE;  WRITELN(TERM, 'YOUR SPELL HAS NO EFFECT ON IT!')
         END (*IF*);
       GOODSPL := GOODSPL AND READYCHECK(USER ^.LASTATK);  MPNEEDED := SPLMP;
       LVLNEEDED := SPLLVL;  INNEEDED := SPLINT;
       IF MAGTYPE = SCRL THEN
        BEGIN
         MPNEEDED := 0;  LVLNEEDED := SPLLVL - 3 - RND(4);  INNEEDED := INNEEDED - 3;
        END (*IF*);
       IF MAGTYPE = DEVICE
       THEN BEGIN MPNEEDED := 0;  LVLNEEDED := - 10;  INNEEDED := 0 END;
       IF MAGTYPE = CHANT
       THEN
        BEGIN
         IF (USER ^.CLASS <> MAGICUSER) AND (SPELLCODE IN [7, 10, 12, 14])
         THEN
          BEGIN
           GOODSPL := FALSE;  WRITELN(TERM, 'ONLY MAGIC-USERS CAN CAST THAT SPELL!')
          END (*IF*);
         IF (USER ^.CLASS <> CLERIC) AND (SPELLCODE IN [2, 13]) THEN
          BEGIN
           GOODSPL := FALSE;  WRITELN(TERM, 'ONLY CLERICS CAN CAST THAT SPELL!')
          END (*IF*);
         IF NOT (USER ^.CLASS IN [CLERIC, MAGICUSER]) AND (SPELLCODE = 1)
         THEN
          BEGIN
           GOODSPL := FALSE;
           WRITELN(TERM, 'ONLY MAGIC USERS AND CLERICS MAY CAST VIGOR SPELLS!')
          END (*IF*);
        END (*IF*);
       IF GOODSPL AND (MAGTYPE = CHANT) THEN
        IF SPELLCODE IN [7, 9, 10, 12, 13, 15, 16]  THEN GOODSPL := NOT SPELLIMIT;
       IF GOODSPL
       THEN
        IF SPELLCOST(USER, MPNEEDED, LVLNEEDED, INNEEDED)
        THEN
         BEGIN
          IF MAGTYPE <> DEVICE
          THEN WRITELN(TERM, 'YOU CAST A ', PS(SPELLIST[SPELLCODE]), ' SPELL!')
          ELSE WRITELN(TERM, 'OK');
          IF PLAYER <> USER
          THEN
           FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
            BEGIN
             WRITE(TERMLIST[ILOOP], PS(USER ^.NAME), ' CASTS A ', PS(SPELLIST[
               SPELLCODE]), ' SPELL ON ');
             IF MONSTER <> NIL  THEN WRITELN(PM(MONSTER), '!')
             ELSE
              IF OBJ <> NIL  THEN BEGIN PRINTOBJ(OBJ ^, TRUE);  WRITELN('!') END
              ELSE
               IF PLAYER ^.TRM <> TERMLIST[ILOOP]
               THEN WRITELN(PS(PLAYER ^.NAME), '!')
               ELSE WRITELN('YOU!');
            END (*FOR*);
          DAMAGE := SPELLCASE(SPELLCODE, USER ^.LVL, USER ^.INT, PLAYER, MONSTER, OBJ
            , TARGET);
          IF SPELLCODE IN [3, 4, 5, 7]
          THEN
           BEGIN
            USER ^.LASTATK := REALTIME + MAX(5, SPLMP DIV 2 - USER ^.LVL);
            USER ^.DEFPLAYER := NIL;  USER ^.DEFMON := NIL;
            IF PLAYER <> NIL
            THEN
             BEGIN USER ^.DEFPLAYER := PLAYER;  PLAYER ^.HITATTIME := REALTIME END
            ELSE
             IF MONSTER <> NIL  THEN USER ^.DEFMON := MONSTER
             ELSE ABORT(' MIL106 - NO SPELL TARGET!');
            IF DAMAGE = 0
            THEN
             BEGIN
              WRITELN(TERM, 'IT MISSED!');
              IF PLAYER <> NIL  THEN WRITELN(PLAYER ^.TRM, 'IT MISSED!')
             END (*IF*)
            ELSE
             IF PLAYER <> NIL  THEN HITPLAYER(DAMAGE)
             ELSE
              IF MONSTER ^.ASSISTANCE  THEN PROTECTNPC(USER, MONSTER)
              ELSE
               BEGIN
                IF MONSTER ^.DEFEND AND (MONSTER ^.DEFPLAYER = NIL)
OR MONSTER^.ATKLASTAGGR AND (MONSTER^.DEFPLAYER <> USER)
                THEN BEGIN MONSTER ^.DEFPLAYER := USER;
IF MONSTER^.MREACT >= 5 THEN MONSTER^.MREACT := 0 END;
                HITMONSTER(DAMAGE);
               END (*ELSE*)
           END (*IF*);
         END (*IF*)
      END (*WITH*)
   END (*SPELL*);


  PROCEDURE MISCMD(CMDCODE: INTEGER; WORD: ALFA; NUM: INTEGER);

   VAR
    FOBJ, TOBJ, OBJ: OBJECTPOINT;
    WORD3, WORD4: ALFA;
    TPLYR: USERPOINT;
    NUM2, COST: INTEGER;

   BEGIN
    WITH USER ^ DO
     CASE CMDCODE OF
      57:
       IF W(RMCODE) = 10  THEN WRITELN(TERM, '"I DONT HAVE SUCH SKILLS, SORRY!"')
       ELSE
        IF W(RMCODE) <> 18  THEN WRITELN(TERM, 'FIND A SMITH FIRST!')
        ELSE
         BEGIN
          OBJ := FINDOBJECT(WORD, NUM, OBJECTTAIL);
          IF OBJ = NIL  THEN WRITELN(TERM, 'OBJECT NOT FOUND.')
          ELSE
           IF NOT (OBJ ^.OBCLASS IN [WEAP, ARMOR, SHIELD])
           THEN WRITELN(TERM, '"I DON''T KNOW HOW TO REPAIR THAT!"')
           ELSE
            BEGIN
             DATA := TRUNC(OBJ ^.PRICE * 0.60) + RND(5);
             IF OBJ ^.MAGIC THEN
              BEGIN
               DATA := DATA * 2;
               WRITELN(TERM, '"VERY WELL!  BUT IT MAY LOSE ITS MAGICAL DWEOMER!"')
              END (*IF*);
IF OBJ^.OBCLASS = WEAP THEN IF OBJ^.MAXHP + OBJ^.MINHP > 30 THEN
  WRITELN(TERM,'"I''M NOT SURE IF I CAN REPAIR SUCH A GREAT WEAPON!"');
             WRITE(TERM, '"HMM, REPAIRING ');  PRINTOBJ(OBJ ^, FALSE);
             WRITELN(' WILL COST YOU ', DATA: 0, ' SHILLINGS.  DO YOU ACCEPT?"');
             ENTRY := XREPAIR;  USWEAP := OBJ
            END (*ELSE*);
         END (*ELSE*);
      58:
       BEGIN
        NUM := 1;
        WHILE NUM <= 10 DO
         IF NOT (WORD[NUM] IN ['A' .. 'Z', ' '])
         THEN
          BEGIN
           FOR NUM2 := NUM + 1 TO 10 DO WORD[NUM2 - 1] := WORD[NUM2];
           WORD[10] := ' '
          END (*IF*)
         ELSE NUM := NUM + 1;
        IF WORD = BLANKS  THEN WRITELN(TERM, 'MISSING OR BAD CHARS IN NAME.')
        ELSE
         IF (SEARCHPLINDEX(WORD) > 0) OR (FINDUSER(WORD, USERTAIL) <> NIL)
         THEN WRITELN(TERM, 'NAME ALREADY IN USE ELSEWHERE.')
         ELSE
          BEGIN
           NUM := SEARCHPLINDEX(NAME);  IF NUM > 0  THEN PLAYERINDEX[NUM] := WORD;
           FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
            WRITELN(TERMLIST[ILOOP], PS(NAME), ' JUST CHANGED HIS NAME TO ', PS(WORD)
              , '.');
           NAME := WORD;  WRITELN(TERM, 'NAME CHANGE COMPLETE.');
           WRITELN(TERM, 'BE SURE TO "SAVE" YOUR CHARACTER TO RECORD THE CHANGE.')
          END (*ELSE*);
       END (*58*);
      59:
       BEGIN
        GETWORD(WORD3, NUM, BUFFER, LENBUF, LOC);
        IF (WORD3 = BLANKS) OR (NUM <> 0)
        THEN WRITELN(TERM, 'MISSING OR BAD CHARS IN NEW PASSWORD.')
        ELSE
         IF HASH(WORD,10) <> PW  THEN WRITELN(TERM, 'WRONG PASSWORD, SORRY.')
         ELSE
          BEGIN
           PW := HASH(WORD3,10);  WRITELN(TERM, 'PW CHANGE COMPLETE.');
           WRITELN(TERM, 'BE SURE TO "SAVE" YOUR CHARACTER TO RECORD THE CHANGE.')
          END (*ELSE*)
       END (*59*);
      60:
       IF TRADETIME >= REALTIME
       THEN
        WRITELN(TERM, 'TRADE ALREADY IN PROGRESS.  TRY AGAIN IN ', TRADETIME -
          REALTIME: 0, ' SECONDS.')
       ELSE
        IF LOC > LENBUF
        THEN
         WRITELN(TERM,
           'FORMAT IS:  OFFER <WHO> <YOUR ITEM/CASH> FOR <THEIR ITEM/CASH>')
        ELSE
         BEGIN
          GETWORD(WORD3, NUM, BUFFER, LENBUF, LOC);
          GETWORD(WORD4, NUM2, BUFFER, LENBUF, LOC);
          TPLYR := FINDPLAYER(WORD, ROOM[RMCODE].RMPLAYERTAIL);
          IF TPLYR = NIL  THEN WRITELN(TERM, 'PLAYER IS NOT HERE!')
          ELSE
           BEGIN
            FOBJ := FINDOBJECT(WORD3, NUM, OBJECTTAIL);
            IF (FOBJ = NIL) AND (WORD3 <> BLANKS)
            THEN WRITELN(TERM, 'YOU DONT HAVE THAT!')
            ELSE
             BEGIN
              TOBJ := FINDOBJECT(WORD4, NUM2, TPLYR ^.OBJECTTAIL);
              IF (TOBJ = NIL) AND (WORD4 <> BLANKS)
              THEN WRITELN(TERM, 'TRANSACTION CANCELLED.')
              ELSE
               BEGIN
                WRITELN(TERM, 'OFFER SENT TO ', PS(TPLYR ^.NAME), '.');
                FCASH := MAX(0, NUM);  TCASH := MAX(0, NUM2);
                TRADETIME := REALTIME + 20;  NFPLYR := NAME;  NTPLYR := TPLYR ^.NAME;
                IF FOBJ <> NIL  THEN SFOBJ := FOBJ ^.NAME;  NFOBJ := WORD3;
                IF TOBJ <> NIL  THEN STOBJ := TOBJ ^.NAME;  NTOBJ := WORD4;
                WRITE(TPLYR ^.TRM, PS(NAME), ' OFFERS YOU ');
                IF FOBJ <> NIL  THEN PRINTOBJ(FOBJ ^, FALSE)
                ELSE WRITE(FCASH: 0, ' SHILLINGS');
                IF TOBJ <> NIL
                THEN BEGIN WRITE(' FOR ');  PRINTOBJ(TOBJ ^, TRUE) END
                ELSE IF TCASH <> 0  THEN WRITE(' FOR ', TCASH: 0, ' SHILLINGS');
                WRITELN('.');
                WRITELN(TPLYR ^.TRM, 'ENTER "ACCEPT" TO ACCEPT THE OFFER.');
               END (*ELSE*)
             END (*ELSE*)
           END (*ELSE*)
         END (*ELSE*)
     END (*CASE*)
   END (*MISCMDS*);


  PROCEDURE ACCEPT;
(* ACCEPT AN OFFER TO TRADE *)

   VAR
    FPLYR: USERPOINT;
    FOBJ, TOBJ: OBJECTPOINT;
    OKTRADE: BOOLEAN;

   BEGIN
    OKTRADE := TRUE;
    IF (TRADETIME < REALTIME) OR (NTPLYR <> USER ^.NAME)
    THEN WRITELN(TERM, 'NOTHING TO ACCEPT.')
    ELSE
     WITH USER ^ DO
      BEGIN
       FPLYR := FINDPLAYER(NFPLYR, ROOM[RMCODE].RMPLAYERTAIL);
       IF FPLYR = NIL  THEN WRITELN(TERM, 'TRANSACTION CANCELLED.')
       ELSE
        BEGIN
         FOBJ := FINDOBJECT(NFOBJ, FCASH, FPLYR ^.OBJECTTAIL);
         TOBJ := FINDOBJECT(NTOBJ, TCASH, OBJECTTAIL);
         IF (FOBJ = NIL) AND (NFOBJ <> BLANKS) OR (TOBJ = NIL) AND (NTOBJ <> BLANKS)
         THEN WRITELN(TERM, 'TRANSACTION CANCELLED.')
         ELSE
          BEGIN
           IF FOBJ <> NIL THEN
            OKTRADE := (FOBJ ^.NAME = SFOBJ) AND (FOBJ ^.WEIGHT + WEIGHT <= STR * 10)
            ;
           IF TOBJ <> NIL THEN
            OKTRADE := OKTRADE AND (TOBJ ^.NAME = STOBJ) AND (TOBJ ^.WEIGHT + FPLYR ^
              .WEIGHT <= FPLYR ^.STR * 10);
           OKTRADE := OKTRADE AND (FCASH <= FPLYR ^.MONEY) AND (TCASH <= MONEY);
           IF NOT OKTRADE  THEN WRITELN(TERM, 'TRANSACTION CANCELLED.')
           ELSE
            BEGIN
             IF FOBJ <> NIL
             THEN
              BEGIN
               STOPUSING(FPLYR, FOBJ);
               IF DELETEOBJECT(FOBJ, FPLYR ^.OBJECTTAIL)
               THEN FPLYR ^.OBJECTTAIL := FPLYR ^.OBJECTTAIL ^.NEXT;
               FPLYR ^.WEIGHT := MAX(0, FPLYR ^.WEIGHT - FOBJ ^.WEIGHT);
               FOBJ ^.NEXT := OBJECTTAIL;  OBJECTTAIL := FOBJ;
               WEIGHT := MIN(5000, WEIGHT + FOBJ ^.WEIGHT);
              END (*IF*)
             ELSE
              BEGIN
               FPLYR ^.MONEY := FPLYR ^.MONEY - FCASH;
               MONEY := MIN(500000, MONEY + FCASH)
              END (*ELSE*);
             IF TOBJ <> NIL
             THEN
              BEGIN
               STOPUSING(USER, TOBJ);
               IF DELETEOBJECT(TOBJ, OBJECTTAIL)
               THEN OBJECTTAIL := OBJECTTAIL ^.NEXT;
               WEIGHT := MAX(0, WEIGHT - TOBJ ^.WEIGHT);
               TOBJ ^.NEXT := FPLYR ^.OBJECTTAIL;  FPLYR ^.OBJECTTAIL := TOBJ;
               FPLYR ^.WEIGHT := MIN(5000, FPLYR ^.WEIGHT + TOBJ ^.WEIGHT);
              END (*IF*)
             ELSE
              BEGIN
               MONEY := MONEY - TCASH;
               FPLYR ^.MONEY := MIN(500000, FPLYR ^.MONEY + TCASH)
              END (*ELSE*);
             WRITELN(TERM, 'OK, YOU TRADE WITH ', PRO[FPLYR ^.SEX], '.');
             WRITELN(FPLYR ^.TRM, PS(NAME),
               ' ACCEPTS YOUR OFFER AND TRADES WITH YOU.');
             TRADETIME := 0;
            END (*ELSE*)
          END (*ELSE*)
        END (*ELSE*)
      END (*WITH*);
   END (*ACCEPT*);


  PROCEDURE TURN(WORD: ALFA; NUM: INTEGER);
(* TURN AWAY UNDEAD MONSTERS *)

   VAR
    DUMMY: ALFA;
    MON: MONSTERPOINT;
    FACTOR: INTEGER;
    TURNED: BOOLEAN;

   BEGIN
    IF NUM = 0  THEN GETWORD(DUMMY, NUM, BUFFER, LENBUF, LOC);
    MON := FINDMONSTER(WORD, NUM, ROOM[USER ^.RMCODE].RMMONSTERTAIL);
    IF MON = NIL  THEN WRITELN(TERM, 'MONSTER NOT FOUND HERE.')
    ELSE
     IF NOT MON ^.UNDEAD  THEN WRITELN(TERM, PM(MON), 'IS NOT UNDEAD!')
     ELSE
      WITH USER ^ DO
       IF NOT (CLASS IN [CLERIC, PALADIN, DM])
       THEN WRITELN(TERM, 'YOU CAN''T TURN AWAY THE UNDEAD!')
       ELSE
        IF READYCHECK(LASTATK)
        THEN
         BEGIN
USER^.HIDDEN := FALSE;
          TURNED := FALSE;  FACTOR := LVL - MON ^.LVL + 2;  LASTATK := REALTIME + 30;
          IF CLASS = PALADIN  THEN FACTOR := FACTOR - 2;  FACTOR := FACTOR - RND(5);
          USER ^.DEFMON := MON;
MON^.DEFPLAYER := USER; MON^.MREACT := 6;
IF RND(3)=1 THEN FACTOR := -1 (*FAIL 1/3RD OF TIME*);
          IF FACTOR < 0  THEN WRITELN(TERM, PM(MON), 'IGNORES YOUR COMMAND!')
          ELSE
           IF FACTOR <= 3
           THEN
            BEGIN
             TURNED := TRUE;  MON ^.EXPERIENCE := MON ^.EXPERIENCE DIV 2;
             WRITELN(TERM, PM(MON), ' FLEES AT YOUR COMMAND!');
            END (*IF*)
           ELSE
            BEGIN
             TURNED := TRUE;  WRITELN(TERM, PM(MON), 'COLLAPSES AND TURNS TO DUST!');
             MAKETREASURE(MON, RMCODE)
            END (*ELSE*);
          FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
           BEGIN
            WRITE(TERMLIST[ILOOP], PS(NAME));
            IF TURNED
            THEN
             IF FACTOR <= 3  THEN WRITE(' TURNS AWAY ')
             ELSE WRITE(' DAMNS AND DESTROYS ')
            ELSE WRITE(' FAILS TO TURN AWAY ');
            WRITELN(PM(MON), '!')
           END (*FOR*);
          IF TURNED THEN
           BEGIN
            SHAREEXPERIENCE(MON, RMCODE);  DELETEMONSTER(MON, RMCODE);  DESTROY(MON)
           END (*IF*)
         END (*IF*)
   END (*TURN*);


  PROCEDURE DEAD;
(* *DEAD* HANDLES UNEXPECTED DEATH (ZERO H.P.) OF A USER *)

   VAR
ILOOP: INTEGER;
    RM: RMCODETYPE;
    OBJ2, OBJ, BODY: OBJECTPOINT;

   BEGIN
    ERRLOC := 'DEAD      ';  RM := USER ^.RMCODE;
    OBJ := USER ^.OBJECTTAIL (* DROP ALL OBJECTS *);  USER ^.OBJECTTAIL := NIL;
(* NOW PLACE THE DEAD BODY AND THE OBJECTS IN THE ROOM *)
NEW(BODY) (*CREATE DEAD BODY*); BODY ^ := DEADBODY;
ILOOP := 1;
REPEAT
 BODY^.NAME[ILOOP+5] := USER^.NAME[ILOOP];
 ILOOP := ILOOP + 1;
UNTIL (ILOOP = 10) OR (USER^.NAME[ILOOP] = ' ');
ILOOP := ILOOP + 5;
BODY^.NAME[ILOOP] := '''';
BODY^.NAME[ILOOP + 1] := 'S';
BODY^.NAME[ILOOP + 2] := ' ';
BODY^.NAME[ILOOP + 3] := '*';
    USER ^.WEIGHT := 0;  USER ^.AC := 10;
    IF USER ^.CON * 5 >= RND(100)
    THEN
     WITH USER ^ DO
      BEGIN (*RESURRECTION*)
       USARM := NIL;  USSHIELD := NIL;  USWEAP := NIL;  WRITELN(TERM);
       ENTRY := XCMD;  STATUS := SNORMAL;
       IF NOTIMEOUT(USER)
       THEN
        BEGIN
         WRITELN(TERM, 'EVERYTHING GOES DARK... YOU FEEL YOURSELF FLOATING AWAY INTO'
           );
         WRITELN(TERM, 'SPACE.  AFTER WHAT SEEMS LIKE AN ETERNITY, YOU FAINTLY HEAR')
          ;
         WRITELN(TERM, 'VOICES!  AS YOU COME TO YOUR SENSES, YOU FIND.....');
        END (*IF*);
       WRITELN(TERM);  WRITELN(TERM);  PLACEPLAYER(USER, 17) (*INFIRMARY*);
       POISONED := FALSE;  CON := MAX(3, CON - 1);  HITS := MAXHITS;  FATIGUE := 5;
       IF LVL > 2
       THEN
        BEGIN
         STATUS := SNORMAL;  MAXHITS := MAX(3, MAXHITS - MAXHITS DIV LVL);
         MAXMAGIC := MAX(3, MAXMAGIC - MAXMAGIC DIV LVL);
         MAXFATIGUE := MAX(3, MAXFATIGUE - MAXFATIGUE DIV LVL);  MAGIC := MAXMAGIC;
         LVL := LVL - 1;  HITS := MAXHITS;  FATIGUE := 10;
         CASE RND(4) OF
          1: STR := MAX(3, STR - 1);
          2: INT := MAX(3, INT - 1);
          3: DEX := MAX(3, DEX - 1);
          4: CON := MAX(3, CON - 1);
         END (*CASE*);
        END (*IF*);
       ROOMDISPLAY(RMCODE, BRIEF);  MONEY := MAX(3, PTY) * 10;  EXPERIENCE := 0;
       WRITELN(TERM, 'THE ACOLYTE GIVES YOU A SMALL BAG OF MONEY AND BIDS YOU GO');
       WRITELN(TERM, 'ON YOUR WAY.');
DEAD := FALSE;
WRITELN(TERM); SAVECHAR;
PROMPTUSER(USER)
      END (*WITH*)
    ELSE
     BEGIN
      IF USER ^.LVL >= 5  THEN DAYMSG('ERA', USER, 'CON FAILED', USER ^.CON + 1);
      WRITE(TERM);  PRINTDESC(1, 2, 0, FALSE);  WRITELN;
(* ISSUE A "YOU'RE DEAD!" MESSAGE. *)
USER^.DEAD := FALSE;
      KILL;  WRITECONTROL(MTLO, ZEROPARM, TERM);  WRITELN (*LOGOFF*);  USER := NIL;
     END (*ELSE*);
    BODY ^.NEXT := ROOM[RM].RMOBJECTTAIL;  ROOM[RM].RMOBJECTTAIL := BODY;
    OBJ2 := OBJ;
    IF OBJ <> NIL THEN
     BEGIN
      WHILE OBJ2 ^.NEXT <> NIL DO OBJ2 := OBJ2 ^.NEXT;  OBJ2 ^.NEXT := BODY ^.NEXT;
      BODY ^.NEXT := OBJ;
     END (* OBJECTS DROPPED *);
   END (*DEAD*);


  PROCEDURE WHYDIE;

   VAR
    ILOOP, INDX: INTEGER;

   BEGIN
    USER ^.STATUS := SLOGIN;  DELETEPLAYER(USER, USER ^.RMCODE);
    IF (MIN(MIN(TLVL[1], TLVL[2]), TLVL[3]) < USER ^.LVL) AND NOTIMEOUT(USER)
    THEN
     BEGIN
      INDX := 3;
      FOR ILOOP := 3 DOWNTO 1 DO IF TLVL[ILOOP] < TLVL[INDX]  THEN INDX := ILOOP;
      USER ^.ENTRY := XDEAD;  TLVL[INDX] := USER ^.LVL;  TNAME[INDX] := USER ^.NAME;
      TCLASS[INDX] := CNAME[USER ^.CLASS];  PROMPTUSER(USER)
     END (*IF*)
    ELSE DEAD
   END (*WHYDIE*);


  PROCEDURE ENTERWHYDIE;
(* READ IN LINE EXPLAINING WHY CHARACTER DIED *)

   VAR
    ILOOP, JLOOP: INTEGER;
    FOUND: BOOLEAN;

   BEGIN
    ILOOP := 0;  FOUND := FALSE;
    WHILE NOT FOUND AND (ILOOP < 3) DO
     BEGIN
      ILOOP := ILOOP + 1;
      FOUND := ((TNAME[ILOOP] = USER ^.NAME) AND (TLVL[ILOOP] = USER ^.LVL));
     END (*WHILE*);
    IF NOT FOUND  THEN WRITELN(TERM, 'ON SECOND THOUGHT, FORGET IT!')
    ELSE
     BEGIN
      FOR JLOOP := 1 TO MIN(LENBUF, 78) DO TBUF[ILOOP, JLOOP] := BUFFER[JLOOP];
      FOR JLOOP := LENBUF + 1 TO 80 DO TBUF[ILOOP, JLOOP] := COL;
     END (*ELSE*);
    DEAD
   END (*ENTERWHYDIE*);


  PROCEDURE MINORCMDS(USER: USERPOINT; CMDCODE: INTEGER);

   BEGIN
    WITH USER ^ DO
     CASE CMDCODE OF
      18:
       BEGIN
        TASKCLOSED := 'C';  WRITELN(TERM, 'MILIEU CLOSED.');
        DAYMSG('CLO', USER, BLANKS, 0)
       END (*18*);
      19:
       BEGIN
        TASKCLOSED := 'O';  WRITELN(TERM, 'MILIEU OPENED.');
        DAYMSG('OPE', USER, BLANKS, 0)
       END (*19*);
      51:
       BEGIN
        TASKCLOSED := 'T';  WRITELN(TERM, 'MILIEU OPEN FOR TESTING ONLY.');
        DAYMSG('TST', USER, BLANKS, 0);
       END (*51*);
      20:
       BEGIN
        WRITELN(TERM, ABSOLUTEPLMAX: 0, ' USERS (CAPACITY)');
        WRITELN(TERM, CURRENTPLINDEX: 0, ' USERS (STORED)');
        WRITELN(TERM, NUMQUEUED: 0, ' USERS (IN WAITING QUEUE)');
        WRITELN(TERM, MAXUSERS: 0, ' USERS (MAX ONLINE)');
        WRITELN(TERM, NUSERS: 0, ' USERS (ACTIVE)');
       END (*20*);
      21:
       BEGIN
        DAYMSG('ABT', USER, BLANKS, 0);  UPDATE;  OFF;  FLUSH(OUTPUT);
        ABORT(' MIL00 - DM TOOK TASK DOWN.');
       END (*21*);
      26:
       BEGIN
        ETIME(WORD);  WRITE(TERM, WORD, '  ');  EDATE(WORD);  WRITELN(WORD);
        WRITELN(TERM, REALTIME: 0, ' SECONDS SINCE DEADSTART OF SYSTEM.');
        WRITELN(TERM, CLOCK: 0, ' MILLISECONDS USED SINCE PROGRAM INITIALIZATION.');
        WRITELN(TERM, 'A RANDOM MONSTER CHECK OCCURS EVERY ', MSPEED: 0, ' SECONDS.')
         ;
       END (*26*);
      27:
       BEGIN ERRFLAG := 0;  ABORT(' MIL01 - DM TOOK TASK DOWN. (UPDATE INHIBITED.)')
       END (*27*);
      28:
       BEGIN (*HELP*)
        RESET(EDESC);  GETSEG(EDESC);
        WHILE NOT EOS(EDESC) DO
         BEGIN
          WRITE(TERM);
          WHILE NOT EOLN(EDESC) DO BEGIN READ(EDESC, CH);  WRITE(CH) END;
          READLN(EDESC);  WRITELN
         END (*WHILE*);
        CURRENTREC := 0 (*FLAG FILE MIXED UP*);  WRITELN(TERM);
        WRITELN(TERM, 'LIST OF ALL COMMANDS:');  WRITE(TERM);
        FOR ILOOP := 1 TO CMDLISTLEN DO
         BEGIN
          IF ILOOP MOD 5 = 1  THEN BEGIN WRITELN;  WRITE(TERM) END;
          WRITE('   ', CMDLIST[ILOOP])
         END (*FOR*);
        WRITELN;
       END (*28*);
      30:
       BEGIN
        INVISIBLE := NOT INVISIBLE;  NONEXISTANT := FALSE;
        IF INVISIBLE  THEN WRITELN(TERM, 'YOU ARE NOW INVISIBLE.')
        ELSE WRITELN(TERM, 'YOU ARE NOW VISIBLE.')
       END (*30*);
      34:
       BEGIN
        ECHO := NOT ECHO;
        IF ECHO  THEN WRITELN(TERM, 'ECHO MODE ON.')
        ELSE WRITELN(TERM, 'ECHO MODE OFF.')
       END (*34*);
      83:
       BEGIN
        NONEXISTANT := NOT NONEXISTANT;
        IF NONEXISTANT
        THEN
         BEGIN
          INVISIBLE := TRUE;
          WRITELN(TERM, 'YOU NO LONGER EXIST TO THE OUTSIDE WORLD.')
         END (*IF*)
        ELSE BEGIN INVISIBLE := FALSE;  WRITELN(TERM, 'YOU NOW EXIST.') END
       END (*83*);
     OTHERWISE
      ABORT(' MIL133 - CASE EXPRESSION OUT OF RANGE!');
     END (*CASE*);
   END (*MINORCMDS*);


  BEGIN (*DOCMD*)
   ERRLOC := 'DOCMD     ';
   IF USER ^.ENTRY = XDEAD  THEN ENTERWHYDIE
   ELSE
    IF (USER ^.HITS > 0) AND NOT USER^.DEAD
    THEN (* NOT DEAD *)
     BEGIN
      IF REALTIME > LASTUPDATE + UPDATEPERIOD
      THEN
       IF (NUSERS > 0) AND (USER ^.STATUS <> SLOGIN) THEN
        BEGIN
         UPDATE (* UPDATE THE DATA FILES *);  FLUSH(OUTPUT);  LASTUPDATE := REALTIME;
         FLUSH(OUTPUT);
        END (*IF*);
      WITH USER ^ DO
       IF ENTRY = XSPELL  THEN SPELL(0)
       ELSE
        IF ENTRY = XSURE  THEN QUIT(DATA)
        ELSE
         BEGIN
          IF REALTIME >= LASTHEAL + HEALWAIT
          THEN
           IF POISONED
           THEN
            BEGIN
             LASTHEAL := REALTIME;
             WRITELN(TERM, 'YOU FEEL THE POISON COARSING THROUGH YOUR VEINS!');
             HITS := MAX(0, HITS - RND(2) * LVL);
             IF (HITS = 0) OR DEAD
             THEN
              BEGIN
               IF LVL > 5  THEN DAYMSG('POI', USER, BLANKS, 0);
               FOR ILOOP := 1 TO MSGTERM(TERMLIST, ALL) DO
                WRITELN(TERMLIST[ILOOP], '### ', PS(NAME), ', THE ', PS(CNAME[CLASS])
                  , ', FINALLY DIED FROM HIS POISONOUS WOUNDS.');
              END (*IF*)
            END (*IF*)
           ELSE
            BEGIN (*HEAL *LVL* HP/MP*)
             LASTHEAL := REALTIME;
             IF REALTIME - HITATTIME >= 90  THEN FATIGUE := MAXFATIGUE
             ELSE FATIGUE := MIN(MAXFATIGUE, FATIGUE + LVL);
             MAGIC := MIN(MAXMAGIC, MAGIC + MIN(LVL, 5));
(* HEAL VITALITY *)
             HITS := MIN(MAXHITS, HITS + LVL DIV 2 + 1);
            END (*IF*);
          LOC := 1 (* RESET GETWORD POINTER *);
          GETWORD(CMD, NUM, BUFFER, LENBUF, LOC) (* GET WORD FROM BUFFER *);
          IF CMD <> BLANKS  THEN CMDCODE := BINARYMATCH(CMD, CMDLISTLEN, CMDLIST)
          ELSE CMDCODE := - 1 (* EMPTY C/R *);
          IF (CMD[1] = '*') AND NOT SSJ  THEN CMDCODE := - 2 (* ILLEGAL ACCESS! *);
          IF CMDCODE > 0
          THEN
           BEGIN
            USER ^.LASTCMD := CMDLIST[CMDCODE];  CMDCODE := CMDNUM[CMDCODE];
(* SPECIFY WHICH *CASE* LABEL TO JUMP TO.  CMDCODE = -1 IF NOT
UNIQUE, = 0 IF NOT FOUND. *)
            GETWORD(WORD, NUM, BUFFER, LENBUF, LOC) (* FETCH 2ND CMD WORD *);
           END (*IF*)
          ELSE USER ^.LASTCMD := BLANKS;
          IF USER ^.ASSOC AND (CMDCODE IN [18, 19, 51, 27, 54])  THEN CMDCODE := - 3;
          CASE CMDCODE OF (* *USER* IS AN IMPLIED PARAMETER IN ALL CMDS *)
           - 3: WRITELN(TERM, 'SORRY, ASSOCIATE DM''S MAY NOT USE THAT COMMAND.');
           - 2: WRITELN(TERM, 'SORRY.. THAT''S FOR DM USE ONLY!');
           - 1: (* NOT UNIQUE.  WORDMATCH ALREADY SENT AN ERROR MSG *);
           0: WRITELN(TERM, 'I DON''T UNDERSTAND.');
           18, 19, 51, 20, 26, 27, 28, 30, 34, 83: MINORCMDS(USER, CMDCODE);
           1, 2, 3, 4, 5, 6, 7, 9:
            BEGIN FOLCOUNT := 0;  GODIRECTION(WORD, NUM, CMDCODE); END;
           63: GETOBJECT(WORD, NUM, RMCODE);
           8: DROPOBJECT(WORD, NUM, RMCODE);
           10: BEGIN NUM := USEOBJECT(WORD, NUM);  IF NUM <> 0  THEN SPELL(NUM) END;
           85, 86, 72, 42, 43, 11: ATTACK(CMDCODE, WORD, RMCODE);
           82, 36, 37, 38, 12, 13, 14:
            IF (CMDCODE = 82) AND NOT USER ^.MASTER
            THEN WRITELN(TERM, 'ONLY MASTER DM''S CAN LOGOFF PLAYERS.')
            ELSE TALK(LENBUF, CMDCODE, WORD);
           16: ENTRY := XEDIT;
           39, 17: BEGIN DATA := CMDCODE;  ENTRY := XSURE END;
           21:
            BEGIN
             DAYMSG('ABT', USER, BLANKS, 0);  UPDATE;  OFF;  FLUSH(OUTPUT);
             ABORT(' MIL00 - DM TOOK TASK DOWN.');
            END (*21*);
           22: PLAYERDISPLAY(USER);
           23:
            BEGIN
             UPDATE;  LASTUPDATE := REALTIME;  WRITELN(TERM, 'FILES UPDATED.');
             FLUSH(OUTPUT);
            END (*23*);
           64, 24, 31:
            IF WORD = BLANKS  THEN ROOMDISPLAY(RMCODE, FALSE)
            ELSE
             BEGIN NUM := LOOK(WORD, NUM, CMDCODE);  IF NUM > 0  THEN SPELL(NUM) END;
           25: BRIEF := NOT BRIEF;
           29: RETURNOBJ(WORD, NUM);
           33: GETSTATUS(WORD, USER);
           32: WRITELN(TERM, 'WHEN IN DOUBT, PANIC.');
           40: SAVECHAR;
           41: INVENTORY;
           35: USERS;
           44: ENTERSPELL(WORD, NUM);
           45: APPEAL;
           46: BUY(WORD, NUM, RMCODE);
           47: ENTRY := XNOTICE;
           48: CATALOG;
           49: PAWN(WORD, NUM);
           50:
            IF (NUM < 1) OR (NUM > 3)  THEN WRITELN(TERM, 'MUST BE 1 TO 3')
            ELSE
             BEGIN
              DAYMSG('PUR', USER, 'DEATH NEWS', 0);  YLVL[NUM] := 0;
              WRITELN(TERM, 'DEATH ENTRY DELETED.')
             END (*ELSE*);
           52: ENTRY := XNEWS;
           53:
            IF (NUM < 1) OR (NUM > 5)  THEN WRITELN(TERM, 'MUST BE  1 TO 5')
            ELSE BEGIN NEWSBUF[NUM, 1] := COL;  WRITELN(TERM, 'NEWS DELETED.') END;
           54:
            BEGIN
             MSPEED := MAX(1, MIN(NUM, 10));
             DAYMSG('SPD', USER, 'MONSPEED  ', MSPEED)
            END (*54*);
           55: FOLLOWPLYR(WORD);
           56: LOSE(WORD);
           57, 58, 59, 60: MISCMD(CMDCODE, WORD, NUM);
           61: ACCEPT;
           62: TURN(WORD, NUM);
           65, 66, 67, 68, 69, 70: OPENCLOSE(CMDCODE, WORD, NUM);
           71: TRACK;
           73: HIDE(WORD, NUM);
           74: SEARCH;
           75: TRAIN;
           76:
            BEGIN
             MESBLOCK := NOT MESBLOCK;
             IF MESBLOCK  THEN WRITELN(TERM, 'SEND MESSAGES BLOCKED.')
             ELSE WRITELN(TERM, 'SEND MESSAGES RECEIVED.')
            END (*76*);
           77: PRINTBREG;
           78: RUN;
           79: PRINTEXP;
           80: DISPDAY(NUM);
           81: PARLEY(WORD, NUM);
           84: STEALOBJ(WORD, NUM);
           87: AUTO := TRUE;
          OTHERWISE
           ABORT(' MIL153 - CASE LABEL UNDEFINED!');
          END (*CASE*)
         END (*WITH*);
      IF USER <> NIL THEN
       IF (USER^.HITS = 0) OR USER^.DEAD  THEN WHYDIE
       ELSE IF NOT USER ^.AUTO  THEN PROMPTUSER(USER) (* ISSUE THE "CMD-?" PROMPT *)
     END (*IF*)
    ELSE WHYDIE (*OOPS, SORRY*)
  END (*DOCMD*);


 PROCEDURE MONSTERATTACK;

  VAR
   PLYR: USERPOINT;
   TEMPFAT: INTEGER;


  PROCEDURE MONSTRIKE(RM: RMCODETYPE);

   VAR
    PLYRSWODM, NUMSP, ACLASS, NUMPLYRS, MONNUM, ILOOP, NUMMONS, DAMAGE: INTEGER;
    PLYR: USERPOINT;
    MONSTER: MONSTERPOINT;
    ATKFLAG: BOOLEAN;
    ESPEED, SPEED: INTEGER;

   BEGIN (*MONSTRIKE*)
    SPEED := MSPEED;  ESPEED := 10;  ERRLOC := 'MONSTRIKE ';
    IF NUSERS = 1  THEN BEGIN SPEED := 1;  ESPEED := 40 END;
    WITH ROOM[RM] DO
     BEGIN
      PLYRSWODM := 0;  NUMPLYRS := 0;  PLYR := RMPLAYERTAIL;
      IF RMMONSTERTAIL <> NIL
      THEN IF NOT RMMONSTERTTAIL ^.PERMANENT  THEN ESPEED := ESPEED DIV 5;
      WHILE PLYR <> NIL DO
       BEGIN
        IF NOT PLYR ^.INVISIBLE  THEN PLYRSWODM := PLYRSWODM + 1;
        NUMPLYRS := NUMPLYRS + 1;  PLYR := PLYR ^.NEXT
       END (*WHILE*);
      IF (ENCOUNTERTIME > 0) AND (WHICHENCOUNTER > 0)
      THEN (*CHECK FOR ENCOUNTER*)
       IF RND((ENCOUNTERTIME * 25) DIV ESPEED) <= 3
       THEN
        BEGIN (*RND ENCOUNTER*)
         ILOOP := 1;
         WHILE (ENCOUNTERINDEX[WHICHENCOUNTER, MIN(ILOOP + 1, 6)] > 0) AND (ILOOP < 6
           ) DO
          ILOOP := ILOOP + 1;
         IF ENCOUNTERINDEX[WHICHENCOUNTER, 1] > 0
         THEN
          BEGIN
           MONNUM := ENCOUNTERINDEX[WHICHENCOUNTER, RND(ILOOP)];
           NUMMONS := RND(MAX(1, PLYRSWODM - 1));
           IF RND(4) = 2  THEN NUMMONS := RND(MAX(1, PLYRSWODM - 1) * 2);
           FOR ILOOP := 1 TO NUMMONS DO
            BEGIN
             NEW(MONSTER);  MONSTER ^ := RANMONLIST[MONNUM];
             MONSTER ^.HITS := MIN(MONSTER ^.MAXHITS, MAX(1, ROUND(MONSTER ^.HITS *
               0.8 + MONSTER ^.HITS * RND(40) / 100)));
             MONSTER ^.LVL := MIN(25, MAX(1, MONSTER ^.LVL + 2 - RND(3)));
             INSERTMONSTER(MONSTER, RM);
            END (*FOR*);
           PLYR := RMPLAYERTAIL;
           FOR ILOOP := 1 TO NUMPLYRS DO
            BEGIN
             IF NOT PLYR ^.AUTO  THEN PLYR ^.ENCOUNTSTOP := TRUE;
             IF NOTIMEOUT(PLYR)
             THEN
              BEGIN
               WRITE(PLYR ^.TRM);
               IF PLYRSWODM <= 1  THEN WRITE('YOU ENCOUNTER ')
               ELSE WRITE('YOUR PARTY ENCOUNTERS ');
               IF NUMMONS = 1  THEN WRITE('A ', PS(MONSTER ^.NAME))
               ELSE WRITE(PN(NUMMONS), PS(MONSTER ^.NAME), 'S');
               WRITELN('!');
              END (*IF*);
             PLYR := PLYR ^.NEXT
            END (*FOR*);
          END (*IF*)
        END (*IF*);
      MONSTER := RMMONSTERTTAIL;
      IF NOT SAFE
      THEN
       WHILE MONSTER <> NIL DO
        WITH MONSTER ^ DO
         BEGIN
          ATKFLAG := FALSE;
          IF (DEFPLAYER = NIL) AND (TOP OR (NUM < 9))
          THEN
           IF SLOWREACT AND (RND(SPEED * 2) = 1) OR FASTREACT
           THEN
            BEGIN
             ATKFLAG := TRUE;  PLYR := RMPLAYERTAIL;
             FOR ILOOP := 1 TO RND(NUMPLYRS) - 1 DO (*HIT RANDOMLY*)
              PLYR := PLYR ^.NEXT;
             IF NOT PLYR ^.EVIL AND NOT PLYR ^.INVISIBLE AND NOT PLYR ^.HIDDEN
             THEN DEFPLAYER := PLYR
             ELSE ATKFLAG := FALSE;
            END (*IF*)
           ELSE
            IF MORALREACT AND (RND(SPEED) = 1)
            THEN
             BEGIN
              PLYR := RMPLAYERTAIL;  DEFPLAYER := PLYR;
              FOR ILOOP := 1 TO NUMPLYRS DO
               BEGIN
                IF (PLYR ^.PTY < DEFPLAYER ^.PTY) AND (RND(3) <= 2)
                THEN DEFPLAYER := PLYR;
                PLYR := PLYR ^.NEXT
               END (*FOR*);
              IF (DEFPLAYER ^.PTY > 7) OR DEFPLAYER ^.INVISIBLE
              THEN DEFPLAYER := NIL
              ELSE ATKFLAG := TRUE;
             END (*IF*);
          USER := DEFPLAYER;  IF USER <> NIL  THEN TERM := USER ^.TRM;  PLYR := USER;
          IF ATKFLAG
          THEN
           BEGIN
MREACT := 0;
            FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
             WRITELN(TERMLIST[ILOOP], PM(MONSTER), 'ATTACKS ', PS(PLYR ^.NAME), '!');
            WRITELN(TERM, PM(MONSTER), ' ATTACKS YOU!')
           END (*IF*);
          IF (DEFPLAYER <> NIL) AND (RND(SPEED) = 1) AND NOT (MREACT IN [1, 2, 3])
          THEN
           BEGIN
            IF REGENERATE  THEN HITS := MIN(MAXHITS, HITS + LVL DIV 2 + 1);
            PLYR := DEFPLAYER;  PLYR ^.HITATTIME := REALTIME;
            ACLASS := - (PLYR ^.AC - 10);
            IF (RND(19) <> 19) AND (RND(21) < 9 - LVL + PLYR ^.LVL + ACLASS + PLYR ^.
              DEX DIV 6) AND (MREACT <> 6) OR (PLYR ^.HITS = 0) OR (MREACT = 4)
            THEN
             BEGIN
              IF NOT PLYR ^.BRIEF AND NOTIMEOUT(PLYR)
              THEN WRITELN(PLYR ^.TRM, PM(MONSTER), 'MISSES YOU!')
             END (*IF*)
            ELSE
             WITH PLYR ^ DO
              BEGIN
               DAMAGE := MONSTER ^.LVL * 4;  DAMAGE := MAX(1, DAMAGE + 3 - RND(5));
               IF MONSTER ^.MONSPELLS
               THEN
                IF RND(3) = 2
                THEN
                 BEGIN
                  CASE RND(4) OF
                   1: NUMSP := 3;
                   2: NUMSP := 4;
                   3: NUMSP := 8;
                   4: NUMSP := 16;
                  END (*CASE*);
                  USER := PLYR;  TERM := PLYR ^.TRM;
                  FOR ILOOP := 1 TO MSGTERM(TERMLIST, LOCAL) DO
                   WRITELN(TERMLIST[ILOOP], 'THE ', PS(MONSTER ^.NAME), ' CASTS A ',
                     PS(SPELLIST[NUMSP]), ' SPELL ON ', PS(NAME), '!');
                  WRITELN(TERM, 'THE ', PS(MONSTER ^.NAME), ' CASTS A ', PS(SPELLIST[
                    NUMSP]), ' SPELL ON YOU!');
                  DAMAGE := SPELLMON(NUMSP, MONSTER ^.LVL, 15, PLYR, NIL, NIL, NAME);
                  IF DAMAGE = 0  THEN DAMAGE := MONSTER ^.LVL * 3;
                 END (*IF*);
               IF MREACT = 5  THEN DAMAGE := DAMAGE DIV 2 + 1;
               IF MREACT = 6  THEN DAMAGE := DAMAGE * 2;  TEMPFAT := 0;
               IF NOTIMEOUT(PLYR)
               THEN
                CASE RND(100) OF
                 1, 2, 3, 4:
                  BEGIN WRITELN(TRM, 'DOUBLE DAMAGE!');  DAMAGE := DAMAGE * 2 END;
                 12, 13, 14:
                  BEGIN
                   WRITELN(TRM, 'VITAL WOUND!');  TEMPFAT := FATIGUE;  FATIGUE := 0;
                  END (*12*);
                 18, 19, 20, 21:
                  BEGIN
                   MREACT := 3;  DAMAGE := 0;
                   WRITELN(TRM, 'THE ', PS(MONSTER ^.NAME), ' FUMBLES!');
                   MONSTER ^.DEFPLAYER := NIL;
                  END (*18*);
                OTHERWISE
                END (*CASE*);
               HITSHARMOR(PLYR, DAMAGE);
               IF NOTIMEOUT(PLYR) THEN
                BEGIN
                 WRITE(TRM, PM(MONSTER));
                 IF BRIEF  THEN WRITE('HITS FOR ')  ELSE WRITE('HITS YOU FOR ');
                 PRINTDMG(PLYR, DAMAGE, BRIEF);
                END (*IF*);
               IF DRAIN AND (RND(4) = 4)
               THEN
                BEGIN
                 IF LVL <= 1  THEN BEGIN CON := 0;  DEAD := TRUE; HITS := 0;  FATIGUE := 0 END
                 ELSE
                  BEGIN
                   IF NOTIMEOUT(PLYR)
                   THEN WRITELN(TRM, 'YOU FEEL WEAK AND DRAINED...');
                   MAXHITS := MAXHITS - MAXHITS DIV LVL;
                   MAXFATIGUE := MAXFATIGUE - MAXFATIGUE DIV LVL;
                   MAXMAGIC := MAXMAGIC - MAXMAGIC DIV LVL;  LVL := LVL - 1;
                   FOR ILOOP := 1 TO 2 DO
                    CASE RND(4) OF
                     1: STR := MAX(3, STR - 1);
                     2: INT := MAX(3, INT - 1);
                     3: DEX := MAX(3, DEX - 1);
                     4: CON := MAX(3, CON - 1);
                    END (*CASE*)
                  END (*ELSE*)
                END (*IF*);
               IF HITS + FATIGUE <= DAMAGE
               THEN
                BEGIN
DEAD := TRUE;
                 HITS := 0;  FATIGUE := 0;  USER := PLYR;  TERM := TRM;
                 IF USER ^.LVL > 5
                 THEN DAYMSG('KIL', USER, MONSTER ^.NAME, MONSTER ^.LVL);
                 FOR ILOOP := 1 TO MSGTERM(TERMLIST, ALL) DO
                  BEGIN
                   WRITE(TERMLIST[ILOOP], '### ', PS(NAME), ', THE ', PS(CNAME[CLASS]
                     ), ', WAS JUST ');
                   CASE RND(4) OF
                    1: WRITE('SLAIN');
                    2: WRITE('KILLED');
                    3: WRITE('DE-REZZED');
                    4: WRITE('MURDERED');
                   END (*CASE*);
                   WRITELN(' BY A ', PS(MONSTER ^.NAME), '.');
                   IF LVL > 10 THEN
                    WRITELN(TERMLIST[ILOOP], '### WE SHALL ALL GRIEVE FOR ', PRO[SEX], '.'
                      );
                  END (*FOR*);
                END (*IF*)
               ELSE
                BEGIN
                 IF POISON AND (DAMAGE > 0)
                 THEN
                  IF (RND(MONSTER ^.LVL * 2) > LVL) AND (RND(3) = 3) THEN
                   BEGIN
                    IF NOTIMEOUT(PLYR)  THEN WRITELN(TRM, 'YOU''VE BEEN POISONED!');
                    POISONED := TRUE
                   END (*IF*);
                 IF DAMAGE > FATIGUE  THEN HITS := HITS - DAMAGE + FATIGUE;
                 FATIGUE := MAX(0, FATIGUE - DAMAGE);
                 IF TEMPFAT > 0  THEN FATIGUE := TEMPFAT
                END (*ELSE*);
               MONSTER ^.MREACT := 0;
              END (*WITH*);
            IF MREACT = 4  THEN MREACT := 0;
           END (*IF*)
          ELSE IF MREACT IN [1, 2, 3]  THEN MREACT := MREACT - 1;
          MONSTER := MONSTER ^.NEXT
         END (*WHILE*)
     END (*WITH*)
   END (*MONSTRIKE*);


  PROCEDURE TIMECHECK(VAR NEXTCHECK: ALFA);
(* CHECK FOR A TIMED EVENT OCCURANCE. *)

   VAR
    EVENTNUM, ILOOP: INTEGER;
    FOUND: BOOLEAN;

   BEGIN (* EXECUTE THE TIMED EVENT. *)
    USER := USERTAIL;  TERM := USER ^.TRM;
(* SELECT A DUMMY USER FOR MSGTERM MESSAGES. *)
    IF NEXTCHECK = 'INITIALIZE'
    THEN
     BEGIN
      FOR ILOOP := LENEVENT DOWNTO 1 DO
       IF CLOCKTIME <= EVENT[ILOOP]  THEN NEXTCHECK := EVENT[ILOOP];
      IF NEXTCHECK = 'INITIALIZE' (*STILL*)  THEN NEXTCHECK := EVENT[1]
     END (*IF*)
    ELSE
     BEGIN
      ILOOP := LENEVENT;  FOUND := FALSE;
      WHILE NOT FOUND AND (ILOOP >= 1) DO
       BEGIN FOUND := (NEXTCHECK >= EVENT[ILOOP]);  ILOOP := ILOOP - 1 END;
      IF FOUND  THEN EVENTNUM := ILOOP + 1
      ELSE ABORT(' MIL943 - TIMED EVENT NOT FOUND!');
      CASE EVENTNUM OF
       1 (*12:01 AM*): NEXTCHECK := EVENT[2];
       2 (*12:05 AM*): IF CLOCKTIME < ' 23.00.00.'  THEN NEXTCHECK := EVENT[3];
       3 (*12:10 AM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'YOU HEAR AN OWL HOOTING IN THE DISTANCE.');
       4 (*12:30 AM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], '>>> PROGRAM WILL ABORT AT 1:00 AM.');
       5 (*12:45 AM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP],
           '>>> PROGRAM ABORTING IN 15 MINUTES. UP AGAIN AT 7 AM.');
       6 (*12:55 AM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], '>>> PROGRAM ABORTING IN 5 MINUTES. ');
       7 (*12:58 AM*):
        BEGIN
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
          WRITELN(TERMLIST[ILOOP],
            'WAIT UNTIL PROGRAM ABORTS: A HANGUP WILL COST YOU A CON POINT.');
         LASTUPDATE := REALTIME - UPDATEPERIOD - 10 (* FORCE UPDATE *);
        END (*7*);
       8 (*12:59 AM*):
        BEGIN
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
          WRITELN(TERMLIST[ILOOP], '*** WARNING *** PROGRAM ABORTING.');
         OFF;  FLUSH(OUTPUT);  ABORT(' MIL001 - PROGRAM TOOK ITSELF DOWN.')
        END (*8*);
       9 (*7:10 AM*):
        BEGIN
         WRITELN(DAYFILE, CLOCKTIME, ' ---- TASK OPEN FOR THE DAY ----');
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
          WRITELN(TERMLIST[ILOOP], 'GOOD MORNING AND WELCOME TO MILIEU!');
        END (*9*);
       10 (*12:00 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'YOU HEAR THE TOWN CLOCK STRIKE THE NOON HOUR.');
       11 (*2:30 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], '>>> PROGRAM WILL ABORT AT 3 OCLOCK.');
       12 (*2:45 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], '>>> PROGRAM WILL ABORT IN 15 MINUTES.');
       13 (*2:55 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], '>>> PROGRAM WILL ABORT IN 5 MINUTES.');
       14 (*2:59 PM*):
        BEGIN
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
          WRITELN(TERMLIST[ILOOP],
            'WAIT FOR ABORT: A HANGUP WILL COST YOU A CON POINT.');
         LASTUPDATE := REALTIME - UPDATEPERIOD - 10 (* FORCE UPDATE *);
        END (*14*);
       15 (*3:00 PM*):
        BEGIN
         FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
          WRITELN(TERMLIST[ILOOP], '*** WARNING *** PROGRAM ABORTING');
         OFF;  FLUSH(OUTPUT);  ABORT(' MIL001 - PROGRAM TOOK ITSELF DOWN.')
        END (*15*);
       16 (*3:04 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'WELCOME BACK!  THAT WASN''T SO BAD, WAS IT?');
       17 (*7:00 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'THE SUN SETS IN THE WEST.');
18: IF DAY=4 THEN
  LASTUPDATE := REALTIME - UPDATEPERIOD - 10;
       19 (*8:59 PM*):
IF DAY=4 THEN BEGIN
  OFF; FLUSH(OUTPUT); ABORT(' MIL001 - PROGRAM TOOK ITSELF DOWN.')
 END
ELSE
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'THE TOWN WATCH SETS OUT ON THE WALLS OF THE CITY.'
           );
       21 (*10:30 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'YOU HEAR CRICKETS CHIRP IN THE GRASS.');
       20 (*12:55 PM*):
        FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
         WRITELN(TERMLIST[ILOOP], 'THE TOWN CLOCK STRIKES THE MIDNIGHT HOUR.');
      END (*CASE*);
      IF (EVENTNUM > 2) THEN
       IF EVENTNUM = LENEVENT  THEN NEXTCHECK := EVENT[1]
       ELSE NEXTCHECK := EVENT[EVENTNUM + 1]
     END (*ELSE*);
   END (*TIMECHECK*);


  BEGIN (*MONSTERATTACK*)
   IF (CLOCKTIME >= NEXTCHECK) OR (NEXTCHECK = 'INITIALIZE')
   THEN IF NUSERS > 0  THEN TIMECHECK(NEXTCHECK);
   PLYR := USERTAIL;
   WHILE PLYR <> NIL DO
    BEGIN
     IF PLYR ^.STATUS <> SLOGIN
     THEN IF ROOM[PLYR ^.RMCODE].RMPLAYERTAIL = PLYR  THEN MONSTRIKE(PLYR ^.RMCODE);
     PLYR := PLYR ^.NEXTUSER
    END (*WHILE*)
  END (*MONSTERATTACK*);



 PROCEDURE INITIALIZE;
(**********************************************************
THIS PROCEDURE INITIALIZES THE DUNGEON, FETCHES THE FILES, AND
BRINGS THE TASK UP.  IT GETS THE EDESC, EROOM, EMON, EOBJ AND EPERSON
FILES.  THE PROCEDURE *ROLLOUT* ROLLS OUT THE TASK AFTER EVERY
50 RA+1 REQUESTS AS PER *MULTI* PROTOCOL.  USERS WHO INADVERTENTLY
LOG IN WHILE THIS PROCEDURE IS IN EFFECT ARE GRACIOUSLY ASKED
TO WAIT 10 SECONDS, AND THEN TRY LOGGING IN AGAIN.
************************************************************)

  VAR
   I, LASTDAY, DAYSAPART, ILOOP, JLOOP: INTEGER;
   OBJECT, OBJECT2: OBJECTPOINT;
   MONSTER, MONSTER2: MONSTERPOINT;
   PLYR: USERPOINT;
   D: ALFA;
   DUMPARM: PARMBLOCK;
   CH: CHAR;
   INITBUF: BUFTYPE;
   INITLEN: LENBUFTYPE;
   INITLOG: LOGLENTYPE;


  PROCEDURE READALFA(VAR STRING: ALFA);

   VAR
    ILOOP: INTEGER;
    CH: CHAR;

   BEGIN
    STRING := BLANKS;  ILOOP := 1;  WHILE EDESC ^ = ' ' DO READ(EDESC, CH);
    WHILE NOT EOLN(EDESC) AND (ILOOP <= 10) DO
     BEGIN
      READ(EDESC, CH);  IF CH = ' '  THEN ILOOP := 100  ELSE STRING[ILOOP] := CH;
      ILOOP := ILOOP + 1
     END (*WHILE*)
   END (*READALFA*);


  PROCEDURE GETFILE(VAR F: SEGCHARFIL; PFN, PW, UN: ALFA7);
   EXTERN;


  PROCEDURE SAVEFET(VAR F: SEGCHARFIL; OFFSET, LOC: INTEGER);
   EXTERN;


  PROCEDURE GETDFILE(VAR F: BINFILETYPE; PFN, PW, UN: ALFA7);
   EXTERN;


  PROCEDURE ATTACHF(VAR F: BINFILETYPE; PFN, PW, UN: ALFA7);
   EXTERN;


  FUNCTION PDATE: INTEGER;
   EXTERN;


  FUNCTION DAYWEEK(SYSDATE: INTEGER): INTEGER;
   EXTERN;


  PROCEDURE SETRA(VAR RA: INTEGER);
(* PASS THE ADDRESS OF THE GLOBAL VARIABLE *RA* TO COMCSYS.  *RA*
   WILL BE INCREMENTED EACH AN RA+1 REQUEST IS ISSUED. *)
   EXTERN;


  BEGIN (*INITIALIZE*)
   RTIME(REALTIME);  CLOSE(INPUT);  OPEN(INPUT, 'INPUT     ', FALSE);
(* CHANGE INPUT FROM SCRATCH TO "INPUT" *)
   NEW(USER);  USER ^ := PROTOUSER (* SET DEFAULTS *);  LOGLEN := 0;  LENBUF := 0;
(* READ IN THE FIRST USER.  OFFICIAL LOGIN DOES NOT OCCUR UNTIL THE
END OF THIS INITILIZATION PHASE *)
   LENBUF := 0;  LOGLEN := 0;
   READCONTROL(CONTROL, PARM, TERM, BUFFER, LENBUF, LOGLEN);
   PACK(BUFFER, 1, USER ^.UN);  INITLEN := 0;  INITLOG := 0;  ILOOP := 7;
   WHILE USER ^.UN[ILOOP] = COL DO
    BEGIN USER ^.UN[ILOOP] := ' ';  ILOOP := ILOOP - 1 END;
   READCONTROL(CONTROL, DUMPARM, TERM, INITBUF, INITLEN, INITLOG);
(* READ IN LOGIN TEXT *)
   USER ^.TRM := TERM;  USER ^.ENTRY := XINIT;  USER ^.STATUS := SINIT;  RA := 0;
   SETRA(RA) (* FORCE SYS= TO INCREMENT THE GLOBAL VARIABLE *RA* *);
   WRITELN(TERM, 'PLEASE WAIT.');  ROLLOUT(TERM);  TIME(CLOCKTIME);  HEADER;
   SYSDATE := PDATE;  SEEDRND(SYSDATE);  DAY := DAYWEEK(SYSDATE);
(* NOW READ IN THE DUNGEON FILES *)
   OPENDFIL(EPERSON, 'EPERSON   ', FALSE);
   ATTACHF(EPERSON, 'EPERSON', FILEPW, ORIGINUN);
   GETFILE(DAYFILE, 'DAYFILE', FILEPW, ORIGINUN);
   GETFILE(EDESC, 'EDESCRP', FILEPW, ORIGINUN);  SWITCH(FALSE, 1);
   GETDFILE(EROOM, 'DUNJON1', FILEPW, ORIGINUN);  RESET(EDESC);  RESET(EPERSON);
   RESET(DAYFILE);  SAVEFET(DAYFILE, 14, 1);  RESET(EROOM);  SAVEFET(EDESC, 14, 4);
   SWITCH(FALSE, 2);  GETDFILE(EROOM, 'DUNJON2', FILEPW, ORIGINUN);  RESET(EROOM);
   SWITCH(FALSE, 1);  LINELIMIT(OUTPUT, MAXINT);  LINELIMIT(INPUT, MAXINT);
   LINELIMIT(DAYFILE, MAXINT);  LINELIMIT(EDESC, MAXINT);  TRADETIME := 0;
   NTPLYR := BLANKS;  NFPLYR := BLANKS;
   FOR ILOOP := 1 TO 3 DO
    BEGIN
     TNAME[ILOOP] := EMPTY;  YNAME[ILOOP] := EMPTY;  TLVL[ILOOP] := 0;
     YLVL[ILOOP] := 0;  TCLASS[ILOOP] := EMPTY;  YCLASS[ILOOP] := EMPTY;
     FOR JLOOP := 1 TO 80 DO
      BEGIN TBUF[ILOOP, JLOOP] := COL;  YBUF[ILOOP, JLOOP] := COL END;
    END (*FOR*);
   FOR ILOOP := 1 TO 5 DO FOR JLOOP := 1 TO 80 DO NEWSBUF[ILOOP, JLOOP] := COL;
   FOR ILOOP := 1 TO ABSOLUTEPLMAX DO PLAYERINDEX[ILOOP] := EMPTY;
   IF EOF(EPERSON) OR EOS(EPERSON)
   THEN
    BEGIN
     REWRITE(EPERSON);  NEW(PLYR);  PLYR ^ := PROTOUSER;  WRITEUSR(PLYR, TRUE);
     NEW(PLYR);  PLYR ^ := PROTOUSER;  WRITEUSR(PLYR, TRUE);
     PUTSEG(EPERSON) (* WRITE EMPTY PRU OF USERS *);
    END (*IF*);
   ILOOP := 1;  ROLLCHECK(TERM);
   WHILE NOT EOS(EROOM) AND (ILOOP <= RANOBJLEN) DO
    BEGIN READUOBJ(EROOM, RANOBJLIST[ILOOP]);  ILOOP := ILOOP + 1; END;
   FOR ILOOP := ILOOP TO RANOBJLEN DO
    BEGIN RANOBJLIST[ILOOP] := PROTOOBJECT;  RANOBJLIST[ILOOP].PERMANENT := FALSE
    END (*FOR*);
   IF NOT EOF(EROOM)  THEN GETSEG(EROOM);  ILOOP := 1;  ROLLCHECK(TERM);
   WHILE NOT EOS(EROOM) AND (ILOOP <= RANMONLEN) DO
    BEGIN READMON(EROOM, RANMONLIST[ILOOP]);  ILOOP := ILOOP + 1; END;
   FOR ILOOP := ILOOP TO RANMONLEN DO
    BEGIN RANMONLIST[ILOOP] := PROTOMONSTER;  RANMONLIST[ILOOP].PERMANENT := FALSE;
    END (*FOR*);
   IF NOT EOF(EROOM)  THEN GETSEG(EROOM);  ROLLCHECK(TERM);  REWRITE(EMAP);
   CURRENTSEG := 0;  NUMSEGS := 0;  EOFSEG := 1;
   FOR ILOOP := 0 TO MAXPLUSONE DO
    BEGIN SLOTTBL[ILOOP] := - 1;  ACTIVE[ILOOP] := 0; END;
   FOR ILOOP := 0 TO RMLIMIT DO ROOM[ILOOP] := PROTOROOM;
   FOR ILOOP := 0 TO MAXSEGS DO RMSEGLOC[ILOOP] := 0;
   IF EOS(EROOM) OR EOF(EROOM)  THEN ADDSEG
   ELSE
    WHILE NOT EOF(EROOM) AND (NUMSEGS <= MAXSEGS) DO
     BEGIN
      IF NUMSEGS = 70  THEN SWITCH(FALSE, 2);  ILOOP := 0;  EOFSEG := EOFSEG + 1;
      ROLLCHECK(TERM);
      WHILE NOT EOS(EROOM) DO
       BEGIN READ(EROOM, I);  WRITE(EMAP, I);  ILOOP := ILOOP + 1; END (*WHILE*);
      NUMSEGS := NUMSEGS + 1;  RMSEGLOC[NUMSEGS - 1] := NUMSEGS;  PUTSEG(EMAP);
      GETSEG(EROOM);  ROLLCHECK(TERM);
     END (*WHILE*);
   NUMROOMS := NUMSEGS * 10 - 1 (* HIGHEST #ED ACTIVE ROOM *);  GETSEG(EDESC, 10000);
   GETSEG(EDESC, - 1) (* READ IN PROGRAM CONSTANTS *);  ROLLCHECK(TERM);
   READLN(EDESC, TASKCLOSED, NUMRUN, LASTDAY, MSPEED);  CURRENTPLINDEX := 0;
   DATE(D);  TODAY := (ORD(D[8]) - ORD('0')) * 10;
   TODAY := TODAY + (ORD(D[9]) - ORD('0'));  RESET(EPERSON);  NEW(PLYR);
   WHILE NOT EOS(EPERSON) AND NOT EOF(EPERSON) DO
    BEGIN
     CURRENTPLINDEX := CURRENTPLINDEX + 1;  READUSR(PLYR, FALSE) (*DON'T READ OBJ*);
     PLAYERINDEX[CURRENTPLINDEX] := PLYR ^.NAME;
     DAYSAPART := ABS(PLYR ^.LASTACCESS - TODAY);
     IF (DAYSAPART > 10) AND (DAYSAPART < 20) AND (PLYR ^.NAME <> EMPTY)
     THEN PLAYERINDEX[CURRENTPLINDEX] := EMPTY;
(* ERASE PLAYER ENTRY IF 10-15 DAYS OLD *)
     IF NOT ODD(CURRENTPLINDEX)  THEN GETSEG(EPERSON);  ROLLCHECK(TERM);
    END (*WHILE*);
   RANDOMACCESS(EPERSON);  DISPOSE(PLYR) (* ERASE TEMP VAR *);  ILOOP := 1;
   WHILE NOT EOLN(EDESC) AND (ILOOP < 80) DO
    BEGIN READ(EDESC, NOTICE[ILOOP]);  ILOOP := ILOOP + 1; END;
   READLN(EDESC);
   IF NOT EOS(EDESC)
   THEN
    BEGIN
     FOR ILOOP := 1 TO 5 DO
      BEGIN
       JLOOP := 1;
       WHILE NOT EOLN(EDESC) AND (JLOOP < 80) DO
        BEGIN READ(EDESC, NEWSBUF[ILOOP, JLOOP]);  JLOOP := JLOOP + 1 END;
       READLN(EDESC);
      END (*FOR*);
     FOR ILOOP := 1 TO 3 DO
      BEGIN
       READ(EDESC, TLVL[ILOOP], YLVL[ILOOP]);  READLN(EDESC);
       READALFA(TNAME[ILOOP]);  READALFA(YNAME[ILOOP]);  READALFA(TCLASS[ILOOP]);
       READALFA(YCLASS[ILOOP]);  READLN(EDESC);  JLOOP := 1;
       WHILE NOT EOLN(EDESC) DO
        BEGIN READ(EDESC, TBUF[ILOOP, JLOOP]);  JLOOP := JLOOP + 1 END;
       READLN(EDESC);  JLOOP := 1;
       WHILE NOT EOLN(EDESC) DO
        BEGIN READ(EDESC, YBUF[ILOOP, JLOOP]);  JLOOP := JLOOP + 1 END;
       READLN(EDESC);
      END (*FOR*);
    END (*IF*);
   ROLLCHECK(TERM);
   IF LASTDAY <> TODAY
   THEN
    FOR ILOOP := 1 TO 3 DO
     BEGIN
      YNAME[ILOOP] := TNAME[ILOOP];  TNAME[ILOOP] := EMPTY;
      YLVL[ILOOP] := TLVL[ILOOP];  TLVL[ILOOP] := 0;  YCLASS[ILOOP] := TCLASS[ILOOP];
      TCLASS[ILOOP] := EMPTY;  YBUF[ILOOP] := TBUF[ILOOP];  TBUF[ILOOP, 1] := COL;
     END (*FOR*);
   SETDAYFILE;  PUTSEG(DAYFILE);  BUFFER := INITBUF;  LENBUF := INITLEN;
   LOGLEN := INITLOG;
(* PUT LOGIN TEXT OF FIRST USER BACK  IN BUFFER *)
   ROLLOUT(TERM);  MESSAGE(' GET DATABASE.');
   ERRFLAG := 1 (*ENABLE ERROR TRAPPING *);  LASTUPDATE := REALTIME;
   SETERR(ERRFLAG, ERRLOC) (*POKE IN ERR TRAP*);
  END (*INITIALIZE*);


 PROCEDURE UPDATE;
(* UPDATE WILL REWRITE THE DUNGEON FILES. THIS IS DONE EVERY
60 MINUTES. *)

  VAR
   I, RLOOP, ILOOP, JLOOP: INTEGER;
   OBJECT: OBJECTPOINT;
   MONSTER: MONSTERPOINT;
   USR: USERPOINT;

  BEGIN
   ERRLOC := 'UPDATE    ';  ERRFLAG := 0 (* INHIBIT REPLACE *);
   FOR ILOOP := 1 TO MSGTERM(TERMLIST, SYSMSG) DO
    WRITELN(TERMLIST[ILOOP], 'FILES UPDATING. PLEASE WAIT.');
   ROLLCHECK(TERM);  SWITCH(TRUE, 1);  REWRITE(EROOM);  ROLLCHECK(TERM);
   FOR ILOOP := 1 TO RANOBJLEN DO WRITEUOBJ(EROOM, RANOBJLIST[ILOOP]);
   PUTSEG(EROOM);  ROLLCHECK(TERM);
   FOR ILOOP := 1 TO RANMONLEN DO WRITEMON(EROOM, RANMONLIST[ILOOP]);  PUTSEG(EROOM);
   ROLLCHECK(TERM);
   FOR ILOOP := 0 TO MAXUSERS DO
    BEGIN
     IF SLOTTBL[ILOOP] > - 1  THEN WRITESEG(ILOOP, SLOTTBL[ILOOP], FALSE);
     ROLLCHECK(TERM)
    END (*FOR*);
   RESET(EMAP);  CURRENTSEG := 1;
   FOR RLOOP := 0 TO NUMSEGS - 1 DO
    BEGIN
     IF RLOOP = 70
     THEN BEGIN WRITE(EROOM, 0);  PUTSEG(EROOM);  SWITCH(TRUE, 2); END;
     ROLLCHECK(TERM);
     IF RMSEGLOC[RLOOP] = 0  THEN ABORT(' MIL288 - UNDEFINED RMSEGLOC!');
     GETSEG(EMAP, RMSEGLOC[RLOOP] - CURRENTSEG);
     IF EOS(EMAP)  THEN ABORT(' MIL423 - EMPTY ROOM SEG TO UPDATE!');  ILOOP := 0;
     WHILE NOT EOS(EMAP) DO
      BEGIN READ(EMAP, I);  WRITE(EROOM, I);  ILOOP := ILOOP + 1; END (*WHILE*);
     CURRENTSEG := RMSEGLOC[RLOOP];  PUTSEG(EROOM);  ROLLCHECK(TERM);
    END (*FOR*);
   SWITCH(FALSE, 1);  ROLLCHECK(TERM);  RESET(EROOM);  REWRITE(EMAP);
   GETSEG(EROOM, 2);  ROLLCHECK(TERM);
   FOR RLOOP := 0 TO NUMSEGS - 1 DO
    BEGIN
     IF RLOOP = 70  THEN SWITCH(FALSE, 2);  ILOOP := 0;  ROLLCHECK(TERM);
     WHILE NOT EOS(EROOM) DO
      BEGIN READ(EROOM, I);  WRITE(EMAP, I);  ILOOP := ILOOP + 1; END (*WHILE*);
     GETSEG(EROOM);  PUTSEG(EMAP);  ROLLCHECK(TERM);  RMSEGLOC[RLOOP] := RLOOP + 1;
    END (*FOR*);
   EOFSEG := NUMSEGS + 1;  CURRENTSEG := 0;  RESET(EDESC);  GETSEG(EDESC, 10000);
   ROLLCHECK(TERM);  REWRITE(EDESC, - 1);  ROLLCHECK(TERM);
   WRITELN(EDESC, TASKCLOSED, NUMRUN + 1, TODAY, MSPEED);  ILOOP := 1;
   WHILE (ILOOP < 80) AND (NOTICE[ILOOP] <> COL) DO
    BEGIN WRITE(EDESC, NOTICE[ILOOP]);  ILOOP := ILOOP + 1 END;
   WRITELN(EDESC);
   FOR ILOOP := 1 TO 5 DO
    BEGIN
     JLOOP := 1;
     WHILE (JLOOP < 80) AND (NEWSBUF[ILOOP, JLOOP] <> COL) DO
      BEGIN WRITE(EDESC, NEWSBUF[ILOOP, JLOOP]);  JLOOP := JLOOP + 1 END;
     WRITELN(EDESC)
    END (*FOR*);
   FOR ILOOP := 1 TO 3 DO
    BEGIN
     WRITELN(EDESC, TLVL[ILOOP], YLVL[ILOOP]);
     WRITELN(EDESC, TNAME[ILOOP], ' ', YNAME[ILOOP], ' ', TCLASS[ILOOP], ' ', YCLASS[
       ILOOP]);
     JLOOP := 1;
     WHILE TBUF[ILOOP, JLOOP] <> COL DO
      BEGIN WRITE(EDESC, TBUF[ILOOP, JLOOP]);  JLOOP := JLOOP + 1 END;
     WRITELN(EDESC);  JLOOP := 1;
     WHILE YBUF[ILOOP, JLOOP] <> COL DO
      BEGIN WRITE(EDESC, YBUF[ILOOP, JLOOP]);  JLOOP := JLOOP + 1 END;
     WRITELN(EDESC);
    END (*FOR*);
   PUTSEG(EDESC);  CURRENTREC := 0 (* POSITION OF EDESC IS UNPREDICTABLE NOW *);
   MESSAGE(' FILES UPDATED.');  ROLLCHECK(TERM);  ERRFLAG := 1 (* RESTART REPLACE *);
  END (*UPDATE*);




 BEGIN (*MULTIO*)
  INITIALIZE (* FETCH ALL FILES, READ IN CONSTANTS, ETC. *);
  WRITELN(DAYFILE, CLOCKTIME, '  DAY ', TODAY: 0, ', TASK INITIALIZED.');
  USER := LOGIN(PARM, TERM, BUFFER, NUSERS, USERTAIL);
(* LOG IN THE FIRST USER.  *FIRSTLOGIN* IS TRUE SO NO INPUT IS
ACTUALLY READ BY *LOGIN* *)
  IF USER <> NIL  THEN PROMPTUSER(USER);  FIRSTLOGIN := FALSE;
  REPEAT
   ERRLOC := 'MULTIO    ';
   WHILE EOS(INPUT) DO
    BEGIN
     FLUSH(OUTPUT);  GETSEG(INPUT);  RA := 1;  RTIME(REALTIME);  TIME(CLOCKTIME);
     IF NOT EOS(INPUT)  THEN   MONSTERATTACK
    END (*WHILE*);
   NOPROMPT := FALSE;  READCONTROL(CONTROL, PARM, TERM, BUFFER, LENBUF, LOGLEN);
   WHICHCONTROL := ORD(CONTROL[1]);
   IF WHICHCONTROL <> 40B  THEN WHICHCONTROL := ORD(CONTROL[2]);  ACTIVEFLAG := 0;
   IF WHICHCONTROL <> MTLI (*LOGIN*)
   THEN
    BEGIN
     ACTIVEFLAG := ACTIVETRM(TERM);
     IF ACTIVEFLAG = 0
     THEN
      BEGIN
       FINDLIMBO(TERM, LIMBOINDEX, FALSE);
       IF LIMBOINDEX = 0 THEN
        BEGIN USER := FINDTERM(TERM, USERTAIL);  USER ^.LASTINPUT := REALTIME END
      END (*IF*)
     ELSE MESSAGE(' UNDEF TERM IGNORED.');
    END (*IF*);
   IF ACTIVEFLAG = 0
   THEN
    CASE WHICHCONTROL OF
     40B (*MTXT*): DOINPUT(BUFFER, LENBUF, USER);
     MTAN: IF TERM <> NORESTART  THEN IF LIMBOINDEX = 0  THEN PROMPTUSER(USER);
     MTNT: (*INTERRUPT*)
      BEGIN
       WRITECONTROL(MTAK, ZEROPARM, TERM);  WRITELN (*INTERRUPT ACKNOWLEDGE*);
       IF LIMBOINDEX <> 0
       THEN
        BEGIN
         WRITELN(TERM, 'END MILIEU.');  WRITECONTROL(MTLO, ZEROPARM, TERM);  WRITELN;
         DELETELIMBO(TERM)
        END (*IF*)
       ELSE BEGIN USER ^.AUTO := FALSE;  PROMPTUSER(USER) END
      END (*MTNT*);
     MTHU: (*HANGUP*)
      IF LIMBOINDEX <> 0  THEN DELETELIMBO(TERM)
      ELSE LOGOFF(USER, TRUE) (* NO MTLO WRITE NEEDED *);
     MTLI: (*LOGIN*)
      BEGIN
       USER := LOGIN(PARM, TERM, BUFFER, NUSERS, USERTAIL);
       IF USER <> NIL  THEN PROMPTUSER(USER);
      END (*MTLI*);
     MTRC: (* IAF ABORT *)
      BEGIN
       MESSAGE(' MIL303 - IAF ABORTED.');  HELLFREEZESOVER := TRUE (* AMAZING!! *)
      END (*MTRC*);
    END (*CASE*);
  UNTIL HELLFREEZESOVER
 END (*MULTIO*);


FUNCTION GETEPT: INTEGER;
(* GETEPT RETURNS THE 5000 LOADER TABLE HEADER FOR GENERATING
THE RUNTIME OVL *)
 EXTERN;


FUNCTION PEEK(ADDR: INTEGER): INTEGER;
(* PEEK RETURNS THE VALUE OF DATA AT ADDRESS *ADDR* *)
 EXTERN;


PROCEDURE SAVEB;
(* SAVEB SAVES THE STACK POINTERS (B4,B5,B6) BEFORE THE
PROGRAM FREEZES *)
 EXTERN;


PROCEDURE FREEZE;
(* FREEZE STOPS THE PROGRAM AFTER THE OVL IS GENERATED.  THE
RUN IS RESUMED AT THE RESTART LABEL. *)
 EXTERN;


PROCEDURE COPYABS(TASKNAME, UN: ALFA7);
(* COPYABS WILL COPY THE LOAD FILE TO A RUNTIME SEGMENT LIBRARY.
THE FIRST RECORD (OVL) IS SKIPPED. *)
 EXTERN;


BEGIN (*MILIEU*)
 TASKNAM := 'MILIEU ';  TASKNAM[7] := COL;
(* THE FIRST THING WE DO IS SAVE THE PROGRAM TO A FILE.  THIS FILE
IS WHAT IS ACTUALLY RUN ON MULTI. *)
 OPENBOOT(BOOTSEG, 'BOOTSEG   ', TRUE);  WRITELN('SNAPSHOT DUMP BEING CONSTRUCTED.');
 REWRITE(BOOTSEG);  WRITE(BOOTSEG, 77000016000000000000B);
 WRITE(BOOTSEG, 23030520240522000000B);  WRITE(BOOTSEG, 43355033375036345555B);
 WRITE(BOOTSEG, GETEPT);  FLUSH(OUTPUT);  SAVEB (* SAVE STACK *);
 FOR ILOOP := 101B TO BOOTLEN DO WRITE(BOOTSEG, PEEK(ILOOP));  PUTSEG(BOOTSEG);
 CLOSEBOOT(BOOTSEG);  FREEZE (* HALT PROGRAM *);  1: FLUSH(OUTPUT);
(* COPY 2ND SEGMENT AND ONWARD OF MILIEU TO ABS *)
 COPYABS(TASKNAM, ORIGINUN);  MESSAGE(' PASCAL/MULTI-6000.3.2 RUNTIME SYSTEM.');
 MULTIO (* DO MILIEU! *)
END (*MILIEU*).