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