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