1 /* $OpenBSD: hack.c,v 1.9 2014/03/11 07:41:10 guenther 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 if (Blind || flags.run == 0) return; 544 if (flags.run == 1 && levl[(int)u.ux][(int)u.uy].typ == ROOM) 545 return; 546 #ifdef QUEST 547 if(u.ux0 == u.ux+u.dx && u.uy0 == u.uy+u.dy) goto stop; 548 #endif /* QUEST */ 549 for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){ 550 if(x == u.ux && y == u.uy) continue; 551 if(!levl[x][y].typ) continue; 552 if((mtmp = m_at(x,y)) && !mtmp->mimic && 553 (!mtmp->minvis || See_invisible)){ 554 if(!mtmp->mtame || (x == u.ux+u.dx && y == u.uy+u.dy)) 555 goto stop; 556 } else mtmp = 0; /* invisible M cannot influence us */ 557 if(x == u.ux-u.dx && y == u.uy-u.dy) continue; 558 switch(levl[x][y].scrsym){ 559 case '|': 560 case '-': 561 case '.': 562 case ' ': 563 break; 564 case '+': 565 if(x != u.ux && y != u.uy) break; 566 if(flags.run != 1) goto stop; 567 /* fall into next case */ 568 case CORR_SYM: 569 corr: 570 if(flags.run == 1 || flags.run == 3) { 571 i = DIST(x,y,u.ux+u.dx,u.uy+u.dy); 572 if(i > 2) break; 573 if(corrct == 1 && DIST(x,y,x0,y0) != 1) 574 noturn = 1; 575 if(i < i0) { 576 i0 = i; 577 x0 = x; 578 y0 = y; 579 m0 = mtmp ? 1 : 0; 580 } 581 } 582 corrct++; 583 break; 584 case '^': 585 if(flags.run == 1) goto corr; /* if you must */ 586 if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop; 587 break; 588 default: /* e.g. objects or trap or stairs */ 589 if(flags.run == 1) goto corr; 590 if(mtmp) break; /* d */ 591 stop: 592 nomul(0); 593 return; 594 } 595 } 596 #ifdef QUEST 597 if(corrct > 0 && (flags.run == 4 || flags.run == 5)) goto stop; 598 #endif /* QUEST */ 599 if(corrct > 1 && flags.run == 2) goto stop; 600 if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 && 601 (corrct == 1 || (corrct == 2 && i0 == 1))) { 602 /* make sure that we do not turn too far */ 603 if(i0 == 2) { 604 if(u.dx == y0-u.uy && u.dy == u.ux-x0) 605 i = 2; /* straight turn right */ 606 else 607 i = -2; /* straight turn left */ 608 } else if(u.dx && u.dy) { 609 if((u.dx == u.dy && y0 == u.uy) || 610 (u.dx != u.dy && y0 != u.uy)) 611 i = -1; /* half turn left */ 612 else 613 i = 1; /* half turn right */ 614 } else { 615 if((x0-u.ux == y0-u.uy && !u.dy) || 616 (x0-u.ux != y0-u.uy && u.dy)) 617 i = 1; /* half turn right */ 618 else 619 i = -1; /* half turn left */ 620 } 621 i += u.last_str_turn; 622 if(i <= 2 && i >= -2) { 623 u.last_str_turn = i; 624 u.dx = x0-u.ux, u.dy = y0-u.uy; 625 } 626 } 627 } 628 629 /* something like lookaround, but we are not running */ 630 /* react only to monsters that might hit us */ 631 int 632 monster_nearby() 633 { 634 int x,y; 635 struct monst *mtmp; 636 637 if(!Blind) 638 for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){ 639 if(x == u.ux && y == u.uy) continue; 640 if((mtmp = m_at(x,y)) && !mtmp->mimic && !mtmp->mtame && 641 !mtmp->mpeaceful && !strchr("Ea", mtmp->data->mlet) && 642 !mtmp->mfroz && !mtmp->msleep && /* aplvax!jcn */ 643 (!mtmp->minvis || See_invisible)) 644 return(1); 645 } 646 return(0); 647 } 648 649 #ifdef QUEST 650 int 651 cansee(xchar x, xchar y) 652 { 653 int dx,dy,adx,ady,sdx,sdy,dmax,d; 654 655 if(Blind) return(0); 656 if(!isok(x,y)) return(0); 657 d = dist(x,y); 658 if(d < 3) return(1); 659 if(d > u.uhorizon*u.uhorizon) return(0); 660 if(!levl[x][y].lit) 661 return(0); 662 dx = x - u.ux; adx = abs(dx); sdx = sgn(dx); 663 dy = y - u.uy; ady = abs(dy); sdy = sgn(dy); 664 if(dx == 0 || dy == 0 || adx == ady){ 665 dmax = (dx == 0) ? ady : adx; 666 for(d = 1; d <= dmax; d++) 667 if(!rroom(sdx*d,sdy*d)) 668 return(0); 669 return(1); 670 } else if(ady > adx){ 671 for(d = 1; d <= ady; d++){ 672 if(!rroom(sdx*( (d*adx)/ady ), sdy*d) || 673 !rroom(sdx*( (d*adx-1)/ady+1 ), sdy*d)) 674 return(0); 675 } 676 return(1); 677 } else { 678 for(d = 1; d <= adx; d++){ 679 if(!rroom(sdx*d, sdy*( (d*ady)/adx )) || 680 !rroom(sdx*d, sdy*( (d*ady-1)/adx+1 ))) 681 return(0); 682 } 683 return(1); 684 } 685 } 686 687 static int 688 rroom(int x, int y) 689 { 690 return(IS_ROOM(levl[u.ux+x][u.uy+y].typ)); 691 } 692 693 #else 694 695 int 696 cansee(xchar x, xchar y) 697 { 698 if (Blind || u.uswallow) 699 return(0); 700 if (dist(x,y) < 3) 701 return(1); 702 if (levl[(int)x][(int)y].lit && seelx <= x && x <= seehx && 703 seely <= y && y <= seehy) 704 return(1); 705 return(0); 706 } 707 #endif /* QUEST */ 708 709 int 710 sgn(int a) 711 { 712 return((a > 0) ? 1 : (a == 0) ? 0 : -1); 713 } 714 715 #ifdef QUEST 716 void 717 setsee() 718 { 719 int x,y; 720 721 if(Blind) { 722 pru(); 723 return; 724 } 725 for(y = u.uy-u.uhorizon; y <= u.uy+u.uhorizon; y++) 726 for(x = u.ux-u.uhorizon; x <= u.ux+u.uhorizon; x++) { 727 if(cansee(x,y)) 728 prl(x,y); 729 } 730 } 731 732 #else 733 734 void 735 setsee() 736 { 737 int x,y; 738 739 if (Blind) { 740 pru(); 741 return; 742 } 743 if (!levl[(int)u.ux][(int)u.uy].lit) { 744 seelx = u.ux-1; 745 seehx = u.ux+1; 746 seely = u.uy-1; 747 seehy = u.uy+1; 748 } else { 749 for(seelx = u.ux; levl[seelx-1][(int)u.uy].lit; seelx--); 750 for(seehx = u.ux; levl[seehx+1][(int)u.uy].lit; seehx++); 751 for(seely = u.uy; levl[(int)u.ux][seely-1].lit; seely--); 752 for(seehy = u.uy; levl[(int)u.ux][seehy+1].lit; seehy++); 753 } 754 for (y = seely; y <= seehy; y++) 755 for (x = seelx; x <= seehx; x++) { 756 prl(x,y); 757 } 758 if (!levl[(int)u.ux][(int)u.uy].lit) 759 seehx = 0; /* seems necessary elsewhere */ 760 else { 761 if(seely == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seely-1); 762 if(seehy == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seehy+1); 763 if(seelx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seelx-1,y); 764 if(seehx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seehx+1,y); 765 } 766 } 767 #endif /* QUEST */ 768 769 void 770 nomul(int nval) 771 { 772 if(multi < 0) return; 773 multi = nval; 774 flags.mv = flags.run = 0; 775 } 776 777 int 778 abon() 779 { 780 if(u.ustr == 3) return(-3); 781 else if(u.ustr < 6) return(-2); 782 else if(u.ustr < 8) return(-1); 783 else if(u.ustr < 17) return(0); 784 else if(u.ustr < 69) return(1); /* up to 18/50 */ 785 else if(u.ustr < 118) return(2); 786 else return(3); 787 } 788 789 int 790 dbon() 791 { 792 if(u.ustr < 6) return(-1); 793 else if(u.ustr < 16) return(0); 794 else if(u.ustr < 18) return(1); 795 else if(u.ustr == 18) return(2); /* up to 18 */ 796 else if(u.ustr < 94) return(3); /* up to 18/75 */ 797 else if(u.ustr < 109) return(4); /* up to 18/90 */ 798 else if(u.ustr < 118) return(5); /* up to 18/99 */ 799 else return(6); 800 } 801 802 void 803 losestr(int num) /* may kill you; cause may be poison or monster like 'A' */ 804 { 805 u.ustr -= num; 806 while(u.ustr < 3) { 807 u.ustr++; 808 u.uhp -= 6; 809 u.uhpmax -= 6; 810 } 811 flags.botl = 1; 812 } 813 814 void 815 losehp(int n, char *knam) 816 { 817 u.uhp -= n; 818 if(u.uhp > u.uhpmax) 819 u.uhpmax = u.uhp; /* perhaps n was negative */ 820 flags.botl = 1; 821 if(u.uhp < 1) { 822 killer = knam; /* the thing that killed you */ 823 done("died"); 824 } 825 } 826 827 void 828 losehp_m(int n, struct monst *mtmp) 829 { 830 u.uhp -= n; 831 flags.botl = 1; 832 if(u.uhp < 1) 833 done_in_by(mtmp); 834 } 835 836 /* hit by V or W */ 837 void 838 losexp() 839 { 840 int num; 841 842 if(u.ulevel > 1) 843 pline("Goodbye level %u.", u.ulevel--); 844 else 845 u.uhp = -1; 846 num = rnd(10); 847 u.uhp -= num; 848 u.uhpmax -= num; 849 u.uexp = newuexp(); 850 flags.botl = 1; 851 } 852 853 int 854 inv_weight() 855 { 856 struct obj *otmp = invent; 857 int wt = (u.ugold + 500)/1000; 858 int carrcap; 859 860 if(Levitation) /* pugh@cornell */ 861 carrcap = MAX_CARR_CAP; 862 else { 863 carrcap = 5*(((u.ustr > 18) ? 20 : u.ustr) + u.ulevel); 864 if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP; 865 if(Wounded_legs & LEFT_SIDE) carrcap -= 10; 866 if(Wounded_legs & RIGHT_SIDE) carrcap -= 10; 867 } 868 while(otmp){ 869 wt += otmp->owt; 870 otmp = otmp->nobj; 871 } 872 return(wt - carrcap); 873 } 874 875 static int 876 inv_cnt() 877 { 878 struct obj *otmp = invent; 879 int ct = 0; 880 881 while(otmp){ 882 ct++; 883 otmp = otmp->nobj; 884 } 885 return(ct); 886 } 887 888 long 889 newuexp() 890 { 891 return(10*(1L << (u.ulevel-1))); 892 } 893