Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / larn / display.c
1 /*      display.c               Larn is copyrighted 1986 by Noah Morgan. */
2 /* $FreeBSD: src/games/larn/display.c,v 1.4 1999/11/16 02:57:21 billf Exp $ */
3 #include "header.h"
4 #define makecode(_a,_b,_c) (((_a)<<16) + ((_b)<<8) + (_c))
5
6 static int minx,maxx,miny,maxy,k,m;
7 static char bot1f=0,bot2f=0,bot3f=0;
8 char always=0;
9 /*
10         bottomline()
11
12         now for the bottom line of the display
13  */
14 bottomline()
15         {       recalc();       bot1f=1;        }
16 bottomhp()
17         {       bot2f=1;        }
18 bottomspell()
19         {       bot3f=1;        }
20 bottomdo()
21         {
22         if (bot1f) { bot3f=bot1f=bot2f=0; bot_linex(); return; }
23         if (bot2f) { bot2f=0; bot_hpx(); }
24         if (bot3f) { bot3f=0; bot_spellx(); }
25         }
26
27 static void botsub();
28
29 bot_linex()
30         {
31         int i;
32         if (cbak[SPELLS] <= -50 || (always))
33                 {
34                 cursor( 1,18);
35                 if (c[SPELLMAX]>99)  lprintf("Spells:%3d(%3d)",(long)c[SPELLS],(long)c[SPELLMAX]);
36                                                 else lprintf("Spells:%3d(%2d) ",(long)c[SPELLS],(long)c[SPELLMAX]);
37                 lprintf(" AC: %-3d  WC: %-3d  Level",(long)c[AC],(long)c[WCLASS]);
38                 if (c[LEVEL]>99) lprintf("%3d",(long)c[LEVEL]);
39                                         else lprintf(" %-2d",(long)c[LEVEL]);
40                 lprintf(" Exp: %-9d %s\n",(long)c[EXPERIENCE],class[c[LEVEL]-1]);
41                 lprintf("HP: %3d(%3d) STR=%-2d INT=%-2d ",
42                         (long)c[HP],(long)c[HPMAX],(long)(c[STRENGTH]+c[STREXTRA]),(long)c[INTELLIGENCE]);
43                 lprintf("WIS=%-2d CON=%-2d DEX=%-2d CHA=%-2d LV:",
44                         (long)c[WISDOM],(long)c[CONSTITUTION],(long)c[DEXTERITY],(long)c[CHARISMA]);
45
46                 if ((level==0) || (wizard))  c[TELEFLAG]=0;
47                 if (c[TELEFLAG])  lprcat(" ?");  else  lprcat(levelname[level]);
48                 lprintf("  Gold: %-6d",(long)c[GOLD]);
49                 always=1;  botside();
50                 c[TMP] = c[STRENGTH]+c[STREXTRA];
51                 for (i=0; i<100; i++) cbak[i]=c[i];
52                 return;
53                 }
54
55         botsub(makecode(SPELLS,8,18),"%3d");
56         if (c[SPELLMAX]>99)  botsub(makecode(SPELLMAX,12,18),"%3d)");
57                                         else botsub(makecode(SPELLMAX,12,18),"%2d) ");
58         botsub(makecode(HP,5,19),"%3d");
59         botsub(makecode(HPMAX,9,19),"%3d");
60         botsub(makecode(AC,21,18),"%-3d");
61         botsub(makecode(WCLASS,30,18),"%-3d");
62         botsub(makecode(EXPERIENCE,49,18),"%-9d");
63         if (c[LEVEL] != cbak[LEVEL])
64                 { cursor(59,18);        lprcat(class[c[LEVEL]-1]);  }
65         if (c[LEVEL]>99) botsub(makecode(LEVEL,40,18),"%3d");
66                                 else botsub(makecode(LEVEL,40,18)," %-2d");
67         c[TMP] = c[STRENGTH]+c[STREXTRA];       botsub(makecode(TMP,18,19),"%-2d");
68         botsub(makecode(INTELLIGENCE,25,19),"%-2d");
69         botsub(makecode(WISDOM,32,19),"%-2d");
70         botsub(makecode(CONSTITUTION,39,19),"%-2d");
71         botsub(makecode(DEXTERITY,46,19),"%-2d");
72         botsub(makecode(CHARISMA,53,19),"%-2d");
73         if ((level != cbak[CAVELEVEL]) || (c[TELEFLAG] != cbak[TELEFLAG]))
74                 {
75                 if ((level==0) || (wizard))  c[TELEFLAG]=0;
76                 cbak[TELEFLAG] = c[TELEFLAG];
77                 cbak[CAVELEVEL] = level;        cursor(59,19);
78                 if (c[TELEFLAG])  lprcat(" ?");  else  lprcat(levelname[level]);
79                 }
80         botsub(makecode(GOLD,69,19),"%-6d");
81         botside();
82         }
83
84 /*
85         special subroutine to update only the gold number on the bottomlines
86         called from ogold()
87  */
88 bottomgold()
89         {
90         botsub(makecode(GOLD,69,19),"%-6d");
91 /*      botsub(GOLD,"%-6d",69,19); */
92         }
93
94 /*
95         special routine to update hp and level fields on bottom lines
96         called in monster.c hitplayer() and spattack()
97  */
98 bot_hpx()
99         {
100         if (c[EXPERIENCE] != cbak[EXPERIENCE])
101                 {
102                 recalc();        bot_linex();
103                 }
104         else botsub(makecode(HP,5,19),"%3d");
105         }
106
107 /*
108         special routine to update number of spells called from regen()
109  */
110 bot_spellx()
111         {
112         botsub(makecode(SPELLS,9,18),"%2d");
113         }
114
115 /*
116         common subroutine for a more economical bottomline()
117  */
118 static struct bot_side_def
119         {
120         int typ;
121         char *string;
122         }
123         bot_data[] =
124         {
125         STEALTH,"stealth",              UNDEADPRO,"undead pro",         SPIRITPRO,"spirit pro",
126         CHARMCOUNT,"Charm",             TIMESTOP,"Time Stop",           HOLDMONST,"Hold Monst",
127         GIANTSTR,"Giant Str",   FIRERESISTANCE,"Fire Resit", DEXCOUNT,"Dexterity",
128         STRCOUNT,"Strength",    SCAREMONST,"Scare",                     HASTESELF,"Haste Self",
129         CANCELLATION,"Cancel",  INVISIBILITY,"Invisible",       ALTPRO,"Protect 3",
130         PROTECTIONTIME,"Protect 2", WTW,"Wall-Walk"
131         };
132
133 botside()
134         {
135         int i,idx;
136         for (i=0; i<17; i++)
137                 {
138                 idx = bot_data[i].typ;
139                 if ((always) || (c[idx] != cbak[idx]))
140                    {
141                    if ((always) || (cbak[idx] == 0))
142                                 { if (c[idx]) { cursor(70,i+1); lprcat(bot_data[i].string); } }  else
143                    if (c[idx]==0)     { cursor(70,i+1); lprcat("          "); }
144                    cbak[idx]=c[idx];
145                    }
146                 }
147         always=0;
148         }
149
150 static void
151 botsub(idx,str)
152         int idx;
153         char *str;
154         {
155         int x,y;
156         y = idx & 0xff;         x = (idx>>8) & 0xff;      idx >>= 16;
157         if (c[idx] != cbak[idx])
158                 { cbak[idx]=c[idx];  cursor(x,y);  lprintf(str,(long)c[idx]); }
159         }
160
161 /*
162  *      subroutine to draw only a section of the screen
163  *      only the top section of the screen is updated.  If entire lines are being
164  *      drawn, then they will be cleared first.
165  */
166 int d_xmin=0,d_xmax=MAXX,d_ymin=0,d_ymax=MAXY;  /* for limited screen drawing */
167 draws(xmin,xmax,ymin,ymax)
168         int xmin,xmax,ymin,ymax;
169         {
170         int i,idx;
171         if (xmin==0 && xmax==MAXX) /* clear section of screen as needed */
172                 {
173                 if (ymin==0) cl_up(79,ymax);
174                 else for (i=ymin; i<ymin; i++)  cl_line(1,i+1);
175                 xmin = -1;
176                 }
177         d_xmin=xmin;    d_xmax=xmax;    d_ymin=ymin;    d_ymax=ymax;    /* for limited screen drawing */
178         drawscreen();
179         if (xmin<=0 && xmax==MAXX) /* draw stuff on right side of screen as needed*/
180                 {
181                 for (i=ymin; i<ymax; i++)
182                         {
183                         idx = bot_data[i].typ;
184                         if (c[idx])
185                                 {
186                                 cursor(70,i+1); lprcat(bot_data[i].string);
187                                 }
188                         cbak[idx]=c[idx];
189                         }
190                 }
191         }
192
193 /*
194         drawscreen()
195
196         subroutine to redraw the whole screen as the player knows it
197  */
198 char screen[MAXX][MAXY],d_flag; /* template for the screen */
199 drawscreen()
200         {
201         int i,j,k;
202         int lastx,lasty;  /* variables used to optimize the object printing */
203         if (d_xmin==0 && d_xmax==MAXX && d_ymin==0 && d_ymax==MAXY)
204                 {
205                 d_flag=1;  clear(); /* clear the screen */
206                 }
207         else
208                 {
209                 d_flag=0;  cursor(1,1);
210                 }
211         if (d_xmin<0)
212                 d_xmin=0; /* d_xmin=-1 means display all without bottomline */
213
214         for (i=d_ymin; i<d_ymax; i++)
215           for (j=d_xmin; j<d_xmax; j++)
216                 if (know[j][i]==0)  screen[j][i] = ' ';  else
217                 if (k=mitem[j][i])  screen[j][i] = monstnamelist[k];  else
218                 if ((k=item[j][i])==OWALL) screen[j][i] = '#';
219                 else screen[j][i] = ' ';
220
221         for (i=d_ymin; i<d_ymax; i++)
222                 {
223                 j=d_xmin;  while ((screen[j][i]==' ') && (j<d_xmax)) j++;
224                 /* was m=0 */
225                 if (j >= d_xmax)  m=d_xmin; /* don't search backwards if blank line */
226                 else
227                         {       /* search backwards for end of line */
228                         m=d_xmax-1;  while ((screen[m][i]==' ') && (m>d_xmin)) --m;
229                         if (j<=m)  cursor(j+1,i+1);  else continue;
230                         }
231                 while (j <= m)
232                         {
233                         if (j <= m-3)
234                                 {
235                                 for (k=j; k<=j+3; k++) if (screen[k][i] != ' ') k=1000;
236                                 if (k < 1000)
237                                         { while(screen[j][i]==' ' && j<=m) j++;  cursor(j+1,i+1); }
238                                 }
239                         lprc(screen[j++][i]);
240                         }
241                 }
242         setbold();              /* print out only bold objects now */
243
244         for (lastx=lasty=127, i=d_ymin; i<d_ymax; i++)
245                 for (j=d_xmin; j<d_xmax; j++)
246                         {
247                         if (k=item[j][i])
248                                 if (k != OWALL)
249                                         if ((know[j][i]) && (mitem[j][i]==0))
250                                                 if (objnamelist[k]!=' ')
251                                                         {
252                                                         if (lasty!=i+1 || lastx!=j)
253                                                                 cursor(lastx=j+1,lasty=i+1); else lastx++;
254                                                         lprc(objnamelist[k]);
255                                                         }
256                         }
257
258         resetbold();  if (d_flag)  { always=1; botside(); always=1; bot_linex(); }
259         oldx=99;
260         d_xmin = 0 , d_xmax = MAXX , d_ymin = 0 , d_ymax = MAXY; /* for limited screen drawing */
261         }
262 \f
263 /*
264         showcell(x,y)
265
266         subroutine to display a cell location on the screen
267  */
268 showcell(x,y)
269         int x,y;
270         {
271         int i,j,k,m;
272         if (c[BLINDCOUNT])  return;     /* see nothing if blind         */
273         if (c[AWARENESS]) { minx = x-3; maxx = x+3;     miny = y-3;     maxy = y+3; }
274                         else      { minx = x-1; maxx = x+1;     miny = y-1;     maxy = y+1; }
275
276         if (minx < 0) minx=0;           if (maxx > MAXX-1) maxx = MAXX-1;
277         if (miny < 0) miny=0;           if (maxy > MAXY-1) maxy = MAXY-1;
278
279         for (j=miny; j<=maxy; j++)
280           for (m=minx; m<=maxx; m++)
281                 if (know[m][j]==0)
282                         {
283                         cursor(m+1,j+1);
284                         x=maxx;  while (know[x][j]) --x;
285                         for (i=m; i<=x; i++)
286                                 {
287                                 if ((k=mitem[i][j]) != 0)  lprc(monstnamelist[k]);
288                                 else switch(k=item[i][j])
289                                         {
290                                         case OWALL:  case 0: case OIVTELETRAP:  case OTRAPARROWIV:
291                                         case OIVDARTRAP: case OIVTRAPDOOR:
292                                                 lprc(objnamelist[k]);   break;
293
294                                         default: setbold(); lprc(objnamelist[k]); resetbold();
295                                         };
296                                 know[i][j]=1;
297                                 }
298                         m = maxx;
299                         }
300         }
301
302 /*
303         this routine shows only the spot that is given it.  the spaces around
304         these coordinated are not shown
305         used in godirect() in monster.c for missile weapons display
306  */
307 show1cell(x,y)
308         int x,y;
309         {
310         if (c[BLINDCOUNT])  return;     /* see nothing if blind         */
311         cursor(x+1,y+1);
312         if ((k=mitem[x][y]) != 0)  lprc(monstnamelist[k]);
313                 else switch(k=item[x][y])
314                         {
315                         case OWALL:  case 0:  case OIVTELETRAP:  case OTRAPARROWIV:
316                         case OIVDARTRAP: case OIVTRAPDOOR:
317                                 lprc(objnamelist[k]);   break;
318
319                         default: setbold(); lprc(objnamelist[k]); resetbold();
320                         };
321         know[x][y]|=1;  /* we end up knowing about it */
322         }
323
324 /*
325         showplayer()
326
327         subroutine to show where the player is on the screen
328         cursor values start from 1 up
329  */
330 showplayer()
331         {
332         cursor(playerx+1,playery+1);
333         oldx=playerx;  oldy=playery;
334         }
335
336 /*
337         moveplayer(dir)
338
339         subroutine to move the player from one room to another
340         returns 0 if can't move in that direction or hit a monster or on an object
341         else returns 1
342         nomove is set to 1 to stop the next move (inadvertent monsters hitting
343         players when walking into walls) if player walks off screen or into wall
344  */
345 short diroffx[] = { 0,  0, 1,  0, -1,  1, -1, 1, -1 };
346 short diroffy[] = { 0,  1, 0, -1,  0, -1, -1, 1,  1 };
347 moveplayer(dir)
348         int dir;                        /*      from = present room #  direction = [1-north]
349                                                         [2-east] [3-south] [4-west] [5-northeast]
350                                                         [6-northwest] [7-southeast] [8-southwest]
351                                                 if direction=0, don't move--just show where he is */
352         {
353         int k,m,i,j;
354         if (c[CONFUSE]) if (c[LEVEL]<rnd(30)) dir=rund(9); /*if confused any dir*/
355         k = playerx + diroffx[dir];             m = playery + diroffy[dir];
356         if (k<0 || k>=MAXX || m<0 || m>=MAXY) { nomove=1; return(yrepcount = 0); }
357         i = item[k][m];                 j = mitem[k][m];
358         if (i==OWALL && c[WTW]==0) { nomove=1;  return(yrepcount = 0); }                /*      hit a wall      */
359         if (k==33 && m==MAXY-1 && level==1)
360                 {
361                 newcavelevel(0); for (k=0; k<MAXX; k++) for (m=0; m<MAXY; m++)
362                 if (item[k][m]==OENTRANCE)
363                   { playerx=k; playery=m; positionplayer();  drawscreen(); return(0); }
364                 }
365         if (j>0)     { hitmonster(k,m); return(yrepcount = 0); } /* hit a monster*/
366         lastpx = playerx;                       lastpy = playery;
367         playerx = k;            playery = m;
368         if (i && i!=OTRAPARROWIV && i!=OIVTELETRAP && i!=OIVDARTRAP && i!=OIVTRAPDOOR) return(yrepcount = 0);  else return(1);
369         }
370 \f
371 /*
372  *      function to show what magic items have been discovered thus far
373  *      enter with -1 for just spells, anything else will give scrolls & potions
374  */
375 static int lincount,count;
376 seemagic(arg)
377         int arg;
378         {
379         int i,number;
380         count = lincount = 0;  nosignal=1;
381
382         if (arg== -1) /* if display spells while casting one */
383                 {
384                 for (number=i=0; i<SPNUM; i++) if (spelknow[i]) number++;
385                 number = (number+2)/3 + 4;      /* # lines needed to display */
386                 cl_up(79,number);  cursor(1,1);
387                 }
388         else
389                 {
390                 resetscroll();  clear();
391                 }
392
393         lprcat("The magic spells you have discovered thus far:\n\n");
394         for (i=0; i<SPNUM; i++)
395                 if (spelknow[i])
396                         { lprintf("%s %-20s ",spelcode[i],spelname[i]);  seepage(); }
397
398         if (arg== -1)
399                 {
400                 seepage();  more();      nosignal=0;
401                 draws(0,MAXX,0,number);  return;
402                 }
403
404         lincount += 3;  if (count!=0) { count=2;  seepage(); }
405
406         lprcat("\nThe magic scrolls you have found to date are:\n\n");
407         count=0;
408         for (i=0; i<MAXSCROLL; i++)
409                 if (scrollname[i][0])
410                   if (scrollname[i][1]!=' ')
411                         { lprintf("%-26s",&scrollname[i][1]);  seepage(); }
412
413         lincount += 3;  if (count!=0) { count=2;  seepage(); }
414
415         lprcat("\nThe magic potions you have found to date are:\n\n");
416         count=0;
417         for (i=0; i<MAXPOTION; i++)
418                 if (potionname[i][0])
419                   if (potionname[i][1]!=' ')
420                         { lprintf("%-26s",&potionname[i][1]);  seepage(); }
421
422         if (lincount!=0) more();        nosignal=0;  setscroll();       drawscreen();
423         }
424
425 /*
426  *      subroutine to paginate the seemagic function
427  */
428 seepage()
429         {
430         if (++count==3)
431                 {
432                 lincount++;     count=0;        lprc('\n');
433                 if (lincount>17) {      lincount=0;  more();  clear();  }
434                 }
435         }