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