view arogue7/player.c @ 265:7fcb2f9f57e6

Mention UltraRogue in the top-level README.
author John "Elwin" Edwards
date Sun, 19 Feb 2017 19:54:17 -0500
parents f9ef86cf22b2
children e52a8a7ad4c5
line wrap: on
line source

/*
 * player.c  -  This file contains functions for dealing with special player 
 * abilities
 *
 * 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.
 */

/*
 * This file contains functions for dealing with special player abilities
 */

#include <ctype.h>
#include <string.h>
#include "curses.h"
#include "rogue.h"
#ifdef PC7300
#include "menu.h"
#endif

bool pick_spell(struct spells spells[], int ability, int num_spells, int power,
           char *prompt, char *type);

/*
 * affect:
 *	cleric affecting undead
 */

void
affect(void)
{
    register struct linked_list *item;
    register struct thing *tp;
    register char *mname;
    bool see;
    coord new_pos;
    int lvl;

    if (!(player.t_ctype == C_CLERIC  ||
          (player.t_ctype == C_PALADIN && pstats.s_lvl > 4) ||
	  cur_relic[HEIL_ANKH] != 0)) {
	msg("You cannot affect undead.");
	return;
    }

    new_pos.y = hero.y + player.t_newpos.y;
    new_pos.x = hero.x + player.t_newpos.x;

    if (cansee(new_pos.y, new_pos.x)) see = TRUE;
    else see = FALSE;

    /* Anything there? */
    if (new_pos.y < 0 || new_pos.y > lines-3 ||
	new_pos.x < 0 || new_pos.x > cols-1 ||
	mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
	msg("Nothing to affect.");
	return;
    }

    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL) {
	debug("Affect what @ %d,%d?", new_pos.y, new_pos.x);
	return;
    }
    tp = THINGPTR(item);
    mname = monster_name(tp);

    if (on(player, ISINVIS) && off(*tp, CANSEE)) {
	msg("%s%s cannot see you", see ? "The " : "It",
	    see ? mname : "");
	return;
    }

    if (off(*tp, TURNABLE) || on(*tp, WASTURNED)) 
	goto annoy;
    turn_off(*tp, TURNABLE);

    lvl = pstats.s_lvl;
    if (player.t_ctype == C_PALADIN && cur_relic[HEIL_ANKH] == 0) {
	lvl -= 4;
    }
    /* Can cleric kill it? */
    if (lvl >= 3 * tp->t_stats.s_lvl) {
	unsigned long test;	/* For overflow check */

	msg("You have destroyed %s%s.", see ? "the " : "it", see ? mname : "");
	test = pstats.s_exp + tp->t_stats.s_exp;

	/* Be sure there is no overflow before increasing experience */
	if (test > pstats.s_exp) pstats.s_exp = test;
	killed(item, FALSE, TRUE, TRUE);
	check_level();
	return;
    }

    /* Can cleric turn it? */
    if (rnd(100) + 1 >
	 (100 * ((2 * tp->t_stats.s_lvl) - lvl)) / lvl) {
	unsigned long test;	/* Overflow test */

	/* Make the monster flee */
	turn_on(*tp, WASTURNED);	/* No more fleeing after this */
	turn_on(*tp, ISFLEE);
	runto(tp, &hero);

	/* Disrupt it */
	dsrpt_monster(tp, TRUE, TRUE);

	/* Let player know */
	msg("You have turned %s%s.", see ? "the " : "it", see ? mname : "");

	/* get points for turning monster -- but check overflow first */
	test = pstats.s_exp + tp->t_stats.s_exp/2;
	if (test > pstats.s_exp) pstats.s_exp = test;
	check_level();

	/* If monster was suffocating, stop it */
	if (on(*tp, DIDSUFFOCATE)) {
	    turn_off(*tp, DIDSUFFOCATE);
	    extinguish(suffocate);
	}

	/* If monster held us, stop it */
	if (on(*tp, DIDHOLD) && (--hold_count == 0))
		turn_off(player, ISHELD);
	turn_off(*tp, DIDHOLD);

	/* It is okay to turn tail */
	tp->t_oldpos = tp->t_pos;

	return;
    }

    /* Otherwise -- no go */
