Mercurial > hg > early-roguelike
diff xrogue/wizard.c @ 133:e6179860cb76
Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 21 Apr 2015 08:55:20 -0400 |
parents | |
children | ce0cf824c192 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/wizard.c Tue Apr 21 08:55:20 2015 -0400 @@ -0,0 +1,819 @@ +/* + wizard.c - Special wizard commands + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 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 <ctype.h> +#include <string.h> +#include "rogue.h" +#include "mach_dep.h" + +/* + * create_obj: + * Create any object for wizard, scroll, magician, or cleric + */ + +create_obj(prompt, which_item, which_type) +bool prompt; +int which_item, which_type; +{ + reg struct linked_list *item; + reg struct object *obj; + reg int wh; + char *pt; + reg int ch, whc, newtype = 0, msz, newitem; + 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); + wprintw(hw,"monster\t\t\tm"); + } + wprintw(hw,"\n\nWhat do you want to create? "); + draw(hw); + do { + ch = wgetch(hw); + if (ch == ESC) { + 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, "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 == ESC) { + restscr(cw); + msg(""); + return; + } + } until (isalpha(ch)); + if (thiswin == hw) /* restore screen if need be */ + restscr(cw); + newtype = 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 +5 */ + whc = rnd(6); + 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; + if (!wizard) whc = rnd(6); + obj->o_dplus += whc; + } + else { /* armor here */ + obj->o_weight = armors[wh].a_wght; + obj->o_ac = armors[wh].a_class - whc; + } + when RING: + 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 + 2; + 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_HUNGER: + case MM_CHOKE: + if (whc < 0 ) + whc = -whc; /* cannot be negative */ + obj->o_ac = (whc + 1) * 2; + break; + when MM_OPEN: + case MM_DRUMS: + case MM_DISAPPEAR: + case MM_KEOGHTOM: + if (whc < 0) + whc = -whc; /* these cannot be negative */ + obj->o_ac = (whc + 3) * 5; + break; + when MM_BRACERS: + obj->o_ac = whc + 4; + when MM_DISP: + obj->o_ac = 3; + when MM_PROTECT: + obj->o_ac = whc + 4; + when MM_SKILLS: + if (whc < 2) + obj->o_ac = rnd(NUM_CHARTYPES-1); + else + obj->o_ac = player.t_ctype; + when MM_CRYSTAL: + obj->o_ac = 1; + 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 > 3 && 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 > 3 && 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) == FALSE) { + obj->o_pos = hero; + fall(item, TRUE); + } +} + +/* + * getbless: + * Get a blessing for a wizards object + */ + +int +getbless() +{ + reg char bless; + + msg("Blessing? (+,-,n)"); + bless = wgetch(msgw); + if (bless == '+') + return (15); + else if (bless == '-') + return (-1); + else + return (0); +} + +/* + * get a non-monster death type + */ + +getdeath() +{ + 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); +} + +/* + * make a monster for the wizard + */ + +makemonster(showall, action) +bool showall; /* showall -> show uniques and genocided creatures */ +char *action; +{ + 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 UNIQUES, DINOS, and quartermaster */ + if (!showall) num_monst -= NUMUNIQUE + NUMDINOS + 1; + max_monster = num_monst; + + /* Print out the monsters */ + + if (levtype == OUTSIDE) { + num_monst = NUMDINOS; + max_monster = NUMMONST - 1; + pres_monst = (pres_monst + NUMMONST - NUMDINOS - 1); + } + + while (num_monst > 0) { + register 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 (levtype == OUTSIDE) + if ((which_monst < NUMMONST-NUMDINOS || which_monst > max_monster)) { + mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- "); + draw(hw); + goto get_monst; + } + 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); + return(which_monst); +} + +/* + * passwd: + * see if user knows password + */ + +bool +passwd() +{ + register char *sp, c; + char buf[LINELEN]; + + msg("Wizard's Password:"); + mpos = 0; + sp = buf; + while ((c = wgetch(cw)) != '\n' && c != '\r' && c != '\033') { + if (c == killchar()) + sp = buf; + else if (c == erasechar() && sp > buf) + sp--; + else + *sp++ = c; + } + if (sp == buf) + return FALSE; + *sp = '\0'; + return (strcmp(PASSWD, xcrypt(buf, "mT")) == 0); + + /* don't mess with the password here or elsewhere. + * + * If anyone goes wizard they forfeit being placed in the scorefile. + * So, no need to be secretive about it. Let them have it! + * + * Additionally, you can begin the game as wizard by starting it + * with a null argument, as in: xrogue "" + */ +} + +/* + * teleport: + * Bamf the hero someplace else + */ + +void +teleport() +{ + 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; + flushinp(); +} + +/* + * whatis: + * What a certin object is + */ + +whatis(what) +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]) {