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