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