Source:NetHack 3.6.1/src/options.c

From NetHackWiki
(Redirected from Source:Ref/initoptions)
Jump to: navigation, search

Below is the full text to options.c from the source code of NetHack 3.6.1. To link to a particular line, write [[Source:NetHack 3.6.1/src/options.c#line123]], for example.

Contents

Top of file

  1.  /* NetHack 3.6	options.c	$NHDT-Date: 1510963525 2017/11/18 00:05:25 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.319 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /*-Copyright (c) Michael Allison, 2008. */
  4.  /* NetHack may be freely redistributed.  See license for details. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

  1.  
  2.  #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
  3.  #include "config.h"
  4.  #include "objclass.h"
  5.  #include "flag.h"
  6.  NEARDATA struct flag flags; /* provide linkage */
  7.  #ifdef SYSFLAGS
  8.  NEARDATA struct sysflag sysflags; /* provide linkage */
  9.  #endif
  10.  NEARDATA struct instance_flags iflags; /* provide linkage */
  11.  #define static
  12.  #else
  13.  #include "hack.h"
  14.  #include "tcap.h"
  15.  #include <ctype.h>
  16.  #endif
  17.  
  18.  #define BACKWARD_COMPAT
  19.  #define WINTYPELEN 16
  20.  
  21.  #ifdef DEFAULT_WC_TILED_MAP
  22.  #define PREFER_TILED TRUE
  23.  #else
  24.  #define PREFER_TILED FALSE
  25.  #endif
  26.  
  27.  enum window_option_types {
  28.      MESSAGE_OPTION = 1,
  29.      STATUS_OPTION,
  30.      MAP_OPTION,
  31.      MENU_OPTION,
  32.      TEXT_OPTION
  33.  };
  34.  
  35.  #define PILE_LIMIT_DFLT 5
  36.  
  37.  /*
  38.   *  NOTE:  If you add (or delete) an option, please update the short
  39.   *  options help (option_help()), the long options help (dat/opthelp),
  40.   *  and the current options setting display function (doset()),
  41.   *  and also the Guidebooks.
  42.   *
  43.   *  The order matters.  If an option is a an initial substring of another
  44.   *  option (e.g. time and timed_delay) the shorter one must come first.
  45.   */
  46.  
  47.  static struct Bool_Opt {
  48.      const char *name;
  49.      boolean *addr, initvalue;
  50.      int optflags;
  51.  } boolopt[] = {
  52.      { "acoustics", &flags.acoustics, TRUE, SET_IN_GAME },
  53.  #if defined(SYSFLAGS) && defined(AMIGA)
  54.      /* Amiga altmeta causes Alt+key to be converted into Meta+key by
  55.         low level nethack code; on by default, can be toggled off if
  56.         Alt+key is needed for some ASCII chars on non-ASCII keyboard */
  57.      { "altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME },
  58.  #else
  59.  #ifdef ALTMETA
  60.      /* non-Amiga altmeta causes nethack's top level command loop to treat
  61.         two character sequence "ESC c" as M-c, for terminals or emulators
  62.         which send "ESC c" when Alt+c is pressed; off by default, enabling
  63.         this can potentially make trouble if user types ESC when nethack
  64.         is honoring this conversion request (primarily after starting a
  65.         count prefix prior to a command and then deciding to cancel it) */
  66.      { "altmeta", &iflags.altmeta, FALSE, SET_IN_GAME },
  67.  #else
  68.      { "altmeta", (boolean *) 0, TRUE, DISP_IN_GAME },
  69.  #endif
  70.  #endif
  71.      { "ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME }, /*WC*/
  72.  #if defined(SYSFLAGS) && defined(MFLOPPY)
  73.      { "asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME },
  74.  #else
  75.      { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE },
  76.  #endif
  77.      { "autodescribe", &iflags.autodescribe, FALSE, SET_IN_GAME },
  78.      { "autodig", &flags.autodig, FALSE, SET_IN_GAME },
  79.      { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
  80.      { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
  81.      { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
  82.  #if defined(MICRO) && !defined(AMIGA)
  83.      { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
  84.  #else
  85.      { "BIOS", (boolean *) 0, FALSE, SET_IN_FILE },
  86.  #endif
  87.      { "blind", &u.uroleplay.blind, FALSE, DISP_IN_GAME },
  88.      { "bones", &flags.bones, TRUE, SET_IN_FILE },
  89.  #ifdef INSURANCE
  90.      { "checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME },
  91.  #else
  92.      { "checkpoint", (boolean *) 0, FALSE, SET_IN_FILE },
  93.  #endif
  94.  #ifdef MFLOPPY
  95.      { "checkspace", &iflags.checkspace, TRUE, SET_IN_GAME },
  96.  #else
  97.      { "checkspace", (boolean *) 0, FALSE, SET_IN_FILE },
  98.  #endif
  99.      { "clicklook", &iflags.clicklook, FALSE, SET_IN_GAME },
  100.      { "cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME },
  101.  #if defined(MICRO) || defined(WIN32)
  102.      { "color", &iflags.wc_color, TRUE, SET_IN_GAME }, /*WC*/
  103.  #else /* systems that support multiple terminals, many monochrome */
  104.      { "color", &iflags.wc_color, FALSE, SET_IN_GAME }, /*WC*/
  105.  #endif
  106.      { "confirm", &flags.confirm, TRUE, SET_IN_GAME },
  107.      { "dark_room", &flags.dark_room, TRUE, SET_IN_GAME },
  108.      { "eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME }, /*WC*/
  109.  #ifdef TTY_GRAPHICS
  110.      { "extmenu", &iflags.extmenu, FALSE, SET_IN_GAME },
  111.  #else
  112.      { "extmenu", (boolean *) 0, FALSE, SET_IN_FILE },
  113.  #endif
  114.  #ifdef OPT_DISPMAP
  115.      { "fast_map", &flags.fast_map, TRUE, SET_IN_GAME },
  116.  #else
  117.      { "fast_map", (boolean *) 0, TRUE, SET_IN_FILE },
  118.  #endif
  119.      { "female", &flags.female, FALSE, DISP_IN_GAME },
  120.      { "fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME },
  121.  #if defined(SYSFLAGS) && defined(AMIFLUSH)
  122.      { "flush", &sysflags.amiflush, FALSE, SET_IN_GAME },
  123.  #else
  124.      { "flush", (boolean *) 0, FALSE, SET_IN_FILE },
  125.  #endif
  126.      { "force_invmenu", &iflags.force_invmenu, FALSE, SET_IN_GAME },
  127.      { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE },
  128.      { "goldX", &iflags.goldX, FALSE, SET_IN_GAME },
  129.      { "help", &flags.help, TRUE, SET_IN_GAME },
  130.      { "herecmd_menu", &iflags.herecmd_menu, FALSE, SET_IN_GAME },
  131.      { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
  132.      { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME },
  133.      { "hitpointbar", &iflags.wc2_hitpointbar, FALSE, SET_IN_GAME }, /*WC2*/
  134.  #ifndef MAC
  135.      { "ignintr", &flags.ignintr, FALSE, SET_IN_GAME },
  136.  #else
  137.      { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE },
  138.  #endif
  139.      { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME },
  140.      { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */
  141.      { "legacy", &flags.legacy, TRUE, DISP_IN_GAME },
  142.      { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME },
  143.      { "lootabc", &flags.lootabc, FALSE, SET_IN_GAME },
  144.  #ifdef MAIL
  145.      { "mail", &flags.biff, TRUE, SET_IN_GAME },
  146.  #else
  147.      { "mail", (boolean *) 0, TRUE, SET_IN_FILE },
  148.  #endif
  149.      { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME },
  150.      { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME },
  151.      /* for menu debugging only*/
  152.      { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_WIZGAME },
  153.      { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME },
  154.  #ifdef TTY_GRAPHICS
  155.      { "menu_overlay", &iflags.menu_overlay, TRUE, SET_IN_GAME },
  156.  #else
  157.      { "menu_overlay", (boolean *) 0, FALSE, SET_IN_FILE },
  158.  #endif
  159.      { "mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME }, /*WC*/
  160.  #ifdef NEWS
  161.      { "news", &iflags.news, TRUE, DISP_IN_GAME },
  162.  #else
  163.      { "news", (boolean *) 0, FALSE, SET_IN_FILE },
  164.  #endif
  165.      { "nudist", &u.uroleplay.nudist, FALSE, DISP_IN_GAME },
  166.      { "null", &flags.null, TRUE, SET_IN_GAME },
  167.  #if defined(SYSFLAGS) && defined(MAC)
  168.      { "page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME },
  169.  #else
  170.      { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE },
  171.  #endif
  172.      { "perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME },
  173.      { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME },
  174.      { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME },   /*WC*/
  175.      { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/
  176.      { "pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME },
  177.  #if defined(MICRO) && !defined(AMIGA)
  178.      { "rawio", &iflags.rawio, FALSE, DISP_IN_GAME },
  179.  #else
  180.      { "rawio", (boolean *) 0, FALSE, SET_IN_FILE },
  181.  #endif
  182.      { "rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME },
  183.  #ifdef RLECOMP
  184.      { "rlecomp", &iflags.rlecomp,
  185.  #if defined(COMPRESS) || defined(ZLIB_COMP)
  186.        FALSE,
  187.  #else
  188.        TRUE,
  189.  #endif
  190.        DISP_IN_GAME },
  191.  #endif
  192.      { "safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME },
  193.      { "sanity_check", &iflags.sanity_check, FALSE, SET_IN_WIZGAME },
  194.      { "selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME }, /*WC*/
  195.      { "showexp", &flags.showexp, FALSE, SET_IN_GAME },
  196.      { "showrace", &flags.showrace, FALSE, SET_IN_GAME },
  197.  #ifdef SCORE_ON_BOTL
  198.      { "showscore", &flags.showscore, FALSE, SET_IN_GAME },
  199.  #else
  200.      { "showscore", (boolean *) 0, FALSE, SET_IN_FILE },
  201.  #endif
  202.      { "silent", &flags.silent, TRUE, SET_IN_GAME },
  203.      { "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE },
  204.      { "sortpack", &flags.sortpack, TRUE, SET_IN_GAME },
  205.      { "sparkle", &flags.sparkle, TRUE, SET_IN_GAME },
  206.      { "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/
  207.      { "standout", &flags.standout, FALSE, SET_IN_GAME },
  208.      { "status_updates", &iflags.status_updates, TRUE, DISP_IN_GAME },
  209.      { "tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME }, /*WC*/
  210.      { "time", &flags.time, FALSE, SET_IN_GAME },
  211.  #ifdef TIMED_DELAY
  212.      { "timed_delay", &flags.nap, TRUE, SET_IN_GAME },
  213.  #else
  214.      { "timed_delay", (boolean *) 0, FALSE, SET_IN_GAME },
  215.  #endif
  216.      { "tombstone", &flags.tombstone, TRUE, SET_IN_GAME },
  217.      { "toptenwin", &iflags.toptenwin, FALSE, SET_IN_GAME },
  218.      { "travel", &flags.travelcmd, TRUE, SET_IN_GAME },
  219.      { "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE },
  220.  #ifdef WIN32
  221.      { "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/
  222.  #else
  223.      { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/
  224.  #endif
  225.      { "verbose", &flags.verbose, TRUE, SET_IN_GAME },
  226.  #ifdef TTY_TILES_ESCCODES
  227.      { "vt_tiledata", &iflags.vt_tiledata, FALSE, SET_IN_FILE },
  228.  #else
  229.      { "vt_tiledata", (boolean *) 0, FALSE, SET_IN_FILE },
  230.  #endif
  231.      { "whatis_menu", &iflags.getloc_usemenu, FALSE, SET_IN_GAME },
  232.      { "whatis_moveskip", &iflags.getloc_moveskip, FALSE, SET_IN_GAME },
  233.      { "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME },
  234.      { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME },
  235.  #ifdef ZEROCOMP
  236.      { "zerocomp", &iflags.zerocomp,
  237.  #if defined(COMPRESS) || defined(ZLIB_COMP)
  238.        FALSE,
  239.  #else
  240.        TRUE,
  241.  #endif
  242.        DISP_IN_GAME },
  243.  #endif
  244.      { (char *) 0, (boolean *) 0, FALSE, 0 }
  245.  };
  246.  
  247.  /* compound options, for option_help() and external programs like Amiga
  248.   * frontend */
  249.  static struct Comp_Opt {
  250.      const char *name, *descr;
  251.      int size; /* for frontends and such allocating space --
  252.                 * usually allowed size of data in game, but
  253.                 * occasionally maximum reasonable size for
  254.                 * typing when game maintains information in
  255.                 * a different format */
  256.      int optflags;
  257.  } compopt[] = {
  258.      { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
  259.        DISP_IN_GAME },
  260.      { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
  261.      { "align_status", "status window alignment", 20, DISP_IN_GAME },   /*WC*/
  262.      { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
  263.  #ifdef BACKWARD_COMPAT
  264.      { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
  265.        SET_IN_GAME },
  266.  #endif
  267.      { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
  268.        PL_PSIZ, DISP_IN_GAME },
  269.      { "disclose", "the kinds of information to disclose at end of game",
  270.        sizeof(flags.end_disclose) * 2, SET_IN_GAME },
  271.      { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ,
  272.        DISP_IN_GAME },
  273.      { "dungeon", "the symbols to use in drawing the dungeon map",
  274.        MAXDCHARS + 1, SET_IN_FILE },
  275.      { "effects", "the symbols to use in drawing special effects",
  276.        MAXECHARS + 1, SET_IN_FILE },
  277.      { "font_map", "the font to use in the map window", 40,
  278.        DISP_IN_GAME },                                              /*WC*/
  279.      { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
  280.      { "font_message", "the font to use in the message window", 40,
  281.        DISP_IN_GAME },                                                  /*WC*/
  282.      { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
  283.      { "font_size_menu", "the size of the menu font", 20,
  284.        DISP_IN_GAME }, /*WC*/
  285.      { "font_size_message", "the size of the message font", 20,
  286.        DISP_IN_GAME }, /*WC*/
  287.      { "font_size_status", "the size of the status font", 20,
  288.        DISP_IN_GAME }, /*WC*/
  289.      { "font_size_text", "the size of the text font", 20,
  290.        DISP_IN_GAME }, /*WC*/
  291.      { "font_status", "the font to use in status window", 40,
  292.        DISP_IN_GAME }, /*WC*/
  293.      { "font_text", "the font to use in text windows", 40,
  294.        DISP_IN_GAME }, /*WC*/
  295.      { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME },
  296.      { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME },
  297.      { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
  298.        PL_PSIZ, DISP_IN_GAME },
  299.      { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
  300.      { "menustyle", "user interface for object selection", MENUTYPELEN,
  301.        SET_IN_GAME },
  302.      { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
  303.      { "menu_deselect_page", "deselect all items on this page of a menu", 4,
  304.        SET_IN_FILE },
  305.      { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE },
  306.      { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME },
  307.      { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
  308.      { "menu_invert_page", "invert all items on this page of a menu", 4,
  309.        SET_IN_FILE },
  310.      { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
  311.      { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
  312.      { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
  313.      { "menu_search", "search for a menu item", 4, SET_IN_FILE },
  314.      { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
  315.      { "menu_select_page", "select all items on this page of a menu", 4,
  316.        SET_IN_FILE },
  317.      { "monsters", "the symbols to use for monsters", MAXMCLASSES,
  318.        SET_IN_FILE },
  319.      { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME },
  320.  #ifdef TTY_GRAPHICS
  321.      { "msg_window", "the type of message window required", 1, SET_IN_GAME },
  322.  #else
  323.      { "msg_window", "the type of message window required", 1, SET_IN_FILE },
  324.  #endif
  325.      { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ,
  326.        DISP_IN_GAME },
  327.      { "number_pad", "use the number pad for movement", 1, SET_IN_GAME },
  328.      { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE },
  329.      { "packorder", "the inventory order of the items in your pack",
  330.        MAXOCLASSES, SET_IN_GAME },
  331.  #ifdef CHANGE_COLOR
  332.      { "palette",
  333.  #ifndef WIN32
  334.        "palette (00c/880/-fff is blue/yellow/reverse white)", 15,
  335.        SET_IN_GAME },
  336.  #else
  337.        "palette (adjust an RGB color in palette (color-R-G-B)", 15,
  338.        SET_IN_FILE },
  339.  #endif
  340.  #if defined(MAC)
  341.      { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE },
  342.  #endif
  343.  #endif
  344.      { "paranoid_confirmation", "extra prompting in certain situations", 28,
  345.        SET_IN_GAME },
  346.      { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
  347.      { "pickup_burden", "maximum burden picked up before prompt", 20,
  348.        SET_IN_GAME },
  349.      { "pickup_types", "types of objects to pick up automatically",
  350.        MAXOCLASSES, SET_IN_GAME },
  351.      { "pile_limit", "threshold for \"there are many objects here\"", 24,
  352.        SET_IN_GAME },
  353.      { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
  354.        DISP_IN_GAME },
  355.      { "player_selection", "choose character via dialog or prompts", 12,
  356.        DISP_IN_GAME },
  357.      { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ,
  358.        DISP_IN_GAME },
  359.      { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ,
  360.        DISP_IN_GAME },
  361.      { "runmode", "display frequency when `running' or `travelling'",
  362.        sizeof "teleport", SET_IN_GAME },
  363.      { "scores", "the parts of the score list you wish to see", 32,
  364.        SET_IN_GAME },
  365.      { "scroll_amount", "amount to scroll map when scroll_margin is reached",
  366.        20, DISP_IN_GAME }, /*WC*/
  367.      { "scroll_margin", "scroll map when this far from the edge", 20,
  368.        DISP_IN_GAME }, /*WC*/
  369.      { "sortloot", "sort object selection lists by description", 4,
  370.        SET_IN_GAME },
  371.  #ifdef MSDOS
  372.      { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
  373.  #endif
  374.  #ifdef STATUS_HILITES
  375.      { "statushilites",
  376.        "0=no status highlighting, N=show highlights for N turns",
  377.        20, SET_IN_GAME },
  378.  #else
  379.      { "statushilites", "highlight control", 20, SET_IN_FILE },
  380.  #endif
  381.      { "symset", "load a set of display symbols from the symbols file", 70,
  382.        SET_IN_GAME },
  383.      { "roguesymset",
  384.        "load a set of rogue display symbols from the symbols file", 70,
  385.        SET_IN_GAME },
  386.  #ifdef WIN32
  387.      { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE },
  388.  #endif
  389.      { "suppress_alert", "suppress alerts about version-specific features", 8,
  390.        SET_IN_GAME },
  391.      { "tile_width", "width of tiles", 20, DISP_IN_GAME },   /*WC*/
  392.      { "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/
  393.      { "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/
  394.      { "traps", "the symbols to use in drawing traps", MAXTCHARS + 1,
  395.        SET_IN_FILE },
  396.      { "vary_msgcount", "show more old messages at a time", 20,
  397.        DISP_IN_GAME }, /*WC*/
  398.  #ifdef MSDOS
  399.      { "video", "method of video updating", 20, SET_IN_FILE },
  400.  #endif
  401.  #ifdef VIDEOSHADES
  402.      { "videocolors", "color mappings for internal screen routines", 40,
  403.        DISP_IN_GAME },
  404.      { "videoshades", "gray shades to map to black/gray/white", 32,
  405.        DISP_IN_GAME },
  406.  #endif
  407.      { "whatis_coord", "show coordinates when auto-describing cursor position",
  408.        1, SET_IN_GAME },
  409.      { "whatis_filter",
  410.        "filter coordinate locations when targeting next or previous",
  411.        1, SET_IN_GAME },
  412.      { "windowcolors", "the foreground/background colors of windows", /*WC*/
  413.        80, DISP_IN_GAME },
  414.      { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
  415.  #ifdef WINCHAIN
  416.      { "windowchain", "window processor to use", WINTYPELEN, SET_IN_SYS },
  417.  #endif
  418.  #ifdef BACKWARD_COMPAT
  419.      { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE },
  420.      { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE },
  421.  #ifdef MAC_GRAPHICS_ENV
  422.      { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE },
  423.  #endif
  424.  #endif
  425.      { (char *) 0, (char *) 0, 0, 0 }
  426.  };
  427.  
  428.  #ifdef OPTION_LISTS_ONLY
  429.  #undef static
  430.  
  431.  #else /* use rest of file */
  432.  
  433.  extern char configfile[]; /* for messages */
  434.  
  435.  extern struct symparse loadsyms[];
  436.  static boolean need_redraw; /* for doset() */
  437.  
  438.  #if defined(TOS) && defined(TEXTCOLOR)
  439.  extern boolean colors_changed;  /* in tos.c */
  440.  #endif
  441.  
  442.  #ifdef VIDEOSHADES
  443.  extern char *shade[3];          /* in sys/msdos/video.c */
  444.  extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
  445.  #endif
  446.  
  447.  static char def_inv_order[MAXOCLASSES] = {
  448.      COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
  449.      SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
  450.      TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
  451.  };
  452.  
  453.  /*
  454.   * Default menu manipulation command accelerators.  These may _not_ be:
  455.   *
  456.   *      + a number - reserved for counts
  457.   *      + an upper or lower case US ASCII letter - used for accelerators
  458.   *      + ESC - reserved for escaping the menu
  459.   *      + NULL, CR or LF - reserved for commiting the selection(s).  NULL
  460.   *        is kind of odd, but the tty's xwaitforspace() will return it if
  461.   *        someone hits a <ret>.
  462.   *      + a default object class symbol - used for object class accelerators
  463.   *
  464.   * Standard letters (for now) are:
  465.   *
  466.   *              <  back 1 page
  467.   *              >  forward 1 page
  468.   *              ^  first page
  469.   *              |  last page
  470.   *              :  search
  471.   *
  472.   *              page            all
  473.   *               ,    select     .
  474.   *               \    deselect   -
  475.   *               ~    invert     @
  476.   *
  477.   * The command name list is duplicated in the compopt array.
  478.   */
  479.  typedef struct {
  480.      const char *name;
  481.      char cmd;
  482.      const char *desc;
  483.  } menu_cmd_t;
  484.  
  485.  static const menu_cmd_t default_menu_cmd_info[] = {
  486.   { "menu_first_page", MENU_FIRST_PAGE, "Go to first page" },
  487.   { "menu_last_page", MENU_LAST_PAGE, "Go to last page" },
  488.   { "menu_next_page", MENU_NEXT_PAGE, "Go to next page" },
  489.   { "menu_previous_page", MENU_PREVIOUS_PAGE, "Go to previous page" },
  490.   { "menu_select_all", MENU_SELECT_ALL, "Select all items" },
  491.   { "menu_deselect_all", MENU_UNSELECT_ALL, "Unselect all items" },
  492.   { "menu_invert_all", MENU_INVERT_ALL, "Invert selection" },
  493.   { "menu_select_page", MENU_SELECT_PAGE, "Select items in current page" },
  494.   { "menu_deselect_page", MENU_UNSELECT_PAGE,
  495.     "Unselect items in current page" },
  496.   { "menu_invert_page", MENU_INVERT_PAGE, "Invert current page selection" },
  497.   { "menu_search", MENU_SEARCH, "Search and toggle matching items" },
  498.  };
  499.  
  500.  /*
  501.   * Allow the user to map incoming characters to various menu commands.
  502.   * The accelerator list must be a valid C string.
  503.   */
  504.  #define MAX_MENU_MAPPED_CMDS 32 /* some number */
  505.  char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
  506.  static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
  507.  static short n_menu_mapped = 0;
  508.  
  509.  static boolean initial, from_file;
  510.  
  511.  STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
  512.  STATIC_DCL void FDECL(escapes, (const char *, char *));
  513.  STATIC_DCL void FDECL(rejectoption, (const char *));
  514.  STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
  515.  STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
  516.  STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P));
  517.  STATIC_DCL int FDECL(change_inv_order, (char *));
  518.  STATIC_DCL boolean FDECL(warning_opts, (char *, const char *));
  519.  STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
  520.  STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
  521.  STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
  522.  
  523.  STATIC_DCL const char *FDECL(attr2attrname, (int));
  524.  STATIC_DCL const char * FDECL(msgtype2name, (int));
  525.  STATIC_DCL int NDECL(query_msgtype);
  526.  STATIC_DCL boolean FDECL(msgtype_add, (int, char *));
  527.  STATIC_DCL void FDECL(free_one_msgtype, (int));
  528.  STATIC_DCL int NDECL(msgtype_count);
  529.  STATIC_DCL boolean FDECL(test_regex_pattern, (const char *, const char *));
  530.  STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
  531.  STATIC_DCL void FDECL(free_one_menu_coloring, (int));
  532.  STATIC_DCL int NDECL(count_menucolors);
  533.  STATIC_DCL boolean FDECL(parse_role_opts, (BOOLEAN_P, const char *,
  534.                                             char *, char **));
  535.  
  536.  STATIC_DCL void FDECL(oc_to_str, (char *, char *));
  537.  STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
  538.  STATIC_DCL void FDECL(opts_add_others, (winid, const char *, int,
  539.                                          char *, int));
  540.  STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int));
  541.  STATIC_DCL boolean FDECL(special_handling, (const char *,
  542.                                              BOOLEAN_P, BOOLEAN_P));
  543.  STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
  544.  STATIC_DCL void FDECL(remove_autopickup_exception,
  545.                        (struct autopickup_exception *));
  546.  STATIC_DCL int FDECL(count_ape_maps, (int *, int *));
  547.  
  548.  STATIC_DCL boolean FDECL(is_wc_option, (const char *));
  549.  STATIC_DCL boolean FDECL(wc_supported, (const char *));
  550.  STATIC_DCL boolean FDECL(is_wc2_option, (const char *));
  551.  STATIC_DCL boolean FDECL(wc2_supported, (const char *));
  552.  STATIC_DCL void FDECL(wc_set_font_name, (int, char *));
  553.  STATIC_DCL int FDECL(wc_set_window_colors, (char *));
  554.  

reglyph_darkroom

  1.  void
  2.  reglyph_darkroom()
  3.  {
  4.      xchar x, y;
  5.  
  6.      for (x = 0; x < COLNO; x++)
  7.          for (y = 0; y < ROWNO; y++) {
  8.              struct rm *lev = &levl[x][y];
  9.  
  10.              if (!flags.dark_room || !iflags.use_color
  11.                  || Is_rogue_level(&u.uz)) {
  12.                  if (lev->glyph == cmap_to_glyph(S_darkroom))
  13.                      lev->glyph = lev->waslit ? cmap_to_glyph(S_room)
  14.                                               : cmap_to_glyph(S_stone);
  15.              } else {
  16.                  if (lev->glyph == cmap_to_glyph(S_room) && lev->seenv
  17.                      && lev->waslit && !cansee(x, y))
  18.                      lev->glyph = cmap_to_glyph(S_darkroom);
  19.                  else if (lev->glyph == cmap_to_glyph(S_stone)
  20.                           && lev->typ == ROOM && lev->seenv && !cansee(x, y))
  21.                      lev->glyph = cmap_to_glyph(S_darkroom);
  22.              }
  23.          }
  24.      if (flags.dark_room && iflags.use_color)
  25.          showsyms[S_darkroom] = showsyms[S_room];
  26.      else
  27.          showsyms[S_darkroom] = showsyms[S_stone];
  28.  }
  29.  

match_optname

  1.  /* check whether a user-supplied option string is a proper leading
  2.     substring of a particular option name; option string might have
  3.     a colon or equals sign and arbitrary value appended to it */
  4.  boolean
  5.  match_optname(user_string, opt_name, min_length, val_allowed)
  6.  const char *user_string, *opt_name;
  7.  int min_length;
  8.  boolean val_allowed;
  9.  {
  10.      int len = (int) strlen(user_string);
  11.  
  12.      if (val_allowed) {
  13.          const char *p = index(user_string, ':'),
  14.                     *q = index(user_string, '=');
  15.  
  16.          if (!p || (q && q < p))
  17.              p = q;
  18.          if (p) {
  19.              /* 'user_string' hasn't necessarily been through mungspaces()
  20.                 so might have tabs or consecutive spaces */
  21.              while (p > user_string && isspace((uchar) *(p - 1)))
  22.                  p--;
  23.              len = (int) (p - user_string);
  24.          }
  25.      }
  26.  
  27.      return (boolean) (len >= min_length
  28.                        && !strncmpi(opt_name, user_string, len));
  29.  }
  30.  

nh_getenv

  1.  /* most environment variables will eventually be printed in an error
  2.   * message if they don't work, and most error message paths go through
  3.   * BUFSZ buffers, which could be overflowed by a maliciously long
  4.   * environment variable.  If a variable can legitimately be long, or
  5.   * if it's put in a smaller buffer, the responsible code will have to
  6.   * bounds-check itself.
  7.   */
  8.  char *
  9.  nh_getenv(ev)
  10.  const char *ev;
  11.  {
  12.      char *getev = getenv(ev);
  13.  
  14.      if (getev && strlen(getev) <= (BUFSZ / 2))
  15.          return getev;
  16.      else
  17.          return (char *) 0;
  18.  }
  19.  

initoptions

  1.  /* process options, possibly including SYSCF */
  2.  void
  3.  initoptions()
  4.  {
  5.      initoptions_init();
  6.  #ifdef SYSCF
  7.  /* someday there may be other SYSCF alternatives besides text file */
  8.  #ifdef SYSCF_FILE
  9.      /* If SYSCF_FILE is specified, it _must_ exist... */
  10.      assure_syscf_file();
  11.      config_error_init(TRUE, SYSCF_FILE, FALSE);
  12.  
  13.      /* ... and _must_ parse correctly. */
  14.      if (!read_config_file(SYSCF_FILE, SET_IN_SYS)) {
  15.          if (config_error_done())
  16.              nh_terminate(EXIT_FAILURE);
  17.      }
  18.      config_error_done();
  19.      /*
  20.       * TODO [maybe]: parse the sysopt entries which are space-separated
  21.       * lists of usernames into arrays with one name per element.
  22.       */
  23.  #endif
  24.  #endif /* SYSCF */
  25.      initoptions_finish();
  26.  }
  27.  

initoptions_init

  1.  void
  2.  initoptions_init()
  3.  {
  4.  #if defined(UNIX) || defined(VMS)
  5.      char *opts;
  6.  #endif
  7.      int i;
  8.  
  9.      /* set up the command parsing */
  10.      reset_commands(TRUE); /* init */
  11.  
  12.      /* initialize the random number generator */
  13.      setrandom();
  14.  
  15.      /* for detection of configfile options specified multiple times */
  16.      iflags.opt_booldup = iflags.opt_compdup = (int *) 0;
  17.  
  18.      for (i = 0; boolopt[i].name; i++) {
  19.          if (boolopt[i].addr)
  20.              *(boolopt[i].addr) = boolopt[i].initvalue;
  21.      }
  22.  #if defined(COMPRESS) || defined(ZLIB_COMP)
  23.      set_savepref("externalcomp");
  24.      set_restpref("externalcomp");
  25.  #ifdef RLECOMP
  26.      set_savepref("!rlecomp");
  27.      set_restpref("!rlecomp");
  28.  #endif
  29.  #else
  30.  #ifdef ZEROCOMP
  31.      set_savepref("zerocomp");
  32.      set_restpref("zerocomp");
  33.  #endif
  34.  #ifdef RLECOMP
  35.      set_savepref("rlecomp");
  36.      set_restpref("rlecomp");
  37.  #endif
  38.  #endif
  39.  #ifdef SYSFLAGS
  40.      Strcpy(sysflags.sysflagsid, "sysflags");
  41.      sysflags.sysflagsid[9] = (char) sizeof(struct sysflag);
  42.  #endif
  43.      flags.end_own = FALSE;
  44.      flags.end_top = 3;
  45.      flags.end_around = 2;
  46.      flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */
  47.      flags.pile_limit = PILE_LIMIT_DFLT;  /* 5 */
  48.      flags.runmode = RUN_LEAP;
  49.      iflags.msg_history = 20;
  50.  #ifdef TTY_GRAPHICS
  51.      iflags.prevmsg_window = 's';
  52.  #endif
  53.      iflags.menu_headings = ATR_INVERSE;
  54.      iflags.getpos_coords = GPCOORDS_NONE;
  55.  
  56.      /* hero's role, race, &c haven't been chosen yet */
  57.      flags.initrole = flags.initrace = flags.initgend = flags.initalign
  58.          = ROLE_NONE;
  59.  
  60.      /* Set the default monster and object class symbols. */
  61.      init_symbols();
  62.      for (i = 0; i < WARNCOUNT; i++)
  63.          warnsyms[i] = def_warnsyms[i].sym;
  64.      iflags.bouldersym = 0;
  65.  
  66.      iflags.travelcc.x = iflags.travelcc.y = -1;
  67.  
  68.      /* for "special achievement" tracking (see obj.h,
  69.         create_object(sp_lev.c), addinv_core1(invent.c) */
  70.      iflags.mines_prize_type = LUCKSTONE;
  71.      iflags.soko_prize_type1 = BAG_OF_HOLDING;
  72.      iflags.soko_prize_type2 = AMULET_OF_REFLECTION;
  73.  
  74.      /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
  75.      (void) memcpy((genericptr_t) flags.inv_order,
  76.                    (genericptr_t) def_inv_order, sizeof flags.inv_order);
  77.      flags.pickup_types[0] = '\0';
  78.      flags.pickup_burden = MOD_ENCUMBER;
  79.      flags.sortloot = 'l'; /* sort only loot by default */
  80.  
  81.      for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
  82.          flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
  83.      switch_symbols(FALSE); /* set default characters */
  84.  #if defined(UNIX) && defined(TTY_GRAPHICS)
  85.      /*
  86.       * Set defaults for some options depending on what we can
  87.       * detect about the environment's capabilities.
  88.       * This has to be done after the global initialization above
  89.       * and before reading user-specific initialization via
  90.       * config file/environment variable below.
  91.       */
  92.      /* this detects the IBM-compatible console on most 386 boxes */
  93.      if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
  94.          if (!symset[PRIMARY].name)
  95.              load_symset("IBMGraphics", PRIMARY);
  96.          if (!symset[ROGUESET].name)
  97.              load_symset("RogueIBM", ROGUESET);
  98.          switch_symbols(TRUE);
  99.  #ifdef TEXTCOLOR
  100.          iflags.use_color = TRUE;
  101.  #endif
  102.      }
  103.  #endif /* UNIX && TTY_GRAPHICS */
  104.  #if defined(UNIX) || defined(VMS)
  105.  #ifdef TTY_GRAPHICS
  106.      /* detect whether a "vt" terminal can handle alternate charsets */
  107.      if ((opts = nh_getenv("TERM"))
  108.          /* [could also check "xterm" which emulates vtXXX by default] */
  109.          && !strncmpi(opts, "vt", 2)
  110.          && AS && AE && index(AS, '\016') && index(AE, '\017')) {
  111.          if (!symset[PRIMARY].name)
  112.              load_symset("DECGraphics", PRIMARY);
  113.          switch_symbols(TRUE);
  114.      }
  115.  #endif
  116.  #endif /* UNIX || VMS */
  117.  
  118.  #ifdef MAC_GRAPHICS_ENV
  119.      if (!symset[PRIMARY].name)
  120.          load_symset("MACGraphics", PRIMARY);
  121.      switch_symbols(TRUE);
  122.  #endif /* MAC_GRAPHICS_ENV */
  123.      flags.menu_style = MENU_FULL;
  124.  
  125.      /* since this is done before init_objects(), do partial init here */
  126.      objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
  127.      nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
  128.  }
  129.  

initoptions_finish

  1.  void
  2.  initoptions_finish()
  3.  {
  4.  #ifndef MAC
  5.      char *opts = getenv("NETHACKOPTIONS");
  6.  
  7.      if (!opts)
  8.          opts = getenv("HACKOPTIONS");
  9.      if (opts) {
  10.          if (*opts == '/' || *opts == '\\' || *opts == '@') {
  11.              if (*opts == '@')
  12.                  opts++; /* @filename */
  13.              /* looks like a filename */
  14.              if (strlen(opts) < BUFSZ / 2) {
  15.                  config_error_init(TRUE, opts, CONFIG_ERROR_SECURE);
  16.                  read_config_file(opts, SET_IN_FILE);
  17.                  config_error_done();
  18.              }
  19.          } else {
  20.              config_error_init(TRUE, (char *) 0, FALSE);
  21.              read_config_file((char *) 0, SET_IN_FILE);
  22.              config_error_done();
  23.              /* let the total length of options be long;
  24.               * parseoptions() will check each individually
  25.               */
  26.              config_error_init(FALSE, "NETHACKOPTIONS", FALSE);
  27.              (void) parseoptions(opts, TRUE, FALSE);
  28.              config_error_done();
  29.          }
  30.      } else
  31.  #endif /* !MAC */
  32.      /*else*/ {
  33.          config_error_init(TRUE, (char *) 0, FALSE);
  34.          read_config_file((char *) 0, SET_IN_FILE);
  35.          config_error_done();
  36.      }
  37.  
  38.      (void) fruitadd(pl_fruit, (struct fruit *) 0);
  39.      /*
  40.       * Remove "slime mold" from list of object names.  This will
  41.       * prevent it from being wished unless it's actually present
  42.       * as a named (or default) fruit.  Wishing for "fruit" will
  43.       * result in the player's preferred fruit [better than "\033"].
  44.       */
  45.      obj_descr[SLIME_MOLD].oc_name = "fruit";
  46.  
  47.      if (iflags.bouldersym)
  48.          update_bouldersym();
  49.      reglyph_darkroom();
  50.  
  51.  #ifdef STATUS_HILITES
  52.      /*
  53.       * A multi-interface binary might only support status highlighting
  54.       * for some of the interfaces; check whether we asked for it but are
  55.       * using one which doesn't.
  56.       */
  57.      if (iflags.hilite_delta && !wc2_supported("statushilites")) {
  58.          raw_printf("Status highlighting not supported for %s interface.",
  59.                     windowprocs.name);
  60.          iflags.hilite_delta = 0;
  61.      }
  62.  #endif
  63.      return;
  64.  }
  65.  

nmcpy

  1.  STATIC_OVL void
  2.  nmcpy(dest, src, maxlen)
  3.  char *dest;
  4.  const char *src;
  5.  int maxlen;
  6.  {
  7.      int count;
  8.  
  9.      for (count = 1; count < maxlen; count++) {
  10.          if (*src == ',' || *src == '\0')
  11.              break; /*exit on \0 terminator*/
  12.          *dest++ = *src++;
  13.      }
  14.      *dest = 0;
  15.  }
  16.  

escapes

  1.  /*
  2.   * escapes(): escape expansion for showsyms.  C-style escapes understood
  3.   * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
  4.   * The ^-prefix for control characters is also understood, and \[mM]
  5.   * has the effect of 'meta'-ing the value which follows (so that the
  6.   * alternate character set will be enabled).
  7.   *
  8.   * X     normal key X
  9.   * ^X    control-X
  10.   * \mX   meta-X
  11.   *
  12.   * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
  13.   * prior to terminating '\0' would pull that '\0' into the output and then
  14.   * keep processing past it, potentially overflowing the output buffer.
  15.   * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
  16.   * output and stop there; trailing \M will fall through to \<other> and
  17.   * yield 'M', then stop.  Any \X or \O followed by something other than
  18.   * an appropriate digit will also fall through to \<other> and yield 'X'
  19.   * or 'O', plus stop if the non-digit is end-of-string.
  20.   */
  21.  STATIC_OVL void
  22.  escapes(cp, tp)
  23.  const char *cp;
  24.  char *tp;
  25.  {
  26.      static NEARDATA const char oct[] = "01234567", dec[] = "0123456789",
  27.                                 hex[] = "00112233445566778899aAbBcCdDeEfF";
  28.      const char *dp;
  29.      int cval, meta, dcount;
  30.  
  31.      while (*cp) {
  32.          /* \M has to be followed by something to do meta conversion,
  33.             otherwise it will just be \M which ultimately yields 'M' */
  34.          meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
  35.          if (meta)
  36.              cp += 2;
  37.  
  38.          cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
  39.          if ((*cp != '\\' && *cp != '^') || !cp[1]) {
  40.              /* simple character, or nothing left for \ or ^ to escape */
  41.              cval = *cp++;
  42.          } else if (*cp == '^') { /* expand control-character syntax */
  43.              cval = (*++cp & 0x1f);
  44.              ++cp;
  45.  
  46.          /* remaining cases are all for backslash; we know cp[1] is not \0 */
  47.          } else if (index(dec, cp[1])) {
  48.              ++cp; /* move past backslash to first digit */
  49.              do {
  50.                  cval = (cval * 10) + (*cp - '0');
  51.              } while (*++cp && index(dec, *cp) && ++dcount < 3);
  52.          } else if ((cp[1] == 'o' || cp[1] == 'O') && cp[2]
  53.                     && index(oct, cp[2])) {
  54.              cp += 2; /* move past backslash and 'O' */
  55.              do {
  56.                  cval = (cval * 8) + (*cp - '0');
  57.              } while (*++cp && index(oct, *cp) && ++dcount < 3);
  58.          } else if ((cp[1] == 'x' || cp[1] == 'X') && cp[2]
  59.                     && (dp = index(hex, cp[2])) != 0) {
  60.              cp += 2; /* move past backslash and 'X' */
  61.              do {
  62.                  cval = (cval * 16) + ((int) (dp - hex) / 2);
  63.              } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
  64.          } else { /* C-style character escapes */
  65.              switch (*++cp) {
  66.              case '\\':
  67.                  cval = '\\';
  68.                  break;
  69.              case 'n':
  70.                  cval = '\n';
  71.                  break;
  72.              case 't':
  73.                  cval = '\t';
  74.                  break;
  75.              case 'b':
  76.                  cval = '\b';
  77.                  break;
  78.              case 'r':
  79.                  cval = '\r';
  80.                  break;
  81.              default:
  82.                  cval = *cp;
  83.              }
  84.              ++cp;
  85.          }
  86.  
  87.          if (meta)
  88.              cval |= 0x80;
  89.          *tp++ = (char) cval;
  90.      }
  91.      *tp = '\0';
  92.  }
  93.  

rejectoption

  1.  STATIC_OVL void
  2.  rejectoption(optname)
  3.  const char *optname;
  4.  {
  5.  #ifdef MICRO
  6.      pline("\"%s\" settable only from %s.", optname, configfile);
  7.  #else
  8.      pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
  9.            configfile);
  10.  #endif
  11.  }
  12.  
  13.  /*
  14.  
  15.  # errors:
  16.  OPTIONS=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  17.  OPTIONS
  18.  OPTIONS=
  19.  MSGTYPE=stop"You swap places with "
  20.  MSGTYPE=st.op "You swap places with "
  21.  MSGTYPE=stop "You swap places with \"
  22.  MENUCOLOR=" blessed "green&none
  23.  MENUCOLOR=" holy " = green&reverse
  24.  MENUCOLOR=" cursed " = red&uline
  25.  MENUCOLOR=" unholy " = reed
  26.  OPTIONS=!legacy:true,fooo
  27.  OPTIONS=align:!pin
  28.  OPTIONS=gender
  29.  
  30.  */
  31.  

string_for_opt

  1.  STATIC_OVL char *
  2.  string_for_opt(opts, val_optional)
  3.  char *opts;
  4.  boolean val_optional;
  5.  {
  6.      char *colon, *equals;
  7.  
  8.      colon = index(opts, ':');
  9.      equals = index(opts, '=');
  10.      if (!colon || (equals && equals < colon))
  11.          colon = equals;
  12.  
  13.      if (!colon || !*++colon) {
  14.          if (!val_optional)
  15.              config_error_add("Missing parameter for '%s'", opts);
  16.          return (char *) 0;
  17.      }
  18.      return colon;
  19.  }
  20.  

string_for_env_opt

  1.  STATIC_OVL char *
  2.  string_for_env_opt(optname, opts, val_optional)
  3.  const char *optname;
  4.  char *opts;
  5.  boolean val_optional;
  6.  {
  7.      if (!initial) {
  8.          rejectoption(optname);
  9.          return (char *) 0;
  10.      }
  11.      return string_for_opt(opts, val_optional);
  12.  }
  13.  

bad_negation

  1.  STATIC_OVL void
  2.  bad_negation(optname, with_parameter)
  3.  const char *optname;
  4.  boolean with_parameter;
  5.  {
  6.      pline_The("%s option may not %sbe negated.", optname,
  7.                with_parameter ? "both have a value and " : "");
  8.  }
  9.  

change_inv_order

  1.  /*
  2.   * Change the inventory order, using the given string as the new order.
  3.   * Missing characters in the new order are filled in at the end from
  4.   * the current inv_order, except for gold, which is forced to be first
  5.   * if not explicitly present.
  6.   *
  7.   * This routine returns 1 unless there is a duplicate or bad char in
  8.   * the string.
  9.   */
  10.  STATIC_OVL int
  11.  change_inv_order(op)
  12.  char *op;
  13.  {
  14.      int oc_sym, num;
  15.      char *sp, buf[QBUFSZ];
  16.      int retval = 1;
  17.  
  18.      num = 0;
  19.      if (!index(op, GOLD_SYM))
  20.          buf[num++] = COIN_CLASS;
  21.  
  22.      for (sp = op; *sp; sp++) {
  23.          boolean fail = FALSE;
  24.          oc_sym = def_char_to_objclass(*sp);
  25.          /* reject bad or duplicate entries */
  26.          if (oc_sym == MAXOCLASSES) { /* not an object class char */
  27.              config_error_add("Not an object class '%c'", *sp);
  28.              retval = 0;
  29.              fail = TRUE;
  30.          } else if (!index(flags.inv_order, oc_sym)) {
  31.              /* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
  32.                 because they aren't in def_inv_order[] so don't make it
  33.                 into flags.inv_order, hence always fail this index() test */
  34.              config_error_add("Object class '%c' not allowed", *sp);
  35.              retval = 0;
  36.              fail = TRUE;
  37.          } else if (index(sp + 1, *sp)) {
  38.              config_error_add("Duplicate object class '%c'", *sp);
  39.              retval = 0;
  40.              fail = TRUE;
  41.          }
  42.          /* retain good ones */
  43.          if (!fail)
  44.              buf[num++] = (char) oc_sym;
  45.      }
  46.      buf[num] = '\0';
  47.  
  48.      /* fill in any omitted classes, using previous ordering */
  49.      for (sp = flags.inv_order; *sp; sp++)
  50.          if (!index(buf, *sp))
  51.              (void) strkitten(&buf[num++], *sp);
  52.      buf[MAXOCLASSES - 1] = '\0';
  53.  
  54.      Strcpy(flags.inv_order, buf);
  55.      return retval;
  56.  }
  57.  

warning_opts

  1.  STATIC_OVL boolean
  2.  warning_opts(opts, optype)
  3.  register char *opts;
  4.  const char *optype;
  5.  {
  6.      uchar translate[WARNCOUNT];
  7.      int length, i;
  8.  
  9.      if (!(opts = string_for_env_opt(optype, opts, FALSE)))
  10.          return FALSE;
  11.      escapes(opts, opts);
  12.  
  13.      length = (int) strlen(opts);
  14.      /* match the form obtained from PC configuration files */
  15.      for (i = 0; i < WARNCOUNT; i++)
  16.          translate[i] = (i >= length) ? 0
  17.                                       : opts[i] ? (uchar) opts[i]
  18.                                                 : def_warnsyms[i].sym;
  19.      assign_warnings(translate);
  20.      return TRUE;
  21.  }
  22.  

assign_warnings

  1.  void
  2.  assign_warnings(graph_chars)
  3.  register uchar *graph_chars;
  4.  {
  5.      int i;
  6.  
  7.      for (i = 0; i < WARNCOUNT; i++)
  8.          if (graph_chars[i])
  9.              warnsyms[i] = graph_chars[i];
  10.  }
  11.  

feature_alert_opts

  1.  STATIC_OVL int
  2.  feature_alert_opts(op, optn)
  3.  char *op;
  4.  const char *optn;
  5.  {
  6.      char buf[BUFSZ];
  7.      unsigned long fnv = get_feature_notice_ver(op); /* version.c */
  8.  
  9.      if (fnv == 0L)
  10.          return 0;
  11.      if (fnv > get_current_feature_ver()) {
  12.          if (!initial) {
  13.              You_cant("disable new feature alerts for future versions.");
  14.          } else {
  15.              config_error_add(
  16.                          "%s=%s Invalid reference to a future version ignored",
  17.                               optn, op);
  18.          }
  19.          return 0;
  20.      }
  21.  
  22.      flags.suppress_alert = fnv;
  23.      if (!initial) {
  24.          Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
  25.                  FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
  26.          pline(
  27.            "Feature change alerts disabled for NetHack %s features and prior.",
  28.                buf);
  29.      }
  30.      return 1;
  31.  }
  32.  

set_duplicate_opt_detection

  1.  void
  2.  set_duplicate_opt_detection(on_or_off)
  3.  int on_or_off;
  4.  {
  5.      int k, *optptr;
  6.  
  7.      if (on_or_off != 0) {
  8.          /*-- ON --*/
  9.          if (iflags.opt_booldup)
  10.              impossible("iflags.opt_booldup already on (memory leak)");
  11.          iflags.opt_booldup = (int *) alloc(SIZE(boolopt) * sizeof (int));
  12.          optptr = iflags.opt_booldup;
  13.          for (k = 0; k < SIZE(boolopt); ++k)
  14.              *optptr++ = 0;
  15.  
  16.          if (iflags.opt_compdup)
  17.              impossible("iflags.opt_compdup already on (memory leak)");
  18.          iflags.opt_compdup = (int *) alloc(SIZE(compopt) * sizeof (int));
  19.          optptr = iflags.opt_compdup;
  20.          for (k = 0; k < SIZE(compopt); ++k)
  21.              *optptr++ = 0;
  22.      } else {
  23.          /*-- OFF --*/
  24.          if (iflags.opt_booldup)
  25.              free((genericptr_t) iflags.opt_booldup);
  26.          iflags.opt_booldup = (int *) 0;
  27.          if (iflags.opt_compdup)
  28.              free((genericptr_t) iflags.opt_compdup);
  29.          iflags.opt_compdup = (int *) 0;
  30.      }
  31.  }
  32.  

duplicate_opt_detection

  1.  STATIC_OVL boolean
  2.  duplicate_opt_detection(opts, iscompound)
  3.  const char *opts;
  4.  int iscompound; /* 0 == boolean option, 1 == compound */
  5.  {
  6.      int i, *optptr;
  7.  
  8.      if (!iscompound && iflags.opt_booldup && initial && from_file) {
  9.          for (i = 0; boolopt[i].name; i++) {
  10.              if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
  11.                  optptr = iflags.opt_booldup + i;
  12.                  *optptr += 1;
  13.                  if (*optptr > 1)
  14.                      return TRUE;
  15.                  else
  16.                      return FALSE;
  17.              }
  18.          }
  19.      } else if (iscompound && iflags.opt_compdup && initial && from_file) {
  20.          for (i = 0; compopt[i].name; i++) {
  21.              if (match_optname(opts, compopt[i].name, strlen(compopt[i].name),
  22.                                TRUE)) {
  23.                  optptr = iflags.opt_compdup + i;
  24.                  *optptr += 1;
  25.                  if (*optptr > 1)
  26.                      return TRUE;
  27.                  else
  28.                      return FALSE;
  29.              }
  30.          }
  31.      }
  32.      return FALSE;
  33.  }
  34.  

complain_about_duplicate

  1.  STATIC_OVL void
  2.  complain_about_duplicate(opts, iscompound)
  3.  const char *opts;
  4.  int iscompound; /* 0 == boolean option, 1 == compound */
  5.  {
  6.  #ifdef MAC
  7.      /* the Mac has trouble dealing with the output of messages while
  8.       * processing the config file.  That should get fixed one day.
  9.       * For now just return.
  10.       */
  11.  #else /* !MAC */
  12.      config_error_add("%s option specified multiple times: %s",
  13.                       iscompound ? "compound" : "boolean", opts);
  14.  #endif /* ?MAC */
  15.      return;
  16.  }
  17.  
  18.  /* paranoia[] - used by parseoptions() and special_handling() */
  19.  STATIC_VAR const struct paranoia_opts {
  20.      int flagmask;        /* which paranoid option */
  21.      const char *argname; /* primary name */
  22.      int argMinLen;       /* minimum number of letters to match */
  23.      const char *synonym; /* alternate name (optional) */
  24.      int synMinLen;
  25.      const char *explain; /* for interactive menu */
  26.  } paranoia[] = {
  27.      /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
  28.         takes precedence and "all" isn't present in the interactive menu,
  29.         and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
  30.         (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
  31.         is just a synonym for "Confirm"); "b"ones vs "br"eak-wand, the
  32.         latter requires at least two letters; "wand"-break vs "Were"-change,
  33.         both require at least two letters during config processing and use
  34.         case-senstivity for 'O's interactive menu */
  35.      { PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2,
  36.        "for \"yes\" confirmations, require \"no\" to reject" },
  37.      { PARANOID_QUIT, "quit", 1, "explore", 1,
  38.        "yes vs y to quit or to enter explore mode" },
  39.      { PARANOID_DIE, "die", 1, "death", 2,
  40.        "yes vs y to die (explore mode or debug mode)" },
  41.      { PARANOID_BONES, "bones", 1, 0, 0,
  42.        "yes vs y to save bones data when dying in debug mode" },
  43.      { PARANOID_HIT, "attack", 1, "hit", 1,
  44.        "yes vs y to attack a peaceful monster" },
  45.      { PARANOID_BREAKWAND, "wand-break", 2, "break-wand", 2,
  46.        "yes vs y to break a wand via (a)pply" },
  47.      { PARANOID_WERECHANGE, "Were-change", 2, (const char *) 0, 0,
  48.        "yes vs y to change form when lycanthropy is controllable" },
  49.      { PARANOID_PRAY, "pray", 1, 0, 0,
  50.        "y to pray (supersedes old \"prayconfirm\" option)" },
  51.      { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1,
  52.        "always pick from inventory for Remove and Takeoff" },
  53.      /* for config file parsing; interactive menu skips these */
  54.      { 0, "none", 4, 0, 0, 0 }, /* require full word match */
  55.      { ~0, "all", 3, 0, 0, 0 }, /* ditto */
  56.  };
  57.  
  58.  extern struct menucoloring *menu_colorings;
  59.  
  60.  static const struct {
  61.      const char *name;
  62.      const int color;
  63.  } colornames[] = {
  64.      { "black", CLR_BLACK },
  65.      { "red", CLR_RED },
  66.      { "green", CLR_GREEN },
  67.      { "brown", CLR_BROWN },
  68.      { "blue", CLR_BLUE },
  69.      { "magenta", CLR_MAGENTA },
  70.      { "cyan", CLR_CYAN },
  71.      { "gray", CLR_GRAY },
  72.      { "orange", CLR_ORANGE },
  73.      { "light green", CLR_BRIGHT_GREEN },
  74.      { "yellow", CLR_YELLOW },
  75.      { "light blue", CLR_BRIGHT_BLUE },
  76.      { "light magenta", CLR_BRIGHT_MAGENTA },
  77.      { "light cyan", CLR_BRIGHT_CYAN },
  78.      { "white", CLR_WHITE },
  79.      { "no color", NO_COLOR },
  80.      { NULL, CLR_BLACK }, /* everything after this is an alias */
  81.      { "transparent", NO_COLOR },
  82.      { "purple", CLR_MAGENTA },
  83.      { "light purple", CLR_BRIGHT_MAGENTA },
  84.      { "bright purple", CLR_BRIGHT_MAGENTA },
  85.      { "grey", CLR_GRAY },
  86.      { "bright red", CLR_ORANGE },
  87.      { "bright green", CLR_BRIGHT_GREEN },
  88.      { "bright blue", CLR_BRIGHT_BLUE },
  89.      { "bright magenta", CLR_BRIGHT_MAGENTA },
  90.      { "bright cyan", CLR_BRIGHT_CYAN }
  91.  };
  92.  
  93.  static const struct {
  94.      const char *name;
  95.      const int attr;
  96.  } attrnames[] = {
  97.      { "none", ATR_NONE },
  98.      { "bold", ATR_BOLD },
  99.      { "dim", ATR_DIM },
  100.      { "underline", ATR_ULINE },
  101.      { "blink", ATR_BLINK },
  102.      { "inverse", ATR_INVERSE },
  103.      { NULL, ATR_NONE }, /* everything after this is an alias */
  104.      { "normal", ATR_NONE },
  105.      { "uline", ATR_ULINE }
  106.  };
  107.  

clr2colorname

  1.  const char *
  2.  clr2colorname(clr)
  3.  int clr;
  4.  {
  5.      int i;
  6.  
  7.      for (i = 0; i < SIZE(colornames); i++)
  8.          if (colornames[i].name && colornames[i].color == clr)
  9.              return colornames[i].name;
  10.      return (char *) 0;
  11.  }
  12.  

match_str2clr

  1.  int
  2.  match_str2clr(str)
  3.  char *str;
  4.  {
  5.      int i, c = CLR_MAX;
  6.  
  7.      /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
  8.         (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
  9.         also copes with trailing space; mungspaces removed any leading space */
  10.      for (i = 0; i < SIZE(colornames); i++)
  11.          if (colornames[i].name
  12.              && fuzzymatch(str, colornames[i].name, " -_", TRUE)) {
  13.              c = colornames[i].color;
  14.              break;
  15.          }
  16.      if (i == SIZE(colornames) && (*str >= '0' && *str <= '9'))
  17.          c = atoi(str);
  18.  
  19.      if (c == CLR_MAX)
  20.          config_error_add("Unknown color '%s'", str);
  21.  
  22.      return c;
  23.  }
  24.  

attr2attrname

  1.  STATIC_OVL const char *
  2.  attr2attrname(attr)
  3.  int attr;
  4.  {
  5.      int i;
  6.  
  7.      for (i = 0; i < SIZE(attrnames); i++)
  8.          if (attrnames[i].attr == attr)
  9.              return attrnames[i].name;
  10.      return (char *) 0;
  11.  }
  12.  

match_str2attr

  1.  int
  2.  match_str2attr(str, complain)
  3.  const char *str;
  4.  boolean complain;
  5.  {
  6.      int i, a = -1;
  7.  
  8.      for (i = 0; i < SIZE(attrnames); i++)
  9.          if (attrnames[i].name
  10.              && fuzzymatch(str, attrnames[i].name, " -_", TRUE)) {
  11.              a = attrnames[i].attr;
  12.              break;
  13.          }
  14.  
  15.      if (a == -1 && complain)
  16.          config_error_add("Unknown text attribute '%s'", str);
  17.  
  18.      return a;
  19.  }
  20.  

query_color

  1.  int
  2.  query_color(prompt)
  3.  const char *prompt;
  4.  {
  5.      winid tmpwin;
  6.      anything any;
  7.      int i, pick_cnt;
  8.      menu_item *picks = (menu_item *) 0;
  9.  
  10.      tmpwin = create_nhwindow(NHW_MENU);
  11.      start_menu(tmpwin);
  12.      any = zeroany;
  13.      for (i = 0; i < SIZE(colornames); i++) {
  14.          if (!colornames[i].name)
  15.              break;
  16.          any.a_int = i + 1;
  17.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name,
  18.                   MENU_UNSELECTED);
  19.      }
  20.      end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick a color");
  21.      pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
  22.      destroy_nhwindow(tmpwin);
  23.      if (pick_cnt > 0) {
  24.          i = colornames[picks->item.a_int - 1].color;
  25.          free((genericptr_t) picks);
  26.          return i;
  27.      }
  28.      return -1;
  29.  }
  30.  

query_attr

  1.  int
  2.  query_attr(prompt)
  3.  const char *prompt;
  4.  {
  5.      winid tmpwin;
  6.      anything any;
  7.      int i, pick_cnt;
  8.      menu_item *picks = (menu_item *) 0;
  9.  
  10.      tmpwin = create_nhwindow(NHW_MENU);
  11.      start_menu(tmpwin);
  12.      any = zeroany;
  13.      for (i = 0; i < SIZE(attrnames); i++) {
  14.          if (!attrnames[i].name)
  15.              break;
  16.          any.a_int = i + 1;
  17.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr,
  18.                   attrnames[i].name, MENU_UNSELECTED);
  19.      }
  20.      end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick an attribute");
  21.      pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
  22.      destroy_nhwindow(tmpwin);
  23.      if (pick_cnt > 0) {
  24.          i = attrnames[picks->item.a_int - 1].attr;
  25.          free((genericptr_t) picks);
  26.          return i;
  27.      }
  28.      return -1;
  29.  }
  30.  
  31.  static const struct {
  32.      const char *name;
  33.      xchar msgtyp;
  34.      const char *descr;
  35.  } msgtype_names[] = {
  36.      { "show", MSGTYP_NORMAL, "Show message normally" },
  37.      { "hide", MSGTYP_NOSHOW, "Hide message" },
  38.      { "noshow", MSGTYP_NOSHOW, NULL },
  39.      { "stop", MSGTYP_STOP, "Prompt for more after the message" },
  40.      { "more", MSGTYP_STOP, NULL },
  41.      { "norep", MSGTYP_NOREP, "Do not repeat the message" }
  42.  };
  43.  

msgtype2name

  1.  STATIC_OVL const char *
  2.  msgtype2name(typ)
  3.  int typ;
  4.  {
  5.      int i;
  6.  
  7.      for (i = 0; i < SIZE(msgtype_names); i++)
  8.          if (msgtype_names[i].descr && msgtype_names[i].msgtyp == typ)
  9.              return msgtype_names[i].name;
  10.      return (char *) 0;
  11.  }
  12.  

query_msgtype

  1.  int
  2.  query_msgtype()
  3.  {
  4.      winid tmpwin;
  5.      anything any;
  6.      int i, pick_cnt;
  7.      menu_item *picks = (menu_item *) 0;
  8.  
  9.      tmpwin = create_nhwindow(NHW_MENU);
  10.      start_menu(tmpwin);
  11.      any = zeroany;
  12.      for (i = 0; i < SIZE(msgtype_names); i++)
  13.          if (msgtype_names[i].descr) {
  14.              any.a_int = msgtype_names[i].msgtyp + 1;
  15.              add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
  16.                   msgtype_names[i].descr, MENU_UNSELECTED);
  17.          }
  18.      end_menu(tmpwin, "How to show the message");
  19.      pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
  20.      destroy_nhwindow(tmpwin);
  21.      if (pick_cnt > 0) {
  22.          i = picks->item.a_int - 1;
  23.          free((genericptr_t) picks);
  24.          return i;
  25.      }
  26.      return -1;
  27.  }
  28.  

msgtype_add

  1.  STATIC_OVL boolean
  2.  msgtype_add(typ, pattern)
  3.  int typ;
  4.  char *pattern;
  5.  {
  6.      struct plinemsg_type
  7.          *tmp = (struct plinemsg_type *) alloc(sizeof (struct plinemsg_type));
  8.  
  9.      tmp->msgtype = typ;
  10.      tmp->regex = regex_init();
  11.      if (!regex_compile(pattern, tmp->regex)) {
  12.          static const char *re_error = "MSGTYPE regex error";
  13.  
  14.          config_error_add("%s: %s", re_error, regex_error_desc(tmp->regex));
  15.          regex_free(tmp->regex);
  16.          free((genericptr_t) tmp);
  17.          return FALSE;
  18.      }
  19.      tmp->pattern = dupstr(pattern);
  20.      tmp->next = plinemsg_types;
  21.      plinemsg_types = tmp;
  22.      return TRUE;
  23.  }
  24.  

msgtype_free

  1.  void
  2.  msgtype_free()
  3.  {
  4.      struct plinemsg_type *tmp, *tmp2 = 0;
  5.  
  6.      for (tmp = plinemsg_types; tmp; tmp = tmp2) {
  7.          tmp2 = tmp->next;
  8.          free((genericptr_t) tmp->pattern);
  9.          regex_free(tmp->regex);
  10.          free((genericptr_t) tmp);
  11.      }
  12.      plinemsg_types = (struct plinemsg_type *) 0;
  13.  }
  14.  

free_one_msgtype

  1.  STATIC_OVL void
  2.  free_one_msgtype(idx)
  3.  int idx; /* 0 .. */
  4.  {
  5.      struct plinemsg_type *tmp = plinemsg_types;
  6.      struct plinemsg_type *prev = NULL;
  7.  
  8.      while (tmp) {
  9.          if (idx == 0) {
  10.              struct plinemsg_type *next = tmp->next;
  11.  
  12.              regex_free(tmp->regex);
  13.              free((genericptr_t) tmp->pattern);
  14.              free((genericptr_t) tmp);
  15.              if (prev)
  16.                  prev->next = next;
  17.              else
  18.                  plinemsg_types = next;
  19.              return;
  20.          }
  21.          idx--;
  22.          prev = tmp;
  23.          tmp = tmp->next;
  24.      }
  25.  }
  26.  

msgtype_type

  1.  int
  2.  msgtype_type(msg, norepeat)
  3.  const char *msg;
  4.  boolean norepeat; /* called from Norep(via pline) */
  5.  {
  6.      struct plinemsg_type *tmp = plinemsg_types;
  7.  
  8.      while (tmp) {
  9.          /* we don't exclude entries with negative msgtype values
  10.             because then the msg might end up matching a later pattern */
  11.          if (regex_match(msg, tmp->regex))
  12.              return tmp->msgtype;
  13.          tmp = tmp->next;
  14.      }
  15.      return norepeat ? MSGTYP_NOREP : MSGTYP_NORMAL;
  16.  }
  17.  

hide_unhide_msgtypes

  1.  /* negate one or more types of messages so that their type handling will
  2.     be disabled or re-enabled; MSGTYPE_NORMAL (value 0) is not affected */
  3.  void
  4.  hide_unhide_msgtypes(hide, hide_mask)
  5.  boolean hide;
  6.  int hide_mask;
  7.  {
  8.      struct plinemsg_type *tmp;
  9.      int mt;
  10.  
  11.      /* negative msgtype value won't be recognized by pline, so does nothing */
  12.      for (tmp = plinemsg_types; tmp; tmp = tmp->next) {
  13.          mt = tmp->msgtype;
  14.          if (!hide)
  15.              mt = -mt; /* unhide: negate negative, yielding positive */
  16.          if (mt > 0 && ((1 << mt) & hide_mask))
  17.              tmp->msgtype = -tmp->msgtype;
  18.      }
  19.  }
  20.  

msgtype_count

  1.  STATIC_OVL int
  2.  msgtype_count(VOID_ARGS)
  3.  {
  4.      int c = 0;
  5.      struct plinemsg_type *tmp = plinemsg_types;
  6.  
  7.      while (tmp) {
  8.          c++;
  9.          tmp = tmp->next;
  10.      }
  11.      return c;
  12.  }
  13.  

msgtype_parse_add

  1.  boolean
  2.  msgtype_parse_add(str)
  3.  char *str;
  4.  {
  5.      char pattern[256];
  6.      char msgtype[11];
  7.  
  8.      if (sscanf(str, "%10s \"%255[^\"]\"", msgtype, pattern) == 2) {
  9.          int typ = -1;
  10.          int i;
  11.  
  12.          for (i = 0; i < SIZE(msgtype_names); i++)
  13.              if (!strncmpi(msgtype_names[i].name, msgtype, strlen(msgtype))) {
  14.                  typ = msgtype_names[i].msgtyp;
  15.                  break;
  16.              }
  17.          if (typ != -1)
  18.              return msgtype_add(typ, pattern);
  19.          else
  20.              config_error_add("Unknown message type '%s'", msgtype);
  21.      } else {
  22.          config_error_add("Malformed MSGTYPE");
  23.      }
  24.      return FALSE;
  25.  }
  26.  

test_regex_pattern

  1.  STATIC_OVL boolean
  2.  test_regex_pattern(str, errmsg)
  3.  const char *str;
  4.  const char *errmsg;
  5.  {
  6.      static const char re_error[] = "Regex error";
  7.      struct nhregex *match;
  8.      boolean retval = TRUE;
  9.  
  10.      if (!str)
  11.          return FALSE;
  12.  
  13.      match = regex_init();
  14.      if (!match) {
  15.          config_error_add("NHregex error");
  16.          return FALSE;
  17.      }
  18.  
  19.      if (!regex_compile(str, match)) {
  20.          config_error_add("%s: %s", errmsg ? errmsg : re_error,
  21.                           regex_error_desc(match));
  22.          retval = FALSE;
  23.      }
  24.      regex_free(match);
  25.      return retval;
  26.  }
  27.  

add_menu_coloring_parsed

  1.  boolean
  2.  add_menu_coloring_parsed(str, c, a)
  3.  char *str;
  4.  int c, a;
  5.  {
  6.      static const char re_error[] = "Menucolor regex error";
  7.      struct menucoloring *tmp;
  8.  
  9.      if (!str)
  10.          return FALSE;
  11.      tmp = (struct menucoloring *) alloc(sizeof (struct menucoloring));
  12.      tmp->match = regex_init();
  13.      if (!regex_compile(str, tmp->match)) {
  14.          config_error_add("%s: %s", re_error, regex_error_desc(tmp->match));
  15.          regex_free(tmp->match);
  16.          free(tmp);
  17.          return FALSE;
  18.      } else {
  19.          tmp->next = menu_colorings;
  20.          tmp->origstr = dupstr(str);
  21.          tmp->color = c;
  22.          tmp->attr = a;
  23.          menu_colorings = tmp;
  24.          return TRUE;
  25.      }
  26.  }
  27.  

add_menu_coloring

  1.  /* parse '"regex_string"=color&attr' and add it to menucoloring */
  2.  boolean
  3.  add_menu_coloring(tmpstr)
  4.  char *tmpstr;
  5.  {
  6.      int c = NO_COLOR, a = ATR_NONE;
  7.      char *tmps, *cs, *amp;
  8.      char str[BUFSZ];
  9.  
  10.      Sprintf(str, "%s", tmpstr);
  11.  
  12.      if (!tmpstr || (cs = index(str, '=')) == 0) {
  13.          config_error_add("Malformed MENUCOLOR");
  14.          return FALSE;
  15.      }
  16.  
  17.      tmps = cs + 1; /* advance past '=' */
  18.      mungspaces(tmps);
  19.      if ((amp = index(tmps, '&')) != 0)
  20.          *amp = '\0';
  21.  
  22.      c = match_str2clr(tmps);
  23.      if (c >= CLR_MAX)
  24.          return FALSE;
  25.  
  26.      if (amp) {
  27.          tmps = amp + 1; /* advance past '&' */
  28.          a = match_str2attr(tmps, TRUE);
  29.          if (a == -1)
  30.              return FALSE;
  31.      }
  32.  
  33.      /* the regexp portion here has not been condensed by mungspaces() */
  34.      *cs = '\0';
  35.      tmps = str;
  36.      if (*tmps == '"' || *tmps == '\'') {
  37.          cs--;
  38.          while (isspace((uchar) *cs))
  39.              cs--;
  40.          if (*cs == *tmps) {
  41.              *cs = '\0';
  42.              tmps++;
  43.          }
  44.      }
  45.  
  46.      return add_menu_coloring_parsed(tmps, c, a);
  47.  }
  48.  

get_menu_coloring

  1.  boolean
  2.  get_menu_coloring(str, color, attr)
  3.  const char *str;
  4.  int *color, *attr;
  5.  {
  6.      struct menucoloring *tmpmc;
  7.  
  8.      if (iflags.use_menu_color)
  9.          for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next)
  10.              if (regex_match(str, tmpmc->match)) {
  11.                  *color = tmpmc->color;
  12.                  *attr = tmpmc->attr;
  13.                  return TRUE;
  14.              }
  15.      return FALSE;
  16.  }
  17.  

free_menu_coloring

  1.  void
  2.  free_menu_coloring()
  3.  {
  4.      struct menucoloring *tmp = menu_colorings;
  5.  
  6.      while (tmp) {
  7.          struct menucoloring *tmp2 = tmp->next;
  8.  
  9.          regex_free(tmp->match);
  10.          free((genericptr_t) tmp->origstr);
  11.          free((genericptr_t) tmp);
  12.          tmp = tmp2;
  13.      }
  14.  }
  15.  

free_one_menu_coloring

  1.  STATIC_OVL void
  2.  free_one_menu_coloring(idx)
  3.  int idx; /* 0 .. */
  4.  {
  5.      struct menucoloring *tmp = menu_colorings;
  6.      struct menucoloring *prev = NULL;
  7.  
  8.      while (tmp) {
  9.          if (idx == 0) {
  10.              struct menucoloring *next = tmp->next;
  11.  
  12.              regex_free(tmp->match);
  13.              free((genericptr_t) tmp->origstr);
  14.              free((genericptr_t) tmp);
  15.              if (prev)
  16.                  prev->next = next;
  17.              else
  18.                  menu_colorings = next;
  19.              return;
  20.          }
  21.          idx--;
  22.          prev = tmp;
  23.          tmp = tmp->next;
  24.      }
  25.  }
  26.  

count_menucolors

  1.  STATIC_OVL int
  2.  count_menucolors(VOID_ARGS)
  3.  {
  4.      int count = 0;
  5.      struct menucoloring *tmp = menu_colorings;
  6.  
  7.      while (tmp) {
  8.          count++;
  9.          tmp = tmp->next;
  10.      }
  11.      return count;
  12.  }
  13.  

parse_role_opts

  1.  STATIC_OVL boolean
  2.  parse_role_opts(negated, fullname, opts, opp)
  3.  boolean negated;
  4.  const char *fullname;
  5.  char *opts;
  6.  char **opp;
  7.  {
  8.      char *op = *opp;
  9.  
  10.      if (negated) {
  11.          bad_negation(fullname, FALSE);
  12.      } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  13.          boolean val_negated = FALSE;
  14.  
  15.          while ((*op == '!') || !strncmpi(op, "no", 2)) {
  16.              if (*op == '!')
  17.                  op++;
  18.              else
  19.                  op += 2;
  20.              val_negated = !val_negated;
  21.          }
  22.          if (val_negated) {
  23.              if (!setrolefilter(op)) {
  24.                  config_error_add("Unknown negated parameter '%s'", op);
  25.                  return FALSE;
  26.              }
  27.          } else {
  28.              if (duplicate_opt_detection(opts, 1))
  29.                  complain_about_duplicate(opts, 1);
  30.              *opp = op;
  31.              return TRUE;
  32.          }
  33.      }
  34.      return FALSE;
  35.  }
  36.  

illegal_menu_cmd_key

  1.  /* Check if character c is illegal as a menu command key */
  2.  boolean
  3.  illegal_menu_cmd_key(c)
  4.  char c;
  5.  {
  6.      if (c == 0 || c == '\r' || c == '\n' || c == '\033'
  7.          || c == ' ' || digit(c) || (letter(c) && c != '@')) {
  8.          config_error_add("Reserved menu command key '%s'", visctrl(c));
  9.          return TRUE;
  10.      } else { /* reject default object class symbols */
  11.          int j;
  12.          for (j = 1; j < MAXOCLASSES; j++)
  13.              if (c == def_oc_syms[j].sym) {
  14.                  config_error_add("Menu command key '%s' is an object class",
  15.                                   visctrl(c));
  16.                  return TRUE;
  17.              }
  18.      }
  19.      return FALSE;
  20.  }
  21.  

parseoptions

  1.  boolean
  2.  parseoptions(opts, tinitial, tfrom_file)
  3.  register char *opts;
  4.  boolean tinitial, tfrom_file;
  5.  {
  6.      char *op;
  7.      unsigned num;
  8.      boolean negated, duplicate;
  9.      int i;
  10.      const char *fullname;
  11.      boolean retval = TRUE;
  12.  
  13.      initial = tinitial;
  14.      from_file = tfrom_file;
  15.      if ((op = index(opts, ',')) != 0) {
  16.          *op++ = 0;
  17.          if (!parseoptions(op, initial, from_file))
  18.              retval = FALSE;
  19.      }
  20.      if (strlen(opts) > BUFSZ / 2) {
  21.          config_error_add("Option too long, max length is %i characters",
  22.                           (BUFSZ / 2));
  23.          return FALSE;
  24.      }
  25.  
  26.      /* strip leading and trailing white space */
  27.      while (isspace((uchar) *opts))
  28.          opts++;
  29.      op = eos(opts);
  30.      while (--op >= opts && isspace((uchar) *op))
  31.          *op = '\0';
  32.  
  33.      if (!*opts) {
  34.          config_error_add("Empty statement");
  35.          return FALSE;
  36.      }
  37.      negated = FALSE;
  38.      while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
  39.          if (*opts == '!')
  40.              opts++;
  41.          else
  42.              opts += 2;
  43.          negated = !negated;
  44.      }
  45.  
  46.      /* variant spelling */
  47.  
  48.      if (match_optname(opts, "colour", 5, FALSE))
  49.          Strcpy(opts, "color"); /* fortunately this isn't longer */
  50.  
  51.      /* special boolean options */
  52.  
  53.      if (match_optname(opts, "female", 3, FALSE)) {
  54.          if (duplicate_opt_detection(opts, 0))
  55.              complain_about_duplicate(opts, 0);
  56.          if (!initial && flags.female == negated) {
  57.              config_error_add("That is not anatomically possible.");
  58.              return FALSE;
  59.          } else
  60.              flags.initgend = flags.female = !negated;
  61.          return retval;
  62.      }
  63.  
  64.      if (match_optname(opts, "male", 4, FALSE)) {
  65.          if (duplicate_opt_detection(opts, 0))
  66.              complain_about_duplicate(opts, 0);
  67.          if (!initial && flags.female != negated) {
  68.              config_error_add("That is not anatomically possible.");
  69.              return FALSE;
  70.          } else
  71.              flags.initgend = flags.female = negated;
  72.          return retval;
  73.      }
  74.  
  75.  #if defined(MICRO) && !defined(AMIGA)
  76.      /* included for compatibility with old NetHack.cnf files */
  77.      if (match_optname(opts, "IBM_", 4, FALSE)) {
  78.          iflags.BIOS = !negated;
  79.          return retval;
  80.      }
  81.  #endif /* MICRO */
  82.  
  83.      /* compound options */
  84.  
  85.      /* This first batch can be duplicated if their values are negated */
  86.  
  87.      /* align:string */
  88.      fullname = "align";
  89.      if (match_optname(opts, fullname, sizeof("align") - 1, TRUE)) {
  90.          if (parse_role_opts(negated, fullname, opts, &op)) {
  91.              if ((flags.initalign = str2align(op)) == ROLE_NONE) {
  92.                  config_error_add("Unknown %s '%s'", fullname, op);
  93.                  return FALSE;
  94.              }
  95.          } else
  96.              return FALSE;
  97.          return retval;
  98.      }
  99.  
  100.      /* role:string or character:string */
  101.      fullname = "role";
  102.      if (match_optname(opts, fullname, 4, TRUE)
  103.          || match_optname(opts, (fullname = "character"), 4, TRUE)) {
  104.          if (parse_role_opts(negated, fullname, opts, &op)) {
  105.              if ((flags.initrole = str2role(op)) == ROLE_NONE) {
  106.                  config_error_add("Unknown %s '%s'", fullname, op);
  107.                  return FALSE;
  108.              } else /* Backwards compatibility */
  109.                  nmcpy(pl_character, op, PL_NSIZ);
  110.          } else
  111.              return FALSE;
  112.          return retval;
  113.      }
  114.  
  115.      /* race:string */
  116.      fullname = "race";
  117.      if (match_optname(opts, fullname, 4, TRUE)) {
  118.          if (parse_role_opts(negated, fullname, opts, &op)) {
  119.              if ((flags.initrace = str2race(op)) == ROLE_NONE) {
  120.                  config_error_add("Unknown %s '%s'", fullname, op);
  121.                  return FALSE;
  122.              } else /* Backwards compatibility */
  123.                  pl_race = *op;
  124.          } else
  125.              return FALSE;
  126.          return retval;
  127.      }
  128.  
  129.      /* gender:string */
  130.      fullname = "gender";
  131.      if (match_optname(opts, fullname, 4, TRUE)) {
  132.          if (parse_role_opts(negated, fullname, opts, &op)) {
  133.              if ((flags.initgend = str2gend(op)) == ROLE_NONE) {
  134.                  config_error_add("Unknown %s '%s'", fullname, op);
  135.                  return FALSE;
  136.              } else
  137.                  flags.female = flags.initgend;
  138.          } else
  139.              return FALSE;
  140.          return retval;
  141.      }
  142.  
  143.      /* We always check for duplicates on the remaining compound options,
  144.         although individual option processing can choose to complain or not */
  145.  
  146.      duplicate = duplicate_opt_detection(opts, 1); /* 1: check compounds */
  147.  
  148.      fullname = "pettype";
  149.      if (match_optname(opts, fullname, 3, TRUE)) {
  150.          if (duplicate)
  151.              complain_about_duplicate(opts, 1);
  152.          if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
  153.              if (negated) {
  154.                  bad_negation(fullname, TRUE);
  155.                  return FALSE;
  156.              } else
  157.                  switch (lowc(*op)) {
  158.                  case 'd': /* dog */
  159.                      preferred_pet = 'd';
  160.                      break;
  161.                  case 'c': /* cat */
  162.                  case 'f': /* feline */
  163.                      preferred_pet = 'c';
  164.                      break;
  165.                  case 'h': /* horse */
  166.                  case 'q': /* quadruped */
  167.                      /* avoids giving "unrecognized type of pet" but
  168.                         pet_type(dog.c) won't actually honor this */
  169.                      preferred_pet = 'h';
  170.                      break;
  171.                  case 'n': /* no pet */
  172.                      preferred_pet = 'n';
  173.                      break;
  174.                  case '*': /* random */
  175.                      preferred_pet = '\0';
  176.                      break;
  177.                  default:
  178.                      config_error_add("Unrecognized pet type '%s'.", op);
  179.                      return FALSE;
  180.                      break;
  181.                  }
  182.          } else if (negated)
  183.              preferred_pet = 'n';
  184.          return retval;
  185.      }
  186.  
  187.      fullname = "catname";
  188.      if (match_optname(opts, fullname, 3, TRUE)) {
  189.          if (duplicate)
  190.              complain_about_duplicate(opts, 1);
  191.          if (negated) {
  192.              bad_negation(fullname, FALSE);
  193.              return FALSE;
  194.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  195.              nmcpy(catname, op, PL_PSIZ);
  196.          } else
  197.              return FALSE;
  198.          sanitize_name(catname);
  199.          return retval;
  200.      }
  201.  
  202.      fullname = "dogname";
  203.      if (match_optname(opts, fullname, 3, TRUE)) {
  204.          if (duplicate)
  205.              complain_about_duplicate(opts, 1);
  206.          if (negated) {
  207.              bad_negation(fullname, FALSE);
  208.              return FALSE;
  209.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  210.              nmcpy(dogname, op, PL_PSIZ);
  211.          } else
  212.              return FALSE;
  213.          sanitize_name(dogname);
  214.          return retval;
  215.      }
  216.  
  217.      fullname = "horsename";
  218.      if (match_optname(opts, fullname, 5, TRUE)) {
  219.          if (duplicate)
  220.              complain_about_duplicate(opts, 1);
  221.          if (negated) {
  222.              bad_negation(fullname, FALSE);
  223.              return FALSE;
  224.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  225.              nmcpy(horsename, op, PL_PSIZ);
  226.          } else
  227.              return FALSE;
  228.          sanitize_name(horsename);
  229.          return retval;
  230.      }
  231.  
  232.      fullname = "number_pad";
  233.      if (match_optname(opts, fullname, 10, TRUE)) {
  234.          boolean compat = (strlen(opts) <= 10);
  235.  
  236.          if (duplicate)
  237.              complain_about_duplicate(opts, 1);
  238.          op = string_for_opt(opts, (compat || !initial));
  239.          if (!op) {
  240.              if (compat || negated || initial) {
  241.                  /* for backwards compatibility, "number_pad" without a
  242.                     value is a synonym for number_pad:1 */
  243.                  iflags.num_pad = !negated;
  244.                  iflags.num_pad_mode = 0;
  245.              }
  246.          } else if (negated) {
  247.              bad_negation(fullname, TRUE);
  248.              return FALSE;
  249.          } else {
  250.              int mode = atoi(op);
  251.  
  252.              if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) {
  253.                  config_error_add("Illegal %s parameter '%s'", fullname, op);
  254.                  return FALSE;
  255.              } else if (mode <= 0) {
  256.                  iflags.num_pad = FALSE;
  257.                  /* German keyboard; y and z keys swapped */
  258.                  iflags.num_pad_mode = (mode < 0); /* 0 or 1 */
  259.              } else {                              /* mode > 0 */
  260.                  iflags.num_pad = TRUE;
  261.                  iflags.num_pad_mode = 0;
  262.                  /* PC Hack / MSDOS compatibility */
  263.                  if (mode == 2 || mode == 4)
  264.                      iflags.num_pad_mode |= 1;
  265.                  /* phone keypad layout */
  266.                  if (mode == 3 || mode == 4)
  267.                      iflags.num_pad_mode |= 2;
  268.              }
  269.          }
  270.          reset_commands(FALSE);
  271.          number_pad(iflags.num_pad ? 1 : 0);
  272.          return retval;
  273.      }
  274.  
  275.      fullname = "roguesymset";
  276.      if (match_optname(opts, fullname, 7, TRUE)) {
  277.          if (duplicate)
  278.              complain_about_duplicate(opts, 1);
  279.          if (negated) {
  280.              bad_negation(fullname, FALSE);
  281.              return FALSE;
  282.          } else if ((op = string_for_opt(opts, FALSE)) != 0) {
  283.              symset[ROGUESET].name = dupstr(op);
  284.              if (!read_sym_file(ROGUESET)) {
  285.                  clear_symsetentry(ROGUESET, TRUE);
  286.                  config_error_add("Unable to load symbol set \"%s\" from \"%s\"",
  287.                             op, SYMBOLS);
  288.                  return FALSE;
  289.              } else {
  290.                  if (!initial && Is_rogue_level(&u.uz))
  291.                      assign_graphics(ROGUESET);
  292.                  need_redraw = TRUE;
  293.              }
  294.          } else
  295.              return FALSE;
  296.          return retval;
  297.      }
  298.  
  299.      fullname = "symset";
  300.      if (match_optname(opts, fullname, 6, TRUE)) {
  301.          if (duplicate)
  302.              complain_about_duplicate(opts, 1);
  303.          if (negated) {
  304.              bad_negation(fullname, FALSE);
  305.              return FALSE;
  306.          } else if ((op = string_for_opt(opts, FALSE)) != 0) {
  307.              symset[PRIMARY].name = dupstr(op);
  308.              if (!read_sym_file(PRIMARY)) {
  309.                  clear_symsetentry(PRIMARY, TRUE);
  310.                  config_error_add(
  311.                                 "Unable to load symbol set \"%s\" from \"%s\"",
  312.                                   op, SYMBOLS);
  313.                  return FALSE;
  314.              } else {
  315.                  switch_symbols(symset[PRIMARY].name != (char *) 0);
  316.                  need_redraw = TRUE;
  317.              }
  318.          } else
  319.              return FALSE;
  320.          return retval;
  321.      }
  322.  
  323.      fullname = "runmode";
  324.      if (match_optname(opts, fullname, 4, TRUE)) {
  325.          if (duplicate)
  326.              complain_about_duplicate(opts, 1);
  327.          if (negated) {
  328.              flags.runmode = RUN_TPORT;
  329.          } else if ((op = string_for_opt(opts, FALSE)) != 0) {
  330.              if (!strncmpi(op, "teleport", strlen(op)))
  331.                  flags.runmode = RUN_TPORT;
  332.              else if (!strncmpi(op, "run", strlen(op)))
  333.                  flags.runmode = RUN_LEAP;
  334.              else if (!strncmpi(op, "walk", strlen(op)))
  335.                  flags.runmode = RUN_STEP;
  336.              else if (!strncmpi(op, "crawl", strlen(op)))
  337.                  flags.runmode = RUN_CRAWL;
  338.              else {
  339.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  340.                  return FALSE;
  341.              }
  342.          } else
  343.              return FALSE;
  344.          return retval;
  345.      }
  346.  
  347.      /* menucolor:"regex_string"=color */
  348.      fullname = "menucolor";
  349.      if (match_optname(opts, fullname, 9, TRUE)) {
  350.          if (negated) {
  351.              bad_negation(fullname, FALSE);
  352.              return FALSE;
  353.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  354.              if (!add_menu_coloring(op))
  355.                  return FALSE;
  356.          } else
  357.              return FALSE;
  358.          return retval;
  359.      }
  360.  
  361.      fullname = "msghistory";
  362.      if (match_optname(opts, fullname, 3, TRUE)) {
  363.          if (duplicate)
  364.              complain_about_duplicate(opts, 1);
  365.          op = string_for_env_opt(fullname, opts, negated);
  366.          if ((negated && !op) || (!negated && op)) {
  367.              iflags.msg_history = negated ? 0 : atoi(op);
  368.          } else if (negated) {
  369.              bad_negation(fullname, TRUE);
  370.              return FALSE;
  371.          }
  372.          return retval;
  373.      }
  374.  
  375.      fullname = "msg_window";
  376.      /* msg_window:single, combo, full or reversed */
  377.      if (match_optname(opts, fullname, 4, TRUE)) {
  378.  /* allow option to be silently ignored by non-tty ports */
  379.  #ifdef TTY_GRAPHICS
  380.          int tmp;
  381.  
  382.          if (duplicate)
  383.              complain_about_duplicate(opts, 1);
  384.          if (!(op = string_for_opt(opts, TRUE))) {
  385.              tmp = negated ? 's' : 'f';
  386.          } else {
  387.              if (negated) {
  388.                  bad_negation(fullname, TRUE);
  389.                  return FALSE;
  390.              }
  391.              tmp = lowc(*op);
  392.          }
  393.          switch (tmp) {
  394.          case 's': /* single message history cycle (default if negated) */
  395.              iflags.prevmsg_window = 's';
  396.              break;
  397.          case 'c': /* combination: two singles, then full page reversed */
  398.              iflags.prevmsg_window = 'c';
  399.              break;
  400.          case 'f': /* full page (default if no opts) */
  401.              iflags.prevmsg_window = 'f';
  402.              break;
  403.          case 'r': /* full page (reversed) */
  404.              iflags.prevmsg_window = 'r';
  405.              break;
  406.          default: {
  407.              config_error_add("Unknown %s parameter '%s'", fullname, op);
  408.              return FALSE;
  409.          }
  410.          }
  411.  #endif
  412.          return retval;
  413.      }
  414.  
  415.      /* WINCAP
  416.       * setting font options  */
  417.      fullname = "font";
  418.      if (!strncmpi(opts, fullname, 4)) {
  419.          int opttype = -1;
  420.          char *fontopts = opts + 4;
  421.  
  422.          if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4))
  423.              opttype = MAP_OPTION;
  424.          else if (!strncmpi(fontopts, "message", 7)
  425.                   || !strncmpi(fontopts, "_message", 8))
  426.              opttype = MESSAGE_OPTION;
  427.          else if (!strncmpi(fontopts, "text", 4)
  428.                   || !strncmpi(fontopts, "_text", 5))
  429.              opttype = TEXT_OPTION;
  430.          else if (!strncmpi(fontopts, "menu", 4)
  431.                   || !strncmpi(fontopts, "_menu", 5))
  432.              opttype = MENU_OPTION;
  433.          else if (!strncmpi(fontopts, "status", 6)
  434.                   || !strncmpi(fontopts, "_status", 7))
  435.              opttype = STATUS_OPTION;
  436.          else if (!strncmpi(fontopts, "_size", 5)) {
  437.              if (!strncmpi(fontopts, "_size_map", 8))
  438.                  opttype = MAP_OPTION;
  439.              else if (!strncmpi(fontopts, "_size_message", 12))
  440.                  opttype = MESSAGE_OPTION;
  441.              else if (!strncmpi(fontopts, "_size_text", 9))
  442.                  opttype = TEXT_OPTION;
  443.              else if (!strncmpi(fontopts, "_size_menu", 9))
  444.                  opttype = MENU_OPTION;
  445.              else if (!strncmpi(fontopts, "_size_status", 11))
  446.                  opttype = STATUS_OPTION;
  447.              else {
  448.                  config_error_add("Unknown %s parameter '%s'", fullname, opts);
  449.                  return FALSE;
  450.              }
  451.              if (duplicate)
  452.                  complain_about_duplicate(opts, 1);
  453.              if (opttype > 0 && !negated
  454.                  && (op = string_for_opt(opts, FALSE)) != 0) {
  455.                  switch (opttype) {
  456.                  case MAP_OPTION:
  457.                      iflags.wc_fontsiz_map = atoi(op);
  458.                      break;
  459.                  case MESSAGE_OPTION:
  460.                      iflags.wc_fontsiz_message = atoi(op);
  461.                      break;
  462.                  case TEXT_OPTION:
  463.                      iflags.wc_fontsiz_text = atoi(op);
  464.                      break;
  465.                  case MENU_OPTION:
  466.                      iflags.wc_fontsiz_menu = atoi(op);
  467.                      break;
  468.                  case STATUS_OPTION:
  469.                      iflags.wc_fontsiz_status = atoi(op);
  470.                      break;
  471.                  }
  472.              }
  473.              return retval;
  474.          } else {
  475.              config_error_add("Unknown %s parameter '%s'", fullname, opts);
  476.              return FALSE;
  477.          }
  478.          if (opttype > 0 && (op = string_for_opt(opts, FALSE)) != 0) {
  479.              wc_set_font_name(opttype, op);
  480.  #ifdef MAC
  481.              set_font_name(opttype, op);
  482.  #endif
  483.              return retval;
  484.          } else if (negated) {
  485.              bad_negation(fullname, TRUE);
  486.              return FALSE;
  487.          }
  488.          return retval;
  489.      }
  490.  
  491.  #ifdef CHANGE_COLOR
  492.      if (match_optname(opts, "palette", 3, TRUE)
  493.  #ifdef MAC
  494.          || match_optname(opts, "hicolor", 3, TRUE)
  495.  #endif
  496.          ) {
  497.          int color_number, color_incr;
  498.  
  499.  #ifndef WIN32
  500.          if (duplicate)
  501.              complain_about_duplicate(opts, 1);
  502.  #endif
  503.  #ifdef MAC
  504.          if (match_optname(opts, "hicolor", 3, TRUE)) {
  505.              if (negated) {
  506.                  bad_negation("hicolor", FALSE);
  507.                  return FALSE;
  508.              }
  509.              color_number = CLR_MAX + 4; /* HARDCODED inverse number */
  510.              color_incr = -1;
  511.          } else
  512.  #endif
  513.          {
  514.              if (negated) {
  515.                  bad_negation("palette", FALSE);
  516.                  return FALSE;
  517.              }
  518.              color_number = 0;
  519.              color_incr = 1;
  520.          }
  521.  #ifdef WIN32
  522.          op = string_for_opt(opts, TRUE);
  523.          if (!alternative_palette(op)) {
  524.              config_error_add("Error in palette parameter '%s'", op);
  525.              return FALSE;
  526.          }
  527.  #else
  528.          if ((op = string_for_opt(opts, FALSE)) != (char *) 0) {
  529.              char *pt = op;
  530.              int cnt, tmp, reverse;
  531.              long rgb;
  532.  
  533.              while (*pt && color_number >= 0) {
  534.                  cnt = 3;
  535.                  rgb = 0L;
  536.                  if (*pt == '-') {
  537.                      reverse = 1;
  538.                      pt++;
  539.                  } else {
  540.                      reverse = 0;
  541.                  }
  542.                  while (cnt-- > 0) {
  543.                      if (*pt && *pt != '/') {
  544.  #ifdef AMIGA
  545.                          rgb <<= 4;
  546.  #else
  547.                          rgb <<= 8;
  548.  #endif
  549.                          tmp = *pt++;
  550.                          if (isalpha((uchar) tmp)) {
  551.                              tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
  552.                          } else {
  553.                              tmp &= 0xf; /* Digits in ASCII too... */
  554.                          }
  555.  #ifndef AMIGA
  556.                          /* Add an extra so we fill f -> ff and 0 -> 00 */
  557.                          rgb += tmp << 4;
  558.  #endif
  559.                          rgb += tmp;
  560.                      }
  561.                  }
  562.                  if (*pt == '/')
  563.                      pt++;
  564.                  change_color(color_number, rgb, reverse);
  565.                  color_number += color_incr;
  566.              }
  567.          }
  568.  #endif /* !WIN32 */
  569.          if (!initial) {
  570.              need_redraw = TRUE;
  571.          }
  572.          return retval;
  573.      }
  574.  #endif /* CHANGE_COLOR */
  575.  
  576.      if (match_optname(opts, "fruit", 2, TRUE)) {
  577.          struct fruit *forig = 0;
  578.          char empty_str = '\0';
  579.  
  580.          if (duplicate)
  581.              complain_about_duplicate(opts, 1);
  582.          op = string_for_opt(opts, negated);
  583.          if (negated) {
  584.              if (op) {
  585.                  bad_negation("fruit", TRUE);
  586.                  return FALSE;
  587.              }
  588.              op = &empty_str;
  589.              goto goodfruit;
  590.          }
  591.          if (!op)
  592.              return FALSE;
  593.          if (!initial) {
  594.              struct fruit *f;
  595.              int fnum = 0;
  596.  
  597.              /* count number of named fruits; if 'op' is found among them,
  598.                 then the count doesn't matter because we won't be adding it */
  599.              f = fruit_from_name(op, FALSE, &fnum);
  600.              if (!f) {
  601.                  if (!flags.made_fruit)
  602.                      forig = fruit_from_name(pl_fruit, FALSE, (int *) 0);
  603.  
  604.                  if (!forig && fnum >= 100) {
  605.                      config_error_add(
  606.                               "Doing that so many times isn't very fruitful.");
  607.                      return retval;
  608.                  }
  609.              }
  610.          }
  611.      goodfruit:
  612.          nmcpy(pl_fruit, op, PL_FSIZ);
  613.          sanitize_name(pl_fruit);
  614.          /* OBJ_NAME(objects[SLIME_MOLD]) won't work for this after
  615.             initialization; it gets changed to generic "fruit" */
  616.          if (!*pl_fruit)
  617.              nmcpy(pl_fruit, "slime mold", PL_FSIZ);
  618.          if (!initial) {
  619.              /* if 'forig' is nonNull, we replace it rather than add
  620.                 a new fruit; it can only be nonNull if no fruits have
  621.                 been created since the previous name was put in place */
  622.              (void) fruitadd(pl_fruit, forig);
  623.              pline("Fruit is now \"%s\".", pl_fruit);
  624.          }
  625.          /* If initial, then initoptions is allowed to do it instead
  626.           * of here (initoptions always has to do it even if there's
  627.           * no fruit option at all.  Also, we don't want people
  628.           * setting multiple fruits in their options.)
  629.           */
  630.          return retval;
  631.      }
  632.  
  633.      fullname = "whatis_coord";
  634.      if (match_optname(opts, fullname, 8, TRUE)) {
  635.          if (duplicate)
  636.              complain_about_duplicate(opts, 1);
  637.          if (negated) {
  638.              iflags.getpos_coords = GPCOORDS_NONE;
  639.              return retval;
  640.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  641.              static char gpcoords[] = { GPCOORDS_NONE, GPCOORDS_COMPASS,
  642.                                         GPCOORDS_COMFULL, GPCOORDS_MAP,
  643.                                         GPCOORDS_SCREEN, '\0' };
  644.              char c = lowc(*op);
  645.  
  646.              if (c && index(gpcoords, c))
  647.                  iflags.getpos_coords = c;
  648.              else {
  649.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  650.                  return FALSE;
  651.              }
  652.          } else
  653.              return FALSE;
  654.          return retval;
  655.      }
  656.  
  657.      fullname = "whatis_filter";
  658.      if (match_optname(opts, fullname, 8, TRUE)) {
  659.          if (duplicate)
  660.              complain_about_duplicate(opts, 1);
  661.          if (negated) {
  662.              iflags.getloc_filter = GFILTER_NONE;
  663.              return retval;
  664.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  665.              char c = lowc(*op);
  666.  
  667.              switch (c) {
  668.              case 'n':
  669.                  iflags.getloc_filter = GFILTER_NONE;
  670.                  break;
  671.              case 'v':
  672.                  iflags.getloc_filter = GFILTER_VIEW;
  673.                  break;
  674.              case 'a':
  675.                  iflags.getloc_filter = GFILTER_AREA;
  676.                  break;
  677.              default: {
  678.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  679.                  return FALSE;
  680.              }
  681.              }
  682.          } else
  683.              return FALSE;
  684.          return retval;
  685.      }
  686.  
  687.      fullname = "warnings";
  688.      if (match_optname(opts, fullname, 5, TRUE)) {
  689.          if (duplicate)
  690.              complain_about_duplicate(opts, 1);
  691.          if (negated) {
  692.              bad_negation(fullname, FALSE);
  693.              return FALSE;
  694.          }
  695.          return warning_opts(opts, fullname);
  696.      }
  697.  
  698.      /* boulder:symbol */
  699.      fullname = "boulder";
  700.      if (match_optname(opts, fullname, 7, TRUE)) {
  701.  #ifdef BACKWARD_COMPAT
  702.          int clash = 0;
  703.  
  704.          if (duplicate)
  705.              complain_about_duplicate(opts, 1);
  706.          if (negated) {
  707.              bad_negation(fullname, FALSE);
  708.              return FALSE;
  709.          }
  710.          /* if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
  711.           */
  712.          if (!(opts = string_for_opt(opts, FALSE)))
  713.              return FALSE;
  714.          escapes(opts, opts);
  715.          if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
  716.              clash = 1;
  717.          else if (opts[0] >= '1' && opts[0] <= '5')
  718.              clash = 2;
  719.          if (clash) {
  720.              /* symbol chosen matches a used monster or warning
  721.                 symbol which is not good - reject it*/
  722.              config_error_add(
  723.                  "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
  724.                               opts[0], (clash == 1) ? "monster" : "warning");
  725.          } else {
  726.              /*
  727.               * Override the default boulder symbol.
  728.               */
  729.              iflags.bouldersym = (uchar) opts[0];
  730.          }
  731.          /* for 'initial', update_bouldersym() is done in initoptions_finish(),
  732.             after all symset options have been processed */
  733.          if (!initial) {
  734.              update_bouldersym();
  735.              need_redraw = TRUE;
  736.          }
  737.          return retval;
  738.  #else
  739.          config_error_add("'%s' no longer supported; use S_boulder:c instead",
  740.                           fullname);
  741.          return FALSE;
  742.  #endif
  743.      }
  744.  
  745.      /* name:string */
  746.      fullname = "name";
  747.      if (match_optname(opts, fullname, 4, TRUE)) {
  748.          if (duplicate)
  749.              complain_about_duplicate(opts, 1);
  750.          if (negated) {
  751.              bad_negation(fullname, FALSE);
  752.              return FALSE;
  753.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  754.              nmcpy(plname, op, PL_NSIZ);
  755.          } else
  756.              return FALSE;
  757.          return retval;
  758.      }
  759.  
  760.      /* altkeyhandler:string */
  761.      fullname = "altkeyhandler";
  762.      if (match_optname(opts, fullname, 4, TRUE)) {
  763.          if (duplicate)
  764.              complain_about_duplicate(opts, 1);
  765.          if (negated) {
  766.              bad_negation(fullname, FALSE);
  767.              return FALSE;
  768.          } else if ((op = string_for_opt(opts, negated)) != 0) {
  769.  #ifdef WIN32
  770.              (void) strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
  771.              load_keyboard_handler();
  772.  #endif
  773.          } else
  774.              return FALSE;
  775.          return retval;
  776.      }
  777.  
  778.      /* WINCAP
  779.       * align_status:[left|top|right|bottom] */
  780.      fullname = "align_status";
  781.      if (match_optname(opts, fullname, sizeof("align_status") - 1, TRUE)) {
  782.          op = string_for_opt(opts, negated);
  783.          if (op && !negated) {
  784.              if (!strncmpi(op, "left", sizeof("left") - 1))
  785.                  iflags.wc_align_status = ALIGN_LEFT;
  786.              else if (!strncmpi(op, "top", sizeof("top") - 1))
  787.                  iflags.wc_align_status = ALIGN_TOP;
  788.              else if (!strncmpi(op, "right", sizeof("right") - 1))
  789.                  iflags.wc_align_status = ALIGN_RIGHT;
  790.              else if (!strncmpi(op, "bottom", sizeof("bottom") - 1))
  791.                  iflags.wc_align_status = ALIGN_BOTTOM;
  792.              else {
  793.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  794.                  return FALSE;
  795.              }
  796.          } else if (negated) {
  797.              bad_negation(fullname, TRUE);
  798.              return FALSE;
  799.          }
  800.          return retval;
  801.      }
  802.  
  803.      /* WINCAP
  804.       * align_message:[left|top|right|bottom] */
  805.      fullname = "align_message";
  806.      if (match_optname(opts, fullname, sizeof("align_message") - 1, TRUE)) {
  807.          if (duplicate)
  808.              complain_about_duplicate(opts, 1);
  809.          op = string_for_opt(opts, negated);
  810.          if (op && !negated) {
  811.              if (!strncmpi(op, "left", sizeof("left") - 1))
  812.                  iflags.wc_align_message = ALIGN_LEFT;
  813.              else if (!strncmpi(op, "top", sizeof("top") - 1))
  814.                  iflags.wc_align_message = ALIGN_TOP;
  815.              else if (!strncmpi(op, "right", sizeof("right") - 1))
  816.                  iflags.wc_align_message = ALIGN_RIGHT;
  817.              else if (!strncmpi(op, "bottom", sizeof("bottom") - 1))
  818.                  iflags.wc_align_message = ALIGN_BOTTOM;
  819.              else {
  820.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  821.                  return FALSE;
  822.              }
  823.          } else if (negated) {
  824.              bad_negation(fullname, TRUE);
  825.              return FALSE;
  826.          }
  827.          return retval;
  828.      }
  829.  
  830.      /* the order to list inventory */
  831.      fullname = "packorder";
  832.      if (match_optname(opts, fullname, 4, TRUE)) {
  833.          if (duplicate)
  834.              complain_about_duplicate(opts, 1);
  835.          if (negated) {
  836.              bad_negation(fullname, FALSE);
  837.              return FALSE;
  838.          } else if (!(op = string_for_opt(opts, FALSE)))
  839.              return FALSE;
  840.  
  841.          if (!change_inv_order(op))
  842.              return FALSE;
  843.          return retval;
  844.      }
  845.  
  846.      /* user can change required response for some prompts (quit, die, hit),
  847.         or add an extra prompt (pray, Remove) that isn't ordinarily there */
  848.      fullname = "paranoid_confirmation";
  849.      if (match_optname(opts, fullname, 8, TRUE)) {
  850.          /* at present we don't complain about duplicates for this
  851.             option, but we do throw away the old settings whenever
  852.             we process a new one [clearing old flags is essential
  853.             for handling default paranoid_confirm:pray sanely] */
  854.          flags.paranoia_bits = 0; /* clear all */
  855.          if (negated) {
  856.              flags.paranoia_bits = 0; /* [now redundant...] */
  857.          } else if ((op = string_for_opt(opts, TRUE)) != 0) {
  858.              char *pp, buf[BUFSZ];
  859.  
  860.              strncpy(buf, op, sizeof buf - 1);
  861.              buf[sizeof buf - 1] = '\0';
  862.              op = mungspaces(buf);
  863.              for (;;) {
  864.                  /* We're looking to parse
  865.                     "paranoid_confirm:whichone wheretwo whothree"
  866.                     and "paranoid_confirm:" prefix has already
  867.                     been stripped off by the time we get here */
  868.                  pp = index(op, ' ');
  869.                  if (pp)
  870.                      *pp = '\0';
  871.                  /* we aren't matching option names but match_optname
  872.                     does what we want once we've broken the space
  873.                     delimited aggregate into separate tokens */
  874.                  for (i = 0; i < SIZE(paranoia); ++i) {
  875.                      if (match_optname(op, paranoia[i].argname,
  876.                                        paranoia[i].argMinLen, FALSE)
  877.                          || (paranoia[i].synonym
  878.                              && match_optname(op, paranoia[i].synonym,
  879.                                               paranoia[i].synMinLen, FALSE))) {
  880.                          if (paranoia[i].flagmask)
  881.                              flags.paranoia_bits |= paranoia[i].flagmask;
  882.                          else /* 0 == "none", so clear all */
  883.                              flags.paranoia_bits = 0;
  884.                          break;
  885.                      }
  886.                  }
  887.                  if (i == SIZE(paranoia)) {
  888.                      /* didn't match anything, so arg is bad;
  889.                         any flags already set will stay set */
  890.                      config_error_add("Unknown %s parameter '%s'",
  891.                                       fullname, op);
  892.                      return FALSE;
  893.                  }
  894.                  /* move on to next token */
  895.                  if (pp)
  896.                      op = pp + 1;
  897.                  else
  898.                      break; /* no next token */
  899.              } /* for(;;) */
  900.          } else
  901.              return FALSE;
  902.          return retval;
  903.      }
  904.  
  905.      /* accept deprecated boolean; superseded by paranoid_confirm:pray */
  906.      fullname = "prayconfirm";
  907.      if (match_optname(opts, fullname, 4, FALSE)) {
  908.          if (negated)
  909.              flags.paranoia_bits &= ~PARANOID_PRAY;
  910.          else
  911.              flags.paranoia_bits |= PARANOID_PRAY;
  912.          return retval;
  913.      }
  914.  
  915.      /* maximum burden picked up before prompt (Warren Cheung) */
  916.      fullname = "pickup_burden";
  917.      if (match_optname(opts, fullname, 8, TRUE)) {
  918.          if (duplicate)
  919.              complain_about_duplicate(opts, 1);
  920.          if (negated) {
  921.              bad_negation(fullname, FALSE);
  922.              return FALSE;
  923.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  924.              switch (lowc(*op)) {
  925.              case 'u': /* Unencumbered */
  926.                  flags.pickup_burden = UNENCUMBERED;
  927.                  break;
  928.              case 'b': /* Burdened (slight encumbrance) */
  929.                  flags.pickup_burden = SLT_ENCUMBER;
  930.                  break;
  931.              case 's': /* streSsed (moderate encumbrance) */
  932.                  flags.pickup_burden = MOD_ENCUMBER;
  933.                  break;
  934.              case 'n': /* straiNed (heavy encumbrance) */
  935.                  flags.pickup_burden = HVY_ENCUMBER;
  936.                  break;
  937.              case 'o': /* OverTaxed (extreme encumbrance) */
  938.              case 't':
  939.                  flags.pickup_burden = EXT_ENCUMBER;
  940.                  break;
  941.              case 'l': /* overLoaded */
  942.                  flags.pickup_burden = OVERLOADED;
  943.                  break;
  944.              default:
  945.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  946.                  return FALSE;
  947.              }
  948.          } else
  949.              return FALSE;
  950.          return retval;
  951.      }
  952.  
  953.      /* types of objects to pick up automatically */
  954.      fullname = "pickup_types";
  955.      if (match_optname(opts, fullname, 8, TRUE)) {
  956.          char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], qbuf[QBUFSZ],
  957.              abuf[BUFSZ] = DUMMY;
  958.          int oc_sym;
  959.          boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
  960.  
  961.          if (duplicate)
  962.              complain_about_duplicate(opts, 1);
  963.          oc_to_str(flags.pickup_types, tbuf);
  964.          flags.pickup_types[0] = '\0'; /* all */
  965.          op = string_for_opt(opts, (compat || !initial));
  966.          if (!op) {
  967.              if (compat || negated || initial) {
  968.                  /* for backwards compatibility, "pickup" without a
  969.                     value is a synonym for autopickup of all types
  970.                     (and during initialization, we can't prompt yet) */
  971.                  flags.pickup = !negated;
  972.                  return retval;
  973.              }
  974.              oc_to_str(flags.inv_order, ocl);
  975.              use_menu = TRUE;
  976.              if (flags.menu_style == MENU_TRADITIONAL
  977.                  || flags.menu_style == MENU_COMBINATION) {
  978.                  use_menu = FALSE;
  979.                  Sprintf(qbuf, "New %s: [%s am] (%s)", fullname, ocl,
  980.                          *tbuf ? tbuf : "all");
  981.                  getlin(qbuf, abuf);
  982.                  op = mungspaces(abuf);
  983.                  if (abuf[0] == '\0' || abuf[0] == '\033')
  984.                      op = tbuf; /* restore */
  985.                  else if (abuf[0] == 'm')
  986.                      use_menu = TRUE;
  987.              }
  988.              if (use_menu) {
  989.                  (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE, ocl,
  990.                                             tbuf);
  991.                  op = tbuf;
  992.              }
  993.          }
  994.          if (negated) {
  995.              bad_negation(fullname, TRUE);
  996.              return FALSE;
  997.          }
  998.          while (*op == ' ')
  999.              op++;
  1000.          if (*op != 'a' && *op != 'A') {
  1001.              num = 0;
  1002.              while (*op) {
  1003.                  oc_sym = def_char_to_objclass(*op);
  1004.                  /* make sure all are valid obj symbols occurring once */
  1005.                  if (oc_sym != MAXOCLASSES
  1006.                      && !index(flags.pickup_types, oc_sym)) {
  1007.                      flags.pickup_types[num] = (char) oc_sym;
  1008.                      flags.pickup_types[++num] = '\0';
  1009.                  } else
  1010.                      badopt = TRUE;
  1011.                  op++;
  1012.              }
  1013.              if (badopt) {
  1014.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  1015.                  return FALSE;
  1016.              }
  1017.          }
  1018.          return retval;
  1019.      }
  1020.  
  1021.      /* pile limit: when walking over objects, number which triggers
  1022.         "there are several/many objects here" instead of listing them */
  1023.      fullname = "pile_limit";
  1024.      if (match_optname(opts, fullname, 4, TRUE)) {
  1025.          if (duplicate)
  1026.              complain_about_duplicate(opts, 1);
  1027.          op = string_for_opt(opts, negated);
  1028.          if ((negated && !op) || (!negated && op))
  1029.              flags.pile_limit = negated ? 0 : atoi(op);
  1030.          else if (negated) {
  1031.              bad_negation(fullname, TRUE);
  1032.              return FALSE;
  1033.          } else /* !op */
  1034.              flags.pile_limit = PILE_LIMIT_DFLT;
  1035.          /* sanity check */
  1036.          if (flags.pile_limit < 0)
  1037.              flags.pile_limit = PILE_LIMIT_DFLT;
  1038.          return retval;
  1039.      }
  1040.  
  1041.      /* play mode: normal, explore/discovery, or debug/wizard */
  1042.      fullname = "playmode";
  1043.      if (match_optname(opts, fullname, 4, TRUE)) {
  1044.          if (duplicate)
  1045.              complain_about_duplicate(opts, 1);
  1046.          if (negated)
  1047.              bad_negation(fullname, FALSE);
  1048.          if (duplicate || negated)
  1049.              return FALSE;
  1050.          op = string_for_opt(opts, FALSE);
  1051.          if (!op)
  1052.              return FALSE;
  1053.          if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
  1054.              wizard = discover = FALSE;
  1055.          } else if (!strncmpi(op, "explore", 6)
  1056.                     || !strncmpi(op, "discovery", 6)) {
  1057.              wizard = FALSE, discover = TRUE;
  1058.          } else if (!strncmpi(op, "debug", 5) || !strncmpi(op, "wizard", 6)) {
  1059.              wizard = TRUE, discover = FALSE;
  1060.          } else {
  1061.              config_error_add("Invalid value for \"%s\":%s", fullname, op);
  1062.              return FALSE;
  1063.          }
  1064.          return retval;
  1065.      }
  1066.  
  1067.      /* WINCAP
  1068.       * player_selection: dialog | prompts */
  1069.      fullname = "player_selection";
  1070.      if (match_optname(opts, fullname, sizeof("player_selection") - 1, TRUE)) {
  1071.          if (duplicate)
  1072.              complain_about_duplicate(opts, 1);
  1073.          op = string_for_opt(opts, negated);
  1074.          if (op && !negated) {
  1075.              if (!strncmpi(op, "dialog", sizeof("dialog") - 1))
  1076.                  iflags.wc_player_selection = VIA_DIALOG;
  1077.              else if (!strncmpi(op, "prompt", sizeof("prompt") - 1))
  1078.                  iflags.wc_player_selection = VIA_PROMPTS;
  1079.              else {
  1080.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  1081.                  return FALSE;
  1082.              }
  1083.          } else if (negated) {
  1084.              bad_negation(fullname, TRUE);
  1085.              return FALSE;
  1086.          }
  1087.          return retval;
  1088.      }
  1089.  
  1090.      /* things to disclose at end of game */
  1091.      fullname = "disclose";
  1092.      if (match_optname(opts, fullname, 7, TRUE)) {
  1093.          /*
  1094.           * The order that the end_disclose options are stored:
  1095.           *      inventory, attribs, vanquished, genocided,
  1096.           *      conduct, overview.
  1097.           * There is an array in flags:
  1098.           *      end_disclose[NUM_DISCLOSURE_OPT];
  1099.           * with option settings for the each of the following:
  1100.           * iagvc [see disclosure_options in decl.c]:
  1101.           * Legal setting values in that array are:
  1102.           *      DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
  1103.           *      DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
  1104.           *      DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
  1105.           *      DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
  1106.           *
  1107.           * Those setting values can be used in the option
  1108.           * string as a prefix to get the desired behaviour.
  1109.           *
  1110.           * For backward compatibility, no prefix is required,
  1111.           * and the presence of a i,a,g,v, or c without a prefix
  1112.           * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
  1113.           */
  1114.          int idx, prefix_val;
  1115.  
  1116.          if (duplicate)
  1117.              complain_about_duplicate(opts, 1);
  1118.          op = string_for_opt(opts, TRUE);
  1119.          if (op && negated) {
  1120.              bad_negation(fullname, TRUE);
  1121.              return FALSE;
  1122.          }
  1123.          /* "disclose" without a value means "all with prompting"
  1124.             and negated means "none without prompting" */
  1125.          if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
  1126.              if (op && !strcmpi(op, "none"))
  1127.                  negated = TRUE;
  1128.              for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
  1129.                  flags.end_disclose[num] = negated
  1130.                                                ? DISCLOSE_NO_WITHOUT_PROMPT
  1131.                                                : DISCLOSE_PROMPT_DEFAULT_YES;
  1132.              return retval;
  1133.          }
  1134.  
  1135.          num = 0;
  1136.          prefix_val = -1;
  1137.          while (*op && num < sizeof flags.end_disclose - 1) {
  1138.              static char valid_settings[] = {
  1139.                  DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
  1140.                  DISCLOSE_PROMPT_DEFAULT_SPECIAL,
  1141.                  DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT,
  1142.                  DISCLOSE_SPECIAL_WITHOUT_PROMPT, '\0'
  1143.              };
  1144.              register char c, *dop;
  1145.  
  1146.              c = lowc(*op);
  1147.              if (c == 'k')
  1148.                  c = 'v'; /* killed -> vanquished */
  1149.              if (c == 'd')
  1150.                  c = 'o'; /* dungeon -> overview */
  1151.              dop = index(disclosure_options, c);
  1152.              if (dop) {
  1153.                  idx = (int) (dop - disclosure_options);
  1154.                  if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
  1155.                      impossible("bad disclosure index %d %c", idx, c);
  1156.                      continue;
  1157.                  }
  1158.                  if (prefix_val != -1) {
  1159.                      if (*dop != 'v') {
  1160.                          if (prefix_val == DISCLOSE_PROMPT_DEFAULT_SPECIAL)
  1161.                              prefix_val = DISCLOSE_PROMPT_DEFAULT_YES;
  1162.                          if (prefix_val == DISCLOSE_SPECIAL_WITHOUT_PROMPT)
  1163.                              prefix_val = DISCLOSE_YES_WITHOUT_PROMPT;
  1164.                      }
  1165.                      flags.end_disclose[idx] = prefix_val;
  1166.                      prefix_val = -1;
  1167.                  } else
  1168.                      flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
  1169.              } else if (index(valid_settings, c)) {
  1170.                  prefix_val = c;
  1171.              } else if (c == ' ') {
  1172.                  ; /* do nothing */
  1173.              } else {
  1174.                  config_error_add("Unknown %s parameter '%c'", fullname, *op);
  1175.                  return FALSE;
  1176.              }
  1177.              op++;
  1178.          }
  1179.          return retval;
  1180.      }
  1181.  
  1182.      /* scores:5t[op] 5a[round] o[wn] */
  1183.      fullname = "scores";
  1184.      if (match_optname(opts, fullname, 4, TRUE)) {
  1185.          if (duplicate)
  1186.              complain_about_duplicate(opts, 1);
  1187.          if (negated) {
  1188.              bad_negation(fullname, FALSE);
  1189.              return FALSE;
  1190.          }
  1191.          if (!(op = string_for_opt(opts, FALSE)))
  1192.              return FALSE;
  1193.  
  1194.          while (*op) {
  1195.              int inum = 1;
  1196.  
  1197.              if (digit(*op)) {
  1198.                  inum = atoi(op);
  1199.                  while (digit(*op))
  1200.                      op++;
  1201.              } else if (*op == '!') {
  1202.                  negated = !negated;
  1203.                  op++;
  1204.              }
  1205.              while (*op == ' ')
  1206.                  op++;
  1207.  
  1208.              switch (*op) {
  1209.              case 't':
  1210.              case 'T':
  1211.                  flags.end_top = inum;
  1212.                  break;
  1213.              case 'a':
  1214.              case 'A':
  1215.                  flags.end_around = inum;
  1216.                  break;
  1217.              case 'o':
  1218.              case 'O':
  1219.                  flags.end_own = !negated;
  1220.                  break;
  1221.              default:
  1222.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  1223.                  return FALSE;
  1224.              }
  1225.              while (letter(*++op) || *op == ' ')
  1226.                  continue;
  1227.              if (*op == '/')
  1228.                  op++;
  1229.          }
  1230.          return retval;
  1231.      }
  1232.  
  1233.      fullname = "sortloot";
  1234.      if (match_optname(opts, fullname, 4, TRUE)) {
  1235.          op = string_for_env_opt(fullname, opts, FALSE);
  1236.          if (op) {
  1237.              char c = lowc(*op);
  1238.  
  1239.              switch (c) {
  1240.              case 'n': /* none */
  1241.              case 'l': /* loot (pickup) */
  1242.              case 'f': /* full (pickup + invent) */
  1243.                  flags.sortloot = c;
  1244.                  break;
  1245.              default:
  1246.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  1247.                  return FALSE;
  1248.              }
  1249.          } else
  1250.              return FALSE;
  1251.          return retval;
  1252.      }
  1253.  
  1254.      fullname = "suppress_alert";
  1255.      if (match_optname(opts, fullname, 4, TRUE)) {
  1256.          if (duplicate)
  1257.              complain_about_duplicate(opts, 1);
  1258.          op = string_for_opt(opts, negated);
  1259.          if (negated) {
  1260.              bad_negation(fullname, FALSE);
  1261.              return FALSE;
  1262.          } else if (op)
  1263.              (void) feature_alert_opts(op, fullname);
  1264.          return retval;
  1265.      }
  1266.  
  1267.  #ifdef VIDEOSHADES
  1268.      /* videocolors:string */
  1269.      fullname = "videocolors";
  1270.      if (match_optname(opts, fullname, 6, TRUE)
  1271.          || match_optname(opts, "videocolours", 10, TRUE)) {
  1272.          if (duplicate)
  1273.              complain_about_duplicate(opts, 1);
  1274.          if (negated) {
  1275.              bad_negation(fullname, FALSE);
  1276.              return FALSE;
  1277.          } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1278.              return FALSE;
  1279.          }
  1280.          if (!assign_videocolors(opts)) /* TODO: error msg */
  1281.              return FALSE;
  1282.          return retval;
  1283.      }
  1284.      /* videoshades:string */
  1285.      fullname = "videoshades";
  1286.      if (match_optname(opts, fullname, 6, TRUE)) {
  1287.          if (duplicate)
  1288.              complain_about_duplicate(opts, 1);
  1289.          if (negated) {
  1290.              bad_negation(fullname, FALSE);
  1291.              return FALSE;
  1292.          } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1293.              return FALSE;
  1294.          }
  1295.          if (!assign_videoshades(opts)) /* TODO: error msg */
  1296.              return FALSE;
  1297.          return retval;
  1298.      }
  1299.  #endif /* VIDEOSHADES */
  1300.  #ifdef MSDOS
  1301.  #ifdef NO_TERMS
  1302.      /* video:string -- must be after longer tests */
  1303.      fullname = "video";
  1304.      if (match_optname(opts, fullname, 5, TRUE)) {
  1305.          if (duplicate)
  1306.              complain_about_duplicate(opts, 1);
  1307.          if (negated) {
  1308.              bad_negation(fullname, FALSE);
  1309.              return FALSE;
  1310.          } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1311.              return FALSE;
  1312.          }
  1313.          if (!assign_video(opts)) /* TODO: error msg */
  1314.              return FALSE;
  1315.          return retval;
  1316.      }
  1317.  #endif /* NO_TERMS */
  1318.      /* soundcard:string -- careful not to match boolean 'sound' */
  1319.      fullname = "soundcard";
  1320.      if (match_optname(opts, fullname, 6, TRUE)) {
  1321.          if (duplicate)
  1322.              complain_about_duplicate(opts, 1);
  1323.          if (negated) {
  1324.              bad_negation(fullname, FALSE);
  1325.              return FALSE;
  1326.          } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1327.              return FALSE;
  1328.          }
  1329.          if (!assign_soundcard(opts)) /* TODO: error msg */
  1330.              return FALSE;
  1331.          return retval;
  1332.      }
  1333.  #endif /* MSDOS */
  1334.  
  1335.      /* WINCAP
  1336.       *
  1337.       *  map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|
  1338.       *            ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen]
  1339.       */
  1340.      fullname = "map_mode";
  1341.      if (match_optname(opts, fullname, sizeof("map_mode") - 1, TRUE)) {
  1342.          if (duplicate)
  1343.              complain_about_duplicate(opts, 1);
  1344.          op = string_for_opt(opts, negated);
  1345.          if (op && !negated) {
  1346.              if (!strncmpi(op, "tiles", sizeof("tiles") - 1))
  1347.                  iflags.wc_map_mode = MAP_MODE_TILES;
  1348.              else if (!strncmpi(op, "ascii4x6", sizeof("ascii4x6") - 1))
  1349.                  iflags.wc_map_mode = MAP_MODE_ASCII4x6;
  1350.              else if (!strncmpi(op, "ascii6x8", sizeof("ascii6x8") - 1))
  1351.                  iflags.wc_map_mode = MAP_MODE_ASCII6x8;
  1352.              else if (!strncmpi(op, "ascii8x8", sizeof("ascii8x8") - 1))
  1353.                  iflags.wc_map_mode = MAP_MODE_ASCII8x8;
  1354.              else if (!strncmpi(op, "ascii16x8", sizeof("ascii16x8") - 1))
  1355.                  iflags.wc_map_mode = MAP_MODE_ASCII16x8;
  1356.              else if (!strncmpi(op, "ascii7x12", sizeof("ascii7x12") - 1))
  1357.                  iflags.wc_map_mode = MAP_MODE_ASCII7x12;
  1358.              else if (!strncmpi(op, "ascii8x12", sizeof("ascii8x12") - 1))
  1359.                  iflags.wc_map_mode = MAP_MODE_ASCII8x12;
  1360.              else if (!strncmpi(op, "ascii16x12", sizeof("ascii16x12") - 1))
  1361.                  iflags.wc_map_mode = MAP_MODE_ASCII16x12;
  1362.              else if (!strncmpi(op, "ascii12x16", sizeof("ascii12x16") - 1))
  1363.                  iflags.wc_map_mode = MAP_MODE_ASCII12x16;
  1364.              else if (!strncmpi(op, "ascii10x18", sizeof("ascii10x18") - 1))
  1365.                  iflags.wc_map_mode = MAP_MODE_ASCII10x18;
  1366.              else if (!strncmpi(op, "fit_to_screen",
  1367.                                 sizeof("fit_to_screen") - 1))
  1368.                  iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
  1369.              else {
  1370.                  config_error_add("Unknown %s parameter '%s'", fullname, op);
  1371.                  return FALSE;
  1372.              }
  1373.          } else if (negated) {
  1374.              bad_negation(fullname, TRUE);
  1375.              return FALSE;
  1376.          }
  1377.          return retval;
  1378.      }
  1379.  
  1380.      /* WINCAP
  1381.       * scroll_amount:nn */
  1382.      fullname = "scroll_amount";
  1383.      if (match_optname(opts, fullname, sizeof "scroll_amount" - 1, TRUE)) {
  1384.          if (duplicate)
  1385.              complain_about_duplicate(opts, 1);
  1386.          op = string_for_opt(opts, negated);
  1387.          if ((negated && !op) || (!negated && op)) {
  1388.              iflags.wc_scroll_amount = negated ? 1 : atoi(op);
  1389.          } else if (negated) {
  1390.              bad_negation(fullname, TRUE);
  1391.              return FALSE;
  1392.          }
  1393.          return retval;
  1394.      }
  1395.  
  1396.      /* WINCAP
  1397.       * scroll_margin:nn */
  1398.      fullname = "scroll_margin";
  1399.      if (match_optname(opts, fullname, sizeof "scroll_margin" - 1, TRUE)) {
  1400.          if (duplicate)
  1401.              complain_about_duplicate(opts, 1);
  1402.          op = string_for_opt(opts, negated);
  1403.          if ((negated && !op) || (!negated && op)) {
  1404.              iflags.wc_scroll_margin = negated ? 5 : atoi(op);
  1405.          } else if (negated) {
  1406.              bad_negation(fullname, TRUE);
  1407.              return FALSE;
  1408.          }
  1409.          return retval;
  1410.      }
  1411.  
  1412.      fullname = "subkeyvalue";
  1413.      if (match_optname(opts, fullname, 5, TRUE)) {
  1414.          /* no duplicate complaint here */
  1415.          if (negated) {
  1416.              bad_negation(fullname, FALSE);
  1417.              return FALSE;
  1418.          } else {
  1419.  #if defined(WIN32)
  1420.              op = string_for_opt(opts, 0);
  1421.              if (!op)
  1422.                  return FALSE;
  1423.              map_subkeyvalue(op);
  1424.  #endif
  1425.          }
  1426.          return retval;
  1427.      }
  1428.  
  1429.      /* WINCAP
  1430.       * tile_width:nn */
  1431.      fullname = "tile_width";
  1432.      if (match_optname(opts, fullname, sizeof("tile_width") - 1, TRUE)) {
  1433.          if (duplicate)
  1434.              complain_about_duplicate(opts, 1);
  1435.          op = string_for_opt(opts, negated);
  1436.          if ((negated && !op) || (!negated && op)) {
  1437.              iflags.wc_tile_width = negated ? 0 : atoi(op);
  1438.          } else if (negated) {
  1439.              bad_negation(fullname, TRUE);
  1440.              return FALSE;
  1441.          }
  1442.          return retval;
  1443.      }
  1444.      /* WINCAP
  1445.       * tile_file:name */
  1446.      fullname = "tile_file";
  1447.      if (match_optname(opts, fullname, sizeof("tile_file") - 1, TRUE)) {
  1448.          if (duplicate)
  1449.              complain_about_duplicate(opts, 1);
  1450.          if ((op = string_for_opt(opts, FALSE)) != 0) {
  1451.              if (iflags.wc_tile_file)
  1452.                  free(iflags.wc_tile_file);
  1453.              iflags.wc_tile_file = dupstr(op);
  1454.          } else
  1455.              return FALSE;
  1456.          return retval;
  1457.      }
  1458.      /* WINCAP
  1459.       * tile_height:nn */
  1460.      fullname = "tile_height";
  1461.      if (match_optname(opts, fullname, sizeof("tile_height") - 1, TRUE)) {
  1462.          if (duplicate)
  1463.              complain_about_duplicate(opts, 1);
  1464.          op = string_for_opt(opts, negated);
  1465.          if ((negated && !op) || (!negated && op)) {
  1466.              iflags.wc_tile_height = negated ? 0 : atoi(op);
  1467.          } else if (negated) {
  1468.              bad_negation(fullname, TRUE);
  1469.              return FALSE;
  1470.          }
  1471.          return retval;
  1472.      }
  1473.  
  1474.      /* WINCAP
  1475.       * vary_msgcount:nn */
  1476.      fullname = "vary_msgcount";
  1477.      if (match_optname(opts, fullname, sizeof("vary_msgcount") - 1, TRUE)) {
  1478.          if (duplicate)
  1479.              complain_about_duplicate(opts, 1);
  1480.          op = string_for_opt(opts, negated);
  1481.          if ((negated && !op) || (!negated && op)) {
  1482.              iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
  1483.          } else if (negated) {
  1484.              bad_negation(fullname, TRUE);
  1485.              return FALSE;
  1486.          }
  1487.          return retval;
  1488.      }
  1489.  
  1490.      /*
  1491.       * windowtype:  option to choose the interface for binaries built
  1492.       * with support for more than one interface (tty + X11, for instance).
  1493.       *
  1494.       * Ideally, 'windowtype' should be processed first, because it
  1495.       * causes the wc_ and wc2_ flags to be set up.
  1496.       * For user, making it be first in a config file is trivial, use
  1497.       * OPTIONS=windowtype:Foo
  1498.       * as the first non-comment line of the file.
  1499.       * Making it first in NETHACKOPTIONS requires it to be at the _end_
  1500.       * because option strings are processed from right to left.
  1501.       */
  1502.      fullname = "windowtype";
  1503.      if (match_optname(opts, fullname, 3, TRUE)) {
  1504.          if (duplicate)
  1505.              complain_about_duplicate(opts, 1);
  1506.          if (negated) {
  1507.              bad_negation(fullname, FALSE);
  1508.              return FALSE;
  1509.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1510.              char buf[WINTYPELEN];
  1511.  
  1512.              nmcpy(buf, op, WINTYPELEN);
  1513.              choose_windows(buf);
  1514.          } else
  1515.              return FALSE;
  1516.          return retval;
  1517.      }
  1518.  
  1519.  #ifdef WINCHAIN
  1520.      fullname = "windowchain";
  1521.      if (match_optname(opts, fullname, 3, TRUE)) {
  1522.          if (negated) {
  1523.              bad_negation(fullname, FALSE);
  1524.              return FALSE;
  1525.          } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1526.              char buf[WINTYPELEN];
  1527.  
  1528.              nmcpy(buf, op, WINTYPELEN);
  1529.              addto_windowchain(buf);
  1530.          } else
  1531.              return FALSE;
  1532.          return retval;
  1533.      }
  1534.  #endif
  1535.  
  1536.      /* WINCAP
  1537.       * setting window colors
  1538.       * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
  1539.       */
  1540.      fullname = "windowcolors";
  1541.      if (match_optname(opts, fullname, 7, TRUE)) {
  1542.          if (duplicate)
  1543.              complain_about_duplicate(opts, 1);
  1544.          if ((op = string_for_opt(opts, FALSE)) != 0) {
  1545.              if (!wc_set_window_colors(op)) /* TODO: error msg*/
  1546.                  return FALSE;
  1547.          } else if (negated)
  1548.              bad_negation(fullname, TRUE);
  1549.          return retval;
  1550.      }
  1551.  
  1552.      /* menustyle:traditional or combination or full or partial */
  1553.      fullname = "menustyle";
  1554.      if (match_optname(opts, fullname, 4, TRUE)) {
  1555.          int tmp;
  1556.          boolean val_required = (strlen(opts) > 5 && !negated);
  1557.  
  1558.          if (duplicate)
  1559.              complain_about_duplicate(opts, 1);
  1560.          if (!(op = string_for_opt(opts, !val_required))) {
  1561.              if (val_required)
  1562.                  return FALSE; /* string_for_opt gave feedback */
  1563.              tmp = negated ? 'n' : 'f';
  1564.          } else {
  1565.              tmp = lowc(*op);
  1566.          }
  1567.          switch (tmp) {
  1568.          case 'n': /* none */
  1569.          case 't': /* traditional: prompt for class(es) by symbol,
  1570.                       prompt for each item within class(es) one at a time */
  1571.              flags.menu_style = MENU_TRADITIONAL;
  1572.              break;
  1573.          case 'c': /* combination: prompt for class(es) by symbol,
  1574.                       choose items within selected class(es) by menu */
  1575.              flags.menu_style = MENU_COMBINATION;
  1576.              break;
  1577.          case 'f': /* full: choose class(es) by first menu,
  1578.                       choose items within selected class(es) by second menu */
  1579.              flags.menu_style = MENU_FULL;
  1580.              break;
  1581.          case 'p': /* partial: skip class filtering,
  1582.                       choose items among all classes by menu */
  1583.              flags.menu_style = MENU_PARTIAL;
  1584.              break;
  1585.          default:
  1586.              config_error_add("Unknown %s parameter '%s'", fullname, op);
  1587.              return FALSE;
  1588.          }
  1589.          return retval;
  1590.      }
  1591.  
  1592.      fullname = "menu_headings";
  1593.      if (match_optname(opts, fullname, 12, TRUE)) {
  1594.          int tmpattr;
  1595.  
  1596.          if (duplicate)
  1597.              complain_about_duplicate(opts, 1);
  1598.          if (negated) {
  1599.              bad_negation(fullname, FALSE);
  1600.              return FALSE;
  1601.          } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1602.              return FALSE;
  1603.          }
  1604.          tmpattr = match_str2attr(opts, TRUE);
  1605.          if (tmpattr == -1)
  1606.              return FALSE;
  1607.          else
  1608.              iflags.menu_headings = tmpattr;
  1609.          return retval;
  1610.      }
  1611.  
  1612.      /* check for menu command mapping */
  1613.      for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
  1614.          fullname = default_menu_cmd_info[i].name;
  1615.          if (duplicate)
  1616.              complain_about_duplicate(opts, 1);
  1617.          if (match_optname(opts, fullname, (int) strlen(fullname), TRUE)) {
  1618.              if (negated) {
  1619.                  bad_negation(fullname, FALSE);
  1620.                  return FALSE;
  1621.              } else if ((op = string_for_opt(opts, FALSE)) != 0) {
  1622.                  char c, op_buf[BUFSZ];
  1623.  
  1624.                  escapes(op, op_buf);
  1625.                  c = *op_buf;
  1626.  
  1627.                  if (illegal_menu_cmd_key(c)) {
  1628.                      return FALSE;
  1629.                  } else
  1630.                      add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
  1631.              }
  1632.              return retval;
  1633.          }
  1634.      }
  1635.  
  1636.      /* hilite fields in status prompt */
  1637.      fullname = "hilite_status";
  1638.      if (match_optname(opts, fullname, 13, TRUE)) {
  1639.  #ifdef STATUS_HILITES
  1640.          if (duplicate)
  1641.              complain_about_duplicate(opts, 1);
  1642.          op = string_for_opt(opts, TRUE);
  1643.          if (op && negated) {
  1644.              clear_status_hilites();
  1645.              return retval;
  1646.          } else if (!op) {
  1647.              config_error_add("Value is mandatory for hilite_status");
  1648.              return FALSE;
  1649.          }
  1650.          if (!parse_status_hl1(op, tfrom_file))
  1651.              return FALSE;
  1652.          return retval;
  1653.  #else
  1654.          config_error_add("'%s' is not supported", fullname);
  1655.          return FALSE;
  1656.  #endif
  1657.      }
  1658.  
  1659.      /* control over whether highlights should be displayed, and for how long */
  1660.      fullname = "statushilites";
  1661.      if (match_optname(opts, fullname, 9, TRUE)) {
  1662.  #ifdef STATUS_HILITES
  1663.          if (negated) {
  1664.              iflags.hilite_delta = 0L;
  1665.          } else {
  1666.              op = string_for_opt(opts, TRUE);
  1667.              iflags.hilite_delta = (!op || !*op) ? 3L : atol(op);
  1668.              if (iflags.hilite_delta < 0L)
  1669.                  iflags.hilite_delta = 1L;
  1670.          }
  1671.          if (!tfrom_file)
  1672.              reset_status_hilites();
  1673.          return retval;
  1674.  #else
  1675.          config_error_add("'%s' is not supported", fullname);
  1676.          return FALSE;
  1677.  #endif
  1678.      }
  1679.  
  1680.      fullname = "DECgraphics";
  1681.      if (match_optname(opts, fullname, 3, TRUE)) {
  1682.  #ifdef BACKWARD_COMPAT
  1683.          boolean badflag = FALSE;
  1684.  
  1685.          if (duplicate)
  1686.              complain_about_duplicate(opts, 1);
  1687.          if (!negated) {
  1688.              /* There is no rogue level DECgraphics-specific set */
  1689.              if (symset[PRIMARY].name) {
  1690.                  badflag = TRUE;
  1691.              } else {
  1692.                  symset[PRIMARY].name = dupstr(fullname);
  1693.                  if (!read_sym_file(PRIMARY)) {
  1694.                      badflag = TRUE;
  1695.                      clear_symsetentry(PRIMARY, TRUE);
  1696.                  } else
  1697.                      switch_symbols(TRUE);
  1698.              }
  1699.              if (badflag) {
  1700.                  config_error_add("Failure to load symbol set %s.", fullname);
  1701.                  return FALSE;
  1702.              }
  1703.          }
  1704.          return retval;
  1705.  #else
  1706.          config_error_add("'%s' no longer supported; use 'symset:%s' instead",
  1707.                           fullname, fullname);
  1708.          return FALSE;
  1709.  #endif
  1710.      } /* "DECgraphics" */
  1711.  
  1712.      fullname = "IBMgraphics";
  1713.      if (match_optname(opts, fullname, 3, TRUE)) {
  1714.  #ifdef BACKWARD_COMPAT
  1715.          const char *sym_name = fullname;
  1716.          boolean badflag = FALSE;
  1717.  
  1718.          if (duplicate)
  1719.              complain_about_duplicate(opts, 1);
  1720.          if (!negated) {
  1721.              for (i = 0; i < NUM_GRAPHICS; ++i) {
  1722.                  if (symset[i].name) {
  1723.                      badflag = TRUE;
  1724.                  } else {
  1725.                      if (i == ROGUESET)
  1726.                          sym_name = "RogueIBM";
  1727.                      symset[i].name = dupstr(sym_name);
  1728.                      if (!read_sym_file(i)) {
  1729.                          badflag = TRUE;
  1730.                          clear_symsetentry(i, TRUE);
  1731.                          break;
  1732.                      }
  1733.                  }
  1734.              }
  1735.              if (badflag) {
  1736.                  config_error_add("Failure to load symbol set %s.", sym_name);
  1737.                  return FALSE;
  1738.              } else {
  1739.                  switch_symbols(TRUE);
  1740.                  if (!initial && Is_rogue_level(&u.uz))
  1741.                      assign_graphics(ROGUESET);
  1742.              }
  1743.          }
  1744.          return retval;
  1745.  #else
  1746.          config_error_add("'%s' no longer supported; use 'symset:%s' instead",
  1747.                           fullname, fullname);
  1748.          return FALSE;
  1749.  #endif
  1750.      } /* "IBMgraphics" */
  1751.  
  1752.      fullname = "MACgraphics";
  1753.      if (match_optname(opts, fullname, 3, TRUE)) {
  1754.  #if defined(MAC_GRAPHICS_ENV) && defined(BACKWARD_COMPAT)
  1755.          boolean badflag = FALSE;
  1756.  
  1757.          if (duplicate)
  1758.              complain_about_duplicate(opts, 1);
  1759.          if (!negated) {
  1760.              if (symset[PRIMARY].name) {
  1761.                  badflag = TRUE;
  1762.              } else {
  1763.                  symset[PRIMARY].name = dupstr(fullname);
  1764.                  if (!read_sym_file(PRIMARY)) {
  1765.                      badflag = TRUE;
  1766.                      clear_symsetentry(PRIMARY, TRUE);
  1767.                  }
  1768.              }
  1769.              if (badflag) {
  1770.                  config_error_add("Failure to load symbol set %s.", fullname);
  1771.                  return FALSE;
  1772.              } else {
  1773.                  switch_symbols(TRUE);
  1774.                  if (!initial && Is_rogue_level(&u.uz))
  1775.                      assign_graphics(ROGUESET);
  1776.              }
  1777.          }
  1778.          return retval;
  1779.  #else   /* !(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */
  1780.          config_error_add("'%s' %s; use 'symset:%s' instead",
  1781.                           fullname,
  1782.  #ifdef MAC_GRAPHICS_ENV /* implies BACKWARD_COMPAT is not defined */
  1783.                           "no longer supported",
  1784.  #else
  1785.                           "is not supported",
  1786.  #endif
  1787.                           fullname);
  1788.          return FALSE;
  1789.  #endif  /* ?(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */
  1790.      } /* "MACgraphics" */
  1791.  
  1792.      /* OK, if we still haven't recognized the option, check the boolean
  1793.       * options list
  1794.       */
  1795.      for (i = 0; boolopt[i].name; i++) {
  1796.          if (match_optname(opts, boolopt[i].name, 3, TRUE)) {
  1797.              /* options that don't exist */
  1798.              if (!boolopt[i].addr) {
  1799.                  if (!initial && !negated)
  1800.                      pline_The("\"%s\" option is not available.",
  1801.                                boolopt[i].name);
  1802.                  return retval;
  1803.              }
  1804.              /* options that must come from config file */
  1805.              if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
  1806.                  rejectoption(boolopt[i].name);
  1807.                  return retval;
  1808.              }
  1809.  
  1810.              op = string_for_opt(opts, TRUE);
  1811.  
  1812.              if (op) {
  1813.                  if (negated) {
  1814.                      config_error_add(
  1815.                             "Negated boolean '%s' should not have a parameter",
  1816.                                       boolopt[i].name);
  1817.                      return FALSE;
  1818.                  }
  1819.                  if (!strcmp(op, "true") || !strcmp(op, "yes")) {
  1820.                      negated = FALSE;
  1821.                  } else if (!strcmp(op, "false") || !strcmp(op, "no")) {
  1822.                      negated = TRUE;
  1823.                  } else {
  1824.                      config_error_add("Illegal parameter for a boolean");
  1825.                      return FALSE;
  1826.                  }
  1827.              }
  1828.  
  1829.              *(boolopt[i].addr) = !negated;
  1830.  
  1831.              /* 0 means boolean opts */
  1832.              if (duplicate_opt_detection(boolopt[i].name, 0))
  1833.                  complain_about_duplicate(boolopt[i].name, 0);
  1834.  #ifdef RLECOMP
  1835.              if (boolopt[i].addr == &iflags.rlecomp)
  1836.                  set_savepref(iflags.rlecomp ? "rlecomp" : "!rlecomp");
  1837.  #endif
  1838.  #ifdef ZEROCOMP
  1839.              if (boolopt[i].addr == &iflags.zerocomp)
  1840.                  set_savepref(iflags.zerocomp ? "zerocomp" : "externalcomp");
  1841.  #endif
  1842.              if (boolopt[i].addr == &iflags.wc_ascii_map) {
  1843.                  /* toggling ascii_map; set tiled_map to its opposite;
  1844.                     what does it mean to turn off ascii map if tiled map
  1845.                     isn't supported? -- right now, we do nothing */
  1846.                  iflags.wc_tiled_map = negated;
  1847.              } else if (boolopt[i].addr == &iflags.wc_tiled_map) {
  1848.                  /* toggling tiled_map; set ascii_map to its opposite;
  1849.                     as with ascii_map, what does it mean to turn off tiled
  1850.                     map if ascii map isn't supported? */
  1851.                  iflags.wc_ascii_map = negated;
  1852.              }
  1853.              /* only do processing below if setting with doset() */
  1854.              if (initial)
  1855.                  return retval;
  1856.  
  1857.              if (boolopt[i].addr == &flags.time
  1858.  #ifdef SCORE_ON_BOTL
  1859.                  || boolopt[i].addr == &flags.showscore
  1860.  #endif
  1861.                  || boolopt[i].addr == &flags.showexp) {
  1862.  #ifdef STATUS_HILITES
  1863.                  status_initialize(REASSESS_ONLY);
  1864.  #endif
  1865.                  context.botl = TRUE;
  1866.              } else if (boolopt[i].addr == &flags.invlet_constant) {
  1867.                  if (flags.invlet_constant)
  1868.                      reassign();
  1869.              } else if (boolopt[i].addr == &flags.lit_corridor
  1870.                         || boolopt[i].addr == &flags.dark_room) {
  1871.                  /*
  1872.                   * All corridor squares seen via night vision or
  1873.                   * candles & lamps change.  Update them by calling
  1874.                   * newsym() on them.  Don't do this if we are
  1875.                   * initializing the options --- the vision system
  1876.                   * isn't set up yet.
  1877.                   */
  1878.                  vision_recalc(2);       /* shut down vision */
  1879.                  vision_full_recalc = 1; /* delayed recalc */
  1880.                  if (iflags.use_color)
  1881.                      need_redraw = TRUE; /* darkroom refresh */
  1882.              } else if (boolopt[i].addr == &flags.showrace
  1883.                         || boolopt[i].addr == &iflags.use_inverse
  1884.                         || boolopt[i].addr == &iflags.hilite_pile
  1885.                         || boolopt[i].addr == &iflags.hilite_pet
  1886.                         || boolopt[i].addr == &iflags.wc_ascii_map
  1887.                         || boolopt[i].addr == &iflags.wc_tiled_map) {
  1888.                  need_redraw = TRUE;
  1889.  #ifdef STATUS_HILITES
  1890.              } else if (boolopt[i].addr == &iflags.wc2_hitpointbar) {
  1891.                  status_initialize(REASSESS_ONLY);
  1892.                  need_redraw = TRUE;
  1893.  #endif
  1894.  #ifdef TEXTCOLOR
  1895.              } else if (boolopt[i].addr == &iflags.use_color) {
  1896.                  need_redraw = TRUE;
  1897.  #ifdef TOS
  1898.                  if (iflags.BIOS) {
  1899.                      if (colors_changed)
  1900.                          restore_colors();
  1901.                      else
  1902.                          set_colors();
  1903.                  }
  1904.  #endif
  1905.  #endif /* TEXTCOLOR */
  1906.              }
  1907.              return retval;
  1908.          }
  1909.      }
  1910.  
  1911.      /* Is it a symbol? */
  1912.      if (strstr(opts, "S_") == opts && parsesymbols(opts)) {
  1913.          switch_symbols(TRUE);
  1914.          check_gold_symbol();
  1915.          return retval;
  1916.      }
  1917.  
  1918.      /* out of valid options */
  1919.      config_error_add("Unknown option '%s'", opts);
  1920.      return FALSE;
  1921.  }
  1922.  

parsebindings

  1.  /* parse key:command */
  2.  boolean
  3.  parsebindings(bindings)
  4.  char* bindings;
  5.  {
  6.      char *bind;
  7.      char key;
  8.      int i;
  9.      boolean ret = FALSE;
  10.  
  11.      /* break off first binding from the rest; parse the rest */
  12.      if ((bind = index(bindings, ',')) != 0) {
  13.          *bind++ = 0;
  14.          ret |= parsebindings(bind);
  15.      }
  16.  
  17.      /* parse a single binding: first split around : */
  18.      if (! (bind = index(bindings, ':')))
  19.          return FALSE; /* it's not a binding */
  20.      *bind++ = 0;
  21.  
  22.      /* read the key to be bound */
  23.      key = txt2key(bindings);
  24.      if (!key) {
  25.          config_error_add("Unknown key binding key '%s'", bindings);
  26.          return FALSE;
  27.      }
  28.  
  29.      bind = trimspaces(bind);
  30.  
  31.      /* is it a special key? */
  32.      if (bind_specialkey(key, bind))
  33.          return TRUE;
  34.  
  35.      /* is it a menu command? */
  36.      for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
  37.          if (!strcmp(default_menu_cmd_info[i].name, bind)) {
  38.              if (illegal_menu_cmd_key(key)) {
  39.                  config_error_add("Bad menu key %s:%s", visctrl(key), bind);
  40.                  return FALSE;
  41.              } else
  42.                  add_menu_cmd_alias(key, default_menu_cmd_info[i].cmd);
  43.              return TRUE;
  44.          }
  45.      }
  46.  
  47.      /* extended command? */
  48.      if (!bind_key(key, bind)) {
  49.          config_error_add("Unknown key binding command '%s'", bind);
  50.          return FALSE;
  51.      }
  52.      return TRUE;
  53.  }
  54.  
  55.  static NEARDATA const char *menutype[] = { "traditional", "combination",
  56.                                             "full", "partial" };
  57.  
  58.  static NEARDATA const char *burdentype[] = { "unencumbered", "burdened",
  59.                                               "stressed",     "strained",
  60.                                               "overtaxed",    "overloaded" };
  61.  
  62.  static NEARDATA const char *runmodes[] = { "teleport", "run", "walk",
  63.                                             "crawl" };
  64.  
  65.  static NEARDATA const char *sortltype[] = { "none", "loot", "full" };
  66.  

oc_to_str

  1.  /*
  2.   * Convert the given string of object classes to a string of default object
  3.   * symbols.
  4.   */
  5.  STATIC_OVL void
  6.  oc_to_str(src, dest)
  7.  char *src, *dest;
  8.  {
  9.      int i;
  10.  
  11.      while ((i = (int) *src++) != 0) {
  12.          if (i < 0 || i >= MAXOCLASSES)
  13.              impossible("oc_to_str:  illegal object class %d", i);
  14.          else
  15.              *dest++ = def_oc_syms[i].sym;
  16.      }
  17.      *dest = '\0';
  18.  }
  19.  

add_menu_cmd_alias

  1.  /*
  2.   * Add the given mapping to the menu command map list.  Always keep the
  3.   * maps valid C strings.
  4.   */
  5.  void
  6.  add_menu_cmd_alias(from_ch, to_ch)
  7.  char from_ch, to_ch;
  8.  {
  9.      if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) {
  10.          pline("out of menu map space.");
  11.      } else {
  12.          mapped_menu_cmds[n_menu_mapped] = from_ch;
  13.          mapped_menu_op[n_menu_mapped] = to_ch;
  14.          n_menu_mapped++;
  15.          mapped_menu_cmds[n_menu_mapped] = 0;
  16.          mapped_menu_op[n_menu_mapped] = 0;
  17.      }
  18.  }
  19.  

get_menu_cmd_key

  1.  char
  2.  get_menu_cmd_key(ch)
  3.  char ch;
  4.  {
  5.      char *found = index(mapped_menu_op, ch);
  6.  
  7.      if (found) {
  8.          int idx = (int) (found - mapped_menu_op);
  9.  
  10.          ch = mapped_menu_cmds[idx];
  11.      }
  12.      return ch;
  13.  }
  14.  

map_menu_cmd

  1.  /*
  2.   * Map the given character to its corresponding menu command.  If it
  3.   * doesn't match anything, just return the original.
  4.   */
  5.  char
  6.  map_menu_cmd(ch)
  7.  char ch;
  8.  {
  9.      char *found = index(mapped_menu_cmds, ch);
  10.  
  11.      if (found) {
  12.          int idx = (int) (found - mapped_menu_cmds);
  13.  
  14.          ch = mapped_menu_op[idx];
  15.      }
  16.      return ch;
  17.  }
  18.  

show_menu_controls

  1.  void
  2.  show_menu_controls(win, dolist)
  3.  winid win;
  4.  boolean dolist;
  5.  {
  6.      char buf[BUFSZ];
  7.  
  8.      putstr(win, 0, "Menu control keys:");
  9.      if (dolist) {
  10.          int i;
  11.  
  12.          for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
  13.              Sprintf(buf, "%-8s %s",
  14.                      visctrl(get_menu_cmd_key(default_menu_cmd_info[i].cmd)),
  15.                      default_menu_cmd_info[i].desc);
  16.              putstr(win, 0, buf);
  17.          }
  18.      } else {
  19.          putstr(win, 0, "");
  20.          putstr(win, 0, "          Page    All items");
  21.          Sprintf(buf, "  Select   %s       %s",
  22.                  visctrl(get_menu_cmd_key(MENU_SELECT_PAGE)),
  23.                  visctrl(get_menu_cmd_key(MENU_SELECT_ALL)));
  24.          putstr(win, 0, buf);
  25.          Sprintf(buf, "Deselect   %s       %s",
  26.                  visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE)),
  27.                  visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL)));
  28.          putstr(win, 0, buf);
  29.          Sprintf(buf, "  Invert   %s       %s",
  30.                  visctrl(get_menu_cmd_key(MENU_INVERT_PAGE)),
  31.                  visctrl(get_menu_cmd_key(MENU_INVERT_ALL)));
  32.          putstr(win, 0, buf);
  33.          putstr(win, 0, "");
  34.          Sprintf(buf, "   Go to   %s   Next page",
  35.                  visctrl(get_menu_cmd_key(MENU_NEXT_PAGE)));
  36.          putstr(win, 0, buf);
  37.          Sprintf(buf, "           %s   Previous page",
  38.                  visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE)));
  39.          putstr(win, 0, buf);
  40.          Sprintf(buf, "           %s   First page",
  41.                  visctrl(get_menu_cmd_key(MENU_FIRST_PAGE)));
  42.          putstr(win, 0, buf);
  43.          Sprintf(buf, "           %s   Last page",
  44.                  visctrl(get_menu_cmd_key(MENU_LAST_PAGE)));
  45.          putstr(win, 0, buf);
  46.          putstr(win, 0, "");
  47.          Sprintf(buf, "           %s   Search and toggle matching entries",
  48.                  visctrl(get_menu_cmd_key(MENU_SEARCH)));
  49.          putstr(win, 0, buf);
  50.      }
  51.  }
  52.  
  53.  #if defined(MICRO) || defined(MAC) || defined(WIN32)
  54.  #define OPTIONS_HEADING "OPTIONS"
  55.  #else
  56.  #define OPTIONS_HEADING "NETHACKOPTIONS"
  57.  #endif
  58.  
  59.  static char fmtstr_doset[] = "%s%-15s [%s]   ";
  60.  static char fmtstr_doset_tab[] = "%s\t[%s]";
  61.  static char n_currently_set[] = "(%d currently set)";
  62.  

doset_add_menu

  1.  /* doset('O' command) menu entries for compound options */
  2.  STATIC_OVL void
  3.  doset_add_menu(win, option, indexoffset)
  4.  winid win;          /* window to add to */
  5.  const char *option; /* option name */
  6.  int indexoffset;    /* value to add to index in compopt[], or zero
  7.                         if option cannot be changed */
  8.  {
  9.      const char *value = "unknown"; /* current value */
  10.      char buf[BUFSZ], buf2[BUFSZ];
  11.      anything any;
  12.      int i;
  13.  
  14.      any = zeroany;
  15.      if (indexoffset == 0) {
  16.          any.a_int = 0;
  17.          value = get_compopt_value(option, buf2);
  18.      } else {
  19.          for (i = 0; compopt[i].name; i++)
  20.              if (strcmp(option, compopt[i].name) == 0)
  21.                  break;
  22.  
  23.          if (compopt[i].name) {
  24.              any.a_int = i + 1 + indexoffset;
  25.              value = get_compopt_value(option, buf2);
  26.          } else {
  27.              /* We are trying to add an option not found in compopt[].
  28.                 This is almost certainly bad, but we'll let it through anyway
  29.                 (with a zero value, so it can't be selected). */
  30.              any.a_int = 0;
  31.          }
  32.      }
  33.      /* "    " replaces "a - " -- assumes menus follow that style */
  34.      if (!iflags.menu_tab_sep)
  35.          Sprintf(buf, fmtstr_doset, any.a_int ? "" : "    ", option,
  36.                  value);
  37.      else
  38.          Sprintf(buf, fmtstr_doset_tab, option, value);
  39.      add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  40.  }
  41.  

opts_add_others

  1.  STATIC_OVL void
  2.  opts_add_others(win, name, id, bufx, nset)
  3.  winid win;
  4.  const char *name;
  5.  int id;
  6.  char *bufx;
  7.  int nset;
  8.  {
  9.      char buf[BUFSZ], buf2[BUFSZ];
  10.      anything any = zeroany;
  11.  
  12.      any.a_int = id;
  13.      if (!bufx)
  14.          Sprintf(buf2, n_currently_set, nset);
  15.      else
  16.          Sprintf(buf2, "%s", bufx);
  17.      if (!iflags.menu_tab_sep)
  18.          Sprintf(buf, fmtstr_doset, any.a_int ? "" : "    ",
  19.                  name, buf2);
  20.      else
  21.          Sprintf(buf, fmtstr_doset_tab, name, buf2);
  22.      add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  23.  }
  24.  

count_apes

  1.  int
  2.  count_apes(VOID_ARGS)
  3.  {
  4.      return count_ape_maps((int *) 0, (int *) 0);
  5.  }
  6.  
  7.  enum opt_other_enums {
  8.      OPT_OTHER_MSGTYPE = -4,
  9.      OPT_OTHER_MENUCOLOR = -3,
  10.      OPT_OTHER_STATHILITE = -2,
  11.      OPT_OTHER_APEXC = -1
  12.      /* these must be < 0 */
  13.  };
  14.  
  15.  static struct other_opts {
  16.      const char *name;
  17.      int optflags;
  18.      enum opt_other_enums code;
  19.      int NDECL((*othr_count_func));
  20.  } othropt[] = {
  21.      { "autopickup exceptions", SET_IN_GAME, OPT_OTHER_APEXC, count_apes },
  22.      { "menucolors", SET_IN_GAME, OPT_OTHER_MENUCOLOR, count_menucolors },
  23.      { "message types", SET_IN_GAME, OPT_OTHER_MSGTYPE, msgtype_count },
  24.  #ifdef STATUS_HILITES
  25.      { "status hilite rules", SET_IN_GAME, OPT_OTHER_STATHILITE,
  26.        count_status_hilites },
  27.  #endif
  28.      { (char *) 0, 0, (enum opt_other_enums) 0 },
  29.  };
  30.  

doset

  1.  /* the 'O' command */
  2.  int
  3.  doset() /* changing options via menu by Per Liboriussen */
  4.  {
  5.      static boolean made_fmtstr = FALSE;
  6.      char buf[BUFSZ], buf2[BUFSZ] = DUMMY;
  7.      const char *name;
  8.      int i = 0, pass, boolcount, pick_cnt, pick_idx, opt_indx;
  9.      boolean *bool_p;
  10.      winid tmpwin;
  11.      anything any;
  12.      menu_item *pick_list;
  13.      int indexoffset, startpass, endpass, optflags;
  14.      boolean setinitial = FALSE, fromfile = FALSE;
  15.      unsigned longest_name_len;
  16.  
  17.      tmpwin = create_nhwindow(NHW_MENU);
  18.      start_menu(tmpwin);
  19.  
  20.  #ifdef notyet /* SYSCF */
  21.      /* XXX I think this is still fragile.  Fixing initial/from_file and/or
  22.         changing the SET_* etc to bitmaps will let me make this better. */
  23.      if (wizard)
  24.          startpass = SET_IN_SYS;
  25.      else
  26.  #endif
  27.          startpass = DISP_IN_GAME;
  28.      endpass = (wizard) ? SET_IN_WIZGAME : SET_IN_GAME;
  29.  
  30.      if (!made_fmtstr && !iflags.menu_tab_sep) {
  31.          /* spin through the options to find the longest name
  32.             and adjust the format string accordingly */
  33.          longest_name_len = 0;
  34.          for (pass = 0; pass <= 2; pass++)
  35.              for (i = 0; (name = ((pass == 0)
  36.                                   ? boolopt[i].name
  37.                                   : (pass == 1)
  38.                                     ? compopt[i].name
  39.                                     : othropt[i].name)) != 0; i++) {
  40.                  if (pass == 0 && !boolopt[i].addr)
  41.                      continue;
  42.                  optflags = (pass == 0) ? boolopt[i].optflags
  43.                                         : (pass == 1)
  44.                                           ? compopt[i].optflags
  45.                                           : othropt[i].optflags;
  46.                  if (optflags < startpass || optflags > endpass)
  47.                      continue;
  48.                  if ((is_wc_option(name) && !wc_supported(name))
  49.                      || (is_wc2_option(name) && !wc2_supported(name)))
  50.                      continue;
  51.  
  52.                  if (strlen(name) > longest_name_len)
  53.                      longest_name_len = strlen(name);
  54.              }
  55.          Sprintf(fmtstr_doset, "%%s%%-%us [%%s]", longest_name_len);
  56.          made_fmtstr = TRUE;
  57.      }
  58.  
  59.      any = zeroany;
  60.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  61.               "Booleans (selecting will toggle value):", MENU_UNSELECTED);
  62.      any.a_int = 0;
  63.      /* first list any other non-modifiable booleans, then modifiable ones */
  64.      for (pass = 0; pass <= 1; pass++)
  65.          for (i = 0; (name = boolopt[i].name) != 0; i++)
  66.              if ((bool_p = boolopt[i].addr) != 0
  67.                  && ((boolopt[i].optflags <= DISP_IN_GAME && pass == 0)
  68.                      || (boolopt[i].optflags >= SET_IN_GAME && pass == 1))) {
  69.                  if (bool_p == &flags.female)
  70.                      continue; /* obsolete */
  71.                  if (boolopt[i].optflags == SET_IN_WIZGAME && !wizard)
  72.                      continue;
  73.                  if ((is_wc_option(name) && !wc_supported(name))
  74.                      || (is_wc2_option(name) && !wc2_supported(name)))
  75.                      continue;
  76.  
  77.                  any.a_int = (pass == 0) ? 0 : i + 1;
  78.                  if (!iflags.menu_tab_sep)
  79.                      Sprintf(buf, fmtstr_doset, (pass == 0) ? "    " : "",
  80.                              name, *bool_p ? "true" : "false");
  81.                  else
  82.                      Sprintf(buf, fmtstr_doset_tab,
  83.                              name, *bool_p ? "true" : "false");
  84.                  add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
  85.                           MENU_UNSELECTED);
  86.              }
  87.  
  88.      boolcount = i;
  89.      indexoffset = boolcount;
  90.      any = zeroany;
  91.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  92.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  93.               "Compounds (selecting will prompt for new value):",
  94.               MENU_UNSELECTED);
  95.  
  96.      /* deliberately put playmode, name, role+race+gender+align first */
  97.      doset_add_menu(tmpwin, "playmode", 0);
  98.      doset_add_menu(tmpwin, "name", 0);
  99.      doset_add_menu(tmpwin, "role", 0);
  100.      doset_add_menu(tmpwin, "race", 0);
  101.      doset_add_menu(tmpwin, "gender", 0);
  102.      doset_add_menu(tmpwin, "align", 0);
  103.  
  104.      for (pass = startpass; pass <= endpass; pass++)
  105.          for (i = 0; (name = compopt[i].name) != 0; i++)
  106.              if (compopt[i].optflags == pass) {
  107.                  if (!strcmp(name, "playmode")  || !strcmp(name, "name")
  108.                      || !strcmp(name, "role")   || !strcmp(name, "race")
  109.                      || !strcmp(name, "gender") || !strcmp(name, "align"))
  110.                      continue;
  111.                  if ((is_wc_option(name) && !wc_supported(name))
  112.                      || (is_wc2_option(name) && !wc2_supported(name)))
  113.                      continue;
  114.  
  115.                  doset_add_menu(tmpwin, name,
  116.                                 (pass == DISP_IN_GAME) ? 0 : indexoffset);
  117.              }
  118.  
  119.      any = zeroany;
  120.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  121.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  122.               "Other settings:", MENU_UNSELECTED);
  123.  
  124.      for (i = 0; (name = othropt[i].name) != 0; i++) {
  125.          if ((is_wc_option(name) && !wc_supported(name))
  126.              || (is_wc2_option(name) && !wc2_supported(name)))
  127.              continue;
  128.          opts_add_others(tmpwin, name, othropt[i].code,
  129.                          (char *) 0, othropt[i].othr_count_func());
  130.      }
  131.  
  132.  #ifdef PREFIXES_IN_USE
  133.      any = zeroany;
  134.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  135.      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  136.               "Variable playground locations:", MENU_UNSELECTED);
  137.      for (i = 0; i < PREFIX_COUNT; i++)
  138.          doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
  139.  #endif
  140.      end_menu(tmpwin, "Set what options?");
  141.      need_redraw = FALSE;
  142.      if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
  143.          /*
  144.           * Walk down the selection list and either invert the booleans
  145.           * or prompt for new values. In most cases, call parseoptions()
  146.           * to take care of options that require special attention, like
  147.           * redraws.
  148.           */
  149.          for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  150.              opt_indx = pick_list[pick_idx].item.a_int - 1;
  151.              if (opt_indx < -1)
  152.                  opt_indx++; /* -1 offset for select_menu() */
  153.              if (opt_indx == OPT_OTHER_APEXC) {
  154.                  (void) special_handling("autopickup_exception", setinitial,
  155.                                          fromfile);
  156.  #ifdef STATUS_HILITES
  157.              } else if (opt_indx == OPT_OTHER_STATHILITE) {
  158.                  if (!status_hilite_menu()) {
  159.                      pline("Bad status hilite(s) specified.");
  160.                  } else {
  161.                      if (wc2_supported("hilite_status"))
  162.                          preference_update("hilite_status");
  163.                  }
  164.  #endif
  165.              } else if (opt_indx == OPT_OTHER_MENUCOLOR) {
  166.                      (void) special_handling("menucolors", setinitial,
  167.                                              fromfile);
  168.              } else if (opt_indx == OPT_OTHER_MSGTYPE) {
  169.                      (void) special_handling("msgtype", setinitial, fromfile);
  170.              } else if (opt_indx < boolcount) {
  171.                  /* boolean option */
  172.                  Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
  173.                          boolopt[opt_indx].name);
  174.                  parseoptions(buf, setinitial, fromfile);
  175.                  if (wc_supported(boolopt[opt_indx].name)
  176.                      || wc2_supported(boolopt[opt_indx].name))
  177.                      preference_update(boolopt[opt_indx].name);
  178.              } else {
  179.                  /* compound option */
  180.                  opt_indx -= boolcount;
  181.  
  182.                  if (!special_handling(compopt[opt_indx].name, setinitial,
  183.                                        fromfile)) {
  184.                      Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
  185.                      getlin(buf, buf2);
  186.                      if (buf2[0] == '\033')
  187.                          continue;
  188.                      Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
  189.                      /* pass the buck */
  190.                      parseoptions(buf, setinitial, fromfile);
  191.                  }
  192.                  if (wc_supported(compopt[opt_indx].name)
  193.                      || wc2_supported(compopt[opt_indx].name))
  194.                      preference_update(compopt[opt_indx].name);
  195.              }
  196.          }
  197.          free((genericptr_t) pick_list);
  198.          pick_list = (menu_item *) 0;
  199.      }
  200.  
  201.      destroy_nhwindow(tmpwin);
  202.      if (need_redraw) {
  203.          check_gold_symbol();
  204.          reglyph_darkroom();
  205.          (void) doredraw();
  206.      }
  207.      return 0;
  208.  }
  209.  

