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