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