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