annoy:
    if (see && tp->t_stats.s_intel > 16)
	msg("%s laughs at you...", prname(mname, TRUE));
    else
	msg("You do not affect %s%s.", see ? "the " : "it", see ? mname : "");

    /* Annoy monster */
   if (off(*tp, ISFLEE)) runto(tp, &hero);
}

/*
 * the magic user is going to try and cast a spell
 */
void
cast(void)
{
    int		spell_ability,
		which_spell,
		num_spells;

    if (player.t_ctype != C_MAGICIAN && player.t_ctype != C_RANGER) {
	msg("You are not permitted to cast spells.");
	return;
    }
    spell_ability = pstats.s_lvl * pstats.s_intel;
    if (player.t_ctype != C_MAGICIAN)
	spell_ability /= 3;

    if (player.t_action != C_CAST) {
	/* 
	 * Get the number of avilable spells 
	 */
	num_spells = 0;
	if (pstats.s_intel >= 16) 
	    num_spells += pstats.s_intel - 15;
	num_spells += pstats.s_lvl;
	if (player.t_ctype != C_MAGICIAN) 
	    num_spells /= 3;
	if (num_spells > MAXSPELLS)	  
	    num_spells = MAXSPELLS;
	if (num_spells < 1) {
	    msg("You are not allowed to cast spells yet.");
	    return;
	}
	if (pick_spell(	magic_spells, 
			spell_ability, 
			num_spells, 
			spell_power,
			"cast",
			"spell"))
	    player.t_action = C_CAST;
	return;
    }

    /* We've waited our required casting time. */
    which_spell = player.t_selection;
    player.t_selection = 0;
    player.t_using = NULL;
    player.t_action = A_NIL;

    if ((spell_power + magic_spells[which_spell].s_cost) > spell_ability) {
	msg("Your attempt fails.");
	return;
    }

    msg("Your spell is successful.");

    if (magic_spells[which_spell].s_type == TYP_POTION)
        quaff(	magic_spells[which_spell].s_which,
		0,
        	magic_spells[which_spell].s_flag,
		FALSE);
    else if (magic_spells[which_spell].s_type == TYP_SCROLL)
        read_scroll(	magic_spells[which_spell].s_which,
        		magic_spells[which_spell].s_flag,
			FALSE);
    else if (magic_spells[which_spell].s_type == TYP_STICK) {
	 if (!player_zap(magic_spells[which_spell].s_which,
			 magic_spells[which_spell].s_flag)) {
	     after = FALSE;
	     return;
	 }
    }
    spell_power += magic_spells[which_spell].s_cost;
}

/* 
 * the druid asks his deity for a spell
 */
void
chant(void)
{
    register int	num_chants, 
			chant_ability, 
			which_chant;

    which_chant = num_chants = chant_ability = 0;

    if (player.t_ctype != C_DRUID && player.t_ctype != C_RANGER) {
	msg("You are not permitted to chant.");
	return;
    }
    if (cur_misc[WEAR_CLOAK] != NULL &&
	cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
	msg("You can't seem to chant!");
	return;
    }
    chant_ability = pstats.s_lvl * pstats.s_wisdom;
    if (player.t_ctype != C_DRUID)
	chant_ability /= 3;

    if (player.t_action != C_CHANT) {
	num_chants = 0;

	/* Get the number of avilable chants */
	if (pstats.s_wisdom > 16) 
	    num_chants = (pstats.s_wisdom - 15) / 2;

	num_chants += pstats.s_lvl;

	if (player.t_ctype != C_DRUID) 
	    num_chants /= 3;

	if (num_chants > MAXCHANTS) 
	    num_chants = MAXCHANTS;

	if (num_chants < 1) {
	    msg("You are not permitted to chant yet.");
	    return;
	}

	/* Prompt for chant */
	if (pick_spell(	druid_spells, 
			chant_ability, 
			num_chants, 
			chant_time,
			"sing",
			"chant"))
	    player.t_action = C_CHANT;

	return;
    }

    /* We've waited our required chanting time. */
    which_chant = player.t_selection;
    player.t_selection = 0;
    player.t_using = NULL;
    player.t_action = A_NIL;

    if (druid_spells[which_chant].s_cost + chant_time > chant_ability) {
	msg("Your chant fails.");
	return;
    }

    msg("Your chant has been granted.");

    if (druid_spells[which_chant].s_type == TYP_POTION)
	quaff(		druid_spells[which_chant].s_which,
			0,
			druid_spells[which_chant].s_flag,
			FALSE);
    else if (druid_spells[which_chant].s_type == TYP_SCROLL)
	read_scroll(	druid_spells[which_chant].s_which,
			druid_spells[which_chant].s_flag,
			FALSE);
    else if (druid_spells[which_chant].s_type == TYP_STICK) {
	 if (!player_zap(druid_spells[which_chant].s_which,
			 druid_spells[which_chant].s_flag)) {
	     after = FALSE;
	     return;
	 }
    }
    chant_time += druid_spells[which_chant].s_cost;
}

