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