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