/*
* 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 <stdlib.h>
#include <string.h>
#include <ctype.h>
#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; i++) {
sprintf(label, "[%d] %s", i+1, deaths[i].name);
mvaddstr(i+2, 0, label);
}
mvaddstr(0, 0, "Which death? ");
refresh();
/* Get the death */
for (;;) {
get_str(label, stdscr);
which_death = atoi(label);
if ((which_death < 1 || which_death > 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<left_limit; i++) {
sprintf(monst_name, "[%d] %c%s\n",
pres_monst,
(showall || monsters[pres_monst].m_normal)
? ' '
: '*',
monsters[pres_monst].m_name);
waddstr(hw, monst_name);
pres_monst++;
}
/* Print right column */
for (i=0; i<left_limit && pres_monst<=max_monster; i++) {
sprintf(monst_name, "[%d] %c%s",
pres_monst,
(showall || monsters[pres_monst].m_normal)
? ' '
: '*',
monsters[pres_monst].m_name);
wmove(hw, i+2, cols/2);
waddstr(hw, monst_name);
pres_monst++;
}
if ((num_monst -= num_lines) > 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));
}