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