1 /*        $NetBSD: hack.read.c,v 1.11 2011/08/06 20:29:37 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.11 2011/08/06 20:29:37 dholland Exp $");
67 #endif                                  /* not lint */
68 
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 
73 static int identify(struct obj *);
74 static int monstersym(int);
75 
76 int
doread(void)77 doread(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 
533 static int
identify(struct obj * otmp)534 identify(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 
542 void
litroom(boolean on)543 litroom(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 
583 do_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  */
630 static int
monstersym(int ch)631 monstersym(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