Mercurial > hg > early-roguelike
view arogue5/options.c @ 251:e7862a021609
Fix the perpetual haste cheat.
Rogue V3 allowed the player to gain perpetual haste by quaffing a
potion of haste while already hasted. This is supposed to remove the
haste effect and cause temporary paralysis.
Super-Rogue removed haste correctly, but gave confusing messages.
author | John "Elwin" Edwards |
---|---|
date | Sat, 28 Jan 2017 11:45:36 -0500 |
parents | 50b89f165a34 |
children | e940e6c00751 |
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. * * 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. */ #include "curses.h" #include <ctype.h> #include <string.h> #include "rogue.h" #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 get_ro(WINDOW *win, int oy, int ox); int get_restr(char *optstr, WINDOW *win); int get_score(char *optstr, WINDOW *win); void put_abil(int *ability, WINDOW *win); int get_abil(int *abil, WINDOW *win); void put_quest(int *quest, WINDOW *win); int get_quest(int *quest, WINDOW *win); void put_bool(bool *b, WINDOW *win); int get_bool(bool *bp, WINDOW *win); void put_str(char *str, 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 }, {"pickup", "Pick things up automatically: ", (void *) &auto_pickup, put_bool, get_bool }, {"name", "Name: ", (void *) whoami, put_str, get_restr }, {"fruit", "Fruit: ", (void *) fruit, put_str, get_str }, {"file", "Save file: ", (void *) file_name, put_str, get_restr }, {"score", "Score file: ", (void *) score_file, put_str, get_score }, {"class", "Character class: ", (void *)&char_type, put_abil, get_abil }, {"quest", "Quest item: ", (void *) &quest_item, put_quest, get_quest } }; /* For fields that would be restricted if use_savedir is set. */ int get_restr(char *optstr, WINDOW *win) { int oy, ox; if (use_savedir) { getyx(win, oy, ox); put_str(optstr, win); return get_ro(win, oy, ox); } else return get_str(optstr, win); } /* For the score file, which must be opened. */ int get_score(char *optstr, WINDOW *win) { char old_score_file[LINELEN]; int status; if (use_savedir) return get_restr(optstr, win); strcpy(old_score_file, optstr); status = get_str(optstr, win); if (status != NORM) return status; if (strcmp(old_score_file, optstr)) { md_reopen_score(); } return status; } /* * The ability field is read-only */ int get_abil(int *abil, WINDOW *win) { register int oy, ox; getyx(win, oy, ox); put_abil(abil, win); return get_ro(win, oy, ox); } /* * The quest field is read-only */ int get_quest(int *quest, WINDOW *win) { register int oy, ox; getyx(win, oy, ox); waddstr(win, rel_magic[*quest].mi_name); return get_ro(win, oy, ox); } /* * get_ro: * "Get" a read-only value. */ int get_ro(WINDOW *win, int oy, int ox) { register int ny, nx; register bool op_bad; op_bad = TRUE; getyx(win, ny, nx); while(op_bad) { wmove(win, oy, ox); draw(win); switch (wgetch(win)) { case '\n': case '\r': op_bad = FALSE; break; case '\033': case '\007': return QUIT; case '-': return MINUS; default: mvwaddstr(win, ny, nx + 5, "(no change allowed)"); } } wmove(win, ny, nx + 5); wclrtoeol(win); wmove(win, ny, nx); waddch(win, '\n'); return NORM; } /* * 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); draw(win); switch (wgetch(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); wclrtoeol(win); waddstr(win, *bp ? "True" : "False"); waddch(win, '\n'); return NORM; } /* * set a string option */ int get_str(char *opt, WINDOW *win) { register char *sp; register int c, oy, ox; char buf[LINELEN]; draw(win); getyx(win, oy, ox); /* * loop reading in the string, and put it in a temporary buffer */ for (sp = buf; (c = md_readchar(win)) != '\n' && c != '\r' && c != '\033' && c != '\007' && sp < &buf[LINELEN-1]; wclrtoeol(win), draw(win)) { if (c == -1) continue; else if (c == md_erasechar()) /* process erase character */ { if (sp > buf) { register int i; sp--; for (i = strlen(unctrl(*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 == hw) /* To move back a line in hw */ break; else if (c == '~') { strcpy(buf, home); waddstr(win, home); sp += strlen(home); continue; } *sp++ = c; waddstr(win, unctrl(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'); draw(win); if (win == cw) mpos += (int)(sp - buf); if (c == '-') return MINUS; else if (c == '\033' || c == '\007') return QUIT; else return NORM; } /* * print and then set options from the terminal */ void option(void) { register OPTION *op; register int retval; wclear(hw); touchwin(hw); /* * Display current values of options */ for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++) { waddstr(hw, op->o_prompt); (*op->o_putfunc)(op->o_opt, hw); waddch(hw, '\n'); } /* * Set values */ wmove(hw, 0, 0); for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++) { waddstr(hw, op->o_prompt); if ((retval = (*op->o_getfunc)(op->o_opt, hw))) if (retval == QUIT) break; else if (op > optlist) { /* MINUS */ wmove(hw, (int)(op - optlist) - 1, 0); op -= 2; } else /* trying to back up beyond the top */ { putchar('\007'); wmove(hw, 0, 0); op--; } } /* * Switch back to original screen */ mvwaddstr(hw, LINES-1, 0, spacemsg); draw(hw); wait_for(hw,' '); clearok(cw, TRUE); touchwin(cw); after = FALSE; } /* * 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 = (int)(sp - str); /* * Look it up and deal with it */ for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++) /* None of these can be changed if using system savefiles. */ if (use_savedir && (!strcmp(op->o_name, "name") || !strcmp(op->o_name, "file") || !strcmp(op->o_name, "score") )) 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; char value[80]; /* * Skip to start of string value */ for (str = sp + 1; *str == '='; str++) continue; if (*str == '~') { strcpy((char *) value, home); start = (char *) value + strlen(home); while (*++str == '/') continue; } else start = (char *) value; /* * Skip to end of string value */ for (sp = str + 1; *sp && *sp != ','; sp++) continue; strucpy(start, str, sp - str); /* Put the value into the option field */ if (op->o_putfunc != put_abil) strcpy((char *)op->o_opt, value); else if (*(int *)op->o_opt == -1) { /* Only init ability once */ register int len = strlen(value); if (isupper(value[0])) value[0] = tolower(value[0]); if (EQSTR(value, "fighter", len)) *(int *)op->o_opt = C_FIGHTER; else if (EQSTR(value, "magic", min(len, 5))) *(int *)op->o_opt = C_MAGICIAN; else if (EQSTR(value, "cleric", len)) *(int *)op->o_opt = C_CLERIC; else if (EQSTR(value, "thief", len)) *(int *)op->o_opt = C_THIEF; } } 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; } } /* * print the character type */ void put_abil(int *ability, WINDOW *win) { char *abil; switch (*ability) { case C_MAGICIAN:abil = "Magic User"; when C_FIGHTER: abil = "Fighter"; when C_CLERIC: abil = "Cleric"; when C_THIEF: abil = "Thief"; otherwise: abil = "??"; } waddstr(win, abil); } /* * print out the quest */ void put_quest(int *quest, WINDOW *win) { waddstr(win, rel_magic[*quest].mi_name); } /* * put out a boolean */ void put_bool(bool *b, WINDOW *win) { waddstr(win, *b ? "True" : "False"); } /* * put out a string */ void put_str(char *str, WINDOW *win) { waddstr(win, str); }