386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 28 Feb 1991 21:32:11 +0000 (13:32 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 28 Feb 1991 21:32:11 +0000 (13:32 -0800)
Work on file usr/othersrc/games/larn/create.c
Work on file usr/othersrc/games/larn/main.c
Work on file usr/othersrc/games/larn/fortune.c
Work on file usr/othersrc/games/larn/monster.c
Work on file usr/othersrc/games/larn/display.c
Work on file usr/othersrc/games/larn/signal.c
Work on file usr/othersrc/games/larn/moreobj.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/games/larn/create.c [new file with mode: 0644]
usr/othersrc/games/larn/display.c [new file with mode: 0644]
usr/othersrc/games/larn/fortune.c [new file with mode: 0644]
usr/othersrc/games/larn/main.c [new file with mode: 0644]
usr/othersrc/games/larn/monster.c [new file with mode: 0644]
usr/othersrc/games/larn/moreobj.c [new file with mode: 0644]
usr/othersrc/games/larn/signal.c [new file with mode: 0644]

diff --git a/usr/othersrc/games/larn/create.c b/usr/othersrc/games/larn/create.c
new file mode 100644 (file)
index 0000000..46c09c9
--- /dev/null
@@ -0,0 +1,463 @@
+/*     create.c                Larn is copyrighted 1986 by Noah Morgan. */
+#include "header.h"
+extern char spelknow[],larnlevels[];
+extern char beenhere[],wizard,level;
+extern short oldx,oldy;
+/*
+       makeplayer()
+
+       subroutine to create the player and the players attributes
+       this is called at the beginning of a game and at no other time
+ */
+makeplayer()
+       {
+       register int i;
+       scbr();  clear();
+       c[HPMAX]=c[HP]=10;              /*      start player off with 15 hit points     */
+       c[LEVEL]=1;                             /*      player starts at level one                      */
+       c[SPELLMAX]=c[SPELLS]=1;        /*      total # spells starts off as 3  */
+       c[REGENCOUNTER]=16;             c[ECOUNTER]=96; /*start regeneration correctly*/
+       c[SHIELD] = c[WEAR] = c[WIELD] = -1;
+       for (i=0; i<26; i++)  iven[i]=0;
+       spelknow[0]=spelknow[1]=1; /*he knows protection, magic missile*/
+       if (c[HARDGAME]<=0)
+               {
+               iven[0]=OLEATHER; iven[1]=ODAGGER;
+               ivenarg[1]=ivenarg[0]=c[WEAR]=0;  c[WIELD]=1;
+               }
+       playerx=rnd(MAXX-2);    playery=rnd(MAXY-2);
+       oldx=0;                 oldy=25;
+       gtime=0;                        /*      time clock starts at zero       */
+       cbak[SPELLS] = -50;
+       for (i=0; i<6; i++)  c[i]=12; /* make the attributes, ie str, int, etc. */
+       recalc();
+       }
+\f
+/*
+       newcavelevel(level)
+       int level;
+
+       function to enter a new level.  This routine must be called anytime the
+       player changes levels.  If that level is unknown it will be created.
+       A new set of monsters will be created for a new level, and existing
+       levels will get a few more monsters.
+       Note that it is here we remove genocided monsters from the present level.
+ */
+newcavelevel(x)
+       register int x;
+       {
+       register int i,j;
+       if (beenhere[level]) savelevel();       /* put the level back into storage      */
+       level = x;                              /* get the new level and put in working storage */
+       if (beenhere[x]==0) for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) know[j][i]=mitem[j][i]=0;
+               else { getlevel(); sethp(0);  goto chgn; }
+       makemaze(x);    makeobject(x);  beenhere[x]=1;  sethp(1);
+
+#if WIZID
+       if (wizard || x==0)
+#else
+       if (x==0)
+#endif
+
+               for (j=0; j<MAXY; j++)
+                       for (i=0; i<MAXX; i++)
+                               know[i][j]=1;
+chgn: checkgen();      /* wipe out any genocided monsters */
+       }
+
+/*
+       makemaze(level)
+       int level;
+
+       subroutine to make the caverns for a given level.  only walls are made.
+ */
+static int mx,mxl,mxh,my,myl,myh,tmp2;
+ makemaze(k)
+       int k;
+       {
+       register int i,j,tmp;
+       int z;
+       if (k > 1 && (rnd(17)<=4 || k==MAXLEVEL-1 || k==MAXLEVEL+MAXVLEVEL-1))
+               {
+               if (cannedlevel(k));    return;         /* read maze from data file */
+               }
+       if (k==0)  tmp=0;  else tmp=OWALL;
+       for (i=0; i<MAXY; i++)  for (j=0; j<MAXX; j++)  item[j][i]=tmp;
+       if (k==0) return;               eat(1,1);
+       if (k==1) item[33][MAXY-1]=0;   /* exit from dungeon */
+
+/*     now for open spaces -- not on level 10  */
+       if (k != MAXLEVEL-1)
+               {
+               tmp2 = rnd(3)+3;
+               for (tmp=0; tmp<tmp2; tmp++)
+                       {
+                       my = rnd(11)+2;   myl = my - rnd(2);  myh = my + rnd(2);
+                       if (k < MAXLEVEL)
+                               {
+                               mx = rnd(44)+5;  mxl = mx - rnd(4);  mxh = mx + rnd(12)+3;
+                               z=0;
+                               }
+                       else
+                               {
+                               mx = rnd(60)+3;  mxl = mx - rnd(2);  mxh = mx + rnd(2);
+                               z = makemonst(k);
+                               }
+                       for (i=mxl; i<mxh; i++)         for (j=myl; j<myh; j++)
+                               {  item[i][j]=0;
+                                  if ((mitem[i][j]=z)) hitp[i][j]=monster[z].hitpoints;
+                               }
+                       }
+               }
+       if (k!=MAXLEVEL-1) { my=rnd(MAXY-2);  for (i=1; i<MAXX-1; i++)  item[i][my] = 0; }
+       if (k>1)  treasureroom(k);
+       }
+
+/*
+       function to eat away a filled in maze
+ */
+eat(xx,yy)
+       register int xx,yy;
+       {
+       register int dir,try;
+       dir = rnd(4);   try=2;
+       while (try)
+               {
+               switch(dir)
+                       {
+                       case 1: if (xx <= 2) break;             /*      west    */
+                                       if ((item[xx-1][yy]!=OWALL) || (item[xx-2][yy]!=OWALL)) break;
+                                       item[xx-1][yy] = item[xx-2][yy] = 0;
+                                       eat(xx-2,yy);   break;
+
+                       case 2: if (xx >= MAXX-3) break;        /*      east    */
+                                       if ((item[xx+1][yy]!=OWALL) || (item[xx+2][yy]!=OWALL)) break;
+                                       item[xx+1][yy] = item[xx+2][yy] = 0;
+                                       eat(xx+2,yy);   break;
+
+                       case 3: if (yy <= 2) break;             /*      south   */
+                                       if ((item[xx][yy-1]!=OWALL) || (item[xx][yy-2]!=OWALL)) break;
+                                       item[xx][yy-1] = item[xx][yy-2] = 0;
+                                       eat(xx,yy-2);   break;
+
+                       case 4: if (yy >= MAXY-3 ) break;       /*      north   */
+                                       if ((item[xx][yy+1]!=OWALL) || (item[xx][yy+2]!=OWALL)) break;
+                                       item[xx][yy+1] = item[xx][yy+2] = 0;
+                                       eat(xx,yy+2);   break;
+                       };
+               if (++dir > 4)  { dir=1;  --try; }
+               }
+       }
+
+/*
+ *     function to read in a maze from a data file
+ *
+ *     Format of maze data file:  1st character = # of mazes in file (ascii digit)
+ *                             For each maze: 18 lines (1st 17 used) 67 characters per line
+ *
+ *     Special characters in maze data file:
+ *
+ *             #       wall                    D       door                    .       random monster
+ *             ~       eye of larn             !       cure dianthroritis
+ *             -       random object
+ */
+cannedlevel(k)
+       int k;
+       {
+       char *row,*lgetl();
+       register int i,j;
+       int it,arg,mit,marg;
+       if (lopen(larnlevels)<0)
+               {
+               write(1,"Can't open the maze data file\n",30);   died(-282); return(0);
+               }
+       i=lgetc();  if (i<='0') { died(-282); return(0); }
+       for (i=18*rund(i-'0'); i>0; i--)        lgetl();   /* advance to desired maze */
+       for (i=0; i<MAXY; i++)
+               {
+               row = lgetl();
+               for (j=0; j<MAXX; j++)
+                       {
+                       it = mit = arg = marg = 0;
+                       switch(*row++)
+                               {
+                               case '#': it = OWALL;                                                           break;
+                               case 'D': it = OCLOSEDDOOR;     arg = rnd(30);          break;
+                               case '~': if (k!=MAXLEVEL-1) break;
+                                                 it = OLARNEYE;
+                                                 mit = rund(8)+DEMONLORD;
+                                                 marg = monster[mit].hitpoints;                        break;
+                               case '!': if (k!=MAXLEVEL+MAXVLEVEL-1)  break;
+                                                 it = OPOTION;                 arg = 21;
+                                                 mit = DEMONLORD+7;
+                                                 marg = monster[mit].hitpoints;                        break;
+                               case '.': if (k<MAXLEVEL)  break;
+                                                 mit = makemonst(k+1);
+                                                 marg = monster[mit].hitpoints;                        break;
+                               case '-': it = newobject(k+1,&arg);                                     break;
+                               };
+                       item[j][i] = it;                iarg[j][i] = arg;
+                       mitem[j][i] = mit;              hitp[j][i] = marg;
+
+#if WIZID
+                       know[j][i] = (wizard) ? 1 : 0;
+#else
+                       know[j][i] = 0;
+#endif
+                       }
+               }
+       lrclose();
+       return(1);
+       }
+
+/*
+       function to make a treasure room on a level
+       level 10's treasure room has the eye in it and demon lords
+       level V3 has potion of cure dianthroritis and demon prince
+ */
+treasureroom(lv)
+       register int lv;
+       {
+       register int tx,ty,xsize,ysize;
+
+       for (tx=1+rnd(10);  tx<MAXX-10;  tx+=10)
+         if ( (lv==MAXLEVEL-1) || (lv==MAXLEVEL+MAXVLEVEL-1) || rnd(13)==2)
+               {
+               xsize = rnd(6)+3;           ysize = rnd(3)+3;  
+               ty = rnd(MAXY-9)+1;  /* upper left corner of room */
+               if (lv==MAXLEVEL-1 || lv==MAXLEVEL+MAXVLEVEL-1)
+                       troom(lv,xsize,ysize,tx=tx+rnd(MAXX-24),ty,rnd(3)+6);
+                       else troom(lv,xsize,ysize,tx,ty,rnd(9));
+               }
+       }
+
+/*
+ *     subroutine to create a treasure room of any size at a given location 
+ *     room is filled with objects and monsters 
+ *     the coordinate given is that of the upper left corner of the room
+ */
+troom(lv,xsize,ysize,tx,ty,glyph)
+       int lv,xsize,ysize,tx,ty,glyph;
+       {
+       register int i,j;
+       int tp1,tp2;
+       for (j=ty-1; j<=ty+ysize; j++)
+               for (i=tx-1; i<=tx+xsize; i++)                  /* clear out space for room */
+                       item[i][j]=0;
+       for (j=ty; j<ty+ysize; j++)
+               for (i=tx; i<tx+xsize; i++)                             /* now put in the walls */
+                       {
+                       item[i][j]=OWALL; mitem[i][j]=0; 
+                       }
+       for (j=ty+1; j<ty+ysize-1; j++)
+               for (i=tx+1; i<tx+xsize-1; i++)                 /* now clear out interior */
+                       item[i][j]=0;
+
+       switch(rnd(2))          /* locate the door on the treasure room */
+               {
+               case 1: item[i=tx+rund(xsize)][j=ty+(ysize-1)*rund(2)]=OCLOSEDDOOR;
+                               iarg[i][j] = glyph;             /* on horizontal walls */
+                               break;
+               case 2: item[i=tx+(xsize-1)*rund(2)][j=ty+rund(ysize)]=OCLOSEDDOOR;
+                               iarg[i][j] = glyph;             /* on vertical walls */
+                               break;
+               };
+
+       tp1=playerx;  tp2=playery;  playery=ty+(ysize>>1);
+       if (c[HARDGAME]<2)
+               for (playerx=tx+1; playerx<=tx+xsize-2; playerx+=2)
+                       for (i=0, j=rnd(6); i<=j; i++)
+                               { something(lv+2); createmonster(makemonst(lv+1)); }
+       else
+               for (playerx=tx+1; playerx<=tx+xsize-2; playerx+=2)
+                       for (i=0, j=rnd(4); i<=j; i++)
+                               { something(lv+2); createmonster(makemonst(lv+3)); }
+
+       playerx=tp1;  playery=tp2;
+       }
+\f
+static void fillroom();
+
+/*
+       ***********
+       MAKE_OBJECT
+       ***********
+       subroutine to create the objects in the maze for the given level
+ */
+makeobject(j)
+       register int j;
+       {
+       register int i;
+       if (j==0)
+               {
+               fillroom(OENTRANCE,0);          /*      entrance to dungeon                     */
+               fillroom(ODNDSTORE,0);          /*      the DND STORE                           */
+               fillroom(OSCHOOL,0);            /*      college of Larn                         */
+               fillroom(OBANK,0);                      /*      1st national bank of larn       */
+               fillroom(OVOLDOWN,0);           /*      volcano shaft to temple         */
+               fillroom(OHOME,0);                      /*      the players home & family       */
+               fillroom(OTRADEPOST,0);         /*  the trading post                    */
+               fillroom(OLRS,0);                       /*  the larn revenue service    */
+               return;
+               }
+
+       if (j==MAXLEVEL) fillroom(OVOLUP,0); /* volcano shaft up from the temple */
+
+/*     make the fixed objects in the maze STAIRS       */
+       if ((j>0) && (j != MAXLEVEL-1) && (j != MAXLEVEL+MAXVLEVEL-1))
+               fillroom(OSTAIRSDOWN,0);
+       if ((j > 1) && (j != MAXLEVEL))                 fillroom(OSTAIRSUP,0);
+
+/*     make the random objects in the maze             */
+
+       fillmroom(rund(3),OBOOK,j);                             fillmroom(rund(3),OALTAR,0);
+       fillmroom(rund(3),OSTATUE,0);                   fillmroom(rund(3),OPIT,0);
+       fillmroom(rund(3),OFOUNTAIN,0);                 fillmroom( rnd(3)-2,OIVTELETRAP,0);
+       fillmroom(rund(2),OTHRONE,0);                   fillmroom(rund(2),OMIRROR,0);
+       fillmroom(rund(2),OTRAPARROWIV,0);              fillmroom( rnd(3)-2,OIVDARTRAP,0);
+       fillmroom(rund(3),OCOOKIE,0);
+       if (j==1) fillmroom(1,OCHEST,j);
+               else fillmroom(rund(2),OCHEST,j);
+       if ((j != MAXLEVEL-1) && (j != MAXLEVEL+MAXVLEVEL-1))
+               fillmroom(rund(2),OIVTRAPDOOR,0);
+       if (j<=10)
+               {
+               fillmroom((rund(2)),ODIAMOND,rnd(10*j+1)+10);
+               fillmroom(rund(2),ORUBY,rnd(6*j+1)+6);
+               fillmroom(rund(2),OEMERALD,rnd(4*j+1)+4);
+               fillmroom(rund(2),OSAPPHIRE,rnd(3*j+1)+2);
+               }
+       for (i=0; i<rnd(4)+3; i++)
+               fillroom(OPOTION,newpotion());  /*      make a POTION   */
+       for (i=0; i<rnd(5)+3; i++)
+               fillroom(OSCROLL,newscroll());  /*      make a SCROLL   */
+       for (i=0; i<rnd(12)+11; i++)
+               fillroom(OGOLDPILE,12*rnd(j+1)+(j<<3)+10); /* make GOLD */
+       if (j==5)       fillroom(OBANK2,0);                             /*      branch office of the bank */
+       froom(2,ORING,0);                               /* a ring mail                  */
+       froom(1,OSTUDLEATHER,0);                /* a studded leather    */
+       froom(3,OSPLINT,0);                             /* a splint mail                */
+       froom(5,OSHIELD,rund(3));               /* a shield                             */
+       froom(2,OBATTLEAXE,rund(3));    /* a battle axe                 */
+       froom(5,OLONGSWORD,rund(3));    /* a long sword                 */
+       froom(5,OFLAIL,rund(3));                /* a flail                              */
+       froom(4,OREGENRING,rund(3));    /* ring of regeneration */
+       froom(1,OPROTRING,rund(3));     /* ring of protection   */
+       froom(2,OSTRRING,4);            /* ring of strength + 4 */
+       froom(7,OSPEAR,rnd(5));         /* a spear                              */
+       froom(3,OORBOFDRAGON,0);        /* orb of dragon slaying*/
+       froom(4,OSPIRITSCARAB,0);               /*scarab of negate spirit*/
+       froom(4,OCUBEofUNDEAD,0);               /* cube of undead control       */
+       froom(2,ORINGOFEXTRA,0);        /* ring of extra regen          */
+       froom(3,ONOTHEFT,0);                    /* device of antitheft          */
+       froom(2,OSWORDofSLASHING,0); /* sword of slashing */
+       if (c[BESSMANN]==0)
+               {
+               froom(4,OHAMMER,0);/*Bessman's flailing hammer*/ c[BESSMANN]=1;
+               }
+       if (c[HARDGAME]<3 || (rnd(4)==3))
+               {
+               if (j>3)
+                       {
+                       froom(3,OSWORD,3);              /* sunsword + 3                 */
+                       froom(5,O2SWORD,rnd(4));  /* a two handed sword */
+                       froom(3,OBELT,4);                       /* belt of striking             */
+                       froom(3,OENERGYRING,3); /* energy ring                  */
+                       froom(4,OPLATE,5);              /* platemail + 5                */
+                       }
+               }
+       }
+
+/*
+       subroutine to fill in a number of objects of the same kind
+ */
+
+fillmroom(n,what,arg)
+       int n,arg;
+       char what;
+       {
+       register int i;
+       for (i=0; i<n; i++)             fillroom(what,arg);
+       }
+froom(n,itm,arg)
+       int n,arg;
+       char itm;
+       {       if (rnd(151) < n) fillroom(itm,arg);    }
+
+/*
+       subroutine to put an object into an empty room
+ *     uses a random walk
+ */
+static void
+fillroom(what,arg)
+       int arg;
+       char what;
+       {
+       register int x,y;
+
+#ifdef EXTRA
+       c[FILLROOM]++;
+#endif
+
+       x=rnd(MAXX-2);  y=rnd(MAXY-2);
+       while (item[x][y])
+               {
+
+#ifdef EXTRA
+               c[RANDOMWALK]++;        /* count up these random walks */
+#endif
+
+               x += rnd(3)-2;          y += rnd(3)-2;
+               if (x > MAXX-2)  x=1;           if (x < 1)  x=MAXX-2;
+               if (y > MAXY-2)  y=1;           if (y < 1)  y=MAXY-2;
+               }
+       item[x][y]=what;                iarg[x][y]=arg;
+       }
+
+/*
+       subroutine to put monsters into an empty room without walls or other
+       monsters
+ */
+fillmonst(what)
+       char what;
+       {
+       register int x,y,trys;
+       for (trys=5; trys>0; --trys) /* max # of creation attempts */
+         {
+         x=rnd(MAXX-2);  y=rnd(MAXY-2);
+         if ((item[x][y]==0) && (mitem[x][y]==0) && ((playerx!=x) || (playery!=y)))
+               {
+               mitem[x][y] = what;  know[x][y]=0;
+               hitp[x][y] = monster[what].hitpoints;  return(0);
+               }
+         }
+       return(-1); /* creation failure */
+       }
+
+/*
+       creates an entire set of monsters for a level
+       must be done when entering a new level
+       if sethp(1) then wipe out old monsters else leave them there
+ */
+sethp(flg)
+       int flg;
+       {
+       register int i,j;
+       if (flg) for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) stealth[j][i]=0;
+       if (level==0) { c[TELEFLAG]=0; return; } /*     if teleported and found level 1 then know level we are on */
+       if (flg)   j = rnd(12) + 2 + (level>>1);   else   j = (level>>1) + 1;
+       for (i=0; i<j; i++)  fillmonst(makemonst(level));
+       positionplayer();
+       }
+
+/*
+ *     Function to destroy all genocided monsters on the present level
+ */
+checkgen()
+       {
+       register int x,y;
+       for (y=0; y<MAXY; y++)
+               for (x=0; x<MAXX; x++)
+                       if (monster[mitem[x][y]].genocided)
+                               mitem[x][y]=0; /* no more monster */
+       }
diff --git a/usr/othersrc/games/larn/display.c b/usr/othersrc/games/larn/display.c
new file mode 100644 (file)
index 0000000..b49de50
--- /dev/null
@@ -0,0 +1,434 @@
+/*     display.c               Larn is copyrighted 1986 by Noah Morgan. */
+#include "header.h"
+#define makecode(_a,_b,_c) (((_a)<<16) + ((_b)<<8) + (_c))
+
+static int minx,maxx,miny,maxy,k,m;
+static char bot1f=0,bot2f=0,bot3f=0;
+char always=0;
+/*
+       bottomline()
+
+       now for the bottom line of the display
+ */
+bottomline()
+       {       recalc();       bot1f=1;        }
+bottomhp()
+       {       bot2f=1;        }
+bottomspell()
+       {       bot3f=1;        }
+bottomdo()
+       {
+       if (bot1f) { bot3f=bot1f=bot2f=0; bot_linex(); return; }
+       if (bot2f) { bot2f=0; bot_hpx(); }
+       if (bot3f) { bot3f=0; bot_spellx(); }
+       }
+
+static void botsub();
+
+bot_linex()
+       {
+       register int i;
+       if (cbak[SPELLS] <= -50 || (always))
+               {
+               cursor( 1,18);
+               if (c[SPELLMAX]>99)  lprintf("Spells:%3d(%3d)",(long)c[SPELLS],(long)c[SPELLMAX]);
+                                               else lprintf("Spells:%3d(%2d) ",(long)c[SPELLS],(long)c[SPELLMAX]);
+               lprintf(" AC: %-3d  WC: %-3d  Level",(long)c[AC],(long)c[WCLASS]);
+               if (c[LEVEL]>99) lprintf("%3d",(long)c[LEVEL]);
+                                       else lprintf(" %-2d",(long)c[LEVEL]);
+               lprintf(" Exp: %-9d %s\n",(long)c[EXPERIENCE],class[c[LEVEL]-1]);
+               lprintf("HP: %3d(%3d) STR=%-2d INT=%-2d ",
+                       (long)c[HP],(long)c[HPMAX],(long)(c[STRENGTH]+c[STREXTRA]),(long)c[INTELLIGENCE]);
+               lprintf("WIS=%-2d CON=%-2d DEX=%-2d CHA=%-2d LV:",
+                       (long)c[WISDOM],(long)c[CONSTITUTION],(long)c[DEXTERITY],(long)c[CHARISMA]);
+
+               if ((level==0) || (wizard))  c[TELEFLAG]=0;
+               if (c[TELEFLAG])  lprcat(" ?");  else  lprcat(levelname[level]);
+               lprintf("  Gold: %-6d",(long)c[GOLD]);
+               always=1;  botside();
+               c[TMP] = c[STRENGTH]+c[STREXTRA];
+               for (i=0; i<100; i++) cbak[i]=c[i];
+               return;
+               }
+
+       botsub(makecode(SPELLS,8,18),"%3d");
+       if (c[SPELLMAX]>99)  botsub(makecode(SPELLMAX,12,18),"%3d)");
+                                       else botsub(makecode(SPELLMAX,12,18),"%2d) ");
+       botsub(makecode(HP,5,19),"%3d");
+       botsub(makecode(HPMAX,9,19),"%3d");
+       botsub(makecode(AC,21,18),"%-3d");
+       botsub(makecode(WCLASS,30,18),"%-3d");
+       botsub(makecode(EXPERIENCE,49,18),"%-9d");
+       if (c[LEVEL] != cbak[LEVEL])
+               { cursor(59,18);        lprcat(class[c[LEVEL]-1]);  }
+       if (c[LEVEL]>99) botsub(makecode(LEVEL,40,18),"%3d");
+                               else botsub(makecode(LEVEL,40,18)," %-2d");
+       c[TMP] = c[STRENGTH]+c[STREXTRA];       botsub(makecode(TMP,18,19),"%-2d");
+       botsub(makecode(INTELLIGENCE,25,19),"%-2d");
+       botsub(makecode(WISDOM,32,19),"%-2d");
+       botsub(makecode(CONSTITUTION,39,19),"%-2d");
+       botsub(makecode(DEXTERITY,46,19),"%-2d");
+       botsub(makecode(CHARISMA,53,19),"%-2d");
+       if ((level != cbak[CAVELEVEL]) || (c[TELEFLAG] != cbak[TELEFLAG]))
+               {
+               if ((level==0) || (wizard))  c[TELEFLAG]=0;
+               cbak[TELEFLAG] = c[TELEFLAG];
+               cbak[CAVELEVEL] = level;        cursor(59,19);
+               if (c[TELEFLAG])  lprcat(" ?");  else  lprcat(levelname[level]);
+               }
+       botsub(makecode(GOLD,69,19),"%-6d");
+       botside();
+       }
+
+/*
+       special subroutine to update only the gold number on the bottomlines
+       called from ogold()
+ */
+bottomgold()
+       {
+       botsub(makecode(GOLD,69,19),"%-6d");
+/*     botsub(GOLD,"%-6d",69,19); */
+       }
+
+/*
+       special routine to update hp and level fields on bottom lines
+       called in monster.c hitplayer() and spattack()
+ */
+bot_hpx()
+       {
+       if (c[EXPERIENCE] != cbak[EXPERIENCE])
+               {
+               recalc();        bot_linex();
+               }
+       else botsub(makecode(HP,5,19),"%3d");   
+       }
+
+/*
+       special routine to update number of spells called from regen()
+ */
+bot_spellx()
+       {
+       botsub(makecode(SPELLS,9,18),"%2d");
+       }
+
+/*
+       common subroutine for a more economical bottomline()
+ */
+static struct bot_side_def
+       {
+       int typ;
+       char *string;
+       }
+       bot_data[] =
+       {
+       STEALTH,"stealth",              UNDEADPRO,"undead pro",         SPIRITPRO,"spirit pro",
+       CHARMCOUNT,"Charm",             TIMESTOP,"Time Stop",           HOLDMONST,"Hold Monst",
+       GIANTSTR,"Giant Str",   FIRERESISTANCE,"Fire Resit", DEXCOUNT,"Dexterity",
+       STRCOUNT,"Strength",    SCAREMONST,"Scare",                     HASTESELF,"Haste Self",
+       CANCELLATION,"Cancel",  INVISIBILITY,"Invisible",       ALTPRO,"Protect 3",
+       PROTECTIONTIME,"Protect 2", WTW,"Wall-Walk"
+       };
+
+botside()
+       {
+       register int i,idx;
+       for (i=0; i<17; i++)
+               {
+               idx = bot_data[i].typ;
+               if ((always) || (c[idx] != cbak[idx]))
+                  {
+                  if ((always) || (cbak[idx] == 0))
+                               { if (c[idx]) { cursor(70,i+1); lprcat(bot_data[i].string); } }  else
+                  if (c[idx]==0)     { cursor(70,i+1); lprcat("          "); }
+                  cbak[idx]=c[idx];
+                  }
+               }
+       always=0;
+       }
+
+static void
+botsub(idx,str)
+       register int idx;
+       char *str;
+       {
+       register int x,y;
+       y = idx & 0xff;         x = (idx>>8) & 0xff;      idx >>= 16;
+       if (c[idx] != cbak[idx])
+               { cbak[idx]=c[idx];  cursor(x,y);  lprintf(str,(long)c[idx]); }
+       }
+
+/*
+ *     subroutine to draw only a section of the screen
+ *     only the top section of the screen is updated.  If entire lines are being
+ *     drawn, then they will be cleared first.
+ */
+int d_xmin=0,d_xmax=MAXX,d_ymin=0,d_ymax=MAXY; /* for limited screen drawing */
+draws(xmin,xmax,ymin,ymax)
+       int xmin,xmax,ymin,ymax;
+       {
+       register int i,idx;
+       if (xmin==0 && xmax==MAXX) /* clear section of screen as needed */
+               {
+               if (ymin==0) cl_up(79,ymax);
+               else for (i=ymin; i<ymin; i++)  cl_line(1,i+1);
+               xmin = -1;
+               }
+       d_xmin=xmin;    d_xmax=xmax;    d_ymin=ymin;    d_ymax=ymax;    /* for limited screen drawing */
+       drawscreen();
+       if (xmin<=0 && xmax==MAXX) /* draw stuff on right side of screen as needed*/
+               {
+               for (i=ymin; i<ymax; i++)
+                       {
+                       idx = bot_data[i].typ;
+                       if (c[idx])
+                               {
+                               cursor(70,i+1); lprcat(bot_data[i].string);
+                               }
+                       cbak[idx]=c[idx];
+                       }
+               }
+       }
+
+/*
+       drawscreen()
+
+       subroutine to redraw the whole screen as the player knows it
+ */
+char screen[MAXX][MAXY],d_flag;        /* template for the screen */
+drawscreen()
+       {
+       register int i,j,k;
+       int lastx,lasty;  /* variables used to optimize the object printing */
+       if (d_xmin==0 && d_xmax==MAXX && d_ymin==0 && d_ymax==MAXY)
+               {
+               d_flag=1;  clear(); /* clear the screen */
+               }
+       else 
+               {
+               d_flag=0;  cursor(1,1);
+               }
+       if (d_xmin<0)
+               d_xmin=0; /* d_xmin=-1 means display all without bottomline */
+
+       for (i=d_ymin; i<d_ymax; i++)
+         for (j=d_xmin; j<d_xmax; j++)
+               if (know[j][i]==0)  screen[j][i] = ' ';  else
+               if (k=mitem[j][i])  screen[j][i] = monstnamelist[k];  else
+               if ((k=item[j][i])==OWALL) screen[j][i] = '#';
+               else screen[j][i] = ' ';
+
+       for (i=d_ymin; i<d_ymax; i++)
+               {
+               j=d_xmin;  while ((screen[j][i]==' ') && (j<d_xmax)) j++;
+               /* was m=0 */
+               if (j >= d_xmax)  m=d_xmin; /* don't search backwards if blank line */
+               else
+                       {       /* search backwards for end of line */
+                       m=d_xmax-1;  while ((screen[m][i]==' ') && (m>d_xmin)) --m;
+                       if (j<=m)  cursor(j+1,i+1);  else continue;
+                       }
+               while (j <= m)
+                       {
+                       if (j <= m-3) 
+                               {
+                               for (k=j; k<=j+3; k++) if (screen[k][i] != ' ') k=1000;
+                               if (k < 1000)
+                                       { while(screen[j][i]==' ' && j<=m) j++;  cursor(j+1,i+1); }
+                               }
+                       lprc(screen[j++][i]);
+                       }
+               }
+       setbold();              /* print out only bold objects now */
+
+       for (lastx=lasty=127, i=d_ymin; i<d_ymax; i++)
+               for (j=d_xmin; j<d_xmax; j++)
+                       {
+                       if (k=item[j][i])
+                               if (k != OWALL)
+                                       if ((know[j][i]) && (mitem[j][i]==0))
+                                               if (objnamelist[k]!=' ')
+                                                       {
+                                                       if (lasty!=i+1 || lastx!=j)
+                                                               cursor(lastx=j+1,lasty=i+1); else lastx++;
+                                                       lprc(objnamelist[k]);
+                                                       }
+                       }
+
+       resetbold();  if (d_flag)  { always=1; botside(); always=1; bot_linex(); }
+       oldx=99;
+       d_xmin = 0 , d_xmax = MAXX , d_ymin = 0 , d_ymax = MAXY; /* for limited screen drawing */
+       }
+\f
+/*
+       showcell(x,y)
+
+       subroutine to display a cell location on the screen
+ */
+showcell(x,y)
+       int x,y;
+       {
+       register int i,j,k,m;
+       if (c[BLINDCOUNT])  return;     /* see nothing if blind         */
+       if (c[AWARENESS]) { minx = x-3; maxx = x+3;     miny = y-3;     maxy = y+3; }
+                       else      { minx = x-1; maxx = x+1;     miny = y-1;     maxy = y+1; }
+
+       if (minx < 0) minx=0;           if (maxx > MAXX-1) maxx = MAXX-1;
+       if (miny < 0) miny=0;           if (maxy > MAXY-1) maxy = MAXY-1;
+
+       for (j=miny; j<=maxy; j++)
+         for (m=minx; m<=maxx; m++)
+               if (know[m][j]==0)
+                       {
+                       cursor(m+1,j+1);
+                       x=maxx;  while (know[x][j]) --x;
+                       for (i=m; i<=x; i++)
+                               {
+                               if ((k=mitem[i][j]) != 0)  lprc(monstnamelist[k]);
+                               else switch(k=item[i][j])
+                                       {
+                                       case OWALL:  case 0: case OIVTELETRAP:  case OTRAPARROWIV:
+                                       case OIVDARTRAP: case OIVTRAPDOOR:      
+                                               lprc(objnamelist[k]);   break;
+
+                                       default: setbold(); lprc(objnamelist[k]); resetbold();
+                                       };
+                               know[i][j]=1;
+                               }
+                       m = maxx;
+                       }
+       }
+
+/*
+       this routine shows only the spot that is given it.  the spaces around
+       these coordinated are not shown
+       used in godirect() in monster.c for missile weapons display
+ */
+show1cell(x,y)
+       int x,y;
+       {
+       if (c[BLINDCOUNT])  return;     /* see nothing if blind         */
+       cursor(x+1,y+1);
+       if ((k=mitem[x][y]) != 0)  lprc(monstnamelist[k]);
+               else switch(k=item[x][y])
+                       {
+                       case OWALL:  case 0:  case OIVTELETRAP:  case OTRAPARROWIV: 
+                       case OIVDARTRAP: case OIVTRAPDOOR:      
+                               lprc(objnamelist[k]);   break;
+
+                       default: setbold(); lprc(objnamelist[k]); resetbold();
+                       };
+       know[x][y]|=1;  /* we end up knowing about it */
+       }
+
+/*
+       showplayer()
+
+       subroutine to show where the player is on the screen
+       cursor values start from 1 up
+ */
+showplayer()
+       {
+       cursor(playerx+1,playery+1);
+       oldx=playerx;  oldy=playery;
+       }
+
+/*
+       moveplayer(dir)
+
+       subroutine to move the player from one room to another
+       returns 0 if can't move in that direction or hit a monster or on an object
+       else returns 1
+       nomove is set to 1 to stop the next move (inadvertent monsters hitting
+       players when walking into walls) if player walks off screen or into wall
+ */
+short diroffx[] = { 0,  0, 1,  0, -1,  1, -1, 1, -1 };
+short diroffy[] = { 0,  1, 0, -1,  0, -1, -1, 1,  1 };
+moveplayer(dir)
+       int dir;                        /*      from = present room #  direction = [1-north]
+                                                       [2-east] [3-south] [4-west] [5-northeast]
+                                                       [6-northwest] [7-southeast] [8-southwest]
+                                               if direction=0, don't move--just show where he is */
+       {
+       register int k,m,i,j;
+       if (c[CONFUSE]) if (c[LEVEL]<rnd(30)) dir=rund(9); /*if confused any dir*/
+       k = playerx + diroffx[dir];             m = playery + diroffy[dir];
+       if (k<0 || k>=MAXX || m<0 || m>=MAXY) { nomove=1; return(yrepcount = 0); }
+       i = item[k][m];                 j = mitem[k][m];
+       if (i==OWALL && c[WTW]==0) { nomove=1;  return(yrepcount = 0); }                /*      hit a wall      */
+       if (k==33 && m==MAXY-1 && level==1)
+               {
+               newcavelevel(0); for (k=0; k<MAXX; k++) for (m=0; m<MAXY; m++)
+               if (item[k][m]==OENTRANCE)
+                 { playerx=k; playery=m; positionplayer();  drawscreen(); return(0); }
+               }
+       if (j>0)     { hitmonster(k,m); return(yrepcount = 0); } /* hit a monster*/
+       lastpx = playerx;                       lastpy = playery;
+       playerx = k;            playery = m;
+       if (i && i!=OTRAPARROWIV && i!=OIVTELETRAP && i!=OIVDARTRAP && i!=OIVTRAPDOOR) return(yrepcount = 0);  else return(1);
+       }
+\f
+/*
+ *     function to show what magic items have been discovered thus far
+ *     enter with -1 for just spells, anything else will give scrolls & potions
+ */
+static int lincount,count;
+seemagic(arg)
+       int arg;
+       {
+       register int i,number;
+       count = lincount = 0;  nosignal=1;
+
+       if (arg== -1) /* if display spells while casting one */
+               {
+               for (number=i=0; i<SPNUM; i++) if (spelknow[i]) number++;
+               number = (number+2)/3 + 4;      /* # lines needed to display */
+               cl_up(79,number);  cursor(1,1);
+               }
+       else
+               {
+               resetscroll();  clear();
+               }
+
+       lprcat("The magic spells you have discovered thus far:\n\n");
+       for (i=0; i<SPNUM; i++)
+               if (spelknow[i])
+                       { lprintf("%s %-20s ",spelcode[i],spelname[i]);  seepage(); }
+
+       if (arg== -1)
+               {
+               seepage();  more();      nosignal=0;
+               draws(0,MAXX,0,number);  return;
+               }
+
+       lincount += 3;  if (count!=0) { count=2;  seepage(); }
+
+       lprcat("\nThe magic scrolls you have found to date are:\n\n");
+       count=0;
+       for (i=0; i<MAXSCROLL; i++)
+               if (scrollname[i][0])
+                 if (scrollname[i][1]!=' ')
+                       { lprintf("%-26s",&scrollname[i][1]);  seepage(); }
+
+       lincount += 3;  if (count!=0) { count=2;  seepage(); }
+
+       lprcat("\nThe magic potions you have found to date are:\n\n");
+       count=0;
+       for (i=0; i<MAXPOTION; i++)
+               if (potionname[i][0])
+                 if (potionname[i][1]!=' ')
+                       { lprintf("%-26s",&potionname[i][1]);  seepage(); }
+
+       if (lincount!=0) more();        nosignal=0;  setscroll();       drawscreen();
+       }
+
+/*
+ *     subroutine to paginate the seemagic function
+ */
+seepage()
+       {
+       if (++count==3)
+               {
+               lincount++;     count=0;        lprc('\n');
+               if (lincount>17) {      lincount=0;  more();  clear();  }
+               }
+       }
diff --git a/usr/othersrc/games/larn/fortune.c b/usr/othersrc/games/larn/fortune.c
new file mode 100644 (file)
index 0000000..f410375
--- /dev/null
@@ -0,0 +1,63 @@
+/* fortune.c            Larn is copyrighted 1986 by Noah Morgan. */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "header.h"
+/*
+ *     function to return a random fortune from the fortune file
+ */
+static char *base=0;   /* pointer to the fortune text */
+static char **flines=0;        /* array of pointers to each fortune */
+static int fd=0;               /* true if we have load the fortune info */
+static int nlines=0;   /* # lines in fortune database */
+
+char *fortune(file)
+       char *file;
+       {
+       register char *p;
+       register int lines,tmp;
+       struct stat stat;
+       char *malloc();
+       if (fd==0)
+               {
+               if ((fd=open(file,O_RDONLY)) < 0)       /* open the file */
+                       return(0); /* can't find file */
+
+       /* find out how big fortune file is and get memory for it */
+               stat.st_size = 16384;
+               if ((fstat(fd,&stat) < 0) || ((base=malloc(1+stat.st_size)) == 0))
+                       {
+                       close(fd); fd= -1; free((char*)base); return(0);        /* can't stat file */
+                       }
+
+       /* read in the entire fortune file */
+               if (read(fd,base,stat.st_size) != stat.st_size)
+                       {
+                       close(fd); fd= -1; free((char*)base); return(0);        /* can't read file */
+                       }
+               close(fd);  base[stat.st_size]=0;       /* final NULL termination */
+
+       /* count up all the lines (and NULL terminate) to know memory needs */
+               for (p=base,lines=0; p<base+stat.st_size; p++) /* count lines */
+                       if (*p == '\n') *p=0,lines++;
+               nlines = lines;
+
+       /* get memory for array of pointers to each fortune */
+               if ((flines=(char**)malloc(nlines*sizeof(char*))) == 0)
+                       {
+                       free((char*)base); fd= -1; return(0); /* malloc() failure */
+                       }
+
+       /* now assign each pointer to a line */
+               for (p=base,tmp=0; tmp<nlines; tmp++)
+                       {
+                       flines[tmp]=p;  while (*p++); /* advance to next line */
+                       }
+               }
+
+       if (fd > 2)     /* if we have a database to look at */
+               return(flines[rund((nlines<=0)?1:nlines)]);
+       else 
+               return(0);
+       }
diff --git a/usr/othersrc/games/larn/main.c b/usr/othersrc/games/larn/main.c
new file mode 100644 (file)
index 0000000..dbe0c89
--- /dev/null
@@ -0,0 +1,878 @@
+/*     main.c          */
+#include <sys/types.h>
+#include "header.h"
+#include <pwd.h>
+static char copyright[]="\nLarn is copyrighted 1986 by Noah Morgan.\n";
+int srcount=0; /* line counter for showstr()   */
+int dropflag=0; /* if 1 then don't lookforobject() next round */
+int rmst=80;   /*      random monster creation counter         */
+int userid;            /* the players login user id number */
+char nowelcome=0,nomove=0; /* if (nomove) then don't count next iteration as a move */
+static char viewflag=0;
+       /*      if viewflag then we have done a 99 stay here and don't showcell in the main loop */
+char restorflag=0;     /* 1 means restore has been done        */
+static char cmdhelp[] = "\
+Cmd line format: larn [-slicnh] [-o<optsifle>] [-##] [++]\n\
+  -s   show the scoreboard\n\
+  -l   show the logfile (wizard id only)\n\
+  -i   show scoreboard with inventories of dead characters\n\
+  -c   create new scoreboard (wizard id only)\n\
+  -n   suppress welcome message on starting game\n\
+  -##  specify level of difficulty (example: -5)\n\
+  -h   print this help text\n\
+  ++   restore game from checkpoint file\n\
+  -o<optsfile>   specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
+";
+#ifdef VT100
+static char *termtypes[] = { "vt100", "vt101", "vt102", "vt103", "vt125",
+       "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
+       "vt341"  };
+#endif VT100
+/*
+       ************
+       MAIN PROGRAM
+       ************
+ */
+main(argc,argv)
+       int argc;
+       char **argv;
+       {
+       register int i,j;
+       int hard;
+       char *ptr=0,*ttype;
+       struct passwd *pwe;
+
+/*
+ *     first task is to identify the player
+ */
+#ifndef VT100
+       init_term();    /* setup the terminal (find out what type) for termcap */
+#endif VT100
+       if (((ptr = getlogin()) == 0) || (*ptr==0))     /* try to get login name */
+         if (pwe=getpwuid(getuid())) /* can we get it from /etc/passwd? */
+               ptr = pwe->pw_name;
+         else
+         if ((ptr = getenv("USER")) == 0)
+               if ((ptr = getenv("LOGNAME")) == 0)
+                 {
+                 noone: write(2, "Can't find your logname.  Who Are You?\n",39);
+                                exit();
+                 }
+       if (ptr==0) goto noone;
+       if (strlen(ptr)==0) goto noone;
+/*
+ *     second task is to prepare the pathnames the player will need
+ */
+       strcpy(loginname,ptr); /* save loginname of the user for logging purposes */
+       strcpy(logname,ptr);    /* this will be overwritten with the players name */
+       if ((ptr = getenv("HOME")) == 0) ptr = ".";
+       strcpy(savefilename, ptr);
+       strcat(savefilename, "/Larn.sav");      /* save file name in home directory */
+       sprintf(optsfile, "%s/.larnopts",ptr);  /* the .larnopts filename */
+
+/*
+ *     now malloc the memory for the dungeon 
+ */
+       cell = (struct cel *)malloc(sizeof(struct cel)*(MAXLEVEL+MAXVLEVEL)*MAXX*MAXY);
+       if (cell == 0) died(-285);      /* malloc failure */
+       lpbuf    = malloc((5* BUFBIG)>>2);      /* output buffer */
+       inbuffer = malloc((5*MAXIBUF)>>2);      /* output buffer */
+       if ((lpbuf==0) || (inbuffer==0)) died(-285); /* malloc() failure */
+
+       lcreat((char*)0);       newgame();              /*      set the initial clock  */ hard= -1;
+
+#ifdef VT100
+/*
+ *     check terminal type to avoid users who have not vt100 type terminals
+ */
+       ttype = getenv("TERM");
+       for (j=1, i=0; i<sizeof(termtypes)/sizeof(char *); i++)
+               if (strcmp(ttype,termtypes[i]) == 0) { j=0;  break; }
+       if (j)
+               {
+               lprcat("Sorry, Larn needs a VT100 family terminal for all it's features.\n"); lflush();
+               exit();
+               }
+#endif VT100
+
+/*
+ *     now make scoreboard if it is not there (don't clear) 
+ */
+       if (access(scorefile,0) == -1) /* not there */
+               makeboard();
+
+/*
+ *     now process the command line arguments 
+ */
+       for (i=1; i<argc; i++)
+               {
+               if (argv[i][0] == '-')
+                 switch(argv[i][1])
+                       {
+                       case 's': showscores();  exit();  /* show scoreboard   */
+
+                       case 'l': /* show log file     */
+                                               diedlog();              exit();
+
+                       case 'i': showallscores();  exit();  /* show all scoreboard */
+
+                       case 'c':                /* anyone with password can create scoreboard */
+                                         lprcat("Preparing to initialize the scoreboard.\n");
+                                         if (getpassword() != 0)  /*make new scoreboard*/
+                                                       {
+                                                       makeboard(); lprc('\n'); showscores();
+                                                       }
+                                         exit();
+
+                       case 'n':       /* no welcome msg       */ nowelcome=1; argv[i][0]=0; break;
+
+                       case '0': case '1': case '2': case '3': case '4': case '5':
+                       case '6': case '7': case '8': case '9': /* for hardness */
+                                               sscanf(&argv[i][1],"%d",&hard); 
+                                               break;
+
+                       case 'h':       /* print out command line arguments */
+                                               write(1,cmdhelp,sizeof(cmdhelp));  exit();
+
+                       case 'o':       /* specify a .larnopts filename */
+                                               strncpy(optsfile,argv[i]+2,127);  break;
+
+                       default:        printf("Unknown option <%s>\n",argv[i]);  exit();
+                       };
+
+               if (argv[i][0] == '+')
+                       {
+                       clear();        restorflag = 1;
+                       if (argv[i][1] == '+')
+                               {
+                               hitflag=1; restoregame(ckpfile); /* restore checkpointed game */
+                               }
+                       i = argc;
+                       }
+               }
+
+       readopts();             /* read the options file if there is one */
+
+
+#ifdef UIDSCORE
+       userid = geteuid();     /* obtain the user's effective id number */
+#else UIDSCORE
+       userid = getplid(logname);      /* obtain the players id number */
+#endif UIDSCORE
+       if (userid < 0) { write(2,"Can't obtain playerid\n",22); exit(); }
+
+#ifdef HIDEBYLINK
+/*
+ *     this section of code causes the program to look like something else to ps
+ */
+       if (strcmp(psname,argv[0])) /* if a different process name only */
+               {
+               if ((i=access(psname,1)) < 0)
+                       {               /* link not there */
+                       if (link(argv[0],psname)>=0)
+                               {
+                               argv[0] = psname;   execv(psname,argv);
+                               }
+                       }
+               else 
+                       unlink(psname);
+               }
+
+       for (i=1; i<argc; i++)
+               {
+               szero(argv[i]); /* zero the argument to avoid ps snooping */
+               }
+#endif HIDEBYLINK
+
+       if (access(savefilename,0)==0)  /* restore game if need to */
+               {
+               clear();        restorflag = 1;
+               hitflag=1;      restoregame(savefilename);  /* restore last game        */
+               }
+       sigsetup();             /* trap all needed signals      */
+       sethard(hard);  /* set up the desired difficulty                                */
+       setupvt100();   /*      setup the terminal special mode                         */
+       if (c[HP]==0)   /* create new game */
+               {
+               makeplayer();   /*      make the character that will play                       */
+               newcavelevel(0);/*      make the dungeon                                                        */
+               predostuff = 1; /* tell signals that we are in the welcome screen */
+               if (nowelcome==0) welcome();     /* welcome the player to the game */
+               }
+       drawscreen();   /*      show the initial dungeon                                        */
+       predostuff = 2; /* tell the trap functions that they must do a showplayer()
+                                               from here on */
+       /* nice(1);     /* games should be run niced */
+       yrepcount = hit2flag = 0;
+       while (1)
+               {
+               if (dropflag==0) lookforobject(); /* see if there is an object here     */
+                       else dropflag=0; /* don't show it just dropped an item */
+               if (hitflag==0) { if (c[HASTEMONST]) movemonst(); movemonst(); }        /*      move the monsters               */
+               if (viewflag==0) showcell(playerx,playery); else viewflag=0;    /*      show stuff around player        */
+               if (hit3flag) flushall();
+               hitflag=hit3flag=0;     nomove=1;
+               bot_linex();    /* update bottom line */
+               while (nomove)
+                       {
+                       if (hit3flag) flushall();
+                       nomove=0; parse();
+                       }       /*      get commands and make moves     */
+               regen();                        /*      regenerate hp and spells                        */
+               if (c[TIMESTOP]==0)
+                       if (--rmst <= 0)
+                               { rmst = 120-(level<<2); fillmonst(makemonst(level)); }
+               }
+       }
+\f
+/*
+       showstr()
+
+       show character's inventory
+ */
+showstr()
+       {
+       register int i,number;
+       for (number=3, i=0; i<26; i++)
+               if (iven[i]) number++;  /* count items in inventory */
+       t_setup(number);        qshowstr();       t_endup(number);
+       }
+
+qshowstr()
+       {
+       register int i,j,k,sigsav;
+       srcount=0;  sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
+       if (c[GOLD]) { lprintf(".)   %d gold pieces",(long)c[GOLD]); srcount++; }
+       for (k=26; k>=0; k--)
+         if (iven[k])
+               {  for (i=22; i<84; i++)
+                        for (j=0; j<=k; j++)  if (i==iven[j])  show3(j); k=0; }
+
+       lprintf("\nElapsed time is %d.  You have %d mobuls left",(long)((gtime+99)/100+1),(long)((TIMELIMIT-gtime)/100));
+       more();         nosignal=sigsav;
+       }
+
+/*
+ *     subroutine to clear screen depending on # lines to display
+ */
+t_setup(count)
+       register int count;
+       {
+       if (count<20)  /* how do we clear the screen? */
+               {
+               cl_up(79,count);  cursor(1,1);
+               }
+       else
+               {
+               resetscroll(); clear();
+               }
+       }
+
+/*
+ *     subroutine to restore normal display screen depending on t_setup()
+ */
+t_endup(count)
+       register int count;
+       {
+       if (count<18)  /* how did we clear the screen? */
+               draws(0,MAXX,0,(count>MAXY) ? MAXY : count);
+       else
+               {
+               drawscreen(); setscroll();
+               }
+       }
+
+/*
+       function to show the things player is wearing only
+ */
+showwear()
+       {
+       register int i,j,sigsav,count;
+       sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
+       srcount=0;
+
+        for (count=2,j=0; j<=26; j++)   /* count number of items we will display */
+          if (i=iven[j])
+               switch(i)
+                       {
+                       case OLEATHER:  case OPLATE:    case OCHAIN:
+                       case ORING:             case OSTUDLEATHER:      case OSPLINT:
+                       case OPLATEARMOR:       case OSSPLATE:  case OSHIELD:
+                       count++;
+                       };
+
+       t_setup(count);
+
+       for (i=22; i<84; i++)
+                for (j=0; j<=26; j++)
+                  if (i==iven[j])
+                       switch(i)
+                               {
+                               case OLEATHER:  case OPLATE:    case OCHAIN:
+                               case ORING:             case OSTUDLEATHER:      case OSPLINT:
+                               case OPLATEARMOR:       case OSSPLATE:  case OSHIELD:
+                               show3(j);
+                               };
+       more();         nosignal=sigsav;        t_endup(count);
+       }
+
+/*
+       function to show the things player can wield only 
+ */
+showwield()
+       {
+       register int i,j,sigsav,count;
+       sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
+       srcount=0;
+
+        for (count=2,j=0; j<=26; j++)  /* count how many items */
+          if (i=iven[j])
+               switch(i)
+                       {
+                       case ODIAMOND:  case ORUBY:  case OEMERALD:  case OSAPPHIRE:
+                       case OBOOK:     case OCHEST:  case OLARNEYE: case ONOTHEFT:
+                       case OSPIRITSCARAB:  case OCUBEofUNDEAD:
+                       case OPOTION:   case OSCROLL:  break;
+                       default:  count++;
+                       };
+
+       t_setup(count);
+
+       for (i=22; i<84; i++)
+                for (j=0; j<=26; j++)
+                  if (i==iven[j])
+                       switch(i)
+                               {
+                               case ODIAMOND:  case ORUBY:  case OEMERALD:  case OSAPPHIRE:
+                               case OBOOK:     case OCHEST:  case OLARNEYE: case ONOTHEFT:
+                               case OSPIRITSCARAB:  case OCUBEofUNDEAD:
+                               case OPOTION:   case OSCROLL:  break;
+                               default:  show3(j);
+                               };
+       more();         nosignal=sigsav;        t_endup(count);
+       }
+
+/*
+ *     function to show the things player can read only
+ */
+showread()
+       {
+       register int i,j,sigsav,count;
+       sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
+       srcount=0;
+
+       for (count=2,j=0; j<=26; j++)
+               switch(iven[j])
+                       {
+                       case OBOOK:     case OSCROLL:   count++;
+                       };
+       t_setup(count);
+
+       for (i=22; i<84; i++)
+                for (j=0; j<=26; j++)
+                  if (i==iven[j])
+                       switch(i)
+                               {
+                               case OBOOK:     case OSCROLL:   show3(j);
+                               };
+       more();         nosignal=sigsav;        t_endup(count);
+       }
+
+/*
+ *     function to show the things player can eat only
+ */
+showeat()
+       {
+       register int i,j,sigsav,count;
+       sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
+       srcount=0;
+
+       for (count=2,j=0; j<=26; j++)
+               switch(iven[j])
+                       {
+                       case OCOOKIE:   count++;
+                       };
+       t_setup(count);
+
+       for (i=22; i<84; i++)
+                for (j=0; j<=26; j++)
+                  if (i==iven[j])
+                       switch(i)
+                               {
+                               case OCOOKIE:   show3(j);
+                               };
+       more();         nosignal=sigsav;        t_endup(count);
+       }
+
+/*
+       function to show the things player can quaff only
+ */
+showquaff()
+       {
+       register int i,j,sigsav,count;
+       sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
+       srcount=0;
+
+       for (count=2,j=0; j<=26; j++)
+               switch(iven[j])
+                       {
+                       case OPOTION:   count++;
+                       };
+       t_setup(count);
+
+       for (i=22; i<84; i++)
+                for (j=0; j<=26; j++)
+                  if (i==iven[j])
+                       switch(i)
+                               {
+                               case OPOTION:   show3(j);
+                               };
+       more();         nosignal=sigsav;                t_endup(count);
+       }
+
+show1(idx,str2)
+       register int idx;
+       register char *str2[];
+       {
+       if (str2==0)  lprintf("\n%c)   %s",idx+'a',objectname[iven[idx]]);
+       else if (*str2[ivenarg[idx]]==0)  lprintf("\n%c)   %s",idx+'a',objectname[iven[idx]]);
+       else lprintf("\n%c)   %s of%s",idx+'a',objectname[iven[idx]],str2[ivenarg[idx]]);
+       }
+
+show3(index)
+       register int index;
+       {
+       switch(iven[index]) 
+               {
+               case OPOTION:   show1(index,potionname);  break;
+               case OSCROLL:   show1(index,scrollname);  break;
+
+               case OLARNEYE:          case OBOOK:                     case OSPIRITSCARAB:
+               case ODIAMOND:          case ORUBY:                     case OCUBEofUNDEAD:
+               case OEMERALD:          case OCHEST:            case OCOOKIE:
+               case OSAPPHIRE:         case ONOTHEFT:          show1(index,(char **)0);  break;
+
+               default:                lprintf("\n%c)   %s",index+'a',objectname[iven[index]]);
+                                               if (ivenarg[index]>0) lprintf(" + %d",(long)ivenarg[index]);
+                                               else if (ivenarg[index]<0) lprintf(" %d",(long)ivenarg[index]);
+                                               break;
+               }
+       if (c[WIELD]==index) lprcat(" (weapon in hand)");
+       if ((c[WEAR]==index) || (c[SHIELD]==index))  lprcat(" (being worn)");
+       if (++srcount>=22) { srcount=0; more(); clear(); }
+       }
+
+/*
+       subroutine to randomly create monsters if needed
+ */
+randmonst()
+       {
+       if (c[TIMESTOP]) return;        /*      don't make monsters if time is stopped  */
+       if (--rmst <= 0)
+               {
+               rmst = 120 - (level<<2);  fillmonst(makemonst(level));
+               }
+       }
+
+\f
+/*
+       parse()
+
+       get and execute a command
+ */
+parse()
+       {
+       register int i,j,k,flag;
+       while   (1)
+               {
+               k = yylex();
+               switch(k)       /*      get the token from the input and switch on it   */
+                       {
+                       case 'h':       moveplayer(4);  return;         /*      west            */
+                       case 'H':       run(4);                 return;         /*      west            */
+                       case 'l':       moveplayer(2);  return;         /*      east            */
+                       case 'L':       run(2);                 return;         /*      east            */
+                       case 'j':       moveplayer(1);  return;         /*      south           */
+                       case 'J':       run(1);                 return;         /*      south           */
+                       case 'k':       moveplayer(3);  return;         /*      north           */
+                       case 'K':       run(3);                 return;         /*      north           */
+                       case 'u':       moveplayer(5);  return;         /*      northeast       */
+                       case 'U':       run(5);                 return;         /*      northeast       */
+                       case 'y':       moveplayer(6);  return;         /*      northwest       */
+                       case 'Y':       run(6);                 return;         /*      northwest       */
+                       case 'n':       moveplayer(7);  return;         /*      southeast       */
+                       case 'N':       run(7);                 return;         /*      southeast       */
+                       case 'b':       moveplayer(8);  return;         /*      southwest       */
+                       case 'B':       run(8);                 return;         /*      southwest       */
+
+                       case '.':       if (yrepcount) viewflag=1; return;              /*      stay here               */
+
+                       case 'w':       yrepcount=0;    wield();        return;         /*      wield a weapon */
+
+                       case 'W':       yrepcount=0;    wear();         return; /*      wear armor      */
+
+                       case 'r':       yrepcount=0;
+                                               if (c[BLINDCOUNT]) { cursors(); lprcat("\nYou can't read anything when you're blind!"); } else
+                                               if (c[TIMESTOP]==0) readscr(); return;          /*      to read a scroll        */
+
+                       case 'q':       yrepcount=0;    if (c[TIMESTOP]==0) quaff();    return; /*      quaff a potion          */
+
+                       case 'd':       yrepcount=0;    if (c[TIMESTOP]==0) dropobj(); return;  /*      to drop an object       */
+
+                       case 'c':       yrepcount=0;    cast();         return;         /*      cast a spell    */
+
+                       case 'i':       yrepcount=0;    nomove=1;  showstr();   return;         /*      status          */
+
+                       case 'e':       yrepcount=0;
+                                               if (c[TIMESTOP]==0) eatcookie(); return;        /*      to eat a fortune cookie */
+
+                       case 'D':       yrepcount=0;    seemagic(0);    nomove=1; return;       /*      list spells and scrolls */
+
+                       case '?':       yrepcount=0;    help(); nomove=1; return;       /*      give the help screen*/
+
+                       case 'S':       clear();  lprcat("Saving . . ."); lflush();  
+                                               savegame(savefilename); wizard=1; died(-257);   /*      save the game - doesn't return  */
+
+                       case 'Z':       yrepcount=0;    if (c[LEVEL]>9) { oteleport(1); return; }
+                                               cursors(); lprcat("\nAs yet, you don't have enough experience to use teleportation");
+                                               return; /*      teleport yourself       */
+
+                       case '^':       /* identify traps */  flag=yrepcount=0;  cursors();
+                                               lprc('\n');  for (j=playery-1; j<playery+2; j++)
+                                                       {
+                                                       if (j < 0) j=0;         if (j >= MAXY) break;
+                                                       for (i=playerx-1; i<playerx+2; i++)
+                                                               {
+                                                               if (i < 0) i=0; if (i >= MAXX) break;
+                                                               switch(item[i][j])
+                                                                       {
+                                                                       case OTRAPDOOR:         case ODARTRAP:
+                                                                       case OTRAPARROW:        case OTELEPORTER:
+                                                                               lprcat("\nIts "); lprcat(objectname[item[i][j]]);  flag++;
+                                                                       };
+                                                               }
+                                                       }
+                                               if (flag==0) lprcat("\nNo traps are visible");
+                                               return;
+
+#if WIZID
+                       case '_':       /*      this is the fudge player password for wizard mode*/
+                                               yrepcount=0;    cursors(); nomove=1;
+                                               if (userid!=wisid)
+                                                       {
+                                                       lprcat("Sorry, you are not empowered to be a wizard.\n");
+                                                       scbr(); /* system("stty -echo cbreak"); */
+                                                       lflush();  return;
+                                                       }
+                                               if (getpassword()==0)
+                                                       {
+                                                       scbr(); /* system("stty -echo cbreak"); */ return;
+                                                       }
+                                               wizard=1;  scbr(); /* system("stty -echo cbreak"); */
+                                               for (i=0; i<6; i++)  c[i]=70;  iven[0]=iven[1]=0;
+                                               take(OPROTRING,50);   take(OLANCE,25);  c[WIELD]=1;
+                                               c[LANCEDEATH]=1;   c[WEAR] = c[SHIELD] = -1;
+                                               raiseexperience(6000000L);  c[AWARENESS] += 25000;
+                                               {
+                                               register int i,j;
+                                               for (i=0; i<MAXY; i++)
+                                                       for (j=0; j<MAXX; j++)  know[j][i]=1;
+                                               for (i=0; i<SPNUM; i++) spelknow[i]=1;
+                                               for (i=0; i<MAXSCROLL; i++)  scrollname[i][0]=' ';
+                                               for (i=0; i<MAXPOTION; i++)  potionname[i][0]=' ';
+                                               }
+                                               for (i=0; i<MAXSCROLL; i++)
+                                                 if (strlen(scrollname[i])>2) /* no null items */
+                                                       { item[i][0]=OSCROLL; iarg[i][0]=i; }
+                                               for (i=MAXX-1; i>MAXX-1-MAXPOTION; i--)
+                                                 if (strlen(potionname[i-MAXX+MAXPOTION])>2) /* no null items */
+                                                       { item[i][0]=OPOTION; iarg[i][0]=i-MAXX+MAXPOTION; }
+                                               for (i=1; i<MAXY; i++)
+                                                       { item[0][i]=i; iarg[0][i]=0; }
+                                               for (i=MAXY; i<MAXY+MAXX; i++)
+                                                       { item[i-MAXY][MAXY-1]=i; iarg[i-MAXY][MAXY-1]=0; }
+                                               for (i=MAXX+MAXY; i<MAXX+MAXY+MAXY; i++)
+                                                       { item[MAXX-1][i-MAXX-MAXY]=i; iarg[MAXX-1][i-MAXX-MAXY]=0; }
+                                               c[GOLD]+=25000; drawscreen();   return;
+#endif
+
+                       case 'T':       yrepcount=0;    cursors();  if (c[SHIELD] != -1) { c[SHIELD] = -1; lprcat("\nYour shield is off"); bottomline(); } else
+                                                                               if (c[WEAR] != -1) { c[WEAR] = -1; lprcat("\nYour armor is off"); bottomline(); }
+                                               else lprcat("\nYou aren't wearing anything");
+                                               return;
+
+                       case 'g':       cursors();
+                                               lprintf("\nThe stuff you are carrying presently weighs %d pounds",(long)packweight());
+                       case ' ':       yrepcount=0;    nomove=1;  return;
+
+                       case 'v':       yrepcount=0;    cursors();
+                                               lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d",(long)VERSION,(long)SUBVERSION,(long)c[HARDGAME]);
+                                               if (wizard) lprcat(" Wizard"); nomove=1;
+                                               if (cheat) lprcat(" Cheater");
+                                               lprcat(copyright);
+                                               return;
+
+                       case 'Q':       yrepcount=0;    quit(); nomove=1;       return; /*      quit            */
+
+                       case 'L'-64:  yrepcount=0;      drawscreen();  nomove=1; return;        /*      look            */
+
+#if WIZID
+#ifdef EXTRA
+                       case 'A':       yrepcount=0;    nomove=1; if (wizard) { diag(); return; }  /*   create diagnostic file */
+                                               return;
+#endif
+#endif
+                       case 'P':       cursors(); 
+                                               if (outstanding_taxes>0)
+                                                       lprintf("\nYou presently owe %d gp in taxes.",(long)outstanding_taxes);
+                                               else
+                                                       lprcat("\nYou do not owe any taxes.");
+                                               return;
+                       };
+               }
+       }
+
+parse2()
+       {
+       if (c[HASTEMONST]) movemonst(); movemonst(); /* move the monsters               */
+       randmonst();    regen();
+       }
+
+run(dir)
+       int dir;
+       {
+       register int i;
+       i=1; while (i)
+               {
+               i=moveplayer(dir);
+               if (i>0) {  if (c[HASTEMONST]) movemonst();  movemonst(); randmonst(); regen(); }
+               if (hitflag) i=0;
+               if (i!=0)  showcell(playerx,playery);
+               }
+       }
+
+/*
+       function to wield a weapon
+ */
+wield()        
+       {
+       register int i;
+       while (1)
+               {
+               if ((i = whatitem("wield"))=='\33')  return;
+               if (i != '.')
+                       {
+                       if (i=='*') showwield();
+                       else  if (iven[i-'a']==0) { ydhi(i); return; }
+                       else if (iven[i-'a']==OPOTION) { ycwi(i); return; }
+                       else if (iven[i-'a']==OSCROLL) { ycwi(i); return; }
+                       else  if ((c[SHIELD]!= -1) && (iven[i-'a']==O2SWORD)) { lprcat("\nBut one arm is busy with your shield!"); return; }
+                       else  { c[WIELD]=i-'a'; if (iven[i-'a'] == OLANCE) c[LANCEDEATH]=1; else c[LANCEDEATH]=0;  bottomline(); return; }
+                       }
+               }
+       }
+
+/*
+       common routine to say you don't have an item
+ */
+ydhi(x)
+       int x;
+       { cursors();  lprintf("\nYou don't have item %c!",x); }
+ycwi(x)
+       int x;
+       { cursors();  lprintf("\nYou can't wield item %c!",x); }
+
+/*
+       function to wear armor
+ */
+wear()
+       {
+       register int i;
+       while (1)
+               {
+               if ((i = whatitem("wear"))=='\33')  return;
+               if (i != '.')
+                       {
+                       if (i=='*') showwear(); else
+                       switch(iven[i-'a'])
+                               {
+                               case 0:  ydhi(i); return;
+                               case OLEATHER:  case OCHAIN:  case OPLATE:      case OSTUDLEATHER:
+                               case ORING:             case OSPLINT:   case OPLATEARMOR:       case OSSPLATE:
+                                               if (c[WEAR] != -1) { lprcat("\nYou're already wearing some armor"); return; }
+                                                       c[WEAR]=i-'a';  bottomline(); return;
+                               case OSHIELD:   if (c[SHIELD] != -1) { lprcat("\nYou are already wearing a shield"); return; }
+                                                               if (iven[c[WIELD]]==O2SWORD) { lprcat("\nYour hands are busy with the two handed sword!"); return; }
+                                                               c[SHIELD] = i-'a';  bottomline(); return;
+                               default:        lprcat("\nYou can't wear that!");
+                               };
+                       }
+               }
+       }
+
+/*
+       function to drop an object
+ */
+dropobj()
+       {
+       register int i;
+       register char *p;
+       long amt;
+       p = &item[playerx][playery];
+       while (1)
+               {
+               if ((i = whatitem("drop"))=='\33')  return;
+               if (i=='*') showstr(); else 
+                       {
+                       if (i=='.')     /* drop some gold */
+                               {
+                               if (*p) { lprcat("\nThere's something here already!"); return; }
+                               lprcat("\n\n");
+                               cl_dn(1,23);
+                               lprcat("How much gold do you drop? ");
+                               if ((amt=readnum((long)c[GOLD])) == 0) return;
+                               if (amt>c[GOLD])
+                                       { lprcat("\nYou don't have that much!"); return; }
+                               if (amt<=32767)
+                                       { *p=OGOLDPILE; i=amt; }
+                               else if (amt<=327670L)
+                                       { *p=ODGOLD; i=amt/10; amt = 10*i; }
+                               else if (amt<=3276700L)
+                                       { *p=OMAXGOLD; i=amt/100; amt = 100*i; }
+                               else if (amt<=32767000L)
+                                       { *p=OKGOLD; i=amt/1000; amt = 1000*i; }
+                               else
+                                       { *p=OKGOLD; i=32767; amt = 32767000L; }
+                               c[GOLD] -= amt; 
+                               lprintf("You drop %d gold pieces",(long)amt);
+                               iarg[playerx][playery]=i; bottomgold();
+                               know[playerx][playery]=0; dropflag=1;  return;
+                               }
+                       drop_object(i-'a');
+                       return;
+                       }
+               }
+       }
+
+/*
+ *     readscr()               Subroutine to read a scroll one is carrying
+ */
+readscr()
+       {
+       register int i;
+       while (1)
+               {
+               if ((i = whatitem("read"))=='\33')  return;
+               if (i != '.')
+                       {
+                       if (i=='*') showread(); else
+                               {
+                               if (iven[i-'a']==OSCROLL) { read_scroll(ivenarg[i-'a']); iven[i-'a']=0; return; }
+                               if (iven[i-'a']==OBOOK)   { readbook(ivenarg[i-'a']);  iven[i-'a']=0; return; }
+                               if (iven[i-'a']==0) { ydhi(i); return; }
+                               lprcat("\nThere's nothing on it to read");  return;
+                               }
+                       }
+               }
+       }
+
+/*
+ *     subroutine to eat a cookie one is carrying
+ */
+eatcookie()
+{
+register int i;
+char *p;
+while (1)
+       {
+       if ((i = whatitem("eat"))=='\33')  return;
+       if (i != '.')
+               if (i=='*') showeat(); else
+                       {
+                       if (iven[i-'a']==OCOOKIE)
+                               {
+                               lprcat("\nThe cookie was delicious.");
+                               iven[i-'a']=0;
+                               if (!c[BLINDCOUNT])
+                                       {
+                                       if (p=fortune(fortfile))
+                                               {
+                                               lprcat("  Inside you find a scrap of paper that says:\n");
+                                               lprcat(p);
+                                               }
+                                       }
+                               return;
+                               }
+                       if (iven[i-'a']==0) { ydhi(i); return; }
+                       lprcat("\nYou can't eat that!");  return;
+                       }
+       }
+}
+
+/*
+ *     subroutine to quaff a potion one is carrying
+ */
+quaff()
+       {
+       register int i;
+       while (1)
+               {
+               if ((i = whatitem("quaff"))=='\33')  return;
+               if (i != '.')
+                       {
+                       if (i=='*') showquaff(); else
+                               {
+                               if (iven[i-'a']==OPOTION) { quaffpotion(ivenarg[i-'a']); iven[i-'a']=0; return; }
+                               if (iven[i-'a']==0) { ydhi(i); return; }
+                               lprcat("\nYou wouldn't want to quaff that, would you? ");  return;
+                               }
+                       }
+               }
+       }
+
+/*
+       function to ask what player wants to do
+ */
+whatitem(str)
+       char *str;
+       {
+       int i;
+       cursors();  lprintf("\nWhat do you want to %s [* for all] ? ",str);
+       i=0; while (i>'z' || (i<'a' && i!='*' && i!='\33' && i!='.')) i=getchar();
+       if (i=='\33')  lprcat(" aborted");
+       return(i);
+       }
+
+/*
+       subroutine to get a number from the player
+       and allow * to mean return amt, else return the number entered
+ */
+unsigned long readnum(mx)
+       long mx;
+       {
+       register int i;
+       register unsigned long amt=0;
+       sncbr();
+       if ((i=getchar()) == '*')  amt = mx;   /* allow him to say * for all gold */
+       else
+               while (i != '\n')
+                       {
+                       if (i=='\033') { scbr(); lprcat(" aborted"); return(0); }
+                       if ((i <= '9') && (i >= '0') && (amt<99999999))
+                               amt = amt*10+i-'0';
+                       i = getchar();
+                       }
+       scbr();  return(amt);
+       }
+
+#ifdef HIDEBYLINK
+/*
+ *     routine to zero every byte in a string
+ */
+szero(str)
+       register char *str;
+       {
+       while (*str)
+               *str++ = 0;
+       }
+#endif HIDEBYLINK
diff --git a/usr/othersrc/games/larn/monster.c b/usr/othersrc/games/larn/monster.c
new file mode 100644 (file)
index 0000000..6ec0865
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ *     monster.c               Larn is copyrighted 1986 by Noah Morgan. 
+ *
+ *     This file contains the following functions:
+ *     ----------------------------------------------------------------------------
+ *
+ *     createmonster(monstno)          Function to create a monster next to the player
+ *             int monstno;
+ *
+ *     int cgood(x,y,itm,monst)        Function to check location for emptiness
+ *             int x,y,itm,monst;
+ *
+ *     createitem(it,arg)                      Routine to place an item next to the player
+ *             int it,arg;
+ *
+ *     cast()                          Subroutine called by parse to cast a spell for the user
+ *
+ *     speldamage(x)           Function to perform spell functions cast by the player
+ *             int x;
+ *
+ *     loseint()                       Routine to decrement your int (intelligence) if > 3
+ *
+ *     isconfuse()             Routine to check to see if player is confused
+ *
+ *     nospell(x,monst)        Routine to return 1 if a spell doesn't affect a monster
+ *             int x,monst;
+ *
+ *     fullhit(xx)                     Function to return full damage against a monst (aka web)
+ *             int xx;
+ *
+ *     direct(spnum,dam,str,arg)       Routine to direct spell damage 1 square in 1 dir
+ *             int spnum,dam,arg;
+ *             char *str;
+ *
+ *     godirect(spnum,dam,str,delay,cshow)             Function to perform missile attacks
+ *             int spnum,dam,delay;
+ *             char *str,cshow;
+ *
+ *     ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
+ *             int x,y;
+ *
+ *     tdirect(spnum)                  Routine to teleport away a monster
+ *             int spnum;
+ *
+ *     omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
+ *             int sp,dam;
+ *             char *str;
+ *
+ *     dirsub(x,y)                     Routine to ask for direction, then modify x,y for it
+ *             int *x,*y;
+ *
+ *     vxy(x,y)                        Routine to verify/fix (*x,*y) for being within bounds
+ *             int *x,*y;
+ *
+ *     dirpoly(spnum)          Routine to ask for a direction and polymorph a monst
+ *             int spnum;
+ *
+ *     hitmonster(x,y)         Function to hit a monster at the designated coordinates
+ *             int x,y;
+ *
+ *     hitm(x,y,amt)           Function to just hit a monster at a given coordinates
+ *             int x,y,amt;
+ *
+ *     hitplayer(x,y)          Function for the monster to hit the player from (x,y)
+ *             int x,y;
+ *
+ *     dropsomething(monst)    Function to create an object when a monster dies
+ *             int monst;
+ *
+ *     dropgold(amount)                Function to drop some gold around player
+ *             int amount;
+ *
+ *     something(level)                Function to create a random item around player
+ *             int level;
+ *
+ *     newobject(lev,i)                Routine to return a randomly selected new object
+ *             int lev,*i;
+ *
+ *  spattack(atckno,xx,yy)     Function to process special attacks from monsters
+ *     int atckno,xx,yy;
+ *
+ *     checkloss(x)    Routine to subtract hp from user and flag bottomline display
+ *             int x;
+ *
+ *     annihilate()   Routine to annihilate monsters around player, playerx,playery
+ *
+ *     newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
+ *             int x,y,dir,lifetime;
+ *
+ *     rmsphere(x,y)           Function to delete a sphere of annihilation from list
+ *             int x,y;
+ *
+ *     sphboom(x,y)            Function to perform the effects of a sphere detonation
+ *             int x,y;
+ *
+ *     genmonst()                      Function to ask for monster and genocide from game
+ *
+ */
+#include "header.h"
+
+struct isave   /* used for altar reality */
+       {
+       char type;      /* 0=item,  1=monster */
+       char id;        /* item number or monster number */
+       short arg;      /* the type of item or hitpoints of monster */
+       };
+
+/*
+ *     createmonster(monstno)          Function to create a monster next to the player
+ *             int monstno;
+ *
+ *     Enter with the monster number (1 to MAXMONST+8)
+ *     Returns no value.
+ */
+createmonster(mon)
+       int mon;
+       {
+       register int x,y,k,i;
+       if (mon<1 || mon>MAXMONST+8)    /* check for monster number out of bounds */
+               {
+               beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon); nap(3000); return;
+               }
+       while (monster[mon].genocided && mon<MAXMONST) mon++; /* genocided? */
+       for (k=rnd(8), i= -8; i<0; i++,k++)     /* choose direction, then try all */
+               {
+               if (k>8) k=1;   /* wraparound the diroff arrays */
+               x = playerx + diroffx[k];               y = playery + diroffy[k];
+               if (cgood(x,y,0,1))     /* if we can create here */
+                       {
+                       mitem[x][y] = mon;
+                       hitp[x][y] = monster[mon].hitpoints;
+                       stealth[x][y]=know[x][y]=0;
+                       switch(mon)
+                               {
+                               case ROTHE: case POLTERGEIST: case VAMPIRE: stealth[x][y]=1;
+                               };
+                       return;
+                       }
+               }
+       }
+
+/*
+ *     int cgood(x,y,itm,monst)          Function to check location for emptiness
+ *             int x,y,itm,monst;
+ *
+ *     Routine to return TRUE if a location does not have itm or monst there
+ *     returns FALSE (0) otherwise
+ *     Enter with itm or monst TRUE or FALSE if checking it
+ *     Example:  if itm==TRUE check for no item at this location
+ *                       if monst==TRUE check for no monster at this location
+ *     This routine will return FALSE if at a wall or the dungeon exit on level 1
+ */
+int cgood(x,y,itm,monst)
+       register int x,y;
+       int itm,monst;
+       {
+       if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
+         if (item[x][y]!=OWALL)        /* can't make anything on walls */
+               if (itm==0 || (item[x][y]==0))  /* is it free of items? */
+                 if (monst==0 || (mitem[x][y]==0))     /* is it free of monsters? */
+                   if ((level!=1) || (x!=33) || (y!=MAXY-1)) /* not exit to level 1 */
+                         return(1);
+       return(0);
+       }
+
+/*
+ *     createitem(it,arg)              Routine to place an item next to the player
+ *             int it,arg;
+ *
+ *     Enter with the item number and its argument (iven[], ivenarg[])
+ *     Returns no value, thus we don't know about createitem() failures.
+ */
+createitem(it,arg)
+       int it,arg;
+       {
+       register int x,y,k,i;
+       if (it >= MAXOBJ) return;       /* no such object */
+       for (k=rnd(8), i= -8; i<0; i++,k++)     /* choose direction, then try all */
+               {
+               if (k>8) k=1;   /* wraparound the diroff arrays */
+               x = playerx + diroffx[k];               y = playery + diroffy[k];
+               if (cgood(x,y,1,0))     /* if we can create here */
+                       {
+                       item[x][y] = it;  know[x][y]=0;  iarg[x][y]=arg;  return;
+                       }
+               }
+       }
+
+/*
+ *     cast()          Subroutine called by parse to cast a spell for the user
+ *
+ *     No arguments and no return value.
+ */
+static char eys[] = "\nEnter your spell: ";
+cast()
+       {
+       register int i,j,a,b,d;
+       cursors();
+       if (c[SPELLS]<=0) {     lprcat("\nYou don't have any spells!"); return; }
+       lprcat(eys);            --c[SPELLS];
+       while ((a=getchar())=='D')
+               { seemagic(-1); cursors();  lprcat(eys); }
+       if (a=='\33') goto over; /*     to escape casting a spell       */
+       if ((b=getchar())=='\33') goto over; /* to escape casting a spell       */
+       if ((d=getchar())=='\33')
+               { over: lprcat(aborted); c[SPELLS]++; return; } /*      to escape casting a spell       */
+#ifdef EXTRA
+       c[SPELLSCAST]++;
+#endif
+       for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
+               if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
+                       if (spelknow[i])
+                               {  speldamage(i);  j = 1;  i=SPNUM; }
+
+       if (j == -1) lprcat("  Nothing Happened ");
+       bottomline();
+       }
+
+static int dirsub();
+
+/*
+ *     speldamage(x)           Function to perform spell functions cast by the player
+ *             int x;
+ *
+ *     Enter with the spell number, returns no value.
+ *     Please insure that there are 2 spaces before all messages here
+ */
+speldamage(x)
+       int x;
+       {
+       register int i,j,clev;
+       int xl,xh,yl,yh;
+       register char *p,*kn,*pm;
+       if (x>=SPNUM) return;   /* no such spell */
+       if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
+       clev = c[LEVEL];
+       if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
+               { lprcat("  It didn't work!");  return; }
+       if (clev*3+2 < x) { lprcat("  Nothing happens.  You seem inexperienced at this"); return; }
+
+       switch(x)
+               {
+/* ----- LEVEL 1 SPELLS ----- */
+
+               case 0: if (c[PROTECTIONTIME]==0)       c[MOREDEFENSES]+=2; /* protection field +2 */
+                               c[PROTECTIONTIME] += 250;   return;
+
+               case 1: i = rnd(((clev+1)<<1)) + clev + 3;
+                               godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
+
+                               return;
+
+               case 2: if (c[DEXCOUNT]==0)     c[DEXTERITY]+=3; /*     dexterity       */
+                               c[DEXCOUNT] += 400;     return;
+
+               case 3: i=rnd(3)+1;
+                               p="  While the %s slept, you smashed it %d times";
+                       ws:     direct(x,fullhit(i),p,i); /*    sleep   */      return;
+
+               case 4: /*      charm monster   */      c[CHARMCOUNT] += c[CHARISMA]<<1;        return;
+
+               case 5: godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /*     sonic spear */
+                               return;
+
+/* ----- LEVEL 2 SPELLS ----- */
+
+               case 6: i=rnd(3)+2;     p="  While the %s is entangled, you hit %d times";
+                               goto ws; /* web */
+
+               case 7: if (c[STRCOUNT]==0) c[STREXTRA]+=3;     /*      strength        */
+                               c[STRCOUNT] += 150+rnd(100);    return;
+
+               case 8: yl = playery-5;     /* enlightenment */
+                               yh = playery+6;   xl = playerx-15;   xh = playerx+16;
+                               vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
+                               for (i=yl; i<=yh; i++) /* enlightenment */
+                                       for (j=xl; j<=xh; j++)  know[j][i]=1;
+                               draws(xl,xh+1,yl,yh+1); return;
+
+               case 9: raisehp(20+(clev<<1));  return;  /* healing */
+
+               case 10:        c[BLINDCOUNT]=0;        return; /* cure blindness       */
+
+               case 11:        createmonster(makemonst(level+1)+8);  return;
+
+               case 12:        if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
+                                       else lprcat("  It didn't believe the illusions!");
+                                       return;
+
+               case 13:        /* if he has the amulet of invisibility then add more time */
+                                       for (j=i=0; i<26; i++)
+                                               if (iven[i]==OAMULET) j+= 1+ivenarg[i];
+                                       c[INVISIBILITY] += (j<<7)+12;   return;
+
+/* ----- LEVEL 3 SPELLS ----- */
+
+               case 14:        godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*        fireball */
+
+               case 15:        godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');        /*      cold */
+                                       return;
+
+               case 16:        dirpoly(x);  return;    /*      polymorph */
+
+               case 17:        c[CANCELLATION]+= 5+clev;       return; /*      cancellation    */
+
+               case 18:        c[HASTESELF]+= 7+clev;  return;  /*     haste self      */
+
+               case 19:        omnidirect(x,30+rnd(10),"  The %s gasps for air");      /* cloud kill */
+                                       return;
+
+               case 20:        xh = min(playerx+1,MAXX-2);             yh = min(playery+1,MAXY-2);
+                                       for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
+                                         for (j=max(playery-1,1); j<=yh; j++)
+                                               {
+                                               kn = &know[i][j];    pm = &mitem[i][j];
+                                               switch(*(p= &item[i][j]))
+                                                 {
+                                                 case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
+                                                                                       *p = *kn = 0;
+                                                                               break;
+
+                                                 case OSTATUE: if (c[HARDGAME]<3)
+                                                                                        {
+                                                                                        *p=OBOOK; iarg[i][j]=level;  *kn=0;
+                                                                                        }
+                                                                               break;
+       
+                                                 case OTHRONE: *pm=GNOMEKING;  *kn=0;  *p= OTHRONE2;
+                                                                               hitp[i][j]=monster[GNOMEKING].hitpoints; break;
+
+                                                 case OALTAR:  *pm=DEMONPRINCE;  *kn=0;
+                                                                               hitp[i][j]=monster[DEMONPRINCE].hitpoints; break;
+                                                 };
+                                               switch(*pm)
+                                                       {
+                                                       case XORN:      ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
+                                                       }
+                                               }
+                                       return;
+
+/* ----- LEVEL 4 SPELLS ----- */
+
+               case 21:        direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
+                                       return;
+
+               case 22:        godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');        /*      lightning */
+                                       return;
+
+               case 23:        i=min(c[HP]-1,c[HPMAX]/2);      /* drain life */
+                                       direct(x,i+i,"",0);     c[HP] -= i;     return;
+
+               case 24:        if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
+                                       c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
+                                       return;
+
+               case 25:        omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
+                                       return;
+
+               case 26:        if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
+                                       if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
+                                       else lprcat("  It didn't work"); return;
+
+/* ----- LEVEL 5 SPELLS ----- */
+
+               case 27:        c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
+
+               case 28:        c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
+
+               case 29:        c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
+
+               case 30:        tdirect(x);  return;  /* teleport away */
+
+               case 31:        omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
+                                       return;
+
+/* ----- LEVEL 6 SPELLS ----- */
+
+               case 32:        if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
+                                               {
+                                               beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
+                                               nap(4000);  died(258); return;
+                                               }
+                                       xl=playerx; yl=playery;
+                                       loseint();
+                                       i=dirsub(&xl,&yl); /* get direction of sphere */
+                                       newsphere(xl,yl,i,rnd(20)+11);  /* make a sphere */
+                                       return;
+
+               case 33:        genmonst();  spelknow[33]=0;  /* genocide */
+                                       loseint();
+                                       return;
+
+               case 34:        /* summon demon */
+                                       if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
+                                       if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
+                                       lprcat("  The demon turned on you and vanished!"); beep();
+                                       i=rnd(40)+30;  lastnum=277;
+                                       losehp(i); /* must say killed by a demon */ return;
+
+               case 35:        /* walk through walls */
+                                       c[WTW] += rnd(10)+5;    return;
+
+               case 36:        /* alter reality */
+                                       {
+                                       struct isave *save;     /* pointer to item save structure */
+                                       int sc; sc=0;   /* # items saved */
+                                       save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
+                                       for (j=0; j<MAXY; j++)
+                                               for (i=0; i<MAXX; i++) /* save all items and monsters */
+                                                       {
+                                                       xl = item[i][j];
+                                                       if (xl && xl!=OWALL && xl!=OANNIHILATION) 
+                                                               {
+                                                               save[sc].type=0;  save[sc].id=item[i][j];
+                                                               save[sc++].arg=iarg[i][j];
+                                                               }
+                                                       if (mitem[i][j]) 
+                                                               {
+                                                               save[sc].type=1;  save[sc].id=mitem[i][j];
+                                                               save[sc++].arg=hitp[i][j];
+                                                               }
+                                                       item[i][j]=OWALL;   mitem[i][j]=0;
+                                                       if (wizard) know[i][j]=1; else know[i][j]=0;
+                                                       }
+                                       eat(1,1);       if (level==1) item[33][MAXY-1]=0;
+                                       for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
+                                       while (sc>0) /* put objects back in level */
+                                               {
+                                               --sc;
+                                               if (save[sc].type == 0)
+                                                       {
+                                                       int trys;
+                                                       for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
+                                                       if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
+                                                       }
+                                               else
+                                                       { /* put monsters back in */
+                                                       int trys;
+                                                       for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
+                                                       if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
+                                                       }
+                                               }
+                                       loseint();
+                                       draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
+                                       free((char*)save);       positionplayer();  return;
+                                       }
+
+               case 37:        /* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
+                                       loseint();
+                                       return;
+
+               default:        lprintf("  spell %d not available!",(long)x); beep();  return;
+               };
+       }
+
+/*
+ *     loseint()               Routine to subtract 1 from your int (intelligence) if > 3
+ *
+ *     No arguments and no return value
+ */
+loseint()
+       {
+       if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
+       }
+
+/*
+ *     isconfuse()             Routine to check to see if player is confused
+ *
+ *     This routine prints out a message saying "You can't aim your magic!"
+ *     returns 0 if not confused, non-zero (time remaining confused) if confused
+ */
+isconfuse()
+       {
+       if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
+       return(c[CONFUSE]);
+       }
+
+/*
+ *     nospell(x,monst)        Routine to return 1 if a spell doesn't affect a monster
+ *             int x,monst;
+ *
+ *     Subroutine to return 1 if the spell can't affect the monster
+ *       otherwise returns 0
+ *     Enter with the spell number in x, and the monster number in monst.
+ */
+nospell(x,monst)
+       int x,monst;
+       {
+       register int tmp;
+       if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0); /* bad spell or monst */
+       if ((tmp=spelweird[monst-1][x])==0) return(0);
+       cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
+       }
+
+/*
+ *     fullhit(xx)             Function to return full damage against a monster (aka web)
+ *             int xx;
+ *
+ *     Function to return hp damage to monster due to a number of full hits
+ *     Enter with the number of full hits being done
+ */
+fullhit(xx)
+       int xx;
+       {
+       register int i;
+       if (xx<0 || xx>20) return(0);   /* fullhits are out of range */
+       if (c[LANCEDEATH]) return(10000);       /* lance of death */
+       i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]); 
+       return( (i>=1) ? i : xx );
+       }
+
+/*
+ *     direct(spnum,dam,str,arg)       Routine to direct spell damage 1 square in 1 dir
+ *             int spnum,dam,arg;
+ *             char *str;
+ *
+ *     Routine to ask for a direction to a spell and then hit the monster
+ *     Enter with the spell number in spnum, the damage to be done in dam,
+ *       lprintf format string in str, and lprintf's argument in arg.
+ *     Returns no value.
+ */
+direct(spnum,dam,str,arg)
+       int spnum,dam,arg;
+       char *str;
+       {
+       int x,y;
+       register int m;
+       if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
+       if (isconfuse()) return;
+       dirsub(&x,&y);
+       m = mitem[x][y];
+       if (item[x][y]==OMIRROR)
+               {
+               if (spnum==3) /* sleep */
+                       {
+                       lprcat("You fall asleep! "); beep();
+               fool:
+                       arg += 2;
+                       while (arg-- > 0) { parse2(); nap(1000); }
+                       return;
+                       }
+               else if (spnum==6) /* web */
+                       {
+                       lprcat("You get stuck in your own web! "); beep();
+                       goto fool;
+                       }
+               else
+                       {
+                       lastnum=278; 
+                       lprintf(str,"spell caster (thats you)",(long)arg);
+                       beep(); losehp(dam); return;
+                       }
+               }
+       if (m==0)
+               {       lprcat("  There wasn't anything there!");       return;  }
+       ifblind(x,y);
+       if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
+       lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
+       }
+
+/*
+ *     godirect(spnum,dam,str,delay,cshow)             Function to perform missile attacks
+ *             int spnum,dam,delay;
+ *             char *str,cshow;
+ *
+ *     Function to hit in a direction from a missile weapon and have it keep
+ *     on going in that direction until its power is exhausted
+ *     Enter with the spell number in spnum, the power of the weapon in hp,
+ *       lprintf format string in str, the # of milliseconds to delay between 
+ *       locations in delay, and the character to represent the weapon in cshow.
+ *     Returns no value.
+ */
+godirect(spnum,dam,str,delay,cshow)
+       int spnum,dam,delay;
+       char *str,cshow;
+       {
+       register char *p;
+       register int x,y,m;
+       int dx,dy;
+       if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
+       if (isconfuse()) return;
+       dirsub(&dx,&dy);        x=dx;   y=dy;
+       dx = x-playerx;         dy = y-playery;         x = playerx;    y = playery;
+       while (dam>0)
+               {
+               x += dx;    y += dy;
+           if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
+                       {
+                       dam=0;  break;  /* out of bounds */
+                       }
+               if ((x==playerx) && (y==playery)) /* if energy hits player */
+                       {
+                       cursors(); lprcat("\nYou are hit my your own magic!"); beep();
+                       lastnum=278;  losehp(dam);  return;
+                       }
+               if (c[BLINDCOUNT]==0) /* if not blind show effect */
+                       {
+                       cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
+                       }
+               if ((m=mitem[x][y]))    /* is there a monster there? */
+                       {
+                       ifblind(x,y);
+                       if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
+                       cursors(); lprc('\n');
+                       lprintf(str,lastmonst);         dam -= hitm(x,y,dam);
+                       show1cell(x,y);  nap(1000);             x -= dx;        y -= dy;
+                       }
+               else switch (*(p= &item[x][y]))
+                       {
+                       case OWALL:     cursors(); lprc('\n'); lprintf(str,"wall");
+                                               if (dam>=50+c[HARDGAME]) /* enough damage? */
+                                                if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
+                                                 if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
+                                                       {
+                                                       lprcat("  The wall crumbles");
+                                       god3:   *p=0;
+                                       god:    know[x][y]=0;
+                                                       show1cell(x,y);
+                                                       }
+                               god2:   dam = 0;        break;
+
+                       case OCLOSEDDOOR:       cursors(); lprc('\n'); lprintf(str,"door");
+                                               if (dam>=40)
+                                                       {
+                                                       lprcat("  The door is blasted apart");
+                                                       goto god3;
+                                                       }
+                                               goto god2;
+
+                       case OSTATUE:   cursors(); lprc('\n'); lprintf(str,"statue");
+                                               if (c[HARDGAME]<3)
+                                                 if (dam>44)
+                                                       {
+                                                       lprcat("  The statue crumbles");
+                                                       *p=OBOOK; iarg[x][y]=level;
+                                                       goto god;
+                                                       }
+                                               goto god2;
+
+                       case OTHRONE:   cursors(); lprc('\n'); lprintf(str,"throne");
+                                       if (dam>39)
+                                               {
+                                               mitem[x][y]=GNOMEKING; hitp[x][y]=monster[GNOMEKING].hitpoints;
+                                               *p = OTHRONE2;
+                                               goto god;
+                                               }
+                                       goto god2;
+
+                       case OMIRROR:   dx *= -1;       dy *= -1;       break;
+                       };
+               dam -= 3 + (c[HARDGAME]>>1);
+               }
+       }
+
+/*
+ *     ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
+ *             int x,y;
+ *
+ *     Subroutine to copy the word "monster" into lastmonst if the player is blind
+ *     Enter with the coordinates (x,y) of the monster
+ *     Returns no value.
+ */
+ifblind(x,y)
+       int x,y;
+       {
+       char *p;
+       vxy(&x,&y);     /* verify correct x,y coordinates */
+       if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
+               else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
+       strcpy(lastmonst,p);
+       }
+
+/*
+ *     tdirect(spnum)          Routine to teleport away a monster
+ *             int spnum;
+ *
+ *     Routine to ask for a direction to a spell and then teleport away monster
+ *     Enter with the spell number that wants to teleport away
+ *     Returns no value.
+ */
+tdirect(spnum)
+       int spnum;
+       {
+       int x,y;
+       register int m;
+       if (spnum<0 || spnum>=SPNUM) return; /* bad args */
+       if (isconfuse()) return;
+       dirsub(&x,&y);
+       if ((m=mitem[x][y])==0)
+               {       lprcat("  There wasn't anything there!");       return;  }
+       ifblind(x,y);
+       if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
+       fillmonst(m);  mitem[x][y]=know[x][y]=0;
+       }
+
+/*
+ *     omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
+ *             int sp,dam;
+ *             char *str;
+ *
+ *     Routine to cast a spell and then hit the monster in all directions
+ *     Enter with the spell number in sp, the damage done to wach square in dam,
+ *       and the lprintf string to identify the spell in str.
+ *     Returns no value.
+ */
+omnidirect(spnum,dam,str)
+       int spnum,dam;
+       char *str;
+       {
+       register int x,y,m;
+       if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
+       for (x=playerx-1; x<playerx+2; x++)
+               for (y=playery-1; y<playery+2; y++)
+                       {
+                       if (m=mitem[x][y])
+                               if (nospell(spnum,m) == 0)
+                                       {
+                                       ifblind(x,y);
+                                       cursors(); lprc('\n'); lprintf(str,lastmonst);
+                                       hitm(x,y,dam);  nap(800);
+                                       }
+                               else  { lasthx=x;  lasthy=y; }
+                       }
+       }
+
+/*
+ *     static dirsub(x,y)              Routine to ask for direction, then modify x,y for it
+ *             int *x,*y;
+ *
+ *     Function to ask for a direction and modify an x,y for that direction
+ *     Enter with the origination coordinates in (x,y).
+ *     Returns index into diroffx[] (0-8).
+ */
+static int
+dirsub(x,y)
+       int *x,*y;
+       {
+       register int i;
+       lprcat("\nIn What Direction? ");
+       for (i=0; ; )
+               switch(getchar())
+                       {
+                       case 'b':       i++;
+                       case 'n':       i++;    
+                       case 'y':       i++;    
+                       case 'u':       i++;
+                       case 'h':       i++;    
+                       case 'k':       i++;
+                       case 'l':       i++;    
+                       case 'j':       i++;            goto out;
+                       };
+out:
+       *x = playerx+diroffx[i];                *y = playery+diroffy[i];
+       vxy(x,y);  return(i);
+       }
+
+/*
+ *     vxy(x,y)           Routine to verify/fix coordinates for being within bounds
+ *             int *x,*y;
+ *
+ *     Function to verify x & y are within the bounds for a level
+ *     If *x or *y is not within the absolute bounds for a level, fix them so that
+ *       they are on the level.
+ *     Returns TRUE if it was out of bounds, and the *x & *y in the calling
+ *     routine are affected.
+ */
+vxy(x,y)
+       int *x,*y;
+       {
+       int flag=0;
+       if (*x<0) { *x=0; flag++; }
+       if (*y<0) { *y=0; flag++; }
+       if (*x>=MAXX) { *x=MAXX-1; flag++; }
+       if (*y>=MAXY) { *y=MAXY-1; flag++; }
+       return(flag);
+       }
+
+/*
+ *     dirpoly(spnum)          Routine to ask for a direction and polymorph a monst
+ *             int spnum;
+ *
+ *     Subroutine to polymorph a monster and ask for the direction its in
+ *     Enter with the spell number in spmun.
+ *     Returns no value.
+ */
+dirpoly(spnum)
+       int spnum;
+       {
+       int x,y,m;
+       if (spnum<0 || spnum>=SPNUM) return; /* bad args */
+       if (isconfuse()) return;        /* if he is confused, he can't aim his magic */
+       dirsub(&x,&y);
+       if (mitem[x][y]==0)
+               {       lprcat("  There wasn't anything there!");       return;  }
+       ifblind(x,y);
+       if (nospell(spnum,mitem[x][y])) { lasthx=x;  lasthy=y; return; }
+       while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
+       hitp[x][y] = monster[m].hitpoints;
+       show1cell(x,y);  /* show the new monster */
+       }
+
+/*
+ *     hitmonster(x,y)         Function to hit a monster at the designated coordinates
+ *             int x,y;
+ *
+ *     This routine is used for a bash & slash type attack on a monster
+ *     Enter with the coordinates of the monster in (x,y).
+ *     Returns no value.
+ */
+hitmonster(x,y)
+       int x,y;
+       {
+       register int tmp,monst,damag,flag;
+       if (c[TIMESTOP])  return;  /* not if time stopped */
+       vxy(&x,&y);     /* verify coordinates are within range */
+       if ((monst = mitem[x][y]) == 0) return;
+       hit3flag=1;  ifblind(x,y);
+       tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS]/4 - 12;
+       cursors();
+       if ((rnd(20) < tmp-c[HARDGAME]) || (rnd(71) < 5)) /* need at least random chance to hit */
+               {
+               lprcat("\nYou hit");  flag=1;
+               damag = fullhit(1);  
+               if (damag<9999) damag=rnd(damag)+1;
+               }
+       else
+               {
+               lprcat("\nYou missed");  flag=0;
+               }
+       lprcat(" the "); lprcat(lastmonst);
+       if (flag)       /* if the monster was hit */
+         if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
+               if (c[WIELD]>0)
+                 if (ivenarg[c[WIELD]] > -10)
+                       {
+                       lprintf("\nYour weapon is dulled by the %s",lastmonst); beep();
+                       --ivenarg[c[WIELD]];
+                       }
+       if (flag)  hitm(x,y,damag);
+       if (monst == VAMPIRE) if (hitp[x][y]<25)  { mitem[x][y]=BAT; know[x][y]=0; }
+       }
+
+/*
+ *     hitm(x,y,amt)           Function to just hit a monster at a given coordinates
+ *             int x,y,amt;
+ *
+ *     Returns the number of hitpoints the monster absorbed
+ *     This routine is used to specifically damage a monster at a location (x,y)
+ *     Called by hitmonster(x,y)
+ */
+hitm(x,y,amt)
+       int x,y;
+       register amt;
+       {
+       register int monst;
+       int hpoints,amt2;
+       vxy(&x,&y);     /* verify coordinates are within range */
+       amt2 = amt;             /* save initial damage so we can return it */
+       monst = mitem[x][y];
+       if (c[HALFDAM]) amt >>= 1;      /* if half damage curse adjust damage points */
+       if (amt<=0) amt2 = amt = 1;
+       lasthx=x;  lasthy=y;
+       stealth[x][y]=1;        /* make sure hitting monst breaks stealth condition */
+       c[HOLDMONST]=0; /* hit a monster breaks hold monster spell      */
+       switch(monst) /* if a dragon and orb(s) of dragon slaying       */
+               {
+               case WHITEDRAGON:               case REDDRAGON:                 case GREENDRAGON:
+               case BRONZEDRAGON:              case PLATINUMDRAGON:    case SILVERDRAGON:
+                       amt *= 1+(c[SLAYING]<<1);       break;
+               }
+/* invincible monster fix is here */
+       if (hitp[x][y] > monster[monst].hitpoints)
+               hitp[x][y] = monster[monst].hitpoints;
+       if ((hpoints = hitp[x][y]) <= amt)
+               {
+#ifdef EXTRA
+               c[MONSTKILLED]++;
+#endif
+               lprintf("\nThe %s died!",lastmonst);
+               raiseexperience((long)monster[monst].experience);
+               amt = monster[monst].gold;  if (amt>0) dropgold(rnd(amt)+amt);
+               dropsomething(monst);   disappear(x,y); bottomline();
+               return(hpoints);
+               }
+       hitp[x][y] = hpoints-amt;       return(amt2);
+       }
+
+/*
+ *     hitplayer(x,y)          Function for the monster to hit the player from (x,y)
+ *             int x,y;
+ *
+ *     Function for the monster to hit the player with monster at location x,y
+ *     Returns nothing of value.
+ */
+hitplayer(x,y)
+       int x,y;
+       {
+       register int dam,tmp,mster,bias;
+       vxy(&x,&y);     /* verify coordinates are within range */
+       lastnum = mster = mitem[x][y];
+/*     spirit naga's and poltergeist's do nothing if scarab of negate spirit   */
+       if (c[NEGATESPIRIT] || c[SPIRITPRO])  if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA))  return;
+/*     if undead and cube of undead control    */
+       if (c[CUBEofUNDEAD] || c[UNDEADPRO]) if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) return;
+       if ((know[x][y]&1) == 0)
+               {
+               know[x][y]=1; show1cell(x,y);
+               }
+       bias = (c[HARDGAME]) + 1;
+       hitflag = hit2flag = hit3flag = 1;
+       yrepcount=0;
+       cursors();      ifblind(x,y);
+       if (c[INVISIBILITY]) if (rnd(33)<20) 
+               {
+               lprintf("\nThe %s misses wildly",lastmonst);    return;
+               }
+       if (c[CHARMCOUNT]) if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30)
+               {
+               lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
+               return;
+               }
+       if (mster==BAT) dam=1;
+       else
+               {
+               dam = monster[mster].damage;
+               dam += rnd((int)((dam<1)?1:dam)) + monster[mster].level;
+               }
+       tmp = 0;
+       if (monster[mster].attack>0)
+         if (((dam + bias + 8) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
+               { if (spattack(monster[mster].attack,x,y)) { flushall(); return; }
+                 tmp = 1;  bias -= 2; cursors(); }
+       if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
+               {
+               lprintf("\n  The %s hit you ",lastmonst);       tmp = 1;
+               if ((dam -= c[AC]) < 0) dam=0;
+               if (dam > 0) { losehp(dam); bottomhp(); flushall(); }
+               }
+       if (tmp == 0)  lprintf("\n  The %s missed ",lastmonst);
+       }
+
+/*
+ *     dropsomething(monst)    Function to create an object when a monster dies
+ *             int monst;
+ *
+ *     Function to create an object near the player when certain monsters are killed
+ *     Enter with the monster number
+ *     Returns nothing of value.
+ */
+dropsomething(monst)
+       int monst;
+       {
+       switch(monst)
+               {
+               case ORC:                         case NYMPH:      case ELF:      case TROGLODYTE:
+               case TROLL:                       case ROTHE:      case VIOLETFUNGI:
+               case PLATINUMDRAGON:  case GNOMEKING:  case REDDRAGON:
+                       something(level); return;
+
+               case LEPRECHAUN: if (rnd(101)>=75) creategem();
+                                                if (rnd(5)==1) dropsomething(LEPRECHAUN);   return;
+               }
+       }
+
+/*
+ *     dropgold(amount)        Function to drop some gold around player
+ *             int amount;
+ *
+ *     Enter with the number of gold pieces to drop
+ *     Returns nothing of value.
+ */
+dropgold(amount)
+       register int amount;
+       {
+       if (amount > 250) createitem(OMAXGOLD,amount/100);  else  createitem(OGOLDPILE,amount);
+       }
+
+/*
+ *     something(level)        Function to create a random item around player
+ *             int level;
+ *
+ *     Function to create an item from a designed probability around player
+ *     Enter with the cave level on which something is to be dropped
+ *     Returns nothing of value.
+ */
+something(level)
+       int level;
+       {
+       register int j;
+       int i;
+       if (level<0 || level>MAXLEVEL+MAXVLEVEL) return;        /* correct level? */
+       if (rnd(101)<8) something(level); /* possibly more than one item */
+       j = newobject(level,&i);                createitem(j,i);
+       }
+
+/*
+ *     newobject(lev,i)        Routine to return a randomly selected new object
+ *             int lev,*i;
+ *
+ *     Routine to return a randomly selected object to be created
+ *     Returns the object number created, and sets *i for its argument
+ *     Enter with the cave level and a pointer to the items arg
+ */
+static char nobjtab[] = { 0, OSCROLL,  OSCROLL,  OSCROLL,  OSCROLL, OPOTION,
+       OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE, 
+       OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
+       OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
+       OBELT, ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
+       OLONGSWORD };
+
+newobject(lev,i)
+       register int lev,*i;
+       {
+       register int tmp=32,j;
+       if (level<0 || level>MAXLEVEL+MAXVLEVEL) return(0);     /* correct level? */
+       if (lev>6) tmp=37; else if (lev>4) tmp=35; 
+       j = nobjtab[tmp=rnd(tmp)];      /* the object type */
+       switch(tmp)
+               {
+               case 1: case 2: case 3: case 4: *i=newscroll(); break;
+               case 5: case 6: case 7: case 8: *i=newpotion(); break;
+               case 9: case 10: case 11: case 12: *i=rnd((lev+1)*10)+lev*10+10; break;
+               case 13: case 14: case 15: case 16:     *i=lev; break;
+               case 17: case 18: case 19: if (!(*i=newdagger()))  return(0);  break;
+               case 20: case 21: case 22: if (!(*i=newleather()))  return(0);  break;
+               case 23: case 32: case 35: *i=rund(lev/3+1); break;
+               case 24: case 26: *i=rnd(lev/4+1);   break;
+               case 25: *i=rund(lev/4+1); break;
+               case 27: *i=rnd(lev/2+1);   break;
+               case 30: case 33: *i=rund(lev/2+1);   break;
+               case 28: *i=rund(lev/3+1); if (*i==0) return(0); break;
+               case 29: case 31: *i=rund(lev/2+1); if (*i==0) return(0); break;
+               case 34: *i=newchain();         break;
+               case 36: *i=newplate();         break;
+               case 37: *i=newsword();         break; 
+               }
+       return(j);
+       }
+
+/*
+ *  spattack(atckno,xx,yy)     Function to process special attacks from monsters
+ *     int atckno,xx,yy;
+ *
+ *     Enter with the special attack number, and the coordinates (xx,yy)
+ *             of the monster that is special attacking
+ *     Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
+ *
+ * atckno   monster     effect
+ * ---------------------------------------------------
+ *     0       none
+ *     1       rust monster    eat armor
+ *     2       hell hound              breathe light fire
+ *     3       dragon                  breathe fire
+ *     4       giant centipede weakening sing
+ *     5       white dragon    cold breath
+ *     6       wraith                  drain level
+ *     7       waterlord               water gusher
+ *     8       leprechaun              steal gold
+ *     9       disenchantress  disenchant weapon or armor
+ *     10      ice lizard              hits with barbed tail
+ *     11      umber hulk              confusion
+ *     12      spirit naga             cast spells     taken from special attacks
+ *     13      platinum dragon psionics
+ *     14      nymph                   steal objects
+ *     15      bugbear                 bite
+ *     16      osequip                 bite
+ *
+ *     char rustarm[ARMORTYPES][2];
+ *     special array for maximum rust damage to armor from rustmonster
+ *     format is: { armor type , minimum attribute 
+ */
+#define ARMORTYPES 6
+static char rustarm[ARMORTYPES][2] = { OSTUDLEATHER,-2,        ORING,-4, OCHAIN,-5,
+       OSPLINT,-6,             OPLATE,-8,              OPLATEARMOR,-9  };
+static char spsel[] = { 1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
+spattack(x,xx,yy)
+       int x,xx,yy;
+       {
+       register int i,j=0,k,m;
+       register char *p=0;
+       if (c[CANCELLATION]) return(0);
+       vxy(&xx,&yy);   /* verify x & y coordinates */
+       switch(x)
+               {
+               case 1: /* rust your armor, j=1 when rusting has occurred */
+                               m = k = c[WEAR];
+                               if ((i=c[SHIELD]) != -1)
+                                       if (--ivenarg[i] < -1) ivenarg[i]= -1; else j=1;
+                               if ((j==0) && (k != -1))
+                                 {
+                                 m = iven[k];
+                                 for (i=0; i<ARMORTYPES; i++)
+                                       if (m == rustarm[i][0]) /* find his armor in table */
+                                               {
+                                               if (--ivenarg[k]< rustarm[i][1])
+                                                       ivenarg[k]= rustarm[i][1]; else j=1; 
+                                               break;
+                                               }
+                                 }
+                               if (j==0)       /* if rusting did not occur */
+                                 switch(m)
+                                       {
+                                       case OLEATHER:  p = "\nThe %s hit you -- Your lucky you have leather on";
+                                                                       break;
+                                   case OSSPLATE:      p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
+                                                                       break;
+                                       }
+                               else  { beep(); p = "\nThe %s hit you -- your armor feels weaker"; }
+                               break;
+
+               case 2:         i = rnd(15)+8-c[AC];
+                       spout:  p="\nThe %s breathes fire at you!";
+                                       if (c[FIRERESISTANCE])
+                                         p="\nThe %s's flame doesn't phase you!";
+                                       else
+                       spout2: if (p) { lprintf(p,lastmonst); beep(); }
+                                       checkloss(i);
+                                       return(0);
+
+               case 3:         i = rnd(20)+25-c[AC];  goto spout;
+
+               case 4: if (c[STRENGTH]>3)
+                                       {
+                                       p="\nThe %s stung you!  You feel weaker"; beep();
+                                       --c[STRENGTH];
+                                       }
+                               else p="\nThe %s stung you!";
+                               break;
+
+               case 5:         p="\nThe %s blasts you with his cold breath";
+                                       i = rnd(15)+18-c[AC];  goto spout2;
+
+               case 6:         lprintf("\nThe %s drains you of your life energy!",lastmonst);
+                                       loselevel();  beep();  return(0);
+
+               case 7:         p="\nThe %s got you with a gusher!";
+                                       i = rnd(15)+25-c[AC];  goto spout2;
+
+               case 8:         if (c[NOTHEFT]) return(0); /* he has a device of no theft */
+                                       if (c[GOLD])
+                                               {
+                                               p="\nThe %s hit you -- Your purse feels lighter";
+                                               if (c[GOLD]>32767)  c[GOLD]>>=1;
+                                                       else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
+                                               if (c[GOLD] < 0) c[GOLD]=0;
+                                               }
+                                       else  p="\nThe %s couldn't find any gold to steal";
+                                       lprintf(p,lastmonst); disappear(xx,yy); beep();
+                                       bottomgold();  return(1);
+
+               case 9: for(j=50; ; )   /* disenchant */
+                                       {
+                                       i=rund(26);  m=iven[i]; /* randomly select item */
+                                       if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
+                                               {
+                                               if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
+                                               lprintf("\nThe %s hits you -- you feel a sense of loss",lastmonst);
+                                               srcount=0; beep(); show3(i);  bottomline();  return(0);
+                                               }
+                                       if (--j<=0)
+                                               {
+                                               p="\nThe %s nearly misses"; break;
+                                               }
+                                       break;
+                                       }               
+                               break;
+
+               case 10:   p="\nThe %s hit you with his barbed tail";
+                                  i = rnd(25)-c[AC];  goto spout2;
+
+               case 11:        p="\nThe %s has confused you"; beep();
+                                       c[CONFUSE]+= 10+rnd(10);                break;
+
+               case 12:        /*      performs any number of other special attacks    */
+                                       return(spattack(spsel[rund(10)],xx,yy));
+
+               case 13:        p="\nThe %s flattens you with his psionics!";
+                                       i = rnd(15)+30-c[AC];  goto spout2;
+
+               case 14:        if (c[NOTHEFT]) return(0); /* he has device of no theft */
+                                       if (emptyhanded()==1)
+                                         {
+                                         p="\nThe %s couldn't find anything to steal";
+                                         break;
+                                         }
+                                       lprintf("\nThe %s picks your pocket and takes:",lastmonst);
+                                       beep();
+                                       if (stealsomething()==0) lprcat("  nothing"); disappear(xx,yy);
+                                       bottomline();  return(1);
+
+               case 15:        i= rnd(10)+ 5-c[AC];
+                       spout3: p="\nThe %s bit you!";
+                                       goto spout2;
+
+               case 16:        i= rnd(15)+10-c[AC];  goto spout3;
+               };
+       if (p) { lprintf(p,lastmonst); bottomline(); }
+       return(0);
+       }
+
+/*
+ *     checkloss(x)    Routine to subtract hp from user and flag bottomline display
+ *             int x;
+ *
+ *     Routine to subtract hitpoints from the user and flag the bottomline display
+ *     Enter with the number of hit points to lose
+ *     Note: if x > c[HP] this routine could kill the player!
+ */
+checkloss(x)
+       int x;
+       {
+       if (x>0) { losehp(x);  bottomhp(); }
+       }
+
+/*
+ *     annihilate()    Routine to annihilate all monsters around player (playerx,playery)
+ *
+ *     Gives player experience, but no dropped objects
+ *     Returns the experience gained from all monsters killed
+ */
+annihilate()
+       {
+       int i,j;
+       register long k;
+       register char *p;
+       for (k=0, i=playerx-1; i<=playerx+1; i++)
+         for (j=playery-1; j<=playery+1; j++)
+               if (!vxy(&i,&j)) /* if not out of bounds */
+                       if (*(p= &mitem[i][j])) /* if a monster there */
+                               if (*p<DEMONLORD+2)
+                                       {
+                                       k += monster[*p].experience;    *p=know[i][j]=0;
+                                       }
+                               else
+                                       {
+                                       lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
+                                       hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
+                                       }
+       if (k>0)
+               {
+               lprcat("\nYou hear loud screams of agony!");    raiseexperience((long)k);
+               }
+       return(k);
+       }
+
+/*
+ *     newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
+ *             int x,y,dir,lifetime;
+ *
+ *     Enter with the coordinates of the sphere in x,y
+ *       the direction (0-8 diroffx format) in dir, and the lifespan of the
+ *       sphere in lifetime (in turns)
+ *     Returns the number of spheres currently in existence
+ */
+newsphere(x,y,dir,life)
+       int x,y,dir,life;
+       {
+       int m;
+       struct sphere *sp;
+       if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
+               return(c[SPHCAST]);     /* can't malloc, therefore failure */
+       if (dir>=9) dir=0;      /* no movement if direction not found */
+       if (level==0) vxy(&x,&y);       /* don't go out of bounds */
+       else
+               {
+               if (x<1) x=1;  if (x>=MAXX-1) x=MAXX-2;
+               if (y<1) y=1;  if (y>=MAXY-1) y=MAXY-2;
+               }
+       if ((m=mitem[x][y]) >= DEMONLORD+4)     /* demons dispel spheres */
+               {
+               know[x][y]=1; show1cell(x,y);   /* show the demon (ha ha) */
+               cursors(); lprintf("\nThe %s dispels the sphere!",monster[m].name);
+               beep(); rmsphere(x,y);  /* remove any spheres that are here */
+               return(c[SPHCAST]);
+               }
+       if (m==DISENCHANTRESS) /* disenchantress cancels spheres */
+               {
+               cursors(); lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); beep();
+boom:  sphboom(x,y);   /* blow up stuff around sphere */
+               rmsphere(x,y);  /* remove any spheres that are here */
+               return(c[SPHCAST]);
+               }
+       if (c[CANCELLATION]) /* cancellation cancels spheres */
+               {
+               cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
+               goto boom;
+               }
+       if (item[x][y]==OANNIHILATION) /* collision of spheres detonates spheres */
+               {
+               cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
+               rmsphere(x,y);
+               goto boom;
+               }
+       if (playerx==x && playery==y) /* collision of sphere and player! */
+               {
+               cursors();
+               lprcat("\nYou have been enveloped by the zone of nothingness!\n");
+               beep(); rmsphere(x,y);  /* remove any spheres that are here */
+               nap(4000);  died(258);
+               }
+       item[x][y]=OANNIHILATION;  mitem[x][y]=0;  know[x][y]=1;
+       show1cell(x,y); /* show the new sphere */
+       sp->x=x;  sp->y=y;  sp->lev=level;  sp->dir=dir;  sp->lifetime=life;  sp->p=0;
+       if (spheres==0) spheres=sp;     /* if first node in the sphere list */
+       else    /* add sphere to beginning of linked list */
+               {
+               sp->p = spheres;        spheres = sp;
+               }
+       return(++c[SPHCAST]);   /* one more sphere in the world */
+       }
+
+/*
+ *     rmsphere(x,y)           Function to delete a sphere of annihilation from list
+ *             int x,y;
+ *
+ *     Enter with the coordinates of the sphere (on current level)
+ *     Returns the number of spheres currently in existence
+ */
+rmsphere(x,y)
+       int x,y;
+       {
+       register struct sphere *sp,*sp2=0;
+       for (sp=spheres; sp; sp2=sp,sp=sp->p)
+         if (level==sp->lev)   /* is sphere on this level? */
+           if ((x==sp->x) && (y==sp->y))       /* locate sphere at this location */
+                       {
+                       item[x][y]=mitem[x][y]=0;  know[x][y]=1;
+                       show1cell(x,y); /* show the now missing sphere */
+                       --c[SPHCAST];   
+                       if (sp==spheres) { sp2=sp; spheres=sp->p; free((char*)sp2); }
+                       else
+                               { sp2->p = sp->p;  free((char*)sp); }
+                       break;
+                       }
+       return(c[SPHCAST]);     /* return number of spheres in the world */
+       }
+
+/*
+ *     sphboom(x,y)    Function to perform the effects of a sphere detonation
+ *             int x,y;
+ *
+ *     Enter with the coordinates of the blast, Returns no value
+ */
+sphboom(x,y)
+       int x,y;
+       {
+       register int i,j;
+       if (c[HOLDMONST]) c[HOLDMONST]=1;
+       if (c[CANCELLATION]) c[CANCELLATION]=1;
+       for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
+         for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
+               {
+               item[j][i]=mitem[j][i]=0;
+               show1cell(j,i);
+               if (playerx==j && playery==i)
+                       {
+                       cursors(); beep();
+                       lprcat("\nYou were too close to the sphere!");
+                       nap(3000);
+                       died(283); /* player killed in explosion */
+                       }
+               }
+       }
+
+/*
+ *     genmonst()              Function to ask for monster and genocide from game
+ *
+ *     This is done by setting a flag in the monster[] structure
+ */
+genmonst()
+       {
+       register int i,j;
+       cursors();  lprcat("\nGenocide what monster? ");
+       for (i=0; (!isalpha(i)) && (i!=' '); i=getchar());
+       lprc(i);
+       for (j=0; j<MAXMONST; j++)      /* search for the monster type */
+               if (monstnamelist[j]==i)        /* have we found it? */
+                       {
+                       monster[j].genocided=1; /* genocided from game */
+                       lprintf("  There will be no more %s's",monster[j].name);
+                       /* now wipe out monsters on this level */
+                       newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
+                       return;
+                       }
+       lprcat("  You sense failure!");
+       }
+
diff --git a/usr/othersrc/games/larn/moreobj.c b/usr/othersrc/games/larn/moreobj.c
new file mode 100644 (file)
index 0000000..f834b1a
--- /dev/null
@@ -0,0 +1,372 @@
+/* moreobj.c           Larn is copyrighted 1986 by Noah Morgan.
+ *
+ *     Routines in this file:
+ *
+ *     oaltar()
+ *     othrone()
+ *     ochest()
+ *     ofountain()
+ */
+#include "header.h"
+
+static void ohear();
+
+/*
+ *     ******
+ *     OALTAR
+ *     ******
+ *
+ *     subroutine to process an altar object
+ */
+oaltar()
+       {
+       unsigned long k;
+
+       lprcat("\nDo you (p) pray  (d) desecrate"); iopts();
+       while (1)
+         {
+         while (1) switch(getchar())
+               {
+               case 'p':       lprcat(" pray\nDo you (m) give money or (j) just pray? ");
+                                       while (1) switch(getchar())
+                                         {
+                                         case 'j':     if (rnd(100)<75) 
+                                                                       lprcat("\nnothing happens");
+                                                               else if (rnd(13)<4) ohear();
+                                                               else if (rnd(43) == 10)
+                                                                       {
+                                                                       if (c[WEAR]) lprcat("\nYou feel your armor vibrate for a moment");
+                                                                       enchantarmor(); return;
+                                                                       }
+                                                               else if (rnd(43) == 10)
+                                                                       {
+                                                                       if (c[WIELD]) lprcat("\nYou feel your weapon vibrate for a moment");
+                                                                       enchweapon(); return;
+                                                                       }
+                                                               else createmonster(makemonst(level+1));
+                                                               return;
+
+                                         case 'm':     lprcat("\n\n");  cursor(1,24);  cltoeoln();
+                                                               cursor(1,23);  cltoeoln();
+                                                               lprcat("how much do you donate? ");
+                                                               k = readnum((long)c[GOLD]);
+                                                               if (c[GOLD]<k)
+                                                                       {
+                                                                       lprcat("\nYou don't have that much!");
+                                                                       return;
+                                                                       }
+                                                               c[GOLD] -= k;
+                                                               if (k < c[GOLD]/10 || k<rnd(50))
+                                                                       { createmonster(makemonst(level+1)); c[AGGRAVATE] += 200; }
+                                                               else if (rnd(101) > 50) { ohear(); return; }
+                                                               else if (rnd(43) == 5)
+                                                                       {
+                                                                       if (c[WEAR]) lprcat("\nYou feel your armor vibrate for a moment");
+                                                                       enchantarmor(); return;
+                                                                       }
+                                                               else if (rnd(43) == 8)
+                                                                       {
+                                                                       if (c[WIELD]) lprcat("\nYou feel your weapon vibrate for a moment");
+                                                                       enchweapon(); return;
+                                                                       }
+                                                               else    lprcat("\nThank You.");
+                                                               bottomline();   return;
+
+                                         case '\33':   return;
+                                         };
+
+               case 'd': lprcat(" desecrate");
+                                 if (rnd(100)<60)
+                                               { createmonster(makemonst(level+2)+8); c[AGGRAVATE] += 2500; }
+                                       else
+                                       if (rnd(101)<30)
+                                               {
+                                               lprcat("\nThe altar crumbles into a pile of dust before your eyes");
+                                               forget();       /*      remember to destroy the altar   */
+                                               }
+                                       else
+                                               lprcat("\nnothing happens");
+                                       return;
+
+               case 'i':
+               case '\33': ignore();
+                                 if (rnd(100)<30)      { createmonster(makemonst(level+1)); c[AGGRAVATE] += rnd(450); }
+                                       else    lprcat("\nnothing happens");
+                                       return;
+               };
+         }
+       }
+
+/*
+       function to cast a +3 protection on the player
+ */
+static void
+ohear()
+       {
+       lprcat("\nYou have been heard!");
+       if (c[ALTPRO]==0) c[MOREDEFENSES]+=3;
+       c[ALTPRO] += 500;       /* protection field */
+       bottomline();
+       }
+
+/*
+       *******
+       OTHRONE
+       *******
+
+       subroutine to process a throne object
+ */
+othrone(arg)
+       int arg;
+       {
+       register int i,k;
+
+       lprcat("\nDo you (p) pry off jewels, (s) sit down"); iopts();
+       while (1)
+         {
+         while (1) switch(getchar())
+               {
+               case 'p':       lprcat(" pry off");  k=rnd(101);
+                                       if (k<25)
+                                               {
+                                               for (i=0; i<rnd(4); i++) creategem(); /* gems pop off the throne */
+                                               item[playerx][playery]=ODEADTHRONE;
+                                               know[playerx][playery]=0;
+                                               }
+                                       else if (k<40 && arg==0)
+                                               {
+                                               createmonster(GNOMEKING);
+                                               item[playerx][playery]=OTHRONE2;
+                                               know[playerx][playery]=0;
+                                               }
+                                       else lprcat("\nnothing happens");
+                                       return;
+
+               case 's':       lprcat(" sit down");  k=rnd(101);
+                                       if (k<30 && arg==0)
+                                               {
+                                               createmonster(GNOMEKING);
+                                               item[playerx][playery]=OTHRONE2;
+                                               know[playerx][playery]=0;
+                                               }
+                                       else if (k<35) { lprcat("\nZaaaappp!  You've been teleported!\n"); beep(); oteleport(0); }
+                                       else lprcat("\nnothing happens");
+                                       return;
+
+               case 'i':
+               case '\33': ignore(); return;
+               };
+         }
+       }
+
+odeadthrone()
+       {
+       register int k;
+
+       lprcat("\nDo you (s) sit down"); iopts();
+       while (1)
+         {
+         while (1) switch(getchar())
+               {
+               case 's':       lprcat(" sit down");  k=rnd(101);
+                                       if (k<35) { lprcat("\nZaaaappp!  You've been teleported!\n"); beep(); oteleport(0); }
+                                       else lprcat("\nnothing happens");
+                                       return;
+
+               case 'i':
+               case '\33': ignore(); return;
+               };
+         }
+       }
+
+/*
+       ******
+       OCHEST
+       ******
+
+       subroutine to process a throne object
+ */
+ochest()
+       {
+       register int i,k;
+       lprcat("\nDo you (t) take it, (o) try to open it"); iopts();
+       while (1)
+         {
+         while (1) switch(getchar())
+               {
+               case 'o':       lprcat(" open it");  k=rnd(101);
+                                       if (k<40)
+                                               {
+                                               lprcat("\nThe chest explodes as you open it"); beep();
+                                               i = rnd(10);  lastnum=281;  /* in case he dies */
+                                               lprintf("\nYou suffer %d hit points damage!",(long)i);
+                                               checkloss(i);
+                                               switch(rnd(10)) /* see if he gets a curse */
+                                                       {
+                                                       case 1: c[ITCHING]+= rnd(1000)+100;
+                                                                       lprcat("\nYou feel an irritation spread over your skin!");
+                                                                       beep();
+                                                                       break;
+
+                                                       case 2: c[CLUMSINESS]+= rnd(1600)+200;
+                                                                       lprcat("\nYou begin to lose hand to eye coordination!");
+                                                                       beep();
+                                                                       break;
+                                                       
+                                                       case 3: c[HALFDAM]+= rnd(1600)+200;
+                                                                       beep();
+                                                                       lprcat("\nA sickness engulfs you!");    break;
+                                                       };
+                                               item[playerx][playery]=know[playerx][playery]=0;
+                                               if (rnd(100)<69) creategem(); /* gems from the chest */
+                                               dropgold(rnd(110*iarg[playerx][playery]+200));
+                                               for (i=0; i<rnd(4); i++) something(iarg[playerx][playery]+2);
+                                               }
+                                       else lprcat("\nnothing happens");
+                                       return;
+
+               case 't':       lprcat(" take");
+                                       if (take(OCHEST,iarg[playerx][playery])==0)
+                                               item[playerx][playery]=know[playerx][playery]=0;
+                                       return;
+
+               case 'i':
+               case '\33': ignore(); return;
+               };
+         }
+       }
+
+/*
+       *********
+       OFOUNTAIN
+       *********
+ */
+
+ofountain()
+       {
+       register int x;
+       cursors();
+       lprcat("\nDo you (d) drink, (w) wash yourself"); iopts();
+       while (1) switch(getchar())
+               {
+               case 'd':       lprcat("drink");
+                                       if (rnd(1501)<2)
+                                               {
+                                               lprcat("\nOops!  You seem to have caught the dreadful sleep!");
+                                               beep(); lflush();  sleep(3);  died(280); return;
+                                               }
+                                       x = rnd(100);
+                                       if (x<7)
+                                               {
+                                               c[HALFDAM] += 200+rnd(200);
+                                               lprcat("\nYou feel a sickness coming on");
+                                               }
+                                       else if (x<13) quaffpotion(23); /* see invisible */
+                                       else if (x < 45)
+                                               lprcat("\nnothing seems to have happened");
+                                       else if (rnd(3) != 2)
+                                               fntchange(1);   /*      change char levels upward       */
+                                       else
+                                               fntchange(-1);  /*      change char levels downward     */
+                                       if (rnd(12)<3)
+                                               {
+                                               lprcat("\nThe fountains bubbling slowly quiets");
+                                               item[playerx][playery]=ODEADFOUNTAIN; /* dead fountain */
+                                               know[playerx][playery]=0;
+                                               }
+                                       return;
+
+               case '\33':
+               case 'i':       ignore();  return;
+
+               case 'w':       lprcat("wash yourself");
+                                       if (rnd(100) < 11)
+                                               {
+                                               x=rnd((level<<2)+2);
+                                               lprintf("\nOh no!  The water was foul!  You suffer %d hit points!",(long)x);
+                                               lastnum=273; losehp(x); bottomline();  cursors();
+                                               }
+                                       else
+                                       if (rnd(100) < 29)
+                                               lprcat("\nYou got the dirt off!");
+                                       else
+                                       if (rnd(100) < 31)
+                                               lprcat("\nThis water seems to be hard water!  The dirt didn't come off!");
+                                       else
+                                       if (rnd(100) < 34)
+                                               createmonster(WATERLORD); /*    make water lord         */
+                                       else
+                                       lprcat("\nnothing seems to have happened");
+                                       return;
+               }
+       }
+
+/*
+       ***
+       FCH
+       ***
+
+       subroutine to process an up/down of a character attribute for ofountain
+ */
+static void
+fch(how,x)
+       int how;
+       long *x;
+       {
+       if (how < 0)     { lprcat(" went down by one!");        --(*x); }
+               else             { lprcat(" went up by one!");  (*x)++; }
+       bottomline();
+       }
+
+/*
+       a subroutine to raise or lower character levels
+       if x > 0 they are raised   if x < 0 they are lowered
+ */
+fntchange(how)
+       int how;
+       {
+       register long j;
+       lprc('\n');
+       switch(rnd(9))
+               {
+               case 1: lprcat("Your strength");                fch(how,&c[0]);         break;
+               case 2: lprcat("Your intelligence");    fch(how,&c[1]);         break;
+               case 3: lprcat("Your wisdom");                  fch(how,&c[2]);         break;
+               case 4: lprcat("Your constitution");    fch(how,&c[3]);         break;
+               case 5: lprcat("Your dexterity");               fch(how,&c[4]);         break;
+               case 6: lprcat("Your charm");                   fch(how,&c[5]);         break;
+               case 7: j=rnd(level+1);
+                               if (how < 0)
+                                       { lprintf("You lose %d hit point",(long)j);  if (j>1) lprcat("s!"); else lprc('!'); losemhp((int)j); }
+                               else
+                                       { lprintf("You gain %d hit point",(long)j);  if (j>1) lprcat("s!"); else lprc('!'); raisemhp((int)j); }
+                               bottomline();           break;
+
+               case 8: j=rnd(level+1);
+                               if (how > 0)
+                                       {
+                                       lprintf("You just gained %d spell",(long)j);  raisemspells((int)j);
+                                       if (j>1) lprcat("s!"); else lprc('!');
+                                       }
+                               else
+                                       {
+                                       lprintf("You just lost %d spell",(long)j);      losemspells((int)j);
+                                       if (j>1) lprcat("s!"); else lprc('!');
+                                       }
+                               bottomline();           break;
+
+               case 9: j = 5*rnd((level+1)*(level+1));
+                               if (how < 0)
+                                       {
+                                       lprintf("You just lost %d experience point",(long)j);
+                                       if (j>1) lprcat("s!"); else lprc('!'); loseexperience((long)j);
+                                       }
+                               else
+                                       {
+                                       lprintf("You just gained %d experience point",(long)j);
+                                       if (j>1) lprcat("s!"); else lprc('!'); raiseexperience((long)j);
+                                       }
+                               break;
+               }
+       cursors();
+       }
diff --git a/usr/othersrc/games/larn/signal.c b/usr/othersrc/games/larn/signal.c
new file mode 100644 (file)
index 0000000..60bd6ce
--- /dev/null
@@ -0,0 +1,148 @@
+#include <signal.h>
+#include "header.h"                    /* "Larn is copyrighted 1986 by Noah Morgan.\n" */
+#define BIT(a) (1<<((a)-1))
+extern char savefilename[],wizard,predostuff,nosignal;
+static s2choose()      /* text to be displayed if ^C during intro screen */
+       {
+       cursor(1,24); lprcat("Press "); setbold(); lprcat("return"); resetbold();
+       lprcat(" to continue: ");   lflush(); 
+       }
+
+static void
+cntlc()        /* what to do for a ^C */
+       {
+       if (nosignal) return;   /* don't do anything if inhibited */
+       signal(SIGQUIT,SIG_IGN);        signal(SIGINT,SIG_IGN);
+       quit(); if (predostuff==1) s2choose(); else showplayer();
+       lflush();
+       signal(SIGQUIT,cntlc);  signal(SIGINT,cntlc);
+       }
+
+/*
+ *     subroutine to save the game if a hangup signal
+ */
+static void
+sgam()
+       {
+       savegame(savefilename);  wizard=1;  died(-257); /* hangup signal */
+       }
+
+#ifdef SIGTSTP
+static void
+tstop() /* control Y   */
+       {
+       if (nosignal)   return;  /* nothing if inhibited */
+       lcreat((char*)0);  clearvt100();        lflush();         signal(SIGTSTP,SIG_DFL);
+#ifdef SIGVTALRM
+       /* looks like BSD4.2 or higher - must clr mask for signal to take effect*/
+       sigsetmask(sigblock(0)& ~BIT(SIGTSTP));
+#endif
+       kill(getpid(),SIGTSTP);
+
+       setupvt100();  signal(SIGTSTP,tstop);
+       if (predostuff==1) s2choose(); else drawscreen();
+       showplayer();   lflush();
+       }
+#endif SIGTSTP
+
+/*
+ *     subroutine to issue the needed signal traps  called from main()
+ */
+static void sigpanic();
+static void sigill()   { sigpanic(SIGILL); }
+static void sigtrap()  { sigpanic(SIGTRAP); }
+static void sigiot()   { sigpanic(SIGIOT); }
+static void sigemt()   { sigpanic(SIGEMT); }
+static void sigfpe()   { sigpanic(SIGFPE); }
+static void sigbus()   { sigpanic(SIGBUS); }
+static void sigsegv()  { sigpanic(SIGSEGV); }
+static void sigsys()   { sigpanic(SIGSYS); }
+static void sigpipe()  { sigpanic(SIGPIPE); }
+static void sigterm()  { sigpanic(SIGTERM); }
+sigsetup()
+       {
+       signal(SIGQUIT, cntlc);                 signal(SIGINT,  cntlc); 
+       signal(SIGKILL, SIG_IGN);               signal(SIGHUP,  sgam);
+       signal(SIGILL,  sigill);                signal(SIGTRAP, sigtrap);
+       signal(SIGIOT,  sigiot);                signal(SIGEMT,  sigemt);
+       signal(SIGFPE,  sigfpe);                signal(SIGBUS,  sigbus);
+       signal(SIGSEGV, sigsegv);               signal(SIGSYS,  sigsys);
+       signal(SIGPIPE, sigpipe);               signal(SIGTERM, sigterm);
+#ifdef SIGTSTP
+       signal(SIGTSTP,tstop);          signal(SIGSTOP,tstop);
+#endif SIGTSTP
+       }
+
+#ifdef BSD     /* for BSD UNIX? */
+
+static char *signame[NSIG] = { "",
+"SIGHUP",  /*  1        hangup */
+"SIGINT",  /*  2        interrupt */
+"SIGQUIT", /*  3        quit */
+"SIGILL",  /*  4        illegal instruction (not reset when caught) */
+"SIGTRAP", /*  5        trace trap (not reset when caught) */
+"SIGIOT",  /*  6        IOT instruction */
+"SIGEMT",  /*  7        EMT instruction */
+"SIGFPE",  /*  8        floating point exception */
+"SIGKILL", /*  9        kill (cannot be caught or ignored) */
+"SIGBUS",  /*  10       bus error */
+"SIGSEGV", /*  11       segmentation violation */
+"SIGSYS",  /*  12       bad argument to system call */
+"SIGPIPE", /*  13       write on a pipe with no one to read it */
+"SIGALRM", /*  14       alarm clock */
+"SIGTERM", /*  15       software termination signal from kill */
+"SIGURG",  /*  16       urgent condition on IO channel */
+"SIGSTOP", /*  17       sendable stop signal not from tty */
+"SIGTSTP", /*  18       stop signal from tty */
+"SIGCONT", /*  19       continue a stopped process */
+"SIGCHLD", /*  20       to parent on child stop or exit */
+"SIGTTIN", /*  21       to readers pgrp upon background tty read */
+"SIGTTOU", /*  22       like TTIN for output if (tp->t_local&LTOSTOP) */
+"SIGIO",   /*  23       input/output possible signal */
+"SIGXCPU", /*  24       exceeded CPU time limit */
+"SIGXFSZ", /*  25       exceeded file size limit */
+"SIGVTALRM",/*  26      virtual time alarm */
+"SIGPROF", /*  27       profiling time alarm */
+"","","","" };
+
+#else BSD      /* for system V? */
+
+static char *signame[NSIG] = { "",
+"SIGHUP",  /*  1        hangup */
+"SIGINT",  /*  2        interrupt */
+"SIGQUIT", /*  3        quit */
+"SIGILL",  /*  4        illegal instruction (not reset when caught) */
+"SIGTRAP", /*  5        trace trap (not reset when caught) */
+"SIGIOT",  /*  6        IOT instruction */
+"SIGEMT",  /*  7        EMT instruction */
+"SIGFPE",  /*  8        floating point exception */
+"SIGKILL", /*  9        kill (cannot be caught or ignored) */
+"SIGBUS",  /*  10       bus error */
+"SIGSEGV", /*  11       segmentation violation */
+"SIGSYS",  /*  12       bad argument to system call */
+"SIGPIPE", /*  13       write on a pipe with no one to read it */
+"SIGALRM", /*  14       alarm clock */
+"SIGTERM", /*  15       software termination signal from kill */
+"SIGUSR1",  /* 16       user defines signal 1 */
+"SIGUSR2", /*  17       user defines signal 2 */
+"SIGCLD",  /*  18       child death */
+"SIGPWR",  /*  19       power fail */
+"","","","","","","","","","","","" };
+
+#endif BSD
+
+/*
+ *     routine to process a fatal error signal
+ */
+static void
+sigpanic(sig)
+       int sig;
+       {
+       char buf[128];
+       signal(sig,SIG_DFL);
+       sprintf(buf,"\nLarn - Panic! Signal %d received [%s]",sig,signame[sig]);
+       write(2,buf,strlen(buf));  sleep(2);
+       sncbr();
+       savegame(savefilename); 
+       kill(getpid(),sig); /* this will terminate us */
+       }