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