Source:NetHack 3.3.0/options.c
Jump to navigation
Jump to search
Below is the full text to options.c from the source code of NetHack 3.3.0. To link to a particular line, write [[NetHack 3.3.0/options.c#line123]], for example.
Warning! This is the source code from an old release. For the latest release, see Source code
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
1. /* SCCS Id: @(#)options.c 3.3 1999/12/01 */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */ 6. #include "config.h" 7. #include "objclass.h" 8. #include "flag.h" 9. NEARDATA struct flag flags; /* provide linkage */ 10. NEARDATA struct instance_flags iflags; /* provide linkage */ 11. #define static 12. #else 13. #include "hack.h" 14. #include "tcap.h" 15. #include <ctype.h> 16. #endif 17. 18. #define WINTYPELEN 16 19. 20. /* 21. * NOTE: If you add (or delete) an option, please update the short 22. * options help (option_help()), the long options help (dat/opthelp), 23. * and the current options setting display function (doset()), 24. * and also the Guidebooks. 25. */ 26. 27. static struct Bool_Opt 28. { 29. const char *name; 30. boolean *addr, initvalue; 31. } boolopt[] = { 32. #ifdef AMIGA 33. {"altmeta", &flags.altmeta, TRUE}, 34. #else 35. {"altmeta", (boolean *)0, TRUE}, 36. #endif 37. #ifdef MFLOPPY 38. {"asksavedisk", &flags.asksavedisk, FALSE}, 39. #else 40. {"asksavedisk", (boolean *)0, FALSE}, 41. #endif 42. {"autopickup", &flags.pickup, TRUE}, 43. {"autoquiver", &flags.autoquiver, FALSE}, 44. #if defined(MICRO) && !defined(AMIGA) 45. {"BIOS", &iflags.BIOS, FALSE}, 46. #else 47. {"BIOS", (boolean *)0, FALSE}, 48. #endif 49. #ifdef INSURANCE 50. {"checkpoint", &flags.ins_chkpt, TRUE}, 51. #else 52. {"checkpoint", (boolean *)0, FALSE}, 53. #endif 54. #ifdef TEXTCOLOR 55. # ifdef MICRO 56. {"color", &iflags.use_color, TRUE}, 57. # else /* systems that support multiple terminals, many monochrome */ 58. {"color", &iflags.use_color, FALSE}, 59. # endif 60. #else 61. {"color", (boolean *)0, FALSE}, 62. #endif 63. {"confirm",&flags.confirm, TRUE}, 64. #ifdef TERMLIB 65. {"DECgraphics", &iflags.DECgraphics, FALSE}, 66. #else 67. {"DECgraphics", (boolean *)0, FALSE}, 68. #endif 69. #ifdef TTY_GRAPHICS 70. {"extmenu", &iflags.extmenu, FALSE}, 71. #endif 72. #ifdef OPT_DISPMAP 73. {"fast_map", &flags.fast_map, TRUE}, 74. #else 75. {"fast_map", (boolean *)0, TRUE}, 76. #endif 77. {"female", &flags.female, FALSE}, 78. {"fixinv", &flags.invlet_constant, TRUE}, 79. #ifdef AMIFLUSH 80. {"flush", &flags.amiflush, FALSE}, 81. #else 82. {"flush", (boolean *)0, FALSE}, 83. #endif 84. {"help", &flags.help, TRUE}, 85. #ifdef TEXTCOLOR 86. {"hilite_pet", &iflags.hilite_pet, FALSE}, 87. #else 88. {"hilite_pet", (boolean *)0, FALSE}, 89. #endif 90. #ifdef ASCIIGRAPH 91. {"IBMgraphics", &iflags.IBMgraphics, FALSE}, 92. #else 93. {"IBMgraphics", (boolean *)0, FALSE}, 94. #endif 95. {"ignintr", &flags.ignintr, FALSE}, 96. #ifdef MAC_GRAPHICS_ENV 97. {"large_font", &iflags.large_font, FALSE}, 98. #else 99. {"large_font", (boolean *)0, FALSE}, 100. #endif 101. {"legacy",&flags.legacy, TRUE}, 102. {"lit_corridor", &flags.lit_corridor, FALSE}, 103. #ifdef MAC_GRAPHICS_ENV 104. {"Macgraphics", &iflags.MACgraphics, TRUE}, 105. #else 106. {"Macgraphics", (boolean *)0, FALSE}, 107. #endif 108. #ifdef MAIL 109. {"mail", &flags.biff, TRUE}, 110. #else 111. {"mail", (boolean *)0, TRUE}, 112. #endif 113. #ifdef NEWS 114. {"news", &iflags.news, TRUE}, 115. #else 116. {"news", (boolean *)0, FALSE}, 117. #endif 118. {"null", &flags.null, TRUE}, 119. {"number_pad", &iflags.num_pad, FALSE}, 120. #ifdef MAC 121. {"page_wait", &flags.page_wait, TRUE}, 122. #else 123. {"page_wait", (boolean *)0, FALSE}, 124. #endif 125. {"perm_invent", &flags.perm_invent, FALSE}, 126. #ifdef MAC 127. {"popup_dialog", &iflags.popup_dialog, FALSE}, 128. #else 129. {"popup_dialog", (boolean *)0, FALSE}, 130. #endif 131. {"prayconfirm", &flags.prayconfirm, TRUE}, 132. #if defined(MSDOS) && defined(USE_TILES) 133. {"preload_tiles", &iflags.preload_tiles, TRUE}, 134. #else 135. {"preload_tiles", (boolean *)0, FALSE}, 136. #endif 137. {"pushweapon", &flags.pushweapon, FALSE}, 138. #if defined(MICRO) && !defined(AMIGA) 139. {"rawio", &iflags.rawio, FALSE}, 140. #else 141. {"rawio", (boolean *)0, FALSE}, 142. #endif 143. {"rest_on_space", &flags.rest_on_space, FALSE}, 144. {"safe_pet", &flags.safe_dog, TRUE}, 145. #ifdef WIZARD 146. {"sanity_check", &iflags.sanity_check, FALSE}, 147. #else 148. {"sanity_check", (boolean *)0, FALSE}, 149. #endif 150. #ifdef EXP_ON_BOTL 151. {"showexp", &flags.showexp, FALSE}, 152. #else 153. {"showexp", (boolean *)0, FALSE}, 154. #endif 155. #ifdef SCORE_ON_BOTL 156. {"showscore", &flags.showscore, FALSE}, 157. #else 158. {"showscore", (boolean *)0, FALSE}, 159. #endif 160. {"silent", &flags.silent, TRUE}, 161. {"sortpack", &flags.sortpack, TRUE}, 162. {"sound", &flags.soundok, TRUE}, 163. {"standout", &flags.standout, FALSE}, 164. {"time", &flags.time, FALSE}, 165. #ifdef TIMED_DELAY 166. {"timed_delay", &flags.nap, TRUE}, 167. #else 168. {"timed_delay", (boolean *)0, FALSE}, 169. #endif 170. {"tombstone",&flags.tombstone, TRUE}, 171. {"toptenwin",&flags.toptenwin, FALSE}, 172. {"verbose", &flags.verbose, TRUE}, 173. {(char *)0, (boolean *)0, FALSE} 174. }; 175. 176. /* compound options, for option_help() and external programs like Amiga 177. * frontend */ 178. static struct Comp_Opt 179. { 180. const char *name, *descr; 181. int size; /* for frontends and such allocating space -- 182. * usually allowed size of data in game, but 183. * occasionally maximum reasonable size for 184. * typing when game maintains information in 185. * a different format */ 186. } compopt[] = { 187. { "align", "your starting alignment (lawful, neutral, or chaotic)", 8 }, 188. #ifdef MAC 189. { "background", "the color of the background (black or white),", 6 }, 190. #endif 191. { "catname", "the name of your (first) cat (e.g., catname:Tabby)", 192. PL_PSIZ }, 193. { "disclose", "the kinds of information to disclose at end of game", 194. sizeof(flags.end_disclose) }, 195. { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", 196. PL_PSIZ }, 197. { "dungeon", "the symbols to use in drawing the dungeon map", 198. MAXDCHARS+1 }, 199. { "effects", "the symbols to use in drawing special effects", 200. MAXECHARS+1 }, 201. #ifdef MAC 202. { "fontmap", "the font to use in the map window,", 40 }, 203. { "fontmessage", "the font to use in the message window,", 40 }, 204. { "fonttext", "the font to use in text windows,", 40 }, 205. #endif 206. { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ }, 207. { "gender", "your starting gender (male or female)", 8 }, 208. { "horsename", "the name of your (first) horse (e.g., horsename:Trigger)", 209. PL_PSIZ }, 210. { "menustyle", "user interface for object selection", MENUTYPELEN }, 211. { "menu_deselect_all", "deselect all items in a menu", 4}, 212. { "menu_deselect_page", "deselect all items on this page of a menu", 4}, 213. { "menu_first_page", "jump to the first page in a menu", 4}, 214. { "menu_invert_all", "invert all items in a menu", 4}, 215. { "menu_invert_page", "invert all items on this page of a menu", 4}, 216. { "menu_last_page", "jump to the last page in a menu", 4}, 217. { "menu_next_page", "goto the next menu page", 4}, 218. { "menu_previous_page", "goto the previous menu page", 4}, 219. { "menu_search", "search for a menu item", 4}, 220. { "menu_select_all", "select all items in a menu", 4}, 221. { "menu_select_page", "select all items on this page of a menu", 4}, 222. { "monsters", "the symbols to use for monsters", MAXMCLASSES }, 223. { "msghistory", "number of top line messages to save", 5 }, 224. { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ }, 225. { "objects", "the symbols to use for objects", MAXOCLASSES }, 226. { "packorder", "the inventory order of the items in your pack", 227. MAXOCLASSES }, 228. #ifdef CHANGE_COLOR 229. { "palette", "palette (00c/880/-fff is blue/yellow/reverse white)", 230. 15 }, 231. # if defined(MAC) 232. { "hicolor", "same as palette, only order is reversed", 15 }, 233. # endif 234. #endif 235. { "pettype", "your preferred initial pet type", 4 }, 236. { "pickup_burden", "maximum burden picked up before prompt", 20 }, 237. { "pickup_types", "types of objects to pick up automatically", 238. MAXOCLASSES }, 239. { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ }, 240. { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ }, 241. { "scores", "the parts of the score list you wish to see", 32 }, 242. #ifdef MSDOS 243. { "soundcard", "type of sound card to use", 20 }, 244. #endif 245. { "suppress_alert", "suppress alert of new features for version specified and prior", 6}, 246. { "traps", "the symbols to use in drawing traps", MAXTCHARS+1 }, 247. #ifdef MAC 248. {"use_stone", "use stone background patterns", 8}, 249. #endif 250. #ifdef MSDOS 251. { "video", "method of video updating", 20 }, 252. #endif 253. #ifdef VIDEOSHADES 254. { "videocolors", "color mappings for internal screen routines", 40 }, 255. { "videoshades", "gray shades to map to black/gray/white", 32 }, 256. #endif 257. { "windowtype", "windowing system to use", WINTYPELEN }, 258. { (char *)0, (char *)0, 0 } 259. }; 260. 261. #ifdef OPTION_LISTS_ONLY 262. #undef static 263. 264. #else /* use rest of file */ 265. 266. static boolean need_redraw; /* for doset() */ 267. 268. #if defined(TOS) && defined(TEXTCOLOR) 269. extern boolean colors_changed; /* in tos.c */ 270. #endif 271. 272. #ifdef VIDEOSHADES 273. extern char *shade[3]; /* in sys/msdos/video.c */ 274. extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */ 275. #endif 276. 277. static char def_inv_order[MAXOCLASSES] = { 278. GOLD_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, 279. SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, 280. TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0, 281. }; 282. 283. /* 284. * Default menu manipulation command accelerators. These may _not_ be: 285. * 286. * + a number - reserved for counts 287. * + an upper or lower case US ASCII letter - used for accelerators 288. * + ESC - reserved for escaping the menu 289. * + NULL, CR or LF - reserved for commiting the selection(s). NULL 290. * is kind of odd, but the tty's xwaitforspace() will return it if 291. * someone hits a <ret>. 292. * + a default object class symbol - used for object class accelerators 293. * 294. * Standard letters (for now) are: 295. * 296. * < back 1 page 297. * > forward 1 page 298. * ^ first page 299. * | last page 300. * : search 301. * 302. * page all 303. * , select . 304. * \ deselect - 305. * ~ invert @ 306. * 307. * The command name list is duplicated in the compopt array. 308. */ 309. typedef struct { 310. const char *name; 311. char cmd; 312. } menu_cmd_t; 313. 314. #define NUM_MENU_CMDS 11 315. static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = { 316. /* 0*/ { "menu_first_page", MENU_FIRST_PAGE }, 317. { "menu_last_page", MENU_LAST_PAGE }, 318. { "menu_next_page", MENU_NEXT_PAGE }, 319. { "menu_previous_page", MENU_PREVIOUS_PAGE }, 320. { "menu_select_all", MENU_SELECT_ALL }, 321. /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL }, 322. { "menu_invert_all", MENU_INVERT_ALL }, 323. { "menu_select_page", MENU_SELECT_PAGE }, 324. { "menu_deselect_page", MENU_UNSELECT_PAGE }, 325. { "menu_invert_page", MENU_INVERT_PAGE }, 326. /*10*/ { "menu_search", MENU_SEARCH }, 327. }; 328. 329. /* 330. * Allow the user to map incoming characters to various menu commands. 331. * The accelerator list must be a valid C string. 332. */ 333. #define MAX_MENU_MAPPED_CMDS 32 /* some number */ 334. char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1]; /* exported */ 335. static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1]; 336. static short n_menu_mapped = 0; 337. 338. 339. static boolean initial, from_file; 340. 341. STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,const char *,int)); 342. STATIC_DCL void FDECL(nmcpy, (char *, const char *, int)); 343. STATIC_DCL void FDECL(escapes, (const char *, char *)); 344. STATIC_DCL int FDECL(boolopt_only_initial, (int)); 345. STATIC_DCL void FDECL(rejectoption, (const char *)); 346. STATIC_DCL void FDECL(badoption, (const char *)); 347. STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P)); 348. STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P)); 349. STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P)); 350. STATIC_DCL int FDECL(change_inv_order, (char *)); 351. STATIC_DCL void FDECL(oc_to_str, (char *, char *)); 352. STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int)); 353. STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *)); 354. 355. /* check whether a user-supplied option string is a proper leading 356. substring of a particular option name; option string might have 357. a colon or equals sign and arbitrary value appended to it */ 358. boolean 359. match_optname(user_string, opt_name, min_length, val_allowed) 360. const char *user_string, *opt_name; 361. int min_length; 362. boolean val_allowed; 363. { 364. int len = (int)strlen(user_string); 365. 366. if (val_allowed) { 367. const char *p = index(user_string, ':'), 368. *q = index(user_string, '='); 369. 370. if (!p || (q && q < p)) p = q; 371. while(p && p > user_string && isspace(*(p-1))) p--; 372. if (p) len = (int)(p - user_string); 373. } 374. 375. return (len >= min_length) && !strncmpi(opt_name, user_string, len); 376. } 377. 378. void 379. initoptions() 380. { 381. char *opts; 382. int i; 383. 384. /* initialize the random number generator */ 385. setrandom(); 386. 387. for (i = 0; boolopt[i].name; i++) { 388. if (boolopt[i].addr) 389. *(boolopt[i].addr) = boolopt[i].initvalue; 390. } 391. flags.end_own = FALSE; 392. flags.end_top = 3; 393. flags.end_around = 2; 394. iflags.msg_history = 20; 395. 396. /* Use negative indices to indicate not yet selected */ 397. flags.initrole = -1; 398. flags.initrace = -1; 399. flags.initgend = -1; 400. flags.initalign = -1; 401. 402. /* Set the default monster and object class symbols. Don't use */ 403. /* memcpy() --- sizeof char != sizeof uchar on some machines. */ 404. for (i = 0; i < MAXOCLASSES; i++) 405. oc_syms[i] = (uchar) def_oc_syms[i]; 406. for (i = 0; i < MAXMCLASSES; i++) 407. monsyms[i] = (uchar) def_monsyms[i]; 408. 409. /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */ 410. (void)memcpy((genericptr_t)flags.inv_order, 411. (genericptr_t)def_inv_order, sizeof flags.inv_order); 412. flags.pickup_types[0] = '\0'; 413. flags.pickup_burden = MOD_ENCUMBER; 414. 415. switch_graphics(ASCII_GRAPHICS); /* set default characters */ 416. #if defined(UNIX) && defined(TTY_GRAPHICS) 417. /* 418. * Set defaults for some options depending on what we can 419. * detect about the environment's capabilities. 420. * This has to be done after the global initialization above 421. * and before reading user-specific initialization via 422. * config file/environment variable below. 423. */ 424. /* this detects the IBM-compatible console on most 386 boxes */ 425. if (!strncmp(getenv("TERM"), "AT", 2)) { 426. switch_graphics(IBM_GRAPHICS); 427. # ifdef TEXTCOLOR 428. iflags.use_color = TRUE; 429. # endif 430. } 431. #endif /* UNIX && TTY_GRAPHICS */ 432. #if defined(UNIX) || defined(VMS) 433. # ifdef TTY_GRAPHICS 434. /* detect whether a "vt" terminal can handle alternate charsets */ 435. if (!strncmpi(getenv("TERM"), "vt", 2) && (AS && AE) && 436. index(AS, '\016') && index(AE, '\017')) { 437. switch_graphics(DEC_GRAPHICS); 438. } 439. # endif 440. #endif /* UNIX || VMS */ 441. 442. #ifdef MAC_GRAPHICS_ENV 443. switch_graphics(MAC_GRAPHICS); 444. #endif /* MAC_GRAPHICS_ENV */ 445. flags.menu_style = MENU_FULL; 446. 447. /* since this is done before init_objects(), do partial init here */ 448. objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; 449. nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); 450. #ifndef MAC 451. opts = getenv("NETHACKOPTIONS"); 452. if (!opts) opts = getenv("HACKOPTIONS"); 453. if (opts) { 454. if (*opts == '/' || *opts == '\\' || *opts == '@') { 455. if (*opts == '@') opts++; /* @filename */ 456. /* looks like a filename */ 457. read_config_file(opts); 458. } else { 459. read_config_file((char *)0); 460. parseoptions(opts, TRUE, FALSE); 461. } 462. } else 463. #endif 464. read_config_file((char *)0); 465. #ifdef AMIGA 466. ami_wbench_init(); /* must be here or can't set fruit */ 467. #endif 468. (void)fruitadd(pl_fruit); 469. /* Remove "slime mold" from list of object names; this will */ 470. /* prevent it from being wished unless it's actually present */ 471. /* as a named (or default) fruit. Wishing for "fruit" will */ 472. /* result in the player's preferred fruit [better than "\033"]. */ 473. obj_descr[SLIME_MOLD].oc_name = "fruit"; 474. 475. return; 476. } 477. 478. STATIC_OVL void 479. nmcpy(dest, src, maxlen) 480. char *dest; 481. const char *src; 482. int maxlen; 483. { 484. int count; 485. 486. for(count = 1; count < maxlen; count++) { 487. if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/ 488. *dest++ = *src++; 489. } 490. *dest = 0; 491. } 492. 493. /* 494. * escapes: escape expansion for showsyms. C-style escapes understood include 495. * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix 496. * for control characters is also understood, and \[mM] followed by any of the 497. * previous forms or by a character has the effect of 'meta'-ing the value (so 498. * that the alternate character set will be enabled). 499. */ 500. STATIC_OVL void 501. escapes(cp, tp) 502. const char *cp; 503. char *tp; 504. { 505. while (*cp) 506. { 507. int cval = 0, meta = 0; 508. 509. if (*cp == '\\' && index("mM", cp[1])) { 510. meta = 1; 511. cp += 2; 512. } 513. if (*cp == '\\' && index("0123456789xXoO", cp[1])) 514. { 515. const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; 516. int dcount = 0; 517. 518. cp++; 519. if (*cp == 'x' || *cp == 'X') 520. for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) 521. cval = (cval * 16) + (dp - hex) / 2; 522. else if (*cp == 'o' || *cp == 'O') 523. for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++) 524. cval = (cval * 8) + (*cp - '0'); 525. else 526. for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++) 527. cval = (cval * 10) + (*cp - '0'); 528. } 529. else if (*cp == '\\') /* C-style character escapes */ 530. { 531. switch (*++cp) 532. { 533. case '\\': cval = '\\'; break; 534. case 'n': cval = '\n'; break; 535. case 't': cval = '\t'; break; 536. case 'b': cval = '\b'; break; 537. case 'r': cval = '\r'; break; 538. default: cval = *cp; 539. } 540. cp++; 541. } 542. else if (*cp == '^') /* expand control-character syntax */ 543. { 544. cval = (*++cp & 0x1f); 545. cp++; 546. } 547. else 548. cval = *cp++; 549. if (meta) 550. cval |= 0x80; 551. *tp++ = cval; 552. } 553. *tp = '\0'; 554. } 555. 556. /* some boolean options can only be set on start-up */ 557. STATIC_OVL int 558. boolopt_only_initial(i) 559. int i; 560. { 561. return (boolopt[i].addr == &flags.female 562. || boolopt[i].addr == &flags.legacy 563. #if defined(MICRO) && !defined(AMIGA) 564. || boolopt[i].addr == &iflags.rawio 565. || boolopt[i].addr == &iflags.BIOS 566. #endif 567. #if defined(MSDOS) && defined(USE_TILES) 568. || boolopt[i].addr == &iflags.preload_tiles 569. #endif 570. ); 571. } 572. 573. STATIC_OVL void 574. rejectoption(optname) 575. const char *optname; 576. { 577. #ifdef MICRO 578. # ifdef AMIGA 579. if(FromWBench){ 580. pline("\"%s\" settable only from %s or in icon.", 581. optname, configfile); 582. } else 583. # endif 584. pline("\"%s\" settable only from %s.", optname, configfile); 585. #else 586. pline("%s can be set only from NETHACKOPTIONS or %s.", optname, 587. configfile); 588. #endif 589. } 590. 591. STATIC_OVL void 592. badoption(opts) 593. const char *opts; 594. { 595. if (!initial) { 596. if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1)) 597. option_help(); 598. else 599. pline("Bad syntax: %s. Enter \"?g\" for help.", opts); 600. return; 601. } 602. # ifdef AMIGA 603. if(ami_wbench_badopt(opts)) { 604. # endif 605. if(from_file) 606. raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts); 607. else 608. raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts); 609. # ifdef AMIGA 610. } 611. # endif 612. wait_synch(); 613. } 614. 615. STATIC_OVL char * 616. string_for_opt(opts, val_optional) 617. char *opts; 618. boolean val_optional; 619. { 620. char *colon, *equals; 621. 622. colon = index(opts, ':'); 623. equals = index(opts, '='); 624. if (!colon || (equals && equals < colon)) colon = equals; 625. 626. if (!colon || !*++colon) { 627. if (!val_optional) badoption(opts); 628. return (char *)0; 629. } 630. return colon; 631. } 632. 633. STATIC_OVL char * 634. string_for_env_opt(optname, opts, val_optional) 635. const char *optname; 636. char *opts; 637. boolean val_optional; 638. { 639. if(!initial) { 640. rejectoption(optname); 641. return (char *)0; 642. } 643. return string_for_opt(opts, val_optional); 644. } 645. 646. STATIC_OVL void 647. bad_negation(optname, with_parameter) 648. const char *optname; 649. boolean with_parameter; 650. { 651. pline_The("%s option may not %sbe negated.", 652. optname, 653. with_parameter ? "both have a value and " : ""); 654. } 655. 656. /* 657. * Change the inventory order, using the given string as the new order. 658. * Missing characters in the new order are filled in at the end from 659. * the current inv_order, except for gold, which is forced to be first 660. * if not explicitly present. 661. * 662. * This routine returns 1 unless there is a duplicate or bad char in 663. * the string. 664. */ 665. STATIC_OVL int 666. change_inv_order(op) 667. char *op; 668. { 669. int oc_sym, num; 670. char *sp, buf[BUFSZ]; 671. 672. num = 0; 673. if (!index(op, GOLD_SYM)) 674. buf[num++] = GOLD_CLASS; 675. 676. for (sp = op; *sp; sp++) { 677. oc_sym = def_char_to_objclass(*sp); 678. /* reject bad or duplicate entries */ 679. if (oc_sym == MAXOCLASSES || 680. oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS || 681. !index(flags.inv_order, oc_sym) || index(sp+1, *sp)) 682. return 0; 683. /* retain good ones */ 684. buf[num++] = (char) oc_sym; 685. } 686. buf[num] = '\0'; 687. 688. /* fill in any omitted classes, using previous ordering */ 689. for (sp = flags.inv_order; *sp; sp++) 690. if (!index(buf, *sp)) { 691. buf[num++] = *sp; 692. buf[num] = '\0'; /* explicitly terminate for next index() */ 693. } 694. 695. Strcpy(flags.inv_order, buf); 696. return 1; 697. } 698. 699. STATIC_OVL void 700. graphics_opts(opts, optype, maxlen, offset) 701. register char *opts; 702. const char *optype; 703. int maxlen, offset; 704. { 705. uchar translate[MAXPCHARS+1]; 706. int length, i; 707. 708. if (!(opts = string_for_env_opt(optype, opts, FALSE))) 709. return; 710. escapes(opts, opts); 711. 712. length = strlen(opts); 713. if (length > maxlen) length = maxlen; 714. /* match the form obtained from PC configuration files */ 715. for (i = 0; i < length; i++) 716. translate[i] = (uchar) opts[i]; 717. assign_graphics(translate, length, maxlen, offset); 718. } 719. 720. STATIC_OVL int 721. feature_alert_opts(op, optn) 722. char *op; 723. const char *optn; 724. { 725. char buf[BUFSZ]; 726. boolean rejectver = FALSE; 727. unsigned long fnv = get_feature_notice_ver(op); /* version.c */ 728. if (fnv == 0L) return 0; 729. if (fnv > get_current_feature_ver()) 730. rejectver = TRUE; 731. else 732. flags.suppress_alert = fnv; 733. if (rejectver) { 734. if (!initial) 735. You_cant("disable new feature alerts for future versions."); 736. else { 737. Sprintf(buf, 738. "\n%s=%s Invalid reference to a future version ignored", 739. optn, op); 740. badoption(buf); 741. } 742. return 0; 743. } 744. if (!initial) { 745. Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, 746. FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH); 747. pline("Feature change alerts disabled for NetHack %s features and prior.", 748. buf); 749. } 750. return 1; 751. } 752. 753. void 754. parseoptions(opts, tinitial, tfrom_file) 755. register char *opts; 756. boolean tinitial, tfrom_file; 757. { 758. register char *op; 759. unsigned num; 760. boolean negated; 761. int i; 762. const char *fullname; 763. 764. initial = tinitial; 765. from_file = tfrom_file; 766. if ((op = index(opts, ',')) != 0) { 767. *op++ = 0; 768. parseoptions(op, initial, from_file); 769. } 770. 771. /* strip leading and trailing white space */ 772. while (isspace(*opts)) opts++; 773. op = eos(opts); 774. while (--op >= opts && isspace(*op)) *op = '\0'; 775. 776. if (!*opts) return; 777. negated = FALSE; 778. while ((*opts == '!') || !strncmpi(opts, "no", 2)) { 779. if (*opts == '!') opts++; else opts += 2; 780. negated = !negated; 781. } 782. 783. /* variant spelling */ 784. 785. if (match_optname(opts, "colour", 5, FALSE)) 786. Strcpy(opts, "color"); /* fortunately this isn't longer */ 787. 788. /* special boolean options */ 789. 790. if (match_optname(opts, "female", 3, FALSE)) { 791. if(!initial && flags.female == negated) 792. pline("That is not anatomically possible."); 793. else 794. flags.initgend = flags.female = !negated; 795. return; 796. } 797. 798. if (match_optname(opts, "male", 4, FALSE)) { 799. if(!initial && flags.female != negated) 800. pline("That is not anatomically possible."); 801. else 802. flags.initgend = flags.female = negated; 803. return; 804. } 805. 806. #if defined(MICRO) && !defined(AMIGA) 807. /* included for compatibility with old NetHack.cnf files */ 808. if (match_optname(opts, "IBM_", 4, FALSE)) { 809. iflags.BIOS = !negated; 810. return; 811. } 812. #endif /* MICRO */ 813. 814. /* compound options */ 815. 816. fullname = "pettype"; 817. if (match_optname(opts, fullname, 3, TRUE)) { 818. if ((op = string_for_env_opt(fullname, opts, negated)) != 0) { 819. if (negated) bad_negation(fullname, TRUE); 820. else switch (*op) { 821. case 'd': /* dog */ 822. case 'D': 823. preferred_pet = 'd'; 824. break; 825. case 'c': /* cat */ 826. case 'C': 827. case 'f': /* feline */ 828. case 'F': 829. preferred_pet = 'c'; 830. break; 831. default: 832. pline("Unrecognized pet type '%s'", op); 833. break; 834. } 835. } else if (negated) preferred_pet = 0; 836. return; 837. } 838. 839. fullname = "catname"; 840. if (match_optname(opts, fullname, 3, TRUE)) { 841. if (negated) bad_negation(fullname, FALSE); 842. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 843. nmcpy(catname, op, PL_PSIZ); 844. return; 845. } 846. 847. fullname = "dogname"; 848. if (match_optname(opts, fullname, 3, TRUE)) { 849. if (negated) bad_negation(fullname, FALSE); 850. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 851. nmcpy(dogname, op, PL_PSIZ); 852. return; 853. } 854. 855. fullname = "horsename"; 856. if (match_optname(opts, fullname, 5, TRUE)) { 857. if (negated) bad_negation(fullname, FALSE); 858. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 859. nmcpy(horsename, op, PL_PSIZ); 860. return; 861. } 862. 863. fullname = "msghistory"; 864. if (match_optname(opts, fullname, 3, TRUE)) { 865. op = string_for_env_opt(fullname, opts, negated); 866. if ((negated && !op) || (!negated && op)) { 867. iflags.msg_history = negated ? 0 : atoi(op); 868. } else if (negated) bad_negation(fullname, TRUE); 869. return; 870. } 871. 872. #ifdef CHANGE_COLOR 873. #ifdef MAC 874. fullname = "use_stone"; 875. if (match_optname(opts, fullname, 6, TRUE)) { 876. op = string_for_env_opt(fullname, opts, negated); 877. if ((negated && !op) || (!negated && op)) { 878. iflags.use_stone = negated ? 0 : atoi(op); 879. } else if (negated) bad_negation(fullname, TRUE); 880. return; 881. } 882. 883. fullname = "background"; 884. if (match_optname(opts, fullname, 5,TRUE)) 885. { 886. if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 887. { 888. if (!strncmpi (op, "white", 5)) 889. change_background (1); 890. else if (!strncmpi (op, "black", 5)) 891. change_background (0); 892. } 893. return; 894. } 895. 896. fullname = "font"; 897. if (!strncmpi(opts, fullname, 4)) 898. { int wintype = -1; 899. 900. opts += 4; 901. if (!strncmpi (opts, "map", 3)) 902. wintype = NHW_MAP; 903. else if (!strncmpi (opts, "message", 7)) 904. wintype = NHW_MESSAGE; 905. else if (!strncmpi (opts, "text", 4)) 906. wintype = NHW_TEXT; 907. 908. if (wintype > 0 && (op = string_for_env_opt(fullname, opts, FALSE)) != 0) 909. { set_font_name (wintype, op); 910. } 911. return; 912. } 913. #endif 914. if (match_optname(opts, "palette", 3, TRUE) 915. # ifdef MAC 916. || match_optname(opts, "hicolor", 3, TRUE) 917. # endif 918. ) { 919. int color_number, color_incr; 920. 921. # ifdef MAC 922. if (match_optname(opts, "hicolor", 3, TRUE)) { 923. if (negated) { 924. bad_negation("hicolor", FALSE); 925. return; 926. } 927. color_number = CLR_MAX + 4; /* HARDCODED inverse number */ 928. color_incr = -1; 929. } else { 930. # endif 931. if (negated) { 932. bad_negation("palette", FALSE); 933. return; 934. } 935. color_number = 0; 936. color_incr = 1; 937. # ifdef MAC 938. } 939. # endif 940. if ((op = string_for_opt(opts, FALSE)) != (char *)0) { 941. char *pt = op; 942. int cnt, tmp, reverse; 943. long rgb; 944. 945. while (*pt && color_number >= 0) { 946. cnt = 3; 947. rgb = 0L; 948. if (*pt == '-') { 949. reverse = 1; 950. pt++; 951. } else { 952. reverse = 0; 953. } 954. while (cnt-- > 0) { 955. if (*pt && *pt != '/') { 956. # ifdef AMIGA 957. rgb <<= 4; 958. # else 959. rgb <<= 8; 960. # endif 961. tmp = *(pt++); 962. if (isalpha(tmp)) { 963. tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */ 964. } else { 965. tmp &= 0xf; /* Digits in ASCII too... */ 966. } 967. # ifndef AMIGA 968. /* Add an extra so we fill f -> ff and 0 -> 00 */ 969. rgb += tmp << 4; 970. # endif 971. rgb += tmp; 972. } 973. } 974. if (*pt == '/') { 975. pt++; 976. } 977. change_color(color_number, rgb, reverse); 978. color_number += color_incr; 979. } 980. } 981. if (!initial) { 982. need_redraw = TRUE; 983. } 984. return; 985. } 986. #endif 987. 988. if (match_optname(opts, "fruit", 2, TRUE)) { 989. char empty_str = '\0'; 990. op = string_for_opt(opts, negated); 991. if (negated) { 992. if (op) { 993. bad_negation("fruit", TRUE); 994. return; 995. } 996. op = &empty_str; 997. goto goodfruit; 998. } 999. if (!op) return; 1000. if (!initial) { 1001. struct fruit *f; 1002. 1003. num = 0; 1004. for(f=ffruit; f; f=f->nextf) { 1005. if (!strcmp(op, f->fname)) goto goodfruit; 1006. num++; 1007. } 1008. if (num >= 100) { 1009. pline("Doing that so many times isn't very fruitful."); 1010. return; 1011. } 1012. } 1013. goodfruit: 1014. nmcpy(pl_fruit, op, PL_FSIZ); 1015. /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */ 1016. if (!*pl_fruit) 1017. nmcpy(pl_fruit, "slime mold", PL_FSIZ); 1018. if (!initial) 1019. (void)fruitadd(pl_fruit); 1020. /* If initial, then initoptions is allowed to do it instead 1021. * of here (initoptions always has to do it even if there's 1022. * no fruit option at all. Also, we don't want people 1023. * setting multiple fruits in their options.) 1024. */ 1025. return; 1026. } 1027. 1028. /* graphics:string */ 1029. fullname = "graphics"; 1030. if (match_optname(opts, fullname, 2, TRUE)) { 1031. if (negated) bad_negation(fullname, FALSE); 1032. else graphics_opts(opts, fullname, MAXPCHARS, 0); 1033. return; 1034. } 1035. fullname = "dungeon"; 1036. if (match_optname(opts, fullname, 2, TRUE)) { 1037. if (negated) bad_negation(fullname, FALSE); 1038. else graphics_opts(opts, fullname, MAXDCHARS, 0); 1039. return; 1040. } 1041. fullname = "traps"; 1042. if (match_optname(opts, fullname, 2, TRUE)) { 1043. if (negated) bad_negation(fullname, FALSE); 1044. else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS); 1045. return; 1046. } 1047. fullname = "effects"; 1048. if (match_optname(opts, fullname, 2, TRUE)) { 1049. if (negated) bad_negation(fullname, FALSE); 1050. else 1051. graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS); 1052. return; 1053. } 1054. 1055. /* objects:string */ 1056. fullname = "objects"; 1057. if (match_optname(opts, fullname, 7, TRUE)) { 1058. int length; 1059. 1060. if (negated) { 1061. bad_negation(fullname, FALSE); 1062. return; 1063. } 1064. if (!(opts = string_for_env_opt(fullname, opts, FALSE))) 1065. return; 1066. escapes(opts, opts); 1067. 1068. /* 1069. * Override the default object class symbols. The first 1070. * object in the object class is the "random object". I 1071. * don't want to use 0 as an object class, so the "random 1072. * object" is basically a place holder. 1073. * 1074. * The object class symbols have already been initialized in 1075. * initoptions(). 1076. */ 1077. length = strlen(opts); 1078. if (length >= MAXOCLASSES) 1079. length = MAXOCLASSES-1; /* don't count RANDOM_OBJECT */ 1080. 1081. for (i = 0; i < length; i++) 1082. oc_syms[i+1] = (uchar) opts[i]; 1083. return; 1084. } 1085. 1086. /* monsters:string */ 1087. fullname = "monsters"; 1088. if (match_optname(opts, fullname, 8, TRUE)) { 1089. int length; 1090. 1091. if (negated) { 1092. bad_negation(fullname, FALSE); 1093. return; 1094. } 1095. if (!(opts = string_for_env_opt(fullname, opts, FALSE))) 1096. return; 1097. escapes(opts, opts); 1098. 1099. /* Override default mon class symbols set in initoptions(). */ 1100. length = strlen(opts); 1101. if (length >= MAXMCLASSES) 1102. length = MAXMCLASSES-1; /* mon class 0 unused */ 1103. 1104. for (i = 0; i < length; i++) 1105. monsyms[i+1] = (uchar) opts[i]; 1106. return; 1107. } 1108. 1109. /* name:string */ 1110. fullname = "name"; 1111. if (match_optname(opts, fullname, 4, TRUE)) { 1112. if (negated) bad_negation(fullname, FALSE); 1113. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1114. nmcpy(plname, op, PL_NSIZ); 1115. return; 1116. } 1117. 1118. /* role:string or character:string */ 1119. fullname = "role"; 1120. if (match_optname(opts, fullname, 4, TRUE) || 1121. match_optname(opts, (fullname = "character"), 4, TRUE)) { 1122. if (negated) bad_negation(fullname, FALSE); 1123. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1124. if ((flags.initrole = str2role(op)) < 0) 1125. badoption(opts); 1126. else /* Backwards compatibility */ 1127. nmcpy(pl_character, op, PL_NSIZ); 1128. return; 1129. } 1130. 1131. /* race:string */ 1132. fullname = "race"; 1133. if (match_optname(opts, fullname, 4, TRUE)) { 1134. if (negated) bad_negation(fullname, FALSE); 1135. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1136. if ((flags.initrace = str2race(op)) < 0) 1137. badoption(opts); 1138. else /* Backwards compatibility */ 1139. pl_race = *op; 1140. return; 1141. } 1142. 1143. /* gender:string */ 1144. fullname = "gender"; 1145. if (match_optname(opts, fullname, 4, TRUE)) { 1146. if (negated) bad_negation(fullname, FALSE); 1147. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1148. if ((flags.initgend = str2gend(op)) < 0) 1149. badoption(opts); 1150. else 1151. flags.female = flags.initgend; 1152. return; 1153. } 1154. 1155. /* align:string */ 1156. fullname = "align"; 1157. if (match_optname(opts, fullname, 4, TRUE)) { 1158. if (negated) bad_negation(fullname, FALSE); 1159. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1160. if ((flags.initalign = str2align(op)) < 0) 1161. badoption(opts); 1162. return; 1163. } 1164. 1165. /* the order to list the pack */ 1166. fullname = "packorder"; 1167. if (match_optname(opts, fullname, 4, TRUE)) { 1168. if (negated) { 1169. bad_negation(fullname, FALSE); 1170. return; 1171. } else if (!(op = string_for_opt(opts, FALSE))) return; 1172. 1173. if (!change_inv_order(op)) 1174. badoption(opts); 1175. return; 1176. } 1177. 1178. /* maximum burden picked up before prompt (Warren Cheung) */ 1179. fullname = "pickup_burden"; 1180. if (match_optname(opts, fullname, 8, TRUE)) { 1181. if (negated) { 1182. bad_negation(fullname, FALSE); 1183. return; 1184. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { 1185. switch (tolower(*op)) { 1186. /* Unencumbered */ 1187. case 'u': 1188. flags.pickup_burden = UNENCUMBERED; 1189. break; 1190. /* Burdened (slight encumberance) */ 1191. case 'b': 1192. flags.pickup_burden = SLT_ENCUMBER; 1193. break; 1194. /* streSsed (moderate encumberance) */ 1195. case 's': 1196. flags.pickup_burden = MOD_ENCUMBER; 1197. break; 1198. /* straiNed (heavy encumberance) */ 1199. case 'n': 1200. flags.pickup_burden = HVY_ENCUMBER; 1201. break; 1202. /* OverTaxed (extreme encumberance) */ 1203. case 'o': 1204. case 't': 1205. flags.pickup_burden = EXT_ENCUMBER; 1206. break; 1207. /* overLoaded */ 1208. case 'l': 1209. flags.pickup_burden = OVERLOADED; 1210. break; 1211. default: 1212. badoption(opts); 1213. } 1214. } 1215. return; 1216. } 1217. 1218. /* types of objects to pick up automatically */ 1219. if (match_optname(opts, "pickup_types", 8, TRUE)) { 1220. char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], 1221. qbuf[QBUFSZ], abuf[BUFSZ]; 1222. int oc_sym; 1223. boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu; 1224. 1225. oc_to_str(flags.pickup_types, tbuf); 1226. flags.pickup_types[0] = '\0'; /* all */ 1227. op = string_for_opt(opts, (compat || !initial)); 1228. if (!op) { 1229. if (compat || negated || initial) { 1230. /* for backwards compatibility, "pickup" without a 1231. value is a synonym for autopickup of all types 1232. (and during initialization, we can't prompt yet) */ 1233. flags.pickup = !negated; 1234. return; 1235. } 1236. oc_to_str(flags.inv_order, ocl); 1237. use_menu = TRUE; 1238. if (flags.menu_style == MENU_TRADITIONAL || 1239. flags.menu_style == MENU_COMBINATION) { 1240. use_menu = FALSE; 1241. Sprintf(qbuf, "New pickup_types: [%s am] (%s)", 1242. ocl, *tbuf ? tbuf : "all"); 1243. getlin(qbuf, abuf); 1244. op = mungspaces(abuf); 1245. if (abuf[0] == '\0' || abuf[0] == '\033') 1246. op = tbuf; /* restore */ 1247. else if (abuf[0] == 'm') 1248. use_menu = TRUE; 1249. } 1250. if (use_menu) { 1251. (void) choose_classes_menu("Auto-Pickup what?", 1, 1252. TRUE, ocl, tbuf); 1253. op = tbuf; 1254. } 1255. } 1256. if (negated) { 1257. bad_negation("pickup_types", TRUE); 1258. return; 1259. } 1260. while (*op == ' ') op++; 1261. if (*op != 'a' && *op != 'A') { 1262. num = 0; 1263. while (*op) { 1264. oc_sym = def_char_to_objclass(*op); 1265. /* make sure all are valid obj symbols occuring once */ 1266. if (oc_sym != MAXOCLASSES && 1267. !index(flags.pickup_types, oc_sym)) { 1268. flags.pickup_types[num] = (char)oc_sym; 1269. flags.pickup_types[++num] = '\0'; 1270. } else 1271. badopt = TRUE; 1272. op++; 1273. } 1274. if (badopt) badoption(opts); 1275. } 1276. return; 1277. } 1278. 1279. /* things to disclose at end of game */ 1280. if (match_optname(opts, "disclose", 4, TRUE)) { 1281. flags.end_disclose[0] = '\0'; /* all */ 1282. if (!(op = string_for_opt(opts, TRUE))) { 1283. /* for backwards compatibility, "disclose" without a 1284. * value means all (was inventory and attributes, 1285. * the only things available then), but negated 1286. * it means "none" 1287. * (note "none" contains none of "iavkg") 1288. */ 1289. if (negated) Strcpy(flags.end_disclose, "none"); 1290. return; 1291. } 1292. if (negated) { 1293. bad_negation("disclose", TRUE); 1294. return; 1295. } 1296. num = 0; 1297. while (*op && num < sizeof flags.end_disclose - 1) { 1298. register char c; 1299. c = lowc(*op); 1300. if (c == 'k') c = 'v'; /* killed -> vanquished */ 1301. if (!index(flags.end_disclose, c)) { 1302. flags.end_disclose[num++] = c; 1303. flags.end_disclose[num] = '\0'; /* for index */ 1304. } 1305. op++; 1306. } 1307. return; 1308. } 1309. 1310. /* scores:5t[op] 5a[round] o[wn] */ 1311. if (match_optname(opts, "scores", 4, TRUE)) { 1312. if (negated) { 1313. bad_negation("scores", FALSE); 1314. return; 1315. } 1316. if (!(op = string_for_opt(opts, FALSE))) return; 1317. 1318. while (*op) { 1319. int inum = 1; 1320. 1321. if (digit(*op)) { 1322. inum = atoi(op); 1323. while (digit(*op)) op++; 1324. } else if (*op == '!') { 1325. negated = !negated; 1326. op++; 1327. } 1328. while (*op == ' ') op++; 1329. 1330. switch (*op) { 1331. case 't': 1332. case 'T': flags.end_top = inum; 1333. break; 1334. case 'a': 1335. case 'A': flags.end_around = inum; 1336. break; 1337. case 'o': 1338. case 'O': flags.end_own = !negated; 1339. break; 1340. default: badoption(opts); 1341. return; 1342. } 1343. while (letter(*++op) || *op == ' ') continue; 1344. if (*op == '/') op++; 1345. } 1346. return; 1347. } 1348. 1349. fullname = "suppress_alert"; 1350. if (match_optname(opts, fullname, 4, TRUE)) { 1351. op = string_for_opt(opts, negated); 1352. if (negated) bad_negation(fullname, FALSE); 1353. else if (op) (void) feature_alert_opts(op,fullname); 1354. return; 1355. } 1356. 1357. #ifdef VIDEOSHADES 1358. /* videocolors:string */ 1359. fullname = "videocolors"; 1360. if (match_optname(opts, fullname, 6, TRUE) || 1361. match_optname(opts, "videocolours", 10, TRUE)) { 1362. if (negated) { 1363. bad_negation(fullname, FALSE); 1364. return; 1365. } 1366. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1367. return; 1368. } 1369. if (!assign_videocolors(opts)) 1370. badoption(opts); 1371. return; 1372. } 1373. /* videoshades:string */ 1374. fullname = "videoshades"; 1375. if (match_optname(opts, fullname, 6, TRUE)) { 1376. if (negated) { 1377. bad_negation(fullname, FALSE); 1378. return; 1379. } 1380. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1381. return; 1382. } 1383. if (!assign_videoshades(opts)) 1384. badoption(opts); 1385. return; 1386. } 1387. #endif /* VIDEOSHADES */ 1388. #ifdef MSDOS 1389. # ifdef NO_TERMS 1390. /* video:string -- must be after longer tests */ 1391. fullname = "video"; 1392. if (match_optname(opts, fullname, 5, TRUE)) { 1393. if (negated) { 1394. bad_negation(fullname, FALSE); 1395. return; 1396. } 1397. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1398. return; 1399. } 1400. if (!assign_video(opts)) 1401. badoption(opts); 1402. return; 1403. } 1404. # endif /* NO_TERMS */ 1405. /* soundcard:string -- careful not to match boolean 'sound' */ 1406. fullname = "soundcard"; 1407. if (match_optname(opts, fullname, 6, TRUE)) { 1408. if (negated) { 1409. bad_negation(fullname, FALSE); 1410. return; 1411. } 1412. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1413. return; 1414. } 1415. if (!assign_soundcard(opts)) 1416. badoption(opts); 1417. return; 1418. } 1419. #endif /* MSDOS */ 1420. 1421. fullname = "windowtype"; 1422. if (match_optname(opts, fullname, 3, TRUE)) { 1423. if (negated) { 1424. bad_negation(fullname, FALSE); 1425. return; 1426. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { 1427. char buf[WINTYPELEN]; 1428. nmcpy(buf, op, WINTYPELEN); 1429. choose_windows(buf); 1430. } 1431. return; 1432. } 1433. 1434. /* menustyle:traditional or combo or full or partial */ 1435. if (match_optname(opts, "menustyle", 4, TRUE)) { 1436. int tmp; 1437. boolean val_required = (strlen(opts) > 5 && !negated); 1438. 1439. if (!(op = string_for_opt(opts, !val_required))) { 1440. if (val_required) return; /* string_for_opt gave feedback */ 1441. tmp = negated ? 'n' : 'f'; 1442. } else { 1443. tmp = tolower(*op); 1444. } 1445. switch (tmp) { 1446. case 'n': /* none */ 1447. case 't': /* traditional */ 1448. flags.menu_style = MENU_TRADITIONAL; 1449. break; 1450. case 'c': /* combo: trad.class sel+menu */ 1451. flags.menu_style = MENU_COMBINATION; 1452. break; 1453. case 'p': /* partial: no class menu */ 1454. flags.menu_style = MENU_PARTIAL; 1455. break; 1456. case 'f': /* full: class menu + menu */ 1457. flags.menu_style = MENU_FULL; 1458. break; 1459. default: 1460. badoption(opts); 1461. } 1462. return; 1463. } 1464. 1465. /* check for menu command mapping */ 1466. for (i = 0; i < NUM_MENU_CMDS; i++) { 1467. fullname = default_menu_cmd_info[i].name; 1468. if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) { 1469. if (negated) 1470. bad_negation(fullname, FALSE); 1471. else if ((op = string_for_opt(opts, FALSE)) != 0) { 1472. int j; 1473. char c, op_buf[BUFSZ]; 1474. boolean isbad = FALSE; 1475. 1476. escapes(op, op_buf); 1477. c = *op_buf; 1478. 1479. if (c == 0 || c == '\r' || c == '\n' || c == '\033' || 1480. c == ' ' || digit(c) || (letter(c) && c != '@')) 1481. isbad = TRUE; 1482. else /* reject default object class symbols */ 1483. for (j = 1; j < MAXOCLASSES; j++) 1484. if (c == def_oc_syms[i]) { 1485. isbad = TRUE; 1486. break; 1487. } 1488. 1489. if (isbad) 1490. badoption(opts); 1491. else 1492. add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd); 1493. } 1494. return; 1495. } 1496. } 1497. 1498. /* OK, if we still haven't recognized the option, check the boolean 1499. * options list 1500. */ 1501. for (i = 0; boolopt[i].name; i++) { 1502. if (match_optname(opts, boolopt[i].name, 3, FALSE)) { 1503. /* options that don't exist */ 1504. if (!boolopt[i].addr) { 1505. if (!initial && !negated) 1506. pline_The("\"%s\" option is not available.", 1507. boolopt[i].name); 1508. return; 1509. } 1510. /* options that must come from config file */ 1511. if (!initial && boolopt_only_initial(i)) { 1512. rejectoption(boolopt[i].name); 1513. return; 1514. } 1515. 1516. *(boolopt[i].addr) = !negated; 1517. 1518. #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV) 1519. if (FALSE 1520. # ifdef TERMLIB 1521. || (boolopt[i].addr) == &iflags.DECgraphics 1522. # endif 1523. # ifdef ASCIIGRAPH 1524. || (boolopt[i].addr) == &iflags.IBMgraphics 1525. # endif 1526. # ifdef MAC_GRAPHICS_ENV 1527. || (boolopt[i].addr) == &iflags.MACgraphics 1528. # endif 1529. ) { 1530. # ifdef REINCARNATION 1531. if (!initial && Is_rogue_level(&u.uz)) 1532. assign_rogue_graphics(FALSE); 1533. # endif 1534. need_redraw = TRUE; 1535. # ifdef TERMLIB 1536. if ((boolopt[i].addr) == &iflags.DECgraphics) 1537. switch_graphics(iflags.DECgraphics ? 1538. DEC_GRAPHICS : ASCII_GRAPHICS); 1539. # endif 1540. # ifdef ASCIIGRAPH 1541. if ((boolopt[i].addr) == &iflags.IBMgraphics) 1542. switch_graphics(iflags.IBMgraphics ? 1543. IBM_GRAPHICS : ASCII_GRAPHICS); 1544. # endif 1545. # ifdef MAC_GRAPHICS_ENV 1546. if ((boolopt[i].addr) == &iflags.MACgraphics) 1547. switch_graphics(iflags.MACgraphics ? 1548. MAC_GRAPHICS : ASCII_GRAPHICS); 1549. # endif 1550. # ifdef REINCARNATION 1551. if (!initial && Is_rogue_level(&u.uz)) 1552. assign_rogue_graphics(TRUE); 1553. # endif 1554. } 1555. #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */ 1556. 1557. /* only do processing below if setting with doset() */ 1558. if (initial) return; 1559. 1560. if ((boolopt[i].addr) == &flags.time 1561. #ifdef EXP_ON_BOTL 1562. || (boolopt[i].addr) == &flags.showexp 1563. #endif 1564. #ifdef SCORE_ON_BOTL 1565. || (boolopt[i].addr) == &flags.showscore 1566. #endif 1567. ) 1568. flags.botl = TRUE; 1569. 1570. else if ((boolopt[i].addr) == &flags.invlet_constant) { 1571. if (flags.invlet_constant) reassign(); 1572. } 1573. #ifdef LAN_MAIL 1574. else if ((boolopt[i].addr) == &flags.biff) { 1575. if (flags.biff) lan_mail_init(); 1576. else lan_mail_finish(); 1577. } 1578. #endif 1579. else if ((boolopt[i].addr) == &iflags.num_pad) 1580. number_pad(iflags.num_pad ? 1 : 0); 1581. 1582. else if ((boolopt[i].addr) == &flags.lit_corridor) { 1583. /* 1584. * All corridor squares seen via night vision or 1585. * candles & lamps change. Update them by calling 1586. * newsym() on them. Don't do this if we are 1587. * initializing the options --- the vision system 1588. * isn't set up yet. 1589. */ 1590. vision_recalc(2); /* shut down vision */ 1591. vision_full_recalc = 1; /* delayed recalc */ 1592. } 1593. 1594. #ifdef TEXTCOLOR 1595. else if ((boolopt[i].addr) == &iflags.use_color 1596. || (boolopt[i].addr) == &iflags.hilite_pet) { 1597. need_redraw = TRUE; 1598. # ifdef TOS 1599. if ((boolopt[i].addr) == &iflags.use_color 1600. && iflags.BIOS) { 1601. if (colors_changed) 1602. restore_colors(); 1603. else 1604. set_colors(); 1605. } 1606. # endif 1607. } 1608. #endif 1609. 1610. return; 1611. } 1612. } 1613. 1614. /* out of valid options */ 1615. badoption(opts); 1616. } 1617. 1618. 1619. static NEARDATA const char *menutype[] = { 1620. "traditional", "combination", "partial", "full" 1621. }; 1622. 1623. static NEARDATA const char *burdentype[] = { 1624. "unencumbered", "burdened", "stressed", 1625. "strained", "overtaxed", "overloaded" 1626. }; 1627. 1628. 1629. /* 1630. * Convert the given string of object classes to a string of default object 1631. * symbols. 1632. */ 1633. STATIC_OVL void 1634. oc_to_str(src,dest) 1635. char *src, *dest; 1636. { 1637. int i; 1638. 1639. while ((i = (int) *src++) != 0) { 1640. if (i < 0 || i >= MAXOCLASSES) 1641. impossible("oc_to_str: illegal object class %d", i); 1642. else 1643. *dest++ = def_oc_syms[i]; 1644. } 1645. *dest = '\0'; 1646. } 1647. 1648. /* 1649. * Add the given mapping to the menu command map list. Always keep the 1650. * maps valid C strings. 1651. */ 1652. void 1653. add_menu_cmd_alias(from_ch, to_ch) 1654. char from_ch, to_ch; 1655. { 1656. if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) 1657. pline("out of menu map space"); 1658. else { 1659. mapped_menu_cmds[n_menu_mapped] = from_ch; 1660. mapped_menu_op[n_menu_mapped] = to_ch; 1661. n_menu_mapped++; 1662. mapped_menu_cmds[n_menu_mapped] = 0; 1663. mapped_menu_op[n_menu_mapped] = 0; 1664. } 1665. } 1666. 1667. /* 1668. * Map the given character to its corresponding menu command. If it 1669. * doesn't match anything, just return the original. 1670. */ 1671. char 1672. map_menu_cmd(ch) 1673. char ch; 1674. { 1675. char *found = index(mapped_menu_cmds, ch); 1676. if (found) { 1677. int idx = found - mapped_menu_cmds; 1678. ch = mapped_menu_op[idx]; 1679. } 1680. return ch; 1681. } 1682. 1683. 1684. #if defined(MICRO) || defined(MAC) 1685. # define OPTIONS_HEADING "OPTIONS" 1686. #else 1687. # define OPTIONS_HEADING "NETHACKOPTIONS" 1688. #endif 1689. 1690. STATIC_OVL void 1691. doset_add_menu(win, option, value, indexoffset) 1692. winid win; /* window to add to */ 1693. const char *option; /* option name */ 1694. const char *value; /* current value */ 1695. int indexoffset; /* value to add to index in compopt[], or zero 1696. if option cannot be changed */ 1697. { 1698. char buf[BUFSZ]; 1699. anything any; 1700. int i; 1701. 1702. any.a_void = 0; 1703. if (indexoffset == 0) { 1704. any.a_int = 0; 1705. } else { 1706. for (i=0; compopt[i].name; i++) 1707. if (strcmp(option, compopt[i].name) == 0) break; 1708. 1709. if (compopt[i].name) { 1710. any.a_int = i + 1 + indexoffset; 1711. } else { 1712. /* We are trying to add an option not found in compopt[]. 1713. This is almost certainly bad, but we'll let it through anyway 1714. (with a zero value, so it can't be selected). */ 1715. any.a_int = 0; 1716. } 1717. } 1718. 1719. /* " " replaces "a - " -- assumes menus follow that style */ 1720. Sprintf(buf, "%s%-14s [%s]", (any.a_int ? "" : " "), option, value); 1721. add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); 1722. } 1723. 1724. /* Changing options via menu by Per Liboriussen */ 1725. int 1726. doset() 1727. { 1728. char ocl[MAXOCLASSES+1], buf[BUFSZ], buf2[BUFSZ]; 1729. int i, pass, boolcount, pick_cnt, pick_idx, opt_indx; 1730. boolean *bool_p; 1731. winid tmpwin; 1732. anything any; 1733. menu_item *pick_list; 1734. 1735. tmpwin = create_nhwindow(NHW_MENU); 1736. start_menu(tmpwin); 1737. 1738. any.a_void = 0; 1739. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, 1740. "Booleans (selecting will toggle value):", MENU_UNSELECTED); 1741. any.a_int = 0; 1742. /* list male/female first, since it's formatted uniquely */ 1743. Sprintf(buf, "%s%-13s", " ", flags.female ? "female" : "male"); 1744. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); 1745. /* next list any other non-modifiable booleans, then modifiable ones */ 1746. for (pass = 0; pass <= 1; pass++) 1747. for (i = 0; boolopt[i].name; i++) 1748. if ((bool_p = boolopt[i].addr) != 0 && 1749. (boolopt_only_initial(i) ^ pass)) { 1750. if (bool_p == &flags.female) continue; /* already done */ 1751. #ifdef WIZARD 1752. if (bool_p == &iflags.sanity_check && !wizard) continue; 1753. #endif 1754. any.a_int = (pass == 0) ? 0 : i + 1; 1755. Sprintf(buf, "%s%-13s [%s]", pass == 0 ? " " : "", 1756. boolopt[i].name, *bool_p ? "true" : "false"); 1757. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, 1758. ATR_NONE, buf, MENU_UNSELECTED); 1759. } 1760. 1761. /* This is ugly. We have all the option names in the compopt[] array, 1762. but we need to look at each option individually to get the value. */ 1763. boolcount = i; 1764. any.a_void = 0; 1765. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); 1766. add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, 1767. "Compounds (selecting will prompt for new value):", 1768. MENU_UNSELECTED); 1769. /* non-modifiable compounds; deliberately put `name' first */ 1770. doset_add_menu(tmpwin, "name", plname, 0); 1771. doset_add_menu(tmpwin, "role", (flags.initrole < 0) ? "(none)" : 1772. roles[flags.initrole].name.m, 0); 1773. doset_add_menu(tmpwin, "race", (flags.initrace < 0) ? "(none)" : 1774. races[flags.initrace].noun, 0); 1775. doset_add_menu(tmpwin, "gender", (flags.initgend < 0) ? "(none)" : 1776. genders[flags.initgend].adj, 0); 1777. doset_add_menu(tmpwin, "align", (flags.initalign < 0) ? "(none)" : 1778. aligns[flags.initalign].adj, 0); 1779. doset_add_menu(tmpwin, "catname", catname[0] ? catname : "(null)", 0); 1780. doset_add_menu(tmpwin, "dogname", dogname[0] ? dogname : "(null)", 0); 1781. doset_add_menu(tmpwin, "horsename", horsename[0] ? horsename : "(null)", 0); 1782. Sprintf(buf, "%u", iflags.msg_history); 1783. doset_add_menu(tmpwin, "msghistory", buf, 0); 1784. doset_add_menu(tmpwin, "pettype", 1785. (preferred_pet == 'c') ? "cat" : 1786. (preferred_pet == 'd') ? "dog" : "random", 0); 1787. #ifdef VIDEOSHADES 1788. Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]); 1789. doset_add_menu(tmpwin, "videoshades", buf, 0); 1790. Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", 1791. ttycolors[CLR_RED], ttycolors[CLR_GREEN], ttycolors[CLR_BROWN], 1792. ttycolors[CLR_BLUE], ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN], 1793. ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN], 1794. ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE], 1795. ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]); 1796. doset_add_menu(tmpwin, "videocolors", buf, 0); 1797. #endif /* VIDEOSHADES */ 1798. doset_add_menu(tmpwin, "windowtype", windowprocs.name, 0); 1799. 1800. /* modifiable compounds */ 1801. doset_add_menu(tmpwin, "disclose", 1802. flags.end_disclose[0] ? flags.end_disclose : "all", 1803. boolcount); 1804. doset_add_menu(tmpwin, "fruit", pl_fruit, boolcount); 1805. doset_add_menu(tmpwin, "menustyle", menutype[(int)flags.menu_style], 1806. boolcount); 1807. oc_to_str(flags.inv_order, ocl); 1808. doset_add_menu(tmpwin, "packorder", ocl, boolcount); 1809. #ifdef CHANGE_COLOR 1810. doset_add_menu(tmpwin, "palette", get_color_string(), boolcount); 1811. #endif 1812. oc_to_str(flags.pickup_types, ocl); 1813. doset_add_menu(tmpwin, "pickup_burden", burdentype[flags.pickup_burden], 1814. boolcount); 1815. doset_add_menu(tmpwin, "pickup_types", ocl[0] ? ocl : "all", 1816. boolcount); 1817. Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, 1818. flags.end_own ? "/own" : ""); 1819. doset_add_menu(tmpwin, "scores", buf, boolcount); 1820. Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, FEATURE_NOTICE_VER_MIN, 1821. FEATURE_NOTICE_VER_PATCH); 1822. doset_add_menu(tmpwin, "suppress_alert", (flags.suppress_alert == 0L) ? 1823. "(null)" : buf, boolcount); 1824. end_menu(tmpwin, "Set what options?"); 1825. 1826. need_redraw = FALSE; 1827. if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) { 1828. /* 1829. * Walk down the selection list and either invert the booleans 1830. * or prompt for new values. In most cases, call parseoptions() 1831. * to take care of options that require special attention, like 1832. * redraws. 1833. */ 1834. for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { 1835. opt_indx = pick_list[pick_idx].item.a_int - 1; 1836. if (opt_indx < boolcount) { 1837. /* boolean option */ 1838. Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "", 1839. boolopt[opt_indx].name); 1840. parseoptions(buf, FALSE, FALSE); 1841. } else { 1842. /* compound option */ 1843. opt_indx -= boolcount; 1844. 1845. /* Special handling of menustyle, pickup_burden, and pickup_types. */ 1846. if (!strcmp("menustyle", compopt[opt_indx].name)) { 1847. const char *style_name; 1848. menu_item *style_pick = (menu_item *)0; 1849. 1850. start_menu(tmpwin); 1851. for (i = 0; i < SIZE(menutype); i++) { 1852. style_name = menutype[i]; 1853. /* note: separate `style_name' variable used 1854. to avoid an optimizer bug in VAX C V2.3 */ 1855. any.a_int = i + 1; 1856. add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, 1857. ATR_NONE, style_name, MENU_UNSELECTED); 1858. } 1859. end_menu(tmpwin, "Select menustyle:"); 1860. if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) { 1861. flags.menu_style = style_pick->item.a_int - 1; 1862. free((genericptr_t)style_pick); 1863. } 1864. } else if (!strcmp("pickup_burden", compopt[opt_indx].name)) { 1865. const char *burden_name, *burden_letters = "ubsntl"; 1866. menu_item *burden_pick = (menu_item *)0; 1867. 1868. start_menu(tmpwin); 1869. for (i = 0; i < SIZE(burdentype); i++) { 1870. burden_name = burdentype[i]; 1871. any.a_int = i + 1; 1872. add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, 1873. ATR_NONE, burden_name, MENU_UNSELECTED); 1874. } 1875. end_menu(tmpwin, "Select encumberence level:"); 1876. if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) { 1877. flags.pickup_burden = burden_pick->item.a_int - 1; 1878. free((genericptr_t)burden_pick); 1879. } 1880. } else if (!strcmp("pickup_types", compopt[opt_indx].name)) { 1881. /* parseoptions will prompt for the list of types */ 1882. parseoptions(strcpy(buf, "pickup_types"), FALSE, FALSE); 1883. } else { 1884. Sprintf(buf, "Set %s to what?", compopt[opt_indx].name); 1885. getlin(buf, buf2); 1886. Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2); 1887. /* pass the buck */ 1888. parseoptions(buf, FALSE, FALSE); 1889. } 1890. } 1891. } 1892. 1893. free((genericptr_t)pick_list); 1894. pick_list = (menu_item *)0; 1895. } 1896. 1897. destroy_nhwindow(tmpwin); 1898. if (need_redraw) 1899. (void) doredraw(); 1900. return 0; 1901. } 1902. 1903. int 1904. dotogglepickup() 1905. { 1906. char buf[BUFSZ], ocl[MAXOCLASSES+1]; 1907. 1908. flags.pickup = !flags.pickup; 1909. if (flags.pickup) { 1910. oc_to_str(flags.pickup_types, ocl); 1911. Sprintf(buf, "ON, for %s objects", ocl[0] ? ocl : "all"); 1912. } else { 1913. Strcpy(buf, "OFF"); 1914. } 1915. pline("Autopickup: %s.", buf); 1916. return 0; 1917. } 1918. 1919. /* data for option_help() */ 1920. static const char *opt_intro[] = { 1921. "", 1922. " NetHack Options Help:", 1923. "", 1924. #define CONFIG_SLOT 3 /* fill in next value at run-time */ 1925. (char *)0, 1926. #if !defined(MICRO) && !defined(MAC) 1927. "or use `NETHACKOPTIONS=\"<options>\"' in your environment", 1928. #endif 1929. "(<options> is a list of options separated by commas)", 1930. #ifdef VMS 1931. "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"", 1932. #endif 1933. "or press \"O\" while playing and use the menu.", 1934. "", 1935. "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", 1936. (char *)0 1937. }; 1938. 1939. static const char *opt_epilog[] = { 1940. "", 1941. "Some of the options can be set only before the game is started; those", 1942. "items will not be selectable in the 'O' command's menu.", 1943. (char *)0 1944. }; 1945. 1946. void 1947. option_help() 1948. { 1949. char buf[BUFSZ], buf2[BUFSZ]; 1950. register int i; 1951. winid datawin; 1952. 1953. datawin = create_nhwindow(NHW_TEXT); 1954. #ifdef AMIGA 1955. if (FromWBench) 1956. Sprintf(buf, "Set options as OPTIONS= in %s or in icon", configfile); 1957. else 1958. #endif 1959. Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile); 1960. opt_intro[CONFIG_SLOT] = (const char *) buf; 1961. for (i = 0; opt_intro[i]; i++) 1962. putstr(datawin, 0, opt_intro[i]); 1963. 1964. /* Boolean options */ 1965. for (i = 0; boolopt[i].name; i++) { 1966. if (boolopt[i].addr) { 1967. #ifdef WIZARD 1968. if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue; 1969. #endif 1970. next_opt(datawin, boolopt[i].name); 1971. } 1972. } 1973. next_opt(datawin, ""); 1974. 1975. /* Compound options */ 1976. putstr(datawin, 0, "Compound options:"); 1977. for (i = 0; compopt[i].name; i++) { 1978. Sprintf(buf2, "`%s'", compopt[i].name); 1979. Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr, 1980. compopt[i+1].name ? ',' : '.'); 1981. putstr(datawin, 0, buf); 1982. } 1983. 1984. for (i = 0; opt_epilog[i]; i++) 1985. putstr(datawin, 0, opt_epilog[i]); 1986. 1987. display_nhwindow(datawin, FALSE); 1988. destroy_nhwindow(datawin); 1989. return; 1990. } 1991. 1992. /* 1993. * prints the next boolean option, on the same line if possible, on a new 1994. * line if not. End with next_opt(""). 1995. */ 1996. void 1997. next_opt(datawin, str) 1998. winid datawin; 1999. const char *str; 2000. { 2001. static char *buf = 0; 2002. int i; 2003. char *s; 2004. 2005. if (!buf) buf = (char *)alloc(BUFSZ); 2006. 2007. if (!*str) { 2008. s = eos(buf); 2009. if (s > &buf[1] && s[-2] == ',') 2010. Strcpy(s - 2, "."); /* replace last ", " */ 2011. i = COLNO; /* (greater than COLNO - 2) */ 2012. } else { 2013. i = strlen(buf) + strlen(str) + 2; 2014. } 2015. 2016. if (i > COLNO - 2) { /* rule of thumb */ 2017. putstr(datawin, 0, buf); 2018. buf[0] = 0; 2019. } 2020. if (*str) { 2021. Strcat(buf, str); 2022. Strcat(buf, ", "); 2023. } else { 2024. putstr(datawin, 0, str); 2025. free(buf), buf = 0; 2026. } 2027. return; 2028. } 2029. 2030. /* Returns the fid of the fruit type; if that type already exists, it 2031. * returns the fid of that one; if it does not exist, it adds a new fruit 2032. * type to the chain and returns the new one. 2033. */ 2034. int 2035. fruitadd(str) 2036. char *str; 2037. { 2038. register int i; 2039. register struct fruit *f; 2040. struct fruit *lastf = 0; 2041. int highest_fruit_id = 0; 2042. char buf[PL_FSIZ]; 2043. boolean user_specified = (str == pl_fruit); 2044. /* if not user-specified, then it's a fruit name for a fruit on 2045. * a bones level... 2046. */ 2047. 2048. /* Note: every fruit has an id (spe for fruit objects) of at least 2049. * 1; 0 is an error. 2050. */ 2051. if (user_specified) { 2052. /* disallow naming after other foods (since it'd be impossible 2053. * to tell the difference) 2054. */ 2055. 2056. boolean found = FALSE, numeric = FALSE; 2057. 2058. for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; 2059. i++) { 2060. if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { 2061. found = TRUE; 2062. break; 2063. } 2064. } 2065. { 2066. char *c; 2067. 2068. c = pl_fruit; 2069. 2070. for(c = pl_fruit; *c >= '0' && *c <= '9'; c++) 2071. ; 2072. if (isspace(*c) || *c == 0) numeric = TRUE; 2073. } 2074. if (found || numeric || 2075. !strncmp(str, "cursed ", 7) || 2076. !strncmp(str, "uncursed ", 9) || 2077. !strncmp(str, "blessed ", 8) || 2078. !strncmp(str, "partly eaten ", 13) || 2079. (!strncmp(str, "tin of ", 7) && 2080. (!strcmp(str+7, "spinach") || 2081. name_to_mon(str+7) >= LOW_PM)) || 2082. !strcmp(str, "empty tin") || 2083. ((!strncmp(eos(str)-7," corpse",7) || 2084. !strncmp(eos(str)-4, " egg",4)) && 2085. name_to_mon(str) >= LOW_PM)) 2086. { 2087. Strcpy(buf, pl_fruit); 2088. Strcpy(pl_fruit, "candied "); 2089. nmcpy(pl_fruit+8, buf, PL_FSIZ-8); 2090. } 2091. } 2092. for(f=ffruit; f; f = f->nextf) { 2093. lastf = f; 2094. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid; 2095. if(!strncmp(str, f->fname, PL_FSIZ)) 2096. goto nonew; 2097. } 2098. /* if adding another fruit would overflow spe, use a random 2099. fruit instead... we've got a lot to choose from. */ 2100. if (highest_fruit_id >= 127) return rnd(127); 2101. highest_fruit_id++; 2102. f = newfruit(); 2103. if (ffruit) lastf->nextf = f; 2104. else ffruit = f; 2105. Strcpy(f->fname, str); 2106. f->fid = highest_fruit_id; 2107. f->nextf = 0; 2108. nonew: 2109. if (user_specified) current_fruit = highest_fruit_id; 2110. return f->fid; 2111. } 2112. 2113. /* 2114. * This is a somewhat generic menu for taking a list of NetHack style 2115. * class choices and presenting them via a description 2116. * rather than the traditional NetHack characters. 2117. * (Benefits users whose first exposure to NetHack is via tiles). 2118. * 2119. * prompt 2120. * The title at the top of the menu. 2121. * 2122. * category: 0 = monster class 2123. * 1 = object class 2124. * 2125. * way 2126. * FALSE = PICK_ONE, TRUE = PICK_ANY 2127. * 2128. * class_list 2129. * a null terminated string containing the list of choices. 2130. * 2131. * class_selection 2132. * a null terminated string containing the selected characters. 2133. * 2134. * Returns number selected. 2135. */ 2136. int 2137. choose_classes_menu(prompt, category, way, class_list, class_select) 2138. const char *prompt; 2139. int category; 2140. boolean way; 2141. char *class_list; 2142. char *class_select; 2143. { 2144. menu_item *pick_list = (menu_item *)0; 2145. winid win; 2146. anything any; 2147. char buf[BUFSZ]; 2148. int i, n; 2149. int ret; 2150. int next_accelerator, accelerator; 2151. 2152. if (class_list == (char *)0 || class_select == (char *)0) return 0; 2153. accelerator = 0; 2154. next_accelerator = 'a'; 2155. any.a_void = 0; 2156. win = create_nhwindow(NHW_MENU); 2157. start_menu(win); 2158. while (*class_list) { 2159. const char *text; 2160. boolean selected; 2161. 2162. text = (char *)0; 2163. selected = FALSE; 2164. switch (category) { 2165. case 0: 2166. text = monexplain[def_char_to_monclass(*class_list)]; 2167. accelerator = *class_list; 2168. Sprintf(buf, "%s", text); 2169. break; 2170. case 1: 2171. text = objexplain[def_char_to_objclass(*class_list)]; 2172. accelerator = next_accelerator; 2173. Sprintf(buf, "%c %s", *class_list, text); 2174. break; 2175. default: 2176. impossible("choose_classes_menu: invalid category %d", 2177. category); 2178. } 2179. if (way && *class_select) { /* Selections there already */ 2180. if (index(class_select, *class_list)) { 2181. selected = TRUE; 2182. } 2183. } 2184. any.a_int = *class_list; 2185. add_menu(win, NO_GLYPH, &any, accelerator, 2186. category ? *class_list : 0, 2187. ATR_NONE, buf, selected); 2188. ++class_list; 2189. if (category > 0) { 2190. ++next_accelerator; 2191. if (next_accelerator == ('z' + 1)) next_accelerator = 'A'; 2192. if (next_accelerator == ('Z' + 1)) break; 2193. } 2194. } 2195. end_menu(win, prompt); 2196. n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list); 2197. destroy_nhwindow(win); 2198. if (n > 0) { 2199. for (i = 0; i < n; ++i) 2200. *class_select++ = (char)pick_list[i].item.a_int; 2201. free((genericptr_t)pick_list); 2202. ret = n; 2203. } else if (n == -1) { 2204. class_select = eos(class_select); 2205. ret = -1; 2206. } else 2207. ret = 0; 2208. *class_select = '\0'; 2209. return ret; 2210. } 2211. 2212. #endif /* OPTION_LISTS_ONLY */ 2213. 2214. /*options.c*/