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