/* Constitution bonus */

int
const_bonus(void)	/* Hit point adjustment for changing levels */
{
    register int bonus;
    if (pstats.s_const > 6 && pstats.s_const <= 14) 
	bonus = 0;
    else if (pstats.s_const > 14) 
	bonus = pstats.s_const-14;
    else if (pstats.s_const > 3) 
	bonus = -1;
    else
	bonus = -2;
    switch(player.t_ctype) {
	case C_FIGHTER:		bonus = min(bonus, 11);
	when C_MAGICIAN:	bonus = min(bonus, 4);
	when C_CLERIC:		bonus = min(bonus, 4);
	when C_THIEF:		bonus = min(bonus, 4);
	when C_RANGER:		bonus = min(bonus, 6);
	when C_PALADIN:		bonus = min(bonus, 8);
	when C_ASSASIN:		bonus = min(bonus, 4);
	when C_MONK:		bonus = min(bonus, 6);
	when C_DRUID:		bonus = min(bonus, 4);
	otherwise:		bonus = min(bonus, 4);
    }
    return(bonus);
}


/* Routines for thieves */

/*
 * gsense:
 *	Sense gold
 */

void
gsense(void)
{
    /* Only thieves can do this */
    if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
	msg("You seem to have no gold sense.");
	return;
    }

    read_scroll(S_GFIND, 0, FALSE);
}

/* 
 * the cleric asks his deity for a spell
 */
void
pray(void)
{
    register int	num_prayers, 
			prayer_ability, 
			which_prayer;

    which_prayer = num_prayers = prayer_ability =  0;

    if (player.t_ctype != C_CLERIC  && 
	player.t_ctype != C_PALADIN &&
	cur_relic[HEIL_ANKH] == 0) {
	    msg("You are not permitted to pray.");
	    return;
    }
    if (cur_misc[WEAR_CLOAK] != NULL &&
	cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
	msg("You can't seem to pray!");
	return;
    }

    prayer_ability = pstats.s_lvl * pstats.s_wisdom;
    if (player.t_ctype != C_CLERIC)
	prayer_ability /= 3;

    if (cur_relic[HEIL_ANKH]) prayer_ability *= 2;

    if (player.t_action != C_PRAY) {
	num_prayers = 0;

	/* Get the number of avilable prayers */
	if (pstats.s_wisdom > 16) 
	    num_prayers += (pstats.s_wisdom - 15) / 2;

	num_prayers += pstats.s_lvl;
	if (cur_relic[HEIL_ANKH]) num_prayers += 3;

	if (player.t_ctype != C_CLERIC) 
	    num_prayers /= 3;

	if (num_prayers > MAXPRAYERS) 
	    num_prayers = MAXPRAYERS;
	if (num_prayers < 1) {
	    msg("You are not permitted to pray yet.");
	    return;
	}

	/* Prompt for prayer */
	if (pick_spell(	cleric_spells, 
			prayer_ability, 
			num_prayers, 
			pray_time,
			"offer",
			"prayer"))
	    player.t_action = C_PRAY;

	return;
    }

    /* We've waited our required praying time. */
    which_prayer = player.t_selection;
    player.t_selection = 0;
    player.t_using = NULL;
    player.t_action = A_NIL;

    if (cleric_spells[which_prayer].s_cost + pray_time > prayer_ability) {
	msg("Your prayer fails.");
	return;
    }

    msg("Your prayer has been granted.");

    if (cleric_spells[which_prayer].s_type == TYP_POTION)
	quaff(		cleric_spells[which_prayer].s_which,
			0,
			cleric_spells[which_prayer].s_flag,
			FALSE);
    else if (cleric_spells[which_prayer].s_type == TYP_SCROLL)
	read_scroll(	cleric_spells[which_prayer].s_which,
			cleric_spells[which_prayer].s_flag,
			FALSE);
    else if (cleric_spells[which_prayer].s_type == TYP_STICK) {
	 if (!player_zap(cleric_spells[which_prayer].s_which,
			 cleric_spells[which_prayer].s_flag)) {
	     after = FALSE;
	     return;
	 }
    }
    pray_time += cleric_spells[which_prayer].s_cost;
}



