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