Annotation of early-roguelike/arogue5/misc.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * routines dealing specifically with miscellaneous magic
3: *
4: * Advanced Rogue
5: * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
6: * All rights reserved.
7: *
8: * See the file LICENSE.TXT for full copyright and licensing information.
9: */
10:
11: #include "curses.h"
12: #include <stdlib.h>
13: #include <ctype.h>
14: #include <string.h>
15: #include "rogue.h"
16:
17: /*
18: * See if a monster has some magic it can use. Use it and return TRUE if so.
19: */
20: bool
21: m_use_item(struct thing *monster, coord *monst_pos, coord *defend_pos)
22: {
23: register struct linked_list *pitem;
24: register struct object *obj;
25: register coord *shoot_dir = can_shoot(monst_pos, defend_pos);
26: int dist=DISTANCE(monst_pos->y, monst_pos->x, defend_pos->y, defend_pos->x);
27:
28: for (pitem=monster->t_pack; pitem; pitem=next(pitem)) {
29: obj = OBJPTR(pitem);
30: if (obj->o_type != RELIC) continue; /* Only care about relics now */
31: switch (obj->o_which) {
32: case MING_STAFF: {
33: static struct object missile = {
34: MISSILE, {0,0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
35: };
36:
37: if (shoot_dir != NULL) {
38: sprintf(missile.o_hurldmg, "%dd4", monster->t_stats.s_lvl);
39: do_motion(&missile, shoot_dir->y, shoot_dir->x, monster);
40: hit_monster(unc(missile.o_pos), &missile, monster);
41: return(TRUE);
42: }
43: }
44: when ASMO_ROD:
45: /* The bolt must be able to reach the defendant */
46: if (shoot_dir != NULL && dist < BOLT_LENGTH * BOLT_LENGTH) {
47: char *name;
48:
49: switch (rnd(3)) { /* Select a function */
50: case 0: name = "lightning bolt";
51: when 1: name = "flame";
52: otherwise: name = "ice";
53: }
54: shoot_bolt( monster,
55: *monst_pos,
56: *shoot_dir,
57: FALSE,
58: monster->t_index,
59: name,
60: roll(monster->t_stats.s_lvl,6));
61: return(TRUE);
62: }
63: when BRIAN_MANDOLIN:
64: /* The defendant must be the player and within 2 spaces */
65: if (ce(*defend_pos, hero) && dist < 9 && no_command == 0 &&
66: rnd(100) < 33) {
67: if (!save(VS_MAGIC, &player, -4) &&
68: !ISWEARING(R_ALERT)) {
69: msg("Some beautiful music enthralls you.");
70: no_command += FREEZETIME;
71: }
72: else msg("You wince at a sour note.");
73: return(TRUE);
74: }
75: when GERYON_HORN:
76: /* The defendant must be the player and within 2 spaces */
77: if (ce(*defend_pos, hero) && dist < 9 &&
78: (off(player, ISFLEE) || player.t_dest != &monster->t_pos)
79: && rnd(100) < 33) {
80: if (!ISWEARING(R_HEROISM) &&
81: !save(VS_MAGIC, &player, -4)) {
82: turn_on(player, ISFLEE);
83: player.t_dest = &monster->t_pos;
84: msg("A shrill blast terrifies you.");
85: }
86: else msg("A shrill blast sends chills up your spine.");
87: return(TRUE);
88: }
89: }
90: }
91: return(FALSE);
92: }
93:
94: /*
95: * add something to the contents of something else
96: * bag: the holder of the items
97: * item: the item to put inside
98: */
99: void
100: put_contents(struct object *bag, struct linked_list *item)
101: {
102: register struct linked_list *titem;
103: register struct object *tobj;
104:
105: bag->o_ac++;
106: tobj = OBJPTR(item);
107: for (titem = bag->contents; titem != NULL; titem = next(titem)) {
108: if ((OBJPTR(titem))->o_which == tobj->o_which)
109: break;
110: }
111: if (titem == NULL) { /* if not a duplicate put at beginning */
112: attach(bag->contents, item);
113: }
114: else {
115: item->l_prev = titem;
116: item->l_next = titem->l_next;
117: if (next(titem) != NULL)
118: (titem->l_next)->l_prev = item;
119: titem->l_next = item;
120: }
121: }
122:
123: /*
124: * remove something from something else
125: * bag: the holder of the items
126: */
127: void
128: take_contents(struct object *bag, struct linked_list *item)
129: {
130:
131: if (bag->o_ac <= 0) {
132: msg("Nothing to take out");
133: return;
134: }
135: bag->o_ac--;
136: detach(bag->contents, item);
137: if (!add_pack(item, FALSE, NULL))
138: put_contents(bag, item);
139: }
140:
141:
142: void
143: do_bag(struct linked_list *item)
144: {
145:
146: register struct linked_list *titem = NULL;
147: register struct object *obj;
148: bool doit = TRUE;
149:
150: obj = OBJPTR(item);
151: while (doit) {
152: msg("What do you want to do? (* for a list): ");
153: mpos = 0;
154: switch (readchar()) {
155: case EOF:
156: case ESCAPE:
157: msg ("");
158: doit = FALSE;
159: when '1':
160: inventory(obj->contents, ALL);
161:
162: when '2':
163: if (obj->o_ac >= MAXCONTENTS) {
164: msg("the %s is full", m_magic[obj->o_which].mi_name);
165: break;
166: }
167: switch (obj->o_which) {
168: case MM_BEAKER: titem = get_item(pack, "put in", POTION);
169: when MM_BOOK: titem = get_item(pack, "put in", SCROLL);
170: }
171: if (titem == NULL)
172: break;
173: detach(pack, titem);
174: inpack--;
175: put_contents(obj, titem);
176:
177: when '3':
178: titem = get_item(obj->contents,"take out",ALL);
179: if (titem == NULL)
180: break;
181: take_contents(obj, titem);
182:
183: when '4':
184: switch (obj->o_which) {
185: case MM_BEAKER:
186: titem = get_item(obj->contents,"quaff",ALL);
187: if (titem == NULL)
188: break;
189: obj->o_ac--;
190: detach(obj->contents, titem);
191: quaff((OBJPTR(titem))->o_which,
192: (OBJPTR(titem))->o_flags & (ISCURSED | ISBLESSED),
193: TRUE);
194: o_discard(titem);
195: when MM_BOOK:
196: if (on(player, ISBLIND)) {
197: msg("You can't see to read anything");
198: break;
199: }
200: titem = get_item(obj->contents,"read",ALL);
201: if (titem == NULL)
202: break;
203: obj->o_ac--;
204: detach(obj->contents, titem);
205: read_scroll((OBJPTR(titem))->o_which,
206: (OBJPTR(titem))->o_flags & (ISCURSED|ISBLESSED),
207: TRUE);
208: o_discard(titem);
209: }
210: doit = FALSE;
211:
212: otherwise:
213: wclear(hw);
214: touchwin(hw);
215: mvwaddstr(hw,0,0,"The following operations are available:");
216: mvwaddstr(hw,2,0,"[1]\tInventory\n");
217: wprintw(hw,"[2]\tPut something in the %s\n",
218: m_magic[obj->o_which].mi_name);
219: wprintw(hw,"[3]\tTake something out of the %s\n",
220: m_magic[obj->o_which].mi_name);
221: switch(obj->o_which) {
222: case MM_BEAKER: waddstr(hw,"[4]\tQuaff a potion\n");
223: when MM_BOOK: waddstr(hw,"[4]\tRead a scroll\n");
224: }
225: waddstr(hw,"[ESC]\tLeave this menu\n");
226: mvwaddstr(hw, LINES-1, 0, spacemsg);
227: draw(hw);
228: wait_for (hw,' ');
229: clearok(cw, TRUE);
230: touchwin(cw);
231: }
232: }
233: }
234:
235: void
236: do_panic(void)
237: {
238: register int x,y;
239: register struct linked_list *mon;
240: register struct thing *th;
241:
242: for (x = hero.x-2; x <= hero.x+2; x++) {
243: for (y = hero.y-2; y <= hero.y+2; y++) {
244: if (y < 1 || x < 0 || y > LINES - 3 || x > COLS - 1)
245: continue;
246: if (isalpha(mvwinch(mw, y, x))) {
247: if ((mon = find_mons(y, x)) != NULL) {
248: th = THINGPTR(mon);
249: if (!on(*th, ISUNDEAD) && !save(VS_MAGIC, th, 0)) {
250: turn_on(*th, ISFLEE);
251: turn_on(*th, WASTURNED);
252:
253: /* If monster was suffocating, stop it */
254: if (on(*th, DIDSUFFOCATE)) {
255: turn_off(*th, DIDSUFFOCATE);
256: extinguish(suffocate);
257: }
258:
259: /* If monster held us, stop it */
260: if (on(*th, DIDHOLD) && (--hold_count == 0))
261: turn_off(player, ISHELD);
262: turn_off(*th, DIDHOLD);
263: }
264: runto(th, &hero);
265: }
266: }
267: }
268: }
269: }
270:
271: /*
272: * print miscellaneous magic bonuses
273: */
274: char *
275: misc_name(struct object *obj)
276: {
277: static char buf[LINELEN];
278: char buf1[LINELEN];
279:
280: buf[0] = '\0';
281: buf1[0] = '\0';
282: if (!(obj->o_flags & ISKNOW))
283: return (m_magic[obj->o_which].mi_name);
284: switch (obj->o_which) {
285: case MM_BRACERS:
286: case MM_PROTECT:
287: strcat(buf, num(obj->o_ac, 0));
288: strcat(buf, " ");
289: }
290: switch (obj->o_which) {
291: case MM_G_OGRE:
292: case MM_G_DEXTERITY:
293: case MM_JEWEL:
294: case MM_STRANGLE:
295: case MM_R_POWERLESS:
296: case MM_DANCE:
297: if (obj->o_flags & ISCURSED)
298: strcat(buf, "cursed ");
299: }
300: strcat(buf, m_magic[obj->o_which].mi_name);
301: switch (obj->o_which) {
302: case MM_JUG:
303: if (obj->o_ac == JUG_EMPTY)
304: strcat(buf1, " [empty]");
305: else if (p_know[obj->o_ac])
306: sprintf(buf1, " [containing a potion of %s (%s)]",
307: p_magic[obj->o_ac].mi_name,
308: p_colors[obj->o_ac]);
309: else sprintf(buf1, " [containing a%s %s liquid]",
310: vowelstr(p_colors[obj->o_ac]),
311: p_colors[obj->o_ac]);
312: when MM_BEAKER:
313: case MM_BOOK: {
314: sprintf(buf1, " [containing %d]", obj->o_ac);
315: }
316: when MM_OPEN:
317: case MM_HUNGER:
318: sprintf(buf1, " [%d ring%s]", obj->o_charges,
319: obj->o_charges == 1 ? "" : "s");
320: when MM_DRUMS:
321: sprintf(buf1, " [%d beat%s]", obj->o_charges,
322: obj->o_charges == 1 ? "" : "s");
323: when MM_DISAPPEAR:
324: case MM_CHOKE:
325: sprintf(buf1, " [%d pinch%s]", obj->o_charges,
326: obj->o_charges == 1 ? "" : "es");
327: when MM_KEOGHTOM:
328: sprintf(buf1, " [%d application%s]", obj->o_charges,
329: obj->o_charges == 1 ? "" : "s");
330: when MM_SKILLS:
331: switch (obj->o_ac) {
332: case C_MAGICIAN: strcpy(buf1, " [magic user]");
333: when C_FIGHTER: strcpy(buf1, " [fighter]");
334: when C_CLERIC: strcpy(buf1, " [cleric]");
335: when C_THIEF: strcpy(buf1, " [thief]");
336: }
337: }
338: strcat (buf, buf1);
339: return buf;
340: }
341:
342: void
343: use_emori(void)
344: {
345: char selection; /* Cloak function */
346: int state = 0; /* Menu state */
347:
348: msg("What do you want to do? (* for a list): ");
349: do {
350: selection = tolower(readchar());
351: switch (selection) {
352: case '*':
353: if (state != 1) {
354: wclear(hw);
355: touchwin(hw);
356: mvwaddstr(hw, 2, 0, "[1] Fly\n[2] Stop flying\n");
357: waddstr(hw, "[3] Turn invisible\n[4] Turn Visible\n");
358: mvwaddstr(hw, 0, 0, "What do you want to do? ");
359: draw(hw);
360: state = 1; /* Now in prompt window */
361: }
362: break;
363:
364: case ESCAPE:
365: if (state == 1) {
366: clearok(cw, TRUE); /* Set up for redraw */
367: touchwin(cw);
368: }
369: msg("");
370:
371: after = FALSE;
372: return;
373:
374: when '1':
375: case '2':
376: case '3':
377: case '4':
378: if (state == 1) { /* In prompt window */
379: clearok(cw, TRUE); /* Set up for redraw */
380: touchwin(cw);
381: }
382:
383: msg("");
384:
385: state = 2; /* Finished */
386: break;
387:
388: default:
389: if (state == 1) { /* In the prompt window */
390: mvwaddstr(hw, 0, 0,
391: "Please enter a selection between 1 and 4: ");
392: draw(hw);
393: }
394: else { /* Normal window */
395: mpos = 0;
396: msg("Please enter a selection between 1 and 4: ");
397: }
398: }
399: } while (state != 2);
400:
401: /* We now must have a selection between 1 and 4 */
402: switch (selection) {
403: case '1': /* Fly */
404: if (on(player, ISFLY)) {
405: extinguish(land); /* Extinguish in case of potion */
406: msg("%slready flying.", terse ? "A" : "You are a");
407: }
408: else {
409: msg("You feel lighter than air!");
410: turn_on(player, ISFLY);
411: }
412: when '2': /* Stop flying */
413: if (off(player, ISFLY))
414: msg("%sot flying.", terse ? "N" : "You are n");
415: else {
416: if (find_slot(land))
417: msg("%sot flying by the cloak.",
418: terse ? "N" : "You are n");
419: else land();
420: }
421: when '3': /* Turn invisible */
422: if (off(player, ISINVIS)) {
423: turn_on(player, ISINVIS);
424: msg("You have a tingling feeling all over your body");
425: PLAYER = IPLAYER;
426: light(&hero);
427: }
428: else {
429: extinguish(appear); /* Extinguish in case of potion */
430: extinguish(dust_appear);/* dust of disappearance */
431: msg("%slready invisible.", terse ? "A" : "You are a");
432: }
433: when '4': /* Turn visible */
434: if (off(player, ISINVIS))
435: msg("%sot invisible.", terse ? "N" : "You are n");
436: else {
437: if (find_slot(appear) || find_slot(dust_appear))
438: msg("%sot invisible by the cloak.",
439: terse ? "N" : "You are n");
440: else appear();
441: }
442: }
443: }
444:
445: void
446: use_mm(int which)
447: {
448: register struct object *obj = NULL;
449: register struct linked_list *item = NULL;
450: bool cursed, blessed, is_mm;
451: char buf[LINELEN];
452:
453: cursed = FALSE;
454: is_mm = FALSE;
455:
456: if (which < 0) { /* A real miscellaneous magic item */
457: is_mm = TRUE;
458: item = get_item(pack, "use", USEABLE);
459: /*
460: * Make certain that it is a micellaneous magic item
461: */
462: if (item == NULL)
463: return;
464:
465: obj = OBJPTR(item);
466: cursed = (obj->o_flags & ISCURSED) != 0;
467: blessed = (obj->o_flags & ISBLESSED) != 0;
468: which = obj->o_which;
469: }
470:
471: if (obj->o_type == RELIC) { /* An artifact */
472: is_mm = FALSE;
473: switch (obj->o_which) {
474: case EMORI_CLOAK:
475: use_emori();
476: when BRIAN_MANDOLIN:
477: /* Put monsters around us to sleep */
478: read_scroll(S_HOLD, 0, FALSE);
479: when GERYON_HORN:
480: /* Chase close monsters away */
481: msg("The horn blasts a shrill tone.");
482: do_panic();
483: when HEIL_ANKH:
484: case YENDOR_AMULET:
485: /* Nothing happens by this mode */
486: msg("Nothing happens.");
487: }
488: }
489: else switch (which) { /* Miscellaneous Magic */
490: /*
491: * the jug of alchemy manufactures potions when you drink
492: * the potion it will make another after a while
493: */
494: case MM_JUG:
495: if (obj->o_ac == JUG_EMPTY) {
496: msg("The jug is empty");
497: break;
498: }
499: quaff (obj->o_ac, 0, FALSE);
500: obj->o_ac = JUG_EMPTY;
501: fuse (alchemy, obj, ALCHEMYTIME, AFTER);
502: if (!(obj->o_flags & ISKNOW))
503: whatis(item);
504:
505: /*
506: * the beaker of plentiful potions is used to hold potions
507: * the book of infinite spells is used to hold scrolls
508: */
509: when MM_BEAKER:
510: case MM_BOOK:
511: do_bag(item);
512:
513: /*
514: * the chime of opening opens up secret doors
515: */
516: when MM_OPEN:
517: {
518: register struct linked_list *exit;
519: register struct room *rp;
520: register coord *cp;
521:
522: if (obj->o_charges <= 0) {
523: msg("The chime is cracked!");
524: break;
525: }
526: obj->o_charges--;
527: msg("chime... chime... hime... ime... me... e...");
528: if ((rp = roomin(&hero)) == NULL) {
529: search(FALSE, TRUE); /* Non-failing search for door */
530: break;
531: }
532: for (exit = rp->r_exit; exit != NULL; exit = next(exit)) {
533: cp = DOORPTR(exit);
534: if (winat(cp->y, cp->x) == SECRETDOOR) {
535: mvaddch (cp->y, cp->x, DOOR);
536: if (cansee (cp->y, cp->x))
537: mvwaddch(cw, cp->y, cp->x, DOOR);
538: }
539: }
540: }
541:
542: /*
543: * the chime of hunger just makes the hero hungry
544: */
545: when MM_HUNGER:
546: if (obj->o_charges <= 0) {
547: msg("The chime is cracked!");
548: break;
549: }
550: obj->o_charges--;
551: food_left = MORETIME + 5;
552: msg(terse ? "Getting hungry" : "You are starting to get hungry");
553: hungry_state = F_HUNGRY;
554: aggravate();
555:
556: /*
557: * the drums of panic make all creatures within two squares run
558: * from the hero in panic unless they save or they are mindless
559: * undead
560: */
561: when MM_DRUMS:
562: if (obj->o_charges <= 0) {
563: msg("The drum is broken!");
564: break;
565: }
566: obj->o_charges--;
567: /*
568: * dust of disappearance makes the player invisible for a while
569: */
570: when MM_DISAPPEAR:
571: m_know[MM_DISAPPEAR] = TRUE;
572: if (obj->o_charges <= 0) {
573: msg("No more dust!");
574: break;
575: }
576: obj->o_charges--;
577: msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze.");
578: if (!find_slot(dust_appear)) {
579: turn_on(player, ISINVIS);
580: fuse(dust_appear, 0, DUSTTIME, AFTER);
581: PLAYER = IPLAYER;
582: light(&hero);
583: }
584: else lengthen(dust_appear, DUSTTIME);
585:
586: /*
587: * dust of choking and sneezing can kill the hero if he misses
588: * the save
589: */
590: when MM_CHOKE:
591: m_know[MM_CHOKE] = TRUE;
592: if (obj->o_charges <= 0) {
593: msg("No more dust!");
594: break;
595: }
596: obj->o_charges--;
597: msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze.");
598: if (!save(VS_POISON, &player, 0)) {
599: msg ("You choke to death!!! --More--");
600: pstats.s_hpt = -1; /* in case he hangs up the phone */
601: wait_for(cw,' ');
602: death(D_CHOKE);
603: }
604: else {
605: msg("You begin to cough and choke uncontrollably");
606: if (find_slot(unchoke))
607: lengthen(unchoke, DUSTTIME);
608: else
609: fuse(unchoke, 0, DUSTTIME, AFTER);
610: turn_on(player, ISHUH);
611: turn_on(player, ISBLIND);
612: light(&hero);
613: }
614:
615: when MM_KEOGHTOM:
616: /*
617: * this is a very powerful healing ointment
618: * but it takes a while to put on...
619: */
620: if (obj->o_charges <= 0) {
621: msg("The jar is empty!");
622: break;
623: }
624: obj->o_charges--;
625: waste_time();
626: if (on(player, HASDISEASE)) {
627: extinguish(cure_disease);
628: cure_disease();
629: msg(terse ? "You feel yourself improving."
630: : "You begin to feel yourself improving again.");
631: }
632: if (on(player, HASINFEST)) {
633: turn_off(player, HASINFEST);
634: infest_dam = 0;
635: msg(terse ? "You feel yourself improving."
636: : "You begin to feel yourself improving again.");
637: }
638: if (on(player, DOROT)) {
639: msg("You feel your skin returning to normal.");
640: turn_off(player, DOROT);
641: }
642: pstats.s_hpt += roll(pstats.s_lvl, 6);
643: if (pstats.s_hpt > max_stats.s_hpt)
644: pstats.s_hpt = max_stats.s_hpt;
645: sight();
646: msg("You begin to feel much better.");
647:
648: /*
649: * The book has a character class associated with it.
650: * if your class matches that of the book, it will raise your
651: * level by one. If your class does not match the one of the book,
652: * it change your class to that of book.
653: * Note that it takes a while to read.
654: */
655: when MM_SKILLS:
656: detach (pack, item);
657: inpack--;
658: waste_time();
659: waste_time();
660: waste_time();
661: waste_time();
662: waste_time();
663: if (obj->o_ac == player.t_ctype) {
664: msg("You feel more skillful");
665: raise_level(TRUE);
666: }
667: else {
668: /*
669: * reset his class and then use check_level to reset hit
670: * points and the right level for his exp pts
671: * drop exp pts by 10%
672: */
673: long save;
674:
675: msg("You feel like a whole new person!");
676: /*
677: * if he becomes a thief he has to have leather armor
678: */
679: if (obj->o_ac == C_THIEF &&
680: cur_armor != NULL &&
681: cur_armor->o_which != LEATHER &&
682: cur_armor->o_which != STUDDED_LEATHER )
683: cur_armor->o_which = STUDDED_LEATHER;
684: /*
685: * if he's changing from a fighter then may have to change
686: * his sword since only fighter can use two-handed
687: * and bastard swords
688: */
689: if (player.t_ctype == C_FIGHTER &&
690: cur_weapon != NULL &&
691: cur_weapon->o_type == WEAPON &&
692: (cur_weapon->o_which== BASWORD ||
693: cur_weapon->o_which== TWOSWORD ))
694: cur_weapon->o_which = SWORD;
695:
696: /*
697: * if he was a thief then take out the trap_look() daemon
698: */
699: if (player.t_ctype == C_THIEF)
700: kill_daemon(trap_look);
701: /*
702: * if he becomes a thief then add the trap_look() daemon
703: */
704: if (obj->o_ac == C_THIEF)
705: start_daemon(trap_look, 0, AFTER);
706: char_type = player.t_ctype = obj->o_ac;
707: save = pstats.s_hpt;
708: max_stats.s_hpt = pstats.s_hpt = 0;
709: max_stats.s_lvl = pstats.s_lvl = 0;
710: max_stats.s_exp = pstats.s_exp -= pstats.s_exp/10;
711: check_level(TRUE);
712: if (pstats.s_hpt > save) /* don't add to current hits */
713: pstats.s_hpt = save;
714: }
715:
716: otherwise:
717: msg("What a strange magic item you have!");
718: }
719: status(FALSE);
720: if (is_mm && m_know[which] && m_guess[which]) {
721: free(m_guess[which]);
722: m_guess[which] = NULL;
723: }
724: else if (is_mm &&
725: !m_know[which] &&
726: askme &&
727: (obj->o_flags & ISKNOW) == 0 &&
728: m_guess[which] == NULL) {
729: msg(terse ? "Call it: " : "What do you want to call it? ");
730: if (get_str(buf, msgw) == NORM) {
731: m_guess[which] = new((unsigned int) strlen(buf) + 1);
732: strcpy(m_guess[which], buf);
733: }
734: }
735: if (item != NULL && which == MM_SKILLS)
736: o_discard(item);
737: updpack(TRUE);
738: }
CVSweb