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