/*
 * steal:
 *	Steal in direction given in delta
 */

void
steal(void)
{
    register struct linked_list *item;
    register struct thing *tp;
    register char *mname;
    coord new_pos;
    int thief_bonus = -50;
    bool isinvisible = FALSE;

    if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
	msg("Only thieves and assassins can steal.");
	return;
    }
    if (on(player, ISBLIND)) {
	msg("You can't see anything.");
	return;
    }

    new_pos.y = hero.y + player.t_newpos.y;
    new_pos.x = hero.x + player.t_newpos.x;

    /* Anything there? */
    if (new_pos.y < 0 || new_pos.y > lines-3 ||
	new_pos.x < 0 || new_pos.x > cols-1 ||
	mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
	msg("Nothing to steal from.");
	return;
    }

    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
	debug("Steal from what @ %d,%d?", new_pos.y, new_pos.x);
    tp = THINGPTR(item);
    if (on(*tp, ISSTONE)) {
	msg ("You can't steal from stone!");
	return;
    }
    if (isinvisible = invisible(tp)) mname = "creature";
    else mname = monster_name(tp);

    /* Can player steal something unnoticed? */
    if (player.t_ctype == C_THIEF) thief_bonus = 10;
    if (player.t_ctype == C_ASSASIN) thief_bonus = 0;
    if (on(*tp, ISUNIQUE)) thief_bonus -= 15;
    if (isinvisible) thief_bonus -= 20;
    if (on(*tp, ISINWALL) && off(player, CANINWALL)) thief_bonus -= 50;

    if (on(*tp, ISHELD) || tp->t_action == A_FREEZE ||
	rnd(100) <
	(thief_bonus + 2*dex_compute() + 5*pstats.s_lvl -
	 5*(tp->t_stats.s_lvl - 3))) {
	register struct linked_list *s_item, *pack_ptr;
	int count = 0;
	unsigned long test;	/* Overflow check */

	s_item = NULL;	/* Start stolen goods out as nothing */

	/* Find a good item to take */
	for (pack_ptr=tp->t_pack; pack_ptr != NULL; pack_ptr=next(pack_ptr))
	    if ((OBJPTR(pack_ptr))->o_type != RELIC &&
		pack_ptr != tp->t_using &&  /* Monster can't be using it */
		rnd(++count) == 0)
		s_item = pack_ptr;

	/* 
	 * Find anything?
	 */
	if (s_item == NULL) {
	    msg("%s apparently has nothing to steal.", prname(mname, TRUE));
	    return;
	}

	/* Take it from monster */
	if (tp->t_pack) detach(tp->t_pack, s_item);

	/* Recalculate the monster's encumberance */
	updpack(TRUE, tp);

	/* Give it to player */
	if (add_pack(s_item, FALSE, NULL) == FALSE) {
	   (OBJPTR(s_item))->o_pos = hero;
	   fall(s_item, TRUE);
	}

	/* Get points for stealing -- but first check for overflow */
	test = pstats.s_exp + tp->t_stats.s_exp/2;
	if (test > pstats.s_exp) pstats.s_exp = test;

	/*
	 * Do adjustments if player went up a level
	 */
	check_level();
    }

    else {
	msg("Your attempt fails.");

	/* Annoy monster (maybe) */
	if (rnd(35) >= dex_compute() + thief_bonus) {
	    /*
	     * If this is a charmed creature, there is a chance it
	     * will become uncharmed.
	     */
	    if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
		msg("The eyes of %s turn clear.", prname(mname, FALSE));
		turn_off(*tp, ISCHARMED);
	    }
	    if (on(*tp, CANSELL)) {
		turn_off(*tp, CANSELL);
		tp->t_action = A_NIL;
		tp->t_movement = 0;
		if (rnd(100) < 50) /* make him steal something */
		    turn_on(*tp, STEALMAGIC);
		else
		    turn_on(*tp, STEALGOLD);
		if (!isinvisible)
		    msg("%s looks insulted.", prname(mname, TRUE));
	    }
	    runto(tp, &hero);
	}
    }
}

