PageRenderTime 59ms CodeModel.GetById 17ms 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

Large files files are truncated, but you can click here to view the full file

  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

Large files files are truncated, but you can click here to view the full file