Move the toptenwin option from flags to iflags to keep it out of save files, thus preventing odd behavior from win32 (nethackW.exe) when restoring and finishing games started and saved with tty (nethack.exe). [See cvs log entry for flag.h for more complete explanation.]
4744 lines
138 KiB
C
4744 lines
138 KiB
C
/* NetHack 3.5 options.c $Date$ $Revision$ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
|
|
#include "config.h"
|
|
#include "objclass.h"
|
|
#include "flag.h"
|
|
NEARDATA struct flag flags; /* provide linkage */
|
|
#ifdef SYSFLAGS
|
|
NEARDATA struct sysflag sysflags; /* provide linkage */
|
|
#endif
|
|
NEARDATA struct instance_flags iflags; /* provide linkage */
|
|
#define static
|
|
#else
|
|
#include "hack.h"
|
|
#include "tcap.h"
|
|
#include <ctype.h>
|
|
#endif
|
|
|
|
#define BACKWARD_COMPAT
|
|
#define WINTYPELEN 16
|
|
|
|
#ifdef DEFAULT_WC_TILED_MAP
|
|
#define PREFER_TILED TRUE
|
|
#else
|
|
#define PREFER_TILED FALSE
|
|
#endif
|
|
|
|
#define MESSAGE_OPTION 1
|
|
#define STATUS_OPTION 2
|
|
#define MAP_OPTION 3
|
|
#define MENU_OPTION 4
|
|
#define TEXT_OPTION 5
|
|
|
|
#define PILE_LIMIT_DFLT 5
|
|
|
|
/*
|
|
* NOTE: If you add (or delete) an option, please update the short
|
|
* options help (option_help()), the long options help (dat/opthelp),
|
|
* and the current options setting display function (doset()),
|
|
* and also the Guidebooks.
|
|
*
|
|
* The order matters. If an option is a an initial substring of another
|
|
* option (e.g. time and timed_delay) the shorter one must come first.
|
|
*/
|
|
|
|
static struct Bool_Opt
|
|
{
|
|
const char *name;
|
|
boolean *addr, initvalue;
|
|
int optflags;
|
|
} boolopt[] = {
|
|
{"acoustics", &flags.acoustics, TRUE, SET_IN_GAME},
|
|
#if defined(SYSFLAGS) && defined(AMIGA)
|
|
/* Amiga altmeta causes Alt+key to be converted into Meta+key by
|
|
low level nethack code; on by default, can be toggled off if
|
|
Alt+key is needed for some ASCII chars on non-ASCII keyboard */
|
|
{"altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME},
|
|
#else
|
|
# ifdef ALTMETA
|
|
/* non-Amiga altmeta causes nethack's top level command loop to treat
|
|
two character sequence "ESC c" as M-c, for terminals or emulators
|
|
which send "ESC c" when Alt+c is pressed; off by default, enabling
|
|
this can potentially make trouble if user types ESC when nethack
|
|
is honoring this conversion request (primarily after starting a
|
|
count prefix prior to a command and then deciding to cancel it) */
|
|
{"altmeta", &iflags.altmeta, FALSE, SET_IN_GAME},
|
|
# else
|
|
{"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
|
|
# endif
|
|
#endif
|
|
{"ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME}, /*WC*/
|
|
#if defined(SYSFLAGS) && defined(MFLOPPY)
|
|
{"asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"autodig", &flags.autodig, FALSE, SET_IN_GAME},
|
|
{"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
|
|
{"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
|
|
#if defined(MICRO) && !defined(AMIGA)
|
|
{"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
|
|
#else
|
|
{"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
#ifdef INSURANCE
|
|
{"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
|
|
#else
|
|
{"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
#ifdef MFLOPPY
|
|
{"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
|
|
#else
|
|
{"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"clicklook", &iflags.clicklook, FALSE, SET_IN_GAME},
|
|
{"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
|
|
# if defined(MICRO) || defined(WIN32)
|
|
{"color", &iflags.wc_color,TRUE, SET_IN_GAME}, /*WC*/
|
|
# else /* systems that support multiple terminals, many monochrome */
|
|
{"color", &iflags.wc_color, FALSE, SET_IN_GAME}, /*WC*/
|
|
# endif
|
|
{"confirm",&flags.confirm, TRUE, SET_IN_GAME},
|
|
{"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME}, /*WC*/
|
|
#ifdef TTY_GRAPHICS
|
|
{"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
#ifdef OPT_DISPMAP
|
|
{"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
|
|
#else
|
|
{"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
|
|
#endif
|
|
{"female", &flags.female, FALSE, DISP_IN_GAME},
|
|
{"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
|
|
#if defined(SYSFLAGS) && defined(AMIFLUSH)
|
|
{"flush", &sysflags.amiflush, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"flush", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
|
|
{"help", &flags.help, TRUE, SET_IN_GAME},
|
|
{"hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME}, /*WC*/
|
|
#ifndef MAC
|
|
{"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */
|
|
{"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
|
|
{"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
|
|
{"lootabc", &flags.lootabc, FALSE, SET_IN_GAME},
|
|
#ifdef MAIL
|
|
{"mail", &flags.biff, TRUE, SET_IN_GAME},
|
|
#else
|
|
{"mail", (boolean *)0, TRUE, SET_IN_FILE},
|
|
#endif
|
|
#ifdef WIZARD
|
|
/* for menu debugging only*/
|
|
{"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME}, /*WC*/
|
|
#ifdef NEWS
|
|
{"news", &iflags.news, TRUE, DISP_IN_GAME},
|
|
#else
|
|
{"news", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"null", &flags.null, TRUE, SET_IN_GAME},
|
|
#if defined(SYSFLAGS) && defined(MAC)
|
|
{"page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME},
|
|
#else
|
|
{"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
|
|
{"pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME},
|
|
{"popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME}, /*WC*/
|
|
{"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME}, /*WC*/
|
|
{"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
|
|
#if defined(MICRO) && !defined(AMIGA)
|
|
{"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
|
|
#else
|
|
{"rawio", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
|
|
#ifdef RLECOMP
|
|
{"rlecomp", &iflags.rlecomp,
|
|
# if defined(COMPRESS) || defined(ZLIB_COMP)
|
|
FALSE,
|
|
# else
|
|
TRUE,
|
|
# endif
|
|
DISP_IN_GAME},
|
|
#endif
|
|
{"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
|
|
#ifdef WIZARD
|
|
{"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME}, /*WC*/
|
|
#ifdef EXP_ON_BOTL
|
|
{"showexp", &flags.showexp, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"showexp", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"showrace", &flags.showrace, FALSE, SET_IN_GAME},
|
|
#ifdef SCORE_ON_BOTL
|
|
{"showscore", &flags.showscore, FALSE, SET_IN_GAME},
|
|
#else
|
|
{"showscore", (boolean *)0, FALSE, SET_IN_FILE},
|
|
#endif
|
|
{"silent", &flags.silent, TRUE, SET_IN_GAME},
|
|
{"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
|
|
{"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
|
|
{"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
|
|
{"splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME}, /*WC*/
|
|
{"standout", &flags.standout, FALSE, SET_IN_GAME},
|
|
{"tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME}, /*WC*/
|
|
{"time", &flags.time, FALSE, SET_IN_GAME},
|
|
#ifdef TIMED_DELAY
|
|
{"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
|
|
#else
|
|
{"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
|
|
#endif
|
|
{"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
|
|
{"toptenwin",&iflags.toptenwin, FALSE, SET_IN_GAME},
|
|
{"travel", &flags.travelcmd, TRUE, SET_IN_GAME},
|
|
#ifdef UNICODE_SUPPORT
|
|
{"unicode", &iflags.unicodedisp, FALSE, SET_IN_GAME},
|
|
#endif
|
|
#ifdef WIN32CON
|
|
{"use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME}, /*WC*/
|
|
#else
|
|
{"use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME}, /*WC*/
|
|
#endif
|
|
{"verbose", &flags.verbose, TRUE, SET_IN_GAME},
|
|
{"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
|
|
#ifdef ZEROCOMP
|
|
{"zerocomp", &iflags.zerocomp,
|
|
# if defined(COMPRESS) || defined(ZLIB_COMP)
|
|
FALSE,
|
|
# else
|
|
TRUE,
|
|
# endif
|
|
DISP_IN_GAME},
|
|
#endif
|
|
{(char *)0, (boolean *)0, FALSE, 0}
|
|
};
|
|
|
|
/* compound options, for option_help() and external programs like Amiga
|
|
* frontend */
|
|
static struct Comp_Opt
|
|
{
|
|
const char *name, *descr;
|
|
int size; /* for frontends and such allocating space --
|
|
* usually allowed size of data in game, but
|
|
* occasionally maximum reasonable size for
|
|
* typing when game maintains information in
|
|
* a different format */
|
|
int optflags;
|
|
} compopt[] = {
|
|
{ "align", "your starting alignment (lawful, neutral, or chaotic)",
|
|
8, DISP_IN_GAME },
|
|
{ "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
|
|
#ifdef BACKWARD_COMPAT
|
|
{ "boulder", "deprecated (use S_boulder in sym file instead)",
|
|
1, SET_IN_FILE },
|
|
#endif
|
|
{ "catname", "the name of your (first) cat (e.g., catname:Tabby)",
|
|
PL_PSIZ, DISP_IN_GAME },
|
|
{ "disclose", "the kinds of information to disclose at end of game",
|
|
sizeof(flags.end_disclose) * 2,
|
|
SET_IN_GAME },
|
|
{ "dogname", "the name of your (first) dog (e.g., dogname:Fang)",
|
|
PL_PSIZ, DISP_IN_GAME },
|
|
{ "dungeon", "the symbols to use in drawing the dungeon map",
|
|
MAXDCHARS+1, SET_IN_FILE },
|
|
{ "effects", "the symbols to use in drawing special effects",
|
|
MAXECHARS+1, SET_IN_FILE },
|
|
{ "font_map", "the font to use in the map window", 40, DISP_IN_GAME }, /*WC*/
|
|
{ "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
|
|
{ "font_message", "the font to use in the message window",
|
|
40, DISP_IN_GAME }, /*WC*/
|
|
{ "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
|
|
{ "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/
|
|
{ "fruit", "the name of a fruit you enjoy eating",
|
|
PL_FSIZ, SET_IN_GAME },
|
|
{ "gender", "your starting gender (male or female)",
|
|
8, DISP_IN_GAME },
|
|
{ "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
|
|
PL_PSIZ, DISP_IN_GAME },
|
|
{ "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
|
|
{ "menustyle", "user interface for object selection",
|
|
MENUTYPELEN, SET_IN_GAME },
|
|
{ "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
|
|
{ "menu_deselect_page", "deselect all items on this page of a menu",
|
|
4, SET_IN_FILE },
|
|
{ "menu_first_page", "jump to the first page in a menu",
|
|
4, SET_IN_FILE },
|
|
{ "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
|
|
{ "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
|
|
{ "menu_invert_page", "invert all items on this page of a menu",
|
|
4, SET_IN_FILE },
|
|
{ "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
|
|
{ "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
|
|
{ "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
|
|
{ "menu_search", "search for a menu item", 4, SET_IN_FILE },
|
|
{ "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
|
|
{ "menu_select_page", "select all items on this page of a menu",
|
|
4, SET_IN_FILE },
|
|
{ "monsters", "the symbols to use for monsters",
|
|
MAXMCLASSES, SET_IN_FILE },
|
|
{ "msghistory", "number of top line messages to save",
|
|
5, DISP_IN_GAME },
|
|
# ifdef TTY_GRAPHICS
|
|
{"msg_window", "the type of message window required",1, SET_IN_GAME},
|
|
# else
|
|
{"msg_window", "the type of message window required", 1, SET_IN_FILE},
|
|
# endif
|
|
{ "name", "your character's name (e.g., name:Merlin-W)",
|
|
PL_NSIZ, DISP_IN_GAME },
|
|
{ "number_pad", "use the number pad for movement", 1, SET_IN_GAME},
|
|
{ "objects", "the symbols to use for objects",
|
|
MAXOCLASSES, SET_IN_FILE },
|
|
{ "packorder", "the inventory order of the items in your pack",
|
|
MAXOCLASSES, SET_IN_GAME },
|
|
#ifdef CHANGE_COLOR
|
|
{ "palette",
|
|
# ifndef WIN32CON
|
|
"palette (00c/880/-fff is blue/yellow/reverse white)",
|
|
15 , SET_IN_GAME },
|
|
# else
|
|
"palette (adjust an RGB color in palette (color-R-G-B)",
|
|
15 , SET_IN_FILE },
|
|
# endif
|
|
# if defined(MAC)
|
|
{ "hicolor", "same as palette, only order is reversed",
|
|
15, SET_IN_FILE },
|
|
# endif
|
|
#endif
|
|
{ "paranoid_confirmation", "extra prompting in certain situations",
|
|
28, SET_IN_GAME },
|
|
{ "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
|
|
{ "pickup_burden", "maximum burden picked up before prompt",
|
|
20, SET_IN_GAME },
|
|
{ "pickup_types", "types of objects to pick up automatically",
|
|
MAXOCLASSES, SET_IN_GAME },
|
|
{ "pile_limit", "threshold for \"there are many objects here\"",
|
|
24, SET_IN_GAME },
|
|
{ "playmode",
|
|
#ifdef WIZARD
|
|
"normal play, non-scoring explore mode, or debug mode",
|
|
#else
|
|
"normal play or non-scoring explore mode",
|
|
#endif
|
|
8, DISP_IN_GAME },
|
|
{ "player_selection", "choose character via dialog or prompts",
|
|
12, DISP_IN_GAME },
|
|
{ "race", "your starting race (e.g., Human, Elf)",
|
|
PL_CSIZ, DISP_IN_GAME },
|
|
{ "role", "your starting role (e.g., Barbarian, Valkyrie)",
|
|
PL_CSIZ, DISP_IN_GAME },
|
|
{ "runmode", "display frequency when `running' or `travelling'",
|
|
sizeof "teleport", SET_IN_GAME },
|
|
{ "scores", "the parts of the score list you wish to see",
|
|
32, SET_IN_GAME },
|
|
{ "scroll_amount", "amount to scroll map when scroll_margin is reached",
|
|
20, DISP_IN_GAME }, /*WC*/
|
|
{ "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
|
|
#ifdef MSDOS
|
|
{ "soundcard", "type of sound card to use", 20, SET_IN_FILE },
|
|
#endif
|
|
{ "symset", "load a set of display symbols from the symbols file", 70,
|
|
#ifdef LOADSYMSETS
|
|
SET_IN_GAME },
|
|
#else
|
|
DISP_IN_GAME},
|
|
#endif
|
|
{ "roguesymset", "load a set of rogue display symbols from the symbols file", 70,
|
|
#ifdef REINCARNATION
|
|
# ifdef LOADSYMSETS
|
|
SET_IN_GAME },
|
|
# else
|
|
DISP_IN_GAME},
|
|
# endif
|
|
#else
|
|
SET_IN_FILE},
|
|
#endif
|
|
{ "suppress_alert", "suppress alerts about version-specific features",
|
|
8, SET_IN_GAME },
|
|
{ "tile_width", "width of tiles", 20, DISP_IN_GAME}, /*WC*/
|
|
{ "tile_height", "height of tiles", 20, DISP_IN_GAME}, /*WC*/
|
|
{ "tile_file", "name of tile file", 70, DISP_IN_GAME}, /*WC*/
|
|
{ "traps", "the symbols to use in drawing traps",
|
|
MAXTCHARS+1, SET_IN_FILE },
|
|
{ "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
|
|
#ifdef MSDOS
|
|
{ "video", "method of video updating", 20, SET_IN_FILE },
|
|
#endif
|
|
#ifdef VIDEOSHADES
|
|
{ "videocolors", "color mappings for internal screen routines",
|
|
40, DISP_IN_GAME },
|
|
{ "videoshades", "gray shades to map to black/gray/white",
|
|
32, DISP_IN_GAME },
|
|
#endif
|
|
#ifdef WIN32CON
|
|
{"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
|
|
#endif
|
|
{ "windowcolors", "the foreground/background colors of windows", /*WC*/
|
|
80, DISP_IN_GAME },
|
|
{ "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
|
|
#ifdef BACKWARD_COMPAT
|
|
{"DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE},
|
|
{"IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE},
|
|
# ifdef MAC_GRAPHICS_ENV
|
|
{"Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE},
|
|
# endif
|
|
#endif
|
|
{ (char *)0, (char *)0, 0, 0 }
|
|
};
|
|
|
|
#ifdef OPTION_LISTS_ONLY
|
|
#undef static
|
|
|
|
#else /* use rest of file */
|
|
|
|
extern struct symparse loadsyms[];
|
|
static boolean need_redraw; /* for doset() */
|
|
|
|
#if defined(TOS) && defined(TEXTCOLOR)
|
|
extern boolean colors_changed; /* in tos.c */
|
|
#endif
|
|
|
|
#ifdef VIDEOSHADES
|
|
extern char *shade[3]; /* in sys/msdos/video.c */
|
|
extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
|
|
#endif
|
|
|
|
static char def_inv_order[MAXOCLASSES] = {
|
|
COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
|
|
SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
|
|
TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
|
|
};
|
|
|
|
/*
|
|
* Default menu manipulation command accelerators. These may _not_ be:
|
|
*
|
|
* + a number - reserved for counts
|
|
* + an upper or lower case US ASCII letter - used for accelerators
|
|
* + ESC - reserved for escaping the menu
|
|
* + NULL, CR or LF - reserved for commiting the selection(s). NULL
|
|
* is kind of odd, but the tty's xwaitforspace() will return it if
|
|
* someone hits a <ret>.
|
|
* + a default object class symbol - used for object class accelerators
|
|
*
|
|
* Standard letters (for now) are:
|
|
*
|
|
* < back 1 page
|
|
* > forward 1 page
|
|
* ^ first page
|
|
* | last page
|
|
* : search
|
|
*
|
|
* page all
|
|
* , select .
|
|
* \ deselect -
|
|
* ~ invert @
|
|
*
|
|
* The command name list is duplicated in the compopt array.
|
|
*/
|
|
typedef struct {
|
|
const char *name;
|
|
char cmd;
|
|
} menu_cmd_t;
|
|
|
|
#define NUM_MENU_CMDS 11
|
|
static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
|
|
/* 0*/ { "menu_first_page", MENU_FIRST_PAGE },
|
|
{ "menu_last_page", MENU_LAST_PAGE },
|
|
{ "menu_next_page", MENU_NEXT_PAGE },
|
|
{ "menu_previous_page", MENU_PREVIOUS_PAGE },
|
|
{ "menu_select_all", MENU_SELECT_ALL },
|
|
/* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL },
|
|
{ "menu_invert_all", MENU_INVERT_ALL },
|
|
{ "menu_select_page", MENU_SELECT_PAGE },
|
|
{ "menu_deselect_page", MENU_UNSELECT_PAGE },
|
|
{ "menu_invert_page", MENU_INVERT_PAGE },
|
|
/*10*/ { "menu_search", MENU_SEARCH },
|
|
};
|
|
|
|
/*
|
|
* Allow the user to map incoming characters to various menu commands.
|
|
* The accelerator list must be a valid C string.
|
|
*/
|
|
#define MAX_MENU_MAPPED_CMDS 32 /* some number */
|
|
char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1]; /* exported */
|
|
static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1];
|
|
static short n_menu_mapped = 0;
|
|
|
|
|
|
static boolean initial, from_file;
|
|
|
|
STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int));
|
|
STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
|
|
STATIC_DCL void FDECL(escapes, (const char *, char *));
|
|
STATIC_DCL void FDECL(rejectoption, (const char *));
|
|
STATIC_DCL void FDECL(badoption, (const char *));
|
|
STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P));
|
|
STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P));
|
|
STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P));
|
|
STATIC_DCL int FDECL(change_inv_order, (char *));
|
|
STATIC_DCL void FDECL(oc_to_str, (char *, char *));
|
|
STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
|
|
STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
|
|
STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
|
|
STATIC_DCL void FDECL(warning_opts, (char *,const char *));
|
|
STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
|
|
STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
|
|
|
|
STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
|
|
STATIC_OVL int FDECL(wc_set_window_colors, (char *));
|
|
STATIC_OVL boolean FDECL(is_wc_option, (const char *));
|
|
STATIC_OVL boolean FDECL(wc_supported, (const char *));
|
|
STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
|
|
STATIC_OVL boolean FDECL(wc2_supported, (const char *));
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
|
|
STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
|
|
#endif
|
|
|
|
/* check whether a user-supplied option string is a proper leading
|
|
substring of a particular option name; option string might have
|
|
a colon or equals sign and arbitrary value appended to it */
|
|
boolean
|
|
match_optname(user_string, opt_name, min_length, val_allowed)
|
|
const char *user_string, *opt_name;
|
|
int min_length;
|
|
boolean val_allowed;
|
|
{
|
|
int len = (int)strlen(user_string);
|
|
|
|
if (val_allowed) {
|
|
const char *p = index(user_string, ':'),
|
|
*q = index(user_string, '=');
|
|
|
|
if (!p || (q && q < p)) p = q;
|
|
while(p && p > user_string && isspace(*(p-1))) p--;
|
|
if (p) len = (int)(p - user_string);
|
|
}
|
|
|
|
return (len >= min_length) && !strncmpi(opt_name, user_string, len);
|
|
}
|
|
|
|
/* most environment variables will eventually be printed in an error
|
|
* message if they don't work, and most error message paths go through
|
|
* BUFSZ buffers, which could be overflowed by a maliciously long
|
|
* environment variable. If a variable can legitimately be long, or
|
|
* if it's put in a smaller buffer, the responsible code will have to
|
|
* bounds-check itself.
|
|
*/
|
|
char *
|
|
nh_getenv(ev)
|
|
const char *ev;
|
|
{
|
|
char *getev = getenv(ev);
|
|
|
|
if (getev && strlen(getev) <= (BUFSZ / 2))
|
|
return getev;
|
|
else
|
|
return (char *)0;
|
|
}
|
|
|
|
/* process options, possibly including SYSCF */
|
|
void
|
|
initoptions()
|
|
{
|
|
initoptions_init();
|
|
#ifdef SYSCF
|
|
/* someday there may be other SYSCF alternatives besides text file */
|
|
# ifdef SYSCF_FILE
|
|
read_config_file(SYSCF_FILE, SET_IN_SYS);
|
|
# endif
|
|
#endif
|
|
initoptions_finish();
|
|
}
|
|
|
|
void
|
|
initoptions_init()
|
|
{
|
|
#if defined(UNIX) || defined(VMS)
|
|
char *opts;
|
|
#endif
|
|
int i;
|
|
|
|
/* set up the command parsing */
|
|
reset_commands(TRUE); /* init */
|
|
|
|
/* initialize the random number generator */
|
|
setrandom();
|
|
|
|
/* for detection of configfile options specified multiple times */
|
|
iflags.opt_booldup = iflags.opt_compdup = (int *)0;
|
|
|
|
for (i = 0; boolopt[i].name; i++) {
|
|
if (boolopt[i].addr)
|
|
*(boolopt[i].addr) = boolopt[i].initvalue;
|
|
}
|
|
#if defined(COMPRESS) || defined(ZLIB_COMP)
|
|
set_savepref("externalcomp");
|
|
set_restpref("externalcomp");
|
|
# ifdef RLECOMP
|
|
set_savepref("!rlecomp");
|
|
set_restpref("!rlecomp");
|
|
# endif
|
|
#else
|
|
# ifdef ZEROCOMP
|
|
set_savepref("zerocomp");
|
|
set_restpref("zerocomp");
|
|
# endif
|
|
# ifdef RLECOMP
|
|
set_savepref("rlecomp");
|
|
set_restpref("rlecomp");
|
|
# endif
|
|
#endif
|
|
#ifdef SYSFLAGS
|
|
Strcpy(sysflags.sysflagsid, "sysflags");
|
|
sysflags.sysflagsid[9] = (char)sizeof(struct sysflag);
|
|
#endif
|
|
flags.end_own = FALSE;
|
|
flags.end_top = 3;
|
|
flags.end_around = 2;
|
|
flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */
|
|
flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */
|
|
flags.runmode = RUN_LEAP;
|
|
iflags.msg_history = 20;
|
|
#ifdef TTY_GRAPHICS
|
|
iflags.prevmsg_window = 's';
|
|
# if defined(UNIX) && defined(UNICODE_WIDEWINPORT)
|
|
iflags.unicodecapable = TRUE;
|
|
# endif
|
|
#endif
|
|
iflags.menu_headings = ATR_INVERSE;
|
|
|
|
/* hero's role, race, &c haven't been chosen yet */
|
|
flags.initrole = flags.initrace =
|
|
flags.initgend = flags.initalign = ROLE_NONE;
|
|
|
|
/* Set the default monster and object class symbols. */
|
|
init_symbols();
|
|
for (i = 0; i < WARNCOUNT; i++)
|
|
warnsyms[i] = def_warnsyms[i].sym;
|
|
iflags.bouldersym = 0;
|
|
|
|
iflags.travelcc.x = iflags.travelcc.y = -1;
|
|
|
|
/* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
|
|
(void)memcpy((genericptr_t)flags.inv_order,
|
|
(genericptr_t)def_inv_order, sizeof flags.inv_order);
|
|
flags.pickup_types[0] = '\0';
|
|
flags.pickup_burden = MOD_ENCUMBER;
|
|
|
|
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
|
|
flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
|
|
switch_symbols(FALSE); /* set default characters */
|
|
#if defined(UNIX) && defined(TTY_GRAPHICS)
|
|
/*
|
|
* Set defaults for some options depending on what we can
|
|
* detect about the environment's capabilities.
|
|
* This has to be done after the global initialization above
|
|
* and before reading user-specific initialization via
|
|
* config file/environment variable below.
|
|
*/
|
|
/* this detects the IBM-compatible console on most 386 boxes */
|
|
if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
|
|
#ifdef LOADSYMSETS
|
|
if (!symset[PRIMARY].name) load_symset("IBMGraphics", PRIMARY);
|
|
if (!symset[ROGUESET].name) load_symset("RogueIBM", ROGUESET);
|
|
switch_symbols(TRUE);
|
|
#endif
|
|
# ifdef TEXTCOLOR
|
|
iflags.use_color = TRUE;
|
|
# endif
|
|
}
|
|
#endif /* UNIX && TTY_GRAPHICS */
|
|
#if defined(UNIX) || defined(VMS)
|
|
# ifdef TTY_GRAPHICS
|
|
/* detect whether a "vt" terminal can handle alternate charsets */
|
|
if ((opts = nh_getenv("TERM")) &&
|
|
!strncmpi(opts, "vt", 2) && AS && AE &&
|
|
index(AS, '\016') && index(AE, '\017')) {
|
|
# ifdef LOADSYMSETS
|
|
if (!symset[PRIMARY].name) load_symset("DECGraphics", PRIMARY);
|
|
switch_symbols(TRUE);
|
|
# endif /*LOADSYMSETS*/
|
|
}
|
|
# endif
|
|
#endif /* UNIX || VMS */
|
|
|
|
#ifdef MAC_GRAPHICS_ENV
|
|
if (!symset[PRIMARY].name) load_symset("MACGraphics", PRIMARY);
|
|
switch_symbols(TRUE);
|
|
#endif /* MAC_GRAPHICS_ENV */
|
|
flags.menu_style = MENU_FULL;
|
|
|
|
/* since this is done before init_objects(), do partial init here */
|
|
objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
|
|
nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
|
|
}
|
|
|
|
void
|
|
initoptions_finish()
|
|
{
|
|
#ifndef MAC
|
|
char *opts = getenv("NETHACKOPTIONS");
|
|
if (!opts) opts = getenv("HACKOPTIONS");
|
|
if (opts) {
|
|
if (*opts == '/' || *opts == '\\' || *opts == '@') {
|
|
if (*opts == '@') opts++; /* @filename */
|
|
/* looks like a filename */
|
|
if (strlen(opts) < BUFSZ/2)
|
|
read_config_file(opts, SET_IN_FILE);
|
|
} else {
|
|
read_config_file((char *)0, SET_IN_FILE);
|
|
/* let the total length of options be long;
|
|
* parseoptions() will check each individually
|
|
*/
|
|
parseoptions(opts, TRUE, FALSE);
|
|
}
|
|
} else
|
|
#endif
|
|
read_config_file((char *)0, SET_IN_FILE);
|
|
|
|
(void)fruitadd(pl_fruit);
|
|
/* Remove "slime mold" from list of object names; this will */
|
|
/* prevent it from being wished unless it's actually present */
|
|
/* as a named (or default) fruit. Wishing for "fruit" will */
|
|
/* result in the player's preferred fruit [better than "\033"]. */
|
|
obj_descr[SLIME_MOLD].oc_name = "fruit";
|
|
|
|
return;
|
|
}
|
|
|
|
STATIC_OVL void
|
|
nmcpy(dest, src, maxlen)
|
|
char *dest;
|
|
const char *src;
|
|
int maxlen;
|
|
{
|
|
int count;
|
|
|
|
for(count = 1; count < maxlen; count++) {
|
|
if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
|
|
*dest++ = *src++;
|
|
}
|
|
*dest = 0;
|
|
}
|
|
|
|
/*
|
|
* escapes(): escape expansion for showsyms. C-style escapes understood
|
|
* include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
|
|
* The ^-prefix for control characters is also understood, and \[mM]
|
|
* has the effect of 'meta'-ing the value which follows (so that the
|
|
* alternate character set will be enabled).
|
|
*
|
|
* For 3.4.3 and earlier, input ending with "\M", backslash, or caret
|
|
* prior to terminating '\0' would pull that '\0' into the output and then
|
|
* keep processing past it, potentially overflowing the output buffer.
|
|
* Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
|
|
* output and stop there; trailing \M will fall through to \<other> and
|
|
* yield 'M', then stop. Any \X or \O followed by something other than
|
|
* an appropriate digit will also fall through to \<other> and yield 'X'
|
|
* or 'O', plus stop if the non-digit is end-of-string.
|
|
*/
|
|
STATIC_OVL void
|
|
escapes(cp, tp)
|
|
const char *cp;
|
|
char *tp;
|
|
{
|
|
static NEARDATA const char
|
|
oct[] = "01234567", dec[] = "0123456789",
|
|
hex[] = "00112233445566778899aAbBcCdDeEfF";
|
|
const char *dp;
|
|
int cval, meta, dcount;
|
|
|
|
while (*cp) {
|
|
/* \M has to be followed by something to do meta conversion,
|
|
otherwise it will just be \M which ultimately yields 'M' */
|
|
meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
|
|
if (meta) cp += 2;
|
|
|
|
cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
|
|
if ((*cp != '\\' && *cp != '^') || !cp[1]) {
|
|
/* simple character, or nothing left for \ or ^ to escape */
|
|
cval = *cp++;
|
|
} else if (*cp == '^') { /* expand control-character syntax */
|
|
cval = (*++cp & 0x1f);
|
|
++cp;
|
|
/* remaining cases are all for backslash and we know cp[1] is not \0 */
|
|
} else if (index(dec, cp[1])) {
|
|
++cp; /* move past backslash to first digit */
|
|
do {
|
|
cval = (cval * 10) + (*cp - '0');
|
|
} while (*++cp && index(dec, *cp) && ++dcount < 3);
|
|
} else if ((cp[1] == 'o' || cp[1] == 'O') &&
|
|
cp[2] && index(oct, cp[2])) {
|
|
cp += 2; /* move past backslash and 'O' */
|
|
do {
|
|
cval = (cval * 8) + (*cp - '0');
|
|
} while (*++cp && index(oct, *cp) && ++dcount < 3);
|
|
} else if ((cp[1] == 'x' || cp[1] == 'X') &&
|
|
cp[2] && (dp = index(hex, cp[2])) != 0) {
|
|
cp += 2; /* move past backslash and 'X' */
|
|
do {
|
|
cval = (cval * 16) + ((int)(dp - hex) / 2);
|
|
} while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
|
|
} else { /* C-style character escapes */
|
|
switch (*++cp) {
|
|
case '\\': cval = '\\'; break;
|
|
case 'n': cval = '\n'; break;
|
|
case 't': cval = '\t'; break;
|
|
case 'b': cval = '\b'; break;
|
|
case 'r': cval = '\r'; break;
|
|
default: cval = *cp;
|
|
}
|
|
++cp;
|
|
}
|
|
|
|
if (meta)
|
|
cval |= 0x80;
|
|
*tp++ = (char)cval;
|
|
}
|
|
*tp = '\0';
|
|
}
|
|
|
|
STATIC_OVL void
|
|
rejectoption(optname)
|
|
const char *optname;
|
|
{
|
|
#ifdef MICRO
|
|
pline("\"%s\" settable only from %s.", optname, configfile);
|
|
#else
|
|
pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
|
|
configfile);
|
|
#endif
|
|
}
|
|
|
|
STATIC_OVL void
|
|
badoption(opts)
|
|
const char *opts;
|
|
{
|
|
if (!initial) {
|
|
if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
|
|
option_help();
|
|
else
|
|
pline("Bad syntax: %s. Enter \"?g\" for help.", opts);
|
|
return;
|
|
}
|
|
#ifdef MAC
|
|
else return;
|
|
#endif
|
|
|
|
if(from_file)
|
|
raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
|
|
else
|
|
raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts);
|
|
|
|
wait_synch();
|
|
}
|
|
|
|
STATIC_OVL char *
|
|
string_for_opt(opts, val_optional)
|
|
char *opts;
|
|
boolean val_optional;
|
|
{
|
|
char *colon, *equals;
|
|
|
|
colon = index(opts, ':');
|
|
equals = index(opts, '=');
|
|
if (!colon || (equals && equals < colon)) colon = equals;
|
|
|
|
if (!colon || !*++colon) {
|
|
if (!val_optional) badoption(opts);
|
|
return (char *)0;
|
|
}
|
|
return colon;
|
|
}
|
|
|
|
STATIC_OVL char *
|
|
string_for_env_opt(optname, opts, val_optional)
|
|
const char *optname;
|
|
char *opts;
|
|
boolean val_optional;
|
|
{
|
|
if(!initial) {
|
|
rejectoption(optname);
|
|
return (char *)0;
|
|
}
|
|
return string_for_opt(opts, val_optional);
|
|
}
|
|
|
|
STATIC_OVL void
|
|
bad_negation(optname, with_parameter)
|
|
const char *optname;
|
|
boolean with_parameter;
|
|
{
|
|
pline_The("%s option may not %sbe negated.",
|
|
optname,
|
|
with_parameter ? "both have a value and " : "");
|
|
}
|
|
|
|
/*
|
|
* Change the inventory order, using the given string as the new order.
|
|
* Missing characters in the new order are filled in at the end from
|
|
* the current inv_order, except for gold, which is forced to be first
|
|
* if not explicitly present.
|
|
*
|
|
* This routine returns 1 unless there is a duplicate or bad char in
|
|
* the string.
|
|
*/
|
|
STATIC_OVL int
|
|
change_inv_order(op)
|
|
char *op;
|
|
{
|
|
int oc_sym, num;
|
|
char *sp, buf[BUFSZ];
|
|
|
|
num = 0;
|
|
#ifndef GOLDOBJ
|
|
if (!index(op, GOLD_SYM))
|
|
buf[num++] = COIN_CLASS;
|
|
#else
|
|
/* !!!! probably unnecessary with gold as normal inventory */
|
|
#endif
|
|
|
|
for (sp = op; *sp; sp++) {
|
|
oc_sym = def_char_to_objclass(*sp);
|
|
/* reject bad or duplicate entries */
|
|
if (oc_sym == MAXOCLASSES ||
|
|
oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
|
|
!index(flags.inv_order, oc_sym) || index(sp+1, *sp))
|
|
return 0;
|
|
/* retain good ones */
|
|
buf[num++] = (char) oc_sym;
|
|
}
|
|
buf[num] = '\0';
|
|
|
|
/* fill in any omitted classes, using previous ordering */
|
|
for (sp = flags.inv_order; *sp; sp++)
|
|
if (!index(buf, *sp)) {
|
|
buf[num++] = *sp;
|
|
buf[num] = '\0'; /* explicitly terminate for next index() */
|
|
}
|
|
|
|
Strcpy(flags.inv_order, buf);
|
|
return 1;
|
|
}
|
|
|
|
STATIC_OVL void
|
|
warning_opts(opts, optype)
|
|
register char *opts;
|
|
const char *optype;
|
|
{
|
|
uchar translate[MAXPCHARS+1];
|
|
int length, i;
|
|
|
|
if (!(opts = string_for_env_opt(optype, opts, FALSE)))
|
|
return;
|
|
escapes(opts, opts);
|
|
|
|
length = strlen(opts);
|
|
if (length > WARNCOUNT) length = WARNCOUNT;
|
|
/* match the form obtained from PC configuration files */
|
|
for (i = 0; i < length; i++)
|
|
translate[i] = (((i < WARNCOUNT) && opts[i]) ?
|
|
(uchar) opts[i] : def_warnsyms[i].sym);
|
|
assign_warnings(translate);
|
|
}
|
|
|
|
void
|
|
assign_warnings(graph_chars)
|
|
register uchar *graph_chars;
|
|
{
|
|
int i;
|
|
for (i = 0; i < WARNCOUNT; i++)
|
|
if (graph_chars[i]) warnsyms[i] = graph_chars[i];
|
|
}
|
|
|
|
STATIC_OVL int
|
|
feature_alert_opts(op, optn)
|
|
char *op;
|
|
const char *optn;
|
|
{
|
|
char buf[BUFSZ];
|
|
boolean rejectver = FALSE;
|
|
unsigned long fnv = get_feature_notice_ver(op); /* version.c */
|
|
if (fnv == 0L) return 0;
|
|
if (fnv > get_current_feature_ver())
|
|
rejectver = TRUE;
|
|
else
|
|
flags.suppress_alert = fnv;
|
|
if (rejectver) {
|
|
if (!initial)
|
|
You_cant("disable new feature alerts for future versions.");
|
|
else {
|
|
Sprintf(buf,
|
|
"\n%s=%s Invalid reference to a future version ignored",
|
|
optn, op);
|
|
badoption(buf);
|
|
}
|
|
return 0;
|
|
}
|
|
if (!initial) {
|
|
Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
|
|
FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
|
|
pline("Feature change alerts disabled for NetHack %s features and prior.",
|
|
buf);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
set_duplicate_opt_detection(on_or_off)
|
|
int on_or_off;
|
|
{
|
|
int k, *optptr;
|
|
if (on_or_off != 0) {
|
|
/*-- ON --*/
|
|
if (iflags.opt_booldup)
|
|
impossible("iflags.opt_booldup already on (memory leak)");
|
|
iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
|
|
optptr = iflags.opt_booldup;
|
|
for (k = 0; k < SIZE(boolopt); ++k)
|
|
*optptr++ = 0;
|
|
|
|
if (iflags.opt_compdup)
|
|
impossible("iflags.opt_compdup already on (memory leak)");
|
|
iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
|
|
optptr = iflags.opt_compdup;
|
|
for (k = 0; k < SIZE(compopt); ++k)
|
|
*optptr++ = 0;
|
|
} else {
|
|
/*-- OFF --*/
|
|
if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
|
|
iflags.opt_booldup = (int *)0;
|
|
if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
|
|
iflags.opt_compdup = (int *)0;
|
|
}
|
|
}
|
|
|
|
STATIC_OVL boolean
|
|
duplicate_opt_detection(opts, iscompound)
|
|
const char *opts;
|
|
int iscompound; /* 0 == boolean option, 1 == compound */
|
|
{
|
|
int i, *optptr;
|
|
if (!iscompound && iflags.opt_booldup && initial && from_file) {
|
|
for (i = 0; boolopt[i].name; i++) {
|
|
if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
|
|
optptr = iflags.opt_booldup + i;
|
|
*optptr += 1;
|
|
if (*optptr > 1) return TRUE;
|
|
else return FALSE;
|
|
}
|
|
}
|
|
} else if (iscompound && iflags.opt_compdup && initial && from_file) {
|
|
for (i = 0; compopt[i].name; i++) {
|
|
if (match_optname(opts, compopt[i].name,
|
|
strlen(compopt[i].name), TRUE)) {
|
|
optptr = iflags.opt_compdup + i;
|
|
*optptr += 1;
|
|
if (*optptr > 1) return TRUE;
|
|
else return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
STATIC_OVL void
|
|
complain_about_duplicate(opts, iscompound)
|
|
const char *opts;
|
|
int iscompound; /* 0 == boolean option, 1 == compound */
|
|
{
|
|
#if defined(MAC)
|
|
/* the Mac has trouble dealing with the output of messages while
|
|
* processing the config file. That should get fixed one day.
|
|
* For now just return.
|
|
*/
|
|
return;
|
|
#endif
|
|
|
|
raw_printf(
|
|
"\nWarning - %s option specified multiple times: %s.\n",
|
|
iscompound ? "compound" : "boolean", opts);
|
|
wait_synch();
|
|
return;
|
|
}
|
|
|
|
/* paranoia[] - used by parseoptions() and special_handling() */
|
|
STATIC_VAR const struct paranoia_opts {
|
|
int flagmask; /* which paranoid option */
|
|
const char *argname; /* primary name */
|
|
int argMinLen; /* minimum number of letters to match */
|
|
const char *synonym; /* alternate name (optional) */
|
|
int synMinLen;
|
|
const char *explain; /* for interactive menu */
|
|
} paranoia[] = {
|
|
/* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
|
|
takes precedence and "all" isn't present in the interactive menu,
|
|
and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
|
|
(also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
|
|
is just a synonym for "Confirm") */
|
|
{ PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2,
|
|
"for \"yes\" confirmations, require \"no\" to reject" },
|
|
{ PARANOID_QUIT, "quit", 1, "explore", 1,
|
|
"yes vs y to quit or to enter explore mode" },
|
|
{ PARANOID_DIE, "die", 1, "death", 2,
|
|
#ifdef WIZARD
|
|
"yes vs y to die (explore mode or debug mode)" },
|
|
#else
|
|
"yes vs y to die (explore mode only)" },
|
|
#endif
|
|
{ PARANOID_BONES, "bones", 1, 0, 0,
|
|
#ifdef WIZARD
|
|
"yes vs y to save bones data when dying in debug mode" },
|
|
#else
|
|
"(only applicable for debug mode)" },
|
|
#endif
|
|
{ PARANOID_HIT, "attack", 1, "hit", 1,
|
|
"yes vs y to attack a peaceful monster" },
|
|
{ PARANOID_PRAY, "pray", 1, 0, 0,
|
|
"y to pray (supersedes old \"prayconfirm\" option)" },
|
|
{ PARANOID_REMOVE, "Remove", 1, "Takeoff", 1,
|
|
"always pick from inventory for Remove and Takeoff" },
|
|
/* for config file parsing; interactive menu skips these */
|
|
{ 0, "none", 4, 0, 0, 0 }, /* require full word match */
|
|
{ ~0, "all", 3, 0, 0, 0 }, /* ditto */
|
|
};
|
|
|
|
void
|
|
parseoptions(opts, tinitial, tfrom_file)
|
|
register char *opts;
|
|
boolean tinitial, tfrom_file;
|
|
{
|
|
register char *op;
|
|
unsigned num;
|
|
boolean negated, duplicate;
|
|
int i;
|
|
const char *fullname;
|
|
|
|
initial = tinitial;
|
|
from_file = tfrom_file;
|
|
if ((op = index(opts, ',')) != 0) {
|
|
*op++ = 0;
|
|
parseoptions(op, initial, from_file);
|
|
}
|
|
if (strlen(opts) > BUFSZ/2) {
|
|
badoption("option too long");
|
|
return;
|
|
}
|
|
|
|
/* strip leading and trailing white space */
|
|
while (isspace(*opts)) opts++;
|
|
op = eos(opts);
|
|
while (--op >= opts && isspace(*op)) *op = '\0';
|
|
|
|
if (!*opts) return;
|
|
negated = FALSE;
|
|
while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
|
|
if (*opts == '!') opts++; else opts += 2;
|
|
negated = !negated;
|
|
}
|
|
|
|
/* variant spelling */
|
|
|
|
if (match_optname(opts, "colour", 5, FALSE))
|
|
Strcpy(opts, "color"); /* fortunately this isn't longer */
|
|
|
|
/* special boolean options */
|
|
|
|
if (match_optname(opts, "female", 3, FALSE)) {
|
|
if (duplicate_opt_detection(opts,0))
|
|
complain_about_duplicate(opts,0);
|
|
if(!initial && flags.female == negated)
|
|
pline("That is not anatomically possible.");
|
|
else
|
|
flags.initgend = flags.female = !negated;
|
|
return;
|
|
}
|
|
|
|
if (match_optname(opts, "male", 4, FALSE)) {
|
|
if (duplicate_opt_detection(opts,0))
|
|
complain_about_duplicate(opts,0);
|
|
if(!initial && flags.female != negated)
|
|
pline("That is not anatomically possible.");
|
|
else
|
|
flags.initgend = flags.female = negated;
|
|
return;
|
|
}
|
|
|
|
#if defined(MICRO) && !defined(AMIGA)
|
|
/* included for compatibility with old NetHack.cnf files */
|
|
if (match_optname(opts, "IBM_", 4, FALSE)) {
|
|
iflags.BIOS = !negated;
|
|
return;
|
|
}
|
|
#endif /* MICRO */
|
|
|
|
/* compound options */
|
|
|
|
/* This first batch can be duplicated if their values are negated */
|
|
|
|
/* align:string */
|
|
fullname = "align";
|
|
if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
|
|
boolean val_negated = FALSE;
|
|
while ((*op == '!') || !strncmpi(op, "no", 2)) {
|
|
if (*op == '!') op++; else op += 2;
|
|
val_negated = !val_negated;
|
|
}
|
|
if (val_negated) {
|
|
if (!setrolefilter(op))
|
|
badoption(opts);
|
|
} else {
|
|
if (duplicate_opt_detection(opts,1))
|
|
complain_about_duplicate(opts,1);
|
|
if ((flags.initalign = str2align(op)) == ROLE_NONE)
|
|
badoption(opts);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* role:string or character:string */
|
|
fullname = "role";
|
|
if (match_optname(opts, fullname, 4, TRUE) ||
|
|
match_optname(opts, (fullname = "character"), 4, TRUE)) {
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
|
|
boolean val_negated = FALSE;
|
|
while ((*op == '!') || !strncmpi(op, "no", 2)) {
|
|
if (*op == '!') op++; else op += 2;
|
|
val_negated = !val_negated;
|
|
}
|
|
if (val_negated) {
|
|
if (!setrolefilter(op))
|
|
badoption(opts);
|
|
} else {
|
|
if (duplicate_opt_detection(opts,1))
|
|
complain_about_duplicate(opts,1);
|
|
if ((flags.initrole = str2role(op)) == ROLE_NONE)
|
|
badoption(opts);
|
|
else /* Backwards compatibility */
|
|
nmcpy(pl_character, op, PL_NSIZ);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* race:string */
|
|
fullname = "race";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
|
|
boolean val_negated = FALSE;
|
|
while ((*op == '!') || !strncmpi(op, "no", 2)) {
|
|
if (*op == '!') op++; else op += 2;
|
|
val_negated = !val_negated;
|
|
}
|
|
if (val_negated) {
|
|
if (!setrolefilter(op))
|
|
badoption(opts);
|
|
} else {
|
|
if (duplicate_opt_detection(opts,1))
|
|
complain_about_duplicate(opts,1);
|
|
if ((flags.initrace = str2race(op)) == ROLE_NONE)
|
|
badoption(opts);
|
|
else /* Backwards compatibility */
|
|
pl_race = *op;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* gender:string */
|
|
fullname = "gender";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
|
|
boolean val_negated = FALSE;
|
|
while ((*op == '!') || !strncmpi(op, "no", 2)) {
|
|
if (*op == '!') op++; else op += 2;
|
|
val_negated = !val_negated;
|
|
}
|
|
if (val_negated) {
|
|
if (!setrolefilter(op))
|
|
badoption(opts);
|
|
} else {
|
|
if (duplicate_opt_detection(opts,1))
|
|
complain_about_duplicate(opts,1);
|
|
if ((flags.initgend = str2gend(op)) == ROLE_NONE)
|
|
badoption(opts);
|
|
else
|
|
flags.female = flags.initgend;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* We always check for duplicates on the remaining compound options,
|
|
although individual option processing can choose to complain or not */
|
|
|
|
duplicate = duplicate_opt_detection(opts,1); /* 1 means check compounds */
|
|
|
|
fullname = "pettype";
|
|
if (match_optname(opts, fullname, 3, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
|
|
if (negated) bad_negation(fullname, TRUE);
|
|
else switch (lowc(*op)) {
|
|
case 'd': /* dog */
|
|
preferred_pet = 'd';
|
|
break;
|
|
case 'c': /* cat */
|
|
case 'f': /* feline */
|
|
preferred_pet = 'c';
|
|
break;
|
|
case 'h': /* horse */
|
|
case 'q': /* quadruped */
|
|
/* avoids giving "unrecognized type of pet" but
|
|
pet_type(dog.c) won't actually honor this */
|
|
preferred_pet = 'h';
|
|
break;
|
|
case 'n': /* no pet */
|
|
preferred_pet = 'n';
|
|
break;
|
|
case '*': /* random */
|
|
preferred_pet = '\0';
|
|
break;
|
|
default:
|
|
pline("Unrecognized pet type '%s'.", op);
|
|
break;
|
|
}
|
|
} else if (negated) preferred_pet = 'n';
|
|
return;
|
|
}
|
|
|
|
fullname = "catname";
|
|
if (match_optname(opts, fullname, 3, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
|
|
nmcpy(catname, op, PL_PSIZ);
|
|
return;
|
|
}
|
|
|
|
fullname = "dogname";
|
|
if (match_optname(opts, fullname, 3, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
|
|
nmcpy(dogname, op, PL_PSIZ);
|
|
return;
|
|
}
|
|
|
|
fullname = "horsename";
|
|
if (match_optname(opts, fullname, 5, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
|
|
nmcpy(horsename, op, PL_PSIZ);
|
|
return;
|
|
}
|
|
|
|
fullname = "number_pad";
|
|
if (match_optname(opts, fullname, 10, TRUE)) {
|
|
boolean compat = (strlen(opts) <= 10);
|
|
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, (compat || !initial));
|
|
if (!op) {
|
|
if (compat || negated || initial) {
|
|
/* for backwards compatibility, "number_pad" without a
|
|
value is a synonym for number_pad:1 */
|
|
iflags.num_pad = !negated;
|
|
iflags.num_pad_mode = 0;
|
|
}
|
|
} else if (negated) {
|
|
bad_negation("number_pad", TRUE);
|
|
return;
|
|
} else {
|
|
int mode = atoi(op);
|
|
|
|
if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) {
|
|
badoption(opts);
|
|
return;
|
|
} else if (mode <= 0) {
|
|
iflags.num_pad = FALSE;
|
|
/* German keyboard; y and z keys swapped */
|
|
iflags.num_pad_mode = (mode < 0); /* 0 or 1 */
|
|
} else { /* mode > 0 */
|
|
iflags.num_pad = TRUE;
|
|
iflags.num_pad_mode = 0;
|
|
/* PC Hack / MSDOS compatibility */
|
|
if (mode == 2 || mode == 4) iflags.num_pad_mode |= 1;
|
|
/* phone keypad layout */
|
|
if (mode == 3 || mode == 4) iflags.num_pad_mode |= 2;
|
|
}
|
|
}
|
|
reset_commands(FALSE);
|
|
number_pad(iflags.num_pad ? 1 : 0);
|
|
return;
|
|
}
|
|
|
|
fullname = "roguesymset";
|
|
if (match_optname(opts, fullname, 7, TRUE)) {
|
|
#if defined(REINCARNATION) && defined(LOADSYMSETS)
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_opt(opts, FALSE)) != 0) {
|
|
symset[ROGUESET].name = (char *)alloc(strlen(op) + 1);
|
|
Strcpy(symset[ROGUESET].name, op);
|
|
if (!read_sym_file(ROGUESET)) {
|
|
clear_symsetentry(ROGUESET, TRUE);
|
|
raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
|
|
op, SYMBOLS);
|
|
wait_synch();
|
|
} else {
|
|
if (!initial && Is_rogue_level(&u.uz))
|
|
assign_graphics(ROGUESET);
|
|
need_redraw = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
fullname = "symset";
|
|
if (match_optname(opts, fullname, 6, TRUE)) {
|
|
#ifdef LOADSYMSETS
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_opt(opts, FALSE)) != 0) {
|
|
symset[PRIMARY].name = (char *)alloc(strlen(op) + 1);
|
|
Strcpy(symset[PRIMARY].name, op);
|
|
if (!read_sym_file(PRIMARY)) {
|
|
clear_symsetentry(PRIMARY, TRUE);
|
|
raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
|
|
op, SYMBOLS);
|
|
wait_synch();
|
|
} else {
|
|
switch_symbols(TRUE);
|
|
need_redraw = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
fullname = "runmode";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
flags.runmode = RUN_TPORT;
|
|
} else if ((op = string_for_opt(opts, FALSE)) != 0) {
|
|
if (!strncmpi(op, "teleport", strlen(op)))
|
|
flags.runmode = RUN_TPORT;
|
|
else if (!strncmpi(op, "run", strlen(op)))
|
|
flags.runmode = RUN_LEAP;
|
|
else if (!strncmpi(op, "walk", strlen(op)))
|
|
flags.runmode = RUN_STEP;
|
|
else if (!strncmpi(op, "crawl", strlen(op)))
|
|
flags.runmode = RUN_CRAWL;
|
|
else
|
|
badoption(opts);
|
|
}
|
|
return;
|
|
}
|
|
|
|
fullname = "msghistory";
|
|
if (match_optname(opts, fullname, 3, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_env_opt(fullname, opts, negated);
|
|
if ((negated && !op) || (!negated && op)) {
|
|
iflags.msg_history = negated ? 0 : atoi(op);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
|
|
fullname="msg_window";
|
|
/* msg_window:single, combo, full or reversed */
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
/* allow option to be silently ignored by non-tty ports */
|
|
#ifdef TTY_GRAPHICS
|
|
int tmp;
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (!(op = string_for_opt(opts, TRUE))) {
|
|
tmp = negated ? 's' : 'f';
|
|
} else {
|
|
if (negated) {
|
|
bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
tmp = tolower(*op);
|
|
}
|
|
switch (tmp) {
|
|
case 's': /* single message history cycle (default if negated) */
|
|
iflags.prevmsg_window = 's';
|
|
break;
|
|
case 'c': /* combination: two singles, then full page reversed */
|
|
iflags.prevmsg_window = 'c';
|
|
break;
|
|
case 'f': /* full page (default if no opts) */
|
|
iflags.prevmsg_window = 'f';
|
|
break;
|
|
case 'r': /* full page (reversed) */
|
|
iflags.prevmsg_window = 'r';
|
|
break;
|
|
default:
|
|
badoption(opts);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* WINCAP
|
|
* setting font options */
|
|
fullname = "font";
|
|
if (!strncmpi(opts, fullname, 4)) {
|
|
int opttype = -1;
|
|
char *fontopts = opts + 4;
|
|
|
|
if (!strncmpi(fontopts, "map", 3) ||
|
|
!strncmpi(fontopts, "_map", 4))
|
|
opttype = MAP_OPTION;
|
|
else if (!strncmpi(fontopts, "message", 7) ||
|
|
!strncmpi(fontopts, "_message", 8))
|
|
opttype = MESSAGE_OPTION;
|
|
else if (!strncmpi(fontopts, "text", 4) ||
|
|
!strncmpi(fontopts, "_text", 5))
|
|
opttype = TEXT_OPTION;
|
|
else if (!strncmpi(fontopts, "menu", 4) ||
|
|
!strncmpi(fontopts, "_menu", 5))
|
|
opttype = MENU_OPTION;
|
|
else if (!strncmpi(fontopts, "status", 6) ||
|
|
!strncmpi(fontopts, "_status", 7))
|
|
opttype = STATUS_OPTION;
|
|
else if (!strncmpi(fontopts, "_size", 5)) {
|
|
if (!strncmpi(fontopts, "_size_map", 8))
|
|
opttype = MAP_OPTION;
|
|
else if (!strncmpi(fontopts, "_size_message", 12))
|
|
opttype = MESSAGE_OPTION;
|
|
else if (!strncmpi(fontopts, "_size_text", 9))
|
|
opttype = TEXT_OPTION;
|
|
else if (!strncmpi(fontopts, "_size_menu", 9))
|
|
opttype = MENU_OPTION;
|
|
else if (!strncmpi(fontopts, "_size_status", 11))
|
|
opttype = STATUS_OPTION;
|
|
else {
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (opttype > 0 && !negated &&
|
|
(op = string_for_opt(opts, FALSE)) != 0) {
|
|
switch(opttype) {
|
|
case MAP_OPTION:
|
|
iflags.wc_fontsiz_map = atoi(op);
|
|
break;
|
|
case MESSAGE_OPTION:
|
|
iflags.wc_fontsiz_message = atoi(op);
|
|
break;
|
|
case TEXT_OPTION:
|
|
iflags.wc_fontsiz_text = atoi(op);
|
|
break;
|
|
case MENU_OPTION:
|
|
iflags.wc_fontsiz_menu = atoi(op);
|
|
break;
|
|
case STATUS_OPTION:
|
|
iflags.wc_fontsiz_status = atoi(op);
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
} else {
|
|
badoption(opts);
|
|
}
|
|
if (opttype > 0 &&
|
|
(op = string_for_opt(opts, FALSE)) != 0) {
|
|
wc_set_font_name(opttype, op);
|
|
#ifdef MAC
|
|
set_font_name (opttype, op);
|
|
#endif
|
|
return;
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
#ifdef CHANGE_COLOR
|
|
if (match_optname(opts, "palette", 3, TRUE)
|
|
# ifdef MAC
|
|
|| match_optname(opts, "hicolor", 3, TRUE)
|
|
# endif
|
|
) {
|
|
int color_number, color_incr;
|
|
|
|
# ifndef WIN32CON
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
# endif
|
|
# ifdef MAC
|
|
if (match_optname(opts, "hicolor", 3, TRUE)) {
|
|
if (negated) {
|
|
bad_negation("hicolor", FALSE);
|
|
return;
|
|
}
|
|
color_number = CLR_MAX + 4; /* HARDCODED inverse number */
|
|
color_incr = -1;
|
|
} else {
|
|
# endif
|
|
if (negated) {
|
|
bad_negation("palette", FALSE);
|
|
return;
|
|
}
|
|
color_number = 0;
|
|
color_incr = 1;
|
|
# ifdef MAC
|
|
}
|
|
# endif
|
|
#ifdef WIN32CON
|
|
op = string_for_opt(opts, TRUE);
|
|
if (!alternative_palette(op))
|
|
badoption(opts);
|
|
#else
|
|
if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
|
|
char *pt = op;
|
|
int cnt, tmp, reverse;
|
|
long rgb;
|
|
|
|
while (*pt && color_number >= 0) {
|
|
cnt = 3;
|
|
rgb = 0L;
|
|
if (*pt == '-') {
|
|
reverse = 1;
|
|
pt++;
|
|
} else {
|
|
reverse = 0;
|
|
}
|
|
while (cnt-- > 0) {
|
|
if (*pt && *pt != '/') {
|
|
# ifdef AMIGA
|
|
rgb <<= 4;
|
|
# else
|
|
rgb <<= 8;
|
|
# endif
|
|
tmp = *(pt++);
|
|
if (isalpha(tmp)) {
|
|
tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
|
|
} else {
|
|
tmp &= 0xf; /* Digits in ASCII too... */
|
|
}
|
|
# ifndef AMIGA
|
|
/* Add an extra so we fill f -> ff and 0 -> 00 */
|
|
rgb += tmp << 4;
|
|
# endif
|
|
rgb += tmp;
|
|
}
|
|
}
|
|
if (*pt == '/') {
|
|
pt++;
|
|
}
|
|
change_color(color_number, rgb, reverse);
|
|
color_number += color_incr;
|
|
}
|
|
}
|
|
# endif /* !WIN32CON */
|
|
if (!initial) {
|
|
need_redraw = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
#endif /* CHANGE_COLOR */
|
|
|
|
if (match_optname(opts, "fruit", 2, TRUE)) {
|
|
char empty_str = '\0';
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if (negated) {
|
|
if (op) {
|
|
bad_negation("fruit", TRUE);
|
|
return;
|
|
}
|
|
op = &empty_str;
|
|
goto goodfruit;
|
|
}
|
|
if (!op) return;
|
|
if (!initial) {
|
|
struct fruit *f;
|
|
|
|
num = 0;
|
|
for(f=ffruit; f; f=f->nextf) {
|
|
if (!strcmp(op, f->fname)) goto goodfruit;
|
|
num++;
|
|
}
|
|
if (num >= 100) {
|
|
pline("Doing that so many times isn't very fruitful.");
|
|
return;
|
|
}
|
|
}
|
|
goodfruit:
|
|
nmcpy(pl_fruit, op, PL_FSIZ);
|
|
/* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
|
|
if (!*pl_fruit)
|
|
nmcpy(pl_fruit, "slime mold", PL_FSIZ);
|
|
if (!initial) {
|
|
(void)fruitadd(pl_fruit);
|
|
pline("Fruit is now \"%s\".", pl_fruit);
|
|
}
|
|
/* If initial, then initoptions is allowed to do it instead
|
|
* of here (initoptions always has to do it even if there's
|
|
* no fruit option at all. Also, we don't want people
|
|
* setting multiple fruits in their options.)
|
|
*/
|
|
return;
|
|
}
|
|
|
|
fullname = "warnings";
|
|
if (match_optname(opts, fullname, 5, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else warning_opts(opts, fullname);
|
|
return;
|
|
}
|
|
|
|
#ifdef BACKWARD_COMPAT
|
|
/* boulder:symbol */
|
|
fullname = "boulder";
|
|
if (match_optname(opts, fullname, 7, TRUE)) {
|
|
int clash = 0;
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
}
|
|
/* if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
|
|
if (!(opts = string_for_opt(opts, FALSE)))
|
|
return;
|
|
escapes(opts, opts);
|
|
if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
|
|
clash = 1;
|
|
else if (opts[0] >= '1' && opts[0] <= '5')
|
|
clash = 2;
|
|
if (clash) {
|
|
/* symbol chosen matches a used monster or warning
|
|
symbol which is not good - reject it*/
|
|
pline(
|
|
"Badoption - boulder symbol '%c' conflicts with a %s symbol.",
|
|
opts[0], (clash == 1) ? "monster" : "warning");
|
|
} else {
|
|
/*
|
|
* Override the default boulder symbol.
|
|
*/
|
|
iflags.bouldersym = (uchar) opts[0];
|
|
}
|
|
if (!initial) need_redraw = TRUE;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* name:string */
|
|
fullname = "name";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
|
|
nmcpy(plname, op, PL_NSIZ);
|
|
return;
|
|
}
|
|
|
|
/* altkeyhandler:string */
|
|
fullname = "altkeyhandler";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_opt(opts, negated))) {
|
|
#ifdef WIN32CON
|
|
(void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
|
|
load_keyboard_handler();
|
|
#endif
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* WINCAP
|
|
* align_status:[left|top|right|bottom] */
|
|
fullname = "align_status";
|
|
if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
|
|
op = string_for_opt(opts, negated);
|
|
if (op && !negated) {
|
|
if (!strncmpi (op, "left", sizeof("left")-1))
|
|
iflags.wc_align_status = ALIGN_LEFT;
|
|
else if (!strncmpi (op, "top", sizeof("top")-1))
|
|
iflags.wc_align_status = ALIGN_TOP;
|
|
else if (!strncmpi (op, "right", sizeof("right")-1))
|
|
iflags.wc_align_status = ALIGN_RIGHT;
|
|
else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
|
|
iflags.wc_align_status = ALIGN_BOTTOM;
|
|
else
|
|
badoption(opts);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* align_message:[left|top|right|bottom] */
|
|
fullname = "align_message";
|
|
if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if (op && !negated) {
|
|
if (!strncmpi (op, "left", sizeof("left")-1))
|
|
iflags.wc_align_message = ALIGN_LEFT;
|
|
else if (!strncmpi (op, "top", sizeof("top")-1))
|
|
iflags.wc_align_message = ALIGN_TOP;
|
|
else if (!strncmpi (op, "right", sizeof("right")-1))
|
|
iflags.wc_align_message = ALIGN_RIGHT;
|
|
else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
|
|
iflags.wc_align_message = ALIGN_BOTTOM;
|
|
else
|
|
badoption(opts);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
/* the order to list the pack */
|
|
fullname = "packorder";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
} else if (!(op = string_for_opt(opts, FALSE))) return;
|
|
|
|
if (!change_inv_order(op))
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
|
|
/* user can change required response for some prompts (quit, die, hit),
|
|
or add an extra prompt (pray, Remove) that isn't ordinarily there */
|
|
fullname = "paranoid_confirmation";
|
|
if (match_optname(opts, fullname, 8, TRUE)) {
|
|
/* at present we don't complain about duplicates for this
|
|
option, but we do throw away the old settings whenever
|
|
we process a new one [clearing old flags is essential
|
|
for handling default paranoid_confirm:pray sanely] */
|
|
flags.paranoia_bits = 0; /* clear all */
|
|
if (negated) {
|
|
flags.paranoia_bits = 0; /* [now redundant...] */
|
|
} else if ((op = string_for_opt(opts, TRUE)) != 0) {
|
|
char *pp, buf[BUFSZ];
|
|
|
|
op = mungspaces(strcpy(buf, op));
|
|
for (;;) {
|
|
/* We're looking to parse
|
|
"paranoid_confirm:whichone wheretwo whothree"
|
|
and "paranoid_confirm:" prefix has already
|
|
been stripped off by the time we get here */
|
|
pp = index(op, ' ');
|
|
if (pp) *pp = '\0';
|
|
/* we aren't matching option names but match_optname
|
|
does what we want once we've broken the space
|
|
delimited aggregate into separate tokens */
|
|
for (i = 0; i < SIZE(paranoia); ++i) {
|
|
if (match_optname(op, paranoia[i].argname,
|
|
paranoia[i].argMinLen, FALSE) ||
|
|
(paranoia[i].synonym &&
|
|
match_optname(op, paranoia[i].synonym,
|
|
paranoia[i].synMinLen, FALSE))) {
|
|
if (paranoia[i].flagmask)
|
|
flags.paranoia_bits |= paranoia[i].flagmask;
|
|
else /* 0 == "none", so clear all */
|
|
flags.paranoia_bits = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (i == SIZE(paranoia)) {
|
|
/* didn't match anything, so arg is bad;
|
|
any flags already set will stay set */
|
|
badoption(opts);
|
|
break;
|
|
}
|
|
/* move on to next token */
|
|
if (pp) op = pp + 1;
|
|
else break; /* no next token */
|
|
} /* for(;;) */
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* accept deprecated boolean; superseded by paranoid_confirm:pray */
|
|
fullname = "prayconfirm";
|
|
if (match_optname(opts, fullname, 4, FALSE)) {
|
|
if (negated)
|
|
flags.paranoia_bits &= ~PARANOID_PRAY;
|
|
else
|
|
flags.paranoia_bits |= PARANOID_PRAY;
|
|
return;
|
|
}
|
|
|
|
/* maximum burden picked up before prompt (Warren Cheung) */
|
|
fullname = "pickup_burden";
|
|
if (match_optname(opts, fullname, 8, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
|
|
switch (tolower(*op)) {
|
|
/* Unencumbered */
|
|
case 'u':
|
|
flags.pickup_burden = UNENCUMBERED;
|
|
break;
|
|
/* Burdened (slight encumbrance) */
|
|
case 'b':
|
|
flags.pickup_burden = SLT_ENCUMBER;
|
|
break;
|
|
/* streSsed (moderate encumbrance) */
|
|
case 's':
|
|
flags.pickup_burden = MOD_ENCUMBER;
|
|
break;
|
|
/* straiNed (heavy encumbrance) */
|
|
case 'n':
|
|
flags.pickup_burden = HVY_ENCUMBER;
|
|
break;
|
|
/* OverTaxed (extreme encumbrance) */
|
|
case 'o':
|
|
case 't':
|
|
flags.pickup_burden = EXT_ENCUMBER;
|
|
break;
|
|
/* overLoaded */
|
|
case 'l':
|
|
flags.pickup_burden = OVERLOADED;
|
|
break;
|
|
default:
|
|
badoption(opts);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* types of objects to pick up automatically */
|
|
if (match_optname(opts, "pickup_types", 8, TRUE)) {
|
|
char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
|
|
qbuf[QBUFSZ], abuf[BUFSZ];
|
|
int oc_sym;
|
|
boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
|
|
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
oc_to_str(flags.pickup_types, tbuf);
|
|
flags.pickup_types[0] = '\0'; /* all */
|
|
op = string_for_opt(opts, (compat || !initial));
|
|
if (!op) {
|
|
if (compat || negated || initial) {
|
|
/* for backwards compatibility, "pickup" without a
|
|
value is a synonym for autopickup of all types
|
|
(and during initialization, we can't prompt yet) */
|
|
flags.pickup = !negated;
|
|
return;
|
|
}
|
|
oc_to_str(flags.inv_order, ocl);
|
|
use_menu = TRUE;
|
|
if (flags.menu_style == MENU_TRADITIONAL ||
|
|
flags.menu_style == MENU_COMBINATION) {
|
|
use_menu = FALSE;
|
|
Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
|
|
ocl, *tbuf ? tbuf : "all");
|
|
getlin(qbuf, abuf);
|
|
op = mungspaces(abuf);
|
|
if (abuf[0] == '\0' || abuf[0] == '\033')
|
|
op = tbuf; /* restore */
|
|
else if (abuf[0] == 'm')
|
|
use_menu = TRUE;
|
|
}
|
|
if (use_menu) {
|
|
(void) choose_classes_menu("Auto-Pickup what?", 1,
|
|
TRUE, ocl, tbuf);
|
|
op = tbuf;
|
|
}
|
|
}
|
|
if (negated) {
|
|
bad_negation("pickup_types", TRUE);
|
|
return;
|
|
}
|
|
while (*op == ' ') op++;
|
|
if (*op != 'a' && *op != 'A') {
|
|
num = 0;
|
|
while (*op) {
|
|
oc_sym = def_char_to_objclass(*op);
|
|
/* make sure all are valid obj symbols occuring once */
|
|
if (oc_sym != MAXOCLASSES &&
|
|
!index(flags.pickup_types, oc_sym)) {
|
|
flags.pickup_types[num] = (char)oc_sym;
|
|
flags.pickup_types[++num] = '\0';
|
|
} else
|
|
badopt = TRUE;
|
|
op++;
|
|
}
|
|
if (badopt) badoption(opts);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* pile limit: when walking over objects, number which triggers
|
|
"there are several/many objects here" instead of listing them */
|
|
fullname = "pile_limit";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts, 1);
|
|
op = string_for_opt(opts, negated);
|
|
if ((negated && !op) || (!negated && op))
|
|
flags.pile_limit = negated ? 0 : atoi(op);
|
|
else if (negated)
|
|
bad_negation(fullname, TRUE);
|
|
else /* !op */
|
|
flags.pile_limit = PILE_LIMIT_DFLT;
|
|
/* sanity check */
|
|
if (flags.pile_limit < 0) flags.pile_limit = PILE_LIMIT_DFLT;
|
|
return;
|
|
}
|
|
|
|
/* play mode: normal, explore/discovery, or debug/wizard */
|
|
fullname = "playmode";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts, 1);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
if (duplicate || negated) return;
|
|
op = string_for_opt(opts, TRUE);
|
|
if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
|
|
wizard = discover = FALSE;
|
|
} else if (!strncmpi(op, "explore", 6) ||
|
|
!strncmpi(op, "discovery", 6)) {
|
|
wizard = FALSE, discover = TRUE;
|
|
} else if (!strncmpi(op, "debug", 5) ||
|
|
!strncmpi(op, "wizard", 6)) {
|
|
#ifdef WIZARD
|
|
wizard = TRUE, discover = FALSE;
|
|
#else
|
|
raw_printf("\"%s\":%s -- debug mode not available.",
|
|
fullname, op);
|
|
#endif
|
|
} else {
|
|
raw_printf("Invalid value for \"%s\":%s.", fullname, op);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* WINCAP
|
|
* player_selection: dialog | prompts */
|
|
fullname = "player_selection";
|
|
if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if (op && !negated) {
|
|
if (!strncmpi(op, "dialog", sizeof("dialog")-1))
|
|
iflags.wc_player_selection = VIA_DIALOG;
|
|
else if (!strncmpi(op, "prompt", sizeof("prompt")-1))
|
|
iflags.wc_player_selection = VIA_PROMPTS;
|
|
else
|
|
badoption(opts);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
|
|
/* things to disclose at end of game */
|
|
if (match_optname(opts, "disclose", 7, TRUE)) {
|
|
/*
|
|
* The order that the end_disclore options are stored:
|
|
* inventory, attribs, vanquished, genocided, conduct
|
|
* There is an array in flags:
|
|
* end_disclose[NUM_DISCLOSURE_OPT];
|
|
* with option settings for the each of the following:
|
|
* iagvc [see disclosure_options in decl.c]:
|
|
* Legal setting values in that array are:
|
|
* DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
|
|
* DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
|
|
* DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
|
|
* DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
|
|
*
|
|
* Those setting values can be used in the option
|
|
* string as a prefix to get the desired behaviour.
|
|
*
|
|
* For backward compatibility, no prefix is required,
|
|
* and the presence of a i,a,g,v, or c without a prefix
|
|
* sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
|
|
*/
|
|
boolean badopt = FALSE;
|
|
int idx, prefix_val;
|
|
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, TRUE);
|
|
if (op && negated) {
|
|
bad_negation("disclose", TRUE);
|
|
return;
|
|
}
|
|
/* "disclose" without a value means "all with prompting"
|
|
and negated means "none without prompting" */
|
|
if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
|
|
if (op && !strcmpi(op, "none")) negated = TRUE;
|
|
for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
|
|
flags.end_disclose[num] = negated ?
|
|
DISCLOSE_NO_WITHOUT_PROMPT :
|
|
DISCLOSE_PROMPT_DEFAULT_YES;
|
|
return;
|
|
}
|
|
|
|
num = 0;
|
|
prefix_val = -1;
|
|
while (*op && num < sizeof flags.end_disclose - 1) {
|
|
register char c, *dop;
|
|
static char valid_settings[] = {
|
|
DISCLOSE_PROMPT_DEFAULT_YES,
|
|
DISCLOSE_PROMPT_DEFAULT_NO,
|
|
DISCLOSE_YES_WITHOUT_PROMPT,
|
|
DISCLOSE_NO_WITHOUT_PROMPT,
|
|
'\0'
|
|
};
|
|
c = lowc(*op);
|
|
if (c == 'k') c = 'v'; /* killed -> vanquished */
|
|
dop = index(disclosure_options, c);
|
|
if (dop) {
|
|
idx = (int)(dop - disclosure_options);
|
|
if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
|
|
impossible("bad disclosure index %d %c",
|
|
idx, c);
|
|
continue;
|
|
}
|
|
if (prefix_val != -1) {
|
|
flags.end_disclose[idx] = prefix_val;
|
|
prefix_val = -1;
|
|
} else
|
|
flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
|
|
} else if (index(valid_settings, c)) {
|
|
prefix_val = c;
|
|
} else if (c == ' ') {
|
|
; /* do nothing */
|
|
} else
|
|
badopt = TRUE;
|
|
op++;
|
|
}
|
|
if (badopt) badoption(opts);
|
|
return;
|
|
}
|
|
|
|
/* scores:5t[op] 5a[round] o[wn] */
|
|
if (match_optname(opts, "scores", 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation("scores", FALSE);
|
|
return;
|
|
}
|
|
if (!(op = string_for_opt(opts, FALSE))) return;
|
|
|
|
while (*op) {
|
|
int inum = 1;
|
|
|
|
if (digit(*op)) {
|
|
inum = atoi(op);
|
|
while (digit(*op)) op++;
|
|
} else if (*op == '!') {
|
|
negated = !negated;
|
|
op++;
|
|
}
|
|
while (*op == ' ') op++;
|
|
|
|
switch (*op) {
|
|
case 't':
|
|
case 'T': flags.end_top = inum;
|
|
break;
|
|
case 'a':
|
|
case 'A': flags.end_around = inum;
|
|
break;
|
|
case 'o':
|
|
case 'O': flags.end_own = !negated;
|
|
break;
|
|
default: badoption(opts);
|
|
return;
|
|
}
|
|
while (letter(*++op) || *op == ' ') continue;
|
|
if (*op == '/') op++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
fullname = "suppress_alert";
|
|
if (match_optname(opts, fullname, 4, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else if (op) (void) feature_alert_opts(op,fullname);
|
|
return;
|
|
}
|
|
|
|
#ifdef VIDEOSHADES
|
|
/* videocolors:string */
|
|
fullname = "videocolors";
|
|
if (match_optname(opts, fullname, 6, TRUE) ||
|
|
match_optname(opts, "videocolours", 10, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
}
|
|
else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
|
|
return;
|
|
}
|
|
if (!assign_videocolors(opts))
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
/* videoshades:string */
|
|
fullname = "videoshades";
|
|
if (match_optname(opts, fullname, 6, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
}
|
|
else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
|
|
return;
|
|
}
|
|
if (!assign_videoshades(opts))
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
#endif /* VIDEOSHADES */
|
|
#ifdef MSDOS
|
|
# ifdef NO_TERMS
|
|
/* video:string -- must be after longer tests */
|
|
fullname = "video";
|
|
if (match_optname(opts, fullname, 5, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
}
|
|
else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
|
|
return;
|
|
}
|
|
if (!assign_video(opts))
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
# endif /* NO_TERMS */
|
|
/* soundcard:string -- careful not to match boolean 'sound' */
|
|
fullname = "soundcard";
|
|
if (match_optname(opts, fullname, 6, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
}
|
|
else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
|
|
return;
|
|
}
|
|
if (!assign_soundcard(opts))
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
#endif /* MSDOS */
|
|
|
|
/* WINCAP
|
|
* map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
|
|
ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
|
|
fullname = "map_mode";
|
|
if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if (op && !negated) {
|
|
if (!strncmpi (op, "tiles", sizeof("tiles")-1))
|
|
iflags.wc_map_mode = MAP_MODE_TILES;
|
|
else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII4x6;
|
|
else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII6x8;
|
|
else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII8x8;
|
|
else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII16x8;
|
|
else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII7x12;
|
|
else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII8x12;
|
|
else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII16x12;
|
|
else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII12x16;
|
|
else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII10x18;
|
|
else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
|
|
iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
|
|
else
|
|
badoption(opts);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* scroll_amount:nn */
|
|
fullname = "scroll_amount";
|
|
if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if ((negated && !op) || (!negated && op)) {
|
|
iflags.wc_scroll_amount = negated ? 1 : atoi(op);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* scroll_margin:nn */
|
|
fullname = "scroll_margin";
|
|
if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if ((negated && !op) || (!negated && op)) {
|
|
iflags.wc_scroll_margin = negated ? 5 : atoi(op);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
fullname = "subkeyvalue";
|
|
if (match_optname(opts, fullname, 5, TRUE)) {
|
|
/* no duplicate complaint here */
|
|
if (negated) bad_negation(fullname, FALSE);
|
|
else {
|
|
#if defined(WIN32CON)
|
|
op = string_for_opt(opts, 0);
|
|
map_subkeyvalue(op);
|
|
#endif
|
|
}
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* tile_width:nn */
|
|
fullname = "tile_width";
|
|
if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if ((negated && !op) || (!negated && op)) {
|
|
iflags.wc_tile_width = negated ? 0 : atoi(op);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* tile_file:name */
|
|
fullname = "tile_file";
|
|
if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if ((op = string_for_opt(opts, FALSE)) != 0) {
|
|
if (iflags.wc_tile_file) free(iflags.wc_tile_file);
|
|
iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
|
|
Strcpy(iflags.wc_tile_file, op);
|
|
}
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* tile_height:nn */
|
|
fullname = "tile_height";
|
|
if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if ((negated && !op) || (!negated && op)) {
|
|
iflags.wc_tile_height = negated ? 0 : atoi(op);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
/* WINCAP
|
|
* vary_msgcount:nn */
|
|
fullname = "vary_msgcount";
|
|
if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, negated);
|
|
if ((negated && !op) || (!negated && op)) {
|
|
iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
fullname = "windowtype";
|
|
if (match_optname(opts, fullname, 3, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
|
|
char buf[WINTYPELEN];
|
|
nmcpy(buf, op, WINTYPELEN);
|
|
choose_windows(buf);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* WINCAP
|
|
* setting window colors
|
|
* syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
|
|
*/
|
|
fullname = "windowcolors";
|
|
if (match_optname(opts, fullname, 7, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if ((op = string_for_opt(opts, FALSE)) != 0) {
|
|
if (!wc_set_window_colors(op))
|
|
badoption(opts);
|
|
} else if (negated) bad_negation(fullname, TRUE);
|
|
return;
|
|
}
|
|
|
|
/* menustyle:traditional or combo or full or partial */
|
|
if (match_optname(opts, "menustyle", 4, TRUE)) {
|
|
int tmp;
|
|
boolean val_required = (strlen(opts) > 5 && !negated);
|
|
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (!(op = string_for_opt(opts, !val_required))) {
|
|
if (val_required) return; /* string_for_opt gave feedback */
|
|
tmp = negated ? 'n' : 'f';
|
|
} else {
|
|
tmp = tolower(*op);
|
|
}
|
|
switch (tmp) {
|
|
case 'n': /* none */
|
|
case 't': /* traditional */
|
|
flags.menu_style = MENU_TRADITIONAL;
|
|
break;
|
|
case 'c': /* combo: trad.class sel+menu */
|
|
flags.menu_style = MENU_COMBINATION;
|
|
break;
|
|
case 'p': /* partial: no class menu */
|
|
flags.menu_style = MENU_PARTIAL;
|
|
break;
|
|
case 'f': /* full: class menu + menu */
|
|
flags.menu_style = MENU_FULL;
|
|
break;
|
|
default:
|
|
badoption(opts);
|
|
}
|
|
return;
|
|
}
|
|
|
|
fullname = "menu_headings";
|
|
if (match_optname(opts, fullname, 12, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (negated) {
|
|
bad_negation(fullname, FALSE);
|
|
return;
|
|
}
|
|
else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
|
|
return;
|
|
}
|
|
if (!strcmpi(opts,"bold"))
|
|
iflags.menu_headings = ATR_BOLD;
|
|
else if (!strcmpi(opts,"inverse"))
|
|
iflags.menu_headings = ATR_INVERSE;
|
|
else if (!strcmpi(opts,"underline"))
|
|
iflags.menu_headings = ATR_ULINE;
|
|
else
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
|
|
/* check for menu command mapping */
|
|
for (i = 0; i < NUM_MENU_CMDS; i++) {
|
|
fullname = default_menu_cmd_info[i].name;
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
|
|
if (negated)
|
|
bad_negation(fullname, FALSE);
|
|
else if ((op = string_for_opt(opts, FALSE)) != 0) {
|
|
int j;
|
|
char c, op_buf[BUFSZ];
|
|
boolean isbad = FALSE;
|
|
|
|
escapes(op, op_buf);
|
|
c = *op_buf;
|
|
|
|
if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
|
|
c == ' ' || digit(c) || (letter(c) && c != '@'))
|
|
isbad = TRUE;
|
|
else /* reject default object class symbols */
|
|
for (j = 1; j < MAXOCLASSES; j++)
|
|
if (c == def_oc_syms[i].sym) {
|
|
isbad = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (isbad)
|
|
badoption(opts);
|
|
else
|
|
add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
#if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
|
|
/* hilite fields in status prompt */
|
|
if (match_optname(opts, "hilite_status", 13, TRUE)) {
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
op = string_for_opt(opts, TRUE);
|
|
if (op && negated) {
|
|
clear_status_hilites();
|
|
return;
|
|
} else if (!op) {
|
|
/* a value is mandatory */
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
if (!set_status_hilites(op))
|
|
badoption(opts);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined(BACKWARD_COMPAT)
|
|
fullname = "DECgraphics";
|
|
if (match_optname(opts, fullname, 10, TRUE)) {
|
|
boolean badflag = FALSE;
|
|
# ifdef LOADSYMSETS
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (!negated) {
|
|
/* There is no rogue level DECgraphics-specific set */
|
|
if (symset[PRIMARY].name)
|
|
badflag = TRUE;
|
|
else {
|
|
symset[PRIMARY].name = (char *)alloc(strlen(fullname) + 1);
|
|
Strcpy(symset[PRIMARY].name, fullname);
|
|
if (!read_sym_file(PRIMARY)) {
|
|
badflag = TRUE;
|
|
clear_symsetentry(PRIMARY, TRUE);
|
|
} else switch_symbols(TRUE);
|
|
}
|
|
if (badflag) {
|
|
pline("Failure to load symbol set %s.",
|
|
fullname);
|
|
wait_synch();
|
|
}
|
|
}
|
|
# endif /*LOADSYMSETS*/
|
|
return;
|
|
}
|
|
fullname = "IBMgraphics";
|
|
if (match_optname(opts, fullname, 10, TRUE)) {
|
|
const char *sym_name = fullname;
|
|
boolean badflag = FALSE;
|
|
# ifdef LOADSYMSETS
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (!negated) {
|
|
for (i = PRIMARY; i <= ROGUESET; ++i) {
|
|
if (symset[i].name)
|
|
badflag = TRUE;
|
|
else {
|
|
if (i == ROGUESET) sym_name = "RogueIBM";
|
|
symset[i].name = (char *)alloc(strlen(sym_name) + 1);
|
|
Strcpy(symset[i].name, sym_name);
|
|
if (!read_sym_file(i)) {
|
|
badflag = TRUE;
|
|
clear_symsetentry(i, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (badflag) {
|
|
pline("Failure to load symbol set %s.",
|
|
sym_name);
|
|
wait_synch();
|
|
} else {
|
|
switch_symbols(TRUE);
|
|
# ifdef REINCARNATION
|
|
if (!initial && Is_rogue_level(&u.uz))
|
|
assign_graphics(ROGUESET);
|
|
# endif
|
|
}
|
|
}
|
|
# endif /*LOADSYMSETS*/
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef MAC_GRAPHICS_ENV
|
|
fullname = "MACgraphics";
|
|
if (match_optname(opts, fullname, 11, TRUE)) {
|
|
boolean badflag = FALSE;
|
|
# ifdef LOADSYMSETS
|
|
if (duplicate) complain_about_duplicate(opts,1);
|
|
if (!negated) {
|
|
if (symset[PRIMARY]).name badflag = TRUE;
|
|
else {
|
|
symset[PRIMARY].name = (char *)alloc(strlen(fullname) + 1);
|
|
Strcpy(symset[PRIMARY].name, fullname);
|
|
if (!read_sym_file(PRIMARY)) {
|
|
badflag = TRUE;
|
|
clear_symsetentry(PRIMARY, TRUE);
|
|
}
|
|
}
|
|
if (badflag) {
|
|
pline("Failure to load symbol set %s.",
|
|
fullname);
|
|
wait_synch();
|
|
} else {
|
|
switch_symbols(TRUE);
|
|
if (!initial && Is_rogue_level(&u.uz))
|
|
assign_graphics(ROGUESET);
|
|
}
|
|
}
|
|
# endif /*LOADSYMSETS*/
|
|
return;
|
|
}
|
|
#endif
|
|
/* OK, if we still haven't recognized the option, check the boolean
|
|
* options list
|
|
*/
|
|
for (i = 0; boolopt[i].name; i++) {
|
|
if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
|
|
|
|
/* options that don't exist */
|
|
if (!boolopt[i].addr) {
|
|
if (!initial && !negated)
|
|
pline_The("\"%s\" option is not available.",
|
|
boolopt[i].name);
|
|
return;
|
|
}
|
|
/* options that must come from config file */
|
|
if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
|
|
rejectoption(boolopt[i].name);
|
|
return;
|
|
}
|
|
|
|
*(boolopt[i].addr) = !negated;
|
|
|
|
/* 0 means boolean opts */
|
|
if (duplicate_opt_detection(boolopt[i].name, 0))
|
|
complain_about_duplicate(boolopt[i].name,0);
|
|
|
|
#ifdef RLECOMP
|
|
if ((boolopt[i].addr) == &iflags.rlecomp) {
|
|
if (*boolopt[i].addr)
|
|
set_savepref("rlecomp");
|
|
else
|
|
set_savepref("!rlecomp");
|
|
}
|
|
#endif
|
|
#ifdef ZEROCOMP
|
|
if ((boolopt[i].addr) == &iflags.zerocomp) {
|
|
if (*boolopt[i].addr)
|
|
set_savepref("zerocomp");
|
|
else
|
|
set_savepref("externalcomp");
|
|
}
|
|
#endif
|
|
/* only do processing below if setting with doset() */
|
|
if (initial) return;
|
|
|
|
if ((boolopt[i].addr) == &flags.time
|
|
#ifdef EXP_ON_BOTL
|
|
|| (boolopt[i].addr) == &flags.showexp
|
|
#endif
|
|
#ifdef SCORE_ON_BOTL
|
|
|| (boolopt[i].addr) == &flags.showscore
|
|
#endif
|
|
) {
|
|
#ifdef STATUS_VIA_WINDOWPORT
|
|
status_initialize(REASSESS_ONLY);
|
|
#endif
|
|
context.botl = TRUE;
|
|
}
|
|
else if ((boolopt[i].addr) == &flags.invlet_constant) {
|
|
if (flags.invlet_constant) reassign();
|
|
}
|
|
else if ((boolopt[i].addr) == &flags.lit_corridor) {
|
|
/*
|
|
* All corridor squares seen via night vision or
|
|
* candles & lamps change. Update them by calling
|
|
* newsym() on them. Don't do this if we are
|
|
* initializing the options --- the vision system
|
|
* isn't set up yet.
|
|
*/
|
|
vision_recalc(2); /* shut down vision */
|
|
vision_full_recalc = 1; /* delayed recalc */
|
|
}
|
|
else if ((boolopt[i].addr) == &iflags.use_inverse ||
|
|
(boolopt[i].addr) == &flags.showrace ||
|
|
(boolopt[i].addr) == &iflags.hilite_pet) {
|
|
need_redraw = TRUE;
|
|
}
|
|
#ifdef TEXTCOLOR
|
|
else if ((boolopt[i].addr) == &iflags.use_color) {
|
|
need_redraw = TRUE;
|
|
# ifdef TOS
|
|
if ((boolopt[i].addr) == &iflags.use_color
|
|
&& iflags.BIOS) {
|
|
if (colors_changed)
|
|
restore_colors();
|
|
else
|
|
set_colors();
|
|
}
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* out of valid options */
|
|
badoption(opts);
|
|
}
|
|
|
|
static NEARDATA const char *menutype[] = {
|
|
"traditional", "combination", "partial", "full"
|
|
};
|
|
|
|
static NEARDATA const char *burdentype[] = {
|
|
"unencumbered", "burdened", "stressed",
|
|
"strained", "overtaxed", "overloaded"
|
|
};
|
|
|
|
static NEARDATA const char *runmodes[] = {
|
|
"teleport", "run", "walk", "crawl"
|
|
};
|
|
|
|
/*
|
|
* Convert the given string of object classes to a string of default object
|
|
* symbols.
|
|
*/
|
|
STATIC_OVL void
|
|
oc_to_str(src,dest)
|
|
char *src, *dest;
|
|
{
|
|
int i;
|
|
|
|
while ((i = (int) *src++) != 0) {
|
|
if (i < 0 || i >= MAXOCLASSES)
|
|
impossible("oc_to_str: illegal object class %d", i);
|
|
else
|
|
*dest++ = def_oc_syms[i].sym;
|
|
}
|
|
*dest = '\0';
|
|
}
|
|
|
|
/*
|
|
* Add the given mapping to the menu command map list. Always keep the
|
|
* maps valid C strings.
|
|
*/
|
|
void
|
|
add_menu_cmd_alias(from_ch, to_ch)
|
|
char from_ch, to_ch;
|
|
{
|
|
if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
|
|
pline("out of menu map space.");
|
|
else {
|
|
mapped_menu_cmds[n_menu_mapped] = from_ch;
|
|
mapped_menu_op[n_menu_mapped] = to_ch;
|
|
n_menu_mapped++;
|
|
mapped_menu_cmds[n_menu_mapped] = 0;
|
|
mapped_menu_op[n_menu_mapped] = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Map the given character to its corresponding menu command. If it
|
|
* doesn't match anything, just return the original.
|
|
*/
|
|
char
|
|
map_menu_cmd(ch)
|
|
char ch;
|
|
{
|
|
char *found = index(mapped_menu_cmds, ch);
|
|
if (found) {
|
|
int idx = (int)(found - mapped_menu_cmds);
|
|
ch = mapped_menu_op[idx];
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
|
|
#if defined(MICRO) || defined(MAC) || defined(WIN32)
|
|
# define OPTIONS_HEADING "OPTIONS"
|
|
#else
|
|
# define OPTIONS_HEADING "NETHACKOPTIONS"
|
|
#endif
|
|
|
|
static char fmtstr_doset_add_menu[] = "%s%-15s [%s] ";
|
|
static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
|
|
|
|
STATIC_OVL void
|
|
doset_add_menu(win, option, indexoffset)
|
|
winid win; /* window to add to */
|
|
const char *option; /* option name */
|
|
int indexoffset; /* value to add to index in compopt[], or zero
|
|
if option cannot be changed */
|
|
{
|
|
const char *value = "unknown"; /* current value */
|
|
char buf[BUFSZ], buf2[BUFSZ];
|
|
anything any;
|
|
int i;
|
|
|
|
any = zeroany;
|
|
if (indexoffset == 0) {
|
|
any.a_int = 0;
|
|
value = get_compopt_value(option, buf2);
|
|
} else {
|
|
for (i=0; compopt[i].name; i++)
|
|
if (strcmp(option, compopt[i].name) == 0) break;
|
|
|
|
if (compopt[i].name) {
|
|
any.a_int = i + 1 + indexoffset;
|
|
value = get_compopt_value(option, buf2);
|
|
} else {
|
|
/* We are trying to add an option not found in compopt[].
|
|
This is almost certainly bad, but we'll let it through anyway
|
|
(with a zero value, so it can't be selected). */
|
|
any.a_int = 0;
|
|
}
|
|
}
|
|
/* " " replaces "a - " -- assumes menus follow that style */
|
|
if (!iflags.menu_tab_sep)
|
|
Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option, value);
|
|
else
|
|
Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
|
|
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
|
|
}
|
|
|
|
/* Changing options via menu by Per Liboriussen */
|
|
int
|
|
doset()
|
|
{
|
|
char buf[BUFSZ], buf2[BUFSZ];
|
|
int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
|
|
boolean *bool_p;
|
|
winid tmpwin;
|
|
anything any;
|
|
menu_item *pick_list;
|
|
int indexoffset, startpass, endpass;
|
|
boolean setinitial = FALSE, fromfile = FALSE;
|
|
int biggest_name = 0;
|
|
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
|
|
any = zeroany;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
|
|
"Booleans (selecting will toggle value):", MENU_UNSELECTED);
|
|
any.a_int = 0;
|
|
/* first list any other non-modifiable booleans, then modifiable ones */
|
|
for (pass = 0; pass <= 1; pass++)
|
|
for (i = 0; boolopt[i].name; i++)
|
|
if ((bool_p = boolopt[i].addr) != 0 &&
|
|
((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
|
|
(boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
|
|
if (bool_p == &flags.female) continue; /* obsolete */
|
|
#ifdef WIZARD
|
|
if (bool_p == &iflags.sanity_check && !wizard) continue;
|
|
if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
|
|
#endif
|
|
if (is_wc_option(boolopt[i].name) &&
|
|
!wc_supported(boolopt[i].name)) continue;
|
|
if (is_wc2_option(boolopt[i].name) &&
|
|
!wc2_supported(boolopt[i].name)) continue;
|
|
any.a_int = (pass == 0) ? 0 : i + 1;
|
|
if (!iflags.menu_tab_sep)
|
|
Sprintf(buf, "%s%-13s [%s]",
|
|
pass == 0 ? " " : "",
|
|
boolopt[i].name, *bool_p ? "true" : "false");
|
|
else
|
|
Sprintf(buf, "%s\t[%s]",
|
|
boolopt[i].name, *bool_p ? "true" : "false");
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
|
|
ATR_NONE, buf, MENU_UNSELECTED);
|
|
}
|
|
|
|
boolcount = i;
|
|
indexoffset = boolcount;
|
|
any = zeroany;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
|
|
"Compounds (selecting will prompt for new value):",
|
|
MENU_UNSELECTED);
|
|
|
|
#ifdef notyet /* SYSCF */
|
|
/* XXX I think this is still fragile. Fixing initial/from_file and/or changing
|
|
the SET_* etc to bitmaps will let me make this better. */
|
|
if(wizard)
|
|
startpass = SET_IN_SYS;
|
|
else
|
|
#endif
|
|
startpass = DISP_IN_GAME;
|
|
endpass = SET_IN_GAME;
|
|
|
|
/* spin through the options to find the biggest name
|
|
and adjust the format string accordingly if needed */
|
|
biggest_name = 0;
|
|
for (i = 0; compopt[i].name; i++)
|
|
if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
|
|
strlen(compopt[i].name) > (unsigned) biggest_name)
|
|
biggest_name = (int) strlen(compopt[i].name);
|
|
if (biggest_name > 30) biggest_name = 30;
|
|
if (!iflags.menu_tab_sep)
|
|
Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
|
|
|
|
/* deliberately put `playmode', `name', `role', `race', `gender' first
|
|
(also alignment if anything ever comes before it in compopt[]) */
|
|
doset_add_menu(tmpwin, "playmode", 0);
|
|
doset_add_menu(tmpwin, "name", 0);
|
|
doset_add_menu(tmpwin, "role", 0);
|
|
doset_add_menu(tmpwin, "race", 0);
|
|
doset_add_menu(tmpwin, "gender", 0);
|
|
|
|
for (pass = startpass; pass <= endpass; pass++)
|
|
for (i = 0; compopt[i].name; i++)
|
|
if (compopt[i].optflags == pass) {
|
|
if (!strcmp(compopt[i].name, "playmode") ||
|
|
!strcmp(compopt[i].name, "name") ||
|
|
!strcmp(compopt[i].name, "role") ||
|
|
!strcmp(compopt[i].name, "race") ||
|
|
!strcmp(compopt[i].name, "gender"))
|
|
continue;
|
|
else if (is_wc_option(compopt[i].name) &&
|
|
!wc_supported(compopt[i].name))
|
|
continue;
|
|
else if (is_wc2_option(compopt[i].name) &&
|
|
!wc2_supported(compopt[i].name))
|
|
continue;
|
|
else
|
|
doset_add_menu(tmpwin, compopt[i].name,
|
|
(pass == DISP_IN_GAME) ? 0 : indexoffset);
|
|
}
|
|
#ifdef STATUS_VIA_WINDOWPORT
|
|
# ifdef STATUS_HILITES
|
|
any.a_int = -2;
|
|
get_status_hilites(buf2, 60);
|
|
if (!iflags.menu_tab_sep)
|
|
Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ",
|
|
"status_hilites", buf2);
|
|
else
|
|
Sprintf(buf, fmtstr_doset_add_menu_tab, "status_hilites", buf2);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
|
|
# endif
|
|
#endif
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
any.a_int = -1;
|
|
Sprintf(buf, "autopickup exceptions (%d currently set)",
|
|
count_ape_maps((int *)0, (int *)0));
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
|
|
#endif /* AUTOPICKUP_EXCEPTIONS */
|
|
#ifdef PREFIXES_IN_USE
|
|
any = zeroany;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
|
|
"Variable playground locations:", MENU_UNSELECTED);
|
|
for (i = 0; i < PREFIX_COUNT; i++)
|
|
doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
|
|
#endif
|
|
end_menu(tmpwin, "Set what options?");
|
|
need_redraw = FALSE;
|
|
if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
|
|
/*
|
|
* Walk down the selection list and either invert the booleans
|
|
* or prompt for new values. In most cases, call parseoptions()
|
|
* to take care of options that require special attention, like
|
|
* redraws.
|
|
*/
|
|
for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
|
|
opt_indx = pick_list[pick_idx].item.a_int - 1;
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
if (opt_indx == -2) { /* -3 due to -1 offset for select_menu() */
|
|
(void)special_handling("autopickup_exception",
|
|
setinitial, fromfile);
|
|
} else
|
|
#endif
|
|
#ifdef STATUS_VIA_WINDOWPORT
|
|
# ifdef STATUS_HILITES
|
|
if (opt_indx == -3) { /* -3 due to -1 offset for select_menu() */
|
|
if (!status_hilite_menu())
|
|
pline("Bad status hilite(s) specified.");
|
|
else {
|
|
if (wc2_supported("status_hilites"))
|
|
preference_update("status_hilites");
|
|
}
|
|
} else
|
|
# endif
|
|
#endif
|
|
if (opt_indx < boolcount) {
|
|
/* boolean option */
|
|
Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
|
|
boolopt[opt_indx].name);
|
|
parseoptions(buf, setinitial, fromfile);
|
|
if (wc_supported(boolopt[opt_indx].name) ||
|
|
wc2_supported(boolopt[opt_indx].name))
|
|
preference_update(boolopt[opt_indx].name);
|
|
} else {
|
|
/* compound option */
|
|
opt_indx -= boolcount;
|
|
|
|
if (!special_handling(compopt[opt_indx].name,
|
|
setinitial, fromfile)) {
|
|
Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
|
|
getlin(buf, buf2);
|
|
if (buf2[0] == '\033')
|
|
continue;
|
|
Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
|
|
/* pass the buck */
|
|
parseoptions(buf, setinitial, fromfile);
|
|
}
|
|
if (wc_supported(compopt[opt_indx].name) ||
|
|
wc2_supported(compopt[opt_indx].name))
|
|
preference_update(compopt[opt_indx].name);
|
|
}
|
|
}
|
|
free((genericptr_t)pick_list);
|
|
pick_list = (menu_item *)0;
|
|
}
|
|
|
|
destroy_nhwindow(tmpwin);
|
|
if (need_redraw)
|
|
(void) doredraw();
|
|
return 0;
|
|
}
|
|
|
|
#ifdef LOADSYMSETS
|
|
struct symsetentry *symset_list = 0; /* files.c will populate this with
|
|
list of available sets */
|
|
#endif
|
|
|
|
STATIC_OVL boolean
|
|
special_handling(optname, setinitial, setfromfile)
|
|
const char *optname;
|
|
boolean setinitial,setfromfile;
|
|
{
|
|
winid tmpwin;
|
|
anything any;
|
|
int i;
|
|
char buf[BUFSZ];
|
|
|
|
/* Special handling of menustyle, pickup_burden, pickup_types,
|
|
* disclose, runmode, msg_window, menu_headings, and number_pad options.
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
* Also takes care of interactive autopickup_exception_handling changes.
|
|
#endif
|
|
*/
|
|
if (!strcmp("menustyle", optname)) {
|
|
const char *style_name;
|
|
menu_item *style_pick = (menu_item *)0;
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
for (i = 0; i < SIZE(menutype); i++) {
|
|
style_name = menutype[i];
|
|
/* note: separate `style_name' variable used
|
|
to avoid an optimizer bug in VAX C V2.3 */
|
|
any.a_int = i + 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
|
|
ATR_NONE, style_name, MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "Select menustyle:");
|
|
if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
|
|
flags.menu_style = style_pick->item.a_int - 1;
|
|
free((genericptr_t)style_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("paranoid_confirmation", optname)) {
|
|
menu_item *paranoia_picks = (menu_item *)0;
|
|
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; paranoia[i].flagmask != 0; ++i) {
|
|
if (paranoia[i].flagmask == PARANOID_BONES && !wizard) continue;
|
|
any.a_int = paranoia[i].flagmask;
|
|
add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0,
|
|
ATR_NONE, paranoia[i].explain,
|
|
(flags.paranoia_bits & paranoia[i].flagmask) ?
|
|
MENU_SELECTED : MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "Actions requiring extra confirmation:");
|
|
i = select_menu(tmpwin, PICK_ANY, ¶noia_picks);
|
|
if (i >= 0) {
|
|
/* player didn't cancel; we reset all the paranoia options
|
|
here even if there were no items picked, since user
|
|
could have toggled off preselected ones to end up with 0 */
|
|
flags.paranoia_bits = 0;
|
|
if (i > 0) {
|
|
/* at least one item set, either preselected or newly picked */
|
|
while (--i >= 0)
|
|
flags.paranoia_bits |= paranoia_picks[i].item.a_int;
|
|
free((genericptr_t)paranoia_picks);
|
|
}
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("pickup_burden", optname)) {
|
|
const char *burden_name, *burden_letters = "ubsntl";
|
|
menu_item *burden_pick = (menu_item *)0;
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; i < SIZE(burdentype); i++) {
|
|
burden_name = burdentype[i];
|
|
any.a_int = i + 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
|
|
ATR_NONE, burden_name, MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "Select encumbrance level:");
|
|
if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
|
|
flags.pickup_burden = burden_pick->item.a_int - 1;
|
|
free((genericptr_t)burden_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("pickup_types", optname)) {
|
|
/* parseoptions will prompt for the list of types */
|
|
parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
|
|
} else if (!strcmp("disclose", optname)) {
|
|
int pick_cnt, pick_idx, opt_idx;
|
|
menu_item *disclosure_category_pick = (menu_item *)0;
|
|
/*
|
|
* The order of disclose_names[]
|
|
* must correspond to disclosure_options in decl.h
|
|
*/
|
|
static const char *disclosure_names[] = {
|
|
"inventory", "attributes", "vanquished", "genocides", "conduct"
|
|
};
|
|
int disc_cat[NUM_DISCLOSURE_OPTIONS];
|
|
const char *disclosure_name;
|
|
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
|
|
disclosure_name = disclosure_names[i];
|
|
any.a_int = i + 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
|
|
ATR_NONE, disclosure_name, MENU_UNSELECTED);
|
|
disc_cat[i] = 0;
|
|
}
|
|
end_menu(tmpwin, "Change which disclosure options categories:");
|
|
if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
|
|
for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
|
|
opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
|
|
disc_cat[opt_idx] = 1;
|
|
}
|
|
free((genericptr_t)disclosure_category_pick);
|
|
disclosure_category_pick = (menu_item *)0;
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
|
|
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
|
|
if (disc_cat[i]) {
|
|
char dbuf[BUFSZ];
|
|
menu_item *disclosure_option_pick = (menu_item *)0;
|
|
|
|
Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
|
|
ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
|
|
any = zeroany;
|
|
any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
|
|
ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
|
|
any = zeroany;
|
|
any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
|
|
ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
|
|
any = zeroany;
|
|
any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
|
|
ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
|
|
end_menu(tmpwin, dbuf);
|
|
if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
|
|
flags.end_disclose[i] = disclosure_option_pick->item.a_char;
|
|
free((genericptr_t)disclosure_option_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
}
|
|
}
|
|
} else if (!strcmp("runmode", optname)) {
|
|
const char *mode_name;
|
|
menu_item *mode_pick = (menu_item *)0;
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; i < SIZE(runmodes); i++) {
|
|
mode_name = runmodes[i];
|
|
any.a_int = i + 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
|
|
ATR_NONE, mode_name, MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "Select run/travel display mode:");
|
|
if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
|
|
flags.runmode = mode_pick->item.a_int - 1;
|
|
free((genericptr_t)mode_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("msg_window", optname)) {
|
|
#ifdef TTY_GRAPHICS
|
|
/* by Christian W. Cooper */
|
|
menu_item *window_pick = (menu_item *)0;
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
any.a_char = 's';
|
|
add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
|
|
ATR_NONE, "single", MENU_UNSELECTED);
|
|
any.a_char = 'c';
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
|
|
ATR_NONE, "combination", MENU_UNSELECTED);
|
|
any.a_char = 'f';
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
|
|
ATR_NONE, "full", MENU_UNSELECTED);
|
|
any.a_char = 'r';
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
|
|
ATR_NONE, "reversed", MENU_UNSELECTED);
|
|
end_menu(tmpwin, "Select message history display type:");
|
|
if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
|
|
iflags.prevmsg_window = window_pick->item.a_char;
|
|
free((genericptr_t)window_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
#endif
|
|
} else if (!strcmp("align_message", optname) ||
|
|
!strcmp("align_status", optname)) {
|
|
menu_item *window_pick = (menu_item *)0;
|
|
char abuf[BUFSZ];
|
|
boolean msg = (*(optname+6) == 'm');
|
|
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
any.a_int = ALIGN_TOP;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
|
|
ATR_NONE, "top", MENU_UNSELECTED);
|
|
any.a_int = ALIGN_BOTTOM;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
|
|
ATR_NONE, "bottom", MENU_UNSELECTED);
|
|
any.a_int = ALIGN_LEFT;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
|
|
ATR_NONE, "left", MENU_UNSELECTED);
|
|
any.a_int = ALIGN_RIGHT;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
|
|
ATR_NONE, "right", MENU_UNSELECTED);
|
|
Sprintf(abuf, "Select %s window placement relative to the map:",
|
|
msg ? "message" : "status");
|
|
end_menu(tmpwin, abuf);
|
|
if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
|
|
if (msg) iflags.wc_align_message = window_pick->item.a_int;
|
|
else iflags.wc_align_status = window_pick->item.a_int;
|
|
free((genericptr_t)window_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("number_pad", optname)) {
|
|
static const char *npchoices[] = {
|
|
" 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
|
|
" 3 (on, phone-style digit layout)",
|
|
" 4 (on, phone-style layout, MSDOS compatible)",
|
|
"-1 (off, 'z' to move upper-left, 'y' to zap wands)"
|
|
};
|
|
menu_item *mode_pick = (menu_item *)0;
|
|
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; i < SIZE(npchoices); i++) {
|
|
any.a_int = i + 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0,
|
|
ATR_NONE, npchoices[i], MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "Select number_pad mode:");
|
|
if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
|
|
switch (mode_pick->item.a_int - 1) {
|
|
case 0: iflags.num_pad = FALSE; iflags.num_pad_mode = 0; break;
|
|
case 1: iflags.num_pad = TRUE; iflags.num_pad_mode = 0; break;
|
|
case 2: iflags.num_pad = TRUE; iflags.num_pad_mode = 1; break;
|
|
case 3: iflags.num_pad = TRUE; iflags.num_pad_mode = 2; break;
|
|
case 4: iflags.num_pad = TRUE; iflags.num_pad_mode = 3; break;
|
|
/* last menu choice: number_pad == -1 */
|
|
case 5: iflags.num_pad = FALSE; iflags.num_pad_mode = 1; break;
|
|
}
|
|
reset_commands(FALSE);
|
|
number_pad(iflags.num_pad ? 1 : 0);
|
|
free((genericptr_t)mode_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("menu_headings", optname)) {
|
|
static const char *mhchoices[3] = {"bold", "inverse", "underline"};
|
|
const char *npletters = "biu";
|
|
menu_item *mode_pick = (menu_item *)0;
|
|
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; i < SIZE(mhchoices); i++) {
|
|
any.a_int = i + 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
|
|
ATR_NONE, mhchoices[i], MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "How to highlight menu headings:");
|
|
if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
|
|
int mode = mode_pick->item.a_int - 1;
|
|
switch(mode) {
|
|
case 2:
|
|
iflags.menu_headings = ATR_ULINE;
|
|
break;
|
|
case 0:
|
|
iflags.menu_headings = ATR_BOLD;
|
|
break;
|
|
case 1:
|
|
default:
|
|
iflags.menu_headings = ATR_INVERSE;
|
|
}
|
|
free((genericptr_t)mode_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
} else if (!strcmp("autopickup_exception", optname)) {
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
int pick_cnt, pick_idx, opt_idx, pass;
|
|
int totalapes = 0, numapes[2] = {0,0};
|
|
menu_item *pick_list = (menu_item *)0;
|
|
char apebuf[1+BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */
|
|
struct autopickup_exception *ape;
|
|
static const struct ape_action {
|
|
char letr;
|
|
const char *desc;
|
|
} action_titles[] = {
|
|
{ 'a', "add new autopickup exception" }, /* [0] */
|
|
{ 'l', "list autopickup exceptions" }, /* [1] */
|
|
{ 'r', "remove existing autopickup exception" }, /* [2] */
|
|
{ 'x', "exit this menu" }, /* [3] */
|
|
};
|
|
|
|
ape_again:
|
|
opt_idx = 0;
|
|
totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any = zeroany;
|
|
for (i = 0; i < SIZE(action_titles); i++) {
|
|
any.a_int++;
|
|
/* omit list and remove if there aren't any yet */
|
|
if (!totalapes && (i == 1 || i == 2)) continue;
|
|
add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr,
|
|
0, ATR_NONE, action_titles[i].desc,
|
|
#if 0 /* this ought to work but doesn't... */
|
|
(action_titles[i].letr == 'x') ? MENU_SELECTED :
|
|
#endif
|
|
MENU_UNSELECTED);
|
|
}
|
|
end_menu(tmpwin, "Do what?");
|
|
if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
|
|
for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
|
|
opt_idx = pick_list[pick_idx].item.a_int - 1;
|
|
}
|
|
free((genericptr_t)pick_list);
|
|
pick_list = (menu_item *)0;
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
|
|
if (pick_cnt < 1 || opt_idx == 3) {
|
|
; /* done--fall through to function exit */
|
|
} else if (opt_idx == 0) { /* add new */
|
|
getlin("What new autopickup exception pattern?", &apebuf[1]);
|
|
mungspaces(&apebuf[1]); /* regularize whitespace */
|
|
if (apebuf[1] == '\033') {
|
|
; /* fall through to function exit */
|
|
} else {
|
|
if (apebuf[1]) {
|
|
apebuf[0] = '\"';
|
|
/* guarantee room for \" prefix and \"\0 suffix;
|
|
-2 is good enough for apebuf[] but -3 makes
|
|
sure the whole thing fits within normal BUFSZ */
|
|
apebuf[sizeof apebuf - 3] = '\0';
|
|
Strcat(apebuf, "\"");
|
|
add_autopickup_exception(apebuf);
|
|
}
|
|
goto ape_again;
|
|
}
|
|
} else { /* list or remove */
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
|
|
if (numapes[pass] == 0) continue;
|
|
ape = iflags.autopickup_exceptions[pass];
|
|
any = zeroany;
|
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
|
|
(pass == 0) ? "Never pickup" : "Always pickup",
|
|
MENU_UNSELECTED);
|
|
for (i = 0; i < numapes[pass] && ape; i++) {
|
|
any.a_void = (opt_idx == 1) ? 0 : ape;
|
|
Sprintf(apebuf, "\"%s\"", ape->pattern);
|
|
add_menu(tmpwin, NO_GLYPH, &any,
|
|
0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
|
|
ape = ape->next;
|
|
}
|
|
}
|
|
Sprintf(apebuf, "%s autopickup exceptions",
|
|
(opt_idx == 1) ? "List of" : "Remove which");
|
|
end_menu(tmpwin, apebuf);
|
|
pick_cnt = select_menu(tmpwin,
|
|
(opt_idx == 1) ? PICK_NONE : PICK_ANY,
|
|
&pick_list);
|
|
if (pick_cnt > 0) {
|
|
for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
|
|
remove_autopickup_exception(
|
|
(struct autopickup_exception *)pick_list[pick_idx].item.a_void);
|
|
}
|
|
free((genericptr_t)pick_list);
|
|
pick_list = (menu_item *)0;
|
|
destroy_nhwindow(tmpwin);
|
|
if (pick_cnt >= 0) goto ape_again;
|
|
}
|
|
#endif /* AUTOPICKUP_EXCEPTIONS */
|
|
} else if (!strcmp("symset", optname)
|
|
|| !strcmp("roguesymset", optname)) {
|
|
menu_item *symset_pick = (menu_item *)0;
|
|
boolean primaryflag = (*optname == 's'),
|
|
rogueflag = (*optname == 'r'),
|
|
ready_to_switch = FALSE,
|
|
nothing_to_do = FALSE;
|
|
#ifdef LOADSYMSETS
|
|
int res;
|
|
char *symset_name, fmtstr[20];
|
|
struct symsetentry *sl;
|
|
int setcount = 0;
|
|
#endif
|
|
int chosen = -2, which_set;
|
|
|
|
#ifdef REINCARNATION
|
|
if (rogueflag) which_set = ROGUESET;
|
|
else
|
|
#endif
|
|
which_set = PRIMARY;
|
|
|
|
#ifndef REINCARNATION
|
|
if (rogueflag) return TRUE;
|
|
#endif
|
|
|
|
#ifdef LOADSYMSETS
|
|
/* clear symset[].name as a flag to read_sym_file() to build list */
|
|
symset_name = symset[which_set].name;
|
|
symset[which_set].name = (char *)0;
|
|
symset_list = (struct symsetentry *)0;
|
|
|
|
res = read_sym_file(which_set);
|
|
if (res && symset_list) {
|
|
char symsetchoice[BUFSZ];
|
|
int let = 'a', biggest = 0, thissize = 0;
|
|
sl = symset_list;
|
|
while (sl) {
|
|
/* check restrictions */
|
|
if ((!rogueflag && sl->rogue) ||
|
|
(!iflags.unicodedisp && sl->unicode) ||
|
|
(!primaryflag && sl->primary)) {
|
|
sl = sl->next;
|
|
continue;
|
|
}
|
|
setcount++;
|
|
/* find biggest name */
|
|
if (sl->name) thissize = strlen(sl->name);
|
|
if (thissize > biggest) biggest = thissize;
|
|
sl = sl->next;
|
|
}
|
|
if (!setcount) {
|
|
pline("There are no appropriate %ssymbol sets available.",
|
|
(rogueflag) ? "rogue level " :
|
|
(primaryflag) ? "primary " :
|
|
"");
|
|
return TRUE;
|
|
}
|
|
|
|
Sprintf(fmtstr,"%%-%ds %%s", biggest + 5);
|
|
tmpwin = create_nhwindow(NHW_MENU);
|
|
start_menu(tmpwin);
|
|
any.a_int = 1;
|
|
add_menu(tmpwin, NO_GLYPH, &any, let++, 0,
|
|
ATR_NONE, "Default Symbols", MENU_UNSELECTED);
|
|
|
|
sl = symset_list;
|
|
while (sl) {
|
|
/* check restrictions */
|
|
if ((!rogueflag && sl->rogue) ||
|
|
(!iflags.unicodedisp && sl->unicode) ||
|
|
(!primaryflag && sl->primary)) {
|
|
sl = sl->next;
|
|
continue;
|
|
}
|
|
if (sl->name) {
|
|
any.a_int = sl->idx + 2;
|
|
Sprintf(symsetchoice, fmtstr, sl->name,
|
|
sl->desc ? sl->desc : "");
|
|
add_menu(tmpwin, NO_GLYPH, &any, let, 0,
|
|
ATR_NONE, symsetchoice, MENU_UNSELECTED);
|
|
if (let == 'z') let = 'A';
|
|
else let++;
|
|
}
|
|
sl = sl->next;
|
|
}
|
|
end_menu(tmpwin, "Select symbol set:");
|
|
if (select_menu(tmpwin, PICK_ONE, &symset_pick) > 0) {
|
|
chosen = symset_pick->item.a_int - 2;
|
|
free((genericptr_t)symset_pick);
|
|
}
|
|
destroy_nhwindow(tmpwin);
|
|
|
|
if (chosen > -1) {
|
|
/* chose an actual symset name from file */
|
|
sl = symset_list;
|
|
while (sl) {
|
|
if (sl->idx == chosen) {
|
|
if (symset_name) {
|
|
free((genericptr_t)symset_name);
|
|
symset_name = (char *)0;
|
|
}
|
|
/* free the now stale attributes */
|
|
clear_symsetentry(which_set, TRUE);
|
|
|
|
/* transfer only the name of the symbol set */
|
|
symset[which_set].name =
|
|
(char *)alloc(strlen(sl->name)+1);
|
|
Strcpy(symset[which_set].name, sl->name);
|
|
ready_to_switch = TRUE;
|
|
break;
|
|
}
|
|
sl = sl->next;
|
|
}
|
|
}
|
|
|
|
else if (chosen == -1) {
|
|
/* explicit selection of defaults */
|
|
/* free the now stale symset attributes */
|
|
if (symset_name) free ((genericptr_t)symset_name);
|
|
symset_name = (char *)0;
|
|
clear_symsetentry(which_set, TRUE);
|
|
}
|
|
else nothing_to_do = TRUE;
|
|
} else if (!res) {
|
|
/* The symbols file could not be accessed */
|
|
pline("Unable to access \"%s\" file.", SYMBOLS);
|
|
return TRUE;
|
|
} else if (!symset_list) {
|
|
/* The symbols file was empty */
|
|
pline("There were no symbol sets found in \"%s\".",
|
|
SYMBOLS);
|
|
return TRUE;
|
|
}
|
|
|
|
/* clean up */
|
|
while (symset_list) {
|
|
sl = symset_list;
|
|
if (sl->name) free((genericptr_t)sl->name);
|
|
sl->name = (char *)0;
|
|
|
|
if (sl->desc) free((genericptr_t)sl->desc);
|
|
sl->desc = (char *)0;
|
|
|
|
symset_list = sl->next;
|
|
free((genericptr_t)sl);
|
|
}
|
|
|
|
if (nothing_to_do) return TRUE;
|
|
|
|
if (!symset[which_set].name && symset_name)
|
|
symset[which_set].name = symset_name;
|
|
|
|
/* Set default symbols and clear the handling value */
|
|
# ifdef REINCARNATION
|
|
if(rogueflag)
|
|
init_r_symbols();
|
|
else
|
|
# endif
|
|
init_l_symbols();
|
|
|
|
if (symset[which_set].name) {
|
|
if (read_sym_file(which_set))
|
|
ready_to_switch = TRUE;
|
|
else {
|
|
clear_symsetentry(which_set, TRUE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (ready_to_switch) switch_symbols(TRUE);
|
|
|
|
# ifdef REINCARNATION
|
|
if (Is_rogue_level(&u.uz)) {
|
|
if (rogueflag)
|
|
assign_graphics(ROGUESET);
|
|
} else
|
|
# endif
|
|
if (!rogueflag) assign_graphics(PRIMARY);
|
|
need_redraw = TRUE;
|
|
#endif /*LOADSYMSETS*/
|
|
return TRUE;
|
|
|
|
} else {
|
|
/* didn't match any of the special options */
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
|
|
(val == ROLE_RANDOM) ? randomrole : none)
|
|
|
|
/* This is ugly. We have all the option names in the compopt[] array,
|
|
but we need to look at each option individually to get the value. */
|
|
STATIC_OVL const char *
|
|
get_compopt_value(optname, buf)
|
|
const char *optname;
|
|
char *buf;
|
|
{
|
|
char ocl[MAXOCLASSES+1];
|
|
static const char none[] = "(none)", randomrole[] = "random",
|
|
to_be_done[] = "(to be done)",
|
|
defopt[] = "default",
|
|
defbrief[] = "def";
|
|
int i;
|
|
|
|
buf[0] = '\0';
|
|
if (!strcmp(optname,"align_message"))
|
|
Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP ? "top" :
|
|
iflags.wc_align_message == ALIGN_LEFT ? "left" :
|
|
iflags.wc_align_message == ALIGN_BOTTOM ? "bottom" :
|
|
iflags.wc_align_message == ALIGN_RIGHT ? "right" :
|
|
defopt);
|
|
else if (!strcmp(optname,"align_status"))
|
|
Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP ? "top" :
|
|
iflags.wc_align_status == ALIGN_LEFT ? "left" :
|
|
iflags.wc_align_status == ALIGN_BOTTOM ? "bottom" :
|
|
iflags.wc_align_status == ALIGN_RIGHT ? "right" :
|
|
defopt);
|
|
else if (!strcmp(optname,"align"))
|
|
Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
|
|
#ifdef WIN32CON
|
|
else if (!strcmp(optname,"altkeyhandler"))
|
|
Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
|
|
iflags.altkeyhandler : "default");
|
|
#endif
|
|
#ifdef BACKWARD_COMPAT
|
|
else if (!strcmp(optname, "boulder"))
|
|
# ifdef UNICODE_DRAWING
|
|
Sprintf(buf, "\\x%04X", iflags.bouldersym ?
|
|
# else
|
|
Sprintf(buf, "%c", iflags.bouldersym ?
|
|
# endif
|
|
iflags.bouldersym :
|
|
showsyms[(int)objects[BOULDER].oc_class + SYM_OFF_O]);
|
|
#endif
|
|
else if (!strcmp(optname, "catname"))
|
|
Sprintf(buf, "%s", catname[0] ? catname : none );
|
|
else if (!strcmp(optname, "disclose")) {
|
|
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
|
|
char topt[2];
|
|
if (i) Strcat(buf," ");
|
|
topt[1] = '\0';
|
|
topt[0] = flags.end_disclose[i];
|
|
Strcat(buf, topt);
|
|
topt[0] = disclosure_options[i];
|
|
Strcat(buf, topt);
|
|
}
|
|
}
|
|
else if (!strcmp(optname, "dogname"))
|
|
Sprintf(buf, "%s", dogname[0] ? dogname : none );
|
|
else if (!strcmp(optname, "dungeon"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "effects"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "font_map"))
|
|
Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
|
|
else if (!strcmp(optname, "font_message"))
|
|
Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
|
|
else if (!strcmp(optname, "font_status"))
|
|
Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
|
|
else if (!strcmp(optname, "font_menu"))
|
|
Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
|
|
else if (!strcmp(optname, "font_text"))
|
|
Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
|
|
else if (!strcmp(optname, "font_size_map")) {
|
|
if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "font_size_message")) {
|
|
if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
|
|
iflags.wc_fontsiz_message);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "font_size_status")) {
|
|
if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "font_size_menu")) {
|
|
if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "font_size_text")) {
|
|
if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "fruit"))
|
|
Sprintf(buf, "%s", pl_fruit);
|
|
else if (!strcmp(optname, "gender"))
|
|
Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
|
|
else if (!strcmp(optname, "horsename"))
|
|
Sprintf(buf, "%s", horsename[0] ? horsename : none);
|
|
else if (!strcmp(optname, "map_mode"))
|
|
Sprintf(buf, "%s",
|
|
iflags.wc_map_mode == MAP_MODE_TILES ? "tiles" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII4x6 ? "ascii4x6" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII6x8 ? "ascii6x8" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII8x8 ? "ascii8x8" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII16x8 ? "ascii16x8" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII7x12 ? "ascii7x12" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII8x12 ? "ascii8x12" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
|
|
iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
|
|
"fit_to_screen" : defopt);
|
|
else if (!strcmp(optname, "menustyle"))
|
|
Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
|
|
else if (!strcmp(optname, "menu_deselect_all"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_deselect_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_first_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_invert_all"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_headings")) {
|
|
Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
|
|
"bold" : (iflags.menu_headings == ATR_INVERSE) ?
|
|
"inverse" : (iflags.menu_headings == ATR_ULINE) ?
|
|
"underline" : "unknown");
|
|
}
|
|
else if (!strcmp(optname, "menu_invert_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_last_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_next_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_previous_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_search"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_select_all"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "menu_select_page"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "monsters"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "msghistory"))
|
|
Sprintf(buf, "%u", iflags.msg_history);
|
|
#ifdef TTY_GRAPHICS
|
|
else if (!strcmp(optname, "msg_window"))
|
|
Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
|
|
(iflags.prevmsg_window=='c') ? "combination" :
|
|
(iflags.prevmsg_window=='f') ? "full" : "reversed");
|
|
#endif
|
|
else if (!strcmp(optname, "name"))
|
|
Sprintf(buf, "%s", plname);
|
|
else if (!strcmp(optname, "number_pad")) {
|
|
static const char *numpadmodes[] = {
|
|
"0=off", "1=on",
|
|
"2=on, MSDOS compatible", "3=on, phone-style layout",
|
|
"4=on, phone layout, MSDOS compatible",
|
|
"-1=off, y & z swapped", /*[5]*/
|
|
};
|
|
int indx = Cmd.num_pad ?
|
|
(Cmd.phone_layout ? (Cmd.pcHack_compat ? 4 : 3) :
|
|
(Cmd.pcHack_compat ? 2 : 1)) :
|
|
Cmd.swap_yz ? 5 : 0;
|
|
|
|
Strcpy(buf, numpadmodes[indx]);
|
|
} else if (!strcmp(optname, "objects"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "packorder")) {
|
|
oc_to_str(flags.inv_order, ocl);
|
|
Sprintf(buf, "%s", ocl);
|
|
}
|
|
#ifdef CHANGE_COLOR
|
|
else if (!strcmp(optname, "palette"))
|
|
Sprintf(buf, "%s", get_color_string());
|
|
#endif
|
|
else if (!strcmp(optname, "paranoid_confirmation")) {
|
|
char tmpbuf[QBUFSZ];
|
|
|
|
tmpbuf[0] = '\0';
|
|
if (ParanoidConfirm) Strcat(tmpbuf, " Confirm");
|
|
if (ParanoidQuit) Strcat(tmpbuf, " quit");
|
|
if (ParanoidDie) Strcat(tmpbuf, " die");
|
|
if (ParanoidBones) Strcat(tmpbuf, " bones");
|
|
if (ParanoidHit) Strcat(tmpbuf, " attack");
|
|
if (ParanoidPray) Strcat(tmpbuf, " pray");
|
|
if (ParanoidRemove) Strcat(tmpbuf, " Remove");
|
|
Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none");
|
|
} else if (!strcmp(optname, "pettype"))
|
|
Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
|
|
(preferred_pet == 'd') ? "dog" :
|
|
(preferred_pet == 'h') ? "horse" :
|
|
(preferred_pet == 'n') ? "none" : "random");
|
|
else if (!strcmp(optname, "pickup_burden"))
|
|
Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
|
|
else if (!strcmp(optname, "pickup_types")) {
|
|
oc_to_str(flags.pickup_types, ocl);
|
|
Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
|
|
}
|
|
else if (!strcmp(optname, "pile_limit"))
|
|
Sprintf(buf, "%d", flags.pile_limit);
|
|
else if (!strcmp(optname, "playmode")) {
|
|
Strcpy(buf,
|
|
wizard ? "debug" : discover ? "explore" : "normal");
|
|
}
|
|
else if (!strcmp(optname, "race"))
|
|
Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
|
|
#ifdef REINCARNATION
|
|
else if (!strcmp(optname, "roguesymset")) {
|
|
Sprintf(buf, "%s",
|
|
# ifdef LOADSYMSETS
|
|
symset[ROGUESET].name ?
|
|
symset[ROGUESET].name :
|
|
# endif
|
|
"default");
|
|
if (currentgraphics == ROGUESET && symset[ROGUESET].name)
|
|
Strcat(buf, ", active");
|
|
#endif
|
|
}
|
|
else if (!strcmp(optname, "role"))
|
|
Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
|
|
else if (!strcmp(optname, "runmode"))
|
|
Sprintf(buf, "%s", runmodes[flags.runmode]);
|
|
else if (!strcmp(optname, "scores")) {
|
|
Sprintf(buf, "%d top/%d around%s", flags.end_top,
|
|
flags.end_around, flags.end_own ? "/own" : "");
|
|
}
|
|
else if (!strcmp(optname, "scroll_amount")) {
|
|
if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "scroll_margin")) {
|
|
if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "player_selection"))
|
|
Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
|
|
#ifdef MSDOS
|
|
else if (!strcmp(optname, "soundcard"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
#endif
|
|
else if (!strcmp(optname, "suppress_alert")) {
|
|
if (flags.suppress_alert == 0L)
|
|
Strcpy(buf, none);
|
|
else
|
|
Sprintf(buf, "%lu.%lu.%lu",
|
|
FEATURE_NOTICE_VER_MAJ,
|
|
FEATURE_NOTICE_VER_MIN,
|
|
FEATURE_NOTICE_VER_PATCH);
|
|
}
|
|
else if (!strcmp(optname, "symset")) {
|
|
Sprintf(buf, "%s",
|
|
#ifdef LOADSYMSETS
|
|
symset[PRIMARY].name ?
|
|
symset[PRIMARY].name :
|
|
#endif
|
|
"default");
|
|
if (currentgraphics == PRIMARY && symset[PRIMARY].name)
|
|
Strcat(buf, ", active");
|
|
}
|
|
else if (!strcmp(optname, "tile_file"))
|
|
Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
|
|
else if (!strcmp(optname, "tile_height")) {
|
|
if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "tile_width")) {
|
|
if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
else if (!strcmp(optname, "traps"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
else if (!strcmp(optname, "vary_msgcount")) {
|
|
if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
|
|
else Strcpy(buf, defopt);
|
|
}
|
|
#ifdef MSDOS
|
|
else if (!strcmp(optname, "video"))
|
|
Sprintf(buf, "%s", to_be_done);
|
|
#endif
|
|
#ifdef VIDEOSHADES
|
|
else if (!strcmp(optname, "videoshades"))
|
|
Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
|
|
else if (!strcmp(optname, "videocolors"))
|
|
Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
|
|
ttycolors[CLR_RED], ttycolors[CLR_GREEN],
|
|
ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
|
|
ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
|
|
ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
|
|
ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
|
|
ttycolors[CLR_BRIGHT_MAGENTA],
|
|
ttycolors[CLR_BRIGHT_CYAN]);
|
|
#endif /* VIDEOSHADES */
|
|
else if (!strcmp(optname, "windowtype"))
|
|
Sprintf(buf, "%s", windowprocs.name);
|
|
else if (!strcmp(optname, "windowcolors"))
|
|
Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
|
|
iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
|
|
iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
|
|
iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
|
|
iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
|
|
iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
|
|
iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
|
|
iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
|
|
iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
|
|
#ifdef PREFIXES_IN_USE
|
|
else {
|
|
for (i = 0; i < PREFIX_COUNT; ++i)
|
|
if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
|
|
Sprintf(buf, "%s", fqn_prefix[i]);
|
|
}
|
|
#endif
|
|
|
|
if (buf[0]) return buf;
|
|
else return "unknown";
|
|
}
|
|
|
|
int
|
|
dotogglepickup()
|
|
{
|
|
char buf[BUFSZ], ocl[MAXOCLASSES+1];
|
|
|
|
flags.pickup = !flags.pickup;
|
|
if (flags.pickup) {
|
|
oc_to_str(flags.pickup_types, ocl);
|
|
Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
(iflags.autopickup_exceptions[AP_LEAVE] ||
|
|
iflags.autopickup_exceptions[AP_GRAB]) ?
|
|
((count_ape_maps((int *)0, (int *)0) == 1) ?
|
|
", with one exception" : ", with some exceptions") :
|
|
#endif
|
|
"");
|
|
} else {
|
|
Strcpy(buf, "OFF");
|
|
}
|
|
pline("Autopickup: %s.", buf);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef AUTOPICKUP_EXCEPTIONS
|
|
int
|
|
add_autopickup_exception(mapping)
|
|
const char *mapping;
|
|
{
|
|
struct autopickup_exception *ape, **apehead;
|
|
char text[256], *text2;
|
|
int textsize = 0;
|
|
boolean grab = FALSE;
|
|
|
|
if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
|
|
text2 = &text[0];
|
|
if (*text2 == '<') { /* force autopickup */
|
|
grab = TRUE;
|
|
++text2;
|
|
} else if (*text2 == '>') { /* default - Do not pickup */
|
|
grab = FALSE;
|
|
++text2;
|
|
}
|
|
textsize = strlen(text2);
|
|
apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
|
|
&iflags.autopickup_exceptions[AP_LEAVE];
|
|
ape = (struct autopickup_exception *)
|
|
alloc(sizeof(struct autopickup_exception));
|
|
ape->pattern = (char *) alloc(textsize+1);
|
|
Strcpy(ape->pattern, text2);
|
|
ape->grab = grab;
|
|
if (!*apehead) ape->next = (struct autopickup_exception *)0;
|
|
else ape->next = *apehead;
|
|
*apehead = ape;
|
|
} else {
|
|
raw_print("syntax error in AUTOPICKUP_EXCEPTION");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
STATIC_OVL void
|
|
remove_autopickup_exception(whichape)
|
|
struct autopickup_exception *whichape;
|
|
{
|
|
struct autopickup_exception *ape, *prev = 0;
|
|
int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
|
|
|
|
for (ape = iflags.autopickup_exceptions[chain]; ape;) {
|
|
if (ape == whichape) {
|
|
struct autopickup_exception *freeape = ape;
|
|
ape = ape->next;
|
|
if (prev) prev->next = ape;
|
|
else iflags.autopickup_exceptions[chain] = ape;
|
|
free(freeape->pattern);
|
|
free(freeape);
|
|
} else {
|
|
prev = ape;
|
|
ape = ape->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC_OVL int
|
|
count_ape_maps(leave, grab)
|
|
int *leave, *grab;
|
|
{
|
|
struct autopickup_exception *ape;
|
|
int pass, totalapes, numapes[2] = {0,0};
|
|
|
|
for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
|
|
ape = iflags.autopickup_exceptions[pass];
|
|
while(ape) {
|
|
ape = ape->next;
|
|
numapes[pass]++;
|
|
}
|
|
}
|
|
totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
|
|
if (leave) *leave = numapes[AP_LEAVE];
|
|
if (grab) *grab = numapes[AP_GRAB];
|
|
return totalapes;
|
|
}
|
|
|
|
void
|
|
free_autopickup_exceptions()
|
|
{
|
|
struct autopickup_exception *ape;
|
|
int pass;
|
|
|
|
for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
|
|
while((ape = iflags.autopickup_exceptions[pass]) != 0) {
|
|
free(ape->pattern);
|
|
iflags.autopickup_exceptions[pass] = ape->next;
|
|
free(ape);
|
|
}
|
|
}
|
|
}
|
|
#endif /* AUTOPICKUP_EXCEPTIONS */
|
|
|
|
#ifdef LOADSYMSETS
|
|
/* bundle some common usage into one easy-to-use routine */
|
|
int
|
|
load_symset(s, which_set)
|
|
const char *s;
|
|
int which_set;
|
|
{
|
|
clear_symsetentry(which_set, TRUE);
|
|
|
|
symset[which_set].name = (char *)alloc(strlen(s)+1);
|
|
Strcpy(symset[which_set].name,s);
|
|
if (read_sym_file(which_set))
|
|
switch_symbols(TRUE);
|
|
else {
|
|
clear_symsetentry(which_set, TRUE);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Parse the value of a SYMBOLS line from a config file */
|
|
void
|
|
parsesymbols(opts)
|
|
register char *opts;
|
|
{
|
|
int val;
|
|
char *op, *symname, *strval, *p;
|
|
struct symparse *symp;
|
|
|
|
if ((op = index(opts, ',')) != 0) {
|
|
*op++ = 0;
|
|
parsesymbols(op);
|
|
}
|
|
|
|
/* S_sample:string */
|
|
symname = opts;
|
|
strval = index(opts, ':');
|
|
if (!symname || !strval) return;
|
|
*strval++ = 0;
|
|
|
|
/* strip leading and trailing white space from symname */
|
|
while (isspace(*symname)) symname++;
|
|
p = eos(symname);
|
|
while (--p >= symname && isspace(*p)) *p = '\0';
|
|
|
|
/* strip leading and trailing white space from strval */
|
|
while (isspace(*strval)) strval++;
|
|
p = eos(strval);
|
|
while (--p >= strval && isspace(*p)) *p = '\0';
|
|
|
|
symp = match_sym(symname);
|
|
if (!symp) return;
|
|
|
|
if (symp->range && symp->range != SYM_CONTROL) {
|
|
val = sym_val(strval);
|
|
update_l_symset(symp, val);
|
|
}
|
|
}
|
|
|
|
struct symparse *
|
|
match_sym(buf)
|
|
char *buf;
|
|
{
|
|
size_t len = strlen(buf);
|
|
const char *p = index(buf, ':'),
|
|
*q = index(buf, '=');
|
|
struct symparse *sp = loadsyms;
|
|
|
|
if (!p || (q && q < p)) p = q;
|
|
while(p && p > buf && isspace(*(p-1))) p--;
|
|
if (p) len = (int)(p - buf);
|
|
while(sp->range) {
|
|
if ((len >= strlen(sp->name)) && !strncmpi(buf, sp->name, len))
|
|
return sp;
|
|
sp++;
|
|
}
|
|
return (struct symparse *)0;
|
|
}
|
|
#endif /*LOADSYMSETS*/
|
|
|
|
/* data for option_help() */
|
|
static const char *opt_intro[] = {
|
|
"",
|
|
" NetHack Options Help:",
|
|
"",
|
|
#define CONFIG_SLOT 3 /* fill in next value at run-time */
|
|
(char *)0,
|
|
#if !defined(MICRO) && !defined(MAC)
|
|
"or use `NETHACKOPTIONS=\"<options>\"' in your environment",
|
|
#endif
|
|
"(<options> is a list of options separated by commas)",
|
|
#ifdef VMS
|
|
"-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
|
|
#endif
|
|
"or press \"O\" while playing and use the menu.",
|
|
"",
|
|
"Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
|
|
(char *)0
|
|
};
|
|
|
|
static const char *opt_epilog[] = {
|
|
"",
|
|
"Some of the options can be set only before the game is started; those",
|
|
"items will not be selectable in the 'O' command's menu.",
|
|
(char *)0
|
|
};
|
|
|
|
void
|
|
option_help()
|
|
{
|
|
char buf[BUFSZ], buf2[BUFSZ];
|
|
register int i;
|
|
winid datawin;
|
|
|
|
datawin = create_nhwindow(NHW_TEXT);
|
|
Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
|
|
opt_intro[CONFIG_SLOT] = (const char *) buf;
|
|
for (i = 0; opt_intro[i]; i++)
|
|
putstr(datawin, 0, opt_intro[i]);
|
|
|
|
/* Boolean options */
|
|
for (i = 0; boolopt[i].name; i++) {
|
|
if (boolopt[i].addr) {
|
|
#ifdef WIZARD
|
|
if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
|
|
if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
|
|
#endif
|
|
next_opt(datawin, boolopt[i].name);
|
|
}
|
|
}
|
|
next_opt(datawin, "");
|
|
|
|
/* Compound options */
|
|
putstr(datawin, 0, "Compound options:");
|
|
for (i = 0; compopt[i].name; i++) {
|
|
Sprintf(buf2, "`%s'", compopt[i].name);
|
|
Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
|
|
compopt[i+1].name ? ',' : '.');
|
|
putstr(datawin, 0, buf);
|
|
}
|
|
|
|
for (i = 0; opt_epilog[i]; i++)
|
|
putstr(datawin, 0, opt_epilog[i]);
|
|
|
|
display_nhwindow(datawin, FALSE);
|
|
destroy_nhwindow(datawin);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* prints the next boolean option, on the same line if possible, on a new
|
|
* line if not. End with next_opt("").
|
|
*/
|
|
void
|
|
next_opt(datawin, str)
|
|
winid datawin;
|
|
const char *str;
|
|
{
|
|
static char *buf = 0;
|
|
int i;
|
|
char *s;
|
|
|
|
if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';
|
|
|
|
if (!*str) {
|
|
s = eos(buf);
|
|
if (s > &buf[1] && s[-2] == ',')
|
|
Strcpy(s - 2, "."); /* replace last ", " */
|
|
i = COLNO; /* (greater than COLNO - 2) */
|
|
} else {
|
|
i = strlen(buf) + strlen(str) + 2;
|
|
}
|
|
|
|
if (i > COLNO - 2) { /* rule of thumb */
|
|
putstr(datawin, 0, buf);
|
|
buf[0] = 0;
|
|
}
|
|
if (*str) {
|
|
Strcat(buf, str);
|
|
Strcat(buf, ", ");
|
|
} else {
|
|
putstr(datawin, 0, str);
|
|
free(buf), buf = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Returns the fid of the fruit type; if that type already exists, it
|
|
* returns the fid of that one; if it does not exist, it adds a new fruit
|
|
* type to the chain and returns the new one.
|
|
*/
|
|
int
|
|
fruitadd(str)
|
|
char *str;
|
|
{
|
|
register int i;
|
|
register struct fruit *f;
|
|
int highest_fruit_id = 0;
|
|
char buf[PL_FSIZ], altname[PL_FSIZ];
|
|
boolean user_specified = (str == pl_fruit);
|
|
/* if not user-specified, then it's a fruit name for a fruit on
|
|
* a bones level...
|
|
*/
|
|
|
|
/* Note: every fruit has an id (kept in obj->spe) of at least 1;
|
|
* 0 is an error.
|
|
*/
|
|
if (user_specified) {
|
|
boolean found = FALSE, numeric = FALSE;
|
|
|
|
/* force fruit to be singular; this handling is not
|
|
needed--or wanted--for fruits from bones because
|
|
they already received it in their original game */
|
|
nmcpy(pl_fruit, makesingular(str), PL_FSIZ);
|
|
/* assert( str == pl_fruit ); */
|
|
|
|
/* disallow naming after other foods (since it'd be impossible
|
|
* to tell the difference)
|
|
*/
|
|
|
|
for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
|
|
i++) {
|
|
if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
{
|
|
char *c;
|
|
|
|
c = pl_fruit;
|
|
|
|
for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
|
|
;
|
|
if (isspace(*c) || *c == 0) numeric = TRUE;
|
|
}
|
|
if (found || numeric ||
|
|
!strncmp(str, "cursed ", 7) ||
|
|
!strncmp(str, "uncursed ", 9) ||
|
|
!strncmp(str, "blessed ", 8) ||
|
|
!strncmp(str, "partly eaten ", 13) ||
|
|
(!strncmp(str, "tin of ", 7) &&
|
|
(!strcmp(str+7, "spinach") ||
|
|
name_to_mon(str+7) >= LOW_PM)) ||
|
|
!strcmp(str, "empty tin") ||
|
|
((!strncmp(eos(str)-7," corpse",7) ||
|
|
!strncmp(eos(str)-4, " egg",4)) &&
|
|
name_to_mon(str) >= LOW_PM))
|
|
{
|
|
Strcpy(buf, pl_fruit);
|
|
Strcpy(pl_fruit, "candied ");
|
|
nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
|
|
}
|
|
*altname = '\0';
|
|
} else {
|
|
/* not user_supplied, so assumed to be from bones */
|
|
copynchars(altname, str, PL_FSIZ-1);
|
|
sanitize_name(altname);
|
|
}
|
|
for(f=ffruit; f; f = f->nextf) {
|
|
if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
|
|
if (!strncmp(str, f->fname, PL_FSIZ-1) ||
|
|
(*altname && !strcmp(altname, f->fname)))
|
|
goto nonew;
|
|
}
|
|
/* if adding another fruit would overflow spe, use a random
|
|
fruit instead... we've got a lot to choose from.
|
|
current_fruit remains as is. */
|
|
if (highest_fruit_id >= 127) return rnd(127);
|
|
|
|
f = newfruit();
|
|
copynchars(f->fname, *altname ? altname : str, PL_FSIZ-1);
|
|
f->fid = ++highest_fruit_id;
|
|
/* we used to go out of our way to add it at the end of the list,
|
|
but the order is arbitrary so use simpler insertion at start */
|
|
f->nextf = ffruit;
|
|
ffruit = f;
|
|
nonew:
|
|
if (user_specified) context.current_fruit = f->fid;
|
|
return f->fid;
|
|
}
|
|
|
|
/*
|
|
* This is a somewhat generic menu for taking a list of NetHack style
|
|
* class choices and presenting them via a description
|
|
* rather than the traditional NetHack characters.
|
|
* (Benefits users whose first exposure to NetHack is via tiles).
|
|
*
|
|
* prompt
|
|
* The title at the top of the menu.
|
|
*
|
|
* category: 0 = monster class
|
|
* 1 = object class
|
|
*
|
|
* way
|
|
* FALSE = PICK_ONE, TRUE = PICK_ANY
|
|
*
|
|
* class_list
|
|
* a null terminated string containing the list of choices.
|
|
*
|
|
* class_selection
|
|
* a null terminated string containing the selected characters.
|
|
*
|
|
* Returns number selected.
|
|
*/
|
|
int
|
|
choose_classes_menu(prompt, category, way, class_list, class_select)
|
|
const char *prompt;
|
|
int category;
|
|
boolean way;
|
|
char *class_list;
|
|
char *class_select;
|
|
{
|
|
menu_item *pick_list = (menu_item *)0;
|
|
winid win;
|
|
anything any;
|
|
char buf[BUFSZ];
|
|
int i, n;
|
|
int ret;
|
|
int next_accelerator, accelerator;
|
|
|
|
if (class_list == (char *)0 || class_select == (char *)0) return 0;
|
|
accelerator = 0;
|
|
next_accelerator = 'a';
|
|
any = zeroany;
|
|
win = create_nhwindow(NHW_MENU);
|
|
start_menu(win);
|
|
while (*class_list) {
|
|
const char *text;
|
|
boolean selected;
|
|
|
|
text = (char *)0;
|
|
selected = FALSE;
|
|
switch (category) {
|
|
case 0:
|
|
text = def_monsyms[def_char_to_monclass(*class_list)].explain;
|
|
accelerator = *class_list;
|
|
Sprintf(buf, "%s", text);
|
|
break;
|
|
case 1:
|
|
text = def_oc_syms[def_char_to_objclass(*class_list)].explain;
|
|
accelerator = next_accelerator;
|
|
Sprintf(buf, "%c %s", *class_list, text);
|
|
break;
|
|
default:
|
|
impossible("choose_classes_menu: invalid category %d",
|
|
category);
|
|
}
|
|
if (way && *class_select) { /* Selections there already */
|
|
if (index(class_select, *class_list)) {
|
|
selected = TRUE;
|
|
}
|
|
}
|
|
any.a_int = *class_list;
|
|
add_menu(win, NO_GLYPH, &any, accelerator,
|
|
category ? *class_list : 0,
|
|
ATR_NONE, buf, selected);
|
|
++class_list;
|
|
if (category > 0) {
|
|
++next_accelerator;
|
|
if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
|
|
if (next_accelerator == ('Z' + 1)) break;
|
|
}
|
|
}
|
|
end_menu(win, prompt);
|
|
n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
|
|
destroy_nhwindow(win);
|
|
if (n > 0) {
|
|
for (i = 0; i < n; ++i)
|
|
*class_select++ = (char)pick_list[i].item.a_int;
|
|
free((genericptr_t)pick_list);
|
|
ret = n;
|
|
} else if (n == -1) {
|
|
class_select = eos(class_select);
|
|
ret = -1;
|
|
} else
|
|
ret = 0;
|
|
*class_select = '\0';
|
|
return ret;
|
|
}
|
|
|
|
struct wc_Opt wc_options[] = {
|
|
{"ascii_map", WC_ASCII_MAP},
|
|
{"color", WC_COLOR},
|
|
{"eight_bit_tty", WC_EIGHT_BIT_IN},
|
|
{"hilite_pet", WC_HILITE_PET},
|
|
{"popup_dialog", WC_POPUP_DIALOG},
|
|
{"player_selection", WC_PLAYER_SELECTION},
|
|
{"preload_tiles", WC_PRELOAD_TILES},
|
|
{"tiled_map", WC_TILED_MAP},
|
|
{"tile_file", WC_TILE_FILE},
|
|
{"tile_width", WC_TILE_WIDTH},
|
|
{"tile_height", WC_TILE_HEIGHT},
|
|
{"use_inverse", WC_INVERSE},
|
|
{"align_message", WC_ALIGN_MESSAGE},
|
|
{"align_status", WC_ALIGN_STATUS},
|
|
{"font_map", WC_FONT_MAP},
|
|
{"font_menu", WC_FONT_MENU},
|
|
{"font_message",WC_FONT_MESSAGE},
|
|
#if 0
|
|
{"perm_invent",WC_PERM_INVENT},
|
|
#endif
|
|
{"font_size_map", WC_FONTSIZ_MAP},
|
|
{"font_size_menu", WC_FONTSIZ_MENU},
|
|
{"font_size_message", WC_FONTSIZ_MESSAGE},
|
|
{"font_size_status", WC_FONTSIZ_STATUS},
|
|
{"font_size_text", WC_FONTSIZ_TEXT},
|
|
{"font_status", WC_FONT_STATUS},
|
|
{"font_text", WC_FONT_TEXT},
|
|
{"map_mode", WC_MAP_MODE},
|
|
{"scroll_amount", WC_SCROLL_AMOUNT},
|
|
{"scroll_margin", WC_SCROLL_MARGIN},
|
|
{"splash_screen", WC_SPLASH_SCREEN},
|
|
{"vary_msgcount",WC_VARY_MSGCOUNT},
|
|
{"windowcolors", WC_WINDOWCOLORS},
|
|
{"mouse_support", WC_MOUSE_SUPPORT},
|
|
{(char *)0, 0L}
|
|
};
|
|
|
|
struct wc_Opt wc2_options[] = {
|
|
{"fullscreen", WC2_FULLSCREEN},
|
|
{"softkeyboard", WC2_SOFTKEYBOARD},
|
|
{"wraptext", WC2_WRAPTEXT},
|
|
#ifdef STATUS_VIA_WINDOWPORT
|
|
{"hilite_status", WC2_HILITE_STATUS},
|
|
#endif
|
|
{(char *)0, 0L}
|
|
};
|
|
|
|
/*
|
|
* If a port wants to change or ensure that the SET_IN_SYS,
|
|
* SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
|
|
* correct (for controlling its display in the option menu) call
|
|
* set_option_mod_status()
|
|
* with the appropriate second argument.
|
|
*/
|
|
void
|
|
set_option_mod_status(optnam, status)
|
|
const char *optnam;
|
|
int status;
|
|
{
|
|
int k;
|
|
if ( SET__IS_VALUE_VALID(status) ) {
|
|
impossible("set_option_mod_status: status out of range %d.",
|
|
status);
|
|
return;
|
|
}
|
|
for (k = 0; boolopt[k].name; k++) {
|
|
if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
|
|
boolopt[k].optflags = status;
|
|
return;
|
|
}
|
|
}
|
|
for (k = 0; compopt[k].name; k++) {
|
|
if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
|
|
compopt[k].optflags = status;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* You can set several wc_options in one call to
|
|
* set_wc_option_mod_status() by setting
|
|
* the appropriate bits for each option that you
|
|
* are setting in the optmask argument
|
|
* prior to calling.
|
|
* example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME);
|
|
*/
|
|
void
|
|
set_wc_option_mod_status(optmask, status)
|
|
unsigned long optmask;
|
|
int status;
|
|
{
|
|
int k = 0;
|
|
if ( SET__IS_VALUE_VALID(status) ) {
|
|
impossible("set_wc_option_mod_status: status out of range %d.",
|
|
status);
|
|
return;
|
|
}
|
|
while (wc_options[k].wc_name) {
|
|
if (optmask & wc_options[k].wc_bit) {
|
|
set_option_mod_status(wc_options[k].wc_name, status);
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
|
|
STATIC_OVL boolean
|
|
is_wc_option(optnam)
|
|
const char *optnam;
|
|
{
|
|
int k = 0;
|
|
while (wc_options[k].wc_name) {
|
|
if (strcmp(wc_options[k].wc_name, optnam) == 0)
|
|
return TRUE;
|
|
k++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
STATIC_OVL boolean
|
|
wc_supported(optnam)
|
|
const char *optnam;
|
|
{
|
|
int k = 0;
|
|
while (wc_options[k].wc_name) {
|
|
if (!strcmp(wc_options[k].wc_name, optnam) &&
|
|
(windowprocs.wincap & wc_options[k].wc_bit))
|
|
return TRUE;
|
|
k++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* You can set several wc2_options in one call to
|
|
* set_wc2_option_mod_status() by setting
|
|
* the appropriate bits for each option that you
|
|
* are setting in the optmask argument
|
|
* prior to calling.
|
|
* example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
|
|
*/
|
|
|
|
void
|
|
set_wc2_option_mod_status(optmask, status)
|
|
unsigned long optmask;
|
|
int status;
|
|
{
|
|
int k = 0;
|
|
if ( SET__IS_VALUE_VALID(status) ) {
|
|
impossible("set_wc2_option_mod_status: status out of range %d.",
|
|
status);
|
|
return;
|
|
}
|
|
while (wc2_options[k].wc_name) {
|
|
if (optmask & wc2_options[k].wc_bit) {
|
|
set_option_mod_status(wc2_options[k].wc_name, status);
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
|
|
STATIC_OVL boolean
|
|
is_wc2_option(optnam)
|
|
const char *optnam;
|
|
{
|
|
int k = 0;
|
|
while (wc2_options[k].wc_name) {
|
|
if (strcmp(wc2_options[k].wc_name, optnam) == 0)
|
|
return TRUE;
|
|
k++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
STATIC_OVL boolean
|
|
wc2_supported(optnam)
|
|
const char *optnam;
|
|
{
|
|
int k = 0;
|
|
while (wc2_options[k].wc_name) {
|
|
if (!strcmp(wc2_options[k].wc_name, optnam) &&
|
|
(windowprocs.wincap2 & wc2_options[k].wc_bit))
|
|
return TRUE;
|
|
k++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
STATIC_OVL void
|
|
wc_set_font_name(opttype, fontname)
|
|
int opttype;
|
|
char *fontname;
|
|
{
|
|
char **fn = (char **)0;
|
|
if (!fontname) return;
|
|
switch(opttype) {
|
|
case MAP_OPTION:
|
|
fn = &iflags.wc_font_map;
|
|
break;
|
|
case MESSAGE_OPTION:
|
|
fn = &iflags.wc_font_message;
|
|
break;
|
|
case TEXT_OPTION:
|
|
fn = &iflags.wc_font_text;
|
|
break;
|
|
case MENU_OPTION:
|
|
fn = &iflags.wc_font_menu;
|
|
break;
|
|
case STATUS_OPTION:
|
|
fn = &iflags.wc_font_status;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
if (fn) {
|
|
if (*fn) free(*fn);
|
|
*fn = (char *)alloc(strlen(fontname) + 1);
|
|
Strcpy(*fn, fontname);
|
|
}
|
|
return;
|
|
}
|
|
|
|
STATIC_OVL int
|
|
wc_set_window_colors(op)
|
|
char *op;
|
|
{
|
|
/* syntax:
|
|
* menu white/black message green/yellow status white/blue text white/black
|
|
*/
|
|
|
|
int j;
|
|
char buf[BUFSZ];
|
|
char *wn, *tfg, *tbg, *newop;
|
|
static const char *wnames[] = { "menu", "message", "status", "text" };
|
|
static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
|
|
static char **fgp[] = {
|
|
&iflags.wc_foregrnd_menu,
|
|
&iflags.wc_foregrnd_message,
|
|
&iflags.wc_foregrnd_status,
|
|
&iflags.wc_foregrnd_text
|
|
};
|
|
static char **bgp[] = {
|
|
&iflags.wc_backgrnd_menu,
|
|
&iflags.wc_backgrnd_message,
|
|
&iflags.wc_backgrnd_status,
|
|
&iflags.wc_backgrnd_text
|
|
};
|
|
|
|
Strcpy(buf, op);
|
|
newop = mungspaces(buf);
|
|
while (newop && *newop) {
|
|
|
|
wn = tfg = tbg = (char *)0;
|
|
|
|
/* until first non-space in case there's leading spaces - before colorname*/
|
|
while(*newop && isspace(*newop)) newop++;
|
|
if (*newop) wn = newop;
|
|
else return 0;
|
|
|
|
/* until first space - colorname*/
|
|
while(*newop && !isspace(*newop)) newop++;
|
|
if (*newop) *newop = '\0';
|
|
else return 0;
|
|
newop++;
|
|
|
|
/* until first non-space - before foreground*/
|
|
while(*newop && isspace(*newop)) newop++;
|
|
if (*newop) tfg = newop;
|
|
else return 0;
|
|
|
|
/* until slash - foreground */
|
|
while(*newop && *newop != '/') newop++;
|
|
if (*newop) *newop = '\0';
|
|
else return 0;
|
|
newop++;
|
|
|
|
/* until first non-space (in case there's leading space after slash) - before background */
|
|
while(*newop && isspace(*newop)) newop++;
|
|
if (*newop) tbg = newop;
|
|
else return 0;
|
|
|
|
/* until first space - background */
|
|
while(*newop && !isspace(*newop)) newop++;
|
|
if (*newop) *newop++ = '\0';
|
|
|
|
for (j = 0; j < 4; ++j) {
|
|
if (!strcmpi(wn, wnames[j]) ||
|
|
!strcmpi(wn, shortnames[j])) {
|
|
if (tfg && !strstri(tfg, " ")) {
|
|
if (*fgp[j]) free(*fgp[j]);
|
|
*fgp[j] = (char *)alloc(strlen(tfg) + 1);
|
|
Strcpy(*fgp[j], tfg);
|
|
}
|
|
if (tbg && !strstri(tbg, " ")) {
|
|
if (*bgp[j]) free(*bgp[j]);
|
|
*bgp[j] = (char *)alloc(strlen(tbg) + 1);
|
|
Strcpy(*bgp[j], tbg);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* set up for wizard mode if player or save file has requested to it;
|
|
called from port-specific startup code to handle `nethack -D' or
|
|
OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
|
|
restoring a game which was saved in wizard mode */
|
|
void
|
|
set_playmode()
|
|
{
|
|
if (wizard) {
|
|
#ifdef WIZARD
|
|
if (authorize_wizard_mode())
|
|
Strcpy(plname, "wizard");
|
|
else
|
|
#endif
|
|
wizard = FALSE; /* not allowed or not available */
|
|
/* force explore mode if we didn't make it into wizard mode */
|
|
discover = !wizard;
|
|
iflags.deferred_X = FALSE;
|
|
}
|
|
/* don't need to do anything special for explore mode or normal play */
|
|
}
|
|
|
|
#endif /* OPTION_LISTS_ONLY */
|
|
|
|
/*options.c*/
|