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