1 /* $OpenBSD: hack.c,v 1.7 2003/05/19 06:30:56 pjanzen 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 #ifndef lint 65 static const char rcsid[] = "$OpenBSD: hack.c,v 1.7 2003/05/19 06:30:56 pjanzen Exp $"; 66 #endif /* not lint */ 67 68 #include "hack.h" 69 #include <stdio.h> 70 71 extern char *nomovemsg; 72 extern char *exclam(); 73 74 static void movobj(struct obj *, int, int); 75 #ifdef QUEST 76 static int rroom(int, int); 77 #endif 78 static int inv_cnt(void); 79 80 /* called on movement: 81 * 1. when throwing ball+chain far away 82 * 2. when teleporting 83 * 3. when walking out of a lit room 84 */ 85 void 86 unsee() 87 { 88 int x,y; 89 struct rm *lev; 90 91 /* 92 if(u.udispl){ 93 u.udispl = 0; 94 newsym(u.udisx, u.udisy); 95 } 96 */ 97 #ifndef QUEST 98 if(seehx){ 99 seehx = 0; 100 } else 101 #endif /* QUEST */ 102 for(x = u.ux-1; x < u.ux+2; x++) 103 for(y = u.uy-1; y < u.uy+2; y++) { 104 if(!isok(x, y)) continue; 105 lev = &levl[x][y]; 106 if(!lev->lit && lev->scrsym == '.') { 107 lev->scrsym =' '; 108 lev->new = 1; 109 on_scr(x,y); 110 } 111 } 112 } 113 114 /* called: 115 * in hack.eat.c: seeoff(0) - blind after eating rotten food 116 * in hack.mon.c: seeoff(0) - blinded by a yellow light 117 * in hack.mon.c: seeoff(1) - swallowed 118 * in hack.do.c: seeoff(0) - blind after drinking potion 119 * in hack.do.c: seeoff(1) - go up or down the stairs 120 * in hack.trap.c:seeoff(1) - fall through trapdoor 121 */ 122 void 123 seeoff(int mode) /* 1 to redo @, 0 to leave them */ 124 { /* 1 means misc movement, 0 means blindness */ 125 int x,y; 126 struct rm *lev; 127 128 if(u.udispl && mode){ 129 u.udispl = 0; 130 levl[(int)u.udisx][(int)u.udisy].scrsym = news0(u.udisx,u.udisy); 131 } 132 #ifndef QUEST 133 if(seehx) { 134 seehx = 0; 135 } else 136 #endif /* QUEST */ 137 if(!mode) { 138 for(x = u.ux-1; x < u.ux+2; x++) 139 for(y = u.uy-1; y < u.uy+2; y++) { 140 if(!isok(x, y)) continue; 141 lev = &levl[x][y]; 142 if(!lev->lit && lev->scrsym == '.') 143 lev->seen = 0; 144 } 145 } 146 } 147 148 void 149 domove() 150 { 151 xchar oldx,oldy; 152 struct monst *mtmp; 153 struct rm *tmpr,*ust; 154 struct trap *trap; 155 struct obj *otmp; 156 157 u_wipe_engr(rnd(5)); 158 159 if(inv_weight() > 0){ 160 pline("You collapse under your load."); 161 nomul(0); 162 return; 163 } 164 if(u.uswallow) { 165 u.dx = u.dy = 0; 166 u.ux = u.ustuck->mx; 167 u.uy = u.ustuck->my; 168 } else { 169 if(Confusion) { 170 do { 171 confdir(); 172 } while(!isok(u.ux+u.dx, u.uy+u.dy) || 173 IS_ROCK(levl[u.ux+u.dx][u.uy+u.dy].typ)); 174 } 175 if(!isok(u.ux+u.dx, u.uy+u.dy)){ 176 nomul(0); 177 return; 178 } 179 } 180 181 ust = &levl[(int)u.ux][(int)u.uy]; 182 oldx = u.ux; 183 oldy = u.uy; 184 if(!u.uswallow && (trap = t_at(u.ux+u.dx, u.uy+u.dy)) && trap->tseen) 185 nomul(0); 186 if(u.ustuck && !u.uswallow && (u.ux+u.dx != u.ustuck->mx || 187 u.uy+u.dy != u.ustuck->my)) { 188 if(dist(u.ustuck->mx, u.ustuck->my) > 2){ 189 /* perhaps it fled (or was teleported or ... ) */ 190 u.ustuck = 0; 191 } else { 192 if(Blind) pline("You cannot escape from it!"); 193 else pline("You cannot escape from %s!", 194 monnam(u.ustuck)); 195 nomul(0); 196 return; 197 } 198 } 199 if(u.uswallow || (mtmp = m_at(u.ux+u.dx,u.uy+u.dy))) { 200 /* attack monster */ 201 202 nomul(0); 203 gethungry(); 204 if(multi < 0) return; /* we just fainted */ 205 206 /* try to attack; note that it might evade */ 207 if(attack(u.uswallow ? u.ustuck : mtmp)) 208 return; 209 } 210 /* not attacking an animal, so we try to move */ 211 if(u.utrap) { 212 if(u.utraptype == TT_PIT) { 213 pline("You are still in a pit."); 214 u.utrap--; 215 } else { 216 pline("You are caught in a beartrap."); 217 if((u.dx && u.dy) || !rn2(5)) u.utrap--; 218 } 219 return; 220 } 221 tmpr = &levl[u.ux+u.dx][u.uy+u.dy]; 222 if(IS_ROCK(tmpr->typ) || 223 (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))){ 224 flags.move = 0; 225 nomul(0); 226 return; 227 } 228 while ((otmp = sobj_at(ENORMOUS_ROCK, u.ux+u.dx, u.uy+u.dy))) { 229 xchar rx = u.ux+2*u.dx, ry = u.uy+2*u.dy; 230 struct trap *ttmp; 231 nomul(0); 232 if (isok(rx,ry) && !IS_ROCK(levl[(int)rx][(int)ry].typ) && 233 (levl[(int)rx][(int)ry].typ != DOOR || !(u.dx && u.dy)) && 234 !sobj_at(ENORMOUS_ROCK, rx, ry)) { 235 if(m_at(rx,ry)) { 236 pline("You hear a monster behind the rock."); 237 pline("Perhaps that's why you cannot move it."); 238 goto cannot_push; 239 } 240 if ((ttmp = t_at(rx,ry))) 241 switch(ttmp->ttyp) { 242 case PIT: 243 pline("You push the rock into a pit!"); 244 deltrap(ttmp); 245 delobj(otmp); 246 pline("It completely fills the pit!"); 247 continue; 248 case TELEP_TRAP: 249 pline("You push the rock and suddenly it disappears!"); 250 delobj(otmp); 251 continue; 252 } 253 if (levl[(int)rx][(int)ry].typ == POOL) { 254 levl[(int)rx][(int)ry].typ = ROOM; 255 mnewsym(rx,ry); 256 prl(rx,ry); 257 pline("You push the rock into the water."); 258 pline("Now you can cross the water!"); 259 delobj(otmp); 260 continue; 261 } 262 otmp->ox = rx; 263 otmp->oy = ry; 264 /* pobj(otmp); */ 265 if(cansee(rx,ry)) atl(rx,ry,otmp->olet); 266 if(Invisible) newsym(u.ux+u.dx, u.uy+u.dy); 267 268 { static long lastmovetime; 269 /* note: this var contains garbage initially and 270 after a restore */ 271 if(moves > lastmovetime+2 || moves < lastmovetime) 272 pline("With great effort you move the enormous rock."); 273 lastmovetime = moves; 274 } 275 } else { 276 pline("You try to move the enormous rock, but in vain."); 277 cannot_push: 278 if((!invent || inv_weight()+90 <= 0) && 279 (!u.dx || !u.dy || (IS_ROCK(levl[(int)u.ux][u.uy+u.dy].typ) 280 && IS_ROCK(levl[u.ux+u.dx][(int)u.uy].typ)))){ 281 pline("However, you can squeeze yourself into a small opening."); 282 break; 283 } else 284 return; 285 } 286 } 287 if(u.dx && u.dy && IS_ROCK(levl[(int)u.ux][u.uy+u.dy].typ) && 288 IS_ROCK(levl[u.ux+u.dx][(int)u.uy].typ) && 289 invent && inv_weight()+40 > 0) { 290 pline("You are carrying too much to get through."); 291 nomul(0); 292 return; 293 } 294 if(Punished && 295 DIST(u.ux+u.dx, u.uy+u.dy, uchain->ox, uchain->oy) > 2){ 296 if(carried(uball)) { 297 movobj(uchain, u.ux, u.uy); 298 goto nodrag; 299 } 300 301 if(DIST(u.ux+u.dx, u.uy+u.dy, uball->ox, uball->oy) < 3){ 302 /* leave ball, move chain under/over ball */ 303 movobj(uchain, uball->ox, uball->oy); 304 goto nodrag; 305 } 306 307 if(inv_weight() + (int) uball->owt/2 > 0) { 308 pline("You cannot %sdrag the heavy iron ball.", 309 invent ? "carry all that and also " : ""); 310 nomul(0); 311 return; 312 } 313 314 movobj(uball, uchain->ox, uchain->oy); 315 unpobj(uball); /* BAH %% */ 316 uchain->ox = u.ux; 317 uchain->oy = u.uy; 318 nomul(-2); 319 nomovemsg = ""; 320 nodrag: ; 321 } 322 u.ux += u.dx; 323 u.uy += u.dy; 324 if(flags.run) { 325 if(tmpr->typ == DOOR || 326 (xupstair == u.ux && yupstair == u.uy) || 327 (xdnstair == u.ux && ydnstair == u.uy)) 328 nomul(0); 329 } 330 331 if(tmpr->typ == POOL && !Levitation) 332 drown(); /* not necessarily fatal */ 333 334 /* 335 if(u.udispl) { 336 u.udispl = 0; 337 newsym(oldx,oldy); 338 } 339 */ 340 if(!Blind) { 341 #ifdef QUEST 342 setsee(); 343 #else 344 if(ust->lit) { 345 if(tmpr->lit) { 346 if(tmpr->typ == DOOR) 347 prl1(u.ux+u.dx,u.uy+u.dy); 348 else if(ust->typ == DOOR) 349 nose1(oldx-u.dx,oldy-u.dy); 350 } else { 351 unsee(); 352 prl1(u.ux+u.dx,u.uy+u.dy); 353 } 354 } else { 355 if(tmpr->lit) setsee(); 356 else { 357 prl1(u.ux+u.dx,u.uy+u.dy); 358 if(tmpr->typ == DOOR) { 359 if(u.dy) { 360 prl(u.ux-1,u.uy); 361 prl(u.ux+1,u.uy); 362 } else { 363 prl(u.ux,u.uy-1); 364 prl(u.ux,u.uy+1); 365 } 366 } 367 } 368 nose1(oldx-u.dx,oldy-u.dy); 369 } 370 #endif /* QUEST */ 371 } else { 372 pru(); 373 } 374 if(!flags.nopick) pickup(1); 375 if(trap) dotrap(trap); /* fall into pit, arrow trap, etc. */ 376 (void) inshop(); 377 if(!Blind) read_engr_at(u.ux,u.uy); 378 } 379 380 static void 381 movobj(struct obj *obj, int ox, int oy) 382 { 383 /* Some dirty programming to get display right */ 384 freeobj(obj); 385 unpobj(obj); 386 obj->nobj = fobj; 387 fobj = obj; 388 obj->ox = ox; 389 obj->oy = oy; 390 } 391 392 int 393 dopickup() 394 { 395 if(!g_at(u.ux,u.uy) && !o_at(u.ux,u.uy)) { 396 pline("There is nothing here to pick up."); 397 return(0); 398 } 399 if(Levitation) { 400 pline("You cannot reach the floor."); 401 return(1); 402 } 403 pickup(0); 404 return(1); 405 } 406 407 void 408 pickup(int all) 409 { 410 struct gold *gold; 411 struct obj *obj, *obj2; 412 int wt; 413 414 if (Levitation) 415 return; 416 while ((gold = g_at(u.ux,u.uy))) { 417 pline("%ld gold piece%s.", gold->amount, plur(gold->amount)); 418 u.ugold += gold->amount; 419 flags.botl = 1; 420 freegold(gold); 421 if(flags.run) nomul(0); 422 if(Invisible) newsym(u.ux,u.uy); 423 } 424 425 /* check for more than one object */ 426 if(!all) { 427 int ct = 0; 428 429 for(obj = fobj; obj; obj = obj->nobj) 430 if(obj->ox == u.ux && obj->oy == u.uy) 431 if(!Punished || obj != uchain) 432 ct++; 433 if(ct < 2) 434 all++; 435 else 436 pline("There are several objects here."); 437 } 438 439 for(obj = fobj; obj; obj = obj2) { 440 obj2 = obj->nobj; /* perhaps obj will be picked up */ 441 if(obj->ox == u.ux && obj->oy == u.uy) { 442 if(flags.run) nomul(0); 443 444 /* do not pick up uchain */ 445 if(Punished && obj == uchain) 446 continue; 447 448 if(!all) { 449 char c; 450 451 pline("Pick up %s ? [ynaq]", doname(obj)); 452 while(!strchr("ynaq ", (c = readchar()))) 453 hackbell(); 454 if(c == 'q') return; 455 if(c == 'n') continue; 456 if(c == 'a') all = 1; 457 } 458 459 if(obj->otyp == DEAD_COCKATRICE && !uarmg){ 460 pline("Touching the dead cockatrice is a fatal mistake."); 461 pline("You turn to stone."); 462 killer = "cockatrice cadaver"; 463 done("died"); 464 } 465 466 if(obj->otyp == SCR_SCARE_MONSTER){ 467 if(!obj->spe) obj->spe = 1; 468 else { 469 /* Note: perhaps the 1st pickup failed: you cannot 470 carry anymore, and so we never dropped it - 471 let's assume that treading on it twice also 472 destroys the scroll */ 473 pline("The scroll turns to dust as you pick it up."); 474 delobj(obj); 475 continue; 476 } 477 } 478 479 wt = inv_weight() + obj->owt; 480 if(wt > 0) { 481 if(obj->quan > 1) { 482 /* see how many we can lift */ 483 int savequan = obj->quan; 484 int iw = inv_weight(); 485 int qq; 486 for(qq = 1; qq < savequan; qq++){ 487 obj->quan = qq; 488 if(iw + weight(obj) > 0) 489 break; 490 } 491 obj->quan = savequan; 492 qq--; 493 /* we can carry qq of them */ 494 if(!qq) goto too_heavy; 495 pline("You can only carry %s of the %s lying here.", 496 (qq == 1) ? "one" : "some", 497 doname(obj)); 498 (void) splitobj(obj, qq); 499 /* note: obj2 is set already, so we'll never 500 * encounter the other half; if it should be 501 * otherwise then write 502 * obj2 = splitobj(obj,qq); 503 */ 504 goto lift_some; 505 } 506 too_heavy: 507 pline("There %s %s here, but %s.", 508 (obj->quan == 1) ? "is" : "are", 509 doname(obj), 510 !invent ? "it is too heavy for you to lift" 511 : "you cannot carry anymore"); 512 break; 513 } 514 lift_some: 515 if(inv_cnt() >= 52) { 516 pline("Your knapsack cannot accommodate anymore items."); 517 break; 518 } 519 if(wt > -5) pline("You have a little trouble lifting"); 520 freeobj(obj); 521 if(Invisible) newsym(u.ux,u.uy); 522 addtobill(obj); /* sets obj->unpaid if necessary */ 523 { int pickquan = obj->quan; 524 int mergquan; 525 if(!Blind) obj->dknown = 1; /* this is done by prinv(), 526 but addinv() needs it already for merging */ 527 obj = addinv(obj); /* might merge it with other objects */ 528 mergquan = obj->quan; 529 obj->quan = pickquan; /* to fool prinv() */ 530 prinv(obj); 531 obj->quan = mergquan; 532 } 533 } 534 } 535 } 536 537 /* stop running if we see something interesting */ 538 /* turn around a corner if that is the only way we can proceed */ 539 /* do not turn left or right twice */ 540 void 541 lookaround() 542 { 543 int x, y, i, x0, y0, m0, i0 = 9; 544 int corrct = 0, noturn = 0; 545 struct monst *mtmp; 546 547 #ifdef lint 548 /* suppress "used before set" message */ 549 x0 = y0 = 0; 550 #endif /* lint */ 551 if (Blind || flags.run == 0) return; 552 if (flags.run == 1 && levl[(int)u.ux][(int)u.uy].typ == ROOM) 553 return; 554 #ifdef QUEST 555 if(u.ux0 == u.ux+u.dx && u.uy0 == u.uy+u.dy) goto stop; 556 #endif /* QUEST */ 557 for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){ 558 if(x == u.ux && y == u.uy) continue; 559 if(!levl[x][y].typ) continue; 560 if((mtmp = m_at(x,y)) && !mtmp->mimic && 561 (!mtmp->minvis || See_invisible)){ 562 if(!mtmp->mtame || (x == u.ux+u.dx && y == u.uy+u.dy)) 563 goto stop; 564 } else mtmp = 0; /* invisible M cannot influence us */ 565 if(x == u.ux-u.dx && y == u.uy-u.dy) continue; 566 switch(levl[x][y].scrsym){ 567 case '|': 568 case '-': 569 case '.': 570 case ' ': 571 break; 572 case '+': 573 if(x != u.ux && y != u.uy) break; 574 if(flags.run != 1) goto stop; 575 /* fall into next case */ 576 case CORR_SYM: 577 corr: 578 if(flags.run == 1 || flags.run == 3) { 579 i = DIST(x,y,u.ux+u.dx,u.uy+u.dy); 580 if(i > 2) break; 581 if(corrct == 1 && DIST(x,y,x0,y0) != 1) 582 noturn = 1; 583 if(i < i0) { 584 i0 = i; 585 x0 = x; 586 y0 = y; 587 m0 = mtmp ? 1 : 0; 588 } 589 } 590 corrct++; 591 break; 592 case '^': 593 if(flags.run == 1) goto corr; /* if you must */ 594 if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop; 595 break; 596 default: /* e.g. objects or trap or stairs */ 597 if(flags.run == 1) goto corr; 598 if(mtmp) break; /* d */ 599 stop: 600 nomul(0); 601 return; 602 } 603 } 604 #ifdef QUEST 605 if(corrct > 0 && (flags.run == 4 || flags.run == 5)) goto stop; 606 #endif /* QUEST */ 607 if(corrct > 1 && flags.run == 2) goto stop; 608 if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 && 609 (corrct == 1 || (corrct == 2 && i0 == 1))) { 610 /* make sure that we do not turn too far */ 611 if(i0 == 2) { 612 if(u.dx == y0-u.uy && u.dy == u.ux-x0) 613 i = 2; /* straight turn right */ 614 else 615 i = -2; /* straight turn left */ 616 } else if(u.dx && u.dy) { 617 if((u.dx == u.dy && y0 == u.uy) || 618 (u.dx != u.dy && y0 != u.uy)) 619 i = -1; /* half turn left */ 620 else 621 i = 1; /* half turn right */ 622 } else { 623 if((x0-u.ux == y0-u.uy && !u.dy) || 624 (x0-u.ux != y0-u.uy && u.dy)) 625 i = 1; /* half turn right */ 626 else 627 i = -1; /* half turn left */ 628 } 629 i += u.last_str_turn; 630 if(i <= 2 && i >= -2) { 631 u.last_str_turn = i; 632 u.dx = x0-u.ux, u.dy = y0-u.uy; 633 } 634 } 635 } 636 637 /* something like lookaround, but we are not running */ 638 /* react only to monsters that might hit us */ 639 int 640 monster_nearby() 641 { 642 int x,y; 643 struct monst *mtmp; 644 645 if(!Blind) 646 for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){ 647 if(x == u.ux && y == u.uy) continue; 648 if((mtmp = m_at(x,y)) && !mtmp->mimic && !mtmp->mtame && 649 !mtmp->mpeaceful && !strchr("Ea", mtmp->data->mlet) && 650 !mtmp->mfroz && !mtmp->msleep && /* aplvax!jcn */ 651 (!mtmp->minvis || See_invisible)) 652 return(1); 653 } 654 return(0); 655 } 656 657 #ifdef QUEST 658 int 659 cansee(xchar x, xchar y) 660 { 661 int dx,dy,adx,ady,sdx,sdy,dmax,d; 662 663 if(Blind) return(0); 664 if(!isok(x,y)) return(0); 665 d = dist(x,y); 666 if(d < 3) return(1); 667 if(d > u.uhorizon*u.uhorizon) return(0); 668 if(!levl[x][y].lit) 669 return(0); 670 dx = x - u.ux; adx = abs(dx); sdx = sgn(dx); 671 dy = y - u.uy; ady = abs(dy); sdy = sgn(dy); 672 if(dx == 0 || dy == 0 || adx == ady){ 673 dmax = (dx == 0) ? ady : adx; 674 for(d = 1; d <= dmax; d++) 675 if(!rroom(sdx*d,sdy*d)) 676 return(0); 677 return(1); 678 } else if(ady > adx){ 679 for(d = 1; d <= ady; d++){ 680 if(!rroom(sdx*( (d*adx)/ady ), sdy*d) || 681 !rroom(sdx*( (d*adx-1)/ady+1 ), sdy*d)) 682 return(0); 683 } 684 return(1); 685 } else { 686 for(d = 1; d <= adx; d++){ 687 if(!rroom(sdx*d, sdy*( (d*ady)/adx )) || 688 !rroom(sdx*d, sdy*( (d*ady-1)/adx+1 ))) 689 return(0); 690 } 691 return(1); 692 } 693 } 694 695 static int 696 rroom(int x, int y) 697 { 698 return(IS_ROOM(levl[u.ux+x][u.uy+y].typ)); 699 } 700 701 #else 702 703 int 704 cansee(xchar x, xchar y) 705 { 706 if (Blind || u.uswallow) 707 return(0); 708 if (dist(x,y) < 3) 709 return(1); 710 if (levl[(int)x][(int)y].lit && seelx <= x && x <= seehx && 711 seely <= y && y <= seehy) 712 return(1); 713 return(0); 714 } 715 #endif /* QUEST */ 716 717 int 718 sgn(int a) 719 { 720 return((a > 0) ? 1 : (a == 0) ? 0 : -1); 721 } 722 723 #ifdef QUEST 724 void 725 setsee() 726 { 727 int x,y; 728 729 if(Blind) { 730 pru(); 731 return; 732 } 733 for(y = u.uy-u.uhorizon; y <= u.uy+u.uhorizon; y++) 734 for(x = u.ux-u.uhorizon; x <= u.ux+u.uhorizon; x++) { 735 if(cansee(x,y)) 736 prl(x,y); 737 } 738 } 739 740 #else 741 742 void 743 setsee() 744 { 745 int x,y; 746 747 if (Blind) { 748 pru(); 749 return; 750 } 751 if (!levl[(int)u.ux][(int)u.uy].lit) { 752 seelx = u.ux-1; 753 seehx = u.ux+1; 754 seely = u.uy-1; 755 seehy = u.uy+1; 756 } else { 757 for(seelx = u.ux; levl[seelx-1][(int)u.uy].lit; seelx--); 758 for(seehx = u.ux; levl[seehx+1][(int)u.uy].lit; seehx++); 759 for(seely = u.uy; levl[(int)u.ux][seely-1].lit; seely--); 760 for(seehy = u.uy; levl[(int)u.ux][seehy+1].lit; seehy++); 761 } 762 for (y = seely; y <= seehy; y++) 763 for (x = seelx; x <= seehx; x++) { 764 prl(x,y); 765 } 766 if (!levl[(int)u.ux][(int)u.uy].lit) 767 seehx = 0; /* seems necessary elsewhere */ 768 else { 769 if(seely == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seely-1); 770 if(seehy == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seehy+1); 771 if(seelx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seelx-1,y); 772 if(seehx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seehx+1,y); 773 } 774 } 775 #endif /* QUEST */ 776 777 void 778 nomul(int nval) 779 { 780 if(multi < 0) return; 781 multi = nval; 782 flags.mv = flags.run = 0; 783 } 784 785 int 786 abon() 787 { 788 if(u.ustr == 3) return(-3); 789 else if(u.ustr < 6) return(-2); 790 else if(u.ustr < 8) return(-1); 791 else if(u.ustr < 17) return(0); 792 else if(u.ustr < 69) return(1); /* up to 18/50 */ 793 else if(u.ustr < 118) return(2); 794 else return(3); 795 } 796 797 int 798 dbon() 799 { 800 if(u.ustr < 6) return(-1); 801 else if(u.ustr < 16) return(0); 802 else if(u.ustr < 18) return(1); 803 else if(u.ustr == 18) return(2); /* up to 18 */ 804 else if(u.ustr < 94) return(3); /* up to 18/75 */ 805 else if(u.ustr < 109) return(4); /* up to 18/90 */ 806 else if(u.ustr < 118) return(5); /* up to 18/99 */ 807 else return(6); 808 } 809 810 void 811 losestr(int num) /* may kill you; cause may be poison or monster like 'A' */ 812 { 813 u.ustr -= num; 814 while(u.ustr < 3) { 815 u.ustr++; 816 u.uhp -= 6; 817 u.uhpmax -= 6; 818 } 819 flags.botl = 1; 820 } 821 822 void 823 losehp(int n, char *knam) 824 { 825 u.uhp -= n; 826 if(u.uhp > u.uhpmax) 827 u.uhpmax = u.uhp; /* perhaps n was negative */ 828 flags.botl = 1; 829 if(u.uhp < 1) { 830 killer = knam; /* the thing that killed you */ 831 done("died"); 832 } 833 } 834 835 void 836 losehp_m(int n, struct monst *mtmp) 837 { 838 u.uhp -= n; 839 flags.botl = 1; 840 if(u.uhp < 1) 841 done_in_by(mtmp); 842 } 843 844 /* hit by V or W */ 845 void 846 losexp() 847 { 848 int num; 849 850 if(u.ulevel > 1) 851 pline("Goodbye level %u.", u.ulevel--); 852 else 853 u.uhp = -1; 854 num = rnd(10); 855 u.uhp -= num; 856 u.uhpmax -= num; 857 u.uexp = newuexp(); 858 flags.botl = 1; 859 } 860 861 int 862 inv_weight() 863 { 864 struct obj *otmp = invent; 865 int wt = (u.ugold + 500)/1000; 866 int carrcap; 867 868 if(Levitation) /* pugh@cornell */ 869 carrcap = MAX_CARR_CAP; 870 else { 871 carrcap = 5*(((u.ustr > 18) ? 20 : u.ustr) + u.ulevel); 872 if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP; 873 if(Wounded_legs & LEFT_SIDE) carrcap -= 10; 874 if(Wounded_legs & RIGHT_SIDE) carrcap -= 10; 875 } 876 while(otmp){ 877 wt += otmp->owt; 878 otmp = otmp->nobj; 879 } 880 return(wt - carrcap); 881 } 882 883 static int 884 inv_cnt() 885 { 886 struct obj *otmp = invent; 887 int ct = 0; 888 889 while(otmp){ 890 ct++; 891 otmp = otmp->nobj; 892 } 893 return(ct); 894 } 895 896 long 897 newuexp() 898 { 899 return(10*(1L << (u.ulevel-1))); 900 } 901