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