handle_add_list_remove

  1.  STATIC_OVL int
  2.  handle_add_list_remove(optname, numtotal)
  3.  const char *optname;
  4.  int numtotal;
  5.  {
  6.      winid tmpwin;
  7.      anything any;
  8.      int i, pick_cnt, opt_idx;
  9.      menu_item *pick_list = (menu_item *) 0;
  10.      static const struct action {
  11.          char letr;
  12.          const char *desc;
  13.      } action_titles[] = {
  14.          { 'a', "add new %s" },         /* [0] */
  15.          { 'l', "list %s" },            /* [1] */
  16.          { 'r', "remove existing %s" }, /* [2] */
  17.          { 'x', "exit this menu" },     /* [3] */
  18.      };
  19.  
  20.      opt_idx = 0;
  21.      tmpwin = create_nhwindow(NHW_MENU);
  22.      start_menu(tmpwin);
  23.      any = zeroany;
  24.      for (i = 0; i < SIZE(action_titles); i++) {
  25.          char tmpbuf[BUFSZ];
  26.  
  27.          any.a_int++;
  28.          /* omit list and remove if there aren't any yet */
  29.          if (!numtotal && (i == 1 || i == 2))
  30.              continue;
  31.          Sprintf(tmpbuf, action_titles[i].desc,
  32.                  (i == 1) ? makeplural(optname) : optname);
  33.          add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE,
  34.                   tmpbuf, (i == 3) ? MENU_SELECTED : MENU_UNSELECTED);
  35.      }
  36.      end_menu(tmpwin, "Do what?");
  37.      if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
  38.          opt_idx = pick_list[0].item.a_int - 1;
  39.          if (pick_cnt > 1 && opt_idx == 3)
  40.              opt_idx = pick_list[1].item.a_int - 1;
  41.          free((genericptr_t) pick_list);
  42.      } else
  43.          opt_idx = 3; /* none selected, exit menu */
  44.      destroy_nhwindow(tmpwin);
  45.      return opt_idx;
  46.  }
  47.  
  48.  struct symsetentry *symset_list = 0; /* files.c will populate this with
  49.                                                list of available sets */
  50.  

