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 21 bottomline(void) 22 { 23 recalc(); 24 bot1f = 1; 25 } 26 27 void 28 bottomhp(void) 29 { 30 bot2f = 1; 31 } 32 33 void 34 bottomspell(void) 35 { 36 bot3f = 1; 37 } 38 39 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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