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