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