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