PageRenderTime 79ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/src/options.c

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