PageRenderTime 77ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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, fullname, 7, TRUE)) {
  1608. int clash = 0;
  1609. if (negated) {
  1610. bad_negation(fullname, FALSE);
  1611. return;
  1612. }
  1613. /* if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
  1614. if (!(opts = string_for_opt(opts, FALSE)))
  1615. return;
  1616. escapes(opts, opts);
  1617. if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
  1618. clash = 1;
  1619. else if (opts[0] >= '1' && opts[0] <= '5')
  1620. clash = 2;
  1621. if (clash) {
  1622. /* symbol chosen matches a used monster or warning
  1623. symbol which is not good - reject it*/
  1624. pline(
  1625. "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
  1626. opts[0], (clash == 1) ? "monster" : "warning");
  1627. } else {
  1628. /*
  1629. * Override the default boulder symbol.
  1630. */
  1631. iflags.bouldersym = (uchar) opts[0];
  1632. }
  1633. if (!initial) need_redraw = TRUE;
  1634. return;
  1635. }
  1636. /* name:string */
  1637. fullname = "name";
  1638. if (match_optname(opts, fullname, 4, TRUE)) {
  1639. if (negated) bad_negation(fullname, FALSE);
  1640. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1641. #ifdef PROXY_GRAPHICS
  1642. /*
  1643. * Can't change player name if authentication required.
  1644. */
  1645. if (!getenv("HACKAUTHENTICATION"))
  1646. #endif
  1647. nmcpy(plname, op, PL_NSIZ);
  1648. return;
  1649. }
  1650. /* role:string or character:string */
  1651. fullname = "role";
  1652. if (match_optname(opts, fullname, 4, TRUE) ||
  1653. match_optname(opts, (fullname = "character"), 4, TRUE)) {
  1654. if (negated) bad_negation(fullname, FALSE);
  1655. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1656. if ((flags.initrole = str2role(op)) == ROLE_NONE)
  1657. badoption(opts);
  1658. else /* Backwards compatibility */
  1659. nmcpy(pl_character, op, PL_NSIZ);
  1660. }
  1661. return;
  1662. }
  1663. /* race:string */
  1664. fullname = "race";
  1665. if (match_optname(opts, fullname, 4, TRUE)) {
  1666. if (negated) bad_negation(fullname, FALSE);
  1667. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1668. if ((flags.initrace = str2race(op)) == ROLE_NONE)
  1669. badoption(opts);
  1670. else /* Backwards compatibility */
  1671. pl_race = *op;
  1672. }
  1673. return;
  1674. }
  1675. /* gender:string */
  1676. fullname = "gender";
  1677. if (match_optname(opts, fullname, 4, TRUE)) {
  1678. if (negated) bad_negation(fullname, FALSE);
  1679. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1680. if ((flags.initgend = str2gend(op)) == ROLE_NONE)
  1681. badoption(opts);
  1682. else
  1683. flags.female = flags.initgend;
  1684. }
  1685. return;
  1686. }
  1687. /* altkeyhandler:string */
  1688. fullname = "altkeyhandler";
  1689. if (match_optname(opts, fullname, 4, TRUE)) {
  1690. if (negated) bad_negation(fullname, FALSE);
  1691. else if ((op = string_for_opt(opts, negated))) {
  1692. #ifdef WIN32CON
  1693. (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
  1694. load_keyboard_handler();
  1695. #endif
  1696. }
  1697. return;
  1698. }
  1699. /* WINCAP
  1700. * align_status:[left|top|right|bottom] */
  1701. fullname = "align_status";
  1702. if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
  1703. op = string_for_opt(opts, negated);
  1704. if (op && !negated) {
  1705. if (!strncmpi (op, "left", sizeof("left")-1))
  1706. iflags.wc_align_status = ALIGN_LEFT;
  1707. else if (!strncmpi (op, "top", sizeof("top")-1))
  1708. iflags.wc_align_status = ALIGN_TOP;
  1709. else if (!strncmpi (op, "right", sizeof("right")-1))
  1710. iflags.wc_align_status = ALIGN_RIGHT;
  1711. else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
  1712. iflags.wc_align_status = ALIGN_BOTTOM;
  1713. else
  1714. badoption(opts);
  1715. } else if (negated) bad_negation(fullname, TRUE);
  1716. return;
  1717. }
  1718. /* WINCAP
  1719. * align_message:[left|top|right|bottom] */
  1720. fullname = "align_message";
  1721. if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
  1722. op = string_for_opt(opts, negated);
  1723. if (op && !negated) {
  1724. if (!strncmpi (op, "left", sizeof("left")-1))
  1725. iflags.wc_align_message = ALIGN_LEFT;
  1726. else if (!strncmpi (op, "top", sizeof("top")-1))
  1727. iflags.wc_align_message = ALIGN_TOP;
  1728. else if (!strncmpi (op, "right", sizeof("right")-1))
  1729. iflags.wc_align_message = ALIGN_RIGHT;
  1730. else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
  1731. iflags.wc_align_message = ALIGN_BOTTOM;
  1732. else
  1733. badoption(opts);
  1734. } else if (negated) bad_negation(fullname, TRUE);
  1735. return;
  1736. }
  1737. /* align:string */
  1738. fullname = "align";
  1739. if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
  1740. if (negated) bad_negation(fullname, FALSE);
  1741. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
  1742. if ((flags.initalign = str2align(op)) == ROLE_NONE)
  1743. badoption(opts);
  1744. return;
  1745. }
  1746. /* the order to list the pack */
  1747. fullname = "packorder";
  1748. if (match_optname(opts, fullname, 4, TRUE)) {
  1749. if (negated) {
  1750. bad_negation(fullname, FALSE);
  1751. return;
  1752. } else if (!(op = string_for_opt(opts, FALSE))) return;
  1753. if (!change_inv_order(op))
  1754. badoption(opts);
  1755. return;
  1756. }
  1757. /* maximum burden picked up before prompt (Warren Cheung) */
  1758. fullname = "pickup_burden";
  1759. if (match_optname(opts, fullname, 8, TRUE)) {
  1760. if (negated) {
  1761. bad_negation(fullname, FALSE);
  1762. return;
  1763. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  1764. switch (tolower(*op)) {
  1765. /* Unencumbered */
  1766. case 'u':
  1767. flags.pickup_burden = UNENCUMBERED;
  1768. break;
  1769. /* Burdened (slight encumbrance) */
  1770. case 'b':
  1771. flags.pickup_burden = SLT_ENCUMBER;
  1772. break;
  1773. /* streSsed (moderate encumbrance) */
  1774. case 's':
  1775. flags.pickup_burden = MOD_ENCUMBER;
  1776. break;
  1777. /* straiNed (heavy encumbrance) */
  1778. case 'n':
  1779. flags.pickup_burden = HVY_ENCUMBER;
  1780. break;
  1781. /* OverTaxed (extreme encumbrance) */
  1782. case 'o':
  1783. case 't':
  1784. flags.pickup_burden = EXT_ENCUMBER;
  1785. break;
  1786. /* overLoaded */
  1787. case 'l':
  1788. flags.pickup_burden = OVERLOADED;
  1789. break;
  1790. default:
  1791. badoption(opts);
  1792. }
  1793. }
  1794. return;
  1795. }
  1796. /* types of objects to pick up automatically */
  1797. if (match_optname(opts, "pickup_types", 8, TRUE)) {
  1798. char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
  1799. qbuf[QBUFSZ], abuf[BUFSZ];
  1800. int oc_sym;
  1801. boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
  1802. oc_to_str(flags.pickup_types, tbuf);
  1803. flags.pickup_types[0] = '\0'; /* all */
  1804. op = string_for_opt(opts, (compat || !initial));
  1805. if (!op) {
  1806. if (compat || negated || initial) {
  1807. /* for backwards compatibility, "pickup" without a
  1808. value is a synonym for autopickup of all types
  1809. (and during initialization, we can't prompt yet) */
  1810. flags.pickup = !negated;
  1811. return;
  1812. }
  1813. oc_to_str(flags.inv_order, ocl);
  1814. use_menu = TRUE;
  1815. if (flags.menu_style == MENU_TRADITIONAL ||
  1816. flags.menu_style == MENU_COMBINATION) {
  1817. use_menu = FALSE;
  1818. Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
  1819. ocl, *tbuf ? tbuf : "all");
  1820. getlin(qbuf, abuf);
  1821. op = mungspaces(abuf);
  1822. if (abuf[0] == '\0' || abuf[0] == '\033')
  1823. op = tbuf; /* restore */
  1824. else if (abuf[0] == 'm')
  1825. use_menu = TRUE;
  1826. }
  1827. if (use_menu) {
  1828. (void) choose_classes_menu("Auto-Pickup what?", 1,
  1829. TRUE, ocl, tbuf);
  1830. op = tbuf;
  1831. }
  1832. }
  1833. if (negated) {
  1834. bad_negation("pickup_types", TRUE);
  1835. return;
  1836. }
  1837. while (*op == ' ') op++;
  1838. if (*op != 'a' && *op != 'A') {
  1839. num = 0;
  1840. while (*op) {
  1841. oc_sym = def_char_to_objclass(*op);
  1842. /* make sure all are valid obj symbols occuring once */
  1843. if (oc_sym != MAXOCLASSES &&
  1844. !index(flags.pickup_types, oc_sym)) {
  1845. flags.pickup_types[num] = (char)oc_sym;
  1846. flags.pickup_types[++num] = '\0';
  1847. } else
  1848. badopt = TRUE;
  1849. op++;
  1850. }
  1851. if (badopt) badoption(opts);
  1852. }
  1853. return;
  1854. }
  1855. /* WINCAP
  1856. * player_selection: dialog | prompts */
  1857. fullname = "player_selection";
  1858. if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
  1859. op = string_for_opt(opts, negated);
  1860. if (op && !negated) {
  1861. if (!strncmpi (op, "dialog", sizeof("dialog")-1))
  1862. iflags.wc_player_selection = VIA_DIALOG;
  1863. else if (!strncmpi (op, "prompt", sizeof("prompt")-1))
  1864. iflags.wc_player_selection = VIA_PROMPTS;
  1865. else
  1866. badoption(opts);
  1867. } else if (negated) bad_negation(fullname, TRUE);
  1868. return;
  1869. }
  1870. /* things to disclose at end of game */
  1871. if (match_optname(opts, "disclose", 7, TRUE)) {
  1872. /*
  1873. * The order that the end_disclore options are stored:
  1874. * inventory, attribs, vanquished, genocided, conduct
  1875. * There is an array in flags:
  1876. * end_disclose[NUM_DISCLOSURE_OPT];
  1877. * with option settings for the each of the following:
  1878. * iagvc [see disclosure_options in decl.c]:
  1879. * Legal setting values in that array are:
  1880. * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
  1881. * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
  1882. * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
  1883. * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
  1884. *
  1885. * Those setting values can be used in the option
  1886. * string as a prefix to get the desired behaviour.
  1887. *
  1888. * For backward compatibility, no prefix is required,
  1889. * and the presence of a i,a,g,v, or c without a prefix
  1890. * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
  1891. */
  1892. boolean badopt = FALSE;
  1893. int idx, prefix_val;
  1894. op = string_for_opt(opts, TRUE);
  1895. if (op && negated) {
  1896. bad_negation("disclose", TRUE);
  1897. return;
  1898. }
  1899. /* "disclose" without a value means "all with prompting"
  1900. and negated means "none without prompting" */
  1901. if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
  1902. if (op && !strcmpi(op, "none")) negated = TRUE;
  1903. for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
  1904. flags.end_disclose[num] = negated ?
  1905. DISCLOSE_NO_WITHOUT_PROMPT :
  1906. DISCLOSE_PROMPT_DEFAULT_YES;
  1907. return;
  1908. }
  1909. num = 0;
  1910. prefix_val = -1;
  1911. while (*op && num < sizeof flags.end_disclose - 1) {
  1912. register char c, *dop;
  1913. static char valid_settings[] = {
  1914. DISCLOSE_PROMPT_DEFAULT_YES,
  1915. DISCLOSE_PROMPT_DEFAULT_NO,
  1916. DISCLOSE_YES_WITHOUT_PROMPT,
  1917. DISCLOSE_NO_WITHOUT_PROMPT,
  1918. '\0'
  1919. };
  1920. c = lowc(*op);
  1921. if (c == 'k') c = 'v'; /* killed -> vanquished */
  1922. dop = index(disclosure_options, c);
  1923. if (dop) {
  1924. idx = dop - disclosure_options;
  1925. if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
  1926. impossible("bad disclosure index %d %c",
  1927. idx, c);
  1928. continue;
  1929. }
  1930. if (prefix_val != -1) {
  1931. flags.end_disclose[idx] = prefix_val;
  1932. prefix_val = -1;
  1933. } else
  1934. flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
  1935. } else if (index(valid_settings, c)) {
  1936. prefix_val = c;
  1937. } else if (c == ' ') {
  1938. /* do nothing */
  1939. } else
  1940. badopt = TRUE;
  1941. op++;
  1942. }
  1943. if (badopt) badoption(opts);
  1944. return;
  1945. }
  1946. /* scores:5t[op] 5a[round] o[wn] */
  1947. if (match_optname(opts, "scores", 4, TRUE)) {
  1948. if (negated) {
  1949. bad_negation("scores", FALSE);
  1950. return;
  1951. }
  1952. if (!(op = string_for_opt(opts, FALSE))) return;
  1953. while (*op) {
  1954. int inum = 1;
  1955. if (digit(*op)) {
  1956. inum = atoi(op);
  1957. while (digit(*op)) op++;
  1958. } else if (*op == '!') {
  1959. negated = !negated;
  1960. op++;
  1961. }
  1962. while (*op == ' ') op++;
  1963. switch (*op) {
  1964. case 't':
  1965. case 'T': flags.end_top = inum;
  1966. break;
  1967. case 'a':
  1968. case 'A': flags.end_around = inum;
  1969. break;
  1970. case 'o':
  1971. case 'O': flags.end_own = !negated;
  1972. break;
  1973. default: badoption(opts);
  1974. return;
  1975. }
  1976. while (letter(*++op) || *op == ' ') continue;
  1977. if (*op == '/') op++;
  1978. }
  1979. return;
  1980. }
  1981. fullname = "suppress_alert";
  1982. if (match_optname(opts, fullname, 4, TRUE)) {
  1983. op = string_for_opt(opts, negated);
  1984. if (negated) bad_negation(fullname, FALSE);
  1985. else if (op) (void) feature_alert_opts(op,fullname);
  1986. return;
  1987. }
  1988. fullname = "tileset";
  1989. if (match_optname(opts, fullname, 4, TRUE)) {
  1990. if (negated || (op = string_for_opt(opts, TRUE)) == 0)
  1991. tileset[0] = '\0';
  1992. else {
  1993. /*
  1994. * The tileset may not be defined (yet) if we're
  1995. * in initial mode, otherwise it must exist.
  1996. */
  1997. if (!initial) {
  1998. int len = strlen(op);
  1999. for(i = 0; i < no_tilesets; i++)
  2000. if (len == strlen(tilesets[i].name) &&
  2001. !strncmpi(tilesets[i].name, op, len))
  2002. break;
  2003. if (i == no_tilesets) {
  2004. pline("Tileset %s not defined.", op);
  2005. return;
  2006. }
  2007. else /* Use canonical case */
  2008. strcpy(tileset, tilesets[i].name);
  2009. }
  2010. else
  2011. nmcpy(tileset, op, PL_PSIZ);
  2012. }
  2013. if (!initial)
  2014. need_redraw = TRUE;
  2015. return;
  2016. }
  2017. #if defined(VIDEOSHADES) && !defined(NO_TERMS)
  2018. /* videocolors:string */
  2019. fullname = "videocolors";
  2020. if (match_optname(opts, fullname, 6, TRUE) ||
  2021. match_optname(opts, "videocolours", 10, TRUE)) {
  2022. if (negated) {
  2023. bad_negation(fullname, FALSE);
  2024. return;
  2025. }
  2026. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  2027. return;
  2028. }
  2029. if (!assign_videocolors(opts))
  2030. badoption(opts);
  2031. return;
  2032. }
  2033. # ifdef MSDOS
  2034. /* videoshades:string */
  2035. fullname = "videoshades";
  2036. if (match_optname(opts, fullname, 6, TRUE)) {
  2037. if (negated) {
  2038. bad_negation(fullname, FALSE);
  2039. return;
  2040. }
  2041. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  2042. return;
  2043. }
  2044. if (!assign_videoshades(opts))
  2045. badoption(opts);
  2046. return;
  2047. }
  2048. # endif
  2049. #endif /* VIDEOSHADES */
  2050. #ifdef MSDOS
  2051. # ifdef NO_TERMS
  2052. /* video:string -- must be after longer tests */
  2053. fullname = "video";
  2054. if (match_optname(opts, fullname, 5, TRUE)) {
  2055. if (negated) {
  2056. bad_negation(fullname, FALSE);
  2057. return;
  2058. }
  2059. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  2060. return;
  2061. }
  2062. if (!assign_video(opts))
  2063. badoption(opts);
  2064. return;
  2065. }
  2066. # endif /* NO_TERMS */
  2067. /* soundcard:string -- careful not to match boolean 'sound' */
  2068. fullname = "soundcard";
  2069. if (match_optname(opts, fullname, 6, TRUE)) {
  2070. if (negated) {
  2071. bad_negation(fullname, FALSE);
  2072. return;
  2073. }
  2074. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  2075. return;
  2076. }
  2077. if (!assign_soundcard(opts))
  2078. badoption(opts);
  2079. return;
  2080. }
  2081. #endif /* MSDOS */
  2082. /* WINCAP
  2083. * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
  2084. ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
  2085. fullname = "map_mode";
  2086. if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
  2087. op = string_for_opt(opts, negated);
  2088. if (op && !negated) {
  2089. if (!strncmpi (op, "tiles", sizeof("tiles")-1))
  2090. iflags.wc_map_mode = MAP_MODE_TILES;
  2091. else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
  2092. iflags.wc_map_mode = MAP_MODE_ASCII4x6;
  2093. else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
  2094. iflags.wc_map_mode = MAP_MODE_ASCII6x8;
  2095. else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
  2096. iflags.wc_map_mode = MAP_MODE_ASCII8x8;
  2097. else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
  2098. iflags.wc_map_mode = MAP_MODE_ASCII16x8;
  2099. else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
  2100. iflags.wc_map_mode = MAP_MODE_ASCII7x12;
  2101. else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
  2102. iflags.wc_map_mode = MAP_MODE_ASCII8x12;
  2103. else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
  2104. iflags.wc_map_mode = MAP_MODE_ASCII16x12;
  2105. else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
  2106. iflags.wc_map_mode = MAP_MODE_ASCII12x16;
  2107. else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
  2108. iflags.wc_map_mode = MAP_MODE_ASCII10x18;
  2109. else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
  2110. iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
  2111. else
  2112. badoption(opts);
  2113. } else if (negated) bad_negation(fullname, TRUE);
  2114. return;
  2115. }
  2116. /* WINCAP
  2117. * scroll_amount:nn */
  2118. fullname = "scroll_amount";
  2119. if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
  2120. op = string_for_opt(opts, negated);
  2121. if ((negated && !op) || (!negated && op)) {
  2122. iflags.wc_scroll_amount = negated ? 1 : atoi(op);
  2123. } else if (negated) bad_negation(fullname, TRUE);
  2124. return;
  2125. }
  2126. /* WINCAP
  2127. * scroll_margin:nn */
  2128. fullname = "scroll_margin";
  2129. if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
  2130. op = string_for_opt(opts, negated);
  2131. if ((negated && !op) || (!negated && op)) {
  2132. iflags.wc_scroll_margin = negated ? 5 : atoi(op);
  2133. } else if (negated) bad_negation(fullname, TRUE);
  2134. return;
  2135. }
  2136. fullname = "subkeyvalue";
  2137. if (match_optname(opts, fullname, 5, TRUE)) {
  2138. if (negated) bad_negation(fullname, FALSE);
  2139. else {
  2140. #if defined(WIN32CON)
  2141. op = string_for_opt(opts, 0);
  2142. map_subkeyvalue(op);
  2143. #endif
  2144. }
  2145. return;
  2146. }
  2147. /* WINCAP
  2148. * tile_width:nn */
  2149. fullname = "tile_width";
  2150. if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
  2151. op = string_for_opt(opts, negated);
  2152. if ((negated && !op) || (!negated && op)) {
  2153. iflags.wc_tile_width = negated ? 0 : atoi(op);
  2154. } else if (negated) bad_negation(fullname, TRUE);
  2155. return;
  2156. }
  2157. /* WINCAP
  2158. * tile_file:name */
  2159. fullname = "tile_file";
  2160. if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
  2161. if ((op = string_for_opt(opts, FALSE)) != 0) {
  2162. if (iflags.wc_tile_file) free(iflags.wc_tile_file);
  2163. iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
  2164. Strcpy(iflags.wc_tile_file, op);
  2165. }
  2166. return;
  2167. }
  2168. /* WINCAP
  2169. * tile_height:nn */
  2170. fullname = "tile_height";
  2171. if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
  2172. op = string_for_opt(opts, negated);
  2173. if ((negated && !op) || (!negated && op)) {
  2174. iflags.wc_tile_height = negated ? 0 : atoi(op);
  2175. } else if (negated) bad_negation(fullname, TRUE);
  2176. return;
  2177. }
  2178. /* WINCAP
  2179. * vary_msgcount:nn */
  2180. fullname = "vary_msgcount";
  2181. if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
  2182. op = string_for_opt(opts, negated);
  2183. if ((negated && !op) || (!negated && op)) {
  2184. iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
  2185. } else if (negated) bad_negation(fullname, TRUE);
  2186. return;
  2187. }
  2188. fullname = "windowtype";
  2189. if (match_optname(opts, fullname, 3, TRUE)) {
  2190. if (negated) {
  2191. bad_negation(fullname, FALSE);
  2192. return;
  2193. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
  2194. char buf[WINTYPELEN];
  2195. nmcpy(buf, op, WINTYPELEN);
  2196. choose_windows(buf);
  2197. }
  2198. return;
  2199. }
  2200. /* WINCAP
  2201. * setting window colors
  2202. * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
  2203. */
  2204. fullname = "windowcolors";
  2205. if (match_optname(opts, fullname, 7, TRUE)) {
  2206. if ((op = string_for_opt(opts, FALSE)) != 0) {
  2207. if (!wc_set_window_colors(op))
  2208. badoption(opts);
  2209. } else if (negated) bad_negation(fullname, TRUE);
  2210. return;
  2211. }
  2212. /* menustyle:traditional or combo or full or partial */
  2213. if (match_optname(opts, "menustyle", 4, TRUE)) {
  2214. int tmp;
  2215. boolean val_required = (strlen(opts) > 5 && !negated);
  2216. if (!(op = string_for_opt(opts, !val_required))) {
  2217. if (val_required) return; /* string_for_opt gave feedback */
  2218. tmp = negated ? 'n' : 'f';
  2219. } else {
  2220. tmp = tolower(*op);
  2221. }
  2222. switch (tmp) {
  2223. case 'n': /* none */
  2224. case 't': /* traditional */
  2225. flags.menu_style = MENU_TRADITIONAL;
  2226. break;
  2227. case 'c': /* combo: trad.class sel+menu */
  2228. flags.menu_style = MENU_COMBINATION;
  2229. break;
  2230. case 'p': /* partial: no class menu */
  2231. flags.menu_style = MENU_PARTIAL;
  2232. break;
  2233. case 'f': /* full: class menu + menu */
  2234. flags.menu_style = MENU_FULL;
  2235. break;
  2236. default:
  2237. badoption(opts);
  2238. }
  2239. return;
  2240. }
  2241. fullname = "menu_headings";
  2242. if (match_optname(opts, fullname, 12, TRUE)) {
  2243. if (negated) {
  2244. bad_negation(fullname, FALSE);
  2245. return;
  2246. }
  2247. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
  2248. return;
  2249. }
  2250. if (!strcmpi(opts,"bold"))
  2251. iflags.menu_headings = ATR_BOLD;
  2252. else if (!strcmpi(opts,"inverse"))
  2253. iflags.menu_headings = ATR_INVERSE;
  2254. else if (!strcmpi(opts,"underline"))
  2255. iflags.menu_headings = ATR_ULINE;
  2256. else
  2257. badoption(opts);
  2258. return;
  2259. }
  2260. /* check for menu command mapping */
  2261. for (i = 0; i < NUM_MENU_CMDS; i++) {
  2262. fullname = default_menu_cmd_info[i].name;
  2263. if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
  2264. if (negated)
  2265. bad_negation(fullname, FALSE);
  2266. else if ((op = string_for_opt(opts, FALSE)) != 0) {
  2267. int j;
  2268. char c, op_buf[BUFSZ];
  2269. boolean isbad = FALSE;
  2270. escapes(op, op_buf);
  2271. c = *op_buf;
  2272. if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
  2273. c == ' ' || digit(c) || (letter(c) && c != '@'))
  2274. isbad = TRUE;
  2275. else /* reject default object class symbols */
  2276. for (j = 1; j < MAXOCLASSES; j++)
  2277. if (c == def_oc_syms[i]) {
  2278. isbad = TRUE;
  2279. break;
  2280. }
  2281. if (isbad)
  2282. badoption(opts);
  2283. else
  2284. add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
  2285. }
  2286. return;
  2287. }
  2288. }
  2289. /* OK, if we still haven't recognized the option, check the boolean
  2290. * options list
  2291. */
  2292. for (i = 0; boolopt[i].name; i++) {
  2293. if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
  2294. /* options that don't exist */
  2295. if (!boolopt[i].addr) {
  2296. if (!initial && !negated)
  2297. pline_The("\"%s\" option is not available.",
  2298. boolopt[i].name);
  2299. return;
  2300. }
  2301. /* options that must come from config file */
  2302. if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
  2303. rejectoption(boolopt[i].name);
  2304. return;
  2305. }
  2306. *(boolopt[i].addr) = !negated;
  2307. duplicate_opt_detection(boolopt[i].name, 0);
  2308. #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV)
  2309. if (FALSE
  2310. # ifdef TERMLIB
  2311. || (boolopt[i].addr) == &iflags.DECgraphics
  2312. # endif
  2313. # ifdef ASCIIGRAPH
  2314. || (boolopt[i].addr) == &iflags.IBMgraphics
  2315. # endif
  2316. # ifdef MAC_GRAPHICS_ENV
  2317. || (boolopt[i].addr) == &iflags.MACgraphics
  2318. # endif
  2319. ) {
  2320. # ifdef REINCARNATION
  2321. /* [ALI] GTK port may call doset() after initial
  2322. * but before we start a game. Prevent false match.
  2323. */
  2324. if (!initial && u.uz.dlevel &&
  2325. Is_rogue_level(&u.uz))
  2326. assign_rogue_graphics(FALSE);
  2327. # endif
  2328. need_redraw = TRUE;
  2329. # ifdef TERMLIB
  2330. if ((boolopt[i].addr) == &iflags.DECgraphics)
  2331. switch_graphics(iflags.DECgraphics ?
  2332. DEC_GRAPHICS : ASCII_GRAPHICS);
  2333. # endif
  2334. # ifdef ASCIIGRAPH
  2335. if ((boolopt[i].addr) == &iflags.IBMgraphics)
  2336. switch_graphics(iflags.IBMgraphics ?
  2337. IBM_GRAPHICS : ASCII_GRAPHICS);
  2338. # endif
  2339. # ifdef MAC_GRAPHICS_ENV
  2340. if ((boolopt[i].addr) == &iflags.MACgraphics)
  2341. switch_graphics(iflags.MACgraphics ?
  2342. MAC_GRAPHICS : ASCII_GRAPHICS);
  2343. # endif
  2344. # ifdef REINCARNATION
  2345. if (!initial && u.uz.dlevel &&
  2346. Is_rogue_level(&u.uz))
  2347. assign_rogue_graphics(TRUE);
  2348. # endif
  2349. }
  2350. #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */
  2351. /* only do processing below if setting with doset() */
  2352. if (initial) return;
  2353. if ((boolopt[i].addr) == &flags.time
  2354. #ifdef EXP_ON_BOTL
  2355. || (boolopt[i].addr) == &flags.showexp
  2356. #endif
  2357. #ifdef SCORE_ON_BOTL
  2358. || (boolopt[i].addr) == &flags.showscore
  2359. #endif
  2360. #ifdef SHOW_WEIGHT
  2361. || (boolopt[i].addr) == &flags.showweight
  2362. #endif
  2363. )
  2364. bot_reconfig();
  2365. else if ((boolopt[i].addr) == &flags.invlet_constant) {
  2366. if (flags.invlet_constant) reassign();
  2367. }
  2368. #ifdef LAN_MAIL
  2369. else if ((boolopt[i].addr) == &flags.biff) {
  2370. if (flags.biff) lan_mail_init();
  2371. else lan_mail_finish();
  2372. }
  2373. #endif
  2374. else if ((boolopt[i].addr) == &flags.lit_corridor) {
  2375. /*
  2376. * All corridor squares seen via night vision or
  2377. * candles & lamps change. Update them by calling
  2378. * newsym() on them. Don't do this if we are
  2379. * initializing the options --- the vision system
  2380. * isn't set up yet.
  2381. */
  2382. if (u.uz.dlevel)
  2383. {
  2384. vision_recalc(2); /* shut down vision */
  2385. vision_full_recalc = 1; /* delayed recalc */
  2386. }
  2387. }
  2388. else if ((boolopt[i].addr) == &iflags.use_inverse ||
  2389. (boolopt[i].addr) == &iflags.showrace ||
  2390. (boolopt[i].addr) == &iflags.hilite_pet) {
  2391. need_redraw = TRUE;
  2392. }
  2393. #ifdef TEXTCOLOR
  2394. else if ((boolopt[i].addr) == &iflags.use_color) {
  2395. need_redraw = TRUE;
  2396. # ifdef TOS
  2397. if ((boolopt[i].addr) == &iflags.use_color
  2398. && iflags.BIOS) {
  2399. if (colors_changed)
  2400. restore_colors();
  2401. else
  2402. set_colors();
  2403. }
  2404. # endif
  2405. }
  2406. #endif
  2407. else if ((boolopt[i].addr) == &flags.perm_invent)
  2408. update_inventory();
  2409. return;
  2410. }
  2411. }
  2412. /* out of valid options */
  2413. badoption(opts);
  2414. }
  2415. static void
  2416. parseauthopt(opts)
  2417. register char *opts;
  2418. {
  2419. register char *op;
  2420. boolean negated;
  2421. const char *fullname;
  2422. if (strlen(opts) > BUFSZ/2) {
  2423. badauthoption("option too long");
  2424. return;
  2425. }
  2426. /* strip leading and trailing white space */
  2427. while (isspace((int)*opts)) opts++;
  2428. op = eos(opts);
  2429. while (--op >= opts && isspace((int)*op)) *op = '\0';
  2430. if (!*opts) return;
  2431. negated = FALSE;
  2432. while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
  2433. if (*opts == '!') opts++; else opts += 2;
  2434. negated = !negated;
  2435. }
  2436. /* compound options */
  2437. fullname = "prog";
  2438. if (match_optname(opts, fullname, 4, TRUE)) {
  2439. if (negated) bad_negation(fullname, FALSE);
  2440. else if ((op = string_for_auth_opt(opts, FALSE)) != 0)
  2441. nmcpy(authentication.prog, op, BUFSZ);
  2442. return;
  2443. }
  2444. fullname = "args";
  2445. if (match_optname(opts, fullname, 4, TRUE)) {
  2446. if (negated) bad_negation(fullname, FALSE);
  2447. else if ((op = string_for_auth_opt(opts, FALSE)) != 0)
  2448. nmcpy(authentication.args, op, BUFSZ);
  2449. return;
  2450. }
  2451. /* out of valid options */
  2452. badauthoption(opts);
  2453. }
  2454. void
  2455. parseauthentication(opts)
  2456. register char *opts;
  2457. {
  2458. register char *op;
  2459. /* Initial values */
  2460. authentication.prog[0] = '\0';
  2461. authentication.args[0] = '\0';
  2462. while ((op = index(opts, ',')) != 0) {
  2463. *op++ = 0;
  2464. parseauthopt(opts);
  2465. opts = op;
  2466. }
  2467. parseauthopt(opts);
  2468. if (!authentication.prog[0] && authentication.args[0])
  2469. badauthoption("Arguments given but no program specified.");
  2470. }
  2471. static void
  2472. parsetilesetopt(opts)
  2473. register char *opts;
  2474. {
  2475. register char *op;
  2476. boolean negated;
  2477. int i;
  2478. const char *fullname;
  2479. if (strlen(opts) > BUFSZ/2) {
  2480. badtileoption("option too long");
  2481. return;
  2482. }
  2483. /* strip leading and trailing white space */
  2484. while (isspace((int)*opts)) opts++;
  2485. op = eos(opts);
  2486. while (--op >= opts && isspace((int)*op)) *op = '\0';
  2487. if (!*opts) return;
  2488. negated = FALSE;
  2489. while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
  2490. if (*opts == '!') opts++; else opts += 2;
  2491. negated = !negated;
  2492. }
  2493. /* compound options */
  2494. fullname = "name";
  2495. if (match_optname(opts, fullname, 4, TRUE)) {
  2496. if (negated) bad_negation(fullname, FALSE);
  2497. else if ((op = string_for_tile_opt(opts, FALSE)) != 0)
  2498. nmcpy(tilesets[no_tilesets].name, op, PL_PSIZ);
  2499. return;
  2500. }
  2501. fullname = "filename";
  2502. if (match_optname(opts, fullname, 4, TRUE)) {
  2503. if (negated) bad_negation(fullname, FALSE);
  2504. else if ((op = string_for_tile_opt(opts, FALSE)) != 0)
  2505. nmcpy(tilesets[no_tilesets].file, op,
  2506. TILESET_MAX_FILENAME);
  2507. return;
  2508. }
  2509. /* OK, if we still haven't recognized the option, check the boolean
  2510. * options list
  2511. */
  2512. for (i = 0; booltileopt[i].name; i++) {
  2513. if (match_optname(opts, booltileopt[i].name, 3, FALSE)) {
  2514. if (negated)
  2515. tilesets[no_tilesets].flags &= ~booltileopt[i].flag;
  2516. else
  2517. tilesets[no_tilesets].flags |= booltileopt[i].flag;
  2518. return;
  2519. }
  2520. }
  2521. /* out of valid options */
  2522. badtileoption(opts);
  2523. }
  2524. void
  2525. parsetileset(opts)
  2526. register char *opts;
  2527. {
  2528. register char *op;
  2529. int i;
  2530. if (no_tilesets >= MAXNOTILESETS) {
  2531. badtileoption("too many tilesets");
  2532. return;
  2533. }
  2534. /* Initial values */
  2535. tilesets[no_tilesets].name[0] = '\0';
  2536. tilesets[no_tilesets].file[0] = '\0';
  2537. tilesets[no_tilesets].flags = 0;
  2538. for (i = 0; booltileopt[i].name; i++)
  2539. tilesets[no_tilesets].flags |= booltileopt[i].initvalue;
  2540. while ((op = index(opts, ',')) != 0) {
  2541. *op++ = 0;
  2542. parsetilesetopt(opts);
  2543. opts = op;
  2544. }
  2545. parsetilesetopt(opts);
  2546. if (tilesets[no_tilesets].name[0] == '\0' ||
  2547. tilesets[no_tilesets].file[0] == '\0') {
  2548. badtileoption("Incomplete tileset definition.");
  2549. }
  2550. else
  2551. no_tilesets++;
  2552. }
  2553. static NEARDATA const char *menutype[] = {
  2554. "traditional", "combination", "partial", "full"
  2555. };
  2556. static NEARDATA const char *burdentype[] = {
  2557. "unencumbered", "burdened", "stressed",
  2558. "strained", "overtaxed", "overloaded"
  2559. };
  2560. static NEARDATA const char *runmodes[] = {
  2561. "teleport", "run", "walk", "crawl"
  2562. };
  2563. /*
  2564. * Convert the given string of object classes to a string of default object
  2565. * symbols.
  2566. */
  2567. STATIC_OVL void
  2568. oc_to_str(src,dest)
  2569. char *src, *dest;
  2570. {
  2571. int i;
  2572. while ((i = (int) *src++) != 0) {
  2573. if (i < 0 || i >= MAXOCLASSES)
  2574. impossible("oc_to_str: illegal object class %d", i);
  2575. else
  2576. *dest++ = def_oc_syms[i];
  2577. }
  2578. *dest = '\0';
  2579. }
  2580. /*
  2581. * Add the given mapping to the menu command map list. Always keep the
  2582. * maps valid C strings.
  2583. */
  2584. void
  2585. add_menu_cmd_alias(from_ch, to_ch)
  2586. char from_ch, to_ch;
  2587. {
  2588. if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
  2589. pline("out of menu map space.");
  2590. else {
  2591. mapped_menu_cmds[n_menu_mapped] = from_ch;
  2592. mapped_menu_op[n_menu_mapped] = to_ch;
  2593. n_menu_mapped++;
  2594. mapped_menu_cmds[n_menu_mapped] = 0;
  2595. mapped_menu_op[n_menu_mapped] = 0;
  2596. }
  2597. }
  2598. /*
  2599. * Map the given character to its corresponding menu command. If it
  2600. * doesn't match anything, just return the original.
  2601. */
  2602. char
  2603. map_menu_cmd(ch)
  2604. char ch;
  2605. {
  2606. char *found = index(mapped_menu_cmds, ch);
  2607. if (found) {
  2608. int idx = found - mapped_menu_cmds;
  2609. ch = mapped_menu_op[idx];
  2610. }
  2611. return ch;
  2612. }
  2613. #if defined(MICRO) || defined(MAC) || defined(WIN32)
  2614. # define OPTIONS_HEADING "OPTIONS"
  2615. #else
  2616. # define OPTIONS_HEADING NETHACK_ENV_OPTIONS
  2617. #endif
  2618. static char fmtstr_doset_add_menu[] = "%s%-15s [%s] ";
  2619. static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
  2620. STATIC_OVL void
  2621. doset_add_menu(win, option, indexoffset)
  2622. winid win; /* window to add to */
  2623. const char *option; /* option name */
  2624. int indexoffset; /* value to add to index in compopt[], or zero
  2625. if option cannot be changed */
  2626. {
  2627. const char *value = "unknown"; /* current value */
  2628. char buf[BUFSZ], buf2[BUFSZ];
  2629. anything any;
  2630. int i;
  2631. any.a_void = 0;
  2632. if (indexoffset == 0) {
  2633. any.a_int = 0;
  2634. value = get_compopt_value(option, buf2);
  2635. } else {
  2636. for (i=0; compopt[i].name; i++)
  2637. if (strcmp(option, compopt[i].name) == 0) break;
  2638. if (compopt[i].name) {
  2639. any.a_int = i + 1 + indexoffset;
  2640. value = get_compopt_value(option, buf2);
  2641. } else {
  2642. /* We are trying to add an option not found in compopt[].
  2643. This is almost certainly bad, but we'll let it through anyway
  2644. (with a zero value, so it can't be selected). */
  2645. any.a_int = 0;
  2646. }
  2647. }
  2648. /* " " replaces "a - " -- assumes menus follow that style */
  2649. if (!iflags.menu_tab_sep)
  2650. Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option, value);
  2651. else
  2652. Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
  2653. add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  2654. }
  2655. /* Changing options via menu by Per Liboriussen */
  2656. int
  2657. doset()
  2658. {
  2659. char buf[BUFSZ], buf2[BUFSZ];
  2660. int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
  2661. boolean *bool_p;
  2662. winid tmpwin;
  2663. anything any;
  2664. menu_item *pick_list;
  2665. int indexoffset, startpass, endpass;
  2666. boolean setinitial = FALSE, fromfile = FALSE;
  2667. int biggest_name = 0;
  2668. tmpwin = create_nhwindow(NHW_MENU);
  2669. start_menu(tmpwin);
  2670. any.a_void = 0;
  2671. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2672. "Booleans (selecting will toggle value):", MENU_UNSELECTED);
  2673. any.a_int = 0;
  2674. /* first list any other non-modifiable booleans, then modifiable ones */
  2675. for (pass = 0; pass <= 1; pass++)
  2676. for (i = 0; boolopt[i].name; i++)
  2677. if ((bool_p = boolopt[i].addr) != 0 &&
  2678. ((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
  2679. (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
  2680. if (bool_p == &flags.female) continue; /* obsolete */
  2681. #ifdef WIZARD
  2682. #ifndef OBJ_SANITY
  2683. if (bool_p == &iflags.sanity_check && !wizard) continue;
  2684. #endif
  2685. if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
  2686. #endif
  2687. if (is_wc_option(boolopt[i].name) &&
  2688. !wc_supported(boolopt[i].name)) continue;
  2689. if (is_wc2_option(boolopt[i].name) &&
  2690. !wc2_supported(boolopt[i].name)) continue;
  2691. any.a_int = (pass == 0) ? 0 : i + 1;
  2692. if (!iflags.menu_tab_sep)
  2693. Sprintf(buf, "%s%-13s [%s]",
  2694. pass == 0 ? " " : "",
  2695. boolopt[i].name, *bool_p ? "true" : "false");
  2696. else
  2697. Sprintf(buf, "%s\t[%s]",
  2698. boolopt[i].name, *bool_p ? "true" : "false");
  2699. add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
  2700. ATR_NONE, buf, MENU_UNSELECTED);
  2701. }
  2702. boolcount = i;
  2703. indexoffset = boolcount;
  2704. any.a_void = 0;
  2705. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  2706. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2707. "Compounds (selecting will prompt for new value):",
  2708. MENU_UNSELECTED);
  2709. startpass = DISP_IN_GAME;
  2710. endpass = SET_IN_GAME;
  2711. /* spin through the options to find the biggest name
  2712. and adjust the format string accordingly if needed */
  2713. biggest_name = 0;
  2714. for (i = 0; compopt[i].name; i++)
  2715. if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
  2716. strlen(compopt[i].name) > (unsigned) biggest_name)
  2717. biggest_name = (int) strlen(compopt[i].name);
  2718. if (biggest_name > 30) biggest_name = 30;
  2719. if (!iflags.menu_tab_sep)
  2720. Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
  2721. /* deliberately put `name', `role', `race', `gender' first */
  2722. doset_add_menu(tmpwin, "name", 0);
  2723. doset_add_menu(tmpwin, "role", 0);
  2724. doset_add_menu(tmpwin, "race", 0);
  2725. doset_add_menu(tmpwin, "gender", 0);
  2726. for (pass = startpass; pass <= endpass; pass++)
  2727. for (i = 0; compopt[i].name; i++)
  2728. if (compopt[i].optflags == pass) {
  2729. if (!strcmp(compopt[i].name, "name") ||
  2730. !strcmp(compopt[i].name, "role") ||
  2731. !strcmp(compopt[i].name, "race") ||
  2732. !strcmp(compopt[i].name, "gender"))
  2733. continue;
  2734. else if (is_wc_option(compopt[i].name) &&
  2735. !wc_supported(compopt[i].name))
  2736. continue;
  2737. else if (is_wc2_option(compopt[i].name) &&
  2738. !wc2_supported(compopt[i].name))
  2739. continue;
  2740. else
  2741. doset_add_menu(tmpwin, compopt[i].name,
  2742. (pass == DISP_IN_GAME) ? 0 : indexoffset);
  2743. }
  2744. #ifdef AUTOPICKUP_EXCEPTIONS
  2745. any.a_int = -1;
  2746. Sprintf(buf, "autopickup exceptions (%d currently set)",
  2747. count_ape_maps((int *)0, (int *)0));
  2748. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
  2749. #endif /* AUTOPICKUP_EXCEPTIONS */
  2750. #ifdef PREFIXES_IN_USE
  2751. any.a_void = 0;
  2752. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  2753. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  2754. "Variable playground locations:", MENU_UNSELECTED);
  2755. for (i = 0; i < PREFIX_COUNT; i++)
  2756. doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
  2757. #endif
  2758. end_menu(tmpwin, "Set what options?");
  2759. need_redraw = FALSE;
  2760. if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
  2761. /*
  2762. * Walk down the selection list and either invert the booleans
  2763. * or prompt for new values. In most cases, call parseoptions()
  2764. * to take care of options that require special attention, like
  2765. * redraws.
  2766. */
  2767. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  2768. opt_indx = pick_list[pick_idx].item.a_int - 1;
  2769. #ifdef AUTOPICKUP_EXCEPTIONS
  2770. if (opt_indx == -2) {
  2771. special_handling("autopickup_exception",
  2772. setinitial, fromfile);
  2773. } else
  2774. #endif
  2775. if (opt_indx < boolcount) {
  2776. /* boolean option */
  2777. Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
  2778. boolopt[opt_indx].name);
  2779. parseoptions(buf, setinitial, fromfile);
  2780. if (wc_supported(boolopt[opt_indx].name) ||
  2781. wc2_supported(boolopt[opt_indx].name))
  2782. preference_update(boolopt[opt_indx].name);
  2783. } else {
  2784. /* compound option */
  2785. opt_indx -= boolcount;
  2786. if (!special_handling(compopt[opt_indx].name,
  2787. setinitial, fromfile)) {
  2788. Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
  2789. getlin(buf, buf2);
  2790. if (buf2[0] == '\033')
  2791. continue;
  2792. Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
  2793. /* pass the buck */
  2794. parseoptions(buf, setinitial, fromfile);
  2795. }
  2796. if (wc_supported(compopt[opt_indx].name) ||
  2797. wc2_supported(compopt[opt_indx].name))
  2798. preference_update(compopt[opt_indx].name);
  2799. }
  2800. }
  2801. free((genericptr_t)pick_list);
  2802. pick_list = (menu_item *)0;
  2803. }
  2804. destroy_nhwindow(tmpwin);
  2805. if (need_redraw)
  2806. (void) doredraw();
  2807. return 0;
  2808. }
  2809. STATIC_OVL boolean
  2810. special_handling(optname, setinitial, setfromfile)
  2811. const char *optname;
  2812. boolean setinitial,setfromfile;
  2813. {
  2814. winid tmpwin;
  2815. anything any;
  2816. int i;
  2817. char buf[BUFSZ];
  2818. boolean retval = FALSE;
  2819. /* Special handling of menustyle, pickup_burden, pickup_types,
  2820. * disclose, runmode, msg_window, menu_headings, and number_pad options.
  2821. #ifdef AUTOPICKUP_EXCEPTIONS
  2822. * Also takes care of interactive autopickup_exception_handling changes.
  2823. #endif
  2824. */
  2825. if (!strcmp("menustyle", optname)) {
  2826. const char *style_name;
  2827. menu_item *style_pick = (menu_item *)0;
  2828. tmpwin = create_nhwindow(NHW_MENU);
  2829. start_menu(tmpwin);
  2830. for (i = 0; i < SIZE(menutype); i++) {
  2831. style_name = menutype[i];
  2832. /* note: separate `style_name' variable used
  2833. to avoid an optimizer bug in VAX C V2.3 */
  2834. any.a_int = i + 1;
  2835. add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
  2836. ATR_NONE, style_name, MENU_UNSELECTED);
  2837. }
  2838. end_menu(tmpwin, "Select menustyle:");
  2839. if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
  2840. flags.menu_style = style_pick->item.a_int - 1;
  2841. free((genericptr_t)style_pick);
  2842. }
  2843. destroy_nhwindow(tmpwin);
  2844. retval = TRUE;
  2845. } else if (!strcmp("pickup_burden", optname)) {
  2846. const char *burden_name, *burden_letters = "ubsntl";
  2847. menu_item *burden_pick = (menu_item *)0;
  2848. tmpwin = create_nhwindow(NHW_MENU);
  2849. start_menu(tmpwin);
  2850. for (i = 0; i < SIZE(burdentype); i++) {
  2851. burden_name = burdentype[i];
  2852. any.a_int = i + 1;
  2853. add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
  2854. ATR_NONE, burden_name, MENU_UNSELECTED);
  2855. }
  2856. end_menu(tmpwin, "Select encumbrance level:");
  2857. if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
  2858. flags.pickup_burden = burden_pick->item.a_int - 1;
  2859. free((genericptr_t)burden_pick);
  2860. }
  2861. destroy_nhwindow(tmpwin);
  2862. retval = TRUE;
  2863. } else if (!strcmp("pickup_types", optname)) {
  2864. /* parseoptions will prompt for the list of types */
  2865. parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
  2866. retval = TRUE;
  2867. } else if (!strcmp("disclose", optname)) {
  2868. int pick_cnt, pick_idx, opt_idx;
  2869. menu_item *disclosure_category_pick = (menu_item *)0;
  2870. /*
  2871. * The order of disclose_names[]
  2872. * must correspond to disclosure_options in decl.h
  2873. */
  2874. static const char *disclosure_names[] = {
  2875. "inventory", "attributes", "vanquished", "genocides", "conduct"
  2876. };
  2877. int disc_cat[NUM_DISCLOSURE_OPTIONS];
  2878. const char *disclosure_name;
  2879. tmpwin = create_nhwindow(NHW_MENU);
  2880. start_menu(tmpwin);
  2881. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  2882. disclosure_name = disclosure_names[i];
  2883. any.a_int = i + 1;
  2884. add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
  2885. ATR_NONE, disclosure_name, MENU_UNSELECTED);
  2886. disc_cat[i] = 0;
  2887. }
  2888. end_menu(tmpwin, "Change which disclosure options categories:");
  2889. if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
  2890. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  2891. opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
  2892. disc_cat[opt_idx] = 1;
  2893. }
  2894. free((genericptr_t)disclosure_category_pick);
  2895. disclosure_category_pick = (menu_item *)0;
  2896. }
  2897. destroy_nhwindow(tmpwin);
  2898. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  2899. if (disc_cat[i]) {
  2900. char dbuf[BUFSZ];
  2901. menu_item *disclosure_option_pick = (menu_item *)0;
  2902. Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
  2903. tmpwin = create_nhwindow(NHW_MENU);
  2904. start_menu(tmpwin);
  2905. any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
  2906. add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
  2907. ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
  2908. any.a_void = 0;
  2909. any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
  2910. add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
  2911. ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
  2912. any.a_void = 0;
  2913. any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
  2914. add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
  2915. ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
  2916. any.a_void = 0;
  2917. any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
  2918. add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
  2919. ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
  2920. end_menu(tmpwin, dbuf);
  2921. if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
  2922. flags.end_disclose[i] = disclosure_option_pick->item.a_char;
  2923. free((genericptr_t)disclosure_option_pick);
  2924. }
  2925. destroy_nhwindow(tmpwin);
  2926. }
  2927. }
  2928. retval = TRUE;
  2929. } else if (!strcmp("runmode", optname)) {
  2930. const char *mode_name;
  2931. menu_item *mode_pick = (menu_item *)0;
  2932. tmpwin = create_nhwindow(NHW_MENU);
  2933. start_menu(tmpwin);
  2934. for (i = 0; i < SIZE(runmodes); i++) {
  2935. mode_name = runmodes[i];
  2936. any.a_int = i + 1;
  2937. add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
  2938. ATR_NONE, mode_name, MENU_UNSELECTED);
  2939. }
  2940. end_menu(tmpwin, "Select run/travel display mode:");
  2941. if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  2942. iflags.runmode = mode_pick->item.a_int - 1;
  2943. free((genericptr_t)mode_pick);
  2944. }
  2945. destroy_nhwindow(tmpwin);
  2946. retval = TRUE;
  2947. }
  2948. #ifdef TTY_GRAPHICS
  2949. else if (!strcmp("msg_window", optname)) {
  2950. /* by Christian W. Cooper */
  2951. menu_item *window_pick = (menu_item *)0;
  2952. tmpwin = create_nhwindow(NHW_MENU);
  2953. start_menu(tmpwin);
  2954. any.a_char = 's';
  2955. add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
  2956. ATR_NONE, "single", MENU_UNSELECTED);
  2957. any.a_char = 'c';
  2958. add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
  2959. ATR_NONE, "combination", MENU_UNSELECTED);
  2960. any.a_char = 'f';
  2961. add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
  2962. ATR_NONE, "full", MENU_UNSELECTED);
  2963. any.a_char = 'r';
  2964. add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
  2965. ATR_NONE, "reversed", MENU_UNSELECTED);
  2966. end_menu(tmpwin, "Select message history display type:");
  2967. if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
  2968. iflags.prevmsg_window = window_pick->item.a_char;
  2969. free((genericptr_t)window_pick);
  2970. }
  2971. destroy_nhwindow(tmpwin);
  2972. retval = TRUE;
  2973. }
  2974. #endif
  2975. else if (!strcmp("align_message", optname) ||
  2976. !strcmp("align_status", optname)) {
  2977. menu_item *window_pick = (menu_item *)0;
  2978. char abuf[BUFSZ];
  2979. boolean msg = (*(optname+6) == 'm');
  2980. tmpwin = create_nhwindow(NHW_MENU);
  2981. start_menu(tmpwin);
  2982. any.a_int = ALIGN_TOP;
  2983. add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
  2984. ATR_NONE, "top", MENU_UNSELECTED);
  2985. any.a_int = ALIGN_BOTTOM;
  2986. add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
  2987. ATR_NONE, "bottom", MENU_UNSELECTED);
  2988. any.a_int = ALIGN_LEFT;
  2989. add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
  2990. ATR_NONE, "left", MENU_UNSELECTED);
  2991. any.a_int = ALIGN_RIGHT;
  2992. add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
  2993. ATR_NONE, "right", MENU_UNSELECTED);
  2994. Sprintf(abuf, "Select %s window placement relative to the map:",
  2995. msg ? "message" : "status");
  2996. end_menu(tmpwin, abuf);
  2997. if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
  2998. if (msg) iflags.wc_align_message = window_pick->item.a_int;
  2999. else iflags.wc_align_status = window_pick->item.a_int;
  3000. free((genericptr_t)window_pick);
  3001. }
  3002. destroy_nhwindow(tmpwin);
  3003. retval = TRUE;
  3004. } else if (!strcmp("number_pad", optname)) {
  3005. static const char *npchoices[3] =
  3006. {"0 (off)", "1 (on)", "2 (on, DOS compatible)"};
  3007. const char *npletters = "abc";
  3008. menu_item *mode_pick = (menu_item *)0;
  3009. tmpwin = create_nhwindow(NHW_MENU);
  3010. start_menu(tmpwin);
  3011. for (i = 0; i < SIZE(npchoices); i++) {
  3012. any.a_int = i + 1;
  3013. add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
  3014. ATR_NONE, npchoices[i], MENU_UNSELECTED);
  3015. }
  3016. end_menu(tmpwin, "Select number_pad mode:");
  3017. if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  3018. int mode = mode_pick->item.a_int - 1;
  3019. switch(mode) {
  3020. case 2:
  3021. iflags.num_pad = 1;
  3022. iflags.num_pad_mode = 1;
  3023. break;
  3024. case 1:
  3025. iflags.num_pad = 1;
  3026. iflags.num_pad_mode = 0;
  3027. break;
  3028. case 0:
  3029. default:
  3030. iflags.num_pad = 0;
  3031. iflags.num_pad_mode = 0;
  3032. }
  3033. free((genericptr_t)mode_pick);
  3034. number_pad(iflags.num_pad);
  3035. }
  3036. destroy_nhwindow(tmpwin);
  3037. retval = TRUE;
  3038. } else if (!strcmp("menu_headings", optname)) {
  3039. static const char *mhchoices[3] = {"bold", "inverse", "underline"};
  3040. const char *npletters = "biu";
  3041. menu_item *mode_pick = (menu_item *)0;
  3042. tmpwin = create_nhwindow(NHW_MENU);
  3043. start_menu(tmpwin);
  3044. for (i = 0; i < SIZE(mhchoices); i++) {
  3045. any.a_int = i + 1;
  3046. add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
  3047. ATR_NONE, mhchoices[i], MENU_UNSELECTED);
  3048. }
  3049. end_menu(tmpwin, "How to highlight menu headings:");
  3050. if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
  3051. int mode = mode_pick->item.a_int - 1;
  3052. switch(mode) {
  3053. case 2:
  3054. iflags.menu_headings = ATR_ULINE;
  3055. break;
  3056. case 0:
  3057. iflags.menu_headings = ATR_BOLD;
  3058. break;
  3059. case 1:
  3060. default:
  3061. iflags.menu_headings = ATR_INVERSE;
  3062. }
  3063. free((genericptr_t)mode_pick);
  3064. }
  3065. destroy_nhwindow(tmpwin);
  3066. retval = TRUE;
  3067. #ifdef AUTOPICKUP_EXCEPTIONS
  3068. } else if (!strcmp("autopickup_exception", optname)) {
  3069. boolean retval;
  3070. int pick_cnt, pick_idx, opt_idx, pass;
  3071. int totalapes = 0, numapes[2] = {0,0};
  3072. menu_item *pick_list = (menu_item *)0;
  3073. anything any;
  3074. char apebuf[BUFSZ];
  3075. struct autopickup_exception *ape;
  3076. static const char *action_titles[] = {
  3077. "a", "add new autopickup exception",
  3078. "l", "list autopickup exceptions",
  3079. "r", "remove existing autopickup exception",
  3080. "e", "exit this menu",
  3081. };
  3082. ape_again:
  3083. opt_idx = 0;
  3084. totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
  3085. tmpwin = create_nhwindow(NHW_MENU);
  3086. start_menu(tmpwin);
  3087. any.a_int = 0;
  3088. for (i = 0; i < SIZE(action_titles) ; i += 2) {
  3089. any.a_int++;
  3090. if (!totalapes && (i >= 2 && i < 6)) continue;
  3091. add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
  3092. 0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
  3093. }
  3094. end_menu(tmpwin, "Do what?");
  3095. if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
  3096. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
  3097. opt_idx = pick_list[pick_idx].item.a_int - 1;
  3098. }
  3099. free((genericptr_t)pick_list);
  3100. pick_list = (menu_item *)0;
  3101. }
  3102. destroy_nhwindow(tmpwin);
  3103. if (pick_cnt < 1) return FALSE;
  3104. if (opt_idx == 0) { /* add new */
  3105. getlin("What new autopickup exception pattern?", &apebuf[1]);
  3106. if (apebuf[1] == '\033') return FALSE;
  3107. apebuf[0] = '"';
  3108. Strcat(apebuf,"\"");
  3109. add_autopickup_exception(apebuf);
  3110. goto ape_again;
  3111. } else if (opt_idx == 3) {
  3112. retval = TRUE;
  3113. } else { /* remove */
  3114. tmpwin = create_nhwindow(NHW_MENU);
  3115. start_menu(tmpwin);
  3116. for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
  3117. if (numapes[pass] == 0) continue;
  3118. ape = iflags.autopickup_exceptions[pass];
  3119. any.a_void = 0;
  3120. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  3121. (pass == 0) ? "Never pickup" : "Always pickup",
  3122. MENU_UNSELECTED);
  3123. for (i = 0; i < numapes[pass] && ape; i++) {
  3124. any.a_void = (opt_idx == 1) ? 0 : ape;
  3125. Sprintf(apebuf, "\"%s\"", ape->pattern);
  3126. add_menu(tmpwin, NO_GLYPH, &any,
  3127. 0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
  3128. ape = ape->next;
  3129. }
  3130. }
  3131. Sprintf(apebuf, "%s autopickup exceptions",
  3132. (opt_idx == 1) ? "List of" : "Remove which");
  3133. end_menu(tmpwin, apebuf);
  3134. pick_cnt = select_menu(tmpwin,
  3135. (opt_idx == 1) ? PICK_NONE : PICK_ANY,
  3136. &pick_list);
  3137. if (pick_cnt > 0) {
  3138. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
  3139. remove_autopickup_exception(
  3140. (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
  3141. }
  3142. free((genericptr_t)pick_list);
  3143. pick_list = (menu_item *)0;
  3144. destroy_nhwindow(tmpwin);
  3145. goto ape_again;
  3146. }
  3147. retval = TRUE;
  3148. #endif /* AUTOPICKUP_EXCEPTIONS */
  3149. }
  3150. return retval;
  3151. }
  3152. #define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
  3153. (val == ROLE_RANDOM) ? randomrole : none)
  3154. /* This is ugly. We have all the option names in the compopt[] array,
  3155. but we need to look at each option individually to get the value. */
  3156. STATIC_OVL const char *
  3157. get_compopt_value(optname, buf)
  3158. const char *optname;
  3159. char *buf;
  3160. {
  3161. char ocl[MAXOCLASSES+1];
  3162. static const char none[] = "(none)", randomrole[] = "random",
  3163. to_be_done[] = "(to be done)",
  3164. defopt[] = "default",
  3165. defbrief[] = "def";
  3166. int i;
  3167. buf[0] = '\0';
  3168. if (!strcmp(optname,"align_message"))
  3169. Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP ? "top" :
  3170. iflags.wc_align_message == ALIGN_LEFT ? "left" :
  3171. iflags.wc_align_message == ALIGN_BOTTOM ? "bottom" :
  3172. iflags.wc_align_message == ALIGN_RIGHT ? "right" :
  3173. defopt);
  3174. else if (!strcmp(optname,"align_status"))
  3175. Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP ? "top" :
  3176. iflags.wc_align_status == ALIGN_LEFT ? "left" :
  3177. iflags.wc_align_status == ALIGN_BOTTOM ? "bottom" :
  3178. iflags.wc_align_status == ALIGN_RIGHT ? "right" :
  3179. defopt);
  3180. else if (!strcmp(optname,"align"))
  3181. Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
  3182. #ifdef WIN32CON
  3183. else if (!strcmp(optname,"altkeyhandler"))
  3184. Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
  3185. iflags.altkeyhandler : "default");
  3186. #endif
  3187. else if (!strcmp(optname, "boulder"))
  3188. Sprintf(buf, "%c", iflags.bouldersym ?
  3189. iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]);
  3190. else if (!strcmp(optname, "catname"))
  3191. Sprintf(buf, "%s", catname[0] ? catname : none );
  3192. else if (!strcmp(optname, "disclose")) {
  3193. for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
  3194. char topt[2];
  3195. if (i) Strcat(buf," ");
  3196. topt[1] = '\0';
  3197. topt[0] = flags.end_disclose[i];
  3198. Strcat(buf, topt);
  3199. topt[0] = disclosure_options[i];
  3200. Strcat(buf, topt);
  3201. }
  3202. }
  3203. else if (!strcmp(optname, "dogname"))
  3204. Sprintf(buf, "%s", dogname[0] ? dogname : none );
  3205. else if (!strcmp(optname, "dungeon"))
  3206. Sprintf(buf, "%s", to_be_done);
  3207. else if (!strcmp(optname, "effects"))
  3208. Sprintf(buf, "%s", to_be_done);
  3209. else if (!strcmp(optname, "font_map"))
  3210. Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
  3211. else if (!strcmp(optname, "font_message"))
  3212. Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
  3213. else if (!strcmp(optname, "font_status"))
  3214. Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
  3215. else if (!strcmp(optname, "font_menu"))
  3216. Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
  3217. else if (!strcmp(optname, "font_text"))
  3218. Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
  3219. else if (!strcmp(optname, "font_size_map")) {
  3220. if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
  3221. else Strcpy(buf, defopt);
  3222. }
  3223. else if (!strcmp(optname, "font_size_message")) {
  3224. if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
  3225. iflags.wc_fontsiz_message);
  3226. else Strcpy(buf, defopt);
  3227. }
  3228. else if (!strcmp(optname, "font_size_status")) {
  3229. if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
  3230. else Strcpy(buf, defopt);
  3231. }
  3232. else if (!strcmp(optname, "font_size_menu")) {
  3233. if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
  3234. else Strcpy(buf, defopt);
  3235. }
  3236. else if (!strcmp(optname, "font_size_text")) {
  3237. if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
  3238. else Strcpy(buf, defopt);
  3239. }
  3240. else if (!strcmp(optname, "fruit"))
  3241. Sprintf(buf, "%s", pl_fruit);
  3242. else if (!strcmp(optname, "gender"))
  3243. Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
  3244. else if (!strcmp(optname, "ghoulname"))
  3245. Sprintf(buf, "%s", ghoulname[0] ? ghoulname : none );
  3246. else if (!strcmp(optname, "horsename"))
  3247. Sprintf(buf, "%s", horsename[0] ? horsename : none);
  3248. else if (!strcmp(optname, "map_mode"))
  3249. Sprintf(buf, "%s",
  3250. iflags.wc_map_mode == MAP_MODE_TILES ? "tiles" :
  3251. iflags.wc_map_mode == MAP_MODE_ASCII4x6 ? "ascii4x6" :
  3252. iflags.wc_map_mode == MAP_MODE_ASCII6x8 ? "ascii6x8" :
  3253. iflags.wc_map_mode == MAP_MODE_ASCII8x8 ? "ascii8x8" :
  3254. iflags.wc_map_mode == MAP_MODE_ASCII16x8 ? "ascii16x8" :
  3255. iflags.wc_map_mode == MAP_MODE_ASCII7x12 ? "ascii7x12" :
  3256. iflags.wc_map_mode == MAP_MODE_ASCII8x12 ? "ascii8x12" :
  3257. iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
  3258. iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
  3259. iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
  3260. iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
  3261. "fit_to_screen" : defopt);
  3262. else if (!strcmp(optname, "menustyle"))
  3263. Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
  3264. else if (!strcmp(optname, "menu_deselect_all"))
  3265. Sprintf(buf, "%s", to_be_done);
  3266. else if (!strcmp(optname, "menu_deselect_page"))
  3267. Sprintf(buf, "%s", to_be_done);
  3268. else if (!strcmp(optname, "menu_first_page"))
  3269. Sprintf(buf, "%s", to_be_done);
  3270. else if (!strcmp(optname, "menu_invert_all"))
  3271. Sprintf(buf, "%s", to_be_done);
  3272. else if (!strcmp(optname, "menu_headings")) {
  3273. Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
  3274. "bold" : (iflags.menu_headings == ATR_INVERSE) ?
  3275. "inverse" : (iflags.menu_headings == ATR_ULINE) ?
  3276. "underline" : "unknown");
  3277. }
  3278. else if (!strcmp(optname, "menu_invert_page"))
  3279. Sprintf(buf, "%s", to_be_done);
  3280. else if (!strcmp(optname, "menu_last_page"))
  3281. Sprintf(buf, "%s", to_be_done);
  3282. else if (!strcmp(optname, "menu_next_page"))
  3283. Sprintf(buf, "%s", to_be_done);
  3284. else if (!strcmp(optname, "menu_previous_page"))
  3285. Sprintf(buf, "%s", to_be_done);
  3286. else if (!strcmp(optname, "menu_search"))
  3287. Sprintf(buf, "%s", to_be_done);
  3288. else if (!strcmp(optname, "menu_select_all"))
  3289. Sprintf(buf, "%s", to_be_done);
  3290. else if (!strcmp(optname, "menu_select_page"))
  3291. Sprintf(buf, "%s", to_be_done);
  3292. else if (!strcmp(optname, "monsters"))
  3293. Sprintf(buf, "%s", to_be_done);
  3294. else if (!strcmp(optname, "msghistory"))
  3295. Sprintf(buf, "%u", iflags.msg_history);
  3296. #ifdef TTY_GRAPHICS
  3297. else if (!strcmp(optname, "msg_window"))
  3298. Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
  3299. (iflags.prevmsg_window=='c') ? "combination" :
  3300. (iflags.prevmsg_window=='f') ? "full" : "reversed");
  3301. #endif
  3302. else if (!strcmp(optname, "name"))
  3303. Sprintf(buf, "%s", plname);
  3304. else if (!strcmp(optname, "number_pad"))
  3305. Sprintf(buf, "%s",
  3306. (!iflags.num_pad) ? "0=off" :
  3307. (iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on");
  3308. else if (!strcmp(optname, "objects"))
  3309. Sprintf(buf, "%s", to_be_done);
  3310. else if (!strcmp(optname, "packorder")) {
  3311. oc_to_str(flags.inv_order, ocl);
  3312. Sprintf(buf, "%s", ocl);
  3313. }
  3314. #ifdef CHANGE_COLOR
  3315. else if (!strcmp(optname, "palette"))
  3316. Sprintf(buf, "%s", get_color_string());
  3317. #endif
  3318. else if (!strcmp(optname, "pettype"))
  3319. Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
  3320. (preferred_pet == 'd') ? "dog" :
  3321. (preferred_pet == 'n') ? "none" : "random");
  3322. else if (!strcmp(optname, "pickup_burden"))
  3323. Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
  3324. else if (!strcmp(optname, "pickup_types")) {
  3325. oc_to_str(flags.pickup_types, ocl);
  3326. Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
  3327. }
  3328. else if (!strcmp(optname, "race"))
  3329. Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
  3330. else if (!strcmp(optname, "role"))
  3331. Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
  3332. else if (!strcmp(optname, "runmode"))
  3333. Sprintf(buf, "%s", runmodes[iflags.runmode]);
  3334. else if (!strcmp(optname, "scores")) {
  3335. Sprintf(buf, "%d top/%d around%s", flags.end_top,
  3336. flags.end_around, flags.end_own ? "/own" : "");
  3337. }
  3338. else if (!strcmp(optname, "scroll_amount")) {
  3339. if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
  3340. else Strcpy(buf, defopt);
  3341. }
  3342. else if (!strcmp(optname, "scroll_margin")) {
  3343. if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
  3344. else Strcpy(buf, defopt);
  3345. }
  3346. else if (!strcmp(optname, "player_selection"))
  3347. Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
  3348. #ifdef MSDOS
  3349. else if (!strcmp(optname, "soundcard"))
  3350. Sprintf(buf, "%s", to_be_done);
  3351. #endif
  3352. else if (!strcmp(optname, "suppress_alert")) {
  3353. if (flags.suppress_alert == 0L)
  3354. Strcpy(buf, none);
  3355. else
  3356. Sprintf(buf, "%lu.%lu.%lu",
  3357. FEATURE_NOTICE_VER_MAJ,
  3358. FEATURE_NOTICE_VER_MIN,
  3359. FEATURE_NOTICE_VER_PATCH);
  3360. }
  3361. else if (!strcmp(optname, "tile_file"))
  3362. Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
  3363. else if (!strcmp(optname, "tile_height")) {
  3364. if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
  3365. else Strcpy(buf, defopt);
  3366. }
  3367. else if (!strcmp(optname, "tile_width")) {
  3368. if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
  3369. else Strcpy(buf, defopt);
  3370. }
  3371. else if (!strcmp(optname, "tileset"))
  3372. Sprintf(buf, "%s", tileset[0] ? tileset : none );
  3373. else if (!strcmp(optname, "traps"))
  3374. Sprintf(buf, "%s", to_be_done);
  3375. else if (!strcmp(optname, "vary_msgcount")) {
  3376. if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
  3377. else Strcpy(buf, defopt);
  3378. }
  3379. #ifdef MSDOS
  3380. else if (!strcmp(optname, "video"))
  3381. Sprintf(buf, "%s", to_be_done);
  3382. #endif
  3383. #ifdef VIDEOSHADES
  3384. # ifdef MSDOS
  3385. else if (!strcmp(optname, "videoshades"))
  3386. Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
  3387. else if (!strcmp(optname, "videocolors"))
  3388. Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
  3389. ttycolors[CLR_RED], ttycolors[CLR_GREEN],
  3390. ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
  3391. ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
  3392. ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
  3393. ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
  3394. ttycolors[CLR_BRIGHT_MAGENTA],
  3395. ttycolors[CLR_BRIGHT_CYAN]);
  3396. # else
  3397. else if (!strcmp(optname, "videocolors"))
  3398. Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
  3399. ttycolors[CLR_RED], ttycolors[CLR_GREEN],
  3400. ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
  3401. ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
  3402. ttycolors[CLR_GRAY], ttycolors[CLR_BLACK],
  3403. ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
  3404. ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
  3405. ttycolors[CLR_BRIGHT_MAGENTA],
  3406. ttycolors[CLR_BRIGHT_CYAN], ttycolors[CLR_WHITE]);
  3407. # endif /* MSDOS */
  3408. #endif /* VIDEOSHADES */
  3409. else if (!strcmp(optname, "windowtype"))
  3410. Sprintf(buf, "%s", windowprocs.name);
  3411. else if (!strcmp(optname, "windowcolors"))
  3412. Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
  3413. iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
  3414. iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
  3415. iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
  3416. iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
  3417. iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
  3418. iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
  3419. iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
  3420. iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
  3421. else if (!strcmp(optname, "wolfname"))
  3422. Sprintf(buf, "%s", wolfname[0] ? wolfname : none );
  3423. #ifdef PREFIXES_IN_USE
  3424. else {
  3425. for (i = 0; i < PREFIX_COUNT; ++i)
  3426. if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
  3427. Sprintf(buf, "%s", fqn_prefix[i]);
  3428. }
  3429. #endif
  3430. if (buf[0]) return buf;
  3431. else return "unknown";
  3432. }
  3433. int
  3434. dotogglepickup()
  3435. {
  3436. char buf[BUFSZ], ocl[MAXOCLASSES+1];
  3437. flags.pickup = !flags.pickup;
  3438. if (flags.pickup) {
  3439. oc_to_str(flags.pickup_types, ocl);
  3440. Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
  3441. #ifdef AUTOPICKUP_EXCEPTIONS
  3442. (iflags.autopickup_exceptions[AP_LEAVE] ||
  3443. iflags.autopickup_exceptions[AP_GRAB]) ?
  3444. ((count_ape_maps((int *)0, (int *)0) == 1) ?
  3445. ", with one exception" : ", with some exceptions") :
  3446. #endif
  3447. "");
  3448. } else {
  3449. Strcpy(buf, "OFF");
  3450. }
  3451. pline("Autopickup: %s.", buf);
  3452. return 0;
  3453. }
  3454. #ifdef AUTOPICKUP_EXCEPTIONS
  3455. int
  3456. add_autopickup_exception(mapping)
  3457. const char *mapping;
  3458. {
  3459. struct autopickup_exception *ape, **apehead;
  3460. char text[256], *text2;
  3461. int textsize = 0;
  3462. boolean grab = FALSE;
  3463. if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
  3464. text2 = &text[0];
  3465. if (*text2 == '<') { /* force autopickup */
  3466. grab = TRUE;
  3467. ++text2;
  3468. } else if (*text2 == '>') { /* default - Do not pickup */
  3469. grab = FALSE;
  3470. ++text2;
  3471. }
  3472. textsize = strlen(text2);
  3473. apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
  3474. &iflags.autopickup_exceptions[AP_LEAVE];
  3475. ape = (struct autopickup_exception *)
  3476. alloc(sizeof(struct autopickup_exception));
  3477. ape->pattern = (char *) alloc(textsize+1);
  3478. Strcpy(ape->pattern, text2);
  3479. ape->grab = grab;
  3480. if (!*apehead) ape->next = (struct autopickup_exception *)0;
  3481. else ape->next = *apehead;
  3482. *apehead = ape;
  3483. } else {
  3484. raw_print("syntax error in AUTOPICKUP_EXCEPTION");
  3485. return 0;
  3486. }
  3487. return 1;
  3488. }
  3489. STATIC_OVL void
  3490. remove_autopickup_exception(whichape)
  3491. struct autopickup_exception *whichape;
  3492. {
  3493. struct autopickup_exception *ape, *prev = 0;
  3494. int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
  3495. for (ape = iflags.autopickup_exceptions[chain]; ape;) {
  3496. if (ape == whichape) {
  3497. struct autopickup_exception *freeape = ape;
  3498. ape = ape->next;
  3499. if (prev) prev->next = ape;
  3500. else iflags.autopickup_exceptions[chain] = ape;
  3501. free(freeape->pattern);
  3502. free(freeape);
  3503. } else {
  3504. prev = ape;
  3505. ape = ape->next;
  3506. }
  3507. }
  3508. }
  3509. STATIC_OVL int
  3510. count_ape_maps(leave, grab)
  3511. int *leave, *grab;
  3512. {
  3513. struct autopickup_exception *ape;
  3514. int pass, totalapes, numapes[2] = {0,0};
  3515. for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
  3516. ape = iflags.autopickup_exceptions[pass];
  3517. while(ape) {
  3518. ape = ape->next;
  3519. numapes[pass]++;
  3520. }
  3521. }
  3522. totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
  3523. if (leave) *leave = numapes[AP_LEAVE];
  3524. if (grab) *grab = numapes[AP_GRAB];
  3525. return totalapes;
  3526. }
  3527. void
  3528. free_autopickup_exceptions()
  3529. {
  3530. struct autopickup_exception *ape;
  3531. int pass;
  3532. for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
  3533. while((ape = iflags.autopickup_exceptions[pass]) != 0) {
  3534. free(ape->pattern);
  3535. iflags.autopickup_exceptions[pass] = ape->next;
  3536. free(ape);
  3537. }
  3538. }
  3539. }
  3540. #endif /* AUTOPICKUP_EXCEPTIONS */
  3541. /* data for option_help() */
  3542. static const char *opt_intro[] = {
  3543. "",
  3544. " SlashEM Options Help:",
  3545. "",
  3546. #define CONFIG_SLOT 3 /* fill in next value at run-time */
  3547. (char *)0,
  3548. #define ENV_SLOT 4 /* substitute variable name in next value at run-time */
  3549. #if !defined(MICRO) && !defined(MAC)
  3550. "or use `%s=\"<options>\"' in your environment",
  3551. #endif
  3552. "(<options> is a list of options separated by commas)",
  3553. #ifdef VMS
  3554. "-- for example, $ DEFINE %s \"noautopickup,fruit:kumquat\"",
  3555. #endif
  3556. "or press \"O\" while playing and use the menu.",
  3557. "",
  3558. "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
  3559. (char *)0
  3560. };
  3561. static const char *opt_epilog[] = {
  3562. "",
  3563. "Some of the options can be set only before the game is started; those",
  3564. "items will not be selectable in the 'O' command's menu.",
  3565. (char *)0
  3566. };
  3567. void
  3568. option_help()
  3569. {
  3570. char buf[BUFSZ], buf2[BUFSZ];
  3571. register int i;
  3572. winid datawin;
  3573. datawin = create_nhwindow(NHW_TEXT);
  3574. Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
  3575. opt_intro[CONFIG_SLOT] = (const char *) buf;
  3576. for (i = 0; opt_intro[i]; i++)
  3577. if (i==ENV_SLOT)
  3578. {
  3579. Sprintf(buf2, opt_intro[ENV_SLOT], NETHACK_ENV_OPTIONS);
  3580. putstr(datawin, 0, buf2);;
  3581. }
  3582. else
  3583. putstr(datawin, 0, opt_intro[i]);
  3584. /* Boolean options */
  3585. for (i = 0; boolopt[i].name; i++) {
  3586. if (boolopt[i].addr) {
  3587. #ifdef WIZARD
  3588. #ifndef OBJ_SANITY
  3589. if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
  3590. #endif
  3591. if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
  3592. #endif
  3593. next_opt(datawin, boolopt[i].name);
  3594. }
  3595. }
  3596. next_opt(datawin, "");
  3597. /* Compound options */
  3598. putstr(datawin, 0, "Compound options:");
  3599. for (i = 0; compopt[i].name; i++) {
  3600. Sprintf(buf2, "`%s'", compopt[i].name);
  3601. Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
  3602. compopt[i+1].name ? ',' : '.');
  3603. putstr(datawin, 0, buf);
  3604. }
  3605. for (i = 0; opt_epilog[i]; i++)
  3606. putstr(datawin, 0, opt_epilog[i]);
  3607. display_nhwindow(datawin, FALSE);
  3608. destroy_nhwindow(datawin);
  3609. return;
  3610. }
  3611. /*
  3612. * prints the next boolean option, on the same line if possible, on a new
  3613. * line if not. End with next_opt("").
  3614. */
  3615. void
  3616. next_opt(datawin, str)
  3617. winid datawin;
  3618. const char *str;
  3619. {
  3620. static char *buf = 0;
  3621. int i;
  3622. char *s;
  3623. if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';
  3624. if (!*str) {
  3625. s = eos(buf);
  3626. if (s > &buf[1] && s[-2] == ',')
  3627. Strcpy(s - 2, "."); /* replace last ", " */
  3628. i = COLNO; /* (greater than COLNO - 2) */
  3629. } else {
  3630. i = strlen(buf) + strlen(str) + 2;
  3631. }
  3632. if (i > COLNO - 2) { /* rule of thumb */
  3633. putstr(datawin, 0, buf);
  3634. buf[0] = 0;
  3635. }
  3636. if (*str) {
  3637. Strcat(buf, str);
  3638. Strcat(buf, ", ");
  3639. } else {
  3640. putstr(datawin, 0, str);
  3641. free(buf), buf = 0;
  3642. }
  3643. return;
  3644. }
  3645. /* Returns the fid of the fruit type; if that type already exists, it
  3646. * returns the fid of that one; if it does not exist, it adds a new fruit
  3647. * type to the chain and returns the new one.
  3648. */
  3649. int
  3650. fruitadd(str)
  3651. char *str;
  3652. {
  3653. register int i;
  3654. register struct fruit *f;
  3655. struct fruit *lastf = 0;
  3656. int highest_fruit_id = 0;
  3657. char buf[PL_FSIZ];
  3658. boolean user_specified = (str == pl_fruit);
  3659. /* if not user-specified, then it's a fruit name for a fruit on
  3660. * a bones level...
  3661. */
  3662. /* Note: every fruit has an id (spe for fruit objects) of at least
  3663. * 1; 0 is an error.
  3664. */
  3665. if (user_specified) {
  3666. /* disallow naming after other foods (since it'd be impossible
  3667. * to tell the difference)
  3668. */
  3669. boolean found = FALSE, numeric = FALSE;
  3670. for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
  3671. i++) {
  3672. if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
  3673. found = TRUE;
  3674. break;
  3675. }
  3676. }
  3677. {
  3678. char *c;
  3679. c = pl_fruit;
  3680. for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
  3681. ;
  3682. if (isspace(*c) || *c == 0) numeric = TRUE;
  3683. }
  3684. if (found || numeric ||
  3685. !strncmp(str, "cursed ", 7) ||
  3686. !strncmp(str, "uncursed ", 9) ||
  3687. !strncmp(str, "blessed ", 8) ||
  3688. !strncmp(str, "partly eaten ", 13) ||
  3689. (!strncmp(str, "tin of ", 7) &&
  3690. (!strcmp(str+7, "spinach") ||
  3691. name_to_mon(str+7) >= LOW_PM)) ||
  3692. !strcmp(str, "empty tin") ||
  3693. ((!strncmp(eos(str)-7," corpse",7) ||
  3694. !strncmp(eos(str)-4, " egg",4)) &&
  3695. name_to_mon(str) >= LOW_PM))
  3696. {
  3697. Strcpy(buf, pl_fruit);
  3698. Strcpy(pl_fruit, "candied ");
  3699. nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
  3700. }
  3701. }
  3702. for(f=ffruit; f; f = f->nextf) {
  3703. lastf = f;
  3704. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
  3705. if(!strncmp(str, f->fname, PL_FSIZ))
  3706. goto nonew;
  3707. }
  3708. /* if adding another fruit would overflow spe, use a random
  3709. fruit instead... we've got a lot to choose from. */
  3710. if (highest_fruit_id >= 127) return rnd(127);
  3711. highest_fruit_id++;
  3712. f = newfruit();
  3713. if (ffruit) lastf->nextf = f;
  3714. else ffruit = f;
  3715. Strcpy(f->fname, str);
  3716. f->fid = highest_fruit_id;
  3717. f->nextf = 0;
  3718. nonew:
  3719. if (user_specified) current_fruit = highest_fruit_id;
  3720. return f->fid;
  3721. }
  3722. /*
  3723. * This is a somewhat generic menu for taking a list of NetHack style
  3724. * class choices and presenting them via a description
  3725. * rather than the traditional NetHack characters.
  3726. * (Benefits users whose first exposure to NetHack is via tiles).
  3727. *
  3728. * prompt
  3729. * The title at the top of the menu.
  3730. *
  3731. * category: 0 = monster class
  3732. * 1 = object class
  3733. *
  3734. * way
  3735. * FALSE = PICK_ONE, TRUE = PICK_ANY
  3736. *
  3737. * class_list
  3738. * a null terminated string containing the list of choices.
  3739. *
  3740. * class_selection
  3741. * a null terminated string containing the selected characters.
  3742. *
  3743. * Returns number selected.
  3744. */
  3745. int
  3746. choose_classes_menu(prompt, category, way, class_list, class_select)
  3747. const char *prompt;
  3748. int category;
  3749. boolean way;
  3750. char *class_list;
  3751. char *class_select;
  3752. {
  3753. menu_item *pick_list = (menu_item *)0;
  3754. winid win;
  3755. anything any;
  3756. char buf[BUFSZ];
  3757. int i, n;
  3758. int ret;
  3759. int next_accelerator, accelerator;
  3760. if (class_list == (char *)0 || class_select == (char *)0) return 0;
  3761. accelerator = 0;
  3762. next_accelerator = 'a';
  3763. any.a_void = 0;
  3764. win = create_nhwindow(NHW_MENU);
  3765. start_menu(win);
  3766. while (*class_list) {
  3767. const char *text;
  3768. boolean selected;
  3769. text = (char *)0;
  3770. selected = FALSE;
  3771. switch (category) {
  3772. case 0:
  3773. text = monexplain[def_char_to_monclass(*class_list)];
  3774. accelerator = *class_list;
  3775. Sprintf(buf, "%s", text);
  3776. break;
  3777. case 1:
  3778. text = objexplain[def_char_to_objclass(*class_list)];
  3779. accelerator = next_accelerator;
  3780. Sprintf(buf, "%c %s", *class_list, text);
  3781. break;
  3782. default:
  3783. impossible("choose_classes_menu: invalid category %d",
  3784. category);
  3785. }
  3786. if (way && *class_select) { /* Selections there already */
  3787. if (index(class_select, *class_list)) {
  3788. selected = TRUE;
  3789. }
  3790. }
  3791. any.a_int = *class_list;
  3792. add_menu(win, NO_GLYPH, &any, accelerator,
  3793. category ? *class_list : 0,
  3794. ATR_NONE, buf, selected);
  3795. ++class_list;
  3796. if (category > 0) {
  3797. ++next_accelerator;
  3798. if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
  3799. if (next_accelerator == ('Z' + 1)) break;
  3800. }
  3801. }
  3802. end_menu(win, prompt);
  3803. n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
  3804. destroy_nhwindow(win);
  3805. if (n > 0) {
  3806. for (i = 0; i < n; ++i)
  3807. *class_select++ = (char)pick_list[i].item.a_int;
  3808. free((genericptr_t)pick_list);
  3809. ret = n;
  3810. } else if (n == -1) {
  3811. class_select = eos(class_select);
  3812. ret = -1;
  3813. } else
  3814. ret = 0;
  3815. *class_select = '\0';
  3816. return ret;
  3817. }
  3818. struct wc_Opt wc_options[] = {
  3819. {"ascii_map", WC_ASCII_MAP},
  3820. {"color", WC_COLOR},
  3821. {"eight_bit_tty", WC_EIGHT_BIT_IN},
  3822. {"hilite_pet", WC_HILITE_PET},
  3823. {"popup_dialog", WC_POPUP_DIALOG},
  3824. {"player_selection", WC_PLAYER_SELECTION},
  3825. {"preload_tiles", WC_PRELOAD_TILES},
  3826. {"tiled_map", WC_TILED_MAP},
  3827. {"tile_file", WC_TILE_FILE},
  3828. {"tile_width", WC_TILE_WIDTH},
  3829. {"tile_height", WC_TILE_HEIGHT},
  3830. {"use_inverse", WC_INVERSE},
  3831. {"align_message", WC_ALIGN_MESSAGE},
  3832. {"align_status", WC_ALIGN_STATUS},
  3833. {"font_map", WC_FONT_MAP},
  3834. {"font_menu", WC_FONT_MENU},
  3835. {"font_message",WC_FONT_MESSAGE},
  3836. #if 0
  3837. {"perm_invent",WC_PERM_INVENT},
  3838. #endif
  3839. {"font_size_map", WC_FONTSIZ_MAP},
  3840. {"font_size_menu", WC_FONTSIZ_MENU},
  3841. {"font_size_message", WC_FONTSIZ_MESSAGE},
  3842. {"font_size_status", WC_FONTSIZ_STATUS},
  3843. {"font_size_text", WC_FONTSIZ_TEXT},
  3844. {"font_status", WC_FONT_STATUS},
  3845. {"font_text", WC_FONT_TEXT},
  3846. {"map_mode", WC_MAP_MODE},
  3847. {"scroll_amount", WC_SCROLL_AMOUNT},
  3848. {"scroll_margin", WC_SCROLL_MARGIN},
  3849. {"splash_screen", WC_SPLASH_SCREEN},
  3850. {"vary_msgcount",WC_VARY_MSGCOUNT},
  3851. {"windowcolors", WC_WINDOWCOLORS},
  3852. {"mouse_support", WC_MOUSE_SUPPORT},
  3853. {(char *)0, 0L}
  3854. };
  3855. struct wc_Opt wc2_options[] = {
  3856. {"fullscreen", WC2_FULLSCREEN},
  3857. {"softkeyboard", WC2_SOFTKEYBOARD},
  3858. {"wraptext", WC2_WRAPTEXT},
  3859. {(char *)0, 0L}
  3860. };
  3861. /*
  3862. * If a port wants to change or ensure that the
  3863. * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
  3864. * correct (for controlling its display in the option menu) call
  3865. * set_option_mod_status()
  3866. * with the second argument of 0,2, or 3 respectively.
  3867. */
  3868. void
  3869. set_option_mod_status(optnam, status)
  3870. const char *optnam;
  3871. int status;
  3872. {
  3873. int k;
  3874. if (status < SET_IN_FILE || status > SET_IN_GAME) {
  3875. impossible("set_option_mod_status: status out of range %d.",
  3876. status);
  3877. return;
  3878. }
  3879. for (k = 0; boolopt[k].name; k++) {
  3880. if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
  3881. boolopt[k].optflags = status;
  3882. return;
  3883. }
  3884. }
  3885. for (k = 0; compopt[k].name; k++) {
  3886. if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
  3887. compopt[k].optflags = status;
  3888. return;
  3889. }
  3890. }
  3891. }
  3892. /*
  3893. * You can set several wc_options in one call to
  3894. * set_wc_option_mod_status() by setting
  3895. * the appropriate bits for each option that you
  3896. * are setting in the optmask argument
  3897. * prior to calling.
  3898. * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME);
  3899. */
  3900. void
  3901. set_wc_option_mod_status(optmask, status)
  3902. unsigned long optmask;
  3903. int status;
  3904. {
  3905. int k = 0;
  3906. if (status < SET_IN_FILE || status > SET_IN_GAME) {
  3907. impossible("set_wc_option_mod_status: status out of range %d.",
  3908. status);
  3909. return;
  3910. }
  3911. while (wc_options[k].wc_name) {
  3912. if (optmask & wc_options[k].wc_bit) {
  3913. set_option_mod_status(wc_options[k].wc_name, status);
  3914. }
  3915. k++;
  3916. }
  3917. }
  3918. STATIC_OVL boolean
  3919. is_wc_option(optnam)
  3920. const char *optnam;
  3921. {
  3922. int k = 0;
  3923. while (wc_options[k].wc_name) {
  3924. if (strcmp(wc_options[k].wc_name, optnam) == 0)
  3925. return TRUE;
  3926. k++;
  3927. }
  3928. return FALSE;
  3929. }
  3930. STATIC_OVL boolean
  3931. wc_supported(optnam)
  3932. const char *optnam;
  3933. {
  3934. int k = 0;
  3935. while (wc_options[k].wc_name) {
  3936. if (!strcmp(wc_options[k].wc_name, optnam) &&
  3937. (windowprocs.wincap & wc_options[k].wc_bit))
  3938. return TRUE;
  3939. k++;
  3940. }
  3941. return FALSE;
  3942. }
  3943. /*
  3944. * You can set several wc2_options in one call to
  3945. * set_wc2_option_mod_status() by setting
  3946. * the appropriate bits for each option that you
  3947. * are setting in the optmask argument
  3948. * prior to calling.
  3949. * example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
  3950. */
  3951. void
  3952. set_wc2_option_mod_status(optmask, status)
  3953. unsigned long optmask;
  3954. int status;
  3955. {
  3956. int k = 0;
  3957. if (status < SET_IN_FILE || status > SET_IN_GAME) {
  3958. impossible("set_wc2_option_mod_status: status out of range %d.",
  3959. status);
  3960. return;
  3961. }
  3962. while (wc2_options[k].wc_name) {
  3963. if (optmask & wc2_options[k].wc_bit) {
  3964. set_option_mod_status(wc2_options[k].wc_name, status);
  3965. }
  3966. k++;
  3967. }
  3968. }
  3969. STATIC_OVL boolean
  3970. is_wc2_option(optnam)
  3971. const char *optnam;
  3972. {
  3973. int k = 0;
  3974. while (wc2_options[k].wc_name) {
  3975. if (strcmp(wc2_options[k].wc_name, optnam) == 0)
  3976. return TRUE;
  3977. k++;
  3978. }
  3979. return FALSE;
  3980. }
  3981. STATIC_OVL boolean
  3982. wc2_supported(optnam)
  3983. const char *optnam;
  3984. {
  3985. int k = 0;
  3986. while (wc2_options[k].wc_name) {
  3987. if (!strcmp(wc2_options[k].wc_name, optnam) &&
  3988. (windowprocs.wincap2 & wc2_options[k].wc_bit))
  3989. return TRUE;
  3990. k++;
  3991. }
  3992. return FALSE;
  3993. }
  3994. STATIC_OVL void
  3995. wc_set_font_name(wtype, fontname)
  3996. int wtype;
  3997. char *fontname;
  3998. {
  3999. char **fn = (char **)0;
  4000. if (!fontname) return;
  4001. switch(wtype) {
  4002. case NHW_MAP:
  4003. fn = &iflags.wc_font_map;
  4004. break;
  4005. case NHW_MESSAGE:
  4006. fn = &iflags.wc_font_message;
  4007. break;
  4008. case NHW_TEXT:
  4009. fn = &iflags.wc_font_text;
  4010. break;
  4011. case NHW_MENU:
  4012. fn = &iflags.wc_font_menu;
  4013. break;
  4014. case NHW_STATUS:
  4015. fn = &iflags.wc_font_status;
  4016. break;
  4017. default:
  4018. return;
  4019. }
  4020. if (fn) {
  4021. if (*fn) free(*fn);
  4022. *fn = (char *)alloc(strlen(fontname) + 1);
  4023. Strcpy(*fn, fontname);
  4024. }
  4025. return;
  4026. }
  4027. STATIC_OVL int
  4028. wc_set_window_colors(op)
  4029. char *op;
  4030. {
  4031. /* syntax:
  4032. * menu white/black message green/yellow status white/blue text white/black
  4033. */
  4034. int j;
  4035. char buf[BUFSZ];
  4036. char *wn, *tfg, *tbg, *newop;
  4037. static const char *wnames[] = { "menu", "message", "status", "text" };
  4038. static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
  4039. static char **fgp[] = {
  4040. &iflags.wc_foregrnd_menu,
  4041. &iflags.wc_foregrnd_message,
  4042. &iflags.wc_foregrnd_status,
  4043. &iflags.wc_foregrnd_text
  4044. };
  4045. static char **bgp[] = {
  4046. &iflags.wc_backgrnd_menu,
  4047. &iflags.wc_backgrnd_message,
  4048. &iflags.wc_backgrnd_status,
  4049. &iflags.wc_backgrnd_text
  4050. };
  4051. Strcpy(buf, op);
  4052. newop = mungspaces(buf);
  4053. while (newop && *newop) {
  4054. wn = tfg = tbg = (char *)0;
  4055. /* until first non-space in case there's leading spaces - before colorname*/
  4056. while(*newop && isspace(*newop)) newop++;
  4057. if (*newop) wn = newop;
  4058. else return 0;
  4059. /* until first space - colorname*/
  4060. while(*newop && !isspace(*newop)) newop++;
  4061. if (*newop) *newop = '\0';
  4062. else return 0;
  4063. newop++;
  4064. /* until first non-space - before foreground*/
  4065. while(*newop && isspace(*newop)) newop++;
  4066. if (*newop) tfg = newop;
  4067. else return 0;
  4068. /* until slash - foreground */
  4069. while(*newop && *newop != '/') newop++;
  4070. if (*newop) *newop = '\0';
  4071. else return 0;
  4072. newop++;
  4073. /* until first non-space (in case there's leading space after slash) - before background */
  4074. while(*newop && isspace(*newop)) newop++;
  4075. if (*newop) tbg = newop;
  4076. else return 0;
  4077. /* until first space - background */
  4078. while(*newop && !isspace(*newop)) newop++;
  4079. if (*newop) *newop++ = '\0';
  4080. for (j = 0; j < 4; ++j) {
  4081. if (!strcmpi(wn, wnames[j]) ||
  4082. !strcmpi(wn, shortnames[j])) {
  4083. if (tfg && !strstri(tfg, " ")) {
  4084. if (*fgp[j]) free(*fgp[j]);
  4085. *fgp[j] = (char *)alloc(strlen(tfg) + 1);
  4086. Strcpy(*fgp[j], tfg);
  4087. }
  4088. if (tbg && !strstri(tbg, " ")) {
  4089. if (*bgp[j]) free(*bgp[j]);
  4090. *bgp[j] = (char *)alloc(strlen(tbg) + 1);
  4091. Strcpy(*bgp[j], tbg);
  4092. }
  4093. break;
  4094. }
  4095. }
  4096. }
  4097. return 1;
  4098. }
  4099. #endif /* OPTION_LISTS_ONLY */
  4100. /*options.c*/