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