PageRenderTime 61ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/slashem/src/options.c

https://bitbucket.org/clivecrous/newt
C | 4384 lines | 4040 code | 147 blank | 197 comment | 531 complexity | 2faff6e57e06b493a4c0353918fb03ef 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. #if defined(GL_GRAPHICS) || defined(SDL_GRAPHICS)
  17. #include "winGL.h" /* Sdlgl_parse_options */
  18. #endif
  19. #include "filename.h"
  20. #define WINTYPELEN 16
  21. #ifdef DEFAULT_WC_TILED_MAP
  22. #define PREFER_TILED TRUE
  23. #else
  24. #define PREFER_TILED FALSE
  25. #endif
  26. /*
  27. * NOTE: If you add (or delete) an option, please update the short
  28. * options help (option_help()), the long options help (dat/opthelp),
  29. * and the current options setting display function (doset()),
  30. * and also the Guidebooks.
  31. *
  32. * The order matters. If an option is a an initial substring of another
  33. * option (e.g. time and timed_delay) the shorter one must come first.
  34. */
  35. static struct Bool_Opt
  36. {
  37. const char *name;
  38. boolean *addr, initvalue;
  39. int optflags;
  40. } boolopt[] = {
  41. #ifdef AMIGA
  42. {"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME},
  43. #else
  44. {"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
  45. #endif
  46. {"ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME}, /*WC*/
  47. #ifdef MFLOPPY
  48. {"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
  49. #else
  50. {"asksavedisk", (boolean *)0, FALSE, SET_IN_GAME},
  51. #endif
  52. {"autodig", &flags.autodig, FALSE, SET_IN_GAME},
  53. {"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
  54. {"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
  55. #if defined(MICRO) && !defined(AMIGA)
  56. {"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
  57. #else
  58. {"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
  59. #endif
  60. #ifdef INSURANCE
  61. {"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
  62. #else
  63. {"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
  64. #endif
  65. #ifdef MFLOPPY
  66. {"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
  67. #else
  68. {"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
  69. #endif
  70. {"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
  71. # if defined(MICRO) || defined(WIN32) || defined(NEWT_GRAPHICS)
  72. {"color", &iflags.wc_color,TRUE, SET_IN_GAME}, /*WC*/
  73. # else /* systems that support multiple terminals, many monochrome */
  74. {"color", &iflags.wc_color, FALSE, SET_IN_GAME}, /*WC*/
  75. # endif
  76. {"confirm",&flags.confirm, TRUE, SET_IN_GAME},
  77. #if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV)
  78. {"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME},
  79. #else
  80. {"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE},
  81. #endif
  82. {"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME}, /*WC*/
  83. #if defined(TTY_GRAPHICS) || defined(NEWT_GRAPHICS)
  84. {"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
  85. #else
  86. {"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
  87. #endif
  88. #ifdef OPT_DISPMAP
  89. {"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
  90. #else
  91. {"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
  92. #endif
  93. {"female", &flags.female, FALSE, DISP_IN_GAME},
  94. {"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
  95. #ifdef AMIFLUSH
  96. {"flush", &flags.amiflush, FALSE, SET_IN_GAME},
  97. #else
  98. {"flush", (boolean *)0, FALSE, SET_IN_FILE},
  99. #endif
  100. {"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
  101. {"help", &flags.help, TRUE, SET_IN_GAME},
  102. {"hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME}, /*WC*/
  103. #ifdef ASCIIGRAPH
  104. {"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME},
  105. #else
  106. {"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE},
  107. #endif
  108. #ifndef MAC
  109. {"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
  110. #else
  111. {"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
  112. #endif
  113. #ifdef SHOW_WEIGHT
  114. {"invweight", &flags.invweight, FALSE, SET_IN_GAME},
  115. #else
  116. {"invweight", (boolean *)0, FALSE, SET_IN_FILE},
  117. #endif
  118. /*WAC the keep savefile option...*/
  119. #ifdef KEEP_SAVE
  120. {"keep_savefile", &flags.keep_savefile, FALSE, SET_IN_FILE},
  121. #else
  122. {"keep_savefile", (boolean *)0, FALSE, DISP_IN_GAME},
  123. #endif
  124. {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */
  125. {"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
  126. {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
  127. {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
  128. #ifdef MAC_GRAPHICS_ENV
  129. {"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
  130. #else
  131. {"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE},
  132. #endif
  133. #ifdef MAIL
  134. {"mail", &flags.biff, TRUE, SET_IN_GAME},
  135. #else
  136. {"mail", (boolean *)0, TRUE, SET_IN_FILE},
  137. #endif
  138. #ifdef MENU_COLOR
  139. # ifdef MICRO
  140. {"menucolors", &iflags.use_menu_color, TRUE, SET_IN_GAME},
  141. # else
  142. {"menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME},
  143. # endif
  144. #else
  145. {"menucolors", (boolean *)0, FALSE, SET_IN_GAME},
  146. #endif
  147. {"menu_on_esc", &flags.menu_on_esc, TRUE, SET_IN_GAME},
  148. #ifdef WIZARD
  149. /* for menu debugging only*/
  150. {"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
  151. #else
  152. {"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
  153. #endif
  154. #ifdef WIZARD
  155. {"mon_polycontrol", &iflags.mon_polycontrol, FALSE, SET_IN_GAME},
  156. #else
  157. {"mon_polycontrol", (boolean *)0, FALSE, SET_IN_FILE},
  158. #endif
  159. {"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME}, /*WC*/
  160. #ifdef NEWS
  161. {"news", &iflags.news, TRUE, DISP_IN_GAME},
  162. #else
  163. {"news", (boolean *)0, FALSE, SET_IN_FILE},
  164. #endif
  165. {"null", &flags.null, TRUE, SET_IN_GAME},
  166. #ifdef MAC
  167. {"page_wait", &flags.page_wait, TRUE, SET_IN_GAME},
  168. #else
  169. {"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
  170. #endif
  171. {"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
  172. {"pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME},
  173. {"popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME}, /*WC*/
  174. {"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
  175. {"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME}, /*WC*/
  176. {"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
  177. {"radar", (boolean *)0, FALSE, SET_IN_FILE}, /* OBSOLETE */
  178. #if defined(MICRO) && !defined(AMIGA)
  179. {"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
  180. #else
  181. {"rawio", (boolean *)0, FALSE, SET_IN_FILE},
  182. #endif
  183. {"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
  184. {"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
  185. #if defined(OBJ_SANITY)
  186. {"sanity_check", &iflags.sanity_check, TRUE, SET_IN_GAME},
  187. #elif defined(WIZARD)
  188. {"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
  189. #else
  190. {"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
  191. #endif
  192. #ifdef EXP_ON_BOTL
  193. {"showexp", &flags.showexp, FALSE, SET_IN_GAME},
  194. #else
  195. {"showexp", (boolean *)0, FALSE, SET_IN_FILE},
  196. #endif
  197. {"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
  198. #ifdef SCORE_ON_BOTL
  199. {"showscore", &flags.showscore, FALSE, SET_IN_GAME},
  200. #else
  201. {"showscore", (boolean *)0, FALSE, SET_IN_FILE},
  202. #endif
  203. /* WAC made the [ xx pts] dmg display optional */
  204. #ifdef SHOW_DMG
  205. {"showdmg", &flags.showdmg, FALSE, SET_IN_GAME},
  206. #else
  207. {"showdmg", (boolean *)0, FALSE, SET_IN_FILE},
  208. #endif
  209. #ifdef SHOW_WEIGHT
  210. {"showweight", &flags.showweight, FALSE, SET_IN_GAME},
  211. #else
  212. {"showweight", (boolean *)0, FALSE, SET_IN_FILE},
  213. #endif
  214. {"silent", &flags.silent, TRUE, SET_IN_GAME},
  215. {"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
  216. {"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
  217. {"sound", &flags.soundok, TRUE, SET_IN_GAME},
  218. {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
  219. {"standout", &flags.standout, FALSE, SET_IN_GAME},
  220. {"splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME}, /*WC*/
  221. {"tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME}, /*WC*/
  222. {"time", &flags.time, FALSE, SET_IN_GAME},
  223. #ifdef TIMED_DELAY
  224. {"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
  225. #else
  226. {"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
  227. #endif
  228. {"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
  229. {"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
  230. {"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
  231. #ifdef WIN32CON
  232. {"use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME}, /*WC*/
  233. #else
  234. {"use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME}, /*WC*/
  235. #endif
  236. {"verbose", &flags.verbose, TRUE, SET_IN_GAME},
  237. {"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
  238. {(char *)0, (boolean *)0, FALSE, 0}
  239. };
  240. genericptr_t nh_option_get_boolopt()
  241. {
  242. return (genericptr_t)boolopt;
  243. }
  244. /* compound options, for option_help() and external programs like Amiga
  245. * frontend */
  246. static struct Comp_Opt
  247. {
  248. const char *name, *descr;
  249. int size; /* for frontends and such allocating space --
  250. * usually allowed size of data in game, but
  251. * occasionally maximum reasonable size for
  252. * typing when game maintains information in
  253. * a different format */
  254. int optflags;
  255. } compopt[] = {
  256. { "align", "your starting alignment (lawful, neutral, or chaotic)",
  257. 8, DISP_IN_GAME },
  258. { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
  259. { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/
  260. { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
  261. { "boulder", "the symbol to use for displaying boulders",
  262. 1, SET_IN_GAME },
  263. { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
  264. PL_PSIZ, DISP_IN_GAME },
  265. { "disclose", "the kinds of information to disclose at end of game",
  266. sizeof(flags.end_disclose) * 2,
  267. SET_IN_GAME },
  268. { "dogname", "the name of your (first) dog (e.g., dogname:Fang)",
  269. PL_PSIZ, DISP_IN_GAME },
  270. { "dungeon", "the symbols to use in drawing the dungeon map",
  271. MAXDCHARS+1, SET_IN_FILE },
  272. { "effects", "the symbols to use in drawing special effects",
  273. MAXECHARS+1, SET_IN_FILE },
  274. { "font_map", "the font to use in the map window", 40, DISP_IN_GAME }, /*WC*/
  275. { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
  276. { "font_message", "the font to use in the message window",
  277. 40, DISP_IN_GAME }, /*WC*/
  278. { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
  279. { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/
  280. { "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/
  281. { "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/
  282. { "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/
  283. { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
  284. { "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/
  285. { "fruit", "the name of a fruit you enjoy eating",
  286. PL_FSIZ, SET_IN_GAME },
  287. { "gender", "your starting gender (male or female)",
  288. 8, DISP_IN_GAME },
  289. { "ghoulname", "the name of your (first) ghoul (e.g., ghoulname:Casper)",
  290. PL_PSIZ, DISP_IN_GAME },
  291. { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
  292. PL_PSIZ, DISP_IN_GAME },
  293. { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
  294. { "menucolor", "set menu colors", PL_PSIZ, SET_IN_FILE },
  295. { "menustyle", "user interface for object selection",
  296. MENUTYPELEN, SET_IN_GAME },
  297. { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
  298. { "menu_deselect_page", "deselect all items on this page of a menu",
  299. 4, SET_IN_FILE },
  300. { "menu_first_page", "jump to the first page in a menu",
  301. 4, SET_IN_FILE },
  302. { "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
  303. { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
  304. { "menu_invert_page", "invert all items on this page of a menu",
  305. 4, SET_IN_FILE },
  306. { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
  307. { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
  308. { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
  309. { "menu_search", "search for a menu item", 4, SET_IN_FILE },
  310. { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
  311. { "menu_select_page", "select all items on this page of a menu",
  312. 4, SET_IN_FILE },
  313. { "monsters", "the symbols to use for monsters",
  314. MAXMCLASSES, SET_IN_FILE },
  315. { "msghistory", "number of top line messages to save",
  316. 5, DISP_IN_GAME },
  317. # ifdef TTY_GRAPHICS
  318. {"msg_window", "the type of message window required",1, SET_IN_GAME},
  319. # else
  320. {"msg_window", "the type of message window required", 1, SET_IN_FILE},
  321. # endif
  322. { "name", "your character's name (e.g., name:Merlin-W)",
  323. PL_NSIZ, DISP_IN_GAME },
  324. { "number_pad", "use the number pad", 1, SET_IN_GAME},
  325. { "objects", "the symbols to use for objects",
  326. MAXOCLASSES, SET_IN_FILE },
  327. { "packorder", "the inventory order of the items in your pack",
  328. MAXOCLASSES, SET_IN_GAME },
  329. #ifdef CHANGE_COLOR
  330. { "palette", "palette (00c/880/-fff is blue/yellow/reverse white)",
  331. 15 , SET_IN_GAME },
  332. # if defined(MAC)
  333. { "hicolor", "same as palette, only order is reversed",
  334. 15, SET_IN_FILE },
  335. # endif
  336. #endif
  337. { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
  338. { "pickup_burden", "maximum burden picked up before prompt",
  339. 20, SET_IN_GAME },
  340. { "pickup_types", "types of objects to pick up automatically",
  341. MAXOCLASSES, SET_IN_GAME },
  342. { "player_selection", "choose character via dialog or prompts",
  343. 12, DISP_IN_GAME },
  344. { "race", "your starting race (e.g., Human, Elf)",
  345. PL_CSIZ, DISP_IN_GAME },
  346. { "role", "your starting role (e.g., Barbarian, Valkyrie)",
  347. PL_CSIZ, DISP_IN_GAME },
  348. { "runmode", "display frequency when `running' or `travelling'",
  349. sizeof "teleport", SET_IN_GAME },
  350. { "scores", "the parts of the score list you wish to see",
  351. 32, SET_IN_GAME },
  352. { "scroll_amount", "amount to scroll map when scroll_margin is reached",
  353. 20, DISP_IN_GAME }, /*WC*/
  354. { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
  355. #ifdef MSDOS
  356. { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
  357. #endif
  358. { "suppress_alert", "suppress alerts about version-specific features",
  359. 8, SET_IN_GAME },
  360. { "tile_width", "width of tiles", 20, DISP_IN_GAME}, /*WC*/
  361. { "tile_height", "height of tiles", 20, DISP_IN_GAME}, /*WC*/
  362. { "tile_file", "name of tile file", 70, DISP_IN_GAME}, /*WC*/
  363. { "tileset", "name of predefined tileset to use",
  364. PL_PSIZ, SET_IN_GAME },
  365. { "traps", "the symbols to use in drawing traps",
  366. MAXTCHARS+1, SET_IN_FILE },
  367. { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
  368. #ifdef MSDOS
  369. { "video", "method of video updating", 20, SET_IN_FILE },
  370. #endif
  371. #ifdef VIDEOSHADES
  372. { "videocolors", "color mappings for internal screen routines",
  373. 40, DISP_IN_GAME },
  374. #ifdef MSDOS
  375. { "videoshades", "gray shades to map to black/gray/white",
  376. 32, DISP_IN_GAME },
  377. #endif
  378. #endif
  379. #ifdef WIN32CON
  380. {"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
  381. #endif
  382. { "windowcolors", "the foreground/background colors of windows", /*WC*/
  383. 80, DISP_IN_GAME },
  384. { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
  385. { "wolfname", "the name of your (first) wolf (e.g., wolfname:Beast)",
  386. PL_PSIZ, DISP_IN_GAME },
  387. { (char *)0, (char *)0, 0, 0 }
  388. };
  389. static struct Bool_Tile_Opt
  390. {
  391. const char *name;
  392. unsigned long flag;
  393. unsigned long initvalue;
  394. } booltileopt[] = {
  395. {"transparent", TILESET_TRANSPARENT, 0},
  396. {"pseudo3D", TILESET_PSEUDO3D, 0},
  397. {(char *)0, 0, 0}
  398. };
  399. #ifdef OPTION_LISTS_ONLY
  400. #undef static
  401. #else /* use rest of file */
  402. static boolean need_redraw; /* for doset() */
  403. #if defined(TOS) && defined(TEXTCOLOR)
  404. extern boolean colors_changed; /* in tos.c */
  405. #endif
  406. #ifdef VIDEOSHADES
  407. extern char *shade[3]; /* in sys/msdos/video.c */
  408. extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c, win/tty/termcap.c*/
  409. #endif
  410. static char def_inv_order[MAXOCLASSES] = {
  411. COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
  412. SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
  413. TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
  414. };
  415. /*
  416. * Default menu manipulation command accelerators. These may _not_ be:
  417. *
  418. * + a number - reserved for counts
  419. * + an upper or lower case US ASCII letter - used for accelerators
  420. * + ESC - reserved for escaping the menu
  421. * + NULL, CR or LF - reserved for commiting the selection(s). NULL
  422. * is kind of odd, but the tty's xwaitforspace() will return it if
  423. * someone hits a <ret>.
  424. * + a default object class symbol - used for object class accelerators
  425. *
  426. * Standard letters (for now) are:
  427. *
  428. * < back 1 page
  429. * > forward 1 page
  430. * ^ first page
  431. * | last page
  432. * : search
  433. *
  434. * page all
  435. * , select .
  436. * \ deselect -
  437. * ~ invert @
  438. *
  439. * The command name list is duplicated in the compopt array.
  440. */
  441. typedef struct {
  442. const char *name;
  443. char cmd;
  444. } menu_cmd_t;
  445. #define NUM_MENU_CMDS 11
  446. static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
  447. /* 0*/ { "menu_first_page", MENU_FIRST_PAGE },
  448. { "menu_last_page", MENU_LAST_PAGE },
  449. { "menu_next_page", MENU_NEXT_PAGE },
  450. { "menu_previous_page", MENU_PREVIOUS_PAGE },
  451. { "menu_select_all", MENU_SELECT_ALL },
  452. /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL },
  453. { "menu_invert_all", MENU_INVERT_ALL },
  454. { "menu_select_page", MENU_SELECT_PAGE },
  455. { "menu_deselect_page", MENU_UNSELECT_PAGE },
  456. { "menu_invert_page", MENU_INVERT_PAGE },
  457. /*10*/ { "menu_search", MENU_SEARCH },
  458. };
  459. /*
  460. * Allow the user to map incoming characters to various menu commands.
  461. * The accelerator list must be a valid C string.
  462. */
  463. #define MAX_MENU_MAPPED_CMDS 32 /* some number */
  464. char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1]; /* exported */
  465. static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1];
  466. static short n_menu_mapped = 0;
  467. static boolean initial, from_file;
  468. STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int));
  469. STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
  470. STATIC_DCL void FDECL(escapes, (const char *, char *));
  471. STATIC_DCL void FDECL(rejectoption, (const char *));
  472. STATIC_DCL void FDECL(badoption, (const char *));
  473. STATIC_OVL void FDECL(badtileoption, (const char *));
  474. STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P));
  475. STATIC_OVL char *FDECL(string_for_tile_opt, (char *, BOOLEAN_P));
  476. STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P));
  477. STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P));
  478. STATIC_DCL int FDECL(change_inv_order, (char *));
  479. STATIC_DCL void FDECL(oc_to_str, (char *, char *));
  480. STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int));
  481. STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
  482. STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
  483. STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
  484. STATIC_DCL void FDECL(warning_opts, (char *,const char *));
  485. STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int));
  486. STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
  487. STATIC_OVL int FDECL(wc_set_window_colors, (char *));
  488. STATIC_OVL boolean FDECL(is_wc_option, (const char *));
  489. STATIC_OVL boolean FDECL(wc_supported, (const char *));
  490. STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
  491. STATIC_OVL boolean FDECL(wc2_supported, (const char *));
  492. #ifdef AUTOPICKUP_EXCEPTIONS
  493. STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
  494. STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
  495. #endif
  496. /* check whether a user-supplied option string is a proper leading
  497. substring of a particular option name; option string might have
  498. a colon or equals sign and arbitrary value appended to it */
  499. boolean
  500. match_optname(user_string, opt_name, min_length, val_allowed)
  501. const char *user_string, *opt_name;
  502. int min_length;
  503. boolean val_allowed;
  504. {
  505. int len = (int)strlen(user_string);
  506. if (val_allowed) {
  507. const char *p = index(user_string, ':'),
  508. *q = index(user_string, '=');
  509. if (!p || (q && q < p)) p = q;
  510. while(p && p > user_string && isspace(*(p-1))) p--;
  511. if (p) len = (int)(p - user_string);
  512. }
  513. return (len >= min_length) && !strncmpi(opt_name, user_string, len);
  514. }
  515. /* most environment variables will eventually be printed in an error
  516. * message if they don't work, and most error message paths go through
  517. * BUFSZ buffers, which could be overflowed by a maliciously long
  518. * environment variable. if a variable can legitimately be long, or
  519. * if it's put in a smaller buffer, the responsible code will have to
  520. * bounds-check itself.
  521. */
  522. char *
  523. nh_getenv(ev)
  524. const char *ev;
  525. {
  526. char *getev = getenv(ev);
  527. if (getev && strlen(getev) <= (BUFSZ / 2))
  528. return getev;
  529. else
  530. return (char *)0;
  531. }
  532. void
  533. initoptions()
  534. {
  535. #ifndef MAC
  536. char *opts;
  537. #endif
  538. int i;
  539. /* initialize the random number generator */
  540. setrandom();
  541. /* for detection of configfile options specified multiple times */
  542. iflags.opt_booldup = iflags.opt_compdup = (int *)0;
  543. for (i = 0; boolopt[i].name; i++) {
  544. if (boolopt[i].addr)
  545. *(boolopt[i].addr) = boolopt[i].initvalue;
  546. }
  547. flags.end_own = FALSE;
  548. flags.end_top = 3;
  549. flags.end_around = 2;
  550. iflags.runmode = RUN_LEAP;
  551. iflags.msg_history = 20;
  552. #ifdef TTY_GRAPHICS
  553. iflags.prevmsg_window = 's';
  554. #endif
  555. iflags.menu_headings = ATR_INVERSE;
  556. /* Use negative indices to indicate not yet selected */
  557. flags.initrole = -1;
  558. flags.initrace = -1;
  559. flags.initgend = -1;
  560. flags.initalign = -1;
  561. /* Set the default monster and object class symbols. Don't use */
  562. /* memcpy() --- sizeof char != sizeof uchar on some machines. */
  563. for (i = 0; i < MAXOCLASSES; i++)
  564. oc_syms[i] = (uchar) def_oc_syms[i];
  565. for (i = 0; i < MAXMCLASSES; i++)
  566. monsyms[i] = (uchar) def_monsyms[i];
  567. for (i = 0; i < WARNCOUNT; i++)
  568. warnsyms[i] = def_warnsyms[i].sym;
  569. iflags.bouldersym = 0;
  570. iflags.travelcc.x = iflags.travelcc.y = -1;
  571. flags.warnlevel = 1;
  572. flags.warntype = 0L;
  573. /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
  574. (void)memcpy((genericptr_t)flags.inv_order,
  575. (genericptr_t)def_inv_order, sizeof flags.inv_order);
  576. flags.pickup_types[0] = '\0';
  577. flags.pickup_burden = MOD_ENCUMBER;
  578. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
  579. flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
  580. switch_graphics(ASCII_GRAPHICS); /* set default characters */
  581. #if defined(UNIX) && defined(TTY_GRAPHICS)
  582. /*
  583. * Set defaults for some options depending on what we can
  584. * detect about the environment's capabilities.
  585. * This has to be done after the global initialization above
  586. * and before reading user-specific initialization via
  587. * config file/environment variable below.
  588. */
  589. /* this detects the IBM-compatible console on most 386 boxes */
  590. if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
  591. switch_graphics(IBM_GRAPHICS);
  592. # ifdef TEXTCOLOR
  593. iflags.use_color = TRUE;
  594. # endif
  595. }
  596. #endif /* UNIX && TTY_GRAPHICS */
  597. #if defined(UNIX) || defined(VMS)
  598. # ifdef TTY_GRAPHICS
  599. /* detect whether a "vt" terminal can handle alternate charsets */
  600. if ((opts = nh_getenv("TERM")) &&
  601. !strncmpi(opts, "vt", 2) && AS && AE &&
  602. index(AS, '\016') && index(AE, '\017')) {
  603. switch_graphics(DEC_GRAPHICS);
  604. }
  605. # endif
  606. #endif /* UNIX || VMS */
  607. #ifdef MAC_GRAPHICS_ENV
  608. switch_graphics(MAC_GRAPHICS);
  609. #endif /* MAC_GRAPHICS_ENV */
  610. flags.menu_style = MENU_FULL;
  611. /* since this is done before init_objects(), do partial init here */
  612. objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
  613. nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
  614. #ifndef MAC
  615. opts = getenv(NETHACK_ENV_OPTIONS);
  616. if (!opts) opts = getenv("NETHACKOPTIONS");
  617. if (!opts) opts = getenv("HACKOPTIONS");
  618. if (opts) {
  619. if (*opts == '/' || *opts == '\\' || *opts == '@') {
  620. if (*opts == '@') opts++; /* @filename */
  621. /* looks like a filename */
  622. if (strlen(opts) < BUFSZ/2)
  623. read_config_file(opts);
  624. } else {
  625. read_config_file((char *)0);
  626. /* let the total length of options be long;
  627. * parseoptions() will check each individually
  628. */
  629. parseoptions(opts, TRUE, FALSE);
  630. }
  631. } else
  632. #endif
  633. read_config_file((char *)0);
  634. (void)fruitadd(pl_fruit);
  635. /* Remove "slime mold" from list of object names; this will */
  636. /* prevent it from being wished unless it's actually present */
  637. /* as a named (or default) fruit. Wishing for "fruit" will */
  638. /* result in the player's preferred fruit [better than "\033"]. */
  639. obj_descr[SLIME_MOLD].oc_name = "fruit";
  640. #if defined(GL_GRAPHICS) || defined(SDL_GRAPHICS)
  641. /* -AJA- SDL/GL support. Needs to happen after main config
  642. * file has been read.
  643. */
  644. opts = getenv(SDLGL_ENV_VAR);
  645. if (opts)
  646. Sdlgl_parse_options(opts, TRUE, FALSE);
  647. #endif
  648. return;
  649. }
  650. STATIC_OVL void
  651. nmcpy(dest, src, maxlen)
  652. char *dest;
  653. const char *src;
  654. int maxlen;
  655. {
  656. int count;
  657. for(count = 1; count < maxlen; count++) {
  658. if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
  659. *dest++ = *src++;
  660. }
  661. *dest = 0;
  662. }
  663. /*
  664. * escapes: escape expansion for showsyms. C-style escapes understood include
  665. * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
  666. * for control characters is also understood, and \[mM] followed by any of the
  667. * previous forms or by a character has the effect of 'meta'-ing the value (so
  668. * that the alternate character set will be enabled).
  669. */
  670. STATIC_OVL void
  671. escapes(cp, tp)
  672. const char *cp;
  673. char *tp;
  674. {
  675. while (*cp)
  676. {
  677. int cval = 0, meta = 0;
  678. if (*cp == '\\' && index("mM", cp[1])) {
  679. meta = 1;
  680. cp += 2;
  681. }
  682. if (*cp == '\\' && index("0123456789xXoO", cp[1]))
  683. {
  684. const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
  685. int dcount = 0;
  686. cp++;
  687. if (*cp == 'x' || *cp == 'X')
  688. for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
  689. cval = (cval * 16) + (dp - hex) / 2;
  690. else if (*cp == 'o' || *cp == 'O')
  691. for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
  692. cval = (cval * 8) + (*cp - '0');
  693. else
  694. for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
  695. cval = (cval * 10) + (*cp - '0');
  696. }
  697. else if (*cp == '\\') /* C-style character escapes */
  698. {
  699. switch (*++cp)
  700. {
  701. case '\\': cval = '\\'; break;
  702. case 'n': cval = '\n'; break;
  703. case 't': cval = '\t'; break;
  704. case 'b': cval = '\b'; break;
  705. case 'r': cval = '\r'; break;
  706. default: cval = *cp;
  707. }
  708. cp++;
  709. }
  710. else if (*cp == '^') /* expand control-character syntax */
  711. {
  712. cval = (*++cp & 0x1f);
  713. cp++;
  714. }
  715. else
  716. cval = *cp++;
  717. if (meta)
  718. cval |= 0x80;
  719. *tp++ = cval;
  720. }
  721. *tp = '\0';
  722. }
  723. STATIC_OVL void
  724. rejectoption(optname)
  725. const char *optname;
  726. {
  727. #ifdef MICRO
  728. pline("\"%s\" settable only from %s.", optname, configfile);
  729. #else
  730. pline("%s can be set only from %s or %s.", optname,
  731. NETHACK_ENV_OPTIONS, configfile);
  732. #endif
  733. }
  734. STATIC_OVL void
  735. badoption(opts)
  736. const char *opts;
  737. {
  738. if (!initial) {
  739. if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
  740. option_help();
  741. else
  742. pline("Bad syntax: %s. Enter \"?g\" for help.", opts);
  743. return;
  744. }
  745. #ifdef MAC
  746. else return;
  747. #endif
  748. if(from_file)
  749. raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
  750. else
  751. raw_printf("Bad syntax in %s: %s.", NETHACK_ENV_OPTIONS, opts);
  752. wait_synch();
  753. }
  754. STATIC_OVL void
  755. badauthoption(opts)
  756. const char *opts;
  757. {
  758. raw_printf("Bad syntax in AUTHENTICATION in %s: %s.", configfile, opts);
  759. wait_synch();
  760. }
  761. STATIC_OVL void
  762. badtileoption(opts)
  763. const char *opts;
  764. {
  765. raw_printf("Bad syntax in TILESET in %s: %s.", configfile, opts);
  766. wait_synch();
  767. }
  768. STATIC_OVL char *
  769. string_for_opt(opts, val_optional)
  770. char *opts;
  771. boolean val_optional;
  772. {
  773. char *colon, *equals;
  774. colon = index(opts, ':');
  775. equals = index(opts, '=');
  776. if (!colon || (equals && equals < colon)) colon = equals;
  777. if (!colon || !*++colon) {
  778. if (!val_optional) badoption(opts);
  779. return (char *)0;
  780. }
  781. return colon;
  782. }
  783. STATIC_OVL char *
  784. string_for_auth_opt(opts, val_optional)
  785. char *opts;
  786. boolean val_optional;
  787. {
  788. char *colon = string_for_opt(opts, TRUE);
  789. if (!colon && !val_optional) badauthoption(opts);
  790. return colon;
  791. }
  792. STATIC_OVL char *
  793. string_for_tile_opt(opts, val_optional)
  794. char *opts;
  795. boolean val_optional;
  796. {
  797. char *colon = string_for_opt(opts, TRUE);
  798. if (!colon && !val_optional) badtileoption(opts);
  799. return colon;
  800. }
  801. STATIC_OVL char *
  802. string_for_env_opt(optname, opts, val_optional)
  803. const char *optname;
  804. char *opts;
  805. boolean val_optional;
  806. {
  807. if(!initial) {
  808. rejectoption(optname);
  809. return (char *)0;
  810. }
  811. return string_for_opt(opts, val_optional);
  812. }
  813. STATIC_OVL void
  814. bad_negation(optname, with_parameter)
  815. const char *optname;
  816. boolean with_parameter;
  817. {
  818. pline_The("%s option may not %sbe negated.",
  819. optname,
  820. with_parameter ? "both have a value and " : "");
  821. }
  822. /*
  823. * Change the inventory order, using the given string as the new order.
  824. * Missing characters in the new order are filled in at the end from
  825. * the current inv_order, except for gold, which is forced to be first
  826. * if not explicitly present.
  827. *
  828. * This routine returns 1 unless there is a duplicate or bad char in
  829. * the string.
  830. */
  831. STATIC_OVL int
  832. change_inv_order(op)
  833. char *op;
  834. {
  835. int oc_sym, num;
  836. char *sp, buf[BUFSZ];
  837. num = 0;
  838. #ifndef GOLDOBJ
  839. if (!index(op, GOLD_SYM))
  840. buf[num++] = COIN_CLASS;
  841. #else
  842. /* !!!! probably unnecessary with gold as normal inventory */
  843. #endif
  844. for (sp = op; *sp; sp++) {
  845. oc_sym = def_char_to_objclass(*sp);
  846. /* reject bad or duplicate entries */
  847. if (oc_sym == MAXOCLASSES ||
  848. oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
  849. !index(flags.inv_order, oc_sym) || index(sp+1, *sp))
  850. return 0;
  851. /* retain good ones */
  852. buf[num++] = (char) oc_sym;
  853. }
  854. buf[num] = '\0';
  855. /* fill in any omitted classes, using previous ordering */
  856. for (sp = flags.inv_order; *sp; sp++)
  857. if (!index(buf, *sp)) {
  858. buf[num++] = *sp;
  859. buf[num] = '\0'; /* explicitly terminate for next index() */
  860. }
  861. Strcpy(flags.inv_order, buf);
  862. return 1;
  863. }
  864. STATIC_OVL void
  865. graphics_opts(opts, optype, maxlen, offset)
  866. register char *opts;
  867. const char *optype;
  868. int maxlen, offset;
  869. {
  870. uchar translate[MAXPCHARS+1];
  871. int length, i;
  872. if (!(opts = string_for_env_opt(optype, opts, FALSE)))
  873. return;
  874. escapes(opts, opts);
  875. length = strlen(opts);
  876. if (length > maxlen) length = maxlen;
  877. /* match the form obtained from PC configuration files */
  878. for (i = 0; i < length; i++)
  879. translate[i] = (uchar) opts[i];
  880. assign_graphics(translate, length, maxlen, offset);
  881. }
  882. STATIC_OVL void
  883. warning_opts(opts, optype)
  884. register char *opts;
  885. const char *optype;
  886. {
  887. uchar translate[MAXPCHARS+1];
  888. int length, i;
  889. if (!(opts = string_for_env_opt(optype, opts, FALSE)))
  890. return;
  891. escapes(opts, opts);
  892. length = strlen(opts);
  893. if (length > WARNCOUNT) length = WARNCOUNT;
  894. /* match the form obtained from PC configuration files */
  895. for (i = 0; i < length; i++)
  896. translate[i] = (((i < WARNCOUNT) && opts[i]) ?
  897. (uchar) opts[i] : def_warnsyms[i].sym);
  898. assign_warnings(translate);
  899. }
  900. void
  901. assign_warnings(graph_chars)
  902. register uchar *graph_chars;
  903. {
  904. int i;
  905. for (i = 0; i < WARNCOUNT; i++)
  906. if (graph_chars[i]) warnsyms[i] = graph_chars[i];
  907. }
  908. STATIC_OVL int
  909. feature_alert_opts(op, optn)
  910. char *op;
  911. const char *optn;
  912. {
  913. char buf[BUFSZ];
  914. boolean rejectver = FALSE;
  915. unsigned long fnv = get_feature_notice_ver(op); /* version.c */
  916. if (fnv == 0L) return 0;
  917. if (fnv > get_current_feature_ver())
  918. rejectver = TRUE;
  919. else
  920. flags.suppress_alert = fnv;
  921. if (rejectver) {
  922. if (!initial)
  923. You_cant("disable new feature alerts for future versions.");
  924. else {
  925. Sprintf(buf,
  926. "\n%s=%s Invalid reference to a future version ignored",
  927. optn, op);
  928. badoption(buf);
  929. }
  930. return 0;
  931. }
  932. if (!initial) {
  933. Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
  934. FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
  935. pline("Feature change alerts disabled for Slash'EM %s features and prior.",
  936. buf);
  937. }
  938. return 1;
  939. }
  940. void
  941. set_duplicate_opt_detection(on_or_off)
  942. int on_or_off;
  943. {
  944. int k, *optptr;
  945. if (on_or_off != 0) {
  946. /*-- ON --*/
  947. if (iflags.opt_booldup)
  948. impossible("iflags.opt_booldup already on (memory leak)");
  949. iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
  950. optptr = iflags.opt_booldup;
  951. for (k = 0; k < SIZE(boolopt); ++k)
  952. *optptr++ = 0;
  953. if (iflags.opt_compdup)
  954. impossible("iflags.opt_compdup already on (memory leak)");
  955. iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
  956. optptr = iflags.opt_compdup;
  957. for (k = 0; k < SIZE(compopt); ++k)
  958. *optptr++ = 0;
  959. } else {
  960. /*-- OFF --*/
  961. if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
  962. iflags.opt_booldup = (int *)0;
  963. if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
  964. iflags.opt_compdup = (int *)0;
  965. }
  966. }
  967. STATIC_OVL void
  968. duplicate_opt_detection(opts, bool_or_comp)
  969. const char *opts;
  970. int bool_or_comp; /* 0 == boolean option, 1 == compound */
  971. {
  972. int i, *optptr;
  973. #if defined(MAC)
  974. /* the Mac has trouble dealing with the output of messages while
  975. * processing the config file. That should get fixed one day.
  976. * For now just return.
  977. */
  978. return;
  979. #endif
  980. if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) {
  981. for (i = 0; boolopt[i].name; i++) {
  982. if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
  983. optptr = iflags.opt_booldup + i;
  984. if (*optptr == 1) {
  985. raw_printf(
  986. "\nWarning - Boolean option specified multiple times: %s.\n",
  987. opts);
  988. wait_synch();
  989. }
  990. *optptr += 1;
  991. break; /* don't match multiple options */
  992. }
  993. }
  994. } else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) {
  995. for (i = 0; compopt[i].name; i++) {
  996. if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) {
  997. optptr = iflags.opt_compdup + i;
  998. if (*optptr == 1) {
  999. raw_printf(
  1000. "\nWarning - compound option specified multiple times: %s.\n",
  1001. compopt[i].name);
  1002. wait_synch();
  1003. }
  1004. *optptr += 1;
  1005. break; /* don't match multiple options */
  1006. }
  1007. }
  1008. }
  1009. }
  1010. #ifdef MENU_COLOR
  1011. extern struct menucoloring *menu_colorings;
  1012. static const struct {
  1013. const char *name;
  1014. const int color;
  1015. } colornames[] = {
  1016. {"black", CLR_BLACK},
  1017. {"red", CLR_RED},
  1018. {"green", CLR_GREEN},
  1019. {"brown", CLR_BROWN},
  1020. {"blue", CLR_BLUE},
  1021. {"magenta", CLR_MAGENTA},
  1022. {"cyan", CLR_CYAN},
  1023. {"gray", CLR_GRAY},
  1024. {"orange", CLR_ORANGE},
  1025. {"lightgreen", CLR_BRIGHT_GREEN},
  1026. {"yellow", CLR_YELLOW},
  1027. {"lightblue", CLR_BRIGHT_BLUE},
  1028. {"lightmagenta", CLR_BRIGHT_MAGENTA},
  1029. {"lightcyan", CLR_BRIGHT_CYAN},
  1030. {"white", CLR_WHITE}
  1031. };
  1032. static const struct {
  1033. const char *name;
  1034. const int attr;
  1035. } attrnames[] = {
  1036. {"none", ATR_NONE},
  1037. {"bold", ATR_BOLD},
  1038. {"dim", ATR_DIM},
  1039. {"underline", ATR_ULINE},
  1040. {"blink", ATR_BLINK},
  1041. {"inverse", ATR_INVERSE}
  1042. };
  1043. /* parse '"regex_string"=color' and add it to menucoloring */
  1044. boolean
  1045. add_menu_coloring(str)
  1046. char *str;
  1047. {
  1048. int i, c = NO_COLOR, a = ATR_NONE;
  1049. struct menucoloring *tmp;
  1050. char *tmps, *cs = strchr(str, '=');
  1051. #ifdef POSIX_REGEX
  1052. int errnum;
  1053. char errbuf[80];
  1054. #endif
  1055. const char *err = (char *)0;
  1056. if (!cs || !str) return FALSE;
  1057. tmps = cs;
  1058. tmps++;
  1059. while (*tmps && isspace(*tmps)) tmps++;
  1060. for (i = 0; i < SIZE(colornames); i++)
  1061. if (strstri(tmps, colornames[i].name) == tmps) {
  1062. c = colornames[i].color;
  1063. break;
  1064. }
  1065. if ((i == SIZE(colornames)) && (*tmps >= '0' && *tmps <='9'))
  1066. c = atoi(tmps);
  1067. if (c > 15) return FALSE;
  1068. tmps = strchr(str, '&');
  1069. if (tmps) {
  1070. tmps++;
  1071. while (*tmps && isspace(*tmps)) tmps++;
  1072. for (i = 0; i < SIZE(attrnames); i++)
  1073. if (strstri(tmps, attrnames[i].name) == tmps) {
  1074. a = attrnames[i].attr;
  1075. break;
  1076. }
  1077. if ((i == SIZE(attrnames)) && (*tmps >= '0' && *tmps <='9'))
  1078. a = atoi(tmps);
  1079. }
  1080. *cs = '\0';
  1081. tmps = str;
  1082. if ((*tmps == '"') || (*tmps == '\'')) {
  1083. cs--;
  1084. while (isspace(*cs)) cs--;
  1085. if (*cs == *tmps) {
  1086. *cs = '\0';
  1087. tmps++;
  1088. }
  1089. }
  1090. tmp = (struct menucoloring *)alloc(sizeof(struct menucoloring));
  1091. #ifdef USE_REGEX_MATCH
  1092. # ifdef GNU_REGEX
  1093. tmp->match.translate = 0;
  1094. tmp->match.fastmap = 0;
  1095. tmp->match.buffer = 0;
  1096. tmp->match.allocated = 0;
  1097. tmp->match.regs_allocated = REGS_FIXED;
  1098. err = re_compile_pattern(tmps, strlen(tmps), &tmp->match);
  1099. # else
  1100. # ifdef POSIX_REGEX
  1101. errnum = regcomp(&tmp->match, tmps, REG_EXTENDED | REG_NOSUB);
  1102. if (errnum != 0) {
  1103. regerror(errnum, &tmp->match, errbuf, sizeof(errbuf));
  1104. err = errbuf;
  1105. }
  1106. # endif
  1107. # endif
  1108. #else
  1109. tmp->match = (char *)alloc(strlen(tmps)+1);
  1110. (void) memcpy((genericptr_t)tmp->match, (genericptr_t)tmps, strlen(tmps)+1);
  1111. #endif
  1112. if (err) {
  1113. raw_printf("\nMenucolor regex error: %s\n", err);
  1114. wait_synch();
  1115. free(tmp);
  1116. return FALSE;
  1117. } else {
  1118. tmp->next = menu_colorings;
  1119. tmp->color = c;
  1120. tmp->attr = a;
  1121. menu_colorings = tmp;
  1122. return TRUE;
  1123. }
  1124. }
  1125. #endif /* MENU_COLOR */
  1126. void
  1127. parseoptions(opts, tinitial, tfrom_file)
  1128. register char *opts;
  1129. boolean tinitial, tfrom_file;
  1130. {
  1131. register char *op;
  1132. unsigned num;
  1133. boolean negated;
  1134. int i;
  1135. const char *fullname;
  1136. initial = tinitial;
  1137. from_file = tfrom_file;
  1138. if ((op = index(opts, ',')) != 0) {
  1139. *op++ = 0;
  1140. parseoptions(op, initial, from_file);
  1141. }
  1142. if (strlen(opts) > BUFSZ/2) {
  1143. badoption("option too long");
  1144. return;
  1145. }
  1146. /* strip leading and trailing white space */
  1147. while (isspace((int)*opts)) opts++;
  1148. op = eos(opts);
  1149. while (--op >= opts && isspace((int)*op)) *op = '\0';
  1150. if (!*opts) return;
  1151. negated = FALSE;
  1152. while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
  1153. if (*opts == '!') opts++; else opts += 2;
  1154. negated = !negated;
  1155. }
  1156. /* variant spelling */
  1157. if (match_optname(opts, "colour", 5, FALSE))
  1158. Strcpy(opts, "color"); /* fortunately this isn't longer */
  1159. if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */
  1160. duplicate_opt_detection(opts, 1); /* 1 means compound opts */
  1161. /* special boolean options */
  1162. if (match_optname(opts, "female", 3, FALSE)) {
  1163. if(!initial && flags.female == negated)
  1164. pline("That is not anatomically possible.");
  1165. else
  1166. flags.initgend = flags.female = !negated;
  1167. return;
  1168. }
  1169. if (match_optname(opts, "male", 4, FALSE)) {
  1170. if(!initial && flags.female != negated)
  1171. pline("That is not anatomically possible.");
  1172. else
  1173. flags.initgend = flags.female = negated;
  1174. return;
  1175. }
  1176. #if defined(MICRO) && !defined(AMIGA)
  1177. /* included for compatibility with old NetHack.cnf files */
  1178. if (match_optname(opts, "IBM_", 4, FALSE)) {
  1179. iflags.BIOS = !negated;
  1180. return;
  1181. }
  1182. #endif /* MICRO */
  1183. /* compound options */
  1184. fullname = "pettype";
  1185. if (match_optname(opts, fullname, 3, TRUE)) {
  1186. if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
  1187. if (negated) bad_negation(fullname, TRUE);
  1188. else switch (*op) {
  1189. case 'd': /* dog */
  1190. case 'D':
  1191. preferred_pet = 'd';
  1192. break;
  1193. case 'c': /* cat */
  1194. case 'C':
  1195. case 'f': /* feline */
  1196. case 'F':
  1197. preferred_pet = 'c';
  1198. break;
  1199. case 'n': /* no pet */
  1200. case 'N':
  1201. preferred_pet = 'n';
  1202. break;
  1203. default:
  1204. pline("Unrecognized pet type '%s'.", op);
  1205. break;
  1206. }
  1207. } else if (negated) preferred_pet = 'n';
  1208. return;
  1209. }
  1210. fullname = "ghoulname";
  1211. if (match_optname(opts, fullname, 3, TRUE)) {
  1212. if (negated) bad_negation(fullname, FALSE);
  1213. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1214. nmcpy(ghoulname, op, PL_PSIZ);
  1215. return;
  1216. }
  1217. fullname = "wolfname";
  1218. if (match_optname(opts, fullname, 3, TRUE)) {
  1219. if (negated) bad_negation(fullname, FALSE);
  1220. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1221. nmcpy(wolfname, op, PL_PSIZ);
  1222. return;
  1223. }
  1224. fullname = "catname";
  1225. if (match_optname(opts, fullname, 3, TRUE)) {
  1226. if (negated) bad_negation(fullname, FALSE);
  1227. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1228. nmcpy(catname, op, PL_PSIZ);
  1229. return;
  1230. }
  1231. fullname = "dogname";
  1232. if (match_optname(opts, fullname, 3, TRUE)) {
  1233. if (negated) bad_negation(fullname, FALSE);
  1234. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1235. nmcpy(dogname, op, PL_PSIZ);
  1236. return;
  1237. }
  1238. fullname = "horsename";
  1239. if (match_optname(opts, fullname, 5, TRUE)) {
  1240. if (negated) bad_negation(fullname, FALSE);
  1241. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1242. nmcpy(horsename, op, PL_PSIZ);
  1243. return;
  1244. }
  1245. /* menucolor:"regex_string"=color */
  1246. fullname = "menucolor";
  1247. if (match_optname(opts, fullname, 9, TRUE)) {
  1248. #ifdef MENU_COLOR
  1249. if (negated) bad_negation(fullname, FALSE);
  1250. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1251. if (!add_menu_coloring(op))
  1252. badoption(opts);
  1253. #endif
  1254. return;
  1255. }
  1256. fullname = "number_pad";
  1257. if (match_optname(opts, fullname, 10, TRUE)) {
  1258. boolean compat = (strlen(opts) <= 10);
  1259. op = string_for_opt(opts, (compat || !initial));
  1260. if (!op) {
  1261. if (compat || negated || initial) {
  1262. /* for backwards compatibility, "number_pad" without a
  1263. value is a synonym for number_pad:1 */
  1264. iflags.num_pad = !negated;
  1265. if (iflags.num_pad) iflags.num_pad_mode = 0;
  1266. number_pad(iflags.num_pad);
  1267. }
  1268. return;
  1269. }
  1270. if (negated) {
  1271. bad_negation("number_pad", TRUE);
  1272. return;
  1273. }
  1274. if (*op == '1' || *op == '2') {
  1275. iflags.num_pad = 1;
  1276. if (*op == '2') iflags.num_pad_mode = 1;
  1277. else iflags.num_pad_mode = 0;
  1278. number_pad(1);
  1279. } else if (*op == '0') {
  1280. iflags.num_pad = 0;
  1281. iflags.num_pad_mode = 0;
  1282. number_pad(0);
  1283. } else badoption(opts);
  1284. return;
  1285. }
  1286. fullname = "runmode";
  1287. if (match_optname(opts, fullname, 4, TRUE)) {
  1288. if (negated) {
  1289. iflags.runmode = RUN_TPORT;
  1290. } else if ((op = string_for_opt(opts, FALSE)) != 0) {
  1291. if (!strncmpi(op, "teleport", strlen(op)))
  1292. iflags.runmode = RUN_TPORT;
  1293. else if (!strncmpi(op, "run", strlen(op)))
  1294. iflags.runmode = RUN_LEAP;
  1295. else if (!strncmpi(op, "walk", strlen(op)))
  1296. iflags.runmode = RUN_STEP;
  1297. else if (!strncmpi(op, "crawl", strlen(op)))
  1298. iflags.runmode = RUN_CRAWL;
  1299. else
  1300. badoption(opts);
  1301. }
  1302. return;
  1303. }
  1304. fullname = "msghistory";
  1305. if (match_optname(opts, fullname, 3, TRUE)) {
  1306. op = string_for_env_opt(fullname, opts, negated);
  1307. if ((negated && !op) || (!negated && op)) {
  1308. iflags.msg_history = negated ? 0 : atoi(op);
  1309. } else if (negated) bad_negation(fullname, TRUE);
  1310. return;
  1311. }
  1312. fullname="msg_window";
  1313. /* msg_window:single, combo, full or reversed */
  1314. if (match_optname(opts, fullname, 4, TRUE)) {
  1315. /* allow option to be silently ignored by non-tty ports */
  1316. #ifdef TTY_GRAPHICS
  1317. int tmp;
  1318. if (!(op = string_for_opt(opts, TRUE))) {
  1319. tmp = negated ? 's' : 'f';
  1320. } else {
  1321. if (negated) {
  1322. bad_negation(fullname, TRUE);
  1323. return;
  1324. }
  1325. tmp = tolower(*op);
  1326. }
  1327. switch (tmp) {
  1328. case 's': /* single message history cycle (default if negated) */
  1329. iflags.prevmsg_window = 's';
  1330. break;
  1331. case 'c': /* combination: two singles, then full page reversed */
  1332. iflags.prevmsg_window = 'c';
  1333. break;
  1334. case 'f': /* full page (default if no opts) */
  1335. iflags.prevmsg_window = 'f';
  1336. break;
  1337. case 'r': /* full page (reversed) */
  1338. iflags.prevmsg_window = 'r';
  1339. break;
  1340. default:
  1341. badoption(opts);
  1342. }
  1343. #endif
  1344. return;
  1345. }
  1346. /* WINCAP
  1347. * setting font options */
  1348. fullname = "font";
  1349. if (!strncmpi(opts, fullname, 4))
  1350. {
  1351. int wintype = -1;
  1352. char *fontopts = opts + 4;
  1353. if (!strncmpi(fontopts, "map", 3) ||
  1354. !strncmpi(fontopts, "_map", 4))
  1355. wintype = NHW_MAP;
  1356. else if (!strncmpi(fontopts, "message", 7) ||
  1357. !strncmpi(fontopts, "_message", 8))
  1358. wintype = NHW_MESSAGE;
  1359. else if (!strncmpi(fontopts, "text", 4) ||
  1360. !strncmpi(fontopts, "_text", 5))
  1361. wintype = NHW_TEXT;
  1362. else if (!strncmpi(fontopts, "menu", 4) ||
  1363. !strncmpi(fontopts, "_menu", 5))
  1364. wintype = NHW_MENU;
  1365. else if (!strncmpi(fontopts, "status", 6) ||
  1366. !strncmpi(fontopts, "_status", 7))
  1367. wintype = NHW_STATUS;
  1368. else if (!strncmpi(fontopts, "_size", 5)) {
  1369. if (!strncmpi(fontopts, "_size_map", 8))
  1370. wintype = NHW_MAP;
  1371. else if (!strncmpi(fontopts, "_size_message", 12))
  1372. wintype = NHW_MESSAGE;
  1373. else if (!strncmpi(fontopts, "_size_text", 9))
  1374. wintype = NHW_TEXT;
  1375. else if (!strncmpi(fontopts, "_size_menu", 9))
  1376. wintype = NHW_MENU;
  1377. else if (!strncmpi(fontopts, "_size_status", 11))
  1378. wintype = NHW_STATUS;
  1379. else {
  1380. badoption(opts);
  1381. return;
  1382. }
  1383. if (wintype > 0 && !negated &&
  1384. (op = string_for_opt(opts, FALSE)) != 0) {
  1385. switch(wintype) {
  1386. case NHW_MAP:
  1387. iflags.wc_fontsiz_map = atoi(op);
  1388. break;
  1389. case NHW_MESSAGE:
  1390. iflags.wc_fontsiz_message = atoi(op);
  1391. break;
  1392. case NHW_TEXT:
  1393. iflags.wc_fontsiz_text = atoi(op);
  1394. break;
  1395. case NHW_MENU:
  1396. iflags.wc_fontsiz_menu = atoi(op);
  1397. break;
  1398. case NHW_STATUS:
  1399. iflags.wc_fontsiz_status = atoi(op);
  1400. break;
  1401. }
  1402. }
  1403. return;
  1404. } else {
  1405. badoption(opts);
  1406. }
  1407. if (wintype > 0 &&
  1408. (op = string_for_opt(opts, FALSE)) != 0) {
  1409. wc_set_font_name(wintype, op);
  1410. #ifdef MAC
  1411. set_font_name (wintype, op);
  1412. #endif
  1413. return;
  1414. } else if (negated) bad_negation(fullname, TRUE);
  1415. return;
  1416. }
  1417. #ifdef CHANGE_COLOR
  1418. if (match_optname(opts, "palette", 3, TRUE)
  1419. # ifdef MAC
  1420. || match_optname(opts, "hicolor", 3, TRUE)
  1421. # endif
  1422. ) {
  1423. int color_number, color_incr;
  1424. # ifdef MAC
  1425. if (match_optname(opts, "hicolor", 3, TRUE)) {
  1426. if (negated) {
  1427. bad_negation("hicolor", FALSE);
  1428. return;
  1429. }
  1430. color_number = CLR_MAX + 4; /* HARDCODED inverse number */
  1431. color_incr = -1;
  1432. } else {
  1433. # endif
  1434. if (negated) {
  1435. bad_negation("palette", FALSE);
  1436. return;
  1437. }
  1438. color_number = 0;
  1439. color_incr = 1;
  1440. # ifdef MAC
  1441. }
  1442. # endif
  1443. if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
  1444. char *pt = op;
  1445. int cnt, tmp, reverse;
  1446. long rgb;
  1447. while (*pt && color_number >= 0) {
  1448. cnt = 3;
  1449. rgb = 0L;
  1450. if (*pt == '-') {
  1451. reverse = 1;
  1452. pt++;
  1453. } else {
  1454. reverse = 0;
  1455. }
  1456. while (cnt-- > 0) {
  1457. if (*pt && *pt != '/') {
  1458. # ifdef AMIGA
  1459. rgb <<= 4;
  1460. # else
  1461. rgb <<= 8;
  1462. # endif
  1463. tmp = *(pt++);
  1464. if (isalpha(tmp)) {
  1465. tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
  1466. } else {
  1467. tmp &= 0xf; /* Digits in ASCII too... */
  1468. }
  1469. # ifndef AMIGA
  1470. /* Add an extra so we fill f -> ff and 0 -> 00 */
  1471. rgb += tmp << 4;
  1472. # endif
  1473. rgb += tmp;
  1474. }
  1475. }
  1476. if (*pt == '/') {
  1477. pt++;
  1478. }
  1479. change_color(color_number, rgb, reverse);
  1480. color_number += color_incr;
  1481. }
  1482. }
  1483. if (!initial) {
  1484. need_redraw = TRUE;
  1485. }
  1486. return;
  1487. }
  1488. #endif /* CHANGE_COLOR */
  1489. if (match_optname(opts, "fruit", 2, TRUE)) {
  1490. char empty_str = '\0';
  1491. op = string_for_opt(opts, negated);
  1492. if (negated) {
  1493. if (op) {
  1494. bad_negation("fruit", TRUE);
  1495. return;
  1496. }
  1497. op = &empty_str;
  1498. goto goodfruit;
  1499. }
  1500. if (!op) return;
  1501. if (!initial) {
  1502. struct fruit *f;
  1503. num = 0;
  1504. for(f=ffruit; f; f=f->nextf) {
  1505. if (!strcmp(op, f->fname)) goto goodfruit;
  1506. num++;
  1507. }
  1508. if (num >= 100) {
  1509. pline("Doing that so many times isn't very fruitful.");
  1510. return;
  1511. }
  1512. }
  1513. goodfruit:
  1514. nmcpy(pl_fruit, op, PL_FSIZ);
  1515. /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
  1516. if (!*pl_fruit)
  1517. nmcpy(pl_fruit, "slime mold", PL_FSIZ);
  1518. if (!initial)
  1519. (void)fruitadd(pl_fruit);
  1520. /* If initial, then initoptions is allowed to do it instead
  1521. * of here (initoptions always has to do it even if there's
  1522. * no fruit option at all. Also, we don't want people
  1523. * setting multiple fruits in their options.)
  1524. */
  1525. return;
  1526. }
  1527. /* graphics:string */
  1528. fullname = "graphics";
  1529. if (match_optname(opts, fullname, 2, TRUE)) {
  1530. if (negated) bad_negation(fullname, FALSE);
  1531. else graphics_opts(opts, fullname, MAXPCHARS, 0);
  1532. return;
  1533. }
  1534. fullname = "dungeon";
  1535. if (match_optname(opts, fullname, 2, TRUE)) {
  1536. if (negated) bad_negation(fullname, FALSE);
  1537. else graphics_opts(opts, fullname, MAXDCHARS, 0);
  1538. return;
  1539. }
  1540. fullname = "traps";
  1541. if (match_optname(opts, fullname, 2, TRUE)) {
  1542. if (negated) bad_negation(fullname, FALSE);
  1543. else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS);
  1544. return;
  1545. }
  1546. fullname = "effects";
  1547. if (match_optname(opts, fullname, 2, TRUE)) {
  1548. if (negated) bad_negation(fullname, FALSE);
  1549. else
  1550. graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS);
  1551. return;
  1552. }
  1553. /* objects:string */
  1554. fullname = "objects";
  1555. if (match_optname(opts, fullname, 7, TRUE)) {
  1556. int length;
  1557. if (negated) {
  1558. bad_negation(fullname, FALSE);
  1559. return;
  1560. }
  1561. if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
  1562. return;
  1563. escapes(opts, opts);
  1564. /*
  1565. * Override the default object class symbols. The first
  1566. * object in the object class is the "random object". I
  1567. * don't want to use 0 as an object class, so the "random
  1568. * object" is basically a place holder.
  1569. *
  1570. * The object class symbols have already been initialized in
  1571. * initoptions().
  1572. */
  1573. length = strlen(opts);
  1574. if (length >= MAXOCLASSES)
  1575. length = MAXOCLASSES-1; /* don't count RANDOM_OBJECT */
  1576. for (i = 0; i < length; i++)
  1577. oc_syms[i+1] = (uchar) opts[i];
  1578. return;
  1579. }
  1580. /* monsters:string */
  1581. fullname = "monsters";
  1582. if (match_optname(opts, fullname, 8, TRUE)) {
  1583. int length;
  1584. if (negated) {
  1585. bad_negation(fullname, FALSE);
  1586. return;
  1587. }
  1588. if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
  1589. return;
  1590. escapes(opts, opts);
  1591. /* Override default mon class symbols set in initoptions(). */
  1592. length = strlen(opts);
  1593. if (length >= MAXMCLASSES)
  1594. length = MAXMCLASSES-1; /* mon class 0 unused */
  1595. for (i = 0; i < length; i++)
  1596. monsyms[i+1] = (uchar) opts[i];
  1597. return;
  1598. }
  1599. fullname = "warnings";
  1600. if (match_optname(opts, fullname, 5, TRUE)) {
  1601. if (negated) bad_negation(fullname, FALSE);
  1602. else warning_opts(opts, fullname);
  1603. return;
  1604. }
  1605. /* boulder:symbol */
  1606. fullname = "boulder";
  1607. if (match_optname(opts, ful

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