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