PageRenderTime 73ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/nethack/src/options.c

https://bitbucket.org/clivecrous/newt
C | 3862 lines | 3406 code | 173 blank | 283 comment | 808 complexity | 3683a09a5c2addc3add467719048b27d MD5 | raw file
Possible License(s): LGPL-2.0
  1. /* SCCS Id: @(#)options.c 3.4 2003/11/14 */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed. See license for details. */
  4. #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
  5. #include "config.h"
  6. #include "objclass.h"
  7. #include "flag.h"
  8. NEARDATA struct flag flags; /* provide linkage */
  9. NEARDATA struct instance_flags iflags; /* provide linkage */
  10. #define static
  11. #else
  12. #include "hack.h"
  13. #include "tcap.h"
  14. #include <ctype.h>
  15. #endif
  16. #define WINTYPELEN 16
  17. #ifdef DEFAULT_WC_TILED_MAP
  18. #define PREFER_TILED TRUE
  19. #else
  20. #define PREFER_TILED FALSE
  21. #endif
  22. /*
  23. * NOTE: If you add (or delete) an option, please update the short
  24. * options help (option_help()), the long options help (dat/opthelp),
  25. * and the current options setting display function (doset()),
  26. * and also the Guidebooks.
  27. *
  28. * The order matters. If an option is a an initial substring of another
  29. * option (e.g. time and timed_delay) the shorter one must come first.
  30. */
  31. static struct Bool_Opt
  32. {
  33. const char *name;
  34. boolean *addr, initvalue;
  35. int optflags;
  36. } boolopt[] = {
  37. #ifdef AMIGA
  38. {"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME},
  39. #else
  40. {"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
  41. #endif
  42. {"ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME}, /*WC*/
  43. #ifdef MFLOPPY
  44. {"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
  45. #else
  46. {"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE},
  47. #endif
  48. {"autodig", &flags.autodig, FALSE, SET_IN_GAME},
  49. {"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
  50. {"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
  51. #if defined(MICRO) && !defined(AMIGA)
  52. {"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
  53. #else
  54. {"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
  55. #endif
  56. #ifdef INSURANCE
  57. {"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
  58. #else
  59. {"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
  60. #endif
  61. #ifdef MFLOPPY
  62. {"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
  63. #else
  64. {"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
  65. #endif
  66. {"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
  67. # if defined(MICRO) || defined(WIN32) || defined(NEWT_GRAPHICS)
  68. {"color", &iflags.wc_color,TRUE, SET_IN_GAME}, /*WC*/
  69. # else /* systems that support multiple terminals, many monochrome */
  70. {"color", &iflags.wc_color, FALSE, SET_IN_GAME}, /*WC*/
  71. # endif
  72. {"confirm",&flags.confirm, TRUE, SET_IN_GAME},
  73. #if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV)
  74. {"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME},
  75. #else
  76. {"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE},
  77. #endif
  78. {"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME}, /*WC*/
  79. #if defined(TTY_GRAPHICS) || defined(NEWT_GRAPHICS)
  80. {"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
  81. #else
  82. {"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
  83. #endif
  84. #ifdef OPT_DISPMAP
  85. {"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
  86. #else
  87. {"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
  88. #endif
  89. {"female", &flags.female, FALSE, DISP_IN_GAME},
  90. {"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
  91. #ifdef AMIFLUSH
  92. {"flush", &flags.amiflush, FALSE, SET_IN_GAME},
  93. #else
  94. {"flush", (boolean *)0, FALSE, SET_IN_FILE},
  95. #endif
  96. {"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
  97. {"help", &flags.help, TRUE, SET_IN_GAME},
  98. {"hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME}, /*WC*/
  99. #ifdef ASCIIGRAPH
  100. {"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME},
  101. #else
  102. {"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE},
  103. #endif
  104. #ifndef MAC
  105. {"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
  106. #else
  107. {"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
  108. #endif
  109. {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */
  110. {"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
  111. {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
  112. {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
  113. #ifdef MAC_GRAPHICS_ENV
  114. {"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
  115. #else
  116. {"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE},
  117. #endif
  118. #ifdef MAIL
  119. {"mail", &flags.biff, TRUE, SET_IN_GAME},
  120. #else
  121. {"mail", (boolean *)0, TRUE, SET_IN_FILE},
  122. #endif
  123. #ifdef WIZARD
  124. /* for menu debugging only*/
  125. {"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
  126. #else
  127. {"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
  128. #endif
  129. {"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME}, /*WC*/
  130. #ifdef NEWS
  131. {"news", &iflags.news, TRUE, DISP_IN_GAME},
  132. #else
  133. {"news", (boolean *)0, FALSE, SET_IN_FILE},
  134. #endif
  135. {"null", &flags.null, TRUE, SET_IN_GAME},
  136. #ifdef MAC
  137. {"page_wait", &flags.page_wait, TRUE, SET_IN_GAME},
  138. #else
  139. {"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
  140. #endif
  141. {"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
  142. {"popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME}, /*WC*/
  143. {"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
  144. {"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME}, /*WC*/
  145. {"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
  146. #if defined(MICRO) && !defined(AMIGA)
  147. {"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
  148. #else
  149. {"rawio", (boolean *)0, FALSE, SET_IN_FILE},
  150. #endif
  151. {"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
  152. {"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
  153. #ifdef WIZARD
  154. {"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
  155. #else
  156. {"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
  157. #endif
  158. #ifdef EXP_ON_BOTL
  159. {"showexp", &flags.showexp, FALSE, SET_IN_GAME},
  160. #else
  161. {"showexp", (boolean *)0, FALSE, SET_IN_FILE},
  162. #endif
  163. {"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
  164. #ifdef SCORE_ON_BOTL
  165. {"showscore", &flags.showscore, FALSE, SET_IN_GAME},
  166. #else
  167. {"showscore", (boolean *)0, FALSE, SET_IN_FILE},
  168. #endif
  169. {"silent", &flags.silent, TRUE, SET_IN_GAME},
  170. {"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
  171. {"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
  172. {"sound", &flags.soundok, TRUE, SET_IN_GAME},
  173. {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
  174. {"standout", &flags.standout, FALSE, SET_IN_GAME},
  175. {"splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME}, /*WC*/
  176. {"tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME}, /*WC*/
  177. {"time", &flags.time, FALSE, SET_IN_GAME},
  178. #ifdef TIMED_DELAY
  179. {"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
  180. #else
  181. {"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
  182. #endif
  183. {"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
  184. {"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
  185. {"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
  186. #ifdef WIN32CON
  187. {"use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME}, /*WC*/
  188. #else
  189. {"use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME}, /*WC*/
  190. #endif
  191. {"verbose", &flags.verbose, TRUE, SET_IN_GAME},
  192. {"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
  193. {(char *)0, (boolean *)0, FALSE, 0}
  194. };
  195. /* compound options, for option_help() and external programs like Amiga
  196. * frontend */
  197. static struct Comp_Opt
  198. {
  199. const char *name, *descr;
  200. int size; /* for frontends and such allocating space --
  201. * usually allowed size of data in game, but
  202. * occasionally maximum reasonable size for
  203. * typing when game maintains information in
  204. * a different format */
  205. int optflags;
  206. } compopt[] = {
  207. { "align", "your starting alignment (lawful, neutral, or chaotic)",
  208. 8, DISP_IN_GAME },
  209. { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
  210. { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/
  211. { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
  212. { "boulder", "the symbol to use for displaying boulders",
  213. 1, SET_IN_GAME },
  214. { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
  215. PL_PSIZ, DISP_IN_GAME },
  216. { "disclose", "the kinds of information to disclose at end of game",
  217. sizeof(flags.end_disclose) * 2,
  218. SET_IN_GAME },
  219. { "dogname", "the name of your (first) dog (e.g., dogname:Fang)",
  220. PL_PSIZ, DISP_IN_GAME },
  221. { "dungeon", "the symbols to use in drawing the dungeon map",
  222. MAXDCHARS+1, SET_IN_FILE },
  223. { "effects", "the symbols to use in drawing special effects",
  224. MAXECHARS+1, SET_IN_FILE },
  225. { "font_map", "the font to use in the map window", 40, DISP_IN_GAME }, /*WC*/
  226. { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
  227. { "font_message", "the font to use in the message window",
  228. 40, DISP_IN_GAME }, /*WC*/
  229. { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
  230. { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/
  231. { "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/
  232. { "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/
  233. { "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/
  234. { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
  235. { "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/
  236. { "fruit", "the name of a fruit you enjoy eating",
  237. PL_FSIZ, SET_IN_GAME },
  238. { "gender", "your starting gender (male or female)",
  239. 8, DISP_IN_GAME },
  240. { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
  241. PL_PSIZ, DISP_IN_GAME },
  242. { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
  243. { "menustyle", "user interface for object selection",
  244. MENUTYPELEN, SET_IN_GAME },
  245. { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
  246. { "menu_deselect_page", "deselect all items on this page of a menu",
  247. 4, SET_IN_FILE },
  248. { "menu_first_page", "jump to the first page in a menu",
  249. 4, SET_IN_FILE },
  250. { "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
  251. { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
  252. { "menu_invert_page", "invert all items on this page of a menu",
  253. 4, SET_IN_FILE },
  254. { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
  255. { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
  256. { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
  257. { "menu_search", "search for a menu item", 4, SET_IN_FILE },
  258. { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
  259. { "menu_select_page", "select all items on this page of a menu",
  260. 4, SET_IN_FILE },
  261. { "monsters", "the symbols to use for monsters",
  262. MAXMCLASSES, SET_IN_FILE },
  263. { "msghistory", "number of top line messages to save",
  264. 5, DISP_IN_GAME },
  265. # ifdef TTY_GRAPHICS
  266. {"msg_window", "the type of message window required",1, SET_IN_GAME},
  267. # else
  268. {"msg_window", "the type of message window required", 1, SET_IN_FILE},
  269. # endif
  270. { "name", "your character's name (e.g., name:Merlin-W)",
  271. PL_NSIZ, DISP_IN_GAME },
  272. { "number_pad", "use the number pad", 1, SET_IN_GAME},
  273. { "objects", "the symbols to use for objects",
  274. MAXOCLASSES, SET_IN_FILE },
  275. { "packorder", "the inventory order of the items in your pack",
  276. MAXOCLASSES, SET_IN_GAME },
  277. #ifdef CHANGE_COLOR
  278. { "palette", "palette (00c/880/-fff is blue/yellow/reverse white)",
  279. 15 , SET_IN_GAME },
  280. # if defined(MAC)
  281. { "hicolor", "same as palette, only order is reversed",
  282. 15, SET_IN_FILE },
  283. # endif
  284. #endif
  285. { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
  286. { "pickup_burden", "maximum burden picked up before prompt",
  287. 20, SET_IN_GAME },
  288. { "pickup_types", "types of objects to pick up automatically",
  289. MAXOCLASSES, SET_IN_GAME },
  290. { "player_selection", "choose character via dialog or prompts",
  291. 12, DISP_IN_GAME },
  292. { "race", "your starting race (e.g., Human, Elf)",
  293. PL_CSIZ, DISP_IN_GAME },
  294. { "role", "your starting role (e.g., Barbarian, Valkyrie)",
  295. PL_CSIZ, DISP_IN_GAME },
  296. { "runmode", "display frequency when `running' or `travelling'",
  297. sizeof "teleport", SET_IN_GAME },
  298. { "scores", "the parts of the score list you wish to see",
  299. 32, SET_IN_GAME },
  300. { "scroll_amount", "amount to scroll map when scroll_margin is reached",
  301. 20, DISP_IN_GAME }, /*WC*/
  302. { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
  303. #ifdef MSDOS
  304. { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
  305. #endif
  306. { "suppress_alert", "suppress alerts about version-specific features",
  307. 8, SET_IN_GAME },
  308. { "tile_width", "width of tiles", 20, DISP_IN_GAME}, /*WC*/
  309. { "tile_height", "height of tiles", 20, DISP_IN_GAME}, /*WC*/
  310. { "tile_file", "name of tile file", 70, DISP_IN_GAME}, /*WC*/
  311. { "traps", "the symbols to use in drawing traps",
  312. MAXTCHARS+1, SET_IN_FILE },
  313. { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
  314. #ifdef MSDOS
  315. { "video", "method of video updating", 20, SET_IN_FILE },
  316. #endif
  317. #ifdef VIDEOSHADES
  318. { "videocolors", "color mappings for internal screen routines",
  319. 40, DISP_IN_GAME },
  320. { "videoshades", "gray shades to map to black/gray/white",
  321. 32, DISP_IN_GAME },
  322. #endif
  323. #ifdef WIN32CON
  324. {"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
  325. #endif
  326. { "windowcolors", "the foreground/background colors of windows", /*WC*/
  327. 80, DISP_IN_GAME },
  328. { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
  329. { (char *)0, (char *)0, 0, 0 }
  330. };
  331. #ifdef OPTION_LISTS_ONLY
  332. #undef static
  333. #else /* use rest of file */
  334. static boolean need_redraw; /* for doset() */
  335. #if defined(TOS) && defined(TEXTCOLOR)
  336. extern boolean colors_changed; /* in tos.c */
  337. #endif
  338. #ifdef VIDEOSHADES
  339. extern char *shade[3]; /* in sys/msdos/video.c */
  340. extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
  341. #endif
  342. static char def_inv_order[MAXOCLASSES] = {
  343. COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
  344. SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
  345. TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
  346. };
  347. /*
  348. * Default menu manipulation command accelerators. These may _not_ be:
  349. *
  350. * + a number - reserved for counts
  351. * + an upper or lower case US ASCII letter - used for accelerators
  352. * + ESC - reserved for escaping the menu
  353. * + NULL, CR or LF - reserved for commiting the selection(s). NULL
  354. * is kind of odd, but the tty's xwaitforspace() will return it if
  355. * someone hits a <ret>.
  356. * + a default object class symbol - used for object class accelerators
  357. *
  358. * Standard letters (for now) are:
  359. *
  360. * < back 1 page
  361. * > forward 1 page
  362. * ^ first page
  363. * | last page
  364. * : search
  365. *
  366. * page all
  367. * , select .
  368. * \ deselect -
  369. * ~ invert @
  370. *
  371. * The command name list is duplicated in the compopt array.
  372. */
  373. typedef struct {
  374. const char *name;
  375. char cmd;
  376. } menu_cmd_t;
  377. #define NUM_MENU_CMDS 11
  378. static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
  379. /* 0*/ { "menu_first_page", MENU_FIRST_PAGE },
  380. { "menu_last_page", MENU_LAST_PAGE },
  381. { "menu_next_page", MENU_NEXT_PAGE },
  382. { "menu_previous_page", MENU_PREVIOUS_PAGE },
  383. { "menu_select_all", MENU_SELECT_ALL },
  384. /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL },
  385. { "menu_invert_all", MENU_INVERT_ALL },
  386. { "menu_select_page", MENU_SELECT_PAGE },
  387. { "menu_deselect_page", MENU_UNSELECT_PAGE },
  388. { "menu_invert_page", MENU_INVERT_PAGE },
  389. /*10*/ { "menu_search", MENU_SEARCH },
  390. };
  391. /*
  392. * Allow the user to map incoming characters to various menu commands.
  393. * The accelerator list must be a valid C string.
  394. */
  395. #define MAX_MENU_MAPPED_CMDS 32 /* some number */
  396. char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1]; /* exported */
  397. static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1];
  398. static short n_menu_mapped = 0;
  399. static boolean initial, from_file;
  400. STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int));
  401. STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
  402. STATIC_DCL void FDECL(escapes, (const char *, char *));
  403. STATIC_DCL void FDECL(rejectoption, (const char *));
  404. STATIC_DCL void FDECL(badoption, (const char *));
  405. STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P));
  406. STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P));
  407. STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P));
  408. STATIC_DCL int FDECL(change_inv_order, (char *));
  409. STATIC_DCL void FDECL(oc_to_str, (char *, char *));
  410. STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int));
  411. STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
  412. STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
  413. STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
  414. STATIC_DCL void FDECL(warning_opts, (char *,const char *));
  415. STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int));
  416. STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
  417. STATIC_OVL int FDECL(wc_set_window_colors, (char *));
  418. STATIC_OVL boolean FDECL(is_wc_option, (const char *));
  419. STATIC_OVL boolean FDECL(wc_supported, (const char *));
  420. STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
  421. STATIC_OVL boolean FDECL(wc2_supported, (const char *));
  422. #ifdef AUTOPICKUP_EXCEPTIONS
  423. STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
  424. STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
  425. #endif
  426. /* check whether a user-supplied option string is a proper leading
  427. substring of a particular option name; option string might have
  428. a colon or equals sign and arbitrary value appended to it */
  429. boolean
  430. match_optname(user_string, opt_name, min_length, val_allowed)
  431. const char *user_string, *opt_name;
  432. int min_length;
  433. boolean val_allowed;
  434. {
  435. int len = (int)strlen(user_string);
  436. if (val_allowed) {
  437. const char *p = index(user_string, ':'),
  438. *q = index(user_string, '=');
  439. if (!p || (q && q < p)) p = q;
  440. while(p && p > user_string && isspace(*(p-1))) p--;
  441. if (p) len = (int)(p - user_string);
  442. }
  443. return (len >= min_length) && !strncmpi(opt_name, user_string, len);
  444. }
  445. /* most environment variables will eventually be printed in an error
  446. * message if they don't work, and most error message paths go through
  447. * BUFSZ buffers, which could be overflowed by a maliciously long
  448. * environment variable. if a variable can legitimately be long, or
  449. * if it's put in a smaller buffer, the responsible code will have to
  450. * bounds-check itself.
  451. */
  452. char *
  453. nh_getenv(ev)
  454. const char *ev;
  455. {
  456. char *getev = getenv(ev);
  457. if (getev && strlen(getev) <= (BUFSZ / 2))
  458. return getev;
  459. else
  460. return (char *)0;
  461. }
  462. void
  463. initoptions()
  464. {
  465. #ifndef MAC
  466. char *opts;
  467. #endif
  468. int i;
  469. /* initialize the random number generator */
  470. setrandom();
  471. /* for detection of configfile options specified multiple times */
  472. iflags.opt_booldup = iflags.opt_compdup = (int *)0;
  473. for (i = 0; boolopt[i].name; i++) {
  474. if (boolopt[i].addr)
  475. *(boolopt[i].addr) = boolopt[i].initvalue;
  476. }
  477. flags.end_own = FALSE;
  478. flags.end_top = 3;
  479. flags.end_around = 2;
  480. iflags.runmode = RUN_LEAP;
  481. iflags.msg_history = 20;
  482. #ifdef TTY_GRAPHICS
  483. iflags.prevmsg_window = 's';
  484. #endif
  485. iflags.menu_headings = ATR_INVERSE;
  486. /* Use negative indices to indicate not yet selected */
  487. flags.initrole = -1;
  488. flags.initrace = -1;
  489. flags.initgend = -1;
  490. flags.initalign = -1;
  491. /* Set the default monster and object class symbols. Don't use */
  492. /* memcpy() --- sizeof char != sizeof uchar on some machines. */
  493. for (i = 0; i < MAXOCLASSES; i++)
  494. oc_syms[i] = (uchar) def_oc_syms[i];
  495. for (i = 0; i < MAXMCLASSES; i++)
  496. monsyms[i] = (uchar) def_monsyms[i];
  497. for (i = 0; i < WARNCOUNT; i++)
  498. warnsyms[i] = def_warnsyms[i].sym;
  499. iflags.bouldersym = 0;
  500. iflags.travelcc.x = iflags.travelcc.y = -1;
  501. flags.warnlevel = 1;
  502. flags.warntype = 0L;
  503. /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
  504. (void)memcpy((genericptr_t)flags.inv_order,
  505. (genericptr_t)def_inv_order, sizeof flags.inv_order);
  506. flags.pickup_types[0] = '\0';
  507. flags.pickup_burden = MOD_ENCUMBER;
  508. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
  509. flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
  510. switch_graphics(ASCII_GRAPHICS); /* set default characters */
  511. #if defined(UNIX) && defined(TTY_GRAPHICS)
  512. /*
  513. * Set defaults for some options depending on what we can
  514. * detect about the environment's capabilities.
  515. * This has to be done after the global initialization above
  516. * and before reading user-specific initialization via
  517. * config file/environment variable below.
  518. */
  519. /* this detects the IBM-compatible console on most 386 boxes */
  520. if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
  521. switch_graphics(IBM_GRAPHICS);
  522. # ifdef TEXTCOLOR
  523. iflags.use_color = TRUE;
  524. # endif
  525. }
  526. #endif /* UNIX && TTY_GRAPHICS */
  527. #if defined(UNIX) || defined(VMS)
  528. # ifdef TTY_GRAPHICS
  529. /* detect whether a "vt" terminal can handle alternate charsets */
  530. if ((opts = nh_getenv("TERM")) &&
  531. !strncmpi(opts, "vt", 2) && AS && AE &&
  532. index(AS, '\016') && index(AE, '\017')) {
  533. switch_graphics(DEC_GRAPHICS);
  534. }
  535. # endif
  536. #endif /* UNIX || VMS */
  537. #ifdef MAC_GRAPHICS_ENV
  538. switch_graphics(MAC_GRAPHICS);
  539. #endif /* MAC_GRAPHICS_ENV */
  540. flags.menu_style = MENU_FULL;
  541. /* since this is done before init_objects(), do partial init here */
  542. objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
  543. nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
  544. #ifndef MAC
  545. opts = getenv("NETHACKOPTIONS");
  546. if (!opts) opts = getenv("HACKOPTIONS");
  547. if (opts) {
  548. if (*opts == '/' || *opts == '\\' || *opts == '@') {
  549. if (*opts == '@') opts++; /* @filename */
  550. /* looks like a filename */
  551. if (strlen(opts) < BUFSZ/2)
  552. read_config_file(opts);
  553. } else {
  554. read_config_file((char *)0);
  555. /* let the total length of options be long;
  556. * parseoptions() will check each individually
  557. */
  558. parseoptions(opts, TRUE, FALSE);
  559. }
  560. } else
  561. #endif
  562. read_config_file((char *)0);
  563. (void)fruitadd(pl_fruit);
  564. /* Remove "slime mold" from list of object names; this will */
  565. /* prevent it from being wished unless it's actually present */
  566. /* as a named (or default) fruit. Wishing for "fruit" will */
  567. /* result in the player's preferred fruit [better than "\033"]. */
  568. obj_descr[SLIME_MOLD].oc_name = "fruit";
  569. return;
  570. }
  571. STATIC_OVL void
  572. nmcpy(dest, src, maxlen)
  573. char *dest;
  574. const char *src;
  575. int maxlen;
  576. {
  577. int count;
  578. for(count = 1; count < maxlen; count++) {
  579. if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
  580. *dest++ = *src++;
  581. }
  582. *dest = 0;
  583. }
  584. /*
  585. * escapes: escape expansion for showsyms. C-style escapes understood include
  586. * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
  587. * for control characters is also understood, and \[mM] followed by any of the
  588. * previous forms or by a character has the effect of 'meta'-ing the value (so
  589. * that the alternate character set will be enabled).
  590. */
  591. STATIC_OVL void
  592. escapes(cp, tp)
  593. const char *cp;
  594. char *tp;
  595. {
  596. while (*cp)
  597. {
  598. int cval = 0, meta = 0;
  599. if (*cp == '\\' && index("mM", cp[1])) {
  600. meta = 1;
  601. cp += 2;
  602. }
  603. if (*cp == '\\' && index("0123456789xXoO", cp[1]))
  604. {
  605. const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
  606. int dcount = 0;
  607. cp++;
  608. if (*cp == 'x' || *cp == 'X')
  609. for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
  610. cval = (cval * 16) + (dp - hex) / 2;
  611. else if (*cp == 'o' || *cp == 'O')
  612. for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
  613. cval = (cval * 8) + (*cp - '0');
  614. else
  615. for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
  616. cval = (cval * 10) + (*cp - '0');
  617. }
  618. else if (*cp == '\\') /* C-style character escapes */
  619. {
  620. switch (*++cp)
  621. {
  622. case '\\': cval = '\\'; break;
  623. case 'n': cval = '\n'; break;
  624. case 't': cval = '\t'; break;
  625. case 'b': cval = '\b'; break;
  626. case 'r': cval = '\r'; break;
  627. default: cval = *cp;
  628. }
  629. cp++;
  630. }
  631. else if (*cp == '^') /* expand control-character syntax */
  632. {
  633. cval = (*++cp & 0x1f);
  634. cp++;
  635. }
  636. else
  637. cval = *cp++;
  638. if (meta)
  639. cval |= 0x80;
  640. *tp++ = cval;
  641. }
  642. *tp = '\0';
  643. }
  644. STATIC_OVL void
  645. rejectoption(optname)
  646. const char *optname;
  647. {
  648. #ifdef MICRO
  649. pline("\"%s\" settable only from %s.", optname, configfile);
  650. #else
  651. pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
  652. configfile);
  653. #endif
  654. }
  655. STATIC_OVL void
  656. badoption(opts)
  657. const char *opts;
  658. {
  659. if (!initial) {
  660. if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
  661. option_help();
  662. else
  663. pline("Bad syntax: %s. Enter \"?g\" for help.", opts);
  664. return;
  665. }
  666. #ifdef MAC
  667. else return;
  668. #endif
  669. if(from_file)
  670. raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
  671. else
  672. raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts);
  673. wait_synch();
  674. }
  675. STATIC_OVL char *
  676. string_for_opt(opts, val_optional)
  677. char *opts;
  678. boolean val_optional;
  679. {
  680. char *colon, *equals;
  681. colon = index(opts, ':');
  682. equals = index(opts, '=');
  683. if (!colon || (equals && equals < colon)) colon = equals;
  684. if (!colon || !*++colon) {
  685. if (!val_optional) badoption(opts);
  686. return (char *)0;
  687. }
  688. return colon;
  689. }
  690. STATIC_OVL char *
  691. string_for_env_opt(optname, opts, val_optional)
  692. const char *optname;
  693. char *opts;
  694. boolean val_optional;
  695. {
  696. if(!initial) {
  697. rejectoption(optname);
  698. return (char *)0;
  699. }
  700. return string_for_opt(opts, val_optional);
  701. }
  702. STATIC_OVL void
  703. bad_negation(optname, with_parameter)
  704. const char *optname;
  705. boolean with_parameter;
  706. {
  707. pline_The("%s option may not %sbe negated.",
  708. optname,
  709. with_parameter ? "both have a value and " : "");
  710. }
  711. /*
  712. * Change the inventory order, using the given string as the new order.
  713. * Missing characters in the new order are filled in at the end from
  714. * the current inv_order, except for gold, which is forced to be first
  715. * if not explicitly present.
  716. *
  717. * This routine returns 1 unless there is a duplicate or bad char in
  718. * the string.
  719. */
  720. STATIC_OVL int
  721. change_inv_order(op)
  722. char *op;
  723. {
  724. int oc_sym, num;
  725. char *sp, buf[BUFSZ];
  726. num = 0;
  727. #ifndef GOLDOBJ
  728. if (!index(op, GOLD_SYM))
  729. buf[num++] = COIN_CLASS;
  730. #else
  731. /* !!!! probably unnecessary with gold as normal inventory */
  732. #endif
  733. for (sp = op; *sp; sp++) {
  734. oc_sym = def_char_to_objclass(*sp);
  735. /* reject bad or duplicate entries */
  736. if (oc_sym == MAXOCLASSES ||
  737. oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
  738. !index(flags.inv_order, oc_sym) || index(sp+1, *sp))
  739. return 0;
  740. /* retain good ones */
  741. buf[num++] = (char) oc_sym;
  742. }
  743. buf[num] = '\0';
  744. /* fill in any omitted classes, using previous ordering */
  745. for (sp = flags.inv_order; *sp; sp++)
  746. if (!index(buf, *sp)) {
  747. buf[num++] = *sp;
  748. buf[num] = '\0'; /* explicitly terminate for next index() */
  749. }
  750. Strcpy(flags.inv_order, buf);
  751. return 1;
  752. }
  753. STATIC_OVL void
  754. graphics_opts(opts, optype, maxlen, offset)
  755. register char *opts;
  756. const char *optype;
  757. int maxlen, offset;
  758. {
  759. uchar translate[MAXPCHARS+1];
  760. int length, i;
  761. if (!(opts = string_for_env_opt(optype, opts, FALSE)))
  762. return;
  763. escapes(opts, opts);
  764. length = strlen(opts);
  765. if (length > maxlen) length = maxlen;
  766. /* match the form obtained from PC configuration files */
  767. for (i = 0; i < length; i++)
  768. translate[i] = (uchar) opts[i];
  769. assign_graphics(translate, length, maxlen, offset);
  770. }
  771. STATIC_OVL void
  772. warning_opts(opts, optype)
  773. register char *opts;
  774. const char *optype;
  775. {
  776. uchar translate[MAXPCHARS+1];
  777. int length, i;
  778. if (!(opts = string_for_env_opt(optype, opts, FALSE)))
  779. return;
  780. escapes(opts, opts);
  781. length = strlen(opts);
  782. if (length > WARNCOUNT) length = WARNCOUNT;
  783. /* match the form obtained from PC configuration files */
  784. for (i = 0; i < length; i++)
  785. translate[i] = (((i < WARNCOUNT) && opts[i]) ?
  786. (uchar) opts[i] : def_warnsyms[i].sym);
  787. assign_warnings(translate);
  788. }
  789. void
  790. assign_warnings(graph_chars)
  791. register uchar *graph_chars;
  792. {
  793. int i;
  794. for (i = 0; i < WARNCOUNT; i++)
  795. if (graph_chars[i]) warnsyms[i] = graph_chars[i];
  796. }
  797. STATIC_OVL int
  798. feature_alert_opts(op, optn)
  799. char *op;
  800. const char *optn;
  801. {
  802. char buf[BUFSZ];
  803. boolean rejectver = FALSE;
  804. unsigned long fnv = get_feature_notice_ver(op); /* version.c */
  805. if (fnv == 0L) return 0;
  806. if (fnv > get_current_feature_ver())
  807. rejectver = TRUE;
  808. else
  809. flags.suppress_alert = fnv;
  810. if (rejectver) {
  811. if (!initial)
  812. You_cant("disable new feature alerts for future versions.");
  813. else {
  814. Sprintf(buf,
  815. "\n%s=%s Invalid reference to a future version ignored",
  816. optn, op);
  817. badoption(buf);
  818. }
  819. return 0;
  820. }
  821. if (!initial) {
  822. Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
  823. FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
  824. pline("Feature change alerts disabled for NetHack %s features and prior.",
  825. buf);
  826. }
  827. return 1;
  828. }
  829. void
  830. set_duplicate_opt_detection(on_or_off)
  831. int on_or_off;
  832. {
  833. int k, *optptr;
  834. if (on_or_off != 0) {
  835. /*-- ON --*/
  836. if (iflags.opt_booldup)
  837. impossible("iflags.opt_booldup already on (memory leak)");
  838. iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
  839. optptr = iflags.opt_booldup;
  840. for (k = 0; k < SIZE(boolopt); ++k)
  841. *optptr++ = 0;
  842. if (iflags.opt_compdup)
  843. impossible("iflags.opt_compdup already on (memory leak)");
  844. iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
  845. optptr = iflags.opt_compdup;
  846. for (k = 0; k < SIZE(compopt); ++k)
  847. *optptr++ = 0;
  848. } else {
  849. /*-- OFF --*/
  850. if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
  851. iflags.opt_booldup = (int *)0;
  852. if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
  853. iflags.opt_compdup = (int *)0;
  854. }
  855. }
  856. STATIC_OVL void
  857. duplicate_opt_detection(opts, bool_or_comp)
  858. const char *opts;
  859. int bool_or_comp; /* 0 == boolean option, 1 == compound */
  860. {
  861. int i, *optptr;
  862. #if defined(MAC)
  863. /* the Mac has trouble dealing with the output of messages while
  864. * processing the config file. That should get fixed one day.
  865. * For now just return.
  866. */
  867. return;
  868. #endif
  869. if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) {
  870. for (i = 0; boolopt[i].name; i++) {
  871. if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
  872. optptr = iflags.opt_booldup + i;
  873. if (*optptr == 1) {
  874. raw_printf(
  875. "\nWarning - Boolean option specified multiple times: %s.\n",
  876. opts);
  877. wait_synch();
  878. }
  879. *optptr += 1;
  880. break; /* don't match multiple options */
  881. }
  882. }
  883. } else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) {
  884. for (i = 0; compopt[i].name; i++) {
  885. if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) {
  886. optptr = iflags.opt_compdup + i;
  887. if (*optptr == 1) {
  888. raw_printf(
  889. "\nWarning - compound option specified multiple times: %s.\n",
  890. compopt[i].name);
  891. wait_synch();
  892. }
  893. *optptr += 1;
  894. break; /* don't match multiple options */
  895. }
  896. }
  897. }
  898. }
  899. void
  900. parseoptions(opts, tinitial, tfrom_file)
  901. register char *opts;
  902. boolean tinitial, tfrom_file;
  903. {
  904. register char *op;
  905. unsigned num;
  906. boolean negated;
  907. int i;
  908. const char *fullname;
  909. initial = tinitial;
  910. from_file = tfrom_file;
  911. if ((op = index(opts, ',')) != 0) {
  912. *op++ = 0;
  913. parseoptions(op, initial, from_file);
  914. }
  915. if (strlen(opts) > BUFSZ/2) {
  916. badoption("option too long");
  917. return;
  918. }
  919. /* strip leading and trailing white space */
  920. while (isspace(*opts)) opts++;
  921. op = eos(opts);
  922. while (--op >= opts && isspace(*op)) *op = '\0';
  923. if (!*opts) return;
  924. negated = FALSE;
  925. while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
  926. if (*opts == '!') opts++; else opts += 2;
  927. negated = !negated;
  928. }
  929. /* variant spelling */
  930. if (match_optname(opts, "colour", 5, FALSE))
  931. Strcpy(opts, "color"); /* fortunately this isn't longer */
  932. if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */
  933. duplicate_opt_detection(opts, 1); /* 1 means compound opts */
  934. /* special boolean options */
  935. if (match_optname(opts, "female", 3, FALSE)) {
  936. if(!initial && flags.female == negated)
  937. pline("That is not anatomically possible.");
  938. else
  939. flags.initgend = flags.female = !negated;
  940. return;
  941. }
  942. if (match_optname(opts, "male", 4, FALSE)) {
  943. if(!initial && flags.female != negated)
  944. pline("That is not anatomically possible.");
  945. else
  946. flags.initgend = flags.female = negated;
  947. return;
  948. }
  949. #if defined(MICRO) && !defined(AMIGA)
  950. /* included for compatibility with old NetHack.cnf files */
  951. if (match_optname(opts, "IBM_", 4, FALSE)) {
  952. iflags.BIOS = !negated;
  953. return;
  954. }
  955. #endif /* MICRO */
  956. /* compound options */
  957. fullname = "pettype";
  958. if (match_optname(opts, fullname, 3, TRUE)) {
  959. if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
  960. if (negated) bad_negation(fullname, TRUE);
  961. else switch (*op) {
  962. case 'd': /* dog */
  963. case 'D':
  964. preferred_pet = 'd';
  965. break;
  966. case 'c': /* cat */
  967. case 'C':
  968. case 'f': /* feline */
  969. case 'F':
  970. preferred_pet = 'c';
  971. break;
  972. case 'n': /* no pet */
  973. case 'N':
  974. preferred_pet = 'n';
  975. break;
  976. default:
  977. pline("Unrecognized pet type '%s'.", op);
  978. break;
  979. }
  980. } else if (negated) preferred_pet = 'n';
  981. return;
  982. }
  983. fullname = "catname";
  984. if (match_optname(opts, fullname, 3, TRUE)) {
  985. if (negated) bad_negation(fullname, FALSE);
  986. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  987. nmcpy(catname, op, PL_PSIZ);
  988. return;
  989. }
  990. fullname = "dogname";
  991. if (match_optname(opts, fullname, 3, TRUE)) {
  992. if (negated) bad_negation(fullname, FALSE);
  993. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  994. nmcpy(dogname, op, PL_PSIZ);
  995. return;
  996. }
  997. fullname = "horsename";
  998. if (match_optname(opts, fullname, 5, TRUE)) {
  999. if (negated) bad_negation(fullname, FALSE);
  1000. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1001. nmcpy(horsename, op, PL_PSIZ);
  1002. return;
  1003. }
  1004. fullname = "number_pad";
  1005. if (match_optname(opts, fullname, 10, TRUE)) {
  1006. boolean compat = (strlen(opts) <= 10);
  1007. number_pad(iflags.num_pad ? 1 : 0);
  1008. op = string_for_opt(opts, (compat || !initial));
  1009. if (!op) {
  1010. if (compat || negated || initial) {
  1011. /* for backwards compatibility, "number_pad" without a
  1012. value is a synonym for number_pad:1 */
  1013. iflags.num_pad = !negated;
  1014. if (iflags.num_pad) iflags.num_pad_mode = 0;
  1015. }
  1016. return;
  1017. }
  1018. if (negated) {
  1019. bad_negation("number_pad", TRUE);
  1020. return;
  1021. }
  1022. if (*op == '1' || *op == '2') {
  1023. iflags.num_pad = 1;
  1024. if (*op == '2') iflags.num_pad_mode = 1;
  1025. else iflags.num_pad_mode = 0;
  1026. } else if (*op == '0') {
  1027. iflags.num_pad = 0;
  1028. iflags.num_pad_mode = 0;
  1029. } else badoption(opts);
  1030. return;
  1031. }
  1032. fullname = "runmode";
  1033. if (match_optname(opts, fullname, 4, TRUE)) {
  1034. if (negated) {
  1035. iflags.runmode = RUN_TPORT;
  1036. } else if ((op = string_for_opt(opts, FALSE)) != 0) {
  1037. if (!strncmpi(op, "teleport", strlen(op)))
  1038. iflags.runmode = RUN_TPORT;
  1039. else if (!strncmpi(op, "run", strlen(op)))
  1040. iflags.runmode = RUN_LEAP;
  1041. else if (!strncmpi(op, "walk", strlen(op)))
  1042. iflags.runmode = RUN_STEP;
  1043. else if (!strncmpi(op, "crawl", strlen(op)))
  1044. iflags.runmode = RUN_CRAWL;
  1045. else
  1046. badoption(opts);
  1047. }
  1048. return;
  1049. }
  1050. fullname = "msghistory";
  1051. if (match_optname(opts, fullname, 3, TRUE)) {
  1052. op = string_for_env_opt(fullname, opts, negated);
  1053. if ((negated && !op) || (!negated && op)) {
  1054. iflags.msg_history = negated ? 0 : atoi(op);
  1055. } else if (negated) bad_negation(fullname, TRUE);
  1056. return;
  1057. }
  1058. fullname="msg_window";
  1059. /* msg_window:single, combo, full or reversed */
  1060. if (match_optname(opts, fullname, 4, TRUE)) {
  1061. /* allow option to be silently ignored by non-tty ports */
  1062. #ifdef TTY_GRAPHICS
  1063. int tmp;
  1064. if (!(op = string_for_opt(opts, TRUE))) {
  1065. tmp = negated ? 's' : 'f';
  1066. } else {
  1067. if (negated) {
  1068. bad_negation(fullname, TRUE);
  1069. return;
  1070. }
  1071. tmp = tolower(*op);
  1072. }
  1073. switch (tmp) {
  1074. case 's': /* single message history cycle (default if negated) */
  1075. iflags.prevmsg_window = 's';
  1076. break;
  1077. case 'c': /* combination: two singles, then full page reversed */
  1078. iflags.prevmsg_window = 'c';
  1079. break;
  1080. case 'f': /* full page (default if no opts) */
  1081. iflags.prevmsg_window = 'f';
  1082. break;
  1083. case 'r': /* full page (reversed) */
  1084. iflags.prevmsg_window = 'r';
  1085. break;
  1086. default:
  1087. badoption(opts);
  1088. }
  1089. #endif
  1090. return;
  1091. }
  1092. /* WINCAP
  1093. * setting font options */
  1094. fullname = "font";
  1095. if (!strncmpi(opts, fullname, 4))
  1096. {
  1097. int wintype = -1;
  1098. char *fontopts = opts + 4;
  1099. if (!strncmpi(fontopts, "map", 3) ||
  1100. !strncmpi(fontopts, "_map", 4))
  1101. wintype = NHW_MAP;
  1102. else if (!strncmpi(fontopts, "message", 7) ||
  1103. !strncmpi(fontopts, "_message", 8))
  1104. wintype = NHW_MESSAGE;
  1105. else if (!strncmpi(fontopts, "text", 4) ||
  1106. !strncmpi(fontopts, "_text", 5))
  1107. wintype = NHW_TEXT;
  1108. else if (!strncmpi(fontopts, "menu", 4) ||
  1109. !strncmpi(fontopts, "_menu", 5))
  1110. wintype = NHW_MENU;
  1111. else if (!strncmpi(fontopts, "status", 6) ||
  1112. !strncmpi(fontopts, "_status", 7))
  1113. wintype = NHW_STATUS;
  1114. else if (!strncmpi(fontopts, "_size", 5)) {
  1115. if (!strncmpi(fontopts, "_size_map", 8))
  1116. wintype = NHW_MAP;
  1117. else if (!strncmpi(fontopts, "_size_message", 12))
  1118. wintype = NHW_MESSAGE;
  1119. else if (!strncmpi(fontopts, "_size_text", 9))
  1120. wintype = NHW_TEXT;
  1121. else if (!strncmpi(fontopts, "_size_menu", 9))
  1122. wintype = NHW_MENU;
  1123. else if (!strncmpi(fontopts, "_size_status", 11))
  1124. wintype = NHW_STATUS;
  1125. else {
  1126. badoption(opts);
  1127. return;
  1128. }
  1129. if (wintype > 0 && !negated &&
  1130. (op = string_for_opt(opts, FALSE)) != 0) {
  1131. switch(wintype) {
  1132. case NHW_MAP:
  1133. iflags.wc_fontsiz_map = atoi(op);
  1134. break;
  1135. case NHW_MESSAGE:
  1136. iflags.wc_fontsiz_message = atoi(op);
  1137. break;
  1138. case NHW_TEXT:
  1139. iflags.wc_fontsiz_text = atoi(op);
  1140. break;
  1141. case NHW_MENU:
  1142. iflags.wc_fontsiz_menu = atoi(op);
  1143. break;
  1144. case NHW_STATUS:
  1145. iflags.wc_fontsiz_status = atoi(op);
  1146. break;
  1147. }
  1148. }
  1149. return;
  1150. } else {
  1151. badoption(opts);
  1152. }
  1153. if (wintype > 0 &&
  1154. (op = string_for_opt(opts, FALSE)) != 0) {
  1155. wc_set_font_name(wintype, op);
  1156. #ifdef MAC
  1157. set_font_name (wintype, op);
  1158. #endif
  1159. return;
  1160. } else if (negated) bad_negation(fullname, TRUE);
  1161. return;
  1162. }
  1163. #ifdef CHANGE_COLOR
  1164. if (match_optname(opts, "palette", 3, TRUE)
  1165. # ifdef MAC
  1166. || match_optname(opts, "hicolor", 3, TRUE)
  1167. # endif
  1168. ) {
  1169. int color_number, color_incr;
  1170. # ifdef MAC
  1171. if (match_optname(opts, "hicolor", 3, TRUE)) {
  1172. if (negated) {
  1173. bad_negation("hicolor", FALSE);
  1174. return;
  1175. }
  1176. color_number = CLR_MAX + 4; /* HARDCODED inverse number */
  1177. color_incr = -1;
  1178. } else {
  1179. # endif
  1180. if (negated) {
  1181. bad_negation("palette", FALSE);
  1182. return;
  1183. }
  1184. color_number = 0;
  1185. color_incr = 1;
  1186. # ifdef MAC
  1187. }
  1188. # endif
  1189. if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
  1190. char *pt = op;
  1191. int cnt, tmp, reverse;
  1192. long rgb;
  1193. while (*pt && color_number >= 0) {
  1194. cnt = 3;
  1195. rgb = 0L;
  1196. if (*pt == '-') {
  1197. reverse = 1;
  1198. pt++;
  1199. } else {
  1200. reverse = 0;
  1201. }
  1202. while (cnt-- > 0) {
  1203. if (*pt && *pt != '/') {
  1204. # ifdef AMIGA
  1205. rgb <<= 4;
  1206. # else
  1207. rgb <<= 8;
  1208. # endif
  1209. tmp = *(pt++);
  1210. if (isalpha(tmp)) {
  1211. tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
  1212. } else {
  1213. tmp &= 0xf; /* Digits in ASCII too... */
  1214. }
  1215. # ifndef AMIGA
  1216. /* Add an extra so we fill f -> ff and 0 -> 00 */
  1217. rgb += tmp << 4;
  1218. # endif
  1219. rgb += tmp;
  1220. }
  1221. }
  1222. if (*pt == '/') {
  1223. pt++;
  1224. }
  1225. change_color(color_number, rgb, reverse);
  1226. color_number += color_incr;
  1227. }
  1228. }
  1229. if (!initial) {
  1230. need_redraw = TRUE;
  1231. }
  1232. return;
  1233. }
  1234. #endif /* CHANGE_COLOR */
  1235. if (match_optname(opts, "fruit", 2, TRUE)) {
  1236. char empty_str = '\0';
  1237. op = string_for_opt(opts, negated);
  1238. if (negated) {
  1239. if (op) {
  1240. bad_negation("fruit", TRUE);
  1241. return;
  1242. }
  1243. op = &empty_str;
  1244. goto goodfruit;
  1245. }
  1246. if (!op) return;
  1247. if (!initial) {
  1248. struct fruit *f;
  1249. num = 0;
  1250. for(f=ffruit; f; f=f->nextf) {
  1251. if (!strcmp(op, f->fname)) goto goodfruit;
  1252. num++;
  1253. }
  1254. if (num >= 100) {
  1255. pline("Doing that so many times isn't very fruitful.");
  1256. return;
  1257. }
  1258. }
  1259. goodfruit:
  1260. nmcpy(pl_fruit, op, PL_FSIZ);
  1261. /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
  1262. if (!*pl_fruit)
  1263. nmcpy(pl_fruit, "slime mold", PL_FSIZ);
  1264. if (!initial)
  1265. (void)fruitadd(pl_fruit);
  1266. /* If initial, then initoptions is allowed to do it instead
  1267. * of here (initoptions always has to do it even if there's
  1268. * no fruit option at all. Also, we don't want people
  1269. * setting multiple fruits in their options.)
  1270. */
  1271. return;
  1272. }
  1273. /* graphics:string */
  1274. fullname = "graphics";
  1275. if (match_optname(opts, fullname, 2, TRUE)) {
  1276. if (negated) bad_negation(fullname, FALSE);
  1277. else graphics_opts(opts, fullname, MAXPCHARS, 0);
  1278. return;
  1279. }
  1280. fullname = "dungeon";
  1281. if (match_optname(opts, fullname, 2, TRUE)) {
  1282. if (negated) bad_negation(fullname, FALSE);
  1283. else graphics_opts(opts, fullname, MAXDCHARS, 0);
  1284. return;
  1285. }
  1286. fullname = "traps";
  1287. if (match_optname(opts, fullname, 2, TRUE)) {
  1288. if (negated) bad_negation(fullname, FALSE);
  1289. else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS);
  1290. return;
  1291. }
  1292. fullname = "effects";
  1293. if (match_optname(opts, fullname, 2, TRUE)) {
  1294. if (negated) bad_negation(fullname, FALSE);
  1295. else
  1296. graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS);
  1297. return;
  1298. }
  1299. /* objects:string */
  1300. fullname = "objects";
  1301. if (match_optname(opts, fullname, 7, TRUE)) {
  1302. int length;
  1303. if (negated) {
  1304. bad_negation(fullname, FALSE);
  1305. return;
  1306. }
  1307. if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
  1308. return;
  1309. escapes(opts, opts);
  1310. /*
  1311. * Override the default object class symbols. The first
  1312. * object in the object class is the "random object". I
  1313. * don't want to use 0 as an object class, so the "random
  1314. * object" is basically a place holder.
  1315. *
  1316. * The object class symbols have already been initialized in
  1317. * initoptions().
  1318. */
  1319. length = strlen(opts);
  1320. if (length >= MAXOCLASSES)
  1321. length = MAXOCLASSES-1; /* don't count RANDOM_OBJECT */
  1322. for (i = 0; i < length; i++)
  1323. oc_syms[i+1] = (uchar) opts[i];
  1324. return;
  1325. }
  1326. /* monsters:string */
  1327. fullname = "monsters";
  1328. if (match_optname(opts, fullname, 8, TRUE)) {
  1329. int length;
  1330. if (negated) {
  1331. bad_negation(fullname, FALSE);
  1332. return;
  1333. }
  1334. if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
  1335. return;
  1336. escapes(opts, opts);
  1337. /* Override default mon class symbols set in initoptions(). */
  1338. length = strlen(opts);
  1339. if (length >= MAXMCLASSES)
  1340. length = MAXMCLASSES-1; /* mon class 0 unused */
  1341. for (i = 0; i < length; i++)
  1342. monsyms[i+1] = (uchar) opts[i];
  1343. return;
  1344. }
  1345. fullname = "warnings";
  1346. if (match_optname(opts, fullname, 5, TRUE)) {
  1347. if (negated) bad_negation(fullname, FALSE);
  1348. else warning_opts(opts, fullname);
  1349. return;
  1350. }
  1351. /* boulder:symbol */
  1352. fullname = "boulder";
  1353. if (match_optname(opts, fullname, 7, TRUE)) {
  1354. int clash = 0;
  1355. if (negated) {
  1356. bad_negation(fullname, FALSE);
  1357. return;
  1358. }
  1359. /* if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
  1360. if (!(opts = string_for_opt(opts, FALSE)))
  1361. return;
  1362. escapes(opts, opts);
  1363. if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
  1364. clash = 1;
  1365. else if (opts[0] >= '1' && opts[0] <= '5')
  1366. clash = 2;
  1367. if (clash) {
  1368. /* symbol chosen matches a used monster or warning
  1369. symbol which is not good - reject it*/
  1370. pline(
  1371. "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
  1372. opts[0], (clash == 1) ? "monster" : "warning");
  1373. } else {
  1374. /*
  1375. * Override the default boulder symbol.
  1376. */
  1377. iflags.bouldersym = (uchar) opts[0];
  1378. }
  1379. if (!initial) need_redraw = TRUE;
  1380. return;
  1381. }
  1382. /* name:string */
  1383. fullname = "name";
  1384. if (match_optname(opts, fullname, 4, TRUE)) {
  1385. if (negated) bad_negation(fullname, FALSE);
  1386. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1387. nmcpy(plname, op, PL_NSIZ);
  1388. return;
  1389. }
  1390. /* role:string or character:string */
  1391. fullname = "role";
  1392. if (match_optname(opts, fullname, 4, TRUE) ||
  1393. match_optname(opts, (fullname = "character"), 4, TRUE)) {
  1394. if (negated) bad_negation(fullname, FALSE);
  1395. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1396. if ((flags.initrole = str2role(op)) == ROLE_NONE)
  1397. badoption(opts);
  1398. else /* Backwards compatibility */
  1399. nmcpy(pl_character, op, PL_NSIZ);
  1400. }
  1401. return;
  1402. }
  1403. /* race:string */
  1404. fullname = "race";
  1405. if (match_optname(opts, fullname, 4, TRUE)) {
  1406. if (negated) bad_negation(fullname, FALSE);
  1407. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1408. if ((flags.initrace = str2race(op)) == ROLE_NONE)
  1409. badoption(opts);
  1410. else /* Backwards compatibility */
  1411. pl_race = *op;
  1412. }
  1413. return;
  1414. }
  1415. /* gender:string */
  1416. fullname = "gender";
  1417. if (match_optname(opts, fullname, 4, TRUE)) {
  1418. if (negated) bad_negation(fullname, FALSE);
  1419. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1420. if ((flags.initgend = str2gend(op)) == ROLE_NONE)
  1421. badoption(opts);
  1422. else
  1423. flags.female = flags.initgend;
  1424. }
  1425. return;
  1426. }
  1427. /* altkeyhandler:string */
  1428. fullname = "altkeyhandler";
  1429. if (match_optname(opts, fullname, 4, TRUE)) {
  1430. if (negated) bad_negation(fullname, FALSE);
  1431. else if ((op = string_for_opt(opts, negated))) {
  1432. #ifdef WIN32CON
  1433. (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
  1434. load_keyboard_handler();
  1435. #endif
  1436. }
  1437. return;
  1438. }
  1439. /* WINCAP
  1440. * align_status:[left|top|right|bottom] */
  1441. fullname = "align_status";
  1442. if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
  1443. op = string_for_opt(opts, negated);
  1444. if (op && !negated) {
  1445. if (!strncmpi (op, "left", sizeof("left")-1))
  1446. iflags.wc_align_status = ALIGN_LEFT;
  1447. else if (!strncmpi (op, "top", sizeof("top")-1))
  1448. iflags.wc_align_status = ALIGN_TOP;
  1449. else if (!strncmpi (op, "right", sizeof("right")-1))
  1450. iflags.wc_align_status = ALIGN_RIGHT;
  1451. else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
  1452. iflags.wc_align_status = ALIGN_BOTTOM;
  1453. else
  1454. badoption(opts);
  1455. } else if (negated) bad_negation(fullname, TRUE);
  1456. return;
  1457. }
  1458. /* WINCAP
  1459. * align_message:[left|top|right|bottom] */
  1460. fullname = "align_message";
  1461. if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
  1462. op = string_for_opt(opts, negated);
  1463. if (op && !negated) {
  1464. if (!strncmpi (op, "left", sizeof("left")-1))
  1465. iflags.wc_align_message = ALIGN_LEFT;
  1466. else if (!strncmpi (op, "top", sizeof("top")-1))
  1467. iflags.wc_align_message = ALIGN_TOP;
  1468. else if (!strncmpi (op, "right", sizeof("right")-1))
  1469. iflags.wc_align_message = ALIGN_RIGHT;
  1470. else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
  1471. iflags.wc_align_message = ALIGN_BOTTOM;
  1472. else
  1473. badoption(opts);
  1474. } else if (negated) bad_negation(fullname, TRUE);
  1475. return;
  1476. }
  1477. /* align:string */
  1478. fullname = "align";
  1479. if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
  1480. if (negated) bad_negation(fullname, FALSE);
  1481. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1482. if ((flags.initalign = str2align(op)) == ROLE_NONE)
  1483. badoption(opts);
  1484. return;
  1485. }
  1486. /* the order to list the pack */
  1487. fullname = "packorder";
  1488. if (match_optname(opts, fullname, 4, TRUE)) {
  1489. if (negated) {
  1490. bad_negation(fullname, FALSE);
  1491. return;
  1492. } else if (!(op = string_for_opt(opts, FALSE))) return;
  1493. if (!change_inv_order(op))
  1494. badoption(opts);
  1495. return;
  1496. }
  1497. /* maximum burden picked up before prompt (Warren Cheung) */
  1498. fullname = "pickup_burden";
  1499. if (match_optname(opts, fullname, 8, TRUE)) {
  1500. if (negated) {
  1501. bad_negation(fullname, FALSE);
  1502. return;
  1503. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1504. switch (tolower(*op)) {
  1505. /* Unencumbered */
  1506. case 'u':
  1507. flags.pickup_burden = UNENCUMBERED;
  1508. break;
  1509. /* Burdened (slight encumbrance) */
  1510. case 'b':
  1511. flags.pickup_burden = SLT_ENCUMBER;
  1512. break;
  1513. /* streSsed (moderate encumbrance) */
  1514. case 's':
  1515. flags.pickup_burden = MOD_ENCUMBER;
  1516. break;
  1517. /* straiNed (heavy encumbrance) */
  1518. case 'n':
  1519. flags.pickup_burden = HVY_ENCUMBER;
  1520. break;
  1521. /* OverTaxed (extreme encumbrance) */
  1522. case 'o':
  1523. case 't':
  1524. flags.pickup_burden = EXT_ENCUMBER;
  1525. break;
  1526. /* overLoaded */
  1527. case 'l':
  1528. flags.pickup_burden = OVERLOADED;
  1529. break;
  1530. default:
  1531. badoption(opts);
  1532. }
  1533. }
  1534. return;
  1535. }
  1536. /* types of objects to pick up automatically */
  1537. if (match_optname(opts, "pickup_types", 8, TRUE)) {
  1538. char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
  1539. qbuf[QBUFSZ], abuf[BUFSZ];
  1540. int oc_sym;
  1541. boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
  1542. oc_to_str(flags.pickup_types, tbuf);
  1543. flags.pickup_types[0] = '\0'; /* all */
  1544. op = string_for_opt(opts, (compat || !initial));
  1545. if (!op) {
  1546. if (compat || negated || initial) {
  1547. /* for backwards compatibility, "pickup" without a
  1548. value is a synonym for autopickup of all types
  1549. (and during initialization, we can't prompt yet) */
  1550. flags.pickup = !negated;
  1551. return;
  1552. }
  1553. oc_to_str(flags.inv_order, ocl);
  1554. use_menu = TRUE;
  1555. if (flags.menu_style == MENU_TRADITIONAL ||
  1556. flags.menu_style == MENU_COMBINATION) {
  1557. use_menu = FALSE;
  1558. Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
  1559. ocl, *tbuf ? tbuf : "all");
  1560. getlin(qbuf, abuf);
  1561. op = mungspaces(abuf);
  1562. if (abuf[0] == '\0' || abuf[0] == '\033')
  1563. op = tbuf; /* restore */
  1564. else if (abuf[0] == 'm')
  1565. use_menu = TRUE;
  1566. }
  1567. if (use_menu) {
  1568. (void) choose_classes_menu("Auto-Pickup what?", 1,
  1569. TRUE, ocl, tbuf);
  1570. op = tbuf;
  1571. }
  1572. }
  1573. if (negated) {
  1574. bad_negation("pickup_types", TRUE);
  1575. return;
  1576. }
  1577. while (*op == ' ') op++;
  1578. if (*op != 'a' && *op != 'A') {
  1579. num = 0;
  1580. while (*op) {
  1581. oc_sym = def_char_to_objclass(*op);
  1582. /* make sure all are valid obj symbols occuring once */
  1583. if (oc_sym != MAXOCLASSES &&
  1584. !index(flags.pickup_types, oc_sym)) {
  1585. flags.pickup_types[num] = (char)oc_sym;
  1586. flags.pickup_types[++num] = '\0';
  1587. } else
  1588. badopt = TRUE;
  1589. op++;
  1590. }
  1591. if (badopt) badoption(opts);
  1592. }
  1593. return;
  1594. }
  1595. /* WINCAP
  1596. * player_selection: dialog | prompts */
  1597. fullname = "player_selection";
  1598. if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
  1599. op = string_for_opt(opts, negated);
  1600. if (op && !negated) {
  1601. if (!strncmpi (op, "dialog", sizeof("dialog")-1))
  1602. iflags.wc_player_selection = VIA_DIALOG;
  1603. else if (!strncmpi (op, "prompt", sizeof("prompt")-1))
  1604. iflags.wc_player_selection = VIA_PROMPTS;
  1605. else
  1606. badoption(opts);
  1607. } else if (negated) bad_negation(fullname, TRUE);
  1608. return;
  1609. }
  1610. /* things to disclose at end of game */
  1611. if (match_optname(opts, "disclose", 7, TRUE)) {
  1612. /*
  1613. * The order that the end_disclore options are stored:
  1614. * inventory, attribs, vanquished, genocided, conduct
  1615. * There is an array in flags:
  1616. * end_disclose[NUM_DISCLOSURE_OPT];
  1617. * with option settings for the each of the following:
  1618. * iagvc [see disclosure_options in decl.c]:
  1619. * Legal setting values in that array are:
  1620. * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
  1621. * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
  1622. * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
  1623. * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
  1624. *
  1625. * Those setting values can be used in the option
  1626. * string as a prefix to get the desired behaviour.
  1627. *
  1628. * For backward compatibility, no prefix is required,
  1629. * and the presence of a i,a,g,v, or c without a prefix
  1630. * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
  1631. */
  1632. boolean badopt = FALSE;
  1633. int idx, prefix_val;
  1634. op = string_for_opt(opts, TRUE);
  1635. if (op && negated) {
  1636. bad_negation("disclose", TRUE);
  1637. return;
  1638. }
  1639. /* "disclose" without a value means "all with prompting"
  1640. and negated means "none without prompting" */
  1641. if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
  1642. if (op && !strcmpi(op, "none")) negated = TRUE;
  1643. for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
  1644. flags.end_disclose[num] = negated ?
  1645. DISCLOSE_NO_WITHOUT_PROMPT :
  1646. DISCLOSE_PROMPT_DEFAULT_YES;
  1647. return;
  1648. }
  1649. num = 0;
  1650. prefix_val = -1;
  1651. while (*op && num < sizeof flags.end_disclose - 1) {
  1652. register char c, *dop;
  1653. static char valid_settings[] = {
  1654. DISCLOSE_PROMPT_DEFAULT_YES,
  1655. DISCLOSE_PROMPT_DEFAULT_NO,
  1656. DISCLOSE_YES_WITHOUT_PROMPT,
  1657. DISCLOSE_NO_WITHOUT_PROMPT,
  1658. '\0'
  1659. };
  1660. c = lowc(*op);
  1661. if (c == 'k') c = 'v'; /* killed -> vanquished */
  1662. dop = index(disclosure_options, c);
  1663. if (dop) {
  1664. idx = dop - disclosure_options;
  1665. if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
  1666. impossible("bad disclosure index %d %c",
  1667. idx, c);
  1668. continue;
  1669. }
  1670. if (prefix_val != -1) {
  1671. flags.end_disclose[idx] = prefix_val;
  1672. prefix_val = -1;
  1673. } else
  1674. flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
  1675. } else if (index(valid_settings, c)) {
  1676. prefix_val = c;
  1677. } else if (c == ' ') {
  1678. /* do nothing */
  1679. } else
  1680. badopt = TRUE;
  1681. op++;
  1682. }
  1683. if (badopt) badoption(opts);
  1684. return;
  1685. }
  1686. /* scores:5t[op] 5a[round] o[wn] */
  1687. if (match_optname(opts, "scores", 4, TRUE)) {
  1688. if (negated) {
  1689. bad_negation("scores", FALSE);
  1690. return;
  1691. }
  1692. if (!(op = string_for_opt(opts, FALSE))) return;
  1693. while (*op) {
  1694. int inum = 1;
  1695. if (digit(*op)) {
  1696. inum = atoi(op);
  1697. while (digit(*op)) op++;
  1698. } else if (*op == '!') {
  1699. negated = !negated;
  1700. op++;
  1701. }
  1702. while (*op == ' ') op++;
  1703. switch (*op) {
  1704. case 't':
  1705. case 'T': flags.end_top = inum;
  1706. break;
  1707. case 'a':
  1708. case 'A': flags.end_around = inum;
  1709. break;
  1710. case 'o':
  1711. case 'O': flags.end_own = !negated;
  1712. break;
  1713. default: badoption(opts);
  1714. return;
  1715. }
  1716. while (letter(*++op) || *op == ' ') continue;
  1717. if (*op == '/') op++;
  1718. }
  1719. return;
  1720. }
  1721. fullname = "suppress_alert";
  1722. if (match_optname(opts, fullname, 4, TRUE)) {
  1723. op = string_for_opt(opts, negated);
  1724. if (negated) bad_negation(fullname, FALSE);
  1725. else if (op) (void) feature_alert_opts(op,fullname);
  1726. return;
  1727. }
  1728. #ifdef VIDEOSHADES
  1729. /* videocolors:string */
  1730. fullname = "videocolors";
  1731. if (match_optname(opts, fullname, 6, TRUE) ||
  1732. match_optname(opts, "videocolours", 10, TRUE)) {
  1733. if (negated) {
  1734. bad_negation(fullname, FALSE);
  1735. return;
  1736. }
  1737. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1738. return;
  1739. }
  1740. if (!assign_videocolors(opts))
  1741. badoption(opts);
  1742. return;
  1743. }
  1744. /* videoshades:string */
  1745. fullname = "videoshades";
  1746. if (match_optname(opts, fullname, 6, TRUE)) {
  1747. if (negated) {
  1748. bad_negation(fullname, FALSE);
  1749. return;
  1750. }
  1751. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1752. return;
  1753. }
  1754. if (!assign_videoshades(opts))
  1755. badoption(opts);
  1756. return;
  1757. }
  1758. #endif /* VIDEOSHADES */
  1759. #ifdef MSDOS
  1760. # ifdef NO_TERMS
  1761. /* video:string -- must be after longer tests */
  1762. fullname = "video";
  1763. if (match_optname(opts, fullname, 5, TRUE)) {
  1764. if (negated) {
  1765. bad_negation(fullname, FALSE);
  1766. return;
  1767. }
  1768. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1769. return;
  1770. }
  1771. if (!assign_video(opts))
  1772. badoption(opts);
  1773. return;
  1774. }
  1775. # endif /* NO_TERMS */
  1776. /* soundcard:string -- careful not to match boolean 'sound' */
  1777. fullname = "soundcard";
  1778. if (match_optname(opts, fullname, 6, TRUE)) {
  1779. if (negated) {
  1780. bad_negation(fullname, FALSE);
  1781. return;
  1782. }
  1783. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1784. return;
  1785. }
  1786. if (!assign_soundcard(opts))
  1787. badoption(opts);
  1788. return;
  1789. }
  1790. #endif /* MSDOS */
  1791. /* WINCAP
  1792. * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
  1793. ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
  1794. fullname = "map_mode";
  1795. if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
  1796. op = string_for_opt(opts, negated);
  1797. if (op && !negated) {
  1798. if (!strncmpi (op, "tiles", sizeof("tiles")-1))
  1799. iflags.wc_map_mode = MAP_MODE_TILES;
  1800. else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
  1801. iflags.wc_map_mode = MAP_MODE_ASCII4x6;
  1802. else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
  1803. iflags.wc_map_mode = MAP_MODE_ASCII6x8;
  1804. else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
  1805. iflags.wc_map_mode = MAP_MODE_ASCII8x8;
  1806. else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
  1807. iflags.wc_map_mode = MAP_MODE_ASCII16x8;
  1808. else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
  1809. iflags.wc_map_mode = MAP_MODE_ASCII7x12;
  1810. else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
  1811. iflags.wc_map_mode = MAP_MODE_ASCII8x12;
  1812. else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
  1813. iflags.wc_map_mode = MAP_MODE_ASCII16x12;
  1814. else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
  1815. iflags.wc_map_mode = MAP_MODE_ASCII12x16;
  1816. else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
  1817. iflags.wc_map_mode = MAP_MODE_ASCII10x18;
  1818. else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
  1819. iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
  1820. else
  1821. badoption(opts);
  1822. } else if (negated) bad_negation(fullname, TRUE);
  1823. return;
  1824. }
  1825. /* WINCAP
  1826. * scroll_amount:nn */
  1827. fullname = "scroll_amount";
  1828. if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
  1829. op = string_for_opt(opts, negated);
  1830. if ((negated && !op) || (!negated && op)) {
  1831. iflags.wc_scroll_amount = negated ? 1 : atoi(op);
  1832. } else if (negated) bad_negation(fullname, TRUE);
  1833. return;
  1834. }
  1835. /* WINCAP
  1836. * scroll_margin:nn */
  1837. fullname = "scroll_margin";
  1838. if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
  1839. op = string_for_opt(opts, negated);
  1840. if ((negated && !op) || (!negated && op)) {
  1841. iflags.wc_scroll_margin = negated ? 5 : atoi(op);
  1842. } else if (negated) bad_negation(fullname, TRUE);
  1843. return;
  1844. }
  1845. fullname = "subkeyvalue";
  1846. if (match_optname(opts, fullname, 5, TRUE)) {
  1847. if (negated) bad_negation(fullname, FALSE);
  1848. else {
  1849. #if defined(WIN32CON)
  1850. op = string_for_opt(opts, 0);
  1851. map_subkeyvalue(op);
  1852. #endif
  1853. }
  1854. return;
  1855. }
  1856. /* WINCAP
  1857. * tile_width:nn */
  1858. fullname = "tile_width";
  1859. if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
  1860. op = string_for_opt(opts, negated);
  1861. if ((negated && !op) || (!negated && op)) {
  1862. iflags.wc_tile_width = negated ? 0 : atoi(op);
  1863. } else if (negated) bad_negation(fullname, TRUE);
  1864. return;
  1865. }
  1866. /* WINCAP
  1867. * tile_file:name */
  1868. fullname = "tile_file";
  1869. if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
  1870. if ((op = string_for_opt(opts, FALSE)) != 0) {
  1871. if (iflags.wc_tile_file) free(iflags.wc_tile_file);
  1872. iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
  1873. Strcpy(iflags.wc_tile_file, op);
  1874. }
  1875. return;
  1876. }
  1877. /* WINCAP
  1878. * tile_height:nn */
  1879. fullname = "tile_height";
  1880. if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
  1881. op = string_for_opt(opts, negated);
  1882. if ((negated && !op) || (!negated && op)) {
  1883. iflags.wc_tile_height = negated ? 0 : atoi(op);
  1884. } else if (negated) bad_negation(fullname, TRUE);
  1885. return;
  1886. }
  1887. /* WINCAP
  1888. * vary_msgcount:nn */
  1889. fullname = "vary_msgcount";
  1890. if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
  1891. op = string_for_opt(opts, negated);
  1892. if ((negated && !op) || (!negated && op)) {
  1893. iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
  1894. } else if (negated) bad_negation(fullname, TRUE);
  1895. return;
  1896. }
  1897. fullname = "windowtype";
  1898. if (match_optname(opts, fullname, 3, TRUE)) {
  1899. if (negated) {
  1900. bad_negation(fullname, FALSE);
  1901. return;
  1902. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1903. char buf[WINTYPELEN];
  1904. nmcpy(buf, op, WINTYPELEN);
  1905. choose_windows(buf);
  1906. }
  1907. return;
  1908. }
  1909. /* WINCAP
  1910. * setting window colors
  1911. * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
  1912. */
  1913. fullname = "windowcolors";
  1914. if (match_optname(opts, fullname, 7, TRUE)) {
  1915. if ((op = string_for_opt(opts, FALSE)) != 0) {
  1916. if (!wc_set_window_colors(op))
  1917. badoption(opts);
  1918. } else if (negated) bad_negation(fullname, TRUE);
  1919. return;
  1920. }
  1921. /* menustyle:traditional or combo or full or partial */
  1922. if (match_optname(opts, "menustyle", 4, TRUE)) {
  1923. int tmp;
  1924. boolean val_required = (strlen(opts) > 5 && !negated);
  1925. if (!(op = string_for_opt(opts, !val_required))) {
  1926. if (val_required) return; /* string_for_opt gave feedback */
  1927. tmp = negated ? 'n' : 'f';
  1928. } else {
  1929. tmp = tolower(*op);
  1930. }
  1931. switch (tmp) {
  1932. case 'n': /* none */
  1933. case 't': /* traditional */
  1934. flags.menu_style = MENU_TRADITIONAL;
  1935. break;
  1936. case 'c': /* combo: trad.class sel+menu */
  1937. flags.menu_style = MENU_COMBINATION;
  1938. break;
  1939. case 'p': /* partial: no class menu */
  1940. flags.menu_style = MENU_PARTIAL;
  1941. break;
  1942. case 'f': /* full: class menu + menu */
  1943. flags.menu_style = MENU_FULL;
  1944. break;
  1945. default:
  1946. badoption(opts);
  1947. }
  1948. return;
  1949. }
  1950. fullname = "menu_headings";
  1951. if (match_optname(opts, fullname, 12, TRUE)) {
  1952. if (negated) {
  1953. bad_negation(fullname, FALSE);
  1954. return;
  1955. }
  1956. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  1957. return;
  1958. }
  1959. if (!strcmpi(opts,"bold"))
  1960. iflags.menu_headings = ATR_BOLD;
  1961. else if (!strcmpi(opts,"inverse"))
  1962. iflags.menu_headings = ATR_INVERSE;
  1963. else if (!strcmpi(opts,"underline"))
  1964. iflags.menu_headings = ATR_ULINE;
  1965. else
  1966. badoption(opts);
  1967. return;
  1968. }
  1969. /* check for menu command mapping */
  1970. for (i = 0; i < NUM_MENU_CMDS; i++) {
  1971. fullname = default_menu_cmd_info[i].name;
  1972. if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
  1973. if (negated)
  1974. bad_negation(fullname, FALSE);
  1975. else if ((op = string_for_opt(opts, FALSE)) != 0) {
  1976. int j;
  1977. char c, op_buf[BUFSZ];
  1978. boolean isbad = FALSE;
  1979. escapes(op, op_buf);
  1980. c = *op_buf;
  1981. if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
  1982. c == ' ' || digit(c) || (letter(c) && c != '@'))
  1983. isbad = TRUE;
  1984. else /* reject default object class symbols */
  1985. for (j = 1; j < MAXOCLASSES; j++)
  1986. if (c == def_oc_syms[i]) {
  1987. isbad = TRUE;
  1988. break;
  1989. }
  1990. if (isbad)
  1991. badoption(opts);
  1992. else
  1993. add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
  1994. }
  1995. return;
  1996. }
  1997. }
  1998. /* OK, if we still haven't recognized the option, check the boolean
  1999. * options list
  2000. */
  2001. for (i = 0; boolopt[i].name; i++) {
  2002. if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
  2003. /* options that don't exist */
  2004. if (!boolopt[i].addr) {
  2005. if (!initial && !negated)
  2006. pline_The("\"%s\" option is not available.",
  2007. boolopt[i].name);
  2008. return;
  2009. }
  2010. /* options that must come from config file */
  2011. if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
  2012. rejectoption(boolopt[i].name);
  2013. return;
  2014. }
  2015. *(boolopt[i].addr) = !negated;
  2016. duplicate_opt_detection(boolopt[i].name, 0);
  2017. #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV)
  2018. if (FALSE
  2019. # ifdef TERMLIB
  2020. || (boolopt[i].addr) == &iflags.DECgraphics
  2021. # endif
  2022. # ifdef ASCIIGRAPH
  2023. || (boolopt[i].addr) == &iflags.IBMgraphics
  2024. # endif
  2025. # ifdef MAC_GRAPHICS_ENV
  2026. || (boolopt[i].addr) == &iflags.MACgraphics
  2027. # endif
  2028. ) {
  2029. # ifdef REINCARNATION
  2030. if (!initial && Is_rogue_level(&u.uz))
  2031. assign_rogue_graphics(FALSE);
  2032. # endif
  2033. need_redraw = TRUE;
  2034. # ifdef TERMLIB
  2035. if ((boolopt[i].addr) == &iflags.DECgraphics)
  2036. switch_graphics(iflags.DECgraphics ?
  2037. DEC_GRAPHICS : ASCII_GRAPHICS);
  2038. # endif
  2039. # ifdef ASCIIGRAPH
  2040. if ((boolopt[i].addr) == &iflags.IBMgraphics)
  2041. switch_graphics(iflags.IBMgraphics ?
  2042. IBM_GRAPHICS : ASCII_GRAPHICS);
  2043. # endif
  2044. # ifdef MAC_GRAPHICS_ENV
  2045. if ((boolopt[i].addr) == &iflags.MACgraphics)
  2046. switch_graphics(iflags.MACgraphics ?
  2047. MAC_GRAPHICS : ASCII_GRAPHICS);
  2048. # endif
  2049. # ifdef REINCARNATION
  2050. if (!initial && Is_rogue_level(&u.uz))
  2051. assign_rogue_graphics(TRUE);
  2052. # endif
  2053. }
  2054. #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */
  2055. /* only do processing below if setting with doset() */
  2056. if (initial) return;
  2057. if ((boolopt[i].addr) == &flags.time
  2058. #ifdef EXP_ON_BOTL
  2059. || (boolopt[i].addr) == &flags.showexp
  2060. #endif
  2061. #ifdef SCORE_ON_BOTL
  2062. || (boolopt[i].addr) == &flags.showscore
  2063. #endif
  2064. )
  2065. flags.botl = TRUE;
  2066. else if ((boolopt[i].addr) == &flags.invlet_constant) {
  2067. if (flags.invlet_constant) reassign();
  2068. }
  2069. #ifdef LAN_MAIL
  2070. else if ((boolopt[i].addr) == &flags.biff) {
  2071. if (flags.biff) lan_mail_init();
  2072. else lan_mail_finish();
  2073. }
  2074. #endif
  2075. else if ((boolopt[i].addr) == &flags.lit_corridor) {
  2076. /*
  2077. * All corridor squares seen via night vision or
  2078. * candles & lamps change. Update them by calling
  2079. * newsym() on them. Don't do this if we are
  2080. * initializing the options --- the vision system
  2081. * isn't set up yet.
  2082. */
  2083. vision_recalc(2); /* shut down vision */
  2084. vision_full_recalc = 1; /* delayed recalc */
  2085. }
  2086. else if ((boolopt[i].addr) == &iflags.use_inverse ||
  2087. (boolopt[i].addr) == &iflags.showrace ||
  2088. (boolopt[i].addr) == &iflags.hilite_pet) {
  2089. need_redraw = TRUE;
  2090. }
  2091. #ifdef TEXTCOLOR
  2092. else if ((boolopt[i].addr) == &iflags.use_color) {
  2093. need_redraw = TRUE;
  2094. # ifdef TOS
  2095. if ((boolopt[i].addr) == &iflags.use_color
  2096. && iflags.BIOS) {
  2097. if (colors_changed)
  2098. restore_colors();
  2099. else
  2100. set_colors();
  2101. }
  2102. # endif
  2103. }
  2104. #endif
  2105. return;
  2106. }
  2107. }
  2108. /* out of valid options */
  2109. badoption(opts);
  2110. }
  2111. static NEARDATA const char *menutype[] = {
  2112. "traditional", "combination", "partial", "full"
  2113. };
  2114. static NEARDATA const char *burdentype[] = {
  2115. "unencumbered", "burdened", "stressed",
  2116. "strained", "overtaxed", "overloaded"
  2117. };
  2118. static NEARDATA const char *runmodes[] = {
  2119. "teleport", "run", "walk", "crawl"
  2120. };
  2121. /*
  2122. * Convert the given string of object classes to a string of default object
  2123. * symbols.
  2124. */
  2125. STATIC_OVL void
  2126. oc_to_str(src,dest)
  2127. char *src, *dest;
  2128. {
  2129. int i;
  2130. while ((i = (int) *src++) != 0) {
  2131. if (i < 0 || i >= MAXOCLASSES)
  2132. impossible("oc_to_str: illegal object class %d", i);
  2133. else
  2134. *dest++ = def_oc_syms[i];
  2135. }
  2136. *dest = '\0';
  2137. }
  2138. /*
  2139. * Add the given mapping to the menu command map list. Always keep the
  2140. * maps valid C strings.
  2141. */
  2142. void
  2143. add_menu_cmd_alias(from_ch, to_ch)
  2144. char from_ch, to_ch;
  2145. {
  2146. if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
  2147. pline("out of menu map space.");
  2148. else {
  2149. mapped_menu_cmds[n_menu_mapped] = from_ch;
  2150. mapped_menu_op[n_menu_mapped] = to_ch;
  2151. n_menu_mapped++;
  2152. mapped_menu_cmds[n_menu_mapped] = 0;
  2153. mapped_menu_op[n_menu_mapped] = 0;
  2154. }
  2155. }
  2156. /*
  2157. * Map the given character to its corresponding menu command. If it
  2158. * doesn't match anything, just return the original.
  2159. */
  2160. char
  2161. map_menu_cmd(ch)
  2162. char ch;
  2163. {
  2164. char *found = index(mapped_menu_cmds, ch);
  2165. if (found) {
  2166. int idx = found - mapped_menu_cmds;
  2167. ch = mapped_menu_op[idx];
  2168. }
  2169. return ch;
  2170. }
  2171. #if defined(MICRO) || defined(MAC) || defined(WIN32)
  2172. # define OPTIONS_HEADING "OPTIONS"
  2173. #else
  2174. # define OPTIONS_HEADING "NETHACKOPTIONS"
  2175. #endif
  2176. static char fmtstr_doset_add_menu[] = "%s%-15s [%s] ";
  2177. static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
  2178. STATIC_OVL void
  2179. doset_add_menu(win, option, indexoffset)
  2180. winid win; /* window to add to */
  2181. const char *option; /* option name */
  2182. int indexoffset; /* value to add to index in compopt[], or zero
  2183. if option cannot be changed */
  2184. {
  2185. const char *value = "unknown"; /* current value */
  2186. char buf[BUFSZ], buf2[BUFSZ];
  2187. anything any;
  2188. int i;
  2189. any.a_void = 0;
  2190. if (indexoffset == 0) {
  2191. any.a_int = 0;
  2192. value = get_compopt_value(option, buf2);
  2193. } else {
  2194. for (i=0; compopt[i].name; i++)
  2195. if (strcmp(option, compopt[i].name) == 0) break;
  2196. if (compopt[i].name) {
  2197. any.a_int = i + 1 + indexoffset;
  2198. value = get_compopt_value(option, buf2);
  2199. } else {
  2200. /* We are trying to add an option not found in compopt[].
  2201. This is almost certainly bad, but we'll let it through anyway
  2202. (with a zero value, so it can't be selected). */
  2203. any.a_int = 0;
  2204. }
  2205. }
  2206. /* " " replaces "a - " -- assumes menus follow that style */
  2207. if (!iflags.menu_tab_sep)
  2208. Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option, value);
  2209. else
  2210. Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
  2211. add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  2212. }
  2213. /* Changing options via menu by Per Liboriussen */
  2214. int
  2215. doset()
  2216. {
  2217. char buf[BUFSZ], buf2[BUFSZ];
  2218. int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
  2219. boolean *bool_p;
  2220. winid tmpwin;
  2221. anything any;
  2222. menu_item *pick_list;
  2223. int indexoffset, startpass, endpass;
  2224. boolean setinitial = FALSE, fromfile = FALSE;
  2225. int biggest_name = 0;
  2226. tmpwin = create_nhwindow(NHW_MENU);
  2227. start_menu(tmpwin);
  2228. any.a_void = 0;
  2229. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2230. "Booleans (selecting will toggle value):", MENU_UNSELECTED);
  2231. any.a_int = 0;
  2232. /* first list any other non-modifiable booleans, then modifiable ones */
  2233. for (pass = 0; pass <= 1; pass++)
  2234. for (i = 0; boolopt[i].name; i++)
  2235. if ((bool_p = boolopt[i].addr) != 0 &&
  2236. ((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
  2237. (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
  2238. if (bool_p == &flags.female) continue; /* obsolete */
  2239. #ifdef WIZARD
  2240. if (bool_p == &iflags.sanity_check && !wizard) continue;
  2241. if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
  2242. #endif
  2243. if (is_wc_option(boolopt[i].name) &&
  2244. !wc_supported(boolopt[i].name)) continue;
  2245. if (is_wc2_option(boolopt[i].name) &&
  2246. !wc2_supported(boolopt[i].name)) continue;
  2247. any.a_int = (pass == 0) ? 0 : i + 1;
  2248. if (!iflags.menu_tab_sep)
  2249. Sprintf(buf, "%s%-13s [%s]",
  2250. pass == 0 ? " " : "",
  2251. boolopt[i].name, *bool_p ? "true" : "false");
  2252. else
  2253. Sprintf(buf, "%s\t[%s]",
  2254. boolopt[i].name, *bool_p ? "true" : "false");
  2255. add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
  2256. ATR_NONE, buf, MENU_UNSELECTED);
  2257. }
  2258. boolcount = i;
  2259. indexoffset = boolcount;
  2260. any.a_void = 0;
  2261. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  2262. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2263. "Compounds (selecting will prompt for new value):",
  2264. MENU_UNSELECTED);
  2265. startpass = DISP_IN_GAME;
  2266. endpass = SET_IN_GAME;
  2267. /* spin through the options to find the biggest name
  2268. and adjust the format string accordingly if needed */
  2269. biggest_name = 0;
  2270. for (i = 0; compopt[i].name; i++)
  2271. if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
  2272. strlen(compopt[i].name) > (unsigned) biggest_name)
  2273. biggest_name = (int) strlen(compopt[i].name);
  2274. if (biggest_name > 30) biggest_name = 30;
  2275. if (!iflags.menu_tab_sep)
  2276. Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
  2277. /* deliberately put `name', `role', `race', `gender' first */
  2278. doset_add_menu(tmpwin, "name", 0);
  2279. doset_add_menu(tmpwin, "role", 0);
  2280. doset_add_menu(tmpwin, "race", 0);
  2281. doset_add_menu(tmpwin, "gender", 0);
  2282. for (pass = startpass; pass <= endpass; pass++)
  2283. for (i = 0; compopt[i].name; i++)
  2284. if (compopt[i].optflags == pass) {
  2285. if (!strcmp(compopt[i].name, "name") ||
  2286. !strcmp(compopt[i].name, "role") ||
  2287. !strcmp(compopt[i].name, "race") ||
  2288. !strcmp(compopt[i].name, "gender"))
  2289. continue;
  2290. else if (is_wc_option(compopt[i].name) &&
  2291. !wc_supported(compopt[i].name))
  2292. continue;
  2293. else if (is_wc2_option(compopt[i].name) &&
  2294. !wc2_supported(compopt[i].name))
  2295. continue;
  2296. else
  2297. doset_add_menu(tmpwin, compopt[i].name,
  2298. (pass == DISP_IN_GAME) ? 0 : indexoffset);
  2299. }
  2300. #ifdef AUTOPICKUP_EXCEPTIONS
  2301. any.a_int = -1;
  2302. Sprintf(buf, "autopickup exceptions (%d currently set)",
  2303. count_ape_maps((int *)0, (int *)0));
  2304. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  2305. #endif /* AUTOPICKUP_EXCEPTIONS */
  2306. #ifdef PREFIXES_IN_USE
  2307. any.a_void = 0;
  2308. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  2309. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2310. "Variable playground locations:", MENU_UNSELECTED);
  2311. for (i = 0; i < PREFIX_COUNT; i++)
  2312. doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
  2313. #endif
  2314. end_menu(tmpwin, "Set what options?");
  2315. need_redraw = FALSE;
  2316. if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
  2317. /*
  2318. * Walk down the selection list and either invert the booleans
  2319. * or prompt for new values. In most cases, call parseoptions()
  2320. * to take care of options that require special attention, like
  2321. * redraws.
  2322. */
  2323. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  2324. opt_indx = pick_list[pick_idx].item.a_int - 1;
  2325. #ifdef AUTOPICKUP_EXCEPTIONS
  2326. if (opt_indx == -2) {
  2327. special_handling("autopickup_exception",
  2328. setinitial, fromfile);
  2329. } else
  2330. #endif
  2331. if (opt_indx < boolcount) {
  2332. /* boolean option */
  2333. Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
  2334. boolopt[opt_indx].name);
  2335. parseoptions(buf, setinitial, fromfile);
  2336. if (wc_supported(boolopt[opt_indx].name) ||
  2337. wc2_supported(boolopt[opt_indx].name))
  2338. preference_update(boolopt[opt_indx].name);
  2339. } else {
  2340. /* compound option */
  2341. opt_indx -= boolcount;
  2342. if (!special_handling(compopt[opt_indx].name,
  2343. setinitial, fromfile)) {
  2344. Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
  2345. getlin(buf, buf2);
  2346. if (buf2[0] == '\033')
  2347. continue;
  2348. Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
  2349. /* pass the buck */
  2350. parseoptions(buf, setinitial, fromfile);
  2351. }
  2352. if (wc_supported(compopt[opt_indx].name) ||
  2353. wc2_supported(compopt[opt_indx].name))
  2354. preference_update(compopt[opt_indx].name);
  2355. }
  2356. }
  2357. free((genericptr_t)pick_list);
  2358. pick_list = (menu_item *)0;
  2359. }
  2360. destroy_nhwindow(tmpwin);
  2361. if (need_redraw)
  2362. (void) doredraw();
  2363. return 0;
  2364. }
  2365. STATIC_OVL boolean
  2366. special_handling(optname, setinitial, setfromfile)
  2367. const char *optname;
  2368. boolean setinitial,setfromfile;
  2369. {
  2370. winid tmpwin;
  2371. anything any;
  2372. int i;
  2373. char buf[BUFSZ];
  2374. boolean retval = FALSE;
  2375. /* Special handling of menustyle, pickup_burden, pickup_types,
  2376. * disclose, runmode, msg_window, menu_headings, and number_pad options.
  2377. #ifdef AUTOPICKUP_EXCEPTIONS
  2378. * Also takes care of interactive autopickup_exception_handling changes.
  2379. #endif
  2380. */
  2381. if (!strcmp("menustyle", optname)) {
  2382. const char *style_name;
  2383. menu_item *style_pick = (menu_item *)0;
  2384. tmpwin = create_nhwindow(NHW_MENU);
  2385. start_menu(tmpwin);
  2386. for (i = 0; i < SIZE(menutype); i++) {
  2387. style_name = menutype[i];
  2388. /* note: separate `style_name' variable used
  2389. to avoid an optimizer bug in VAX C V2.3 */
  2390. any.a_int = i + 1;
  2391. add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
  2392. ATR_NONE, style_name, MENU_UNSELECTED);
  2393. }
  2394. end_menu(tmpwin, "Select menustyle:");
  2395. if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
  2396. flags.menu_style = style_pick->item.a_int - 1;
  2397. free((genericptr_t)style_pick);
  2398. }
  2399. destroy_nhwindow(tmpwin);
  2400. retval = TRUE;
  2401. } else if (!strcmp("pickup_burden", optname)) {
  2402. const char *burden_name, *burden_letters = "ubsntl";
  2403. menu_item *burden_pick = (menu_item *)0;
  2404. tmpwin = create_nhwindow(NHW_MENU);
  2405. start_menu(tmpwin);
  2406. for (i = 0; i < SIZE(burdentype); i++) {
  2407. burden_name = burdentype[i];
  2408. any.a_int = i + 1;
  2409. add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
  2410. ATR_NONE, burden_name, MENU_UNSELECTED);
  2411. }
  2412. end_menu(tmpwin, "Select encumbrance level:");
  2413. if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
  2414. flags.pickup_burden = burden_pick->item.a_int - 1;
  2415. free((genericptr_t)burden_pick);
  2416. }
  2417. destroy_nhwindow(tmpwin);
  2418. retval = TRUE;
  2419. } else if (!strcmp("pickup_types", optname)) {
  2420. /* parseoptions will prompt for the list of types */
  2421. parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
  2422. retval = TRUE;
  2423. } else if (!strcmp("disclose", optname)) {
  2424. int pick_cnt, pick_idx, opt_idx;
  2425. menu_item *disclosure_category_pick = (menu_item *)0;
  2426. /*
  2427. * The order of disclose_names[]
  2428. * must correspond to disclosure_options in decl.h
  2429. */
  2430. static const char *disclosure_names[] = {
  2431. "inventory", "attributes", "vanquished", "genocides", "conduct"
  2432. };
  2433. int disc_cat[NUM_DISCLOSURE_OPTIONS];
  2434. const char *disclosure_name;
  2435. tmpwin = create_nhwindow(NHW_MENU);
  2436. start_menu(tmpwin);
  2437. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  2438. disclosure_name = disclosure_names[i];
  2439. any.a_int = i + 1;
  2440. add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
  2441. ATR_NONE, disclosure_name, MENU_UNSELECTED);
  2442. disc_cat[i] = 0;
  2443. }
  2444. end_menu(tmpwin, "Change which disclosure options categories:");
  2445. if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
  2446. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  2447. opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
  2448. disc_cat[opt_idx] = 1;
  2449. }
  2450. free((genericptr_t)disclosure_category_pick);
  2451. disclosure_category_pick = (menu_item *)0;
  2452. }
  2453. destroy_nhwindow(tmpwin);
  2454. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  2455. if (disc_cat[i]) {
  2456. char dbuf[BUFSZ];
  2457. menu_item *disclosure_option_pick = (menu_item *)0;
  2458. Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
  2459. tmpwin = create_nhwindow(NHW_MENU);
  2460. start_menu(tmpwin);
  2461. any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
  2462. add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
  2463. ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
  2464. any.a_void = 0;
  2465. any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
  2466. add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
  2467. ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
  2468. any.a_void = 0;
  2469. any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
  2470. add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
  2471. ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
  2472. any.a_void = 0;
  2473. any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
  2474. add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
  2475. ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
  2476. end_menu(tmpwin, dbuf);
  2477. if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
  2478. flags.end_disclose[i] = disclosure_option_pick->item.a_char;
  2479. free((genericptr_t)disclosure_option_pick);
  2480. }
  2481. destroy_nhwindow(tmpwin);
  2482. }
  2483. }
  2484. retval = TRUE;
  2485. } else if (!strcmp("runmode", optname)) {
  2486. const char *mode_name;
  2487. menu_item *mode_pick = (menu_item *)0;
  2488. tmpwin = create_nhwindow(NHW_MENU);
  2489. start_menu(tmpwin);
  2490. for (i = 0; i < SIZE(runmodes); i++) {
  2491. mode_name = runmodes[i];
  2492. any.a_int = i + 1;
  2493. add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
  2494. ATR_NONE, mode_name, MENU_UNSELECTED);
  2495. }
  2496. end_menu(tmpwin, "Select run/travel display mode:");
  2497. if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  2498. iflags.runmode = mode_pick->item.a_int - 1;
  2499. free((genericptr_t)mode_pick);
  2500. }
  2501. destroy_nhwindow(tmpwin);
  2502. retval = TRUE;
  2503. }
  2504. #ifdef TTY_GRAPHICS
  2505. else if (!strcmp("msg_window", optname)) {
  2506. /* by Christian W. Cooper */
  2507. menu_item *window_pick = (menu_item *)0;
  2508. tmpwin = create_nhwindow(NHW_MENU);
  2509. start_menu(tmpwin);
  2510. any.a_char = 's';
  2511. add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
  2512. ATR_NONE, "single", MENU_UNSELECTED);
  2513. any.a_char = 'c';
  2514. add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
  2515. ATR_NONE, "combination", MENU_UNSELECTED);
  2516. any.a_char = 'f';
  2517. add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
  2518. ATR_NONE, "full", MENU_UNSELECTED);
  2519. any.a_char = 'r';
  2520. add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
  2521. ATR_NONE, "reversed", MENU_UNSELECTED);
  2522. end_menu(tmpwin, "Select message history display type:");
  2523. if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
  2524. iflags.prevmsg_window = window_pick->item.a_char;
  2525. free((genericptr_t)window_pick);
  2526. }
  2527. destroy_nhwindow(tmpwin);
  2528. retval = TRUE;
  2529. }
  2530. #endif
  2531. else if (!strcmp("align_message", optname) ||
  2532. !strcmp("align_status", optname)) {
  2533. menu_item *window_pick = (menu_item *)0;
  2534. char abuf[BUFSZ];
  2535. boolean msg = (*(optname+6) == 'm');
  2536. tmpwin = create_nhwindow(NHW_MENU);
  2537. start_menu(tmpwin);
  2538. any.a_int = ALIGN_TOP;
  2539. add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
  2540. ATR_NONE, "top", MENU_UNSELECTED);
  2541. any.a_int = ALIGN_BOTTOM;
  2542. add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
  2543. ATR_NONE, "bottom", MENU_UNSELECTED);
  2544. any.a_int = ALIGN_LEFT;
  2545. add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
  2546. ATR_NONE, "left", MENU_UNSELECTED);
  2547. any.a_int = ALIGN_RIGHT;
  2548. add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
  2549. ATR_NONE, "right", MENU_UNSELECTED);
  2550. Sprintf(abuf, "Select %s window placement relative to the map:",
  2551. msg ? "message" : "status");
  2552. end_menu(tmpwin, abuf);
  2553. if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
  2554. if (msg) iflags.wc_align_message = window_pick->item.a_int;
  2555. else iflags.wc_align_status = window_pick->item.a_int;
  2556. free((genericptr_t)window_pick);
  2557. }
  2558. destroy_nhwindow(tmpwin);
  2559. retval = TRUE;
  2560. } else if (!strcmp("number_pad", optname)) {
  2561. static const char *npchoices[3] =
  2562. {"0 (off)", "1 (on)", "2 (on, DOS compatible)"};
  2563. const char *npletters = "abc";
  2564. menu_item *mode_pick = (menu_item *)0;
  2565. tmpwin = create_nhwindow(NHW_MENU);
  2566. start_menu(tmpwin);
  2567. for (i = 0; i < SIZE(npchoices); i++) {
  2568. any.a_int = i + 1;
  2569. add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
  2570. ATR_NONE, npchoices[i], MENU_UNSELECTED);
  2571. }
  2572. end_menu(tmpwin, "Select number_pad mode:");
  2573. if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  2574. int mode = mode_pick->item.a_int - 1;
  2575. switch(mode) {
  2576. case 2:
  2577. iflags.num_pad = 1;
  2578. iflags.num_pad_mode = 1;
  2579. break;
  2580. case 1:
  2581. iflags.num_pad = 1;
  2582. iflags.num_pad_mode = 0;
  2583. break;
  2584. case 0:
  2585. default:
  2586. iflags.num_pad = 0;
  2587. iflags.num_pad_mode = 0;
  2588. }
  2589. free((genericptr_t)mode_pick);
  2590. }
  2591. destroy_nhwindow(tmpwin);
  2592. retval = TRUE;
  2593. } else if (!strcmp("menu_headings", optname)) {
  2594. static const char *mhchoices[3] = {"bold", "inverse", "underline"};
  2595. const char *npletters = "biu";
  2596. menu_item *mode_pick = (menu_item *)0;
  2597. tmpwin = create_nhwindow(NHW_MENU);
  2598. start_menu(tmpwin);
  2599. for (i = 0; i < SIZE(mhchoices); i++) {
  2600. any.a_int = i + 1;
  2601. add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
  2602. ATR_NONE, mhchoices[i], MENU_UNSELECTED);
  2603. }
  2604. end_menu(tmpwin, "How to highlight menu headings:");
  2605. if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  2606. int mode = mode_pick->item.a_int - 1;
  2607. switch(mode) {
  2608. case 2:
  2609. iflags.menu_headings = ATR_ULINE;
  2610. break;
  2611. case 0:
  2612. iflags.menu_headings = ATR_BOLD;
  2613. break;
  2614. case 1:
  2615. default:
  2616. iflags.menu_headings = ATR_INVERSE;
  2617. }
  2618. free((genericptr_t)mode_pick);
  2619. }
  2620. destroy_nhwindow(tmpwin);
  2621. retval = TRUE;
  2622. #ifdef AUTOPICKUP_EXCEPTIONS
  2623. } else if (!strcmp("autopickup_exception", optname)) {
  2624. boolean retval;
  2625. int pick_cnt, pick_idx, opt_idx, pass;
  2626. int totalapes = 0, numapes[2] = {0,0};
  2627. menu_item *pick_list = (menu_item *)0;
  2628. anything any;
  2629. char apebuf[BUFSZ];
  2630. struct autopickup_exception *ape;
  2631. static const char *action_titles[] = {
  2632. "a", "add new autopickup exception",
  2633. "l", "list autopickup exceptions",
  2634. "r", "remove existing autopickup exception",
  2635. "e", "exit this menu",
  2636. };
  2637. ape_again:
  2638. opt_idx = 0;
  2639. totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
  2640. tmpwin = create_nhwindow(NHW_MENU);
  2641. start_menu(tmpwin);
  2642. any.a_int = 0;
  2643. for (i = 0; i < SIZE(action_titles) ; i += 2) {
  2644. any.a_int++;
  2645. if (!totalapes && (i >= 2 && i < 6)) continue;
  2646. add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
  2647. 0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
  2648. }
  2649. end_menu(tmpwin, "Do what?");
  2650. if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
  2651. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  2652. opt_idx = pick_list[pick_idx].item.a_int - 1;
  2653. }
  2654. free((genericptr_t)pick_list);
  2655. pick_list = (menu_item *)0;
  2656. }
  2657. destroy_nhwindow(tmpwin);
  2658. if (pick_cnt < 1) return FALSE;
  2659. if (opt_idx == 0) { /* add new */
  2660. getlin("What new autopickup exception pattern?", &apebuf[1]);
  2661. if (apebuf[1] == '\033') return FALSE;
  2662. apebuf[0] = '"';
  2663. Strcat(apebuf,"\"");
  2664. add_autopickup_exception(apebuf);
  2665. goto ape_again;
  2666. } else if (opt_idx == 3) {
  2667. retval = TRUE;
  2668. } else { /* remove */
  2669. tmpwin = create_nhwindow(NHW_MENU);
  2670. start_menu(tmpwin);
  2671. for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
  2672. if (numapes[pass] == 0) continue;
  2673. ape = iflags.autopickup_exceptions[pass];
  2674. any.a_void = 0;
  2675. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2676. (pass == 0) ? "Never pickup" : "Always pickup",
  2677. MENU_UNSELECTED);
  2678. for (i = 0; i < numapes[pass] && ape; i++) {
  2679. any.a_void = (opt_idx == 1) ? 0 : ape;
  2680. Sprintf(apebuf, "\"%s\"", ape->pattern);
  2681. add_menu(tmpwin, NO_GLYPH, &any,
  2682. 0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
  2683. ape = ape->next;
  2684. }
  2685. }
  2686. Sprintf(apebuf, "%s autopickup exceptions",
  2687. (opt_idx == 1) ? "List of" : "Remove which");
  2688. end_menu(tmpwin, apebuf);
  2689. pick_cnt = select_menu(tmpwin,
  2690. (opt_idx == 1) ? PICK_NONE : PICK_ANY,
  2691. &pick_list);
  2692. if (pick_cnt > 0) {
  2693. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
  2694. remove_autopickup_exception(
  2695. (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
  2696. }
  2697. free((genericptr_t)pick_list);
  2698. pick_list = (menu_item *)0;
  2699. destroy_nhwindow(tmpwin);
  2700. goto ape_again;
  2701. }
  2702. retval = TRUE;
  2703. #endif /* AUTOPICKUP_EXCEPTIONS */
  2704. }
  2705. return retval;
  2706. }
  2707. #define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
  2708. (val == ROLE_RANDOM) ? randomrole : none)
  2709. /* This is ugly. We have all the option names in the compopt[] array,
  2710. but we need to look at each option individually to get the value. */
  2711. STATIC_OVL const char *
  2712. get_compopt_value(optname, buf)
  2713. const char *optname;
  2714. char *buf;
  2715. {
  2716. char ocl[MAXOCLASSES+1];
  2717. static const char none[] = "(none)", randomrole[] = "random",
  2718. to_be_done[] = "(to be done)",
  2719. defopt[] = "default",
  2720. defbrief[] = "def";
  2721. int i;
  2722. buf[0] = '\0';
  2723. if (!strcmp(optname,"align_message"))
  2724. Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP ? "top" :
  2725. iflags.wc_align_message == ALIGN_LEFT ? "left" :
  2726. iflags.wc_align_message == ALIGN_BOTTOM ? "bottom" :
  2727. iflags.wc_align_message == ALIGN_RIGHT ? "right" :
  2728. defopt);
  2729. else if (!strcmp(optname,"align_status"))
  2730. Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP ? "top" :
  2731. iflags.wc_align_status == ALIGN_LEFT ? "left" :
  2732. iflags.wc_align_status == ALIGN_BOTTOM ? "bottom" :
  2733. iflags.wc_align_status == ALIGN_RIGHT ? "right" :
  2734. defopt);
  2735. else if (!strcmp(optname,"align"))
  2736. Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
  2737. #ifdef WIN32CON
  2738. else if (!strcmp(optname,"altkeyhandler"))
  2739. Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
  2740. iflags.altkeyhandler : "default");
  2741. #endif
  2742. else if (!strcmp(optname, "boulder"))
  2743. Sprintf(buf, "%c", iflags.bouldersym ?
  2744. iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]);
  2745. else if (!strcmp(optname, "catname"))
  2746. Sprintf(buf, "%s", catname[0] ? catname : none );
  2747. else if (!strcmp(optname, "disclose")) {
  2748. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  2749. char topt[2];
  2750. if (i) Strcat(buf," ");
  2751. topt[1] = '\0';
  2752. topt[0] = flags.end_disclose[i];
  2753. Strcat(buf, topt);
  2754. topt[0] = disclosure_options[i];
  2755. Strcat(buf, topt);
  2756. }
  2757. }
  2758. else if (!strcmp(optname, "dogname"))
  2759. Sprintf(buf, "%s", dogname[0] ? dogname : none );
  2760. else if (!strcmp(optname, "dungeon"))
  2761. Sprintf(buf, "%s", to_be_done);
  2762. else if (!strcmp(optname, "effects"))
  2763. Sprintf(buf, "%s", to_be_done);
  2764. else if (!strcmp(optname, "font_map"))
  2765. Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
  2766. else if (!strcmp(optname, "font_message"))
  2767. Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
  2768. else if (!strcmp(optname, "font_status"))
  2769. Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
  2770. else if (!strcmp(optname, "font_menu"))
  2771. Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
  2772. else if (!strcmp(optname, "font_text"))
  2773. Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
  2774. else if (!strcmp(optname, "font_size_map")) {
  2775. if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
  2776. else Strcpy(buf, defopt);
  2777. }
  2778. else if (!strcmp(optname, "font_size_message")) {
  2779. if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
  2780. iflags.wc_fontsiz_message);
  2781. else Strcpy(buf, defopt);
  2782. }
  2783. else if (!strcmp(optname, "font_size_status")) {
  2784. if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
  2785. else Strcpy(buf, defopt);
  2786. }
  2787. else if (!strcmp(optname, "font_size_menu")) {
  2788. if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
  2789. else Strcpy(buf, defopt);
  2790. }
  2791. else if (!strcmp(optname, "font_size_text")) {
  2792. if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
  2793. else Strcpy(buf, defopt);
  2794. }
  2795. else if (!strcmp(optname, "fruit"))
  2796. Sprintf(buf, "%s", pl_fruit);
  2797. else if (!strcmp(optname, "gender"))
  2798. Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
  2799. else if (!strcmp(optname, "horsename"))
  2800. Sprintf(buf, "%s", horsename[0] ? horsename : none);
  2801. else if (!strcmp(optname, "map_mode"))
  2802. Sprintf(buf, "%s",
  2803. iflags.wc_map_mode == MAP_MODE_TILES ? "tiles" :
  2804. iflags.wc_map_mode == MAP_MODE_ASCII4x6 ? "ascii4x6" :
  2805. iflags.wc_map_mode == MAP_MODE_ASCII6x8 ? "ascii6x8" :
  2806. iflags.wc_map_mode == MAP_MODE_ASCII8x8 ? "ascii8x8" :
  2807. iflags.wc_map_mode == MAP_MODE_ASCII16x8 ? "ascii16x8" :
  2808. iflags.wc_map_mode == MAP_MODE_ASCII7x12 ? "ascii7x12" :
  2809. iflags.wc_map_mode == MAP_MODE_ASCII8x12 ? "ascii8x12" :
  2810. iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
  2811. iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
  2812. iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
  2813. iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
  2814. "fit_to_screen" : defopt);
  2815. else if (!strcmp(optname, "menustyle"))
  2816. Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
  2817. else if (!strcmp(optname, "menu_deselect_all"))
  2818. Sprintf(buf, "%s", to_be_done);
  2819. else if (!strcmp(optname, "menu_deselect_page"))
  2820. Sprintf(buf, "%s", to_be_done);
  2821. else if (!strcmp(optname, "menu_first_page"))
  2822. Sprintf(buf, "%s", to_be_done);
  2823. else if (!strcmp(optname, "menu_invert_all"))
  2824. Sprintf(buf, "%s", to_be_done);
  2825. else if (!strcmp(optname, "menu_headings")) {
  2826. Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
  2827. "bold" : (iflags.menu_headings == ATR_INVERSE) ?
  2828. "inverse" : (iflags.menu_headings == ATR_ULINE) ?
  2829. "underline" : "unknown");
  2830. }
  2831. else if (!strcmp(optname, "menu_invert_page"))
  2832. Sprintf(buf, "%s", to_be_done);
  2833. else if (!strcmp(optname, "menu_last_page"))
  2834. Sprintf(buf, "%s", to_be_done);
  2835. else if (!strcmp(optname, "menu_next_page"))
  2836. Sprintf(buf, "%s", to_be_done);
  2837. else if (!strcmp(optname, "menu_previous_page"))
  2838. Sprintf(buf, "%s", to_be_done);
  2839. else if (!strcmp(optname, "menu_search"))
  2840. Sprintf(buf, "%s", to_be_done);
  2841. else if (!strcmp(optname, "menu_select_all"))
  2842. Sprintf(buf, "%s", to_be_done);
  2843. else if (!strcmp(optname, "menu_select_page"))
  2844. Sprintf(buf, "%s", to_be_done);
  2845. else if (!strcmp(optname, "monsters"))
  2846. Sprintf(buf, "%s", to_be_done);
  2847. else if (!strcmp(optname, "msghistory"))
  2848. Sprintf(buf, "%u", iflags.msg_history);
  2849. #ifdef TTY_GRAPHICS
  2850. else if (!strcmp(optname, "msg_window"))
  2851. Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
  2852. (iflags.prevmsg_window=='c') ? "combination" :
  2853. (iflags.prevmsg_window=='f') ? "full" : "reversed");
  2854. #endif
  2855. else if (!strcmp(optname, "name"))
  2856. Sprintf(buf, "%s", plname);
  2857. else if (!strcmp(optname, "number_pad"))
  2858. Sprintf(buf, "%s",
  2859. (!iflags.num_pad) ? "0=off" :
  2860. (iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on");
  2861. else if (!strcmp(optname, "objects"))
  2862. Sprintf(buf, "%s", to_be_done);
  2863. else if (!strcmp(optname, "packorder")) {
  2864. oc_to_str(flags.inv_order, ocl);
  2865. Sprintf(buf, "%s", ocl);
  2866. }
  2867. #ifdef CHANGE_COLOR
  2868. else if (!strcmp(optname, "palette"))
  2869. Sprintf(buf, "%s", get_color_string());
  2870. #endif
  2871. else if (!strcmp(optname, "pettype"))
  2872. Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
  2873. (preferred_pet == 'd') ? "dog" :
  2874. (preferred_pet == 'n') ? "none" : "random");
  2875. else if (!strcmp(optname, "pickup_burden"))
  2876. Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
  2877. else if (!strcmp(optname, "pickup_types")) {
  2878. oc_to_str(flags.pickup_types, ocl);
  2879. Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
  2880. }
  2881. else if (!strcmp(optname, "race"))
  2882. Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
  2883. else if (!strcmp(optname, "role"))
  2884. Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
  2885. else if (!strcmp(optname, "runmode"))
  2886. Sprintf(buf, "%s", runmodes[iflags.runmode]);
  2887. else if (!strcmp(optname, "scores")) {
  2888. Sprintf(buf, "%d top/%d around%s", flags.end_top,
  2889. flags.end_around, flags.end_own ? "/own" : "");
  2890. }
  2891. else if (!strcmp(optname, "scroll_amount")) {
  2892. if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
  2893. else Strcpy(buf, defopt);
  2894. }
  2895. else if (!strcmp(optname, "scroll_margin")) {
  2896. if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
  2897. else Strcpy(buf, defopt);
  2898. }
  2899. else if (!strcmp(optname, "player_selection"))
  2900. Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
  2901. #ifdef MSDOS
  2902. else if (!strcmp(optname, "soundcard"))
  2903. Sprintf(buf, "%s", to_be_done);
  2904. #endif
  2905. else if (!strcmp(optname, "suppress_alert")) {
  2906. if (flags.suppress_alert == 0L)
  2907. Strcpy(buf, none);
  2908. else
  2909. Sprintf(buf, "%lu.%lu.%lu",
  2910. FEATURE_NOTICE_VER_MAJ,
  2911. FEATURE_NOTICE_VER_MIN,
  2912. FEATURE_NOTICE_VER_PATCH);
  2913. }
  2914. else if (!strcmp(optname, "tile_file"))
  2915. Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
  2916. else if (!strcmp(optname, "tile_height")) {
  2917. if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
  2918. else Strcpy(buf, defopt);
  2919. }
  2920. else if (!strcmp(optname, "tile_width")) {
  2921. if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
  2922. else Strcpy(buf, defopt);
  2923. }
  2924. else if (!strcmp(optname, "traps"))
  2925. Sprintf(buf, "%s", to_be_done);
  2926. else if (!strcmp(optname, "vary_msgcount")) {
  2927. if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
  2928. else Strcpy(buf, defopt);
  2929. }
  2930. #ifdef MSDOS
  2931. else if (!strcmp(optname, "video"))
  2932. Sprintf(buf, "%s", to_be_done);
  2933. #endif
  2934. #ifdef VIDEOSHADES
  2935. else if (!strcmp(optname, "videoshades"))
  2936. Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
  2937. else if (!strcmp(optname, "videocolors"))
  2938. Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
  2939. ttycolors[CLR_RED], ttycolors[CLR_GREEN],
  2940. ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
  2941. ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
  2942. ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
  2943. ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
  2944. ttycolors[CLR_BRIGHT_MAGENTA],
  2945. ttycolors[CLR_BRIGHT_CYAN]);
  2946. #endif /* VIDEOSHADES */
  2947. else if (!strcmp(optname, "windowtype"))
  2948. Sprintf(buf, "%s", windowprocs.name);
  2949. else if (!strcmp(optname, "windowcolors"))
  2950. Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
  2951. iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
  2952. iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
  2953. iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
  2954. iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
  2955. iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
  2956. iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
  2957. iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
  2958. iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
  2959. #ifdef PREFIXES_IN_USE
  2960. else {
  2961. for (i = 0; i < PREFIX_COUNT; ++i)
  2962. if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
  2963. Sprintf(buf, "%s", fqn_prefix[i]);
  2964. }
  2965. #endif
  2966. if (buf[0]) return buf;
  2967. else return "unknown";
  2968. }
  2969. int
  2970. dotogglepickup()
  2971. {
  2972. char buf[BUFSZ], ocl[MAXOCLASSES+1];
  2973. flags.pickup = !flags.pickup;
  2974. if (flags.pickup) {
  2975. oc_to_str(flags.pickup_types, ocl);
  2976. Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
  2977. #ifdef AUTOPICKUP_EXCEPTIONS
  2978. (iflags.autopickup_exceptions[AP_LEAVE] ||
  2979. iflags.autopickup_exceptions[AP_GRAB]) ?
  2980. ((count_ape_maps((int *)0, (int *)0) == 1) ?
  2981. ", with one exception" : ", with some exceptions") :
  2982. #endif
  2983. "");
  2984. } else {
  2985. Strcpy(buf, "OFF");
  2986. }
  2987. pline("Autopickup: %s.", buf);
  2988. return 0;
  2989. }
  2990. #ifdef AUTOPICKUP_EXCEPTIONS
  2991. int
  2992. add_autopickup_exception(mapping)
  2993. const char *mapping;
  2994. {
  2995. struct autopickup_exception *ape, **apehead;
  2996. char text[256], *text2;
  2997. int textsize = 0;
  2998. boolean grab = FALSE;
  2999. if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
  3000. text2 = &text[0];
  3001. if (*text2 == '<') { /* force autopickup */
  3002. grab = TRUE;
  3003. ++text2;
  3004. } else if (*text2 == '>') { /* default - Do not pickup */
  3005. grab = FALSE;
  3006. ++text2;
  3007. }
  3008. textsize = strlen(text2);
  3009. apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
  3010. &iflags.autopickup_exceptions[AP_LEAVE];
  3011. ape = (struct autopickup_exception *)
  3012. alloc(sizeof(struct autopickup_exception));
  3013. ape->pattern = (char *) alloc(textsize+1);
  3014. Strcpy(ape->pattern, text2);
  3015. ape->grab = grab;
  3016. if (!*apehead) ape->next = (struct autopickup_exception *)0;
  3017. else ape->next = *apehead;
  3018. *apehead = ape;
  3019. } else {
  3020. raw_print("syntax error in AUTOPICKUP_EXCEPTION");
  3021. return 0;
  3022. }
  3023. return 1;
  3024. }
  3025. STATIC_OVL void
  3026. remove_autopickup_exception(whichape)
  3027. struct autopickup_exception *whichape;
  3028. {
  3029. struct autopickup_exception *ape, *prev = 0;
  3030. int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
  3031. for (ape = iflags.autopickup_exceptions[chain]; ape;) {
  3032. if (ape == whichape) {
  3033. struct autopickup_exception *freeape = ape;
  3034. ape = ape->next;
  3035. if (prev) prev->next = ape;
  3036. else iflags.autopickup_exceptions[chain] = ape;
  3037. free(freeape->pattern);
  3038. free(freeape);
  3039. } else {
  3040. prev = ape;
  3041. ape = ape->next;
  3042. }
  3043. }
  3044. }
  3045. STATIC_OVL int
  3046. count_ape_maps(leave, grab)
  3047. int *leave, *grab;
  3048. {
  3049. struct autopickup_exception *ape;
  3050. int pass, totalapes, numapes[2] = {0,0};
  3051. for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
  3052. ape = iflags.autopickup_exceptions[pass];
  3053. while(ape) {
  3054. ape = ape->next;
  3055. numapes[pass]++;
  3056. }
  3057. }
  3058. totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
  3059. if (leave) *leave = numapes[AP_LEAVE];
  3060. if (grab) *grab = numapes[AP_GRAB];
  3061. return totalapes;
  3062. }
  3063. void
  3064. free_autopickup_exceptions()
  3065. {
  3066. struct autopickup_exception *ape;
  3067. int pass;
  3068. for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
  3069. while((ape = iflags.autopickup_exceptions[pass]) != 0) {
  3070. free(ape->pattern);
  3071. iflags.autopickup_exceptions[pass] = ape->next;
  3072. free(ape);
  3073. }
  3074. }
  3075. }
  3076. #endif /* AUTOPICKUP_EXCEPTIONS */
  3077. /* data for option_help() */
  3078. static const char *opt_intro[] = {
  3079. "",
  3080. " NetHack Options Help:",
  3081. "",
  3082. #define CONFIG_SLOT 3 /* fill in next value at run-time */
  3083. (char *)0,
  3084. #if !defined(MICRO) && !defined(MAC)
  3085. "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
  3086. #endif
  3087. "(<options> is a list of options separated by commas)",
  3088. #ifdef VMS
  3089. "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
  3090. #endif
  3091. "or press \"O\" while playing and use the menu.",
  3092. "",
  3093. "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
  3094. (char *)0
  3095. };
  3096. static const char *opt_epilog[] = {
  3097. "",
  3098. "Some of the options can be set only before the game is started; those",
  3099. "items will not be selectable in the 'O' command's menu.",
  3100. (char *)0
  3101. };
  3102. void
  3103. option_help()
  3104. {
  3105. char buf[BUFSZ], buf2[BUFSZ];
  3106. register int i;
  3107. winid datawin;
  3108. datawin = create_nhwindow(NHW_TEXT);
  3109. Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
  3110. opt_intro[CONFIG_SLOT] = (const char *) buf;
  3111. for (i = 0; opt_intro[i]; i++)
  3112. putstr(datawin, 0, opt_intro[i]);
  3113. /* Boolean options */
  3114. for (i = 0; boolopt[i].name; i++) {
  3115. if (boolopt[i].addr) {
  3116. #ifdef WIZARD
  3117. if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
  3118. if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
  3119. #endif
  3120. next_opt(datawin, boolopt[i].name);
  3121. }
  3122. }
  3123. next_opt(datawin, "");
  3124. /* Compound options */
  3125. putstr(datawin, 0, "Compound options:");
  3126. for (i = 0; compopt[i].name; i++) {
  3127. Sprintf(buf2, "`%s'", compopt[i].name);
  3128. Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
  3129. compopt[i+1].name ? ',' : '.');
  3130. putstr(datawin, 0, buf);
  3131. }
  3132. for (i = 0; opt_epilog[i]; i++)
  3133. putstr(datawin, 0, opt_epilog[i]);
  3134. display_nhwindow(datawin, FALSE);
  3135. destroy_nhwindow(datawin);
  3136. return;
  3137. }
  3138. /*
  3139. * prints the next boolean option, on the same line if possible, on a new
  3140. * line if not. End with next_opt("").
  3141. */
  3142. void
  3143. next_opt(datawin, str)
  3144. winid datawin;
  3145. const char *str;
  3146. {
  3147. static char *buf = 0;
  3148. int i;
  3149. char *s;
  3150. if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';
  3151. if (!*str) {
  3152. s = eos(buf);
  3153. if (s > &buf[1] && s[-2] == ',')
  3154. Strcpy(s - 2, "."); /* replace last ", " */
  3155. i = COLNO; /* (greater than COLNO - 2) */
  3156. } else {
  3157. i = strlen(buf) + strlen(str) + 2;
  3158. }
  3159. if (i > COLNO - 2) { /* rule of thumb */
  3160. putstr(datawin, 0, buf);
  3161. buf[0] = 0;
  3162. }
  3163. if (*str) {
  3164. Strcat(buf, str);
  3165. Strcat(buf, ", ");
  3166. } else {
  3167. putstr(datawin, 0, str);
  3168. free(buf), buf = 0;
  3169. }
  3170. return;
  3171. }
  3172. /* Returns the fid of the fruit type; if that type already exists, it
  3173. * returns the fid of that one; if it does not exist, it adds a new fruit
  3174. * type to the chain and returns the new one.
  3175. */
  3176. int
  3177. fruitadd(str)
  3178. char *str;
  3179. {
  3180. register int i;
  3181. register struct fruit *f;
  3182. struct fruit *lastf = 0;
  3183. int highest_fruit_id = 0;
  3184. char buf[PL_FSIZ];
  3185. boolean user_specified = (str == pl_fruit);
  3186. /* if not user-specified, then it's a fruit name for a fruit on
  3187. * a bones level...
  3188. */
  3189. /* Note: every fruit has an id (spe for fruit objects) of at least
  3190. * 1; 0 is an error.
  3191. */
  3192. if (user_specified) {
  3193. /* disallow naming after other foods (since it'd be impossible
  3194. * to tell the difference)
  3195. */
  3196. boolean found = FALSE, numeric = FALSE;
  3197. for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
  3198. i++) {
  3199. if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
  3200. found = TRUE;
  3201. break;
  3202. }
  3203. }
  3204. {
  3205. char *c;
  3206. c = pl_fruit;
  3207. for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
  3208. ;
  3209. if (isspace(*c) || *c == 0) numeric = TRUE;
  3210. }
  3211. if (found || numeric ||
  3212. !strncmp(str, "cursed ", 7) ||
  3213. !strncmp(str, "uncursed ", 9) ||
  3214. !strncmp(str, "blessed ", 8) ||
  3215. !strncmp(str, "partly eaten ", 13) ||
  3216. (!strncmp(str, "tin of ", 7) &&
  3217. (!strcmp(str+7, "spinach") ||
  3218. name_to_mon(str+7) >= LOW_PM)) ||
  3219. !strcmp(str, "empty tin") ||
  3220. ((!strncmp(eos(str)-7," corpse",7) ||
  3221. !strncmp(eos(str)-4, " egg",4)) &&
  3222. name_to_mon(str) >= LOW_PM))
  3223. {
  3224. Strcpy(buf, pl_fruit);
  3225. Strcpy(pl_fruit, "candied ");
  3226. nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
  3227. }
  3228. }
  3229. for(f=ffruit; f; f = f->nextf) {
  3230. lastf = f;
  3231. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
  3232. if(!strncmp(str, f->fname, PL_FSIZ))
  3233. goto nonew;
  3234. }
  3235. /* if adding another fruit would overflow spe, use a random
  3236. fruit instead... we've got a lot to choose from. */
  3237. if (highest_fruit_id >= 127) return rnd(127);
  3238. highest_fruit_id++;
  3239. f = newfruit();
  3240. if (ffruit) lastf->nextf = f;
  3241. else ffruit = f;
  3242. Strcpy(f->fname, str);
  3243. f->fid = highest_fruit_id;
  3244. f->nextf = 0;
  3245. nonew:
  3246. if (user_specified) current_fruit = highest_fruit_id;
  3247. return f->fid;
  3248. }
  3249. /*
  3250. * This is a somewhat generic menu for taking a list of NetHack style
  3251. * class choices and presenting them via a description
  3252. * rather than the traditional NetHack characters.
  3253. * (Benefits users whose first exposure to NetHack is via tiles).
  3254. *
  3255. * prompt
  3256. * The title at the top of the menu.
  3257. *
  3258. * category: 0 = monster class
  3259. * 1 = object class
  3260. *
  3261. * way
  3262. * FALSE = PICK_ONE, TRUE = PICK_ANY
  3263. *
  3264. * class_list
  3265. * a null terminated string containing the list of choices.
  3266. *
  3267. * class_selection
  3268. * a null terminated string containing the selected characters.
  3269. *
  3270. * Returns number selected.
  3271. */
  3272. int
  3273. choose_classes_menu(prompt, category, way, class_list, class_select)
  3274. const char *prompt;
  3275. int category;
  3276. boolean way;
  3277. char *class_list;
  3278. char *class_select;
  3279. {
  3280. menu_item *pick_list = (menu_item *)0;
  3281. winid win;
  3282. anything any;
  3283. char buf[BUFSZ];
  3284. int i, n;
  3285. int ret;
  3286. int next_accelerator, accelerator;
  3287. if (class_list == (char *)0 || class_select == (char *)0) return 0;
  3288. accelerator = 0;
  3289. next_accelerator = 'a';
  3290. any.a_void = 0;
  3291. win = create_nhwindow(NHW_MENU);
  3292. start_menu(win);
  3293. while (*class_list) {
  3294. const char *text;
  3295. boolean selected;
  3296. text = (char *)0;
  3297. selected = FALSE;
  3298. switch (category) {
  3299. case 0:
  3300. text = monexplain[def_char_to_monclass(*class_list)];
  3301. accelerator = *class_list;
  3302. Sprintf(buf, "%s", text);
  3303. break;
  3304. case 1:
  3305. text = objexplain[def_char_to_objclass(*class_list)];
  3306. accelerator = next_accelerator;
  3307. Sprintf(buf, "%c %s", *class_list, text);
  3308. break;
  3309. default:
  3310. impossible("choose_classes_menu: invalid category %d",
  3311. category);
  3312. }
  3313. if (way && *class_select) { /* Selections there already */
  3314. if (index(class_select, *class_list)) {
  3315. selected = TRUE;
  3316. }
  3317. }
  3318. any.a_int = *class_list;
  3319. add_menu(win, NO_GLYPH, &any, accelerator,
  3320. category ? *class_list : 0,
  3321. ATR_NONE, buf, selected);
  3322. ++class_list;
  3323. if (category > 0) {
  3324. ++next_accelerator;
  3325. if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
  3326. if (next_accelerator == ('Z' + 1)) break;
  3327. }
  3328. }
  3329. end_menu(win, prompt);
  3330. n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
  3331. destroy_nhwindow(win);
  3332. if (n > 0) {
  3333. for (i = 0; i < n; ++i)
  3334. *class_select++ = (char)pick_list[i].item.a_int;
  3335. free((genericptr_t)pick_list);
  3336. ret = n;
  3337. } else if (n == -1) {
  3338. class_select = eos(class_select);
  3339. ret = -1;
  3340. } else
  3341. ret = 0;
  3342. *class_select = '\0';
  3343. return ret;
  3344. }
  3345. struct wc_Opt wc_options[] = {
  3346. {"ascii_map", WC_ASCII_MAP},
  3347. {"color", WC_COLOR},
  3348. {"eight_bit_tty", WC_EIGHT_BIT_IN},
  3349. {"hilite_pet", WC_HILITE_PET},
  3350. {"popup_dialog", WC_POPUP_DIALOG},
  3351. {"player_selection", WC_PLAYER_SELECTION},
  3352. {"preload_tiles", WC_PRELOAD_TILES},
  3353. {"tiled_map", WC_TILED_MAP},
  3354. {"tile_file", WC_TILE_FILE},
  3355. {"tile_width", WC_TILE_WIDTH},
  3356. {"tile_height", WC_TILE_HEIGHT},
  3357. {"use_inverse", WC_INVERSE},
  3358. {"align_message", WC_ALIGN_MESSAGE},
  3359. {"align_status", WC_ALIGN_STATUS},
  3360. {"font_map", WC_FONT_MAP},
  3361. {"font_menu", WC_FONT_MENU},
  3362. {"font_message",WC_FONT_MESSAGE},
  3363. #if 0
  3364. {"perm_invent",WC_PERM_INVENT},
  3365. #endif
  3366. {"font_size_map", WC_FONTSIZ_MAP},
  3367. {"font_size_menu", WC_FONTSIZ_MENU},
  3368. {"font_size_message", WC_FONTSIZ_MESSAGE},
  3369. {"font_size_status", WC_FONTSIZ_STATUS},
  3370. {"font_size_text", WC_FONTSIZ_TEXT},
  3371. {"font_status", WC_FONT_STATUS},
  3372. {"font_text", WC_FONT_TEXT},
  3373. {"map_mode", WC_MAP_MODE},
  3374. {"scroll_amount", WC_SCROLL_AMOUNT},
  3375. {"scroll_margin", WC_SCROLL_MARGIN},
  3376. {"splash_screen", WC_SPLASH_SCREEN},
  3377. {"vary_msgcount",WC_VARY_MSGCOUNT},
  3378. {"windowcolors", WC_WINDOWCOLORS},
  3379. {"mouse_support", WC_MOUSE_SUPPORT},
  3380. {(char *)0, 0L}
  3381. };
  3382. struct wc_Opt wc2_options[] = {
  3383. {"fullscreen", WC2_FULLSCREEN},
  3384. {"softkeyboard", WC2_SOFTKEYBOARD},
  3385. {"wraptext", WC2_WRAPTEXT},
  3386. {(char *)0, 0L}
  3387. };
  3388. /*
  3389. * If a port wants to change or ensure that the
  3390. * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
  3391. * correct (for controlling its display in the option menu) call
  3392. * set_option_mod_status()
  3393. * with the second argument of 0,2, or 3 respectively.
  3394. */
  3395. void
  3396. set_option_mod_status(optnam, status)
  3397. const char *optnam;
  3398. int status;
  3399. {
  3400. int k;
  3401. if (status < SET_IN_FILE || status > SET_IN_GAME) {
  3402. impossible("set_option_mod_status: status out of range %d.",
  3403. status);
  3404. return;
  3405. }
  3406. for (k = 0; boolopt[k].name; k++) {
  3407. if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
  3408. boolopt[k].optflags = status;
  3409. return;
  3410. }
  3411. }
  3412. for (k = 0; compopt[k].name; k++) {
  3413. if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
  3414. compopt[k].optflags = status;
  3415. return;
  3416. }
  3417. }
  3418. }
  3419. /*
  3420. * You can set several wc_options in one call to
  3421. * set_wc_option_mod_status() by setting
  3422. * the appropriate bits for each option that you
  3423. * are setting in the optmask argument
  3424. * prior to calling.
  3425. * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME);
  3426. */
  3427. void
  3428. set_wc_option_mod_status(optmask, status)
  3429. unsigned long optmask;
  3430. int status;
  3431. {
  3432. int k = 0;
  3433. if (status < SET_IN_FILE || status > SET_IN_GAME) {
  3434. impossible("set_wc_option_mod_status: status out of range %d.",
  3435. status);
  3436. return;
  3437. }
  3438. while (wc_options[k].wc_name) {
  3439. if (optmask & wc_options[k].wc_bit) {
  3440. set_option_mod_status(wc_options[k].wc_name, status);
  3441. }
  3442. k++;
  3443. }
  3444. }
  3445. STATIC_OVL boolean
  3446. is_wc_option(optnam)
  3447. const char *optnam;
  3448. {
  3449. int k = 0;
  3450. while (wc_options[k].wc_name) {
  3451. if (strcmp(wc_options[k].wc_name, optnam) == 0)
  3452. return TRUE;
  3453. k++;
  3454. }
  3455. return FALSE;
  3456. }
  3457. STATIC_OVL boolean
  3458. wc_supported(optnam)
  3459. const char *optnam;
  3460. {
  3461. int k = 0;
  3462. while (wc_options[k].wc_name) {
  3463. if (!strcmp(wc_options[k].wc_name, optnam) &&
  3464. (windowprocs.wincap & wc_options[k].wc_bit))
  3465. return TRUE;
  3466. k++;
  3467. }
  3468. return FALSE;
  3469. }
  3470. /*
  3471. * You can set several wc2_options in one call to
  3472. * set_wc2_option_mod_status() by setting
  3473. * the appropriate bits for each option that you
  3474. * are setting in the optmask argument
  3475. * prior to calling.
  3476. * example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
  3477. */
  3478. void
  3479. set_wc2_option_mod_status(optmask, status)
  3480. unsigned long optmask;
  3481. int status;
  3482. {
  3483. int k = 0;
  3484. if (status < SET_IN_FILE || status > SET_IN_GAME) {
  3485. impossible("set_wc2_option_mod_status: status out of range %d.",
  3486. status);
  3487. return;
  3488. }
  3489. while (wc2_options[k].wc_name) {
  3490. if (optmask & wc2_options[k].wc_bit) {
  3491. set_option_mod_status(wc2_options[k].wc_name, status);
  3492. }
  3493. k++;
  3494. }
  3495. }
  3496. STATIC_OVL boolean
  3497. is_wc2_option(optnam)
  3498. const char *optnam;
  3499. {
  3500. int k = 0;
  3501. while (wc2_options[k].wc_name) {
  3502. if (strcmp(wc2_options[k].wc_name, optnam) == 0)
  3503. return TRUE;
  3504. k++;
  3505. }
  3506. return FALSE;
  3507. }
  3508. STATIC_OVL boolean
  3509. wc2_supported(optnam)
  3510. const char *optnam;
  3511. {
  3512. int k = 0;
  3513. while (wc2_options[k].wc_name) {
  3514. if (!strcmp(wc2_options[k].wc_name, optnam) &&
  3515. (windowprocs.wincap2 & wc2_options[k].wc_bit))
  3516. return TRUE;
  3517. k++;
  3518. }
  3519. return FALSE;
  3520. }
  3521. STATIC_OVL void
  3522. wc_set_font_name(wtype, fontname)
  3523. int wtype;
  3524. char *fontname;
  3525. {
  3526. char **fn = (char **)0;
  3527. if (!fontname) return;
  3528. switch(wtype) {
  3529. case NHW_MAP:
  3530. fn = &iflags.wc_font_map;
  3531. break;
  3532. case NHW_MESSAGE:
  3533. fn = &iflags.wc_font_message;
  3534. break;
  3535. case NHW_TEXT:
  3536. fn = &iflags.wc_font_text;
  3537. break;
  3538. case NHW_MENU:
  3539. fn = &iflags.wc_font_menu;
  3540. break;
  3541. case NHW_STATUS:
  3542. fn = &iflags.wc_font_status;
  3543. break;
  3544. default:
  3545. return;
  3546. }
  3547. if (fn) {
  3548. if (*fn) free(*fn);
  3549. *fn = (char *)alloc(strlen(fontname) + 1);
  3550. Strcpy(*fn, fontname);
  3551. }
  3552. return;
  3553. }
  3554. STATIC_OVL int
  3555. wc_set_window_colors(op)
  3556. char *op;
  3557. {
  3558. /* syntax:
  3559. * menu white/black message green/yellow status white/blue text white/black
  3560. */
  3561. int j;
  3562. char buf[BUFSZ];
  3563. char *wn, *tfg, *tbg, *newop;
  3564. static const char *wnames[] = { "menu", "message", "status", "text" };
  3565. static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
  3566. static char **fgp[] = {
  3567. &iflags.wc_foregrnd_menu,
  3568. &iflags.wc_foregrnd_message,
  3569. &iflags.wc_foregrnd_status,
  3570. &iflags.wc_foregrnd_text
  3571. };
  3572. static char **bgp[] = {
  3573. &iflags.wc_backgrnd_menu,
  3574. &iflags.wc_backgrnd_message,
  3575. &iflags.wc_backgrnd_status,
  3576. &iflags.wc_backgrnd_text
  3577. };
  3578. Strcpy(buf, op);
  3579. newop = mungspaces(buf);
  3580. while (newop && *newop) {
  3581. wn = tfg = tbg = (char *)0;
  3582. /* until first non-space in case there's leading spaces - before colorname*/
  3583. while(*newop && isspace(*newop)) newop++;
  3584. if (*newop) wn = newop;
  3585. else return 0;
  3586. /* until first space - colorname*/
  3587. while(*newop && !isspace(*newop)) newop++;
  3588. if (*newop) *newop = '\0';
  3589. else return 0;
  3590. newop++;
  3591. /* until first non-space - before foreground*/
  3592. while(*newop && isspace(*newop)) newop++;
  3593. if (*newop) tfg = newop;
  3594. else return 0;
  3595. /* until slash - foreground */
  3596. while(*newop && *newop != '/') newop++;
  3597. if (*newop) *newop = '\0';
  3598. else return 0;
  3599. newop++;
  3600. /* until first non-space (in case there's leading space after slash) - before background */
  3601. while(*newop && isspace(*newop)) newop++;
  3602. if (*newop) tbg = newop;
  3603. else return 0;
  3604. /* until first space - background */
  3605. while(*newop && !isspace(*newop)) newop++;
  3606. if (*newop) *newop++ = '\0';
  3607. for (j = 0; j < 4; ++j) {
  3608. if (!strcmpi(wn, wnames[j]) ||
  3609. !strcmpi(wn, shortnames[j])) {
  3610. if (tfg && !strstri(tfg, " ")) {
  3611. if (*fgp[j]) free(*fgp[j]);
  3612. *fgp[j] = (char *)alloc(strlen(tfg) + 1);
  3613. Strcpy(*fgp[j], tfg);
  3614. }
  3615. if (tbg && !strstri(tbg, " ")) {
  3616. if (*bgp[j]) free(*bgp[j]);
  3617. *bgp[j] = (char *)alloc(strlen(tbg) + 1);
  3618. Strcpy(*bgp[j], tbg);
  3619. }
  3620. break;
  3621. }
  3622. }
  3623. }
  3624. return 1;
  3625. }
  3626. #endif /* OPTION_LISTS_ONLY */
  3627. /*options.c*/