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