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