#ifdef PC7300
/* Use MAXSPELLS or whatever is the biggest number of spells/prayers/etc */
static menu_t Display;				/* The menu structure */
static mitem_t Dispitems[MAXSPELLS+1];		/* Info for each line */
static char Displines[MAXSPELLS+1][LINELEN+1];	/* The lines themselves */
#endif

/*
 * this routine lets the player pick the spell that they
 * want to cast regardless of character class
 * spells: spell list
 * ability: spell ability
 * num_spells: number of spells that can be cast
 * power: spell power
 * prompt: prompt for spell list
 * type: type of thing--> spell, prayer, chant
 */
bool
pick_spell(struct spells spells[], int ability, int num_spells, int power,
           char *prompt, char *type)
{
    bool		nohw = FALSE;
    register int	i;
    int			curlen,
			maxlen,
			dummy,
			which_spell,
			spell_left;
#ifdef PC7300
    char label[LINELEN],	/* For menu label */
	 title[LINELEN];	/* For menu title */
#endif

    if (cur_misc[WEAR_CLOAK] != NULL &&
	cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
	msg("You can't seem to start a %s!", type);
	return(FALSE);
    }

    /* Prompt for spells */
    msg("Which %s are you %sing? (* for list): ", type, prompt);

    which_spell = (int) (readchar() - 'a');
    msg("");	/* Get rid of the prompt */
    if (which_spell == (int) ESCAPE - (int) 'a') {
	after = FALSE;
	return(FALSE);
    }
    if (which_spell >= 0 && which_spell < num_spells) nohw = TRUE;

    else if (slow_invent) {
	register char c;

	nohw = TRUE;
	do {
	    for (i=0; i<num_spells; i++) {
		msg("");
		mvwaddch(msgw, 0, 0, '[');
		waddch(msgw, (char) ((int) 'a' + i));
		wprintw(msgw, "] A %s of ", type);
		if (spells[i].s_type == TYP_POTION)
		    waddstr(msgw, p_magic[spells[i].s_which].mi_name);
		else if (spells[i].s_type == TYP_SCROLL)
		    waddstr(msgw, s_magic[spells[i].s_which].mi_name);
		else if (spells[i].s_type == TYP_STICK)
		    waddstr(msgw, ws_magic[spells[i].s_which].mi_name);
		waddstr(msgw, morestr);
	        wclrtobot(msgw);
		clearok(msgw, FALSE);
		draw(msgw);
		do {
		    c = readchar();
		} while (c != ' ' && c != ESCAPE);
		if (c == ESCAPE)
		    break;
	    }
	    msg("");
	    wmove(msgw, 0, 0);
	    wprintw(msgw, "Which %s are you %sing? ", type, prompt);
	    clearok(msgw, FALSE);
	    draw(msgw);

	    which_spell = (int) (readchar() - 'a');
	} while (which_spell != (int) (ESCAPE - 'a') &&
		 (which_spell < 0 || which_spell >= num_spells));

	if (which_spell == (int) (ESCAPE - 'a')) {
	    mpos = 0;
	    msg("");
	    after = FALSE;
	    return(FALSE);
	}
    }
    else {
	/* Now display the possible spells */
	wclear(hw);
	touchwin(hw);
	wmove(hw, 2, 0);
	*type = toupper(*type);
	wprintw(hw, "	Cost	%s", type);
	*type = tolower(*type);
	mvwaddstr(hw, 3, 0,
		"-----------------------------------------------");
	maxlen = 47;	/* Maximum width of header */

	for (i=0; i<num_spells; i++) {
	    sprintf(prbuf, "[%c]	%3d	A %s of ",
			(char) ((int) 'a' + i), spells[i].s_cost, type);
	    if (spells[i].s_type == TYP_POTION)
		strcat(prbuf, p_magic[spells[i].s_which].mi_name);
	    else if (spells[i].s_type == TYP_SCROLL)
		strcat(prbuf, s_magic[spells[i].s_which].mi_name);
	    else if (spells[i].s_type == TYP_STICK)
		strcat(prbuf, ws_magic[spells[i].s_which].mi_name);
	    mvwaddstr(hw, i+4, 0, prbuf);

	    /* Get the length of the line */
	    getyx(hw, dummy, curlen);
	    if (maxlen < curlen) maxlen = curlen;

#ifdef PC7300
	    /* Put it into the PC menu display */
	    strcpy(Displines[i], prbuf);
	    Dispitems[i].mi_name = Displines[i];
	    Dispitems[i].mi_flags = 0;
	    Dispitems[i].mi_val = i;
#endif
	}

	spell_left = ability - power;
	if (spell_left < 0) {
	    spell_left = 0;
	    if (spell_left < -20) power = ability + 20;
	}
	sprintf(prbuf, "[Current %s power = %d]", type, spell_left);

	mvwaddstr(hw, 0, 0, prbuf);
	wprintw(hw, " Which %s are you %sing? ", type, prompt);
	getyx(hw, dummy, curlen);
	if (maxlen < curlen) maxlen = curlen;

#ifdef PC7300
	/* Place an end marker for the items */
	Dispitems[num_spells].mi_name = 0;

	/* Design prompts */
	sprintf(label, "Current %s power is %d", type, spell_left);
	*type = toupper(*type);
	sprintf(title, "	Cost	%s", type);
	*type = tolower(*type);
	sprintf(prbuf, "Select a %s or press Cancl to continue.", type);

	/* Set up the main menu structure */
	Display.m_label = label;
	Display.m_title = title;
	Display.m_prompt = prbuf;
	Display.m_curptr = '\0';
	Display.m_markptr = '\0';
	Display.m_flags = M_ASISTITLE;
	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) {
	    if (Display.m_selcnt == 0) {
		/* Menu was cancelled */
		after = FALSE;
		return FALSE;	/* all done if abort */
	    }
	    else which_spell = (int) Display.m_curi->mi_val;
	    goto got_spell;
	}
#endif
	/* Should we overlay? */
	if (menu_overlay && num_spells + 3 < lines / 2) {
	    over_win(cw, hw, num_spells + 5, maxlen + 3, 0, curlen, '\0');
	}
	else draw(hw);
    }

    if (!nohw) {
	which_spell = (int) (readchar() - 'a');
	while (which_spell < 0 || which_spell >= num_spells) {
	    if (which_spell == (int) ESCAPE - (int) 'a') {
		after = FALSE;

		/* Restore the screen */
		touchwin(cw);
		if (num_spells + 3 < lines / 2) clearok(cw, FALSE);
		else clearok(cw, TRUE);
		return(FALSE);
	    }
	    wmove(hw, 0, 0);
	    wclrtoeol(hw);
	    wprintw(hw, "Please enter one of the listed %ss. ", type);
	    getyx(hw, dummy, curlen);
	    if (maxlen < curlen) maxlen = curlen;

	    /* Should we overlay? */
	    if (menu_overlay && num_spells + 3 < lines / 2) {
		over_win(cw, hw, num_spells + 5, maxlen + 3,
			    0, curlen, '\0');
	    }
	    else draw(hw);

	    which_spell = (int) (readchar() - 'a');
	}
    }

    /* Now restore the screen if we have to */
    if (!nohw) {
	touchwin(cw);
	if (num_spells + 3 < lines / 2) clearok(cw, FALSE);
	else clearok(cw, TRUE);
    }

#ifdef PC7300
got_spell:
#endif
    if (spells[which_spell].s_type == TYP_STICK && 
	need_dir(STICK, spells[which_spell].s_which)) {
	    if (!get_dir(&player.t_newpos)) {
		after = FALSE;
		return(FALSE);
	    }
    }
    player.t_selection = which_spell;
    player.t_using = NULL;
    player.t_no_move = (which_spell/3 + 1) * movement(&player);
    return(TRUE);
}