/* * wizard.c - Special wizard commands * * Advanced Rogue * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T * All rights reserved. * * Based on "Rogue: Exploring the Dungeons of Doom" * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ /* * Special wizard commands (some of which are also non-wizard commands * under strange circumstances) */ #include "curses.h" #include #include #include #include "rogue.h" #ifdef PC7300 #include "menu.h" #endif int getbless(void); /* * create_obj: * Create any object for wizard, scroll, magician, or cleric */ void create_obj(bool prompt, int which_item, int which_type) { reg struct linked_list *item; reg struct object *obj; reg int wh; reg char ch, newitem, newtype, whc, msz, *pt; WINDOW *thiswin; thiswin = cw; if (prompt) { bool nogood = TRUE; thiswin = hw; wclear(hw); wprintw(hw,"Item\t\t\tKey\n\n"); wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_RING].mi_name,RING, things[TYP_STICK].mi_name,STICK); wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_POTION].mi_name,POTION, things[TYP_SCROLL].mi_name,SCROLL); wprintw(hw,"%s\t\t\t%c\n%s\t\t\t%c\n",things[TYP_ARMOR].mi_name,ARMOR, things[TYP_WEAPON].mi_name,WEAPON); wprintw(hw,"%s\t%c\n",things[TYP_MM].mi_name,MM); wprintw(hw,"%s\t\t\t%c\n",things[TYP_FOOD].mi_name,FOOD); if (wizard) { wprintw(hw,"%s\t\t%c\n",things[TYP_RELIC].mi_name,RELIC); waddstr(hw,"monster\t\t\tm"); } wprintw(hw,"\n\nWhat do you want to create? "); draw(hw); do { ch = wgetch(hw); if (ch == ESCAPE) { restscr(cw); return; } switch (ch) { case RING: case STICK: case POTION: case SCROLL: case ARMOR: case WEAPON: case FOOD: case MM: nogood = FALSE; break; case RELIC: case 'm': if (wizard) nogood = FALSE; break; default: nogood = TRUE; } } while (nogood); newitem = ch; } else newitem = which_item; pt = "those"; msz = 0; if(newitem == 'm') { /* make monster and be done with it */ wh = makemonster(TRUE, "Creation", "create"); if (wh > 0) { creat_mons (&player, wh, TRUE); light(&hero); } return; } if(newitem == GOLD) pt = "gold"; /* else if(isatrap(newitem)) pt = "traps"; */ switch(newitem) { case POTION: whc = TYP_POTION; msz = MAXPOTIONS; when SCROLL: whc = TYP_SCROLL; msz = MAXSCROLLS; when WEAPON: whc = TYP_WEAPON; msz = MAXWEAPONS; when ARMOR: whc = TYP_ARMOR; msz = MAXARMORS; when RING: whc = TYP_RING; msz = MAXRINGS; when STICK: whc = TYP_STICK; msz = MAXSTICKS; when MM: whc = TYP_MM; msz = MAXMM; when RELIC: whc = TYP_RELIC; msz = MAXRELIC; when FOOD: whc = TYP_FOOD; msz = MAXFOODS; otherwise: if (thiswin == hw) restscr(cw); mpos = 0; msg("Even wizards can't create %s !!",pt); return; } if(msz == 1) { /* if only one type of item */ ch = 'a'; } else if (prompt) { register struct magic_item *wmi; char wmn; register int ii; int old_prob; mpos = 0; wmi = NULL; wmn = 0; switch(newitem) { case POTION: wmi = &p_magic[0]; when SCROLL: wmi = &s_magic[0]; when RING: wmi = &r_magic[0]; when STICK: wmi = &ws_magic[0]; when MM: wmi = &m_magic[0]; when RELIC: wmi = &rel_magic[0]; when FOOD: wmi = &foods[0]; when WEAPON: wmn = 1; when ARMOR: wmn = 2; } wclear(hw); thiswin = hw; if (wmi != NULL) { ii = old_prob = 0; while (ii < msz) { if(wmi->mi_prob == old_prob && wizard == FALSE) { msz--; /* can't make a unique item */ } else { mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a'); waddstr(hw,") "); waddstr(hw,wmi->mi_name); ii++; } old_prob = wmi->mi_prob; wmi++; } } else if (wmn != 0) { for(ii = 0 ; ii < msz ; ii++) { mvwaddch(hw,ii % 13,ii > 12 ? cols/2 : 0, ii + 'a'); waddstr(hw,") "); if(wmn == 1) waddstr(hw,weaps[ii].w_name); else waddstr(hw,armors[ii].a_name); } } sprintf(prbuf,"Which %s? ",things[whc].mi_name); mvwaddstr(hw,lines - 1, 0, prbuf); draw(hw); do { ch = wgetch(hw); if (ch == ESCAPE) { restscr(cw); msg(""); return; } } until (isalpha(ch)); if (thiswin == hw) /* restore screen if need be */ restscr(cw); newtype = tolower(ch) - 'a'; if(newtype < 0 || newtype >= msz) { /* if an illegal value */ mpos = 0; msg("There is no such %s",things[whc].mi_name); return; } } else newtype = which_type; item = new_item(sizeof *obj); /* get some memory */ obj = OBJPTR(item); obj->o_type = newitem; /* store the new items */ obj->o_mark[0] = '\0'; obj->o_which = newtype; obj->o_group = 0; obj->contents = NULL; obj->o_count = 1; obj->o_flags = 0; obj->o_dplus = obj->o_hplus = 0; obj->o_weight = 0; wh = obj->o_which; mpos = 0; if (!wizard) /* users get 0 to +3 */ whc = rnd(4); else /* wizard gets to choose */ whc = getbless(); if (whc < 0) obj->o_flags |= ISCURSED; switch (obj->o_type) { case WEAPON: case ARMOR: if (obj->o_type == WEAPON) { init_weapon(obj, wh); obj->o_hplus += whc; obj->o_dplus += whc; } else { /* armor here */ obj->o_weight = armors[wh].a_wght; obj->o_ac = armors[wh].a_class - whc; } when RING: if (whc > 1 && r_magic[wh].mi_bless != 0) obj->o_flags |= ISBLESSED; r_know[wh] = TRUE; switch(wh) { case R_ADDSTR: case R_ADDWISDOM: case R_ADDINTEL: case R_PROTECT: case R_ADDHIT: case R_ADDDAM: case R_DIGEST: obj->o_ac = whc + 1; break; default: obj->o_ac = 0; } obj->o_weight = things[TYP_RING].mi_wght; when MM: if (whc > 1 && m_magic[wh].mi_bless != 0) obj->o_flags |= ISBLESSED; m_know[wh] = TRUE; switch(wh) { case MM_JUG: switch(rnd(11)) { case 0: obj->o_ac = P_PHASE; when 1: obj->o_ac = P_CLEAR; when 2: obj->o_ac = P_SEEINVIS; when 3: obj->o_ac = P_HEALING; when 4: obj->o_ac = P_MFIND; when 5: obj->o_ac = P_TFIND; when 6: obj->o_ac = P_HASTE; when 7: obj->o_ac = P_RESTORE; when 8: obj->o_ac = P_FLY; when 9: obj->o_ac = P_SKILL; when 10:obj->o_ac = P_FFIND; } when MM_OPEN: case MM_HUNGER: case MM_DRUMS: case MM_DISAPPEAR: case MM_CHOKE: case MM_KEOGHTOM: if (whc < 0) whc = -whc; /* these cannot be negative */ obj->o_ac = (whc + 1) * 5; break; when MM_BRACERS: obj->o_ac = whc * 2 + 1; when MM_DISP: obj->o_ac = 2; when MM_PROTECT: obj->o_ac = whc; when MM_SKILLS: if (wizard && whc != 0) obj->o_ac = rnd(NUM_CHARTYPES-1); else obj->o_ac = player.t_ctype; otherwise: obj->o_ac = 0; } obj->o_weight = things[TYP_MM].mi_wght; when STICK: if (whc > 1 && ws_magic[wh].mi_bless != 0) obj->o_flags |= ISBLESSED; ws_know[wh] = TRUE; fix_stick(obj); when SCROLL: if (whc > 1 && s_magic[wh].mi_bless != 0) obj->o_flags |= ISBLESSED; obj->o_weight = things[TYP_SCROLL].mi_wght; s_know[wh] = TRUE; when POTION: if (whc > 1 && p_magic[wh].mi_bless != 0) obj->o_flags |= ISBLESSED; obj->o_weight = things[TYP_POTION].mi_wght; if (wh == P_ABIL) obj->o_kind = rnd(NUMABILITIES); p_know[wh] = TRUE; when RELIC: obj->o_weight = things[TYP_RELIC].mi_wght; switch (obj->o_which) { case QUILL_NAGROM: obj->o_charges = QUILLCHARGES; when EMORI_CLOAK: obj->o_charges = 1; otherwise: break; } when FOOD: obj->o_weight = things[TYP_FOOD].mi_wght; } mpos = 0; obj->o_flags |= ISKNOW; if (add_pack(item, FALSE, NULL) == FALSE) { obj->o_pos = hero; fall(item, TRUE); } } /* * getbless: * Get a blessing for a wizards object */ int getbless(void) { reg char bless; msg("Blessing? (+,-,n)"); bless = wgetch(msgw); if (bless == '+') return (rnd(3) + 2); else if (bless == '-') return (-rnd(3) - 1); else return (0); } /* * get a non-monster death type */ int getdeath(void) { register int i; int which_death; char label[80]; clear(); for (i=0; i DEATHNUM)) { mvaddstr(0, 0, "Please enter a number in the displayed range -- "); refresh(); } else break; } return(deaths[which_death-1].reason); } #ifdef PC7300 static menu_t Display; /* The menu structure */ static mitem_t Dispitems[NUMMONST+1]; /* Info for each line */ static char Displines[NUMMONST+1][LINELEN+1]; /* The lines themselves */ #endif /* * make a monster for the wizard * showall -> show uniques and genocided creatures */ short makemonster(bool showall, char *label, char *action) { #ifdef PC7300 register int nextmonst; #endif register int i; register short which_monst; register int num_monst = NUMMONST, pres_monst=1, num_lines=2*(lines-3); int max_monster; char monst_name[40]; /* If we're not showing all, subtract out the UNIQUES and quartermaster */ if (!showall) num_monst -= NUMUNIQUE + 1; max_monster = num_monst; #ifdef PC7300 nextmonst = 0; for (i=1; i<=num_monst; i++) { /* Only display existing monsters if we're not showing them all */ if (showall || monsters[i].m_normal) { strcpy(Displines[nextmonst], monsters[i]); Dispitems[nextmonst].mi_name = Displines[nextmonst]; Dispitems[nextmonst].mi_flags = 0; Dispitems[nextmonst++].mi_val = i; } } /* Place an end marker for the items */ Dispitems[nextmonst].mi_name = 0; /* Set up the main menu structure */ Display.m_label = label; Display.m_title = "Monster Listing"; Display.m_prompt = "Select a monster or press Cancl."; Display.m_curptr = '\0'; Display.m_markptr = '\0'; Display.m_flags = 0; Display.m_selcnt = 1; Display.m_items = Dispitems; Display.m_curi = 0; /* * Try to display the menu. If we don't have a local terminal, * the call will fail and we will just continue with the * normal mode. */ if (menu(&Display) >= 0) { restscr(cw); touchwin(cw); return(Display.m_selcnt == 1 ? Display.m_curi->mi_val : -1); } #endif /* Print out the monsters */ while (num_monst > 0) { int left_limit; if (num_monst < num_lines) left_limit = (num_monst+1)/2; else left_limit = num_lines/2; wclear(hw); touchwin(hw); /* Print left column */ wmove(hw, 2, 0); for (i=0; i 0) { mvwaddstr(hw, lines-1, 0, morestr); draw(hw); wait_for(' '); } else { mvwaddstr(hw, 0, 0, "Which monster"); if (!terse) { waddstr(hw, " do you wish to "); waddstr(hw, action); } waddstr(hw, "? "); draw(hw); } } get_monst: get_str(monst_name, hw); which_monst = atoi(monst_name); if ((which_monst < 1 || which_monst > max_monster)) { mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- "); draw(hw); goto get_monst; } restscr(cw); touchwin(cw); return(which_monst); } /* * passwd: * see if user knows password */ bool passwd(void) { register char *sp, c; char buf[LINELEN], *crypt(); msg("Wizard's Password:"); mpos = 0; sp = buf; while ((c = readchar()) != '\n' && c != '\r' && c != '\033') if (c == md_killchar()) sp = buf; else if (c == md_erasechar() && sp > buf) sp--; else *sp++ = c; if (sp == buf) return FALSE; *sp = '\0'; return (strcmp(PASSWD, md_crypt(buf, "mT")) == 0); } /* * teleport: * Bamf the hero someplace else */ int teleport(void) { register struct room *new_rp = NULL, *old_rp = roomin(&hero); register int rm, which; coord old; bool got_position = FALSE; /* Disrupt whatever the hero was doing */ dsrpt_player(); /* * If the hero wasn't doing something disruptable, NULL out his * action anyway and let him know about it. We don't want him * swinging or moving into his old place. */ if (player.t_action != A_NIL) { player.t_action = A_NIL; msg("You feel momentarily disoriented."); } old = hero; mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x)); if (ISWEARING(R_TELCONTROL) || wizard) { got_position = move_hero(H_TELEPORT); if (!got_position) msg("Your attempt fails."); else { new_rp = roomin(&hero); msg("You teleport successfully."); } } if (!got_position) { do { rm = rnd_room(); rnd_pos(&rooms[rm], &hero); } until(winat(hero.y, hero.x) == FLOOR); new_rp = &rooms[rm]; } player.t_oldpos = old; /* Save last position */ /* If hero gets moved, darken old room */ if (old_rp && old_rp != new_rp) { old_rp->r_flags |= FORCEDARK; /* Fake darkness */ light(&old); old_rp->r_flags &= ~FORCEDARK; /* Restore light state */ } /* Darken where we just came from */ else if (levtype == MAZELEV) light(&old); light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); /* if entering a treasure room, wake everyone up......Surprise! */ if (new_rp->r_flags & ISTREAS) wake_room(new_rp); /* Reset current room and position */ oldrp = new_rp; /* Used in look() */ player.t_oldpos = hero; /* * make sure we set/unset the ISINWALL on a teleport */ which = winat(hero.y, hero.x); if (isrock(which)) turn_on(player, ISINWALL); else turn_off(player, ISINWALL); /* * turn off ISHELD in case teleportation was done while fighting * something that holds you */ if (on(player, ISHELD)) { register struct linked_list *ip, *nip; register struct thing *mp; turn_off(player, ISHELD); hold_count = 0; for (ip = mlist; ip; ip = nip) { mp = THINGPTR(ip); nip = next(ip); if (on(*mp, DIDHOLD)) { turn_off(*mp, DIDHOLD); turn_on(*mp, CANHOLD); } turn_off(*mp, DIDSUFFOCATE); /* Suffocation -- see below */ } } /* Make sure player does not suffocate */ extinguish(suffocate); count = 0; running = FALSE; md_flushinp(); return rm; } /* * whatis: * What a certin object is */ void whatis(struct linked_list *what) { register struct object *obj; register struct linked_list *item; if (what == NULL) { /* do we need to ask which one? */ if ((item = get_item(pack, "identify", IDENTABLE, FALSE, FALSE))==NULL) return; } else item = what; obj = OBJPTR(item); switch (obj->o_type) { case SCROLL: s_know[obj->o_which] = TRUE; if (s_guess[obj->o_which]) { free(s_guess[obj->o_which]); s_guess[obj->o_which] = NULL; } when POTION: p_know[obj->o_which] = TRUE; if (p_guess[obj->o_which]) { free(p_guess[obj->o_which]); p_guess[obj->o_which] = NULL; } when STICK: ws_know[obj->o_which] = TRUE; if (ws_guess[obj->o_which]) { free(ws_guess[obj->o_which]); ws_guess[obj->o_which] = NULL; } when RING: r_know[obj->o_which] = TRUE; if (r_guess[obj->o_which]) { free(r_guess[obj->o_which]); r_guess[obj->o_which] = NULL; } when MM: /* If it's an identified jug, identify its potion */ if (obj->o_which == MM_JUG && (obj->o_flags & ISKNOW)) { if (obj->o_ac != JUG_EMPTY) p_know[obj->o_ac] = TRUE; break; } m_know[obj->o_which] = TRUE; if (m_guess[obj->o_which]) { free(m_guess[obj->o_which]); m_guess[obj->o_which] = NULL; } otherwise: break; } obj->o_flags |= ISKNOW; if (what == NULL) msg(inv_name(obj, FALSE)); }