special_handling

  1.  STATIC_OVL boolean
  2.  special_handling(optname, setinitial, setfromfile)
  3.  const char *optname;
  4.  boolean setinitial, setfromfile;
  5.  {
  6.      winid tmpwin;
  7.      anything any;
  8.      int i, n;
  9.      char buf[BUFSZ];
  10.  
  11.      /* Special handling of menustyle, pickup_burden, pickup_types,
  12.       * disclose, runmode, msg_window, menu_headings, sortloot,
  13.       * and number_pad options.
  14.       * Also takes care of interactive autopickup_exception_handling changes.
  15.       */
  16.      if (!strcmp("menustyle", optname)) {
  17.          const char *style_name;
  18.          menu_item *style_pick = (menu_item *) 0;
  19.  
  20.          tmpwin = create_nhwindow(NHW_MENU);
  21.          start_menu(tmpwin);
  22.          any = zeroany;
  23.          for (i = 0; i < SIZE(menutype); i++) {
  24.              style_name = menutype[i];
  25.              /* note: separate `style_name' variable used
  26.                 to avoid an optimizer bug in VAX C V2.3 */
  27.              any.a_int = i + 1;
  28.              add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE,
  29.                       style_name, MENU_UNSELECTED);
  30.          }
  31.          end_menu(tmpwin, "Select menustyle:");
  32.          if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
  33.              flags.menu_style = style_pick->item.a_int - 1;
  34.              free((genericptr_t) style_pick);
  35.          }
  36.          destroy_nhwindow(tmpwin);
  37.      } else if (!strcmp("paranoid_confirmation", optname)) {
  38.          menu_item *paranoia_picks = (menu_item *) 0;
  39.  
  40.          tmpwin = create_nhwindow(NHW_MENU);
  41.          start_menu(tmpwin);
  42.          any = zeroany;
  43.          for (i = 0; paranoia[i].flagmask != 0; ++i) {
  44.              if (paranoia[i].flagmask == PARANOID_BONES && !wizard)
  45.                  continue;
  46.              any.a_int = paranoia[i].flagmask;
  47.              add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0,
  48.                       ATR_NONE, paranoia[i].explain,
  49.                       (flags.paranoia_bits & paranoia[i].flagmask)
  50.                           ? MENU_SELECTED
  51.                           : MENU_UNSELECTED);
  52.          }
  53.          end_menu(tmpwin, "Actions requiring extra confirmation:");
  54.          i = select_menu(tmpwin, PICK_ANY, &paranoia_picks);
  55.          if (i >= 0) {
  56.              /* player didn't cancel; we reset all the paranoia options
  57.                 here even if there were no items picked, since user
  58.                 could have toggled off preselected ones to end up with 0 */
  59.              flags.paranoia_bits = 0;
  60.              if (i > 0) {
  61.                  /* at least 1 item set, either preselected or newly picked */
  62.                  while (--i >= 0)
  63.                      flags.paranoia_bits |= paranoia_picks[i].item.a_int;
  64.                  free((genericptr_t) paranoia_picks);
  65.              }
  66.          }
  67.          destroy_nhwindow(tmpwin);
  68.      } else if (!strcmp("pickup_burden", optname)) {
  69.          const char *burden_name, *burden_letters = "ubsntl";
  70.          menu_item *burden_pick = (menu_item *) 0;
  71.  
  72.          tmpwin = create_nhwindow(NHW_MENU);
  73.          start_menu(tmpwin);
  74.          any = zeroany;
  75.          for (i = 0; i < SIZE(burdentype); i++) {
  76.              burden_name = burdentype[i];
  77.              any.a_int = i + 1;
  78.              add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE,
  79.                       burden_name, MENU_UNSELECTED);
  80.          }
  81.          end_menu(tmpwin, "Select encumbrance level:");
  82.          if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
  83.              flags.pickup_burden = burden_pick->item.a_int - 1;
  84.              free((genericptr_t) burden_pick);
  85.          }
  86.          destroy_nhwindow(tmpwin);
  87.      } else if (!strcmp("pickup_types", optname)) {
  88.          /* parseoptions will prompt for the list of types */
  89.          parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
  90.      } else if (!strcmp("disclose", optname)) {
  91.          /* order of disclose_names[] must correspond to
  92.             disclosure_options in decl.c */
  93.          static const char *disclosure_names[] = {
  94.              "inventory", "attributes", "vanquished",
  95.              "genocides", "conduct",    "overview",
  96.          };
  97.          int disc_cat[NUM_DISCLOSURE_OPTIONS];
  98.          int pick_cnt, pick_idx, opt_idx;
  99.          char c;
  100.          menu_item *disclosure_pick = (menu_item *) 0;
  101.  
  102.          tmpwin = create_nhwindow(NHW_MENU);
  103.          start_menu(tmpwin);
  104.          any = zeroany;
  105.          for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  106.              Sprintf(buf, "%-12s[%c%c]", disclosure_names[i],
  107.                      flags.end_disclose[i], disclosure_options[i]);
  108.              any.a_int = i + 1;
  109.              add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
  110.                       ATR_NONE, buf, MENU_UNSELECTED);
  111.              disc_cat[i] = 0;
  112.          }
  113.          end_menu(tmpwin, "Change which disclosure options categories:");
  114.          pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_pick);
  115.          if (pick_cnt > 0) {
  116.              for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  117.                  opt_idx = disclosure_pick[pick_idx].item.a_int - 1;
  118.                  disc_cat[opt_idx] = 1;
  119.              }
  120.              free((genericptr_t) disclosure_pick);
  121.              disclosure_pick = (menu_item *) 0;
  122.          }
  123.          destroy_nhwindow(tmpwin);
  124.  
  125.          for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  126.              if (disc_cat[i]) {
  127.                  c = flags.end_disclose[i];
  128.                  Sprintf(buf, "Disclosure options for %s:",
  129.                          disclosure_names[i]);
  130.                  tmpwin = create_nhwindow(NHW_MENU);
  131.                  start_menu(tmpwin);
  132.                  any = zeroany;
  133.                  /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
  134.                  any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
  135.                  add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
  136.                           "Never disclose, without prompting",
  137.                           (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
  138.                  any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
  139.                  add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
  140.                           "Always disclose, without prompting",
  141.                           (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
  142.                  if (*disclosure_names[i] == 'v') {
  143.                      any.a_char = DISCLOSE_SPECIAL_WITHOUT_PROMPT; /* '#' */
  144.                      add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
  145.                               "Always disclose, pick sort order from menu",
  146.                               (c == any.a_char) ? MENU_SELECTED
  147.                                                 : MENU_UNSELECTED);
  148.                  }
  149.                  any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
  150.                  add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
  151.                           "Prompt, with default answer of \"No\"",
  152.                           (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
  153.                  any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
  154.                  add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
  155.                           "Prompt, with default answer of \"Yes\"",
  156.                           (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
  157.                  if (*disclosure_names[i] == 'v') {
  158.                      any.a_char = DISCLOSE_PROMPT_DEFAULT_SPECIAL; /* '?' */
  159.                      add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
  160.                  "Prompt, with default answer of \"Ask\" to request sort menu",
  161.                               (c == any.a_char) ? MENU_SELECTED
  162.                                                 : MENU_UNSELECTED);
  163.                  }
  164.                  end_menu(tmpwin, buf);
  165.                  n = select_menu(tmpwin, PICK_ONE, &disclosure_pick);
  166.                  if (n > 0) {
  167.                      flags.end_disclose[i] = disclosure_pick[0].item.a_char;
  168.                      if (n > 1 && flags.end_disclose[i] == c)
  169.                          flags.end_disclose[i] = disclosure_pick[1].item.a_char;
  170.                      free((genericptr_t) disclosure_pick);
  171.                  }
  172.                  destroy_nhwindow(tmpwin);
  173.              }
  174.          }
  175.      } else if (!strcmp("runmode", optname)) {
  176.          const char *mode_name;
  177.          menu_item *mode_pick = (menu_item *) 0;
  178.  
  179.          tmpwin = create_nhwindow(NHW_MENU);
  180.          start_menu(tmpwin);
  181.          any = zeroany;
  182.          for (i = 0; i < SIZE(runmodes); i++) {
  183.              mode_name = runmodes[i];
  184.              any.a_int = i + 1;
  185.              add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE,
  186.                       mode_name, MENU_UNSELECTED);
  187.          }
  188.          end_menu(tmpwin, "Select run/travel display mode:");
  189.          if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  190.              flags.runmode = mode_pick->item.a_int - 1;
  191.              free((genericptr_t) mode_pick);
  192.          }
  193.          destroy_nhwindow(tmpwin);
  194.      } else if (!strcmp("whatis_coord", optname)) {
  195.          menu_item *window_pick = (menu_item *) 0;
  196.          int pick_cnt;
  197.          char gp = iflags.getpos_coords;
  198.  
  199.          tmpwin = create_nhwindow(NHW_MENU);
  200.          start_menu(tmpwin);
  201.          any = zeroany;
  202.          any.a_char = GPCOORDS_COMPASS;
  203.          add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMPASS,
  204.                   0, ATR_NONE, "compass ('east' or '3s' or '2n,4w')",
  205.                   (gp == GPCOORDS_COMPASS) ? MENU_SELECTED : MENU_UNSELECTED);
  206.          any.a_char = GPCOORDS_COMFULL;
  207.          add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMFULL, 0, ATR_NONE,
  208.                   "full compass ('east' or '3south' or '2north,4west')",
  209.                   (gp == GPCOORDS_COMFULL) ? MENU_SELECTED : MENU_UNSELECTED);
  210.          any.a_char = GPCOORDS_MAP;
  211.          add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_MAP,
  212.                   0, ATR_NONE, "map <x,y>",
  213.                   (gp == GPCOORDS_MAP) ? MENU_SELECTED : MENU_UNSELECTED);
  214.          any.a_char = GPCOORDS_SCREEN;
  215.          add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_SCREEN,
  216.                   0, ATR_NONE, "screen [row,column]",
  217.                   (gp == GPCOORDS_SCREEN) ? MENU_SELECTED : MENU_UNSELECTED);
  218.          any.a_char = GPCOORDS_NONE;
  219.          add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE,
  220.                   0, ATR_NONE, "none (no coordinates displayed)",
  221.                   (gp == GPCOORDS_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
  222.          any.a_long = 0L;
  223.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  224.          Sprintf(buf, "map: upper-left: <%d,%d>, lower-right: <%d,%d>%s",
  225.                  1, 0, COLNO - 1, ROWNO - 1,
  226.                  flags.verbose ? "; column 0 unused, off left edge" : "");
  227.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  228.          if (strcmp(windowprocs.name, "tty"))
  229.              add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
  230.         "screen: row is offset to accommodate tty interface's use of top line",
  231.                       MENU_UNSELECTED);
  232.  #if COLNO == 80
  233.  #define COL80ARG flags.verbose ? "; column 80 is not used" : ""
  234.  #else
  235.  #define COL80ARG ""
  236.  #endif
  237.          Sprintf(buf, "screen: upper-left: [%02d,%02d], lower-right: [%d,%d]%s",
  238.                  0 + 2, 1, ROWNO - 1 + 2, COLNO - 1, COL80ARG);
  239.  #undef COL80ARG
  240.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  241.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  242.          end_menu(tmpwin,
  243.              "Select coordinate display when auto-describing a map position:");
  244.          if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
  245.              iflags.getpos_coords = window_pick[0].item.a_char;
  246.              /* PICK_ONE doesn't unselect preselected entry when
  247.                 selecting another one */
  248.              if (pick_cnt > 1 && iflags.getpos_coords == gp)
  249.                  iflags.getpos_coords = window_pick[1].item.a_char;
  250.              free((genericptr_t) window_pick);
  251.          }
  252.          destroy_nhwindow(tmpwin);
  253.      } else if (!strcmp("whatis_filter", optname)) {
  254.          menu_item *window_pick = (menu_item *) 0;
  255.          int pick_cnt;
  256.          char gf = iflags.getloc_filter;
  257.  
  258.          tmpwin = create_nhwindow(NHW_MENU);
  259.          start_menu(tmpwin);
  260.          any = zeroany;
  261.          any.a_char = (GFILTER_NONE + 1);
  262.          add_menu(tmpwin, NO_GLYPH, &any, 'n',
  263.                   0, ATR_NONE, "no filtering",
  264.                   (gf == GFILTER_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
  265.          any.a_char = (GFILTER_VIEW + 1);
  266.          add_menu(tmpwin, NO_GLYPH, &any, 'v',
  267.                   0, ATR_NONE, "in view only",
  268.                   (gf == GFILTER_VIEW) ? MENU_SELECTED : MENU_UNSELECTED);
  269.          any.a_char = (GFILTER_AREA + 1);
  270.          add_menu(tmpwin, NO_GLYPH, &any, 'a',
  271.                   0, ATR_NONE, "in same area",
  272.                   (gf == GFILTER_AREA) ? MENU_SELECTED : MENU_UNSELECTED);
  273.          end_menu(tmpwin,
  274.        "Select location filtering when going for next/previous map position:");
  275.          if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
  276.              iflags.getloc_filter = (window_pick[0].item.a_char - 1);
  277.              /* PICK_ONE doesn't unselect preselected entry when
  278.                 selecting another one */
  279.              if (pick_cnt > 1 && iflags.getloc_filter == gf)
  280.                  iflags.getloc_filter = (window_pick[1].item.a_char - 1);
  281.              free((genericptr_t) window_pick);
  282.          }
  283.          destroy_nhwindow(tmpwin);
  284.      } else if (!strcmp("msg_window", optname)) {
  285.  #ifdef TTY_GRAPHICS
  286.          /* by Christian W. Cooper */
  287.          menu_item *window_pick = (menu_item *) 0;
  288.  
  289.          tmpwin = create_nhwindow(NHW_MENU);
  290.          start_menu(tmpwin);
  291.          any = zeroany;
  292.          any.a_char = 's';
  293.          add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE, "single",
  294.                   MENU_UNSELECTED);
  295.          any.a_char = 'c';
  296.          add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE, "combination",
  297.                   MENU_UNSELECTED);
  298.          any.a_char = 'f';
  299.          add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full",
  300.                   MENU_UNSELECTED);
  301.          any.a_char = 'r';
  302.          add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed",
  303.                   MENU_UNSELECTED);
  304.          end_menu(tmpwin, "Select message history display type:");
  305.          if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
  306.              iflags.prevmsg_window = window_pick->item.a_char;
  307.              free((genericptr_t) window_pick);
  308.          }
  309.          destroy_nhwindow(tmpwin);
  310.  #endif
  311.      } else if (!strcmp("sortloot", optname)) {
  312.          const char *sortl_name;
  313.          menu_item *sortl_pick = (menu_item *) 0;
  314.  
  315.          tmpwin = create_nhwindow(NHW_MENU);
  316.          start_menu(tmpwin);
  317.          any = zeroany;
  318.          for (i = 0; i < SIZE(sortltype); i++) {
  319.              sortl_name = sortltype[i];
  320.              any.a_char = *sortl_name;
  321.              add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE,
  322.                       sortl_name, (flags.sortloot == *sortl_name)
  323.                                      ? MENU_SELECTED : MENU_UNSELECTED);
  324.          }
  325.          end_menu(tmpwin, "Select loot sorting type:");
  326.          n = select_menu(tmpwin, PICK_ONE, &sortl_pick);
  327.          if (n > 0) {
  328.              char c = sortl_pick[0].item.a_char;
  329.  
  330.              if (n > 1 && c == flags.sortloot)
  331.                  c = sortl_pick[1].item.a_char;
  332.              flags.sortloot = c;
  333.              free((genericptr_t) sortl_pick);
  334.          }
  335.          destroy_nhwindow(tmpwin);
  336.      } else if (!strcmp("align_message", optname)
  337.                 || !strcmp("align_status", optname)) {
  338.          menu_item *window_pick = (menu_item *) 0;
  339.          char abuf[BUFSZ];
  340.          boolean msg = (*(optname + 6) == 'm');
  341.  
  342.          tmpwin = create_nhwindow(NHW_MENU);
  343.          start_menu(tmpwin);
  344.          any = zeroany;
  345.          any.a_int = ALIGN_TOP;
  346.          add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top",
  347.                   MENU_UNSELECTED);
  348.          any.a_int = ALIGN_BOTTOM;
  349.          add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom",
  350.                   MENU_UNSELECTED);
  351.          any.a_int = ALIGN_LEFT;
  352.          add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left",
  353.                   MENU_UNSELECTED);
  354.          any.a_int = ALIGN_RIGHT;
  355.          add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right",
  356.                   MENU_UNSELECTED);
  357.          Sprintf(abuf, "Select %s window placement relative to the map:",
  358.                  msg ? "message" : "status");
  359.          end_menu(tmpwin, abuf);
  360.          if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
  361.              if (msg)
  362.                  iflags.wc_align_message = window_pick->item.a_int;
  363.              else
  364.                  iflags.wc_align_status = window_pick->item.a_int;
  365.              free((genericptr_t) window_pick);
  366.          }
  367.          destroy_nhwindow(tmpwin);
  368.      } else if (!strcmp("number_pad", optname)) {
  369.          static const char *npchoices[] = {
  370.              " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
  371.              " 3 (on, phone-style digit layout)",
  372.              " 4 (on, phone-style layout, MSDOS compatible)",
  373.              "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
  374.          };
  375.          menu_item *mode_pick = (menu_item *) 0;
  376.  
  377.          tmpwin = create_nhwindow(NHW_MENU);
  378.          start_menu(tmpwin);
  379.          any = zeroany;
  380.          for (i = 0; i < SIZE(npchoices); i++) {
  381.              any.a_int = i + 1;
  382.              add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE,
  383.                       npchoices[i], MENU_UNSELECTED);
  384.          }
  385.          end_menu(tmpwin, "Select number_pad mode:");
  386.          if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  387.              switch (mode_pick->item.a_int - 1) {
  388.              case 0:
  389.                  iflags.num_pad = FALSE;
  390.                  iflags.num_pad_mode = 0;
  391.                  break;
  392.              case 1:
  393.                  iflags.num_pad = TRUE;
  394.                  iflags.num_pad_mode = 0;
  395.                  break;
  396.              case 2:
  397.                  iflags.num_pad = TRUE;
  398.                  iflags.num_pad_mode = 1;
  399.                  break;
  400.              case 3:
  401.                  iflags.num_pad = TRUE;
  402.                  iflags.num_pad_mode = 2;
  403.                  break;
  404.              case 4:
  405.                  iflags.num_pad = TRUE;
  406.                  iflags.num_pad_mode = 3;
  407.                  break;
  408.              /* last menu choice: number_pad == -1 */
  409.              case 5:
  410.                  iflags.num_pad = FALSE;
  411.                  iflags.num_pad_mode = 1;
  412.                  break;
  413.              }
  414.              reset_commands(FALSE);
  415.              number_pad(iflags.num_pad ? 1 : 0);
  416.