| abstract
| - 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 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 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 . 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. *
, \b, , , \xnnn (hex), \onnn (octal),
nn (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 = '
'; break; 535. case 't': cval = ' '; break; 536. case 'b': cval = '\b'; break; 537. case 'r': cval = ''; 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. "
%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 == '' || c == '
' || 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=\"\"' in your environment", 1928. #endif 1929. "( 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= 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*/
|