Annotation of early-roguelike/arogue7/wizard.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * wizard.c - Special wizard commands
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: /*
16: * Special wizard commands (some of which are also non-wizard commands
17: * under strange circumstances)
18: */
19:
20: #include "curses.h"
21: #include <stdlib.h>
22: #include <string.h>
23: #include <ctype.h>
24: #include "rogue.h"
25: #ifdef PC7300
26: #include "menu.h"
27: #endif
28:
29: int getbless(void);
30:
31: /*
32: * create_obj:
33: * Create any object for wizard, scroll, magician, or cleric
34: */
35: void
36: create_obj(bool prompt, int which_item, int which_type)
37: {
38: reg struct linked_list *item;
39: reg struct object *obj;
40: reg int wh;
41: reg char ch, newitem, newtype, whc, msz, *pt;
42: WINDOW *thiswin;
43:
44: thiswin = cw;
45: if (prompt) {
46: bool nogood = TRUE;
47:
48: thiswin = hw;
49: wclear(hw);
50: wprintw(hw,"Item\t\t\tKey\n\n");
51: wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_RING].mi_name,RING,
52: things[TYP_STICK].mi_name,STICK);
53: wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_POTION].mi_name,POTION,
54: things[TYP_SCROLL].mi_name,SCROLL);
55: wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_ARMOR].mi_name,ARMOR,
56: things[TYP_WEAPON].mi_name,WEAPON);
57: wprintw(hw,"%s\t%c\n",things[TYP_MM].mi_name,MM);
58: wprintw(hw,"%s\t\t\t%c\n",things[TYP_FOOD].mi_name,FOOD);
59: if (wizard) {
60: wprintw(hw,"%s\t\t%c\n",things[TYP_RELIC].mi_name,RELIC);
61: waddstr(hw,"monster\t\t\tm");
62: }
63: wprintw(hw,"\n\nWhat do you want to create? ");
64: draw(hw);
65: do {
66: ch = wgetch(hw);
67: if (ch == ESCAPE) {
68: restscr(cw);
69: return;
70: }
71: switch (ch) {
72: case RING:
73: case STICK:
74: case POTION:
75: case SCROLL:
76: case ARMOR:
77: case WEAPON:
78: case FOOD:
79: case MM:
80: nogood = FALSE;
81: break;
82: case RELIC:
83: case 'm':
84: if (wizard)
85: nogood = FALSE;
86: break;
87: default:
88: nogood = TRUE;
89: }
90: } while (nogood);
91: newitem = ch;
92: }
93: else
94: newitem = which_item;
95:
96: pt = "those";
97: msz = 0;
98: if(newitem == 'm') {
99: /* make monster and be done with it */
100: wh = makemonster(TRUE, "Creation", "create");
101: if (wh > 0) {
102: creat_mons (&player, wh, TRUE);
103: light(&hero);
104: }
105: return;
106: }
107: if(newitem == GOLD)
108: pt = "gold";
109: /* else if(isatrap(newitem))
110: pt = "traps";
111: */
112: switch(newitem) {
113: case POTION: whc = TYP_POTION; msz = MAXPOTIONS;
114: when SCROLL: whc = TYP_SCROLL; msz = MAXSCROLLS;
115: when WEAPON: whc = TYP_WEAPON; msz = MAXWEAPONS;
116: when ARMOR: whc = TYP_ARMOR; msz = MAXARMORS;
117: when RING: whc = TYP_RING; msz = MAXRINGS;
118: when STICK: whc = TYP_STICK; msz = MAXSTICKS;
119: when MM: whc = TYP_MM; msz = MAXMM;
120: when RELIC: whc = TYP_RELIC; msz = MAXRELIC;
121: when FOOD: whc = TYP_FOOD; msz = MAXFOODS;
122: otherwise:
123: if (thiswin == hw)
124: restscr(cw);
125: mpos = 0;
126: msg("Even wizards can't create %s !!",pt);
127: return;
128: }
129: if(msz == 1) { /* if only one type of item */
130: ch = 'a';
131: }
132: else if (prompt) {
133: register struct magic_item *wmi;
134: char wmn;
135: register int ii;
136: int old_prob;
137:
138: mpos = 0;
139: wmi = NULL;
140: wmn = 0;
141: switch(newitem) {
142: case POTION: wmi = &p_magic[0];
143: when SCROLL: wmi = &s_magic[0];
144: when RING: wmi = &r_magic[0];
145: when STICK: wmi = &ws_magic[0];
146: when MM: wmi = &m_magic[0];
147: when RELIC: wmi = &rel_magic[0];
148: when FOOD: wmi = &foods[0];
149: when WEAPON: wmn = 1;
150: when ARMOR: wmn = 2;
151: }
152: wclear(hw);
153: thiswin = hw;
154: if (wmi != NULL) {
155: ii = old_prob = 0;
156: while (ii < msz) {
157: if(wmi->mi_prob == old_prob && wizard == FALSE) {
158: msz--; /* can't make a unique item */
159: }
160: else {
161: mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a');
162: waddstr(hw,") ");
163: waddstr(hw,wmi->mi_name);
164: ii++;
165: }
166: old_prob = wmi->mi_prob;
167: wmi++;
168: }
169: }
170: else if (wmn != 0) {
171: for(ii = 0 ; ii < msz ; ii++) {
172: mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a');
173: waddstr(hw,") ");
174: if(wmn == 1)
175: waddstr(hw,weaps[ii].w_name);
176: else
177: waddstr(hw,armors[ii].a_name);
178: }
179: }
180: sprintf(prbuf,"Which %s? ",things[whc].mi_name);
181: mvwaddstr(hw,lines - 1, 0, prbuf);
182: draw(hw);
183: do {
184: ch = wgetch(hw);
185: if (ch == ESCAPE) {
186: restscr(cw);
187: msg("");
188: return;
189: }
190: } until (isalpha(ch));
191: if (thiswin == hw) /* restore screen if need be */
192: restscr(cw);
193: newtype = tolower(ch) - 'a';
194: if(newtype < 0 || newtype >= msz) { /* if an illegal value */
195: mpos = 0;
196: msg("There is no such %s",things[whc].mi_name);
197: return;
198: }
199: }
200: else
201: newtype = which_type;
202: item = new_item(sizeof *obj); /* get some memory */
203: obj = OBJPTR(item);
204: obj->o_type = newitem; /* store the new items */
205: obj->o_mark[0] = '\0';
206: obj->o_which = newtype;
207: obj->o_group = 0;
208: obj->contents = NULL;
209: obj->o_count = 1;
210: obj->o_flags = 0;
211: obj->o_dplus = obj->o_hplus = 0;
212: obj->o_weight = 0;
213: wh = obj->o_which;
214: mpos = 0;
215: if (!wizard) /* users get 0 to +3 */
216: whc = rnd(4);
217: else /* wizard gets to choose */
218: whc = getbless();
219: if (whc < 0)
220: obj->o_flags |= ISCURSED;
221: switch (obj->o_type) {
222: case WEAPON:
223: case ARMOR:
224: if (obj->o_type == WEAPON) {
225: init_weapon(obj, wh);
226: obj->o_hplus += whc;
227: obj->o_dplus += whc;
228: }
229: else { /* armor here */
230: obj->o_weight = armors[wh].a_wght;
231: obj->o_ac = armors[wh].a_class - whc;
232: }
233: when RING:
234: if (whc > 1 && r_magic[wh].mi_bless != 0)
235: obj->o_flags |= ISBLESSED;
236: r_know[wh] = TRUE;
237: switch(wh) {
238: case R_ADDSTR:
239: case R_ADDWISDOM:
240: case R_ADDINTEL:
241: case R_PROTECT:
242: case R_ADDHIT:
243: case R_ADDDAM:
244: case R_DIGEST:
245: obj->o_ac = whc + 1;
246: break;
247: default:
248: obj->o_ac = 0;
249: }
250: obj->o_weight = things[TYP_RING].mi_wght;
251: when MM:
252: if (whc > 1 && m_magic[wh].mi_bless != 0)
253: obj->o_flags |= ISBLESSED;
254: m_know[wh] = TRUE;
255: switch(wh) {
256: case MM_JUG:
257: switch(rnd(11)) {
258: case 0: obj->o_ac = P_PHASE;
259: when 1: obj->o_ac = P_CLEAR;
260: when 2: obj->o_ac = P_SEEINVIS;
261: when 3: obj->o_ac = P_HEALING;
262: when 4: obj->o_ac = P_MFIND;
263: when 5: obj->o_ac = P_TFIND;
264: when 6: obj->o_ac = P_HASTE;
265: when 7: obj->o_ac = P_RESTORE;
266: when 8: obj->o_ac = P_FLY;
267: when 9: obj->o_ac = P_SKILL;
268: when 10:obj->o_ac = P_FFIND;
269: }
270: when MM_OPEN:
271: case MM_HUNGER:
272: case MM_DRUMS:
273: case MM_DISAPPEAR:
274: case MM_CHOKE:
275: case MM_KEOGHTOM:
276: if (whc < 0)
277: whc = -whc; /* these cannot be negative */
278: obj->o_ac = (whc + 1) * 5;
279: break;
280: when MM_BRACERS:
281: obj->o_ac = whc * 2 + 1;
282: when MM_DISP:
283: obj->o_ac = 2;
284: when MM_PROTECT:
285: obj->o_ac = whc;
286: when MM_SKILLS:
287: if (wizard && whc != 0)
288: obj->o_ac = rnd(NUM_CHARTYPES-1);
289: else
290: obj->o_ac = player.t_ctype;
291: otherwise:
292: obj->o_ac = 0;
293: }
294: obj->o_weight = things[TYP_MM].mi_wght;
295: when STICK:
296: if (whc > 1 && ws_magic[wh].mi_bless != 0)
297: obj->o_flags |= ISBLESSED;
298: ws_know[wh] = TRUE;
299: fix_stick(obj);
300: when SCROLL:
301: if (whc > 1 && s_magic[wh].mi_bless != 0)
302: obj->o_flags |= ISBLESSED;
303: obj->o_weight = things[TYP_SCROLL].mi_wght;
304: s_know[wh] = TRUE;
305: when POTION:
306: if (whc > 1 && p_magic[wh].mi_bless != 0)
307: obj->o_flags |= ISBLESSED;
308: obj->o_weight = things[TYP_POTION].mi_wght;
309: if (wh == P_ABIL) obj->o_kind = rnd(NUMABILITIES);
310: p_know[wh] = TRUE;
311: when RELIC:
312: obj->o_weight = things[TYP_RELIC].mi_wght;
313: switch (obj->o_which) {
314: case QUILL_NAGROM: obj->o_charges = QUILLCHARGES;
315: when EMORI_CLOAK: obj->o_charges = 1;
316: otherwise: break;
317: }
318: when FOOD:
319: obj->o_weight = things[TYP_FOOD].mi_wght;
320: }
321: mpos = 0;
322: obj->o_flags |= ISKNOW;
323: if (add_pack(item, FALSE, NULL) == FALSE) {
324: obj->o_pos = hero;
325: fall(item, TRUE);
326: }
327: }
328:
329: /*
330: * getbless:
331: * Get a blessing for a wizards object
332: */
333: int
334: getbless(void)
335: {
336: reg char bless;
337:
338: msg("Blessing? (+,-,n)");
339: bless = wgetch(msgw);
340: if (bless == '+')
341: return (rnd(3) + 2);
342: else if (bless == '-')
343: return (-rnd(3) - 1);
344: else
345: return (0);
346: }
347:
348: /*
349: * get a non-monster death type
350: */
351: int
352: getdeath(void)
353: {
354: register int i;
355: int which_death;
356: char label[80];
357:
358: clear();
359: for (i=0; i<DEATHNUM; i++) {
360: sprintf(label, "[%d] %s", i+1, deaths[i].name);
361: mvaddstr(i+2, 0, label);
362: }
363: mvaddstr(0, 0, "Which death? ");
364: refresh();
365:
366: /* Get the death */
367: for (;;) {
368: get_str(label, stdscr);
369: which_death = atoi(label);
370: if ((which_death < 1 || which_death > DEATHNUM)) {
371: mvaddstr(0, 0, "Please enter a number in the displayed range -- ");
372: refresh();
373: }
374: else break;
375: }
376: return(deaths[which_death-1].reason);
377: }
378:
379: #ifdef PC7300
380: static menu_t Display; /* The menu structure */
381: static mitem_t Dispitems[NUMMONST+1]; /* Info for each line */
382: static char Displines[NUMMONST+1][LINELEN+1]; /* The lines themselves */
383: #endif
384:
385: /*
386: * make a monster for the wizard
387: * showall -> show uniques and genocided creatures
388: */
389: short
390: makemonster(bool showall, char *label, char *action)
391: {
392: #ifdef PC7300
393: register int nextmonst;
394: #endif
395: register int i;
396: register short which_monst;
397: register int num_monst = NUMMONST, pres_monst=1, num_lines=2*(lines-3);
398: int max_monster;
399: char monst_name[40];
400:
401: /* If we're not showing all, subtract out the UNIQUES and quartermaster */
402: if (!showall) num_monst -= NUMUNIQUE + 1;
403: max_monster = num_monst;
404:
405: #ifdef PC7300
406: nextmonst = 0;
407: for (i=1; i<=num_monst; i++) {
408: /* Only display existing monsters if we're not showing them all */
409: if (showall || monsters[i].m_normal) {
410: strcpy(Displines[nextmonst], monsters[i]);
411: Dispitems[nextmonst].mi_name = Displines[nextmonst];
412: Dispitems[nextmonst].mi_flags = 0;
413: Dispitems[nextmonst++].mi_val = i;
414: }
415: }
416:
417: /* Place an end marker for the items */
418: Dispitems[nextmonst].mi_name = 0;
419:
420: /* Set up the main menu structure */
421: Display.m_label = label;
422: Display.m_title = "Monster Listing";
423: Display.m_prompt = "Select a monster or press Cancl.";
424: Display.m_curptr = '\0';
425: Display.m_markptr = '\0';
426: Display.m_flags = 0;
427: Display.m_selcnt = 1;
428: Display.m_items = Dispitems;
429: Display.m_curi = 0;
430:
431: /*
432: * Try to display the menu. If we don't have a local terminal,
433: * the call will fail and we will just continue with the
434: * normal mode.
435: */
436: if (menu(&Display) >= 0) {
437: restscr(cw);
438: touchwin(cw);
439: return(Display.m_selcnt == 1 ? Display.m_curi->mi_val : -1);
440: }
441: #endif
442:
443: /* Print out the monsters */
444: while (num_monst > 0) {
445: int left_limit;
446:
447: if (num_monst < num_lines) left_limit = (num_monst+1)/2;
448: else left_limit = num_lines/2;
449:
450: wclear(hw);
451: touchwin(hw);
452:
453: /* Print left column */
454: wmove(hw, 2, 0);
455: for (i=0; i<left_limit; i++) {
456: sprintf(monst_name, "[%d] %c%s\n",
457: pres_monst,
458: (showall || monsters[pres_monst].m_normal)
459: ? ' '
460: : '*',
461: monsters[pres_monst].m_name);
462: waddstr(hw, monst_name);
463: pres_monst++;
464: }
465:
466: /* Print right column */
467: for (i=0; i<left_limit && pres_monst<=max_monster; i++) {
468: sprintf(monst_name, "[%d] %c%s",
469: pres_monst,
470: (showall || monsters[pres_monst].m_normal)
471: ? ' '
472: : '*',
473: monsters[pres_monst].m_name);
474: wmove(hw, i+2, cols/2);
475: waddstr(hw, monst_name);
476: pres_monst++;
477: }
478:
479: if ((num_monst -= num_lines) > 0) {
480: mvwaddstr(hw, lines-1, 0, morestr);
481: draw(hw);
482: wait_for(' ');
483: }
484:
485: else {
486: mvwaddstr(hw, 0, 0, "Which monster");
487: if (!terse) {
488: waddstr(hw, " do you wish to ");
489: waddstr(hw, action);
490: }
491: waddstr(hw, "? ");
492: draw(hw);
493: }
494: }
495:
496: get_monst:
497: get_str(monst_name, hw);
498: which_monst = atoi(monst_name);
499: if ((which_monst < 1 || which_monst > max_monster)) {
500: mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- ");
501: draw(hw);
502: goto get_monst;
503: }
504: restscr(cw);
505: touchwin(cw);
506: return(which_monst);
507: }
508:
509: /*
510: * passwd:
511: * see if user knows password
512: */
513:
514: bool
515: passwd(void)
516: {
517: register char *sp, c;
518: char buf[LINELEN], *crypt();
519:
520: msg("Wizard's Password:");
521: mpos = 0;
522: sp = buf;
523: while ((c = readchar()) != '\n' && c != '\r' && c != '\033')
524: if (c == md_killchar())
525: sp = buf;
526: else if (c == md_erasechar() && sp > buf)
527: sp--;
528: else
529: *sp++ = c;
530: if (sp == buf)
531: return FALSE;
532: *sp = '\0';
533: return (strcmp(PASSWD, md_crypt(buf, "mT")) == 0);
534: }
535:
536:
537: /*
538: * teleport:
539: * Bamf the hero someplace else
540: */
541:
542: int
543: teleport(void)
544: {
545: register struct room *new_rp = NULL, *old_rp = roomin(&hero);
546: register int rm, which;
547: coord old;
548: bool got_position = FALSE;
549:
550: /* Disrupt whatever the hero was doing */
551: dsrpt_player();
552:
553: /*
554: * If the hero wasn't doing something disruptable, NULL out his
555: * action anyway and let him know about it. We don't want him
556: * swinging or moving into his old place.
557: */
558: if (player.t_action != A_NIL) {
559: player.t_action = A_NIL;
560: msg("You feel momentarily disoriented.");
561: }
562:
563: old = hero;
564: mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x));
565: if (ISWEARING(R_TELCONTROL) || wizard) {
566: got_position = move_hero(H_TELEPORT);
567: if (!got_position)
568: msg("Your attempt fails.");
569: else {
570: new_rp = roomin(&hero);
571: msg("You teleport successfully.");
572: }
573: }
574: if (!got_position) {
575: do {
576: rm = rnd_room();
577: rnd_pos(&rooms[rm], &hero);
578: } until(winat(hero.y, hero.x) == FLOOR);
579: new_rp = &rooms[rm];
580: }
581: player.t_oldpos = old; /* Save last position */
582:
583: /* If hero gets moved, darken old room */
584: if (old_rp && old_rp != new_rp) {
585: old_rp->r_flags |= FORCEDARK; /* Fake darkness */
586: light(&old);
587: old_rp->r_flags &= ~FORCEDARK; /* Restore light state */
588: }
589:
590: /* Darken where we just came from */
591: else if (levtype == MAZELEV) light(&old);
592:
593: light(&hero);
594: mvwaddch(cw, hero.y, hero.x, PLAYER);
595: /* if entering a treasure room, wake everyone up......Surprise! */
596: if (new_rp->r_flags & ISTREAS)
597: wake_room(new_rp);
598:
599: /* Reset current room and position */
600: oldrp = new_rp; /* Used in look() */
601: player.t_oldpos = hero;
602: /*
603: * make sure we set/unset the ISINWALL on a teleport
604: */
605: which = winat(hero.y, hero.x);
606: if (isrock(which)) turn_on(player, ISINWALL);
607: else turn_off(player, ISINWALL);
608:
609: /*
610: * turn off ISHELD in case teleportation was done while fighting
611: * something that holds you
612: */
613: if (on(player, ISHELD)) {
614: register struct linked_list *ip, *nip;
615: register struct thing *mp;
616:
617: turn_off(player, ISHELD);
618: hold_count = 0;
619: for (ip = mlist; ip; ip = nip) {
620: mp = THINGPTR(ip);
621: nip = next(ip);
622: if (on(*mp, DIDHOLD)) {
623: turn_off(*mp, DIDHOLD);
624: turn_on(*mp, CANHOLD);
625: }
626: turn_off(*mp, DIDSUFFOCATE); /* Suffocation -- see below */
627: }
628: }
629:
630: /* Make sure player does not suffocate */
631: extinguish(suffocate);
632:
633: count = 0;
634: running = FALSE;
635: md_flushinp();
636: return rm;
637: }
638:
639: /*
640: * whatis:
641: * What a certin object is
642: */
643:
644: void
645: whatis(struct linked_list *what)
646: {
647: register struct object *obj;
648: register struct linked_list *item;
649:
650: if (what == NULL) { /* do we need to ask which one? */
651: if ((item = get_item(pack, "identify", IDENTABLE, FALSE, FALSE))==NULL)
652: return;
653: }
654: else
655: item = what;
656: obj = OBJPTR(item);
657: switch (obj->o_type) {
658: case SCROLL:
659: s_know[obj->o_which] = TRUE;
660: if (s_guess[obj->o_which]) {
661: free(s_guess[obj->o_which]);
662: s_guess[obj->o_which] = NULL;
663: }
664: when POTION:
665: p_know[obj->o_which] = TRUE;
666: if (p_guess[obj->o_which]) {
667: free(p_guess[obj->o_which]);
668: p_guess[obj->o_which] = NULL;
669: }
670: when STICK:
671: ws_know[obj->o_which] = TRUE;
672: if (ws_guess[obj->o_which]) {
673: free(ws_guess[obj->o_which]);
674: ws_guess[obj->o_which] = NULL;
675: }
676: when RING:
677: r_know[obj->o_which] = TRUE;
678: if (r_guess[obj->o_which]) {
679: free(r_guess[obj->o_which]);
680: r_guess[obj->o_which] = NULL;
681: }
682: when MM:
683: /* If it's an identified jug, identify its potion */
684: if (obj->o_which == MM_JUG && (obj->o_flags & ISKNOW)) {
685: if (obj->o_ac != JUG_EMPTY)
686: p_know[obj->o_ac] = TRUE;
687: break;
688: }
689:
690: m_know[obj->o_which] = TRUE;
691: if (m_guess[obj->o_which]) {
692: free(m_guess[obj->o_which]);
693: m_guess[obj->o_which] = NULL;
694: }
695: otherwise:
696: break;
697: }
698: obj->o_flags |= ISKNOW;
699: if (what == NULL)
700: msg(inv_name(obj, FALSE));
701: }
702:
CVSweb