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 } 629