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