view rogue4/options.c @ 245:e7aab31362af

Rogue V[345], Super-Rogue: Fix violet fungi/venus flytraps. Violet fungi (renamed venus flytraps in Rogue V5) do an increasing amount of damage each time they hit. If they miss, you still suffer the same number of HP. This worked by keeping a counter and printing new damage strings into monsters[5].m_stats.s_dmg, which is the "prototype" of that particular monster. Each individual monster has its own damage string. Apparently these were once char *, pointing to the same string as the prototype. When the s_dmg member was changed to be an internal char array, changing the prototype's damage string no longer had any effect on actual monsters. As a result, flytraps did no damage on a hit, or only one point in V5. The mechanism for doing damage on a miss continued to work. This has been fixed by overwriting the individual monster's damage string instead of the prototype's. It is now no longer necessary to reset the damage string when the flytrap is killed. The method for resetting it when the hero teleports away had to be modified. Comments referencing the long-unused xstr have been removed.
author John "Elwin" Edwards
date Sun, 01 May 2016 19:39:56 -0400
parents 50b89f165a34
children e52a8a7ad4c5
line wrap: on
line source

/*
 * This file has all the code for the option command.  I would rather
 * this command were not necessary, but it is the only way to keep the
 * wolves off of my back.
 *
 * @(#)options.c	4.12 (Berkeley) 3/2/82
 *
 * Rogue: Exploring the Dungeons of Doom
 * Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
 * All rights reserved.
 *
 * See the file LICENSE.TXT for full copyright and licensing information.
 */

#include <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"

#define	EQSTR(a, b, c)	(strncmp(a, b, c) == 0)

#define	NUM_OPTS	(sizeof optlist / sizeof (OPTION))

/*
 * description of an option and what to do with it
 */
struct optstruct {
    char	*o_name;	/* option name */
    char	*o_prompt;	/* prompt for interactive entry */
    void	*o_opt;		/* pointer to thing to set */
    void	(*o_putfunc)();	/* function to print value */
    int		(*o_getfunc)();	/* function to get value interactively */
};

typedef struct optstruct	OPTION;

int allowchange(OPTION *opt);

void put_bool(bool *b);
void put_str(char *str);
int get_bool(bool *bp, WINDOW *win);
int get_str(char *opt, WINDOW *win);

OPTION	optlist[] = {
    {"terse",	 "Terse output: ",
		 (void *) &terse,	put_bool,	get_bool	},
    {"flush",	 "Flush typeahead during battle: ",
		(void *) &fight_flush,	put_bool,	get_bool	},
    {"jump",	 "Show position only at end of run: ",
		(void *) &jump,		put_bool,	get_bool	},
    {"step",	"Do inventories one line at a time: ",
		(void *) &slow_invent,	put_bool,	get_bool	},
    {"askme",	"Ask me about unidentified things: ",
		(void *) &askme,	put_bool,	get_bool	},
    {"passgo",	"Follow turnings in passageways: ",
		(void *) &passgo,	put_bool,	get_bool	},
    {"name",	 "Name: ",
		(void *) whoami,	put_str,	get_str		},
    {"fruit",	 "Fruit: ",
		(void *) fruit,		put_str,	get_str		},
    {"file",	 "Save file: ",
		(void *) file_name,	put_str,	get_str		}
};

/*
 * option:
 *	Print and then set options from the terminal
 */
void
option(void)
{
    register OPTION	*op;
    register int	retval;

    wclear(hw);
    /*
     * Display current values of options
     */
    for (op = optlist; op < &optlist[NUM_OPTS]; op++)
    {
        if (allowchange(op))
        {
	    waddstr(hw, op->o_prompt);
	    (*op->o_putfunc)(op->o_opt);
	    waddch(hw, '\n');
        }
    }
    /*
     * Set values
     */
    wmove(hw, 0, 0);
    for (op = optlist; op < &optlist[NUM_OPTS]; op++)
    {
        if (!allowchange(op))
            continue;
	waddstr(hw, op->o_prompt);
	if ((retval = (*op->o_getfunc)(op->o_opt, hw)))
        {
	    if (retval == QUIT)
		break;
#if 0 /* disable MINUS */
	    else if (op > optlist) {	/* MINUS */
		wmove(hw, (op - optlist) - 1, 0);
		op -= 2;
	    }
	    else	/* trying to back up beyond the top */
	    {
		putchar('\007');
		wmove(hw, 0, 0);
		op--;
	    }
#else
            break;
#endif
        }
    }
    /*
     * Switch back to original screen
     */
    mvwaddstr(hw, LINES-1, 0, "--Press space to continue--");
    wrefresh(hw);
    wait_for(' ');
    clearok(curscr, TRUE);
    touchwin(stdscr);
    after = FALSE;
}

/*
 * put_bool
 *	Put out a boolean
 */
void
put_bool(bool *b)
{
    waddstr(hw, *b ? "True" : "False");
}

/*
 * put_str:
 *	Put out a string
 */
void
put_str(char *str)
{
    waddstr(hw, str);
}

/*
 * get_bool:
 *	Allow changing a boolean option and print it out
 */
