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