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