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