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