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 29 bottomline(void) 30 { 31 recalc(); 32 bot1f = 1; 33 } 34 35 void 36 bottomhp(void) 37 { 38 bot2f = 1; 39 } 40 41 void 42 bottomspell(void) 43 { 44 bot3f = 1; 45 } 46 47 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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