1 /* $NetBSD: hack.pri.c,v 1.6 2001/03/25 20:44:02 jsm Exp $ */ 2 3 /* 4 * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. 5 */ 6 7 #include <sys/cdefs.h> 8 #ifndef lint 9 __RCSID("$NetBSD: hack.pri.c,v 1.6 2001/03/25 20:44:02 jsm Exp $"); 10 #endif /* not lint */ 11 12 #include "hack.h" 13 #include "extern.h" 14 xchar scrlx, scrhx, scrly, scrhy; /* corners of new area on 15 * screen */ 16 17 void 18 swallowed() 19 { 20 char ulook[] = "|@|"; 21 ulook[1] = u.usym; 22 23 cls(); 24 curs(u.ux - 1, u.uy + 1); 25 fputs("/-\\", stdout); 26 curx = u.ux + 2; 27 curs(u.ux - 1, u.uy + 2); 28 fputs(ulook, stdout); 29 curx = u.ux + 2; 30 curs(u.ux - 1, u.uy + 3); 31 fputs("\\-/", stdout); 32 curx = u.ux + 2; 33 u.udispl = 1; 34 u.udisx = u.ux; 35 u.udisy = u.uy; 36 } 37 38 39 /* VARARGS1 */ 40 boolean panicking; 41 42 void 43 #ifdef __STDC__ 44 panic(const char *fmt, ...) 45 #else 46 panic(va_alist) 47 va_dcl 48 #endif 49 { 50 va_list ap; 51 #ifndef __STDC__ 52 const char *fmt; 53 va_start(ap); 54 fmt = va_arg(ap, const char *); 55 #else 56 va_start(ap, fmt); 57 #endif 58 if (panicking++) 59 exit(1); /* avoid loops - this should never happen */ 60 home(); 61 puts(" Suddenly, the dungeon collapses."); 62 fputs(" ERROR: ", stdout); 63 vprintf(fmt, ap); 64 va_end(ap); 65 #ifdef DEBUG 66 #ifdef UNIX 67 if (!fork()) 68 abort(); /* generate core dump */ 69 #endif /* UNIX */ 70 #endif /* DEBUG */ 71 more(); /* contains a fflush() */ 72 done("panicked"); 73 } 74 75 void 76 atl(x, y, ch) 77 int x, y, ch; 78 { 79 struct rm *crm = &levl[x][y]; 80 81 if (x < 0 || x > COLNO - 1 || y < 0 || y > ROWNO - 1) { 82 impossible("atl(%d,%d,%c)", x, y, ch); 83 return; 84 } 85 if (crm->seen && crm->scrsym == ch) 86 return; 87 crm->scrsym = ch; 88 crm->new = 1; 89 on_scr(x, y); 90 } 91 92 void 93 on_scr(x, y) 94 int x, y; 95 { 96 if (x < scrlx) 97 scrlx = x; 98 if (x > scrhx) 99 scrhx = x; 100 if (y < scrly) 101 scrly = y; 102 if (y > scrhy) 103 scrhy = y; 104 } 105 106 /* 107 * call: (x,y) - display (-1,0) - close (leave last symbol) (-1,-1)- close 108 * (undo last symbol) (-1,let)-open: initialize symbol (-2,let)-change let 109 */ 110 111 void 112 tmp_at(x, y) 113 schar x, y; 114 { 115 static schar prevx, prevy; 116 static char let; 117 if ((int) x == -2) { /* change let call */ 118 let = y; 119 return; 120 } 121 if ((int) x == -1 && (int) y >= 0) { /* open or close call */ 122 let = y; 123 prevx = -1; 124 return; 125 } 126 if (prevx >= 0 && cansee(prevx, prevy)) { 127 delay_output(); 128 prl(prevx, prevy); /* in case there was a monster */ 129 at(prevx, prevy, levl[prevx][prevy].scrsym); 130 } 131 if (x >= 0) { /* normal call */ 132 if (cansee(x, y)) 133 at(x, y, let); 134 prevx = x; 135 prevy = y; 136 } else { /* close call */ 137 let = 0; 138 prevx = -1; 139 } 140 } 141 142 /* like the previous, but the symbols are first erased on completion */ 143 void 144 Tmp_at(x, y) 145 schar x, y; 146 { 147 static char let; 148 static xchar cnt; 149 static coord tc[COLNO]; /* but watch reflecting beams! */ 150 int xx, yy; 151 if ((int) x == -1) { 152 if (y > 0) { /* open call */ 153 let = y; 154 cnt = 0; 155 return; 156 } 157 /* close call (do not distinguish y==0 and y==-1) */ 158 while (cnt--) { 159 xx = tc[cnt].x; 160 yy = tc[cnt].y; 161 prl(xx, yy); 162 at(xx, yy, levl[xx][yy].scrsym); 163 } 164 cnt = let = 0; /* superfluous */ 165 return; 166 } 167 if ((int) x == -2) { /* change let call */ 168 let = y; 169 return; 170 } 171 /* normal call */ 172 if (cansee(x, y)) { 173 if (cnt) 174 delay_output(); 175 at(x, y, let); 176 tc[cnt].x = x; 177 tc[cnt].y = y; 178 if (++cnt >= COLNO) 179 panic("Tmp_at overflow?"); 180 levl[x][y].new = 0; /* prevent pline-nscr erasing --- */ 181 } 182 } 183 184 void 185 setclipped() 186 { 187 error("Hack needs a screen of size at least %d by %d.\n", 188 ROWNO + 2, COLNO); 189 } 190 191 void 192 at(x, y, ch) 193 xchar x, y; 194 char ch; 195 { 196 #ifndef lint 197 /* if xchar is unsigned, lint will complain about if(x < 0) */ 198 if (x < 0 || x > COLNO - 1 || y < 0 || y > ROWNO - 1) { 199 impossible("At gets 0%o at %d %d.", ch, x, y); 200 return; 201 } 202 #endif /* lint */ 203 if (!ch) { 204 impossible("At gets null at %d %d.", x, y); 205 return; 206 } 207 y += 2; 208 curs(x, y); 209 (void) putchar(ch); 210 curx++; 211 } 212 213 void 214 prme() 215 { 216 if (!Invisible) 217 at(u.ux, u.uy, u.usym); 218 } 219 220 int 221 doredraw() 222 { 223 docrt(); 224 return (0); 225 } 226 227 void 228 docrt() 229 { 230 int x, y; 231 struct rm *room; 232 struct monst *mtmp; 233 234 if (u.uswallow) { 235 swallowed(); 236 return; 237 } 238 cls(); 239 240 /* 241 * Some ridiculous code to get display of @ and monsters (almost) 242 * right 243 */ 244 if (!Invisible) { 245 levl[(u.udisx = u.ux)][(u.udisy = u.uy)].scrsym = u.usym; 246 levl[u.udisx][u.udisy].seen = 1; 247 u.udispl = 1; 248 } else 249 u.udispl = 0; 250 251 seemons(); /* reset old positions */ 252 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 253 mtmp->mdispl = 0; 254 seemons(); /* force new positions to be shown */ 255 /* 256 * This nonsense should disappear soon 257 * --------------------------------- 258 */ 259 260 for (y = 0; y < ROWNO; y++) 261 for (x = 0; x < COLNO; x++) 262 if ((room = &levl[x][y])->new) { 263 room->new = 0; 264 at(x, y, room->scrsym); 265 } else if (room->seen) 266 at(x, y, room->scrsym); 267 scrlx = COLNO; 268 scrly = ROWNO; 269 scrhx = scrhy = 0; 270 flags.botlx = 1; 271 bot(); 272 } 273 274 void 275 docorner(xmin, ymax) 276 int xmin, ymax; 277 { 278 int x, y; 279 struct rm *room; 280 struct monst *mtmp; 281 282 if (u.uswallow) { /* Can be done more efficiently */ 283 swallowed(); 284 return; 285 } 286 seemons(); /* reset old positions */ 287 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 288 if (mtmp->mx >= xmin && mtmp->my < ymax) 289 mtmp->mdispl = 0; 290 seemons(); /* force new positions to be shown */ 291 292 for (y = 0; y < ymax; y++) { 293 if (y > ROWNO && CD) 294 break; 295 curs(xmin, y + 2); 296 cl_end(); 297 if (y < ROWNO) { 298 for (x = xmin; x < COLNO; x++) { 299 if ((room = &levl[x][y])->new) { 300 room->new = 0; 301 at(x, y, room->scrsym); 302 } else if (room->seen) 303 at(x, y, room->scrsym); 304 } 305 } 306 } 307 if (ymax > ROWNO) { 308 cornbot(xmin - 1); 309 if (ymax > ROWNO + 1 && CD) { 310 curs(1, ROWNO + 3); 311 cl_eos(); 312 } 313 } 314 } 315 316 void 317 curs_on_u() 318 { 319 curs(u.ux, u.uy + 2); 320 } 321 322 void 323 pru() 324 { 325 if (u.udispl && (Invisible || u.udisx != u.ux || u.udisy != u.uy)) 326 /* if(! levl[u.udisx][u.udisy].new) */ 327 if (!vism_at(u.udisx, u.udisy)) 328 newsym(u.udisx, u.udisy); 329 if (Invisible) { 330 u.udispl = 0; 331 prl(u.ux, u.uy); 332 } else if (!u.udispl || u.udisx != u.ux || u.udisy != u.uy) { 333 atl(u.ux, u.uy, u.usym); 334 u.udispl = 1; 335 u.udisx = u.ux; 336 u.udisy = u.uy; 337 } 338 levl[u.ux][u.uy].seen = 1; 339 } 340 341 #ifndef NOWORM 342 #include "def.wseg.h" 343 #endif /* NOWORM */ 344 345 /* print a position that is visible for @ */ 346 void 347 prl(int x, int y) 348 { 349 struct rm *room; 350 struct monst *mtmp; 351 struct obj *otmp; 352 353 if (x == u.ux && y == u.uy && (!Invisible)) { 354 pru(); 355 return; 356 } 357 if (!isok(x, y)) 358 return; 359 room = &levl[x][y]; 360 if ((!room->typ) || 361 (IS_ROCK(room->typ) && levl[u.ux][u.uy].typ == CORR)) 362 return; 363 if ((mtmp = m_at(x, y)) && !mtmp->mhide && 364 (!mtmp->minvis || See_invisible)) { 365 #ifndef NOWORM 366 if (m_atseg) 367 pwseg(m_atseg); 368 else 369 #endif /* NOWORM */ 370 pmon(mtmp); 371 } else if ((otmp = o_at(x, y)) && room->typ != POOL) 372 atl(x, y, otmp->olet); 373 else if (mtmp && (!mtmp->minvis || See_invisible)) { 374 /* must be a hiding monster, but not hiding right now */ 375 /* assume for the moment that long worms do not hide */ 376 pmon(mtmp); 377 } else if (g_at(x, y) && room->typ != POOL) 378 atl(x, y, '$'); 379 else if (!room->seen || room->scrsym == ' ') { 380 room->new = room->seen = 1; 381 newsym(x, y); 382 on_scr(x, y); 383 } 384 room->seen = 1; 385 } 386 387 char 388 news0(x, y) 389 xchar x, y; 390 { 391 struct obj *otmp; 392 struct trap *ttmp; 393 struct rm *room; 394 char tmp; 395 396 room = &levl[x][y]; 397 if (!room->seen) 398 tmp = ' '; 399 else if (room->typ == POOL) 400 tmp = POOL_SYM; 401 else if (!Blind && (otmp = o_at(x, y))) 402 tmp = otmp->olet; 403 else if (!Blind && g_at(x, y)) 404 tmp = '$'; 405 else if (x == xupstair && y == yupstair) 406 tmp = '<'; 407 else if (x == xdnstair && y == ydnstair) 408 tmp = '>'; 409 else if ((ttmp = t_at(x, y)) && ttmp->tseen) 410 tmp = '^'; 411 else 412 switch (room->typ) { 413 case SCORR: 414 case SDOOR: 415 tmp = room->scrsym; /* %% wrong after killing 416 * mimic ! */ 417 break; 418 case HWALL: 419 tmp = '-'; 420 break; 421 case VWALL: 422 tmp = '|'; 423 break; 424 case LDOOR: 425 case DOOR: 426 tmp = '+'; 427 break; 428 case CORR: 429 tmp = CORR_SYM; 430 break; 431 case ROOM: 432 if (room->lit || cansee(x, y) || Blind) 433 tmp = '.'; 434 else 435 tmp = ' '; 436 break; 437 /* 438 case POOL: 439 tmp = POOL_SYM; 440 break; 441 */ 442 default: 443 tmp = ERRCHAR; 444 } 445 return (tmp); 446 } 447 448 void 449 newsym(x, y) 450 int x, y; 451 { 452 atl(x, y, news0(x, y)); 453 } 454 455 /* used with wand of digging (or pick-axe): fill scrsym and force display */ 456 /* also when a POOL evaporates */ 457 void 458 mnewsym(x, y) 459 int x, y; 460 { 461 struct rm *room; 462 char newscrsym; 463 464 if (!vism_at(x, y)) { 465 room = &levl[x][y]; 466 newscrsym = news0(x, y); 467 if (room->scrsym != newscrsym) { 468 room->scrsym = newscrsym; 469 room->seen = 0; 470 } 471 } 472 } 473 474 void 475 nosee(x, y) 476 int x, y; 477 { 478 struct rm *room; 479 480 if (!isok(x, y)) 481 return; 482 room = &levl[x][y]; 483 if (room->scrsym == '.' && !room->lit && !Blind) { 484 room->scrsym = ' '; 485 room->new = 1; 486 on_scr(x, y); 487 } 488 } 489 490 #ifndef QUEST 491 void 492 prl1(x, y) 493 int x, y; 494 { 495 if (u.dx) { 496 if (u.dy) { 497 prl(x - (2 * u.dx), y); 498 prl(x - u.dx, y); 499 prl(x, y); 500 prl(x, y - u.dy); 501 prl(x, y - (2 * u.dy)); 502 } else { 503 prl(x, y - 1); 504 prl(x, y); 505 prl(x, y + 1); 506 } 507 } else { 508 prl(x - 1, y); 509 prl(x, y); 510 prl(x + 1, y); 511 } 512 } 513 514 void 515 nose1(x, y) 516 int x, y; 517 { 518 if (u.dx) { 519 if (u.dy) { 520 nosee(x, u.uy); 521 nosee(x, u.uy - u.dy); 522 nosee(x, y); 523 nosee(u.ux - u.dx, y); 524 nosee(u.ux, y); 525 } else { 526 nosee(x, y - 1); 527 nosee(x, y); 528 nosee(x, y + 1); 529 } 530 } else { 531 nosee(x - 1, y); 532 nosee(x, y); 533 nosee(x + 1, y); 534 } 535 } 536 #endif /* QUEST */ 537 538 int 539 vism_at(x, y) 540 int x, y; 541 { 542 struct monst *mtmp; 543 544 return ((x == u.ux && y == u.uy && !Invisible) 545 ? 1 : 546 (mtmp = m_at(x, y)) 547 ? ((Blind && Telepat) || canseemon(mtmp)) : 548 0); 549 } 550 551 #ifdef NEWSCR 552 void 553 pobj(obj) 554 struct obj *obj; 555 { 556 int show = (!obj->oinvis || See_invisible) && 557 cansee(obj->ox, obj->oy); 558 if (obj->odispl) { 559 if (obj->odx != obj->ox || obj->ody != obj->oy || !show) 560 if (!vism_at(obj->odx, obj->ody)) { 561 newsym(obj->odx, obj->ody); 562 obj->odispl = 0; 563 } 564 } 565 if (show && !vism_at(obj->ox, obj->oy)) { 566 atl(obj->ox, obj->oy, obj->olet); 567 obj->odispl = 1; 568 obj->odx = obj->ox; 569 obj->ody = obj->oy; 570 } 571 } 572 #endif /* NEWSCR */ 573 574 void 575 unpobj(obj) 576 struct obj *obj; 577 { 578 /* 579 * if(obj->odispl){ if(!vism_at(obj->odx, obj->ody)) newsym(obj->odx, 580 * obj->ody); obj->odispl = 0; } 581 */ 582 if (!vism_at(obj->ox, obj->oy)) 583 newsym(obj->ox, obj->oy); 584 } 585 586 void 587 seeobjs() 588 { 589 struct obj *obj, *obj2; 590 for (obj = fobj; obj; obj = obj2) { 591 obj2 = obj->nobj; 592 if (obj->olet == FOOD_SYM && obj->otyp >= CORPSE 593 && obj->age + 250 < moves) 594 delobj(obj); 595 } 596 for (obj = invent; obj; obj = obj2) { 597 obj2 = obj->nobj; 598 if (obj->olet == FOOD_SYM && obj->otyp >= CORPSE 599 && obj->age + 250 < moves) 600 useup(obj); 601 } 602 } 603 604 void 605 seemons() 606 { 607 struct monst *mtmp; 608 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 609 if (mtmp->data->mlet == ';') 610 mtmp->minvis = (u.ustuck != mtmp && 611 levl[mtmp->mx][mtmp->my].typ == POOL); 612 pmon(mtmp); 613 #ifndef NOWORM 614 if (mtmp->wormno) 615 wormsee(mtmp->wormno); 616 #endif /* NOWORM */ 617 } 618 } 619 620 void 621 pmon(mon) 622 struct monst *mon; 623 { 624 int show = (Blind && Telepat) || canseemon(mon); 625 if (mon->mdispl) { 626 if (mon->mdx != mon->mx || mon->mdy != mon->my || !show) 627 unpmon(mon); 628 } 629 if (show && !mon->mdispl) { 630 atl(mon->mx, mon->my, 631 (!mon->mappearance 632 || u.uprops[PROP(RIN_PROTECTION_FROM_SHAPE_CHANGERS)].p_flgs 633 ) ? mon->data->mlet : mon->mappearance); 634 mon->mdispl = 1; 635 mon->mdx = mon->mx; 636 mon->mdy = mon->my; 637 } 638 } 639 640 void 641 unpmon(mon) 642 struct monst *mon; 643 { 644 if (mon->mdispl) { 645 newsym(mon->mdx, mon->mdy); 646 mon->mdispl = 0; 647 } 648 } 649 650 void 651 nscr() 652 { 653 int x, y; 654 struct rm *room; 655 656 if (u.uswallow || u.ux == FAR || flags.nscrinh) 657 return; 658 pru(); 659 for (y = scrly; y <= scrhy; y++) 660 for (x = scrlx; x <= scrhx; x++) 661 if ((room = &levl[x][y])->new) { 662 room->new = 0; 663 at(x, y, room->scrsym); 664 } 665 scrhx = scrhy = 0; 666 scrlx = COLNO; 667 scrly = ROWNO; 668 } 669 670 /* 100 suffices for bot(); no relation with COLNO */ 671 char oldbot[100], newbot[100]; 672 void 673 cornbot(lth) 674 int lth; 675 { 676 if (lth < sizeof(oldbot)) { 677 oldbot[lth] = 0; 678 flags.botl = 1; 679 } 680 } 681 682 void 683 bot() 684 { 685 char *ob = oldbot, *nb = newbot; 686 int i; 687 if (flags.botlx) 688 *ob = 0; 689 flags.botl = flags.botlx = 0; 690 #ifdef GOLD_ON_BOTL 691 (void) sprintf(newbot, 692 "Level %-2d Gold %-5lu Hp %3d(%d) Ac %-2d Str ", 693 dlevel, u.ugold, u.uhp, u.uhpmax, u.uac); 694 #else 695 (void) sprintf(newbot, 696 "Level %-2d Hp %3d(%d) Ac %-2d Str ", 697 dlevel, u.uhp, u.uhpmax, u.uac); 698 #endif /* GOLD_ON_BOTL */ 699 if (u.ustr > 18) { 700 if (u.ustr > 117) 701 (void) strcat(newbot, "18/**"); 702 else 703 (void) sprintf(eos(newbot), "18/%02d", u.ustr - 18); 704 } else 705 (void) sprintf(eos(newbot), "%-2d ", u.ustr); 706 #ifdef EXP_ON_BOTL 707 (void) sprintf(eos(newbot), " Exp %2d/%-5lu ", u.ulevel, u.uexp); 708 #else 709 (void) sprintf(eos(newbot), " Exp %2u ", u.ulevel); 710 #endif /* EXP_ON_BOTL */ 711 (void) strcat(newbot, hu_stat[u.uhs]); 712 if (flags.time) 713 (void) sprintf(eos(newbot), " %ld", moves); 714 if (strlen(newbot) >= COLNO) { 715 char *bp0, *bp1; 716 bp0 = bp1 = newbot; 717 do { 718 if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ') 719 *bp1++ = *bp0; 720 } while (*bp0++); 721 } 722 for (i = 1; i < COLNO; i++) { 723 if (*ob != *nb) { 724 curs(i, ROWNO + 2); 725 (void) putchar(*nb ? *nb : ' '); 726 curx++; 727 } 728 if (*ob) 729 ob++; 730 if (*nb) 731 nb++; 732 } 733 (void) strcpy(oldbot, newbot); 734 } 735 736 #ifdef WAN_PROBING 737 void 738 mstatusline(mtmp) 739 struct monst *mtmp; 740 { 741 pline("Status of %s: ", monnam(mtmp)); 742 pline("Level %-2d Gold %-5lu Hp %3d(%d) Ac %-2d Dam %d", 743 mtmp->data->mlevel, mtmp->mgold, mtmp->mhp, mtmp->mhpmax, 744 mtmp->data->ac, (mtmp->data->damn + 1) * (mtmp->data->damd + 1)); 745 } 746 #endif /* WAN_PROBING */ 747 748 void 749 cls() 750 { 751 if (flags.toplin == 1) 752 more(); 753 flags.toplin = 0; 754 755 clear_screen(); 756 757 flags.botlx = 1; 758 } 759