1 /* $NetBSD: hack.read.c,v 1.8 2003/04/02 18:36:39 jsm 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 <sys/cdefs.h> 65 #ifndef lint 66 __RCSID("$NetBSD: hack.read.c,v 1.8 2003/04/02 18:36:39 jsm Exp $"); 67 #endif /* not lint */ 68 69 #include <stdlib.h> 70 #include "hack.h" 71 #include "extern.h" 72 73 int 74 doread() 75 { 76 struct obj *scroll; 77 boolean confused = (Confusion != 0); 78 boolean known = FALSE; 79 80 scroll = getobj("?", "read"); 81 if (!scroll) 82 return (0); 83 if (!scroll->dknown && Blind) { 84 pline("Being blind, you cannot read the formula on the scroll."); 85 return (0); 86 } 87 if (Blind) 88 pline("As you pronounce the formula on it, the scroll disappears."); 89 else 90 pline("As you read the scroll, it disappears."); 91 if (confused) 92 pline("Being confused, you mispronounce the magic words ... "); 93 94 switch (scroll->otyp) { 95 #ifdef MAIL 96 case SCR_MAIL: 97 readmail( /* scroll */ ); 98 break; 99 #endif /* MAIL */ 100 case SCR_ENCHANT_ARMOR: 101 { 102 struct obj *otmp = some_armor(); 103 if (!otmp) { 104 strange_feeling(scroll, "Your skin glows then fades."); 105 return (1); 106 } 107 if (confused) { 108 pline("Your %s glows silver for a moment.", 109 objects[otmp->otyp].oc_name); 110 otmp->rustfree = 1; 111 break; 112 } 113 if (otmp->spe > 3 && rn2(otmp->spe)) { 114 pline("Your %s glows violently green for a while, then evaporates.", 115 objects[otmp->otyp].oc_name); 116 useup(otmp); 117 break; 118 } 119 pline("Your %s glows green for a moment.", 120 objects[otmp->otyp].oc_name); 121 otmp->cursed = 0; 122 otmp->spe++; 123 break; 124 } 125 case SCR_DESTROY_ARMOR: 126 if (confused) { 127 struct obj *otmp = some_armor(); 128 if (!otmp) { 129 strange_feeling(scroll, "Your bones itch."); 130 return (1); 131 } 132 pline("Your %s glows purple for a moment.", 133 objects[otmp->otyp].oc_name); 134 otmp->rustfree = 0; 135 break; 136 } 137 if (uarm) { 138 pline("Your armor turns to dust and falls to the floor!"); 139 useup(uarm); 140 } else if (uarmh) { 141 pline("Your helmet turns to dust and is blown away!"); 142 useup(uarmh); 143 } else if (uarmg) { 144 pline("Your gloves vanish!"); 145 useup(uarmg); 146 selftouch("You"); 147 } else { 148 strange_feeling(scroll, "Your skin itches."); 149 return (1); 150 } 151 break; 152 case SCR_CONFUSE_MONSTER: 153 if (confused) { 154 pline("Your hands begin to glow purple."); 155 Confusion += rnd(100); 156 } else { 157 pline("Your hands begin to glow blue."); 158 u.umconf = 1; 159 } 160 break; 161 case SCR_SCARE_MONSTER: 162 { 163 int ct = 0; 164 struct monst *mtmp; 165 166 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 167 if (cansee(mtmp->mx, mtmp->my)) { 168 if (confused) 169 mtmp->mflee = mtmp->mfroz = 170 mtmp->msleep = 0; 171 else 172 mtmp->mflee = 1; 173 ct++; 174 } 175 if (!ct) { 176 if (confused) 177 pline("You hear sad wailing in the distance."); 178 else 179 pline("You hear maniacal laughter in the distance."); 180 } 181 break; 182 } 183 case SCR_BLANK_PAPER: 184 if (confused) 185 pline("You see strange patterns on this scroll."); 186 else 187 pline("This scroll seems to be blank."); 188 break; 189 case SCR_REMOVE_CURSE: 190 { 191 struct obj *obj; 192 if (confused) 193 pline("You feel like you need some help."); 194 else 195 pline("You feel like someone is helping you."); 196 for (obj = invent; obj; obj = obj->nobj) 197 if (obj->owornmask) 198 obj->cursed = confused; 199 if (Punished && !confused) { 200 Punished = 0; 201 freeobj(uchain); 202 unpobj(uchain); 203 free((char *) uchain); 204 uball->spe = 0; 205 uball->owornmask &= ~W_BALL; 206 uchain = uball = (struct obj *) 0; 207 } 208 break; 209 } 210 case SCR_CREATE_MONSTER: 211 { 212 int cnt = 1; 213 214 if (!rn2(73)) 215 cnt += rnd(4); 216 if (confused) 217 cnt += 12; 218 while (cnt--) 219 (void) makemon(confused ? PM_ACID_BLOB : 220 (struct permonst *) 0, u.ux, u.uy); 221 break; 222 } 223 case SCR_ENCHANT_WEAPON: 224 if (uwep && confused) { 225 pline("Your %s glows silver for a moment.", 226 objects[uwep->otyp].oc_name); 227 uwep->rustfree = 1; 228 } else if (!chwepon(scroll, 1)) /* tests for !uwep */ 229 return (1); 230 break; 231 case SCR_DAMAGE_WEAPON: 232 if (uwep && confused) { 233 pline("Your %s glows purple for a moment.", 234 objects[uwep->otyp].oc_name); 235 uwep->rustfree = 0; 236 } else if (!chwepon(scroll, -1)) /* tests for !uwep */ 237 return (1); 238 break; 239 case SCR_TAMING: 240 { 241 int i, j; 242 int bd = confused ? 5 : 1; 243 struct monst *mtmp; 244 245 for (i = -bd; i <= bd; i++) 246 for (j = -bd; j <= bd; j++) 247 if ((mtmp = m_at(u.ux + i, u.uy + j)) != NULL) 248 (void) tamedog(mtmp, (struct obj *) 0); 249 break; 250 } 251 case SCR_GENOCIDE: 252 { 253 char buf[BUFSZ]; 254 struct monst *mtmp, *mtmp2; 255 256 pline("You have found a scroll of genocide!"); 257 known = TRUE; 258 if (confused) 259 *buf = u.usym; 260 else 261 do { 262 pline("What monster do you want to genocide (Type the letter)? "); 263 getlin(buf); 264 } while (strlen(buf) != 1 || !monstersym(*buf)); 265 if (!strchr(fut_geno, *buf)) 266 charcat(fut_geno, *buf); 267 if (!strchr(genocided, *buf)) 268 charcat(genocided, *buf); 269 else { 270 pline("Such monsters do not exist in this world."); 271 break; 272 } 273 for (mtmp = fmon; mtmp; mtmp = mtmp2) { 274 mtmp2 = mtmp->nmon; 275 if (mtmp->data->mlet == *buf) 276 mondead(mtmp); 277 } 278 pline("Wiped out all %c's.", *buf); 279 if (*buf == u.usym) { 280 killer = "scroll of genocide"; 281 u.uhp = -1; 282 } 283 break; 284 } 285 case SCR_LIGHT: 286 if (!Blind) 287 known = TRUE; 288 litroom(!confused); 289 break; 290 case SCR_TELEPORTATION: 291 if (confused) 292 level_tele(); 293 else { 294 #ifdef QUEST 295 int oux = u.ux, ouy = u.uy; 296 tele(); 297 if (dist(oux, ouy) > 100) 298 known = TRUE; 299 #else /* QUEST */ 300 int uroom = inroom(u.ux, u.uy); 301 tele(); 302 if (uroom != inroom(u.ux, u.uy)) 303 known = TRUE; 304 #endif /* QUEST */ 305 } 306 break; 307 case SCR_GOLD_DETECTION: 308 /* 309 * Unfortunately this code has become slightly less elegant, 310 * now that gold and traps no longer are of the same type. 311 */ 312 if (confused) { 313 struct trap *ttmp; 314 315 if (!ftrap) { 316 strange_feeling(scroll, "Your toes stop itching."); 317 return (1); 318 } else { 319 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) 320 if (ttmp->tx != u.ux || ttmp->ty != u.uy) 321 goto outtrapmap; 322 /* 323 * only under me - no separate display 324 * required 325 */ 326 pline("Your toes itch!"); 327 break; 328 outtrapmap: 329 cls(); 330 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) 331 at(ttmp->tx, ttmp->ty, '$'); 332 prme(); 333 pline("You feel very greedy!"); 334 } 335 } else { 336 struct gold *gtmp; 337 338 if (!fgold) { 339 strange_feeling(scroll, "You feel materially poor."); 340 return (1); 341 } else { 342 known = TRUE; 343 for (gtmp = fgold; gtmp; gtmp = gtmp->ngold) 344 if (gtmp->gx != u.ux || gtmp->gy != u.uy) 345 goto outgoldmap; 346 /* 347 * only under me - no separate display 348 * required 349 */ 350 pline("You notice some gold between your feet."); 351 break; 352 outgoldmap: 353 cls(); 354 for (gtmp = fgold; gtmp; gtmp = gtmp->ngold) 355 at(gtmp->gx, gtmp->gy, '$'); 356 prme(); 357 pline("You feel very greedy, and sense gold!"); 358 } 359 } 360 /* common sequel */ 361 more(); 362 docrt(); 363 break; 364 case SCR_FOOD_DETECTION: 365 { 366 int ct = 0, ctu = 0; 367 struct obj *obj; 368 char foodsym = confused ? POTION_SYM : FOOD_SYM; 369 370 for (obj = fobj; obj; obj = obj->nobj) 371 if (obj->olet == FOOD_SYM) { 372 if (obj->ox == u.ux && obj->oy == u.uy) 373 ctu++; 374 else 375 ct++; 376 } 377 if (!ct && !ctu) { 378 strange_feeling(scroll, "Your nose twitches."); 379 return (1); 380 } else if (!ct) { 381 known = TRUE; 382 pline("You smell %s close nearby.", 383 confused ? "something" : "food"); 384 385 } else { 386 known = TRUE; 387 cls(); 388 for (obj = fobj; obj; obj = obj->nobj) 389 if (obj->olet == foodsym) 390 at(obj->ox, obj->oy, FOOD_SYM); 391 prme(); 392 pline("Your nose tingles and you smell %s!", 393 confused ? "something" : "food"); 394 more(); 395 docrt(); 396 } 397 break; 398 } 399 case SCR_IDENTIFY: 400 /* known = TRUE; */ 401 if (confused) 402 pline("You identify this as an identify scroll."); 403 else 404 pline("This is an identify scroll."); 405 useup(scroll); 406 objects[SCR_IDENTIFY].oc_name_known = 1; 407 if (!confused) 408 while ( 409 !ggetobj("identify", identify, rn2(5) ? 1 : rn2(5)) 410 && invent 411 ); 412 return (1); 413 case SCR_MAGIC_MAPPING: 414 { 415 struct rm *lev; 416 int num, zx, zy; 417 418 known = TRUE; 419 pline("On this scroll %s a map!", 420 confused ? "was" : "is"); 421 for (zy = 0; zy < ROWNO; zy++) 422 for (zx = 0; zx < COLNO; zx++) { 423 if (confused && rn2(7)) 424 continue; 425 lev = &(levl[zx][zy]); 426 if ((num = lev->typ) == 0) 427 continue; 428 if (num == SCORR) { 429 lev->typ = CORR; 430 lev->scrsym = CORR_SYM; 431 } else if (num == SDOOR) { 432 lev->typ = DOOR; 433 lev->scrsym = '+'; 434 /* do sth in doors ? */ 435 } else if (lev->seen) 436 continue; 437 #ifndef QUEST 438 if (num != ROOM) 439 #endif /* QUEST */ 440 { 441 lev->seen = lev->new = 1; 442 if (lev->scrsym == ' ' || !lev->scrsym) 443 newsym(zx, zy); 444 else 445 on_scr(zx, zy); 446 } 447 } 448 break; 449 } 450 case SCR_AMNESIA: 451 { 452 int zx, zy; 453 454 known = TRUE; 455 for (zx = 0; zx < COLNO; zx++) 456 for (zy = 0; zy < ROWNO; zy++) 457 if (!confused || rn2(7)) 458 if (!cansee(zx, zy)) 459 levl[zx][zy].seen = 0; 460 docrt(); 461 pline("Thinking of Maud you forget everything else."); 462 break; 463 } 464 case SCR_FIRE: 465 { 466 int num = 0; 467 struct monst *mtmp; 468 469 known = TRUE; 470 if (confused) { 471 pline("The scroll catches fire and you burn your hands."); 472 losehp(1, "scroll of fire"); 473 } else { 474 pline("The scroll erupts in a tower of flame!"); 475 if (Fire_resistance) 476 pline("You are uninjured."); 477 else { 478 num = rnd(6); 479 u.uhpmax -= num; 480 losehp(num, "scroll of fire"); 481 } 482 } 483 num = (2 * num + 1) / 3; 484 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 485 if (dist(mtmp->mx, mtmp->my) < 3) { 486 mtmp->mhp -= num; 487 if (strchr("FY", mtmp->data->mlet)) 488 mtmp->mhp -= 3 * num; /* this might well kill 489 * 'F's */ 490 if (mtmp->mhp < 1) { 491 killed(mtmp); 492 break; /* primitive */ 493 } 494 } 495 } 496 break; 497 } 498 case SCR_PUNISHMENT: 499 known = TRUE; 500 if (confused) { 501 pline("You feel guilty."); 502 break; 503 } 504 pline("You are being punished for your misbehaviour!"); 505 if (Punished) { 506 pline("Your iron ball gets heavier."); 507 uball->owt += 15; 508 break; 509 } 510 Punished = INTRINSIC; 511 setworn(mkobj_at(CHAIN_SYM, u.ux, u.uy), W_CHAIN); 512 setworn(mkobj_at(BALL_SYM, u.ux, u.uy), W_BALL); 513 uball->spe = 1; /* special ball (see save) */ 514 break; 515 default: 516 impossible("What weird language is this written in? (%u)", 517 scroll->otyp); 518 } 519 if (!objects[scroll->otyp].oc_name_known) { 520 if (known && !confused) { 521 objects[scroll->otyp].oc_name_known = 1; 522 more_experienced(0, 10); 523 } else if (!objects[scroll->otyp].oc_uname) 524 docall(scroll); 525 } 526 useup(scroll); 527 return (1); 528 } 529 530 int 531 identify(otmp) /* also called by newmail() */ 532 struct obj *otmp; 533 { 534 objects[otmp->otyp].oc_name_known = 1; 535 otmp->known = otmp->dknown = 1; 536 prinv(otmp); 537 return (1); 538 } 539 540 void 541 litroom(on) 542 boolean on; 543 { 544 #ifndef QUEST 545 int num, zx, zy; 546 #endif 547 548 /* first produce the text (provided he is not blind) */ 549 if (Blind) 550 goto do_it; 551 if (!on) { 552 if (u.uswallow || !xdnstair || levl[u.ux][u.uy].typ == CORR || 553 !levl[u.ux][u.uy].lit) { 554 pline("It seems even darker in here than before."); 555 return; 556 } else 557 pline("It suddenly becomes dark in here."); 558 } else { 559 if (u.uswallow) { 560 pline("%s's stomach is lit.", Monnam(u.ustuck)); 561 return; 562 } 563 if (!xdnstair) { 564 pline("Nothing Happens."); 565 return; 566 } 567 #ifdef QUEST 568 pline("The cave lights up around you, then fades."); 569 return; 570 #else /* QUEST */ 571 if (levl[u.ux][u.uy].typ == CORR) { 572 pline("The corridor lights up around you, then fades."); 573 return; 574 } else if (levl[u.ux][u.uy].lit) { 575 pline("The light here seems better now."); 576 return; 577 } else 578 pline("The room is lit."); 579 #endif /* QUEST */ 580 } 581 582 do_it: 583 #ifdef QUEST 584 return; 585 #else /* QUEST */ 586 if (levl[u.ux][u.uy].lit == on) 587 return; 588 if (levl[u.ux][u.uy].typ == DOOR) { 589 if (IS_ROOM(levl[u.ux][u.uy + 1].typ)) 590 zy = u.uy + 1; 591 else if (IS_ROOM(levl[u.ux][u.uy - 1].typ)) 592 zy = u.uy - 1; 593 else 594 zy = u.uy; 595 if (IS_ROOM(levl[u.ux + 1][u.uy].typ)) 596 zx = u.ux + 1; 597 else if (IS_ROOM(levl[u.ux - 1][u.uy].typ)) 598 zx = u.ux - 1; 599 else 600 zx = u.ux; 601 } else { 602 zx = u.ux; 603 zy = u.uy; 604 } 605 for (seelx = u.ux; (num = levl[seelx - 1][zy].typ) != CORR && num != 0; 606 seelx--); 607 for (seehx = u.ux; (num = levl[seehx + 1][zy].typ) != CORR && num != 0; 608 seehx++); 609 for (seely = u.uy; (num = levl[zx][seely - 1].typ) != CORR && num != 0; 610 seely--); 611 for (seehy = u.uy; (num = levl[zx][seehy + 1].typ) != CORR && num != 0; 612 seehy++); 613 for (zy = seely; zy <= seehy; zy++) 614 for (zx = seelx; zx <= seehx; zx++) { 615 levl[zx][zy].lit = on; 616 if (!Blind && dist(zx, zy) > 2) { 617 if (on) 618 prl(zx, zy); 619 else 620 nosee(zx, zy); 621 } 622 } 623 if (!on) 624 seehx = 0; 625 #endif /* QUEST */ 626 } 627 628 /* Test whether we may genocide all monsters with symbol ch */ 629 int 630 monstersym(ch) /* arnold@ucsfcgl */ 631 char ch; 632 { 633 const struct permonst *mp; 634 635 /* 636 * can't genocide certain monsters 637 */ 638 if (strchr("12 &:", ch)) 639 return FALSE; 640 641 if (ch == pm_eel.mlet) 642 return TRUE; 643 for (mp = mons; mp < &mons[CMNUM + 2]; mp++) 644 if (mp->mlet == ch) 645 return TRUE; 646 return FALSE; 647 } 648