int
get_bool(bool *bp, WINDOW *win)
{
    register int oy, ox;
    register bool op_bad;

    op_bad = TRUE;
    getyx(win, oy, ox);
    waddstr(win, *bp ? "True" : "False");
    while (op_bad)	
    {
	wmove(win, oy, ox);
	wrefresh(win);
	switch (readcharw(win))
	{
	    case 't':
	    case 'T':
		*bp = TRUE;
		op_bad = FALSE;
		break;
	    case 'f':
	    case 'F':
		*bp = FALSE;
		op_bad = FALSE;
		break;
	    case '\n':
	    case '\r':
		op_bad = FALSE;
		break;
	    case '\033':
	    case '\007':
		return QUIT;
	    case '-':
		return MINUS;
	    default:
		mvwaddstr(win, oy, ox + 10, "(T or F)");
	}
    }
    wmove(win, oy, ox);
    waddstr(win, *bp ? "True" : "False");
    waddch(win, '\n');
    return NORM;
}

/*
 * get_str:
 *	Set a string option
 */
#define MAXINP	50	/* max string to read from terminal or environment */

int
get_str(char *opt, WINDOW *win)
{
    register char *sp;
    register int c, oy, ox;
    char buf[MAXSTR];

    getyx(win, oy, ox);
    wrefresh(win);
    /*
     * loop reading in the string, and put it in a temporary buffer
     */
    for (sp = buf; (c = readcharw(win)) != '\n' && c != '\r' && c != '\033';
	wclrtoeol(win), wrefresh(win))
    {
	if (c == -1)
	    continue;
	else if (c == md_erasechar())	/* process erase character */
	{
	    if (sp > buf)
	    {
		register int i;

		sp--;
		for (i = strlen(unctrol(*sp)); i; i--)
		    waddch(win, '\b');
	    }
	    continue;
	}
	else if (c == md_killchar())     /* process kill character */
	{
	    sp = buf;
	    wmove(win, oy, ox);
	    continue;
	}
	else if (sp == buf)
	{
	    if (c == '-' && win != stdscr)
		break;
	    else if (c == '~')
	    {
		strcpy(buf, home);
		waddstr(win, home);
		sp += strlen(home);
		continue;
	    }
	}
	if (sp >= &buf[MAXINP] || !(isprint(c) || c == ' '))
	    putchar(CTRL('G'));
	else
	{
	    *sp++ = c;
	    waddstr(win, unctrol(c));
	}
    }
    *sp = '\0';
    if (sp > buf)	/* only change option if something has been typed */
	strucpy(opt, buf, strlen(buf));
    wmove(win, oy, ox);
    waddstr(win, opt);
    waddch(win, '\n');
    wrefresh(win);
    if (win == stdscr)
	mpos += sp - buf;
    if (c == '-')
	return MINUS;
    else if (c == '\033' || c == '\007')
	return QUIT;
    else
	return NORM;
}

#ifdef WIZARD
/*
 * get_num:
 *	Get a numeric option
 */
int
get_num(short *opt, WINDOW *win)
{
    register int i;
    char buf[MAXSTR];

    if ((i = get_str(buf, win)) == NORM)
	*opt = atoi(buf);
    return i;
}
#endif

/*
 * parse_opts:
 *	Parse options from string, usually taken from the environment.
 *	The string is a series of comma seperated values, with booleans
 *	being stated as "name" (true) or "noname" (false), and strings
 *	being "name=....", with the string being defined up to a comma
 *	or the end of the entire option string.
 */
void
parse_opts(char *str)
{
    register char *sp;
    register OPTION *op;
    register int len;

    while (*str)
    {
	/*
	 * Get option name
	 */
	for (sp = str; isalpha(*sp); sp++)
	    continue;
	len = sp - str;
	/*
	 * Look it up and deal with it
	 */
	for (op = optlist; op < &optlist[NUM_OPTS]; op++)
        {
            /* If using system savefiles, changing your name or the
               save file is not allowed. */
            if (!allowchange(op))
                continue;
	    if (EQSTR(str, op->o_name, len))
	    {
		if (op->o_putfunc == put_bool)	/* if option is a boolean */
		    *(bool *)op->o_opt = TRUE;
		else				/* string option */
		{
		    register char *start;
		    /*
		     * Skip to start of string value
		     */
		    for (str = sp + 1; *str == '='; str++)
			continue;
		    if (*str == '~')
		    {
			strcpy((char *) op->o_opt, home);
			start = (char *) op->o_opt + strlen(home);
			while (*++str == '/')
			    continue;
		    }
		    else
			start = (char *) op->o_opt;
		    /*
		     * Skip to end of string value
		     */
		    for (sp = str + 1; *sp && *sp != ','; sp++)
			continue;
		    strucpy(start, str, sp - str);
		}
		break;
	    }
	    /*
	     * check for "noname" for booleans
	     */
	    else if (op->o_putfunc == put_bool
	      && EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2))
	    {
		*(bool *)op->o_opt = FALSE;
		break;
	    }
        }

	/*
	 * skip to start of next option name
	 */
	while (*sp && !isalpha(*sp))
	    sp++;
	str = sp;
    }
}

/*
 * strucpy:
 *	Copy string using unctrol for things
 */
void
strucpy(char *s1, char *s2, int len)
{
    if (len > MAXINP)
	len = MAXINP;
    while (len--)
    {
	if (isprint(*s2) || *s2 == ' ')
	    *s1++ = *s2;
	s2++;
    }
    *s1 = '\0';
}

/* Tells whether the player is allowed to change the option. */
int allowchange(OPTION *opt)
{
    if (!use_savedir)
        return 1;
    if (!strcmp(opt->o_name, "name"))
        return 0;
    if (!strcmp(opt->o_name, "file"))
        return 0;
    return 1;
}