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