Source:NetHack 3.2.0/options.c
(Redirected from NetHack 3.2.0/options.c)
Jump to navigation
Jump to search
Below is the full text to options.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.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.2 96/02/14 */ 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. #define static 11. #else 12. #include "hack.h" 13. #include "termcap.h" 14. #include <ctype.h> 15. #endif 16. 17. #define WINTYPELEN 16 18. 19. /* 20. * NOTE: If you add (or delete) an option, please update the short 21. * options help (option_help()), the long options help (dat/opthelp), 22. * and the current options setting display function (doset()), 23. * and also the Guidebooks. 24. */ 25. 26. static struct Bool_Opt 27. { 28. const char *name; 29. boolean *addr, initvalue; 30. } boolopt[] = { 31. #ifdef AMIGA 32. {"altmeta", &flags.altmeta, TRUE}, 33. #else 34. {"altmeta", (boolean *)0, TRUE}, 35. #endif 36. #ifdef MFLOPPY 37. {"asksavedisk", &flags.asksavedisk, FALSE}, 38. #else 39. {"asksavedisk", (boolean *)0, FALSE}, 40. #endif 41. {"autopickup", &flags.pickup, TRUE}, 42. #if defined(MICRO) && !defined(AMIGA) 43. {"BIOS", &flags.BIOS, FALSE}, 44. #else 45. {"BIOS", (boolean *)0, FALSE}, 46. #endif 47. #ifdef INSURANCE 48. {"checkpoint", &flags.ins_chkpt, TRUE}, 49. #else 50. {"checkpoint", (boolean *)0, FALSE}, 51. #endif 52. #ifdef TEXTCOLOR 53. # ifdef MICRO 54. {"color", &flags.use_color, TRUE}, 55. # else /* systems that support multiple terminals, many monochrome */ 56. {"color", &flags.use_color, FALSE}, 57. # endif 58. #else 59. {"color", (boolean *)0, FALSE}, 60. #endif 61. {"confirm",&flags.confirm, TRUE}, 62. #ifdef TERMLIB 63. {"DECgraphics", &flags.DECgraphics, FALSE}, 64. #else 65. {"DECgraphics", (boolean *)0, FALSE}, 66. #endif 67. #ifdef OPT_DISPMAP 68. {"fast_map", &flags.fast_map, TRUE}, 69. #else 70. {"fast_map", (boolean *)0, TRUE}, 71. #endif 72. {"female", &flags.female, FALSE}, 73. {"fixinv", &flags.invlet_constant, TRUE}, 74. #ifdef AMIFLUSH 75. {"flush", &flags.amiflush, FALSE}, 76. #else 77. {"flush", (boolean *)0, FALSE}, 78. #endif 79. {"help", &flags.help, TRUE}, 80. #ifdef TEXTCOLOR 81. {"hilite_pet", &flags.hilite_pet, FALSE}, 82. #else 83. {"hilite_pet", (boolean *)0, FALSE}, 84. #endif 85. #ifdef ASCIIGRAPH 86. {"IBMgraphics", &flags.IBMgraphics, FALSE}, 87. #else 88. {"IBMgraphics", (boolean *)0, FALSE}, 89. #endif 90. {"ignintr", &flags.ignintr, FALSE}, 91. #ifdef MAC_GRAPHICS_ENV 92. {"large_font", &flags.large_font, FALSE}, 93. #else 94. {"large_font", (boolean *)0, FALSE}, 95. #endif 96. {"legacy",&flags.legacy, TRUE}, 97. {"lit_corridor", &flags.lit_corridor, FALSE}, 98. #ifdef MAC_GRAPHICS_ENV 99. {"Macgraphics", &flags.MACgraphics, TRUE}, 100. #else 101. {"Macgraphics", (boolean *)0, FALSE}, 102. #endif 103. #ifdef MAIL 104. {"mail", &flags.biff, TRUE}, 105. #else 106. {"mail", (boolean *)0, TRUE}, 107. #endif 108. #ifdef NEWS 109. {"news", &flags.news, TRUE}, 110. #else 111. {"news", (boolean *)0, FALSE}, 112. #endif 113. {"null", &flags.null, TRUE}, 114. {"number_pad", &flags.num_pad, FALSE}, 115. #ifdef MAC 116. {"page_wait", &flags.page_wait, TRUE}, 117. #else 118. {"page_wait", (boolean *)0, FALSE}, 119. #endif 120. {"perm_invent", &flags.perm_invent, FALSE}, 121. #ifdef MAC 122. {"popup_dialog", &flags.popup_dialog, FALSE}, 123. #else 124. {"popup_dialog", (boolean *)0, FALSE}, 125. #endif 126. #if defined(MICRO) && !defined(AMIGA) 127. {"rawio", &flags.rawio, FALSE}, 128. #else 129. {"rawio", (boolean *)0, FALSE}, 130. #endif 131. {"rest_on_space", &flags.rest_on_space, FALSE}, 132. {"safe_pet", &flags.safe_dog, TRUE}, 133. #ifdef WIZARD 134. {"sanity_check", &flags.sanity_check, FALSE}, 135. #else 136. {"sanity_check", (boolean *)0, FALSE}, 137. #endif 138. #ifdef EXP_ON_BOTL 139. {"showexp", &flags.showexp, FALSE}, 140. #else 141. {"showexp", (boolean *)0, FALSE}, 142. #endif 143. #ifdef SCORE_ON_BOTL 144. {"showscore", &flags.showscore, FALSE}, 145. #else 146. {"showscore", (boolean *)0, FALSE}, 147. #endif 148. {"silent", &flags.silent, TRUE}, 149. {"sortpack", &flags.sortpack, TRUE}, 150. {"sound", &flags.soundok, TRUE}, 151. {"standout", &flags.standout, FALSE}, 152. {"time", &flags.time, FALSE}, 153. #ifdef TIMED_DELAY 154. {"timed_delay", &flags.nap, TRUE}, 155. #else 156. {"timed_delay", (boolean *)0, FALSE}, 157. #endif 158. {"tombstone",&flags.tombstone, TRUE}, 159. {"toptenwin",&flags.toptenwin, FALSE}, 160. {"verbose", &flags.verbose, TRUE}, 161. {(char *)0, (boolean *)0, FALSE} 162. }; 163. 164. /* compound options, for option_help() and external programs like Amiga 165. * frontend */ 166. static struct Comp_Opt 167. { 168. const char *name, *descr; 169. int size; /* for frontends and such allocating space -- 170. * usually allowed size of data in game, but 171. * occasionally maximum reasonable size for 172. * typing when game maintains information in 173. * a different format */ 174. } compopt[] = { 175. { "catname", "the name of your (first) cat (e.g., catname:Tabby),", 176. PL_PSIZ }, 177. { "disclose", "the kinds of information to disclose at end of game,", 178. sizeof(flags.end_disclose) }, 179. { "dogname", "the name of your (first) dog (e.g., dogname:Fang),", 180. PL_PSIZ }, 181. { "dungeon", "the symbols to use in drawing the dungeon map,", 182. MAXDCHARS+1 }, 183. { "effects", "the symbols to use in drawing special effects,", 184. MAXECHARS+1 }, 185. { "fruit", "the name of a fruit you enjoy eating,", PL_FSIZ }, 186. { "menustyle", "user interface for object selection,", MENUTYPELEN }, 187. { "monsters", "the symbols to use for monsters,", MAXMCLASSES }, 188. { "msghistory", "number of top line messages to save,", 5 }, 189. { "name", "your character's name (e.g., name:Merlin-W),", PL_NSIZ }, 190. { "objects", "the symbols to use for objects,", MAXOCLASSES }, 191. { "packorder", "the inventory order of the items in your pack,", 192. MAXOCLASSES }, 193. #ifdef CHANGE_COLOR 194. { "palette", "palette (00c/880/-fff is blue/yellow/reverse white),", 195. 15 }, 196. # if defined(MAC) 197. { "hicolor", "same as palette, only order is reversed,", 15 }, 198. # endif 199. #endif 200. { "pettype", "your preferred initial pet type,", 4 }, 201. { "pickup_types", "types of objects to pick up automatically,", 202. MAXOCLASSES }, 203. { "scores", "the parts of the score list you wish to see,", 32 }, 204. #ifdef MSDOS 205. { "soundcard", "type of sound card to use,", 20 }, 206. #endif 207. { "traps", "the symbols to use in drawing traps,", MAXTCHARS+1 }, 208. #ifdef MSDOS 209. { "video", "method of video updating,", 20 }, 210. #endif 211. #ifdef VIDEOSHADES 212. { "videocolors", "color mappings for internal screen routines,", 40 }, 213. { "videoshades", "gray shades to map to black/gray/white,", 32 }, 214. #endif 215. { "windowtype", "windowing system to use.", WINTYPELEN }, 216. { (char *)0, (char *)0, 0 } 217. }; 218. 219. #ifdef OPTION_LISTS_ONLY 220. #undef static 221. 222. #else /* use rest of file */ 223. 224. static boolean need_redraw; /* for doset() */ 225. 226. #if defined(TOS) && defined(TEXTCOLOR) 227. extern boolean colors_changed; /* in tos.c */ 228. #endif 229. 230. #ifdef VIDEOSHADES 231. extern char *shade[3]; /* in sys/msdos/video.c */ 232. extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */ 233. #endif 234. 235. extern const char *roles[]; /* from u_init.c */ 236. 237. static char def_inv_order[MAXOCLASSES] = { 238. GOLD_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, 239. SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, 240. TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0, 241. }; 242. 243. static boolean initial, from_file; 244. 245. static void FDECL(nmcpy, (char *, const char *, int)); 246. static void FDECL(escapes, (const char *, char *)); 247. static void FDECL(rejectoption, (const char *)); 248. static void FDECL(badoption, (const char *)); 249. static char *FDECL(string_for_opt, (char *,BOOLEAN_P)); 250. static char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P)); 251. static void FDECL(bad_negation, (const char *,BOOLEAN_P)); 252. static int FDECL(change_inv_order, (char *)); 253. static void FDECL(oc_to_str, (char *, char *)); 254. static void FDECL(graphics_opts, (char *,const char *,int,int)); 255. 256. void 257. initoptions() 258. { 259. register char *opts; 260. int i; 261. 262. for (i = 0; boolopt[i].name; i++) { 263. if (boolopt[i].addr) 264. *(boolopt[i].addr) = boolopt[i].initvalue; 265. } 266. flags.end_own = FALSE; 267. flags.end_top = 3; 268. flags.end_around = 2; 269. flags.msg_history = 20; 270. 271. /* Set the default monster and object class symbols. Don't use */ 272. /* memcpy() --- sizeof char != sizeof uchar on some machines. */ 273. for (i = 0; i < MAXOCLASSES; i++) 274. oc_syms[i] = (uchar) def_oc_syms[i]; 275. for (i = 0; i < MAXMCLASSES; i++) 276. monsyms[i] = (uchar) def_monsyms[i]; 277. 278. /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */ 279. (void)memcpy((genericptr_t)flags.inv_order, 280. (genericptr_t)def_inv_order, sizeof flags.inv_order); 281. flags.pickup_types[0] = '\0'; 282. 283. switch_graphics(ASCII_GRAPHICS); /* set default characters */ 284. #if defined(UNIX) && defined(TTY_GRAPHICS) 285. /* 286. * Set defaults for some options depending on what we can 287. * detect about the environment's capabilities. 288. * This has to be done after the global initialization above 289. * and before reading user-specific initialization via 290. * config file/environment variable below. 291. */ 292. /* this detects the IBM-compatible console on most 386 boxes */ 293. if (!strncmp(getenv("TERM"), "AT", 2)) { 294. switch_graphics(IBM_GRAPHICS); 295. # ifdef TEXTCOLOR 296. flags.use_color = TRUE; 297. # endif 298. } 299. #endif /* UNIX && TTY_GRAPHICS */ 300. #if defined(UNIX) || defined(VMS) 301. # ifdef TTY_GRAPHICS 302. /* detect whether a "vt" terminal can handle alternate charsets */ 303. if (!strncmpi(getenv("TERM"), "vt", 2) && (AS && AE) && 304. index(AS, '\016') && index(AE, '\017')) { 305. switch_graphics(DEC_GRAPHICS); 306. } 307. # endif 308. #endif /* UNIX || VMS */ 309. 310. #ifdef MAC_GRAPHICS_ENV 311. switch_graphics(MAC_GRAPHICS); 312. #endif /* MAC_GRAPHICS_ENV */ 313. flags.menu_style = MENU_FULL; 314. 315. /* since this is done before init_objects(), do partial init here */ 316. objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; 317. nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); 318. opts = getenv("NETHACKOPTIONS"); 319. if (!opts) opts = getenv("HACKOPTIONS"); 320. if (opts) { 321. if (*opts == '/' || *opts == '\\' || *opts == '@') { 322. if (*opts == '@') opts++; /* @filename */ 323. /* looks like a filename */ 324. read_config_file(opts); 325. } else { 326. read_config_file((char *)0); 327. parseoptions(opts, TRUE, FALSE); 328. } 329. } else { 330. read_config_file((char *)0); 331. } 332. #ifdef AMIGA 333. ami_wbench_init(); /* must be here or can't set fruit */ 334. #endif 335. (void)fruitadd(pl_fruit); 336. /* Remove "slime mold" from list of object names; this will */ 337. /* prevent it from being wished unless it's actually present */ 338. /* as a named (or default) fruit. Wishing for "fruit" will */ 339. /* result in the player's preferred fruit [better than "\033"]. */ 340. obj_descr[SLIME_MOLD].oc_name = "fruit"; 341. 342. if (flags.female) { /* should have been set in NETHACKOPTIONS */ 343. roles[2] = "Cavewoman"; 344. roles[6] = "Priestess"; 345. } 346. } 347. 348. static void 349. nmcpy(dest, src, maxlen) 350. char *dest; 351. const char *src; 352. int maxlen; 353. { 354. int count; 355. 356. for(count = 1; count < maxlen; count++) { 357. if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/ 358. *dest++ = *src++; 359. } 360. *dest = 0; 361. } 362. 363. /* 364. * escapes: escape expansion for showsyms. C-style escapes understood include 365. * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix 366. * for control characters is also understood, and \[mM] followed by any of the 367. * previous forms or by a character has the effect of 'meta'-ing the value (so 368. * that the alternate character set will be enabled). 369. */ 370. static void 371. escapes(cp, tp) 372. const char *cp; 373. char *tp; 374. { 375. while (*cp) 376. { 377. int cval = 0, meta = 0; 378. 379. if (*cp == '\\' && index("mM", cp[1])) { 380. meta = 1; 381. cp += 2; 382. } 383. if (*cp == '\\' && index("0123456789xXoO", cp[1])) 384. { 385. const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; 386. int dcount = 0; 387. 388. cp++; 389. if (*cp == 'x' || *cp == 'X') 390. for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) 391. cval = (cval * 16) + (dp - hex) / 2; 392. else if (*cp == 'o' || *cp == 'O') 393. for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++) 394. cval = (cval * 8) + (*cp - '0'); 395. else 396. for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++) 397. cval = (cval * 10) + (*cp - '0'); 398. } 399. else if (*cp == '\\') /* C-style character escapes */ 400. { 401. switch (*++cp) 402. { 403. case '\\': cval = '\\'; break; 404. case 'n': cval = '\n'; break; 405. case 't': cval = '\t'; break; 406. case 'b': cval = '\b'; break; 407. case 'r': cval = '\r'; break; 408. default: cval = *cp; 409. } 410. cp++; 411. } 412. else if (*cp == '^') /* expand control-character syntax */ 413. { 414. cval = (*++cp & 0x1f); 415. cp++; 416. } 417. else 418. cval = *cp++; 419. if (meta) 420. cval |= 0x80; 421. *tp++ = cval; 422. } 423. *tp = '\0'; 424. } 425. 426. static void 427. rejectoption(optname) 428. const char *optname; 429. { 430. #ifdef MICRO 431. # ifdef AMIGA 432. if(FromWBench){ 433. pline("\"%s\" settable only from %s or in icon.", 434. optname, configfile); 435. } else 436. # endif 437. pline("\"%s\" settable only from %s.", optname, configfile); 438. #else 439. pline("%s can be set only from NETHACKOPTIONS or %s.", optname, 440. configfile); 441. #endif 442. } 443. 444. static void 445. badoption(opts) 446. const char *opts; 447. { 448. if (!initial) { 449. if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1)) 450. option_help(); 451. else 452. pline("Bad syntax: %s. Enter \"?g\" for help.", opts); 453. return; 454. } 455. # ifdef AMIGA 456. if(ami_wbench_badopt(opts)) { 457. # endif 458. if(from_file) 459. raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts); 460. else 461. raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts); 462. # ifdef AMIGA 463. } 464. # endif 465. wait_synch(); 466. } 467. 468. static char * 469. string_for_opt(opts, val_optional) 470. char *opts; 471. boolean val_optional; 472. { 473. register char *colon; 474. 475. colon = index(opts, ':'); 476. if (!colon || !*++colon) { 477. if (!val_optional) badoption(opts); 478. return (char *)0; 479. } 480. return colon; 481. } 482. 483. static char * 484. string_for_env_opt(optname, opts, val_optional) 485. const char *optname; 486. char *opts; 487. boolean val_optional; 488. { 489. if(!initial) { 490. rejectoption(optname); 491. return (char *)0; 492. } 493. return string_for_opt(opts, val_optional); 494. } 495. 496. static void 497. bad_negation(optname, with_parameter) 498. const char *optname; 499. boolean with_parameter; 500. { 501. pline_The("%s option may not %sbe negated.", 502. optname, 503. with_parameter ? "both have a value and " : ""); 504. } 505. 506. /* 507. * Change the inventory order, using the given string as the new order. 508. * Missing characters in the new order are filled in at the end from 509. * the current inv_order, except for gold, which is forced to be first 510. * if not explicitly present. 511. * 512. * This routine returns 1 unless there is a duplicate or bad char in 513. * the string. 514. */ 515. static int 516. change_inv_order(op) 517. char *op; 518. { 519. int oc_sym, num; 520. char *sp, buf[BUFSZ]; 521. 522. num = 0; 523. if (!index(op, GOLD_SYM)) 524. buf[num++] = GOLD_CLASS; 525. 526. for (sp = op; *sp; sp++) { 527. oc_sym = def_char_to_objclass(*sp); 528. /* reject bad or duplicate entries */ 529. if (oc_sym == MAXOCLASSES || 530. oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS || 531. !index(flags.inv_order, oc_sym) || index(sp+1, *sp)) 532. return 0; 533. /* retain good ones */ 534. buf[num++] = (char) oc_sym; 535. } 536. buf[num] = '\0'; 537. 538. /* fill in any omitted classes, using previous ordering */ 539. for (sp = flags.inv_order; *sp; sp++) 540. if (!index(buf, *sp)) { 541. buf[num++] = *sp; 542. buf[num] = '\0'; /* explicitly terminate for next index() */ 543. } 544. 545. Strcpy(flags.inv_order, buf); 546. return 1; 547. } 548. 549. static void 550. graphics_opts(opts, optype, maxlen, offset) 551. register char *opts; 552. const char *optype; 553. int maxlen, offset; 554. { 555. uchar translate[MAXPCHARS+1]; 556. int length, i; 557. 558. if (!(opts = string_for_env_opt(optype, opts, FALSE))) 559. return; 560. escapes(opts, opts); 561. 562. length = strlen(opts); 563. if (length > maxlen) length = maxlen; 564. /* match the form obtained from PC configuration files */ 565. for (i = 0; i < length; i++) 566. translate[i] = (uchar) opts[i]; 567. assign_graphics(translate, length, maxlen, offset); 568. } 569. 570. void 571. parseoptions(opts, tinitial, tfrom_file) 572. register char *opts; 573. boolean tinitial, tfrom_file; 574. { 575. register char *op; 576. unsigned num; 577. boolean negated; 578. int i; 579. char tbuf[MAXOCLASSES + 1]; 580. const char *fullname; 581. 582. initial = tinitial; 583. from_file = tfrom_file; 584. if ((op = index(opts, ',')) != 0) { 585. *op++ = 0; 586. parseoptions(op, initial, from_file); 587. } 588. 589. /* strip leading and trailing white space */ 590. while (isspace(*opts)) opts++; 591. op = eos(opts); 592. while (--op >= opts && isspace(*op)) *op = '\0'; 593. 594. if (!*opts) return; 595. negated = FALSE; 596. while ((*opts == '!') || !strncmpi(opts, "no", 2)) { 597. if (*opts == '!') opts++; else opts += 2; 598. negated = !negated; 599. } 600. 601. /* variant spelling */ 602. 603. if (!strcmpi(opts, "colour")) 604. Strcpy(opts, "color"); /* fortunately this is shorter */ 605. 606. /* special boolean options */ 607. 608. if (!strncmpi(opts, "female", 3)) { 609. if(!initial && flags.female == negated) 610. pline("That is not anatomically possible."); 611. else 612. flags.female = !negated; 613. return; 614. } 615. 616. if (!strncmpi(opts, "male", 4)) { 617. if(!initial && flags.female != negated) 618. pline("That is not anatomically possible."); 619. else 620. flags.female = negated; 621. return; 622. } 623. 624. #if defined(MICRO) && !defined(AMIGA) 625. /* included for compatibility with old NetHack.cnf files */ 626. if (!strncmp(opts, "IBM_", 4)) { 627. flags.BIOS = !negated; 628. return; 629. } 630. #endif /* MICRO */ 631. 632. /* compound options */ 633. 634. fullname = "pettype"; 635. if (!strncmpi(opts, fullname, 3)) { 636. if ((op = string_for_env_opt(fullname, opts, negated)) != 0) { 637. if (negated) bad_negation(fullname, TRUE); 638. else switch (*op) { 639. case 'd': /* dog */ 640. case 'D': 641. preferred_pet = 'd'; 642. break; 643. case 'c': /* cat */ 644. case 'C': 645. case 'f': /* feline */ 646. case 'F': 647. preferred_pet = 'c'; 648. break; 649. default: 650. pline("Unrecognized pet type '%s'", op); 651. break; 652. } 653. } else if (negated) preferred_pet = 0; 654. return; 655. } 656. 657. fullname = "catname"; 658. if (!strncmpi(opts, fullname, 3)) { 659. if (negated) bad_negation(fullname, FALSE); 660. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 661. nmcpy(catname, op, PL_PSIZ); 662. return; 663. } 664. 665. fullname = "dogname"; 666. if (!strncmpi(opts, fullname, 3)) { 667. if (negated) bad_negation(fullname, FALSE); 668. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 669. nmcpy(dogname, op, PL_PSIZ); 670. return; 671. } 672. 673. fullname = "msghistory"; 674. if (!strncmpi(opts, fullname, 3)) { 675. op = string_for_env_opt(fullname, opts, negated); 676. if ((negated && !op) || (!negated && op)) { 677. flags.msg_history = negated ? 0 : atoi(op); 678. } else if (negated) bad_negation(fullname, TRUE); 679. return; 680. } 681. 682. #ifdef CHANGE_COLOR 683. if (!strncmpi(opts, "palette", 3) 684. # ifdef MAC 685. || !strncmpi(opts, "hicolor", 3) 686. # endif 687. ) { 688. int color_number, color_incr; 689. 690. # ifdef MAC 691. if (!strncmpi(opts, "hicolor", 3)) { 692. if (negated) { 693. bad_negation("hicolor", FALSE); 694. return; 695. } 696. color_number = CLR_MAX + 4; /* HARDCODED inverse number */ 697. color_incr = -1; 698. } else { 699. # endif 700. if (negated) { 701. bad_negation("palette", FALSE); 702. return; 703. } 704. color_number = 0; 705. color_incr = 1; 706. # ifdef MAC 707. } 708. # endif 709. if ((op = string_for_opt(opts, FALSE)) != (char *)0) { 710. char *pt = op; 711. int cnt, tmp, reverse; 712. long rgb; 713. 714. while (*pt && color_number >= 0) { 715. cnt = 3; 716. rgb = 0L; 717. if (*pt == '-') { 718. reverse = 1; 719. pt++; 720. } else { 721. reverse = 0; 722. } 723. while (cnt-- > 0) { 724. if (*pt && *pt != '/') { 725. # ifdef AMIGA 726. rgb <<= 4; 727. # else 728. rgb <<= 8; 729. # endif 730. tmp = *(pt++); 731. if (isalpha(tmp)) { 732. tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */ 733. } else { 734. tmp &= 0xf; /* Digits in ASCII too... */ 735. } 736. # ifndef AMIGA 737. /* Add an extra so we fill f -> ff and 0 -> 00 */ 738. rgb += tmp << 4; 739. # endif 740. rgb += tmp; 741. } 742. } 743. if (*pt == '/') { 744. pt++; 745. } 746. change_color(color_number, rgb, reverse); 747. color_number += color_incr; 748. } 749. } 750. if (!initial) { 751. need_redraw = TRUE; 752. } 753. return; 754. } 755. #endif 756. 757. if (!strncmpi(opts, "fruit", 2)) { 758. char empty_str = '\0'; 759. op = string_for_opt(opts, negated); 760. if (negated) { 761. if (op) { 762. bad_negation("fruit", TRUE); 763. return; 764. } 765. op = &empty_str; 766. goto goodfruit; 767. } 768. if (!op) return; 769. if (!initial) { 770. struct fruit *f; 771. 772. num = 0; 773. for(f=ffruit; f; f=f->nextf) { 774. if (!strcmp(op, f->fname)) goto goodfruit; 775. num++; 776. } 777. if (num >= 100) { 778. pline("Doing that so many times isn't very fruitful."); 779. return; 780. } 781. } 782. goodfruit: 783. nmcpy(pl_fruit, op, PL_FSIZ); 784. /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */ 785. if (!*pl_fruit) 786. nmcpy(pl_fruit, "slime mold", PL_FSIZ); 787. if (!initial) 788. (void)fruitadd(pl_fruit); 789. /* If initial, then initoptions is allowed to do it instead 790. * of here (initoptions always has to do it even if there's 791. * no fruit option at all. Also, we don't want people 792. * setting multiple fruits in their options.) 793. */ 794. return; 795. } 796. 797. /* graphics:string */ 798. fullname = "graphics"; 799. if (!strncmpi(opts, fullname, 2)) { 800. if (negated) bad_negation(fullname, FALSE); 801. else graphics_opts(opts, fullname, MAXPCHARS, 0); 802. return; 803. } 804. fullname = "dungeon"; 805. if (!strncmpi(opts, fullname, 2)) { 806. if (negated) bad_negation(fullname, FALSE); 807. else graphics_opts(opts, fullname, MAXDCHARS, 0); 808. return; 809. } 810. fullname = "traps"; 811. if (!strncmpi(opts, fullname, 2)) { 812. if (negated) bad_negation(fullname, FALSE); 813. else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS); 814. return; 815. } 816. fullname = "effects"; 817. if (!strncmpi(opts, fullname, 2)) { 818. if (negated) bad_negation(fullname, FALSE); 819. else 820. graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS); 821. return; 822. } 823. 824. /* objects:string */ 825. fullname = "objects"; 826. if (!strncmpi(opts, fullname, 7)) { 827. int length; 828. 829. if (negated) { 830. bad_negation(fullname, FALSE); 831. return; 832. } 833. if (!(opts = string_for_env_opt(fullname, opts, FALSE))) 834. return; 835. escapes(opts, opts); 836. 837. /* 838. * Override the default object class symbols. The first 839. * object in the object class is the "random object". I 840. * don't want to use 0 as an object class, so the "random 841. * object" is basically a place holder. 842. * 843. * The object class symbols have already been initialized in 844. * initoptions(). 845. */ 846. length = strlen(opts); 847. if (length >= MAXOCLASSES) 848. length = MAXOCLASSES-1; /* don't count RANDOM_OBJECT */ 849. 850. for (i = 0; i < length; i++) 851. oc_syms[i+1] = (uchar) opts[i]; 852. return; 853. } 854. 855. /* monsters:string */ 856. fullname = "monsters"; 857. if (!strncmpi(opts, fullname, 8)) { 858. int length; 859. 860. if (negated) { 861. bad_negation(fullname, FALSE); 862. return; 863. } 864. if (!(opts = string_for_env_opt(fullname, opts, FALSE))) 865. return; 866. escapes(opts, opts); 867. 868. /* Override default mon class symbols set in initoptions(). */ 869. length = strlen(opts); 870. if (length >= MAXMCLASSES) 871. length = MAXMCLASSES-1; /* mon class 0 unused */ 872. 873. for (i = 0; i < length; i++) 874. monsyms[i+1] = (uchar) opts[i]; 875. return; 876. } 877. 878. /* name:string */ 879. fullname = "name"; 880. if (!strncmpi(opts, fullname, 4)) { 881. if (negated) bad_negation(fullname, FALSE); 882. else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 883. nmcpy(plname, op, PL_NSIZ); 884. return; 885. } 886. 887. /* the order to list the pack */ 888. fullname = "packorder"; 889. if (!strncmpi(opts, fullname, 4)) { 890. if (negated) { 891. bad_negation(fullname, FALSE); 892. return; 893. } else if (!(op = string_for_opt(opts, FALSE))) return; 894. 895. if (!change_inv_order(op)) 896. badoption(opts); 897. return; 898. } 899. 900. /* types of objects to pick up automatically */ 901. if (!strncmpi(opts, "pickup_types", 4)) { 902. int oc_sym; 903. boolean badopt = FALSE, compat = (strlen(opts) <= 6); 904. 905. oc_to_str(flags.pickup_types, tbuf); 906. flags.pickup_types[0] = '\0'; /* all */ 907. op = string_for_opt(opts, TRUE); 908. if (!op) { 909. if (!compat && !negated) { 910. char ocl[MAXOCLASSES + 1]; 911. 912. oc_to_str(flags.inv_order, ocl); 913. if (choose_classes_menu("Auto-Pickup what?", 1, 914. TRUE, ocl, tbuf)) 915. op = tbuf; 916. else 917. return; 918. } else if (!compat) { 919. /* !pickup_types means no pickup types, but we can't do 920. that by just emptying pickup_types, because that's a 921. special case which means all types rather than none */ 922. flags.pickup = 0; 923. return; 924. } else { 925. /* for backwards compatibility, "pickup" without a value 926. (as opposed to "pickup_types" without a value) 927. is a synonym for boolean autopickup, and pickup_types 928. gets reset to "all" */ 929. flags.pickup = !negated; 930. return; 931. } 932. } 933. if (negated) { 934. bad_negation("pickup_types", TRUE); 935. return; 936. } 937. while (*op == ' ') op++; 938. if (*op != 'a' && *op != 'A') { 939. num = 0; 940. while (*op) { 941. oc_sym = def_char_to_objclass(*op); 942. /* make sure all are valid obj symbols occuring once */ 943. if (oc_sym != MAXOCLASSES && 944. !index(flags.pickup_types, oc_sym)) { 945. flags.pickup_types[num] = (char)oc_sym; 946. flags.pickup_types[++num] = '\0'; 947. } else 948. badopt = TRUE; 949. op++; 950. } 951. if (badopt) badoption(opts); 952. } 953. return; 954. } 955. 956. /* things to disclose at end of game */ 957. if (!strncmpi(opts, "disclose", 4)) { 958. flags.end_disclose[0] = '\0'; /* all */ 959. if (!(op = string_for_opt(opts, TRUE))) { 960. /* for backwards compatibility, "disclose" without a 961. * value means all (was inventory and attributes, 962. * the only things available then), but negated 963. * it means "none" 964. * (note "none" contains none of "iavkg") 965. */ 966. if (negated) Strcpy(flags.end_disclose, "none"); 967. return; 968. } 969. if (negated) { 970. bad_negation("disclose", TRUE); 971. return; 972. } 973. num = 0; 974. while (*op && num < sizeof flags.end_disclose - 1) { 975. register char c; 976. c = lowc(*op); 977. if (c == 'k') c = 'v'; /* killed -> vanquished */ 978. if (!index(flags.end_disclose, c)) { 979. flags.end_disclose[num++] = c; 980. flags.end_disclose[num] = '\0'; /* for index */ 981. } 982. op++; 983. } 984. return; 985. } 986. 987. /* scores:5t[op] 5a[round] o[wn] */ 988. if (!strncmpi(opts, "scores", 6)) { 989. if (negated) { 990. bad_negation("scores", FALSE); 991. return; 992. } 993. if (!(op = string_for_opt(opts, FALSE))) return; 994. 995. while (*op) { 996. int inum = 1; 997. 998. if (digit(*op)) { 999. inum = atoi(op); 1000. while (digit(*op)) op++; 1001. } else if (*op == '!') { 1002. negated = !negated; 1003. op++; 1004. } 1005. while (*op == ' ') op++; 1006. 1007. switch (*op) { 1008. case 't': 1009. case 'T': flags.end_top = inum; 1010. break; 1011. case 'a': 1012. case 'A': flags.end_around = inum; 1013. break; 1014. case 'o': 1015. case 'O': flags.end_own = !negated; 1016. break; 1017. default: badoption(opts); 1018. return; 1019. } 1020. while (letter(*++op) || *op == ' ') continue; 1021. if (*op == '/') op++; 1022. } 1023. return; 1024. } 1025. 1026. #ifdef VIDEOSHADES 1027. /* videocolors:string */ 1028. fullname = "videocolors"; 1029. if (!strncmpi(opts, fullname, 6)) { 1030. if (negated) { 1031. bad_negation(fullname, FALSE); 1032. return; 1033. } 1034. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1035. return; 1036. } 1037. if (!assign_videocolors(opts)) 1038. badoption(opts); 1039. return; 1040. } 1041. /* videoshades:string */ 1042. fullname = "videoshades"; 1043. if (!strncmpi(opts, fullname, 6)) { 1044. if (negated) { 1045. bad_negation(fullname, FALSE); 1046. return; 1047. } 1048. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1049. return; 1050. } 1051. if (!assign_videoshades(opts)) 1052. badoption(opts); 1053. return; 1054. } 1055. #endif /* VIDEOSHADES */ 1056. #ifdef MSDOS 1057. # ifdef NO_TERMS 1058. /* video:string -- must be after longer tests */ 1059. fullname = "video"; 1060. if (!strncmpi(opts, fullname, 5)) { 1061. if (negated) { 1062. bad_negation(fullname, FALSE); 1063. return; 1064. } 1065. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1066. return; 1067. } 1068. if (!assign_video(opts)) 1069. badoption(opts); 1070. return; 1071. } 1072. # endif 1073. /* soundcard:string -- careful not to match boolean 'sound' */ 1074. fullname = "soundcard"; 1075. if (!strncmpi(opts, fullname, 6)) { 1076. if (negated) { 1077. bad_negation(fullname, FALSE); 1078. return; 1079. } 1080. else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1081. return; 1082. } 1083. if (!assign_soundcard(opts)) 1084. badoption(opts); 1085. return; 1086. } 1087. #endif 1088. fullname = "windowtype"; 1089. if (!strncmpi(opts, fullname, 3)) { 1090. if (negated) { 1091. bad_negation(fullname, FALSE); 1092. return; 1093. } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { 1094. char buf[WINTYPELEN]; 1095. nmcpy(buf, op, WINTYPELEN); 1096. choose_windows(buf); 1097. } 1098. return; 1099. } 1100. 1101. /* menustyle:traditional or combo or full or partial */ 1102. if (!strncmpi(opts, "menustyle", 4)) { 1103. int tmp; 1104. boolean val_required = (strlen(opts) > 5 && !negated); 1105. 1106. if (!(op = string_for_opt(opts, !val_required))) { 1107. if (val_required) return; /* string_for_opt gave feedback */ 1108. tmp = negated ? 'n' : 'f'; 1109. } else { 1110. tmp = tolower(*op); 1111. } 1112. switch (tmp) { 1113. case 'n': /* none */ 1114. case 't': /* traditional */ 1115. flags.menu_style = MENU_TRADITIONAL; 1116. break; 1117. case 'c': /* combo: trad.class sel+menu */ 1118. flags.menu_style = MENU_COMBINATION; 1119. break; 1120. case 'p': /* partial: no class menu */ 1121. flags.menu_style = MENU_PARTIAL; 1122. break; 1123. case 'f': /* full: class menu + menu */ 1124. flags.menu_style = MENU_FULL; 1125. break; 1126. default: 1127. badoption(opts); 1128. } 1129. return; 1130. } 1131. /* OK, if we still haven't recognized the option, check the boolean 1132. * options list 1133. */ 1134. for (i = 0; boolopt[i].name; i++) { 1135. if (strlen(opts) >= 3 && 1136. !strncmpi(boolopt[i].name, opts, strlen(opts))) { 1137. /* options that don't exist */ 1138. if (!boolopt[i].addr) { 1139. if (!initial && !negated) 1140. pline_The("\"%s\" option is not available.", 1141. boolopt[i].name); 1142. return; 1143. } 1144. /* options that must come from config file */ 1145. if (!initial && 1146. ((boolopt[i].addr) == &flags.legacy 1147. #if defined(MICRO) && !defined(AMIGA) 1148. || (boolopt[i].addr) == &flags.rawio 1149. #endif 1150. )) { 1151. rejectoption(boolopt[i].name); 1152. return; 1153. } 1154. 1155. *(boolopt[i].addr) = !negated; 1156. 1157. #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV) 1158. if (FALSE 1159. # ifdef TERMLIB 1160. || (boolopt[i].addr) == &flags.DECgraphics 1161. # endif 1162. # ifdef ASCIIGRAPH 1163. || (boolopt[i].addr) == &flags.IBMgraphics 1164. # endif 1165. # ifdef MAC_GRAPHICS_ENV 1166. || (boolopt[i].addr) == &flags.MACgraphics 1167. # endif 1168. ) { 1169. # ifdef REINCARNATION 1170. if (!initial && Is_rogue_level(&u.uz)) 1171. assign_rogue_graphics(FALSE); 1172. # endif 1173. need_redraw = TRUE; 1174. # ifdef TERMLIB 1175. if ((boolopt[i].addr) == &flags.DECgraphics) 1176. switch_graphics(flags.DECgraphics ? 1177. DEC_GRAPHICS : ASCII_GRAPHICS); 1178. # endif 1179. # ifdef ASCIIGRAPH 1180. if ((boolopt[i].addr) == &flags.IBMgraphics) 1181. switch_graphics(flags.IBMgraphics ? 1182. IBM_GRAPHICS : ASCII_GRAPHICS); 1183. # endif 1184. # ifdef MAC_GRAPHICS_ENV 1185. if ((boolopt[i].addr) == &flags.MACgraphics) 1186. switch_graphics(flags.MACgraphics ? 1187. MAC_GRAPHICS : ASCII_GRAPHICS); 1188. # endif 1189. # ifdef REINCARNATION 1190. if (!initial && Is_rogue_level(&u.uz)) 1191. assign_rogue_graphics(TRUE); 1192. # endif 1193. } 1194. #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */ 1195. 1196. /* only do processing below if setting with doset() */ 1197. if (initial) return; 1198. 1199. if ((boolopt[i].addr) == &flags.time 1200. #ifdef EXP_ON_BOTL 1201. || (boolopt[i].addr) == &flags.showexp 1202. #endif 1203. #ifdef SCORE_ON_BOTL 1204. || (boolopt[i].addr) == &flags.showscore 1205. #endif 1206. ) 1207. flags.botl = TRUE; 1208. 1209. else if ((boolopt[i].addr) == &flags.invlet_constant) { 1210. if (flags.invlet_constant) reassign(); 1211. } 1212. 1213. else if ((boolopt[i].addr) == &flags.num_pad) 1214. number_pad(flags.num_pad ? 1 : 0); 1215. 1216. else if ((boolopt[i].addr) == &flags.lit_corridor) { 1217. /* 1218. * All corridor squares seen via night vision or 1219. * candles & lamps change. Update them by calling 1220. * newsym() on them. Don't do this if we are 1221. * initializing the options --- the vision system 1222. * isn't set up yet. 1223. */ 1224. vision_recalc(2); /* shut down vision */ 1225. vision_full_recalc = 1; /* delayed recalc */ 1226. } 1227. 1228. #ifdef TEXTCOLOR 1229. else if ((boolopt[i].addr) == &flags.use_color 1230. || (boolopt[i].addr) == &flags.hilite_pet) { 1231. need_redraw = TRUE; 1232. # ifdef TOS 1233. if ((boolopt[i].addr) == &flags.use_color 1234. && flags.BIOS) { 1235. if (colors_changed) 1236. restore_colors(); 1237. else 1238. set_colors(); 1239. } 1240. # endif 1241. } 1242. #endif 1243. 1244. return; 1245. } 1246. } 1247. 1248. /* out of valid options */ 1249. badoption(opts); 1250. } 1251. 1252. static NEARDATA const char *menutype[] = { 1253. "traditional", "combination", "partial", "full" 1254. }; 1255. 1256. /* 1257. * Convert the given string of object classes to a string of default object 1258. * symbols. 1259. */ 1260. static void 1261. oc_to_str(src,dest) 1262. char *src, *dest; 1263. { 1264. int i; 1265. 1266. while ((i = (int) *src++) != 0) { 1267. if (i < 0 || i >= MAXOCLASSES) 1268. impossible("oc_to_str: illegal object class %d", i); 1269. else 1270. *dest++ = def_oc_syms[i]; 1271. } 1272. *dest = '\0'; 1273. } 1274. 1275. #if defined(MICRO) || defined(MAC) 1276. # define OPTIONS_HEADING "OPTIONS" 1277. #else 1278. # define OPTIONS_HEADING "NETHACKOPTIONS" 1279. #endif 1280. 1281. int 1282. doset() 1283. { 1284. char buf[BUFSZ], ocl[MAXOCLASSES+1], on_off; 1285. const char *opt_name; 1286. int i; 1287. winid tmpwin; 1288. 1289. switch (yn_function("Show the current settings [c], or set options [s]?", 1290. "csq", 'q')) { 1291. default: 1292. case 'q': 1293. clear_nhwindow(WIN_MESSAGE); 1294. return 0; 1295. case 'c': 1296. tmpwin = create_nhwindow(NHW_MENU); 1297. putstr(tmpwin, 0, OPTIONS_HEADING); 1298. putstr(tmpwin, 0, ""); 1299. /* print the booleans */ 1300. for (i = 0; boolopt[i].name; i++) { 1301. if (!boolopt[i].addr) continue; 1302. opt_name = boolopt[i].name; 1303. if (*(boolopt[i].addr)) { 1304. on_off = ' '; /* on */ 1305. } else { 1306. if (!strcmp(opt_name, "female")) 1307. opt_name = "male", on_off = ' '; 1308. else 1309. on_off = '!'; /* off */ 1310. } 1311. Sprintf(buf, "%c%s", on_off, opt_name); 1312. putstr(tmpwin, 0, buf); 1313. } 1314. /* print the compounds */ 1315. Sprintf(buf, " catname: %s", 1316. (catname[0] != 0) ? catname : "(null)"); 1317. putstr(tmpwin, 0, buf); 1318. Sprintf(buf, " disclose: %s", 1319. (flags.end_disclose[0]) ? flags.end_disclose : "all"); 1320. putstr(tmpwin, 0, buf); 1321. Sprintf(buf, " dogname: %s", 1322. (dogname[0] != 0) ? dogname : "(null)"); 1323. putstr(tmpwin, 0, buf); 1324. Sprintf(buf, " fruit: %s", pl_fruit); 1325. putstr(tmpwin, 0, buf); 1326. Sprintf(buf, " menustyle: %s", menutype[(int)flags.menu_style]); 1327. putstr(tmpwin, 0, buf); 1328. Sprintf(buf, " msghistory: %u", flags.msg_history); 1329. putstr(tmpwin, 0, buf); 1330. Sprintf(buf, " name: %s", plname); 1331. putstr(tmpwin, 0, buf); 1332. oc_to_str(flags.inv_order, ocl); 1333. Sprintf(buf, " packorder: %s", ocl); 1334. putstr(tmpwin, 0, buf); 1335. #ifdef CHANGE_COLOR 1336. Sprintf(buf, " palette: %s", get_color_string()); 1337. putstr(tmpwin, 0, buf); 1338. #endif 1339. Sprintf(buf, " pettype: %s", preferred_pet == 'c' ? "cat" : 1340. preferred_pet == 'd' ? "dog" : "random"); 1341. putstr(tmpwin, 0, buf); 1342. oc_to_str(flags.pickup_types, ocl); 1343. Sprintf(buf, " pickup_types: %s", (ocl[0]) ? ocl : "all"); 1344. putstr(tmpwin, 0, buf); 1345. Sprintf(buf, " scores: %d top/%d around%s", 1346. flags.end_top, flags.end_around, 1347. (flags.end_own ? "/own" : "")); 1348. putstr(tmpwin, 0, buf); 1349. #ifdef VIDEOSHADES 1350. Sprintf(buf, " videoshades: %s-%s-%s", 1351. shade[0],shade[1],shade[2]); 1352. putstr(tmpwin, 0, buf); 1353. Sprintf(buf, " videocolors: %d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", 1354. ttycolors[CLR_RED],ttycolors[CLR_GREEN],ttycolors[CLR_BROWN], 1355. ttycolors[CLR_BLUE],ttycolors[CLR_MAGENTA],ttycolors[CLR_CYAN], 1356. ttycolors[CLR_ORANGE],ttycolors[CLR_BRIGHT_GREEN], 1357. ttycolors[CLR_YELLOW],ttycolors[CLR_BRIGHT_BLUE], 1358. ttycolors[CLR_BRIGHT_MAGENTA],ttycolors[CLR_BRIGHT_CYAN]); 1359. putstr(tmpwin, 0, buf); 1360. #endif /* VIDEOSHADES */ 1361. Sprintf(buf, " windowtype: %s", windowprocs.name); 1362. putstr(tmpwin, 0, buf); 1363. display_nhwindow(tmpwin, TRUE); 1364. destroy_nhwindow(tmpwin); 1365. break; 1366. case 's': 1367. clear_nhwindow(WIN_MESSAGE); 1368. getlin("What options do you want to set?", buf); 1369. if(buf[0] == '\033') return 0; 1370. need_redraw = FALSE; 1371. parseoptions(buf, FALSE, FALSE); 1372. if(need_redraw) 1373. (void) doredraw(); 1374. break; 1375. } 1376. 1377. return 0; 1378. } 1379. 1380. int 1381. dotogglepickup() 1382. { 1383. char buf[BUFSZ], ocl[MAXOCLASSES+1]; 1384. 1385. flags.pickup = !flags.pickup; 1386. if (flags.pickup) { 1387. oc_to_str(flags.pickup_types, ocl); 1388. Sprintf(buf, "ON, for %s objects", ocl[0] ? ocl : "all"); 1389. } else { 1390. Strcpy(buf, "OFF"); 1391. } 1392. pline("Autopickup: %s.", buf); 1393. return 0; 1394. } 1395. 1396. /* data for option_help() */ 1397. static const char *opt_intro[] = { 1398. "", 1399. " NetHack Options Help:", 1400. "", 1401. #define CONFIG_SLOT 3 /* fill in next value at run-time */ 1402. (char *)0, 1403. #if !defined(MICRO) && !defined(MAC) 1404. "or use `NETHACKOPTIONS=\"<options>\"' in your environment;", 1405. # ifdef VMS 1406. "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"", 1407. # endif 1408. #endif 1409. "or press \"O\" while playing, and type your <options> at the prompt.", 1410. "In all cases, <options> is a list of options separated by commas.", 1411. "", 1412. "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", 1413. (char *)0 1414. }; 1415. 1416. static const char *opt_epilog[] = { 1417. "", 1418. "Some of the options can be set only before the game is started. You will", 1419. "be so informed, if you attempt to set them while in the game.", 1420. (char *)0 1421. }; 1422. 1423. void 1424. option_help() 1425. { 1426. char buf[BUFSZ], buf2[BUFSZ]; 1427. register int i; 1428. winid datawin; 1429. 1430. datawin = create_nhwindow(NHW_TEXT); 1431. #ifdef AMIGA 1432. if(FromWBench){ 1433. Sprintf(buf,"Set options as OPTIONS= in %s or in icon;",configfile); 1434. } else 1435. #endif 1436. Sprintf(buf, "Set options as OPTIONS=<options> in %s;", configfile); 1437. opt_intro[CONFIG_SLOT] = (const char *) buf; 1438. for (i = 0; opt_intro[i]; i++) 1439. putstr(datawin, 0, opt_intro[i]); 1440. 1441. /* Boolean options */ 1442. for (i = 0; boolopt[i].name; i++) { 1443. if (boolopt[i].addr) 1444. next_opt(datawin, boolopt[i].name); 1445. } 1446. next_opt(datawin, ""); 1447. 1448. /* Compound options */ 1449. putstr(datawin, 0, "Compound options:"); 1450. for (i = 0; compopt[i].name; i++) { 1451. Sprintf(buf2, "`%s'", compopt[i].name); 1452. Sprintf(buf, "%-14s - %s", buf2, compopt[i].descr); 1453. putstr(datawin, 0, buf); 1454. } 1455. 1456. for (i = 0; opt_epilog[i]; i++) 1457. putstr(datawin, 0, opt_epilog[i]); 1458. 1459. display_nhwindow(datawin, FALSE); 1460. destroy_nhwindow(datawin); 1461. return; 1462. } 1463. 1464. /* 1465. * prints the next boolean option, on the same line if possible, on a new 1466. * line if not. End with next_opt(""). 1467. */ 1468. void 1469. next_opt(datawin, str) 1470. winid datawin; 1471. const char *str; 1472. { 1473. static char buf[121]; 1474. int i; 1475. char *s; 1476. 1477. if (!*str) { 1478. for (s = buf; *s; s++); /* find end of string */ 1479. if (s > &buf[1] && s[-2] == ',') 1480. s[-2] = 0; /* strip last ", " */ 1481. i = 121; 1482. } 1483. else 1484. i = strlen(buf) + strlen(str) + 2; 1485. 1486. if (i > COLNO - 2) { /* rule of thumb */ 1487. putstr(datawin, 0, buf); 1488. buf[0] = 0; 1489. } 1490. if (*str) { 1491. Strcat(buf, str); 1492. Strcat(buf, ", "); 1493. } 1494. else 1495. putstr(datawin, 0, str); 1496. return; 1497. } 1498. 1499. /* Returns the fid of the fruit type; if that type already exists, it 1500. * returns the fid of that one; if it does not exist, it adds a new fruit 1501. * type to the chain and returns the new one. 1502. */ 1503. int 1504. fruitadd(str) 1505. char *str; 1506. { 1507. register int i; 1508. register struct fruit *f; 1509. struct fruit *lastf = 0; 1510. int highest_fruit_id = 0; 1511. char buf[PL_FSIZ]; 1512. boolean user_specified = (str == pl_fruit); 1513. /* if not user-specified, then it's a fruit name for a fruit on 1514. * a bones level... 1515. */ 1516. 1517. /* Note: every fruit has an id (spe for fruit objects) of at least 1518. * 1; 0 is an error. 1519. */ 1520. if (user_specified) { 1521. /* disallow naming after other foods (since it'd be impossible 1522. * to tell the difference) 1523. */ 1524. 1525. boolean found = FALSE; 1526. 1527. for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; 1528. i++) { 1529. if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { 1530. found = TRUE; 1531. break; 1532. } 1533. } 1534. if (found || 1535. (!strncmp(str, "tin of ", 7) && 1536. (!strcmp(str+7, "spinach") || 1537. name_to_mon(str+7) >= LOW_PM)) || 1538. !strcmp(str, "empty tin") || 1539. ((!strncmp(eos(str)-6," corpse",7) || 1540. !strncmp(eos(str)-3, " egg",4)) && 1541. name_to_mon(str) >= LOW_PM)) 1542. { 1543. Strcpy(buf, pl_fruit); 1544. Strcpy(pl_fruit, "candied "); 1545. nmcpy(pl_fruit+8, buf, PL_FSIZ-8); 1546. } 1547. } 1548. for(f=ffruit; f; f = f->nextf) { 1549. lastf = f; 1550. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid; 1551. if(!strncmp(str, f->fname, PL_FSIZ)) 1552. goto nonew; 1553. } 1554. /* if adding another fruit would overflow spe, use a random 1555. fruit instead... we've got a lot to choose from. */ 1556. if (highest_fruit_id >= 127) return rnd(127); 1557. highest_fruit_id++; 1558. f = newfruit(); 1559. if (ffruit) lastf->nextf = f; 1560. else ffruit = f; 1561. Strcpy(f->fname, str); 1562. f->fid = highest_fruit_id; 1563. f->nextf = 0; 1564. nonew: 1565. if (user_specified) current_fruit = highest_fruit_id; 1566. return f->fid; 1567. } 1568. 1569. /* 1570. * This is a somewhat generic menu for taking a list of NetHack style 1571. * class choices and presenting them via a description 1572. * rather than the traditional NetHack characters. 1573. * (Benefits users whose first exposure to NetHack is via tiles). 1574. * 1575. * prompt 1576. * The title at the top of the menu. 1577. * 1578. * category: 0 = monster class 1579. * 1 = object class 1580. * 1581. * way 1582. * FALSE = PICK_ONE, TRUE = PICK_ANY 1583. * 1584. * class_list 1585. * a null terminated string containing the list of choices. 1586. * 1587. * class_selection 1588. * a null terminated string containing the selected characters. 1589. * 1590. * Returns number selected (or ESC if aborted). 1591. */ 1592. int 1593. choose_classes_menu(prompt, category, way, class_list, class_select) 1594. const char *prompt; 1595. int category; 1596. boolean way; 1597. char *class_list; 1598. char *class_select; 1599. { 1600. menu_item *pick_list = (menu_item *)0; 1601. winid win; 1602. anything any; 1603. char buf[BUFSZ]; 1604. int i, n; 1605. int ret; 1606. int next_accelerator, accelerator; 1607. 1608. if (class_list == (char *)0 || class_select == (char *)0) return 0; 1609. accelerator = 0; 1610. next_accelerator = 'a'; 1611. any.a_void = 0; 1612. win = create_nhwindow(NHW_MENU); 1613. start_menu(win); 1614. while (*class_list) { 1615. const char *text; 1616. boolean selected; 1617. 1618. text = (char *)0; 1619. selected = FALSE; 1620. switch (category) { 1621. case 0: 1622. text = monexplain[def_char_to_monclass(*class_list)]; 1623. accelerator = *class_list; 1624. Sprintf(buf, "%s", text); 1625. break; 1626. case 1: 1627. text = objexplain[def_char_to_objclass(*class_list)]; 1628. accelerator = next_accelerator; 1629. Sprintf(buf, "%c %s", *class_list, text); 1630. break; 1631. default: 1632. impossible("choose_classes_menu: invalid category %d", 1633. category); 1634. } 1635. if (way && *class_select) { /* Selections there already */ 1636. if (index(class_select, *class_list)) { 1637. selected = TRUE; 1638. } 1639. } 1640. any.a_int = *class_list; 1641. add_menu(win, NO_GLYPH, &any, accelerator, ATR_NONE, buf, selected); 1642. ++class_list; 1643. if (category > 0) { 1644. ++next_accelerator; 1645. if (next_accelerator == ('z' + 1)) next_accelerator = 'A'; 1646. if (next_accelerator == ('Z' + 1)) break; 1647. } 1648. } 1649. end_menu(win, prompt); 1650. n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list); 1651. destroy_nhwindow(win); 1652. if (n > 0) { 1653. for (i = 0; i < n; ++i) { 1654. *class_select++ = (char)pick_list[i].item.a_int; 1655. } 1656. free((genericptr_t)pick_list); 1657. ret = n; 1658. } else if (n == -1) { 1659. class_select = eos(class_select); 1660. ret = -1; 1661. } else 1662. ret = 0; 1663. *class_select = '\0'; 1664. return ret; 1665. } 1666. 1667. #endif /* OPTION_LISTS_ONLY */ 1668. 1669. /*options.c*/