Mercurial > hg > early-roguelike
comparison arogue7/misc.c @ 125:adfa37e67084
Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Fri, 08 May 2015 15:24:40 -0400 |
parents | |
children | b786053d2f37 |
comparison
equal
deleted
inserted
replaced
124:d10fc4a065ac | 125:adfa37e67084 |
---|---|
1 /* | |
2 * misc.c - routines dealing specifically with miscellaneous magic | |
3 * | |
4 * Advanced Rogue | |
5 * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T | |
6 * All rights reserved. | |
7 * | |
8 * Based on "Rogue: Exploring the Dungeons of Doom" | |
9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
10 * All rights reserved. | |
11 * | |
12 * See the file LICENSE.TXT for full copyright and licensing information. | |
13 */ | |
14 | |
15 #include "curses.h" | |
16 #include <ctype.h> | |
17 #include "rogue.h" | |
18 #ifdef PC7300 | |
19 #include "menu.h" | |
20 #endif | |
21 | |
22 /* | |
23 * routines dealing specifically with miscellaneous magic | |
24 */ | |
25 | |
26 /* | |
27 * changeclass: | |
28 * Change the player's class to the specified one. | |
29 */ | |
30 | |
31 changeclass(newclass) | |
32 int newclass; | |
33 { | |
34 if (newclass == player.t_ctype) { | |
35 msg("You feel more skillful."); | |
36 raise_level(); | |
37 } | |
38 else { | |
39 /* | |
40 * reset his class and then use check_level to reset hit | |
41 * points and the right level for his exp pts | |
42 * drop exp pts by 10% | |
43 */ | |
44 long save; | |
45 | |
46 msg("You feel like a whole new person!"); | |
47 | |
48 /* | |
49 * if he becomes a thief he has to have leather armor | |
50 */ | |
51 if ((newclass == C_THIEF || newclass == C_ASSASIN) && | |
52 cur_armor != NULL && | |
53 cur_armor->o_which != LEATHER && | |
54 cur_armor->o_which != STUDDED_LEATHER ) | |
55 cur_armor->o_which = STUDDED_LEATHER; | |
56 /* | |
57 * if he becomes a monk he can't wear armor | |
58 */ | |
59 if (newclass == C_MONK && cur_armor != NULL) { | |
60 cur_armor->o_ac = armors[cur_armor->o_which].a_class - | |
61 cur_armor->o_ac; | |
62 cur_armor->o_type = MM; | |
63 cur_armor->o_which = MM_PROTECT; | |
64 cur_armor->o_flags &= ~(ISPROT | ISKNOW | ISMETAL); | |
65 cur_misc[WEAR_CLOAK] = cur_armor; | |
66 cur_armor = NULL; | |
67 } | |
68 /* | |
69 * if he used to be a spell caster of some sort, kill the fuse | |
70 */ | |
71 if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER) | |
72 extinguish(spell_recovery); | |
73 if (player.t_ctype == C_DRUID || player.t_ctype == C_RANGER) | |
74 extinguish(chant_recovery); | |
75 if ((player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) && | |
76 !cur_relic[HEIL_ANKH]) | |
77 extinguish(prayer_recovery); | |
78 /* | |
79 * if he becomes a spell caster of some kind, give him a fuse | |
80 */ | |
81 if (newclass == C_MAGICIAN || newclass == C_RANGER) | |
82 fuse(spell_recovery, 0, SPELLTIME, AFTER); | |
83 if (newclass == C_DRUID || newclass == C_RANGER) | |
84 fuse(chant_recovery, 0, SPELLTIME, AFTER); | |
85 if ((newclass==C_CLERIC || newclass==C_PALADIN) && !cur_misc[HEIL_ANKH]) | |
86 fuse(prayer_recovery, 0, SPELLTIME, AFTER); | |
87 /* | |
88 * if he's changing from a fighter then may have to change | |
89 * his sword since only fighter can use two-handed | |
90 * and bastard swords | |
91 */ | |
92 if ((player.t_ctype == C_FIGHTER || | |
93 player.t_ctype == C_RANGER || | |
94 player.t_ctype == C_PALADIN) && | |
95 cur_weapon != NULL && | |
96 cur_weapon->o_type == WEAPON && | |
97 (cur_weapon->o_which== BASWORD || | |
98 cur_weapon->o_which== TWOSWORD ) && | |
99 !(newclass == C_FIGHTER || | |
100 newclass == C_RANGER || | |
101 newclass == C_PALADIN) && | |
102 !(newclass == C_ASSASIN && | |
103 cur_weapon->o_which == BASWORD)) | |
104 cur_weapon->o_which = SWORD; | |
105 | |
106 /* | |
107 * if he was a thief then take out the trap_look() daemon | |
108 */ | |
109 if (player.t_ctype == C_THIEF || | |
110 player.t_ctype == C_MONK || | |
111 player.t_ctype == C_ASSASIN) | |
112 kill_daemon(trap_look); | |
113 | |
114 /* | |
115 * if he becomes a thief then add the trap_look() daemon | |
116 */ | |
117 if (newclass == C_THIEF || newclass == C_ASSASIN || newclass == C_MONK) | |
118 daemon(trap_look, 0, AFTER); | |
119 char_type = player.t_ctype = newclass; | |
120 save = pstats.s_hpt; | |
121 max_stats.s_hpt = pstats.s_hpt = 0; | |
122 max_stats.s_lvl = pstats.s_lvl = 0; | |
123 max_stats.s_lvladj = pstats.s_lvladj = 0; | |
124 max_stats.s_exp = pstats.s_exp -= pstats.s_exp/10; | |
125 check_level(); | |
126 if (pstats.s_hpt > save) /* don't add to current hits */ | |
127 pstats.s_hpt = save; | |
128 } | |
129 } | |
130 | |
131 /* | |
132 * Use the relic that our monster is wielding. | |
133 */ | |
134 m_use_relic(monster) | |
135 register struct thing *monster; | |
136 { | |
137 register struct object *obj; | |
138 | |
139 /* Make sure we really have it */ | |
140 if (monster->t_using) obj = OBJPTR(monster->t_using); | |
141 else { | |
142 debug("Relic not set!"); | |
143 monster->t_action = A_NIL; | |
144 return; | |
145 } | |
146 | |
147 /* Now let's see what we're using */ | |
148 if (obj->o_type == RELIC) switch (obj->o_which) { | |
149 case MING_STAFF: { | |
150 static struct object missile = { | |
151 MISSILE, {0,0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1 | |
152 }; | |
153 | |
154 debug("Firing Ming's staff"); | |
155 sprintf(missile.o_hurldmg, "%dd4", monster->t_stats.s_lvl); | |
156 do_motion(&missile, | |
157 monster->t_newpos.y, monster->t_newpos.x, monster); | |
158 hit_monster(unc(missile.o_pos), &missile, monster); | |
159 monster->t_artifact = monster->t_artifact * 4 / 5; | |
160 } | |
161 when EMORI_CLOAK: | |
162 debug("stunning with Emori's cloak"); | |
163 do_zap(monster, obj, &monster->t_newpos, WS_PARALYZE, NULL); | |
164 obj->o_charges = 0; | |
165 | |
166 when ASMO_ROD: { | |
167 char *name; | |
168 | |
169 switch (rnd(3)) { /* Select a function */ | |
170 case 0: name = "lightning bolt"; | |
171 when 1: name = "flame"; | |
172 otherwise: name = "ice"; | |
173 } | |
174 shoot_bolt( monster, | |
175 monster->t_pos, | |
176 monster->t_newpos, | |
177 FALSE, | |
178 monster->t_index, | |
179 name, | |
180 roll(monster->t_stats.s_lvl,6)); | |
181 monster->t_artifact /= 2; | |
182 } | |
183 when BRIAN_MANDOLIN: | |
184 /* Make sure the defendant is still around */ | |
185 if (DISTANCE(monster->t_pos.y, monster->t_pos.x, | |
186 hero.y, hero.x) < 25) { | |
187 if (!save(VS_MAGIC, &player, -4) && | |
188 !ISWEARING(R_ALERT)) { | |
189 msg("Some beautiful music enthralls you."); | |
190 player.t_no_move += movement(&player) * FREEZETIME; | |
191 player.t_action = A_FREEZE; | |
192 monster->t_artifact = monster->t_artifact * 2 / 3; | |
193 } | |
194 else { | |
195 msg("You wince at a sour note."); | |
196 monster->t_artifact /= 3; | |
197 } | |
198 } | |
199 when GERYON_HORN: | |
200 /* Make sure the defendant is still around */ | |
201 if (DISTANCE(monster->t_pos.y, monster->t_pos.x, | |
202 hero.y, hero.x) < 25) { | |
203 if (!ISWEARING(R_HEROISM) && | |
204 !save(VS_MAGIC, &player, -4)) { | |
205 turn_on(player, ISFLEE); | |
206 player.t_dest = &monster->t_pos; | |
207 msg("A shrill blast terrifies you."); | |
208 monster->t_artifact = monster->t_artifact * 3 / 4; | |
209 } | |
210 else { | |
211 msg("A shrill blast sends chills up your spine."); | |
212 monster->t_artifact /= 3; | |
213 } | |
214 } | |
215 | |
216 otherwise: | |
217 /* Unknown RELIC! */ | |
218 debug("Unknown wielded relic %d", obj->o_which); | |
219 } | |
220 else debug("Declared relic is %d", obj->o_type); | |
221 | |
222 turn_off(*monster, CANSURPRISE); | |
223 /* Reset the monsters actions */ | |
224 monster->t_action = A_NIL; | |
225 monster->t_using = NULL; | |
226 } | |
227 | |
228 /* | |
229 * add something to the contents of something else | |
230 */ | |
231 put_contents(bag, item) | |
232 register struct object *bag; /* the holder of the items */ | |
233 register struct linked_list *item; /* the item to put inside */ | |
234 { | |
235 register struct linked_list *titem; | |
236 register struct object *tobj; | |
237 | |
238 bag->o_ac++; | |
239 tobj = OBJPTR(item); | |
240 for (titem = bag->contents; titem != NULL; titem = next(titem)) { | |
241 if ((OBJPTR(titem))->o_which == tobj->o_which) | |
242 break; | |
243 } | |
244 if (titem == NULL) { /* if not a duplicate put at beginning */ | |
245 attach(bag->contents, item); | |
246 } | |
247 else { | |
248 item->l_prev = titem; | |
249 item->l_next = titem->l_next; | |
250 if (next(titem) != NULL) | |
251 (titem->l_next)->l_prev = item; | |
252 titem->l_next = item; | |
253 } | |
254 } | |
255 | |
256 /* | |
257 * remove something from something else | |
258 */ | |
259 take_contents(bag, item) | |
260 register struct object *bag; /* the holder of the items */ | |
261 register struct linked_list *item; | |
262 { | |
263 | |
264 if (bag->o_ac <= 0) { | |
265 msg("Nothing to take out"); | |
266 return; | |
267 } | |
268 bag->o_ac--; | |
269 detach(bag->contents, item); | |
270 if (!add_pack(item, FALSE, NULL)) | |
271 put_contents(bag, item); | |
272 } | |
273 | |
274 | |
275 do_bag(item) | |
276 register struct linked_list *item; | |
277 { | |
278 | |
279 register struct linked_list *titem; | |
280 register struct object *obj, *tobj; | |
281 bool doit = TRUE; | |
282 | |
283 obj = OBJPTR(item); | |
284 while (doit) { | |
285 msg("What do you want to do? (* for a list): "); | |
286 mpos = 0; | |
287 switch (readchar()) { | |
288 case EOF: | |
289 case ESCAPE: | |
290 msg (""); | |
291 doit = FALSE; | |
292 when '1': | |
293 inventory(obj->contents, ALL); | |
294 | |
295 when '2': | |
296 if (obj->o_ac >= MAXCONTENTS) { | |
297 msg("the %s is full", m_magic[obj->o_which].mi_name); | |
298 break; | |
299 } | |
300 switch (obj->o_which) { | |
301 case MM_BEAKER: | |
302 titem = get_item(pack, "put in", POTION, FALSE, FALSE); | |
303 when MM_BOOK: | |
304 titem = get_item(pack, "put in", SCROLL, FALSE, FALSE); | |
305 } | |
306 if (titem == NULL) | |
307 break; | |
308 detach(pack, titem); | |
309 inpack--; | |
310 put_contents(obj, titem); | |
311 | |
312 when '3': | |
313 titem = get_item(obj->contents,"take out",ALL,FALSE,FALSE); | |
314 if (titem == NULL) | |
315 break; | |
316 take_contents(obj, titem); | |
317 | |
318 when '4': | |
319 switch (obj->o_which) { | |
320 case MM_BEAKER: | |
321 titem = get_item(obj->contents,"quaff",ALL,FALSE,FALSE); | |
322 if (titem == NULL) | |
323 break; | |
324 tobj = OBJPTR(titem); | |
325 obj->o_ac--; | |
326 detach(obj->contents, titem); | |
327 quaff(tobj->o_which, | |
328 tobj->o_kind, | |
329 tobj->o_flags, | |
330 TRUE); | |
331 if (p_know[tobj->o_which] && p_guess[tobj->o_which]) | |
332 { | |
333 free(p_guess[tobj->o_which]); | |
334 p_guess[tobj->o_which] = NULL; | |
335 } | |
336 else if (!p_know[tobj->o_which] && | |
337 askme && | |
338 (tobj->o_flags & ISKNOW) == 0 && | |
339 (tobj->o_flags & ISPOST) == 0 && | |
340 p_guess[tobj->o_which] == NULL) { | |
341 nameitem(titem, FALSE); | |
342 } | |
343 o_discard(titem); | |
344 when MM_BOOK: | |
345 if (on(player, ISBLIND)) { | |
346 msg("You can't see to read anything"); | |
347 break; | |
348 } | |
349 titem = get_item(obj->contents,"read",ALL,FALSE,FALSE); | |
350 if (titem == NULL) | |
351 break; | |
352 tobj = OBJPTR(titem); | |
353 obj->o_ac--; | |
354 detach(obj->contents, titem); | |
355 read_scroll(tobj->o_which, | |
356 tobj->o_flags & (ISCURSED|ISBLESSED), | |
357 TRUE); | |
358 if (s_know[tobj->o_which] && s_guess[tobj->o_which]) | |
359 { | |
360 free(s_guess[tobj->o_which]); | |
361 s_guess[tobj->o_which] = NULL; | |
362 } | |
363 else if (!s_know[tobj->o_which] && | |
364 askme && | |
365 (tobj->o_flags & ISKNOW) == 0 && | |
366 (tobj->o_flags & ISPOST) == 0 && | |
367 s_guess[tobj->o_which] == NULL) { | |
368 nameitem(titem, FALSE); | |
369 } | |
370 o_discard(titem); | |
371 } | |
372 doit = FALSE; | |
373 | |
374 otherwise: | |
375 wclear(hw); | |
376 touchwin(hw); | |
377 mvwaddstr(hw,0,0,"The following operations are available:"); | |
378 mvwaddstr(hw,2,0,"[1]\tInventory\n"); | |
379 wprintw(hw,"[2]\tPut something in the %s\n", | |
380 m_magic[obj->o_which].mi_name); | |
381 wprintw(hw,"[3]\tTake something out of the %s\n", | |
382 m_magic[obj->o_which].mi_name); | |
383 switch(obj->o_which) { | |
384 case MM_BEAKER: waddstr(hw,"[4]\tQuaff a potion\n"); | |
385 when MM_BOOK: waddstr(hw,"[4]\tRead a scroll\n"); | |
386 } | |
387 waddstr(hw,"[ESC]\tLeave this menu\n"); | |
388 mvwaddstr(hw, lines-1, 0, spacemsg); | |
389 draw(hw); | |
390 wait_for (' '); | |
391 clearok(cw, TRUE); | |
392 touchwin(cw); | |
393 } | |
394 } | |
395 } | |
396 | |
397 do_panic(who) | |
398 int who; /* Kind of monster to panic (all if who is NULL) */ | |
399 { | |
400 register int x,y; | |
401 register struct linked_list *mon, *item; | |
402 register struct thing *th; | |
403 | |
404 for (x = hero.x-2; x <= hero.x+2; x++) { | |
405 for (y = hero.y-2; y <= hero.y+2; y++) { | |
406 if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1) | |
407 continue; | |
408 if (isalpha(mvwinch(mw, y, x))) { | |
409 if ((mon = find_mons(y, x)) != NULL) { | |
410 th = THINGPTR(mon); | |
411 | |
412 /* Is this the right kind of monster to panic? */ | |
413 if (who && th->t_index != who) continue; | |
414 | |
415 if (who || | |
416 (!on(*th, ISUNDEAD) && !save(VS_MAGIC, th, 0) && off(*th, WASTURNED))) { | |
417 msg("%s %s.", prname(monster_name(th), TRUE), | |
418 terse ? "panics" : "turns to run in panic"); | |
419 | |
420 turn_on(*th, ISFLEE); | |
421 turn_on(*th, WASTURNED); | |
422 turn_off(*th, CANSURPRISE); | |
423 | |
424 /* Disrupt what it was doing */ | |
425 dsrpt_monster(th, TRUE, TRUE); | |
426 | |
427 /* If monster was suffocating, stop it */ | |
428 if (on(*th, DIDSUFFOCATE)) { | |
429 turn_off(*th, DIDSUFFOCATE); | |
430 extinguish(suffocate); | |
431 } | |
432 | |
433 /* If monster held us, stop it */ | |
434 if (on(*th, DIDHOLD) && (--hold_count == 0)) | |
435 turn_off(player, ISHELD); | |
436 turn_off(*th, DIDHOLD); | |
437 | |
438 /* | |
439 * if he has something he might drop it | |
440 */ | |
441 if ((item = th->t_pack) != NULL && | |
442 (OBJPTR(item))->o_type != RELIC && | |
443 rnd(100) < 50) { | |
444 detach(th->t_pack, item); | |
445 fall(item, FALSE); | |
446 } | |
447 | |
448 /* It is okay to turn tail */ | |
449 th->t_oldpos = th->t_pos; | |
450 } | |
451 runto(th, &hero); | |
452 } | |
453 } | |
454 } | |
455 } | |
456 } | |
457 | |
458 /* | |
459 * print miscellaneous magic bonuses | |
460 */ | |
461 char * | |
462 misc_name(obj) | |
463 register struct object *obj; | |
464 { | |
465 static char buf[LINELEN]; | |
466 char buf1[LINELEN]; | |
467 | |
468 buf[0] = '\0'; | |
469 buf1[0] = '\0'; | |
470 if (!(obj->o_flags & ISKNOW)) | |
471 return (m_magic[obj->o_which].mi_name); | |
472 switch (obj->o_which) { | |
473 case MM_BRACERS: | |
474 case MM_PROTECT: | |
475 strcat(buf, num(obj->o_ac, 0)); | |
476 strcat(buf, " "); | |
477 } | |
478 switch (obj->o_which) { | |
479 case MM_G_OGRE: | |
480 case MM_G_DEXTERITY: | |
481 case MM_JEWEL: | |
482 case MM_STRANGLE: | |
483 case MM_R_POWERLESS: | |
484 case MM_DANCE: | |
485 if (obj->o_flags & ISCURSED) | |
486 strcat(buf, "cursed "); | |
487 } | |
488 strcat(buf, m_magic[obj->o_which].mi_name); | |
489 switch (obj->o_which) { | |
490 case MM_JUG: | |
491 if (obj->o_ac == JUG_EMPTY) | |
492 strcat(buf1, " [empty]"); | |
493 else if (p_know[obj->o_ac]) | |
494 sprintf(buf1, " [containing a potion of %s (%s)]", | |
495 p_magic[obj->o_ac].mi_name, | |
496 p_colors[obj->o_ac]); | |
497 else sprintf(buf1, " [containing a%s %s liquid]", | |
498 vowelstr(p_colors[obj->o_ac]), | |
499 p_colors[obj->o_ac]); | |
500 when MM_BEAKER: | |
501 case MM_BOOK: { | |
502 sprintf(buf1, " [containing %d]", obj->o_ac); | |
503 } | |
504 when MM_OPEN: | |
505 case MM_HUNGER: | |
506 sprintf(buf1, " [%d ring%s]", obj->o_charges, | |
507 obj->o_charges == 1 ? "" : "s"); | |
508 when MM_DRUMS: | |
509 sprintf(buf1, " [%d beat%s]", obj->o_charges, | |
510 obj->o_charges == 1 ? "" : "s"); | |
511 when MM_DISAPPEAR: | |
512 case MM_CHOKE: | |
513 sprintf(buf1, " [%d pinch%s]", obj->o_charges, | |
514 obj->o_charges == 1 ? "" : "es"); | |
515 when MM_KEOGHTOM: | |
516 sprintf(buf1, " [%d application%s]", obj->o_charges, | |
517 obj->o_charges == 1 ? "" : "s"); | |
518 when MM_SKILLS: | |
519 sprintf(buf1, " [%s]", char_class[obj->o_ac].name); | |
520 } | |
521 strcat (buf, buf1); | |
522 return buf; | |
523 } | |
524 | |
525 use_emori() | |
526 { | |
527 char selection; /* Cloak function */ | |
528 int state = 0; /* Menu state */ | |
529 | |
530 msg("What do you want to do? (* for a list): "); | |
531 do { | |
532 selection = tolower(readchar()); | |
533 switch (selection) { | |
534 case '*': | |
535 if (state != 1) { | |
536 wclear(hw); | |
537 touchwin(hw); | |
538 mvwaddstr(hw, 2, 0, "[1] Fly\n[2] Stop flying\n"); | |
539 waddstr(hw, "[3] Turn invisible\n[4] Turn Visible\n"); | |
540 mvwaddstr(hw, 0, 0, "What do you want to do? "); | |
541 draw(hw); | |
542 state = 1; /* Now in prompt window */ | |
543 } | |
544 break; | |
545 | |
546 case ESCAPE: | |
547 if (state == 1) { | |
548 clearok(cw, TRUE); /* Set up for redraw */ | |
549 touchwin(cw); | |
550 } | |
551 msg(""); | |
552 | |
553 after = FALSE; | |
554 return; | |
555 | |
556 when '1': | |
557 case '2': | |
558 case '3': | |
559 case '4': | |
560 if (state == 1) { /* In prompt window */ | |
561 clearok(cw, TRUE); /* Set up for redraw */ | |
562 touchwin(cw); | |
563 } | |
564 | |
565 msg(""); | |
566 | |
567 state = 2; /* Finished */ | |
568 break; | |
569 | |
570 default: | |
571 if (state == 1) { /* In the prompt window */ | |
572 mvwaddstr(hw, 0, 0, | |
573 "Please enter a selection between 1 and 4: "); | |
574 draw(hw); | |
575 } | |
576 else { /* Normal window */ | |
577 mpos = 0; | |
578 msg("Please enter a selection between 1 and 4: "); | |
579 } | |
580 } | |
581 } while (state != 2); | |
582 | |
583 /* We now must have a selection between 1 and 4 */ | |
584 switch (selection) { | |
585 case '1': /* Fly */ | |
586 if (on(player, ISFLY)) { | |
587 extinguish(land); /* Extinguish in case of potion */ | |
588 msg("%slready flying.", terse ? "A" : "You are a"); | |
589 } | |
590 else { | |
591 msg("You feel lighter than air!"); | |
592 turn_on(player, ISFLY); | |
593 } | |
594 when '2': /* Stop flying */ | |
595 if (off(player, ISFLY)) | |
596 msg("%sot flying.", terse ? "N" : "You are n"); | |
597 else { | |
598 if (find_slot(land)) | |
599 msg("%sot flying by the cloak.", | |
600 terse ? "N" : "You are n"); | |
601 else land(); | |
602 } | |
603 when '3': /* Turn invisible */ | |
604 if (off(player, ISINVIS)) { | |
605 turn_on(player, ISINVIS); | |
606 msg("You have a tingling feeling all over your body"); | |
607 PLAYER = IPLAYER; | |
608 light(&hero); | |
609 } | |
610 else { | |
611 extinguish(appear); /* Extinguish in case of potion */ | |
612 extinguish(dust_appear);/* dust of disappearance */ | |
613 msg("%slready invisible.", terse ? "A" : "You are a"); | |
614 } | |
615 when '4': /* Turn visible */ | |
616 if (off(player, ISINVIS)) | |
617 msg("%sot invisible.", terse ? "N" : "You are n"); | |
618 else { | |
619 if (find_slot(appear) || find_slot(dust_appear)) | |
620 msg("%sot invisible by the cloak.", | |
621 terse ? "N" : "You are n"); | |
622 else appear(); | |
623 } | |
624 } | |
625 } | |
626 | |
627 #ifdef PC7300 | |
628 static menu_t Display; /* The menu structure */ | |
629 static mitem_t Dispitems[MAXQUILL+1]; /* Info for each line */ | |
630 static char Displines[MAXQUILL+1][LINELEN+1]; /* The lines themselves */ | |
631 #endif | |
632 /* | |
633 * try to write a scroll with the quill of Nagrom | |
634 */ | |
635 use_quill(obj) | |
636 struct object *obj; | |
637 { | |
638 struct linked_list *item; | |
639 register int i, | |
640 scroll_ability; | |
641 int which_scroll, | |
642 curlen, | |
643 maxlen, | |
644 dummy; | |
645 bool nohw = FALSE; | |
646 | |
647 i = which_scroll = 0; | |
648 scroll_ability = obj->o_charges; | |
649 | |
650 /* Prompt for scrolls */ | |
651 msg("Which scroll are you writing? (* for list): "); | |
652 | |
653 which_scroll = (int) (readchar() - 'a'); | |
654 if (which_scroll == (int) ESCAPE - (int) 'a') { | |
655 mpos = 0; | |
656 msg(""); | |
657 after = FALSE; | |
658 return; | |
659 } | |
660 if (which_scroll >= 0 && which_scroll < MAXQUILL) nohw = TRUE; | |
661 | |
662 else if (slow_invent) { | |
663 register char c; | |
664 | |
665 nohw = TRUE; | |
666 do { | |
667 for (i=0; i<MAXQUILL; i++) { | |
668 msg(""); | |
669 mvwaddch(msgw, 0, 0, '['); | |
670 waddch(msgw, (char) ((int) 'a' + i)); | |
671 waddstr(msgw, "] A scroll of "); | |
672 waddstr(msgw, s_magic[quill_scrolls[i].s_which].mi_name); | |
673 waddstr(msgw, morestr); | |
674 clearok(msgw, FALSE); | |
675 draw(msgw); | |
676 do { | |
677 c = readchar(); | |
678 } while (c != ' ' && c != ESCAPE); | |
679 if (c == ESCAPE) | |
680 break; | |
681 } | |
682 msg(""); | |
683 mvwaddstr(msgw, 0, 0, "Which scroll are you writing? "); | |
684 clearok(msgw, FALSE); | |
685 draw(msgw); | |
686 | |
687 which_scroll = (int) (readchar() - 'a'); | |
688 } while (which_scroll != (int) (ESCAPE - 'a') && | |
689 (which_scroll < 0 || which_scroll >= MAXQUILL)); | |
690 | |
691 if (which_scroll == (int) (ESCAPE - 'a')) { | |
692 mpos = 0; | |
693 msg(""); | |
694 after = FALSE; | |
695 return; | |
696 } | |
697 } | |
698 else { | |
699 /* Now display the possible scrolls */ | |
700 wclear(hw); | |
701 touchwin(hw); | |
702 mvwaddstr(hw, 2, 0, " Cost Scroll"); | |
703 mvwaddstr(hw, 3, 0, | |
704 "-----------------------------------------------"); | |
705 maxlen = 47; /* Maximum width of header */ | |
706 | |
707 for (i=0; i<MAXQUILL; i++) { | |
708 wmove(hw, i+4, 0); | |
709 sprintf(prbuf, "[%c] %3d A scroll of %s", | |
710 (char) ((int) 'a' + i), | |
711 quill_scrolls[i].s_cost, | |
712 s_magic[quill_scrolls[i].s_which].mi_name); | |
713 #ifdef PC7300 | |
714 /* Put it into the PC menu display */ | |
715 strcpy(Displines[i], prbuf); | |
716 Dispitems[i].mi_name = Displines[i]; | |
717 Dispitems[i].mi_flags = 0; | |
718 Dispitems[i].mi_val = i; | |
719 #endif | |
720 waddstr(hw, prbuf); | |
721 | |
722 /* Get the length of the line */ | |
723 getyx(hw, dummy, curlen); | |
724 if (maxlen < curlen) maxlen = curlen; | |
725 } | |
726 | |
727 sprintf(prbuf, "[Current scroll power = %d]", scroll_ability); | |
728 mvwaddstr(hw, 0, 0, prbuf); | |
729 waddstr(hw, " Which scroll are you writing? "); | |
730 getyx(hw, dummy, curlen); | |
731 if (maxlen < curlen) maxlen = curlen; | |
732 | |
733 #ifdef PC7300 | |
734 /* Place an end marker for the items */ | |
735 Dispitems[MAXQUILL].mi_name = 0; | |
736 | |
737 /* Design prompts */ | |
738 sprintf(prbuf, "Current scroll power is %d", scroll_ability); | |
739 | |
740 /* Set up the main menu structure */ | |
741 Display.m_label = prbuf; | |
742 Display.m_title = " Cost Scroll"; | |
743 Display.m_prompt = "Select a scroll or press Cancl to continue."; | |
744 Display.m_curptr = '\0'; | |
745 Display.m_markptr = '\0'; | |
746 Display.m_flags = M_ASISTITLE; | |
747 Display.m_selcnt = 1; | |
748 Display.m_items = Dispitems; | |
749 Display.m_curi = 0; | |
750 | |
751 /* | |
752 * Try to display the menu. If we don't have a local terminal, | |
753 * the call will fail and we will just continue with the | |
754 * normal mode. | |
755 */ | |
756 if (menu(&Display) >= 0) { | |
757 if (Display.m_selcnt == 0) { | |
758 /* Menu was cancelled */ | |
759 after = FALSE; | |
760 return FALSE; /* all done if abort */ | |
761 } | |
762 else which_scroll = (int) Display.m_curi->mi_val; | |
763 goto got_scroll; | |
764 } | |
765 #endif | |
766 /* Should we overlay? */ | |
767 if (menu_overlay && MAXQUILL + 3 < lines / 2) { | |
768 over_win(cw, hw, MAXQUILL + 5, maxlen + 3, 0, curlen, NULL); | |
769 } | |
770 else draw(hw); | |
771 } | |
772 | |
773 if (!nohw) { | |
774 which_scroll = (int) (readchar() - 'a'); | |
775 while (which_scroll < 0 || which_scroll >= MAXQUILL) { | |
776 if (which_scroll == (int) ESCAPE - (int) 'a') { | |
777 after = FALSE; | |
778 | |
779 /* Restore the screen */ | |
780 touchwin(cw); | |
781 if (MAXQUILL + 3 < lines / 2) clearok(cw, FALSE); | |
782 else { | |
783 msg(""); | |
784 clearok(cw, TRUE); | |
785 } | |
786 return; | |
787 } | |
788 wmove(hw, 0, 0); | |
789 wclrtoeol(hw); | |
790 waddstr(hw, "Please enter one of the listed scrolls. "); | |
791 getyx(hw, dummy, curlen); | |
792 if (maxlen < curlen) maxlen = curlen; | |
793 | |
794 /* Should we overlay? */ | |
795 if (menu_overlay && MAXQUILL + 3 < lines / 2) { | |
796 over_win(cw, hw, MAXQUILL + 5, maxlen + 3, | |
797 0, curlen, NULL); | |
798 } | |
799 else draw(hw); | |
800 | |
801 which_scroll = (int) (readchar() - 'a'); | |
802 } | |
803 } | |
804 | |
805 /* Now restore the screen if we have to */ | |
806 if (!nohw) { | |
807 touchwin(cw); | |
808 if (MAXQUILL + 3 < lines / 2) clearok(cw, FALSE); | |
809 else { | |
810 msg(""); | |
811 clearok(cw, TRUE); | |
812 } | |
813 } | |
814 else msg(""); | |
815 | |
816 | |
817 #ifdef PC7300 | |
818 got_scroll: | |
819 #endif | |
820 /* We've waited our required time. */ | |
821 player.t_using = NULL; | |
822 player.t_action = A_NIL; | |
823 | |
824 if (quill_scrolls[which_scroll].s_cost > scroll_ability) { | |
825 msg("Your attempt fails."); | |
826 return; | |
827 } | |
828 | |
829 obj->o_charges -= quill_scrolls[which_scroll].s_cost; | |
830 item = spec_item(SCROLL, quill_scrolls[which_scroll].s_which, 0, 0); | |
831 if (add_pack(item, FALSE, NULL) == FALSE) { | |
832 (OBJPTR(item))->o_pos = hero; | |
833 fall(item, TRUE); | |
834 } | |
835 } | |
836 | |
837 use_mm(which) | |
838 int which; | |
839 { | |
840 register struct object *obj; | |
841 register struct linked_list *item; | |
842 bool cursed, blessed, is_mm; | |
843 | |
844 cursed = FALSE; | |
845 is_mm = FALSE; | |
846 | |
847 if (which < 0) { /* A real miscellaneous magic item */ | |
848 /* This is miscellaneous magic. It takes 3 movement periods to use */ | |
849 if (player.t_action != C_USE) { | |
850 int units; /* Number of movement units for the item */ | |
851 | |
852 item = get_item(pack, "use", USEABLE, FALSE, FALSE); | |
853 | |
854 /* | |
855 * Make certain that it is a micellaneous magic item | |
856 */ | |
857 if (item == NULL) | |
858 return; | |
859 | |
860 units = usage_time(item); | |
861 if (units < 0) return; | |
862 | |
863 player.t_using = item; /* Remember what it is */ | |
864 player.t_action = C_USE; /* We are quaffing */ | |
865 player.t_no_move = units * movement(&player); | |
866 return; | |
867 } | |
868 | |
869 /* We have waited our time, let's use the item */ | |
870 item = player.t_using; | |
871 player.t_using = NULL; | |
872 player.t_action = A_NIL; | |
873 | |
874 is_mm = TRUE; | |
875 | |
876 obj = OBJPTR(item); | |
877 cursed = (obj->o_flags & ISCURSED) != 0; | |
878 blessed = (obj->o_flags & ISBLESSED) != 0; | |
879 which = obj->o_which; | |
880 } | |
881 | |
882 if (obj->o_type == POTION) { /* An potion */ | |
883 is_mm = FALSE; | |
884 inpack--; | |
885 detach (pack, item); | |
886 switch (obj->o_which) { | |
887 case P_POISON: | |
888 if (cur_weapon) { | |
889 if (cur_weapon->o_type == RELIC) { | |
890 msg("The poison burns off %s", | |
891 inv_name(cur_weapon,FALSE)); | |
892 } | |
893 else { | |
894 cur_weapon->o_flags |= ISPOISON; | |
895 msg("Your weapon has %s gooey stuff on it", | |
896 p_colors[cur_weapon->o_which]); | |
897 } | |
898 } | |
899 else | |
900 msg("The poison pours on the floor and disappears!"); | |
901 } | |
902 o_discard(item); | |
903 } | |
904 else if (obj->o_type == RELIC) { /* An artifact */ | |
905 is_mm = FALSE; | |
906 switch (obj->o_which) { | |
907 case EMORI_CLOAK: | |
908 use_emori(); | |
909 when QUILL_NAGROM: | |
910 use_quill(obj); | |
911 when BRIAN_MANDOLIN: | |
912 /* Put monsters around us to sleep */ | |
913 read_scroll(S_HOLD, 0, FALSE); | |
914 when GERYON_HORN: | |
915 /* Chase close monsters away */ | |
916 msg("The horn blasts a shrill tone."); | |
917 do_panic(NULL); | |
918 when HEIL_ANKH: | |
919 case YENDOR_AMULET: | |
920 case STONEBONES_AMULET: | |
921 /* Nothing happens by this mode */ | |
922 msg("Nothing happens."); | |
923 when EYE_VECNA: | |
924 msg("The pain subsides..."); | |
925 when SURTUR_RING: | |
926 /* Panic fire giants */ | |
927 do_panic(findmindex("fire giant")); | |
928 } | |
929 } | |
930 else switch (which) { /* Miscellaneous Magic */ | |
931 /* | |
932 * the jug of alchemy manufactures potions when you drink | |
933 * the potion it will make another after a while | |
934 */ | |
935 case MM_JUG: | |
936 if (obj->o_ac == JUG_EMPTY) { | |
937 msg("The jug is empty"); | |
938 break; | |
939 } | |
940 quaff (obj->o_ac, NULL, NULL, FALSE); | |
941 obj->o_ac = JUG_EMPTY; | |
942 fuse (alchemy, obj, ALCHEMYTIME, AFTER); | |
943 if (!(obj->o_flags & ISKNOW)) | |
944 whatis(item); | |
945 | |
946 /* | |
947 * the beaker of plentiful potions is used to hold potions | |
948 * the book of infinite spells is used to hold scrolls | |
949 */ | |
950 when MM_BEAKER: | |
951 case MM_BOOK: | |
952 do_bag(item); | |
953 | |
954 /* | |
955 * the chime of opening opens up secret doors | |
956 */ | |
957 when MM_OPEN: | |
958 { | |
959 register struct linked_list *exit; | |
960 register struct room *rp; | |
961 register coord *cp; | |
962 | |
963 if (obj->o_charges <= 0) { | |
964 msg("The chime is cracked!"); | |
965 break; | |
966 } | |
967 obj->o_charges--; | |
968 msg("chime... chime... hime... ime... me... e..."); | |
969 if ((rp = roomin(&hero)) == NULL) { | |
970 search(FALSE, TRUE); /* Non-failing search for door */ | |
971 break; | |
972 } | |
973 for (exit = rp->r_exit; exit != NULL; exit = next(exit)) { | |
974 cp = DOORPTR(exit); | |
975 if (winat(cp->y, cp->x) == SECRETDOOR) { | |
976 mvaddch (cp->y, cp->x, DOOR); | |
977 if (cansee (cp->y, cp->x)) | |
978 mvwaddch(cw, cp->y, cp->x, DOOR); | |
979 } | |
980 } | |
981 } | |
982 | |
983 /* | |
984 * the chime of hunger just makes the hero hungry | |
985 */ | |
986 when MM_HUNGER: | |
987 if (obj->o_charges <= 0) { | |
988 msg("The chime is cracked!"); | |
989 break; | |
990 } | |
991 obj->o_charges--; | |
992 if (food_left >= MORETIME + 5) { | |
993 food_left = MORETIME + 5; | |
994 msg(terse? "Getting hungry" : "You are starting to get hungry"); | |
995 hungry_state = F_HUNGRY; | |
996 } | |
997 aggravate(TRUE, TRUE); | |
998 | |
999 /* | |
1000 * the drums of panic make all creatures within two squares run | |
1001 * from the hero in panic unless they save or they are mindless | |
1002 * undead | |
1003 */ | |
1004 when MM_DRUMS: | |
1005 if (obj->o_charges <= 0) { | |
1006 msg("The drum is broken!"); | |
1007 break; | |
1008 } | |
1009 obj->o_charges--; | |
1010 do_panic(NULL); | |
1011 /* | |
1012 * dust of disappearance makes the player invisible for a while | |
1013 */ | |
1014 when MM_DISAPPEAR: | |
1015 m_know[MM_DISAPPEAR] = TRUE; | |
1016 if (obj->o_charges <= 0) { | |
1017 msg("No more dust!"); | |
1018 break; | |
1019 } | |
1020 obj->o_charges--; | |
1021 msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze."); | |
1022 if (!find_slot(dust_appear)) { | |
1023 turn_on(player, ISINVIS); | |
1024 fuse(dust_appear, 0, DUSTTIME, AFTER); | |
1025 PLAYER = IPLAYER; | |
1026 light(&hero); | |
1027 } | |
1028 else lengthen(dust_appear, DUSTTIME); | |
1029 | |
1030 /* | |
1031 * dust of choking and sneezing can kill the hero if he misses | |
1032 * the save | |
1033 */ | |
1034 when MM_CHOKE: | |
1035 m_know[MM_CHOKE] = TRUE; | |
1036 if (obj->o_charges <= 0) { | |
1037 msg("No more dust!"); | |
1038 break; | |
1039 } | |
1040 obj->o_charges--; | |
1041 msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze."); | |
1042 if (!cur_relic[SURTUR_RING] && !save(VS_POISON, &player, 0)) { | |
1043 msg ("You choke to death!!! --More--"); | |
1044 pstats.s_hpt = -1; /* in case he hangs up the phone */ | |
1045 wait_for(' '); | |
1046 death(D_CHOKE); | |
1047 } | |
1048 else { | |
1049 msg("You begin to cough and choke uncontrollably"); | |
1050 if (find_slot(unchoke)) | |
1051 lengthen(unchoke, DUSTTIME); | |
1052 else | |
1053 fuse(unchoke, 0, DUSTTIME, AFTER); | |
1054 turn_on(player, ISHUH); | |
1055 turn_on(player, ISBLIND); | |
1056 light(&hero); | |
1057 } | |
1058 | |
1059 when MM_KEOGHTOM: | |
1060 /* | |
1061 * this is a very powerful healing ointment | |
1062 * but it takes a while to put on... | |
1063 */ | |
1064 obj->o_charges--; | |
1065 if (on(player, HASDISEASE)) { | |
1066 extinguish(cure_disease); | |
1067 cure_disease(); | |
1068 msg(terse ? "You feel yourself improving." | |
1069 : "You begin to feel yourself improving again."); | |
1070 } | |
1071 if (on(player, HASINFEST)) { | |
1072 turn_off(player, HASINFEST); | |
1073 infest_dam = 0; | |
1074 msg(terse ? "You feel yourself improving." | |
1075 : "You begin to feel yourself improving again."); | |
1076 } | |
1077 if (on(player, DOROT)) { | |
1078 msg("You feel your skin returning to normal."); | |
1079 turn_off(player, DOROT); | |
1080 } | |
1081 pstats.s_hpt += roll(pstats.s_lvl, 6); | |
1082 if (pstats.s_hpt > max_stats.s_hpt) | |
1083 pstats.s_hpt = max_stats.s_hpt; | |
1084 sight(); | |
1085 msg("You begin to feel much better."); | |
1086 | |
1087 /* | |
1088 * The book has a character class associated with it. | |
1089 * if your class matches that of the book, it will raise your | |
1090 * level by one. If your class does not match the one of the book, | |
1091 * it change your class to that of book. | |
1092 * Note that it takes a while to read. | |
1093 */ | |
1094 when MM_SKILLS: | |
1095 detach (pack, item); | |
1096 inpack--; | |
1097 changeclass(obj->o_ac); | |
1098 | |
1099 otherwise: | |
1100 msg("What a strange magic item you have!"); | |
1101 } | |
1102 status(FALSE); | |
1103 if (is_mm && m_know[which] && m_guess[which]) { | |
1104 free(m_guess[which]); | |
1105 m_guess[which] = NULL; | |
1106 } | |
1107 else if (is_mm && | |
1108 !m_know[which] && | |
1109 askme && | |
1110 (obj->o_flags & ISKNOW) == 0 && | |
1111 m_guess[which] == NULL) { | |
1112 nameitem(item, FALSE); | |
1113 } | |
1114 if (item != NULL && which == MM_SKILLS) | |
1115 o_discard(item); | |
1116 updpack(TRUE, &player); | |
1117 } | |
1118 | |
1119 /* | |
1120 * usage_time: | |
1121 * Return how long it takes to use an item. For now we only give time | |
1122 * for MM, RELIC, SCROLL, and POTION items. | |
1123 */ | |
1124 | |
1125 int | |
1126 usage_time(item) | |
1127 struct linked_list *item; | |
1128 { | |
1129 register struct object *obj; | |
1130 register int units = -1; | |
1131 | |
1132 obj = OBJPTR(item); | |
1133 switch (obj->o_type) { | |
1134 case SCROLL: units = 4; | |
1135 when POTION: units = 3; | |
1136 when RELIC: /* An artifact */ | |
1137 switch (obj->o_which) { | |
1138 case QUILL_NAGROM: units = 2; | |
1139 when EMORI_CLOAK: units = 2; | |
1140 when BRIAN_MANDOLIN:units = 4; | |
1141 when GERYON_HORN: units = 3; | |
1142 when HEIL_ANKH: | |
1143 case YENDOR_AMULET: | |
1144 case STONEBONES_AMULET: | |
1145 units = 2; | |
1146 when EYE_VECNA: | |
1147 /* Do some effects right away! */ | |
1148 units = 6; | |
1149 | |
1150 /* The eye will do nothing other than give a headache */ | |
1151 pstats.s_hpt -= 35; | |
1152 msg("You feel a sudden shooting pain in your eye!"); | |
1153 if (pstats.s_hpt < 0) { | |
1154 msg ("The pain is too much for you! -- More --"); | |
1155 wait_for(' '); | |
1156 death(D_RELIC); | |
1157 } | |
1158 when SURTUR_RING: | |
1159 units = 3; | |
1160 msg("Your nose tickles a bit."); | |
1161 } | |
1162 when MM: | |
1163 switch (obj->o_which) { /* Miscellaneous Magic */ | |
1164 case MM_JUG: | |
1165 if (obj->o_ac == JUG_EMPTY) { | |
1166 msg("The jug is empty"); | |
1167 return (-1); | |
1168 } | |
1169 units = 3; | |
1170 when MM_BEAKER: | |
1171 case MM_BOOK: | |
1172 /* This is a strange case because it can go forever */ | |
1173 units = 1; | |
1174 when MM_OPEN: | |
1175 case MM_HUNGER: | |
1176 /* Chimes */ | |
1177 units = 3; | |
1178 when MM_DRUMS: | |
1179 units = 3; | |
1180 when MM_DISAPPEAR: | |
1181 case MM_CHOKE: | |
1182 /* Dust */ | |
1183 units = 3; | |
1184 when MM_KEOGHTOM: | |
1185 /* Ointment */ | |
1186 if (obj->o_charges <= 0) { | |
1187 msg("The jar is empty!"); | |
1188 return (-1); | |
1189 } | |
1190 units = 5; | |
1191 when MM_SKILLS: | |
1192 /* A whole book! */ | |
1193 units = 15; | |
1194 otherwise: | |
1195 /* What is it? */ | |
1196 units = -1; | |
1197 } | |
1198 otherwise: units = -1; | |
1199 } | |
1200 | |
1201 return (units); | |
1202 } |