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