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

/src/options.c

https://bitbucket.org/Andy51/nethack
C | 3862 lines | 3406 code | 173 blank | 283 comment | 806 complexity | a0197c347862855a8a9a2a83e0207365 MD5 | raw file
Possible License(s): LGPL-2.0

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

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

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