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