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