PageRenderTime 70ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/wizard1.c

https://github.com/NickMcConnell/Beleriand
C | 2954 lines | 1948 code | 525 blank | 481 comment | 572 complexity | 02deae2cea7e36ca32cab78fa1531faa MD5 | raw file
  1. /** \file wizard1.c
  2. \brief Spoilers
  3. * Generation of object, artifact, and monster spoilers.
  4. *
  5. * This file has been updated to work with Oangband 0.5.1.
  6. *
  7. * Copyright (c) 1997 Ben Harrison, and others
  8. *
  9. * This work is free software; you can redistribute it and/or modify it
  10. * under the terms of either:
  11. *
  12. * a) the GNU General Public License as published by the Free Software
  13. * Foundation, version 2, or
  14. *
  15. * b) the "Angband licence":
  16. * This software may be copied and distributed for educational, research,
  17. * and not for profit purposes provided that this copyright and statement
  18. * are included in all such copies. Other copyrights may also apply.
  19. */
  20. #include "angband.h"
  21. #include "buildid.h"
  22. #include "cmds.h"
  23. #include "monster.h"
  24. #ifdef ALLOW_SPOILERS
  25. /**
  26. * The spoiler file being created
  27. */
  28. static ang_file *fff = NULL;
  29. /*
  30. * Item Spoilers by Ben Harrison (benh@phial.com)
  31. */
  32. /**
  33. * Describe the kind
  34. */
  35. static void kind_info(char *buf, char *dam, char *wgt, int *lev,
  36. s32b * val, int k)
  37. {
  38. object_kind *k_ptr;
  39. object_type *i_ptr;
  40. object_type object_type_body;
  41. /* Hack */
  42. size_t buf_len = 80;
  43. /* Get local object */
  44. i_ptr = &object_type_body;
  45. /* Prepare a fake item */
  46. object_prep(i_ptr, k, MAXIMISE);
  47. /* Obtain the "kind" info */
  48. k_ptr = &k_info[i_ptr->k_idx];
  49. /* It is known */
  50. i_ptr->ident |= (IDENT_KNOWN);
  51. /* Cancel bonuses */
  52. i_ptr->pval = 0;
  53. i_ptr->to_a = 0;
  54. i_ptr->to_h = 0;
  55. i_ptr->to_d = 0;
  56. /* Level */
  57. (*lev) = k_ptr->level;
  58. /* Value */
  59. (*val) = object_value(i_ptr);
  60. /* Hack */
  61. if (!buf || !dam || !wgt)
  62. return;
  63. /* Description (too brief) */
  64. object_desc(buf, buf_len, i_ptr, ODESC_BASE | ODESC_SPOIL);
  65. /* Misc info */
  66. strcpy(dam, "");
  67. /* Damage */
  68. switch (i_ptr->tval) {
  69. /* Bows */
  70. case TV_BOW:
  71. {
  72. break;
  73. }
  74. /* Ammo */
  75. case TV_SHOT:
  76. case TV_BOLT:
  77. case TV_ARROW:
  78. {
  79. sprintf(dam, "%dd%d", i_ptr->dd, i_ptr->ds);
  80. break;
  81. }
  82. /* Weapons */
  83. case TV_HAFTED:
  84. case TV_POLEARM:
  85. case TV_SWORD:
  86. case TV_DIGGING:
  87. {
  88. sprintf(dam, "%dd%d", i_ptr->dd, i_ptr->ds);
  89. break;
  90. }
  91. /* Armour */
  92. case TV_BOOTS:
  93. case TV_GLOVES:
  94. case TV_CLOAK:
  95. case TV_CROWN:
  96. case TV_HELM:
  97. case TV_SHIELD:
  98. case TV_SOFT_ARMOR:
  99. case TV_HARD_ARMOR:
  100. case TV_DRAG_ARMOR:
  101. {
  102. sprintf(dam, "%d", i_ptr->ac);
  103. break;
  104. }
  105. }
  106. /* Weight */
  107. sprintf(wgt, "%3d.%d", i_ptr->weight / 10, i_ptr->weight % 10);
  108. }
  109. /**
  110. * Create a spoiler file for items
  111. */
  112. static void spoil_obj_desc(const char *fname)
  113. {
  114. int i, k, s, t, n = 0;
  115. u16b who[200];
  116. char buf[1024];
  117. char wgt[80];
  118. char dam[80];
  119. /* Build the filename */
  120. path_build(buf, 1024, ANGBAND_DIR_USER, fname);
  121. /* Open the file */
  122. fff = file_open(buf, MODE_WRITE, FTYPE_TEXT);
  123. /* Oops */
  124. if (!fff) {
  125. msg("Cannot create spoiler file.");
  126. return;
  127. }
  128. /* Header */
  129. file_putf(fff, "Spoiler File -- Basic Items (2.?.?)\n\n\n");
  130. /* More Header */
  131. file_putf(fff, "%-45s %8s%7s%5s%9s\n",
  132. "Description", "Dam/AC", "Wgt", "Lev", "Cost");
  133. file_putf(fff, "%-45s %8s%7s%5s%9s\n",
  134. "----------------------------------------",
  135. "------", "---", "---", "----");
  136. /* List the groups */
  137. for (i = 0; TRUE; i++) {
  138. /* Write out the group title */
  139. if (group_item[i].name) {
  140. /* Hack -- bubble-sort by cost and then level */
  141. for (s = 0; s < n - 1; s++) {
  142. for (t = 0; t < n - 1; t++) {
  143. int i1 = t;
  144. int i2 = t + 1;
  145. int e1;
  146. int e2;
  147. s32b t1;
  148. s32b t2;
  149. kind_info(NULL, NULL, NULL, &e1, &t1, who[i1]);
  150. kind_info(NULL, NULL, NULL, &e2, &t2, who[i2]);
  151. if ((t1 > t2) || ((t1 == t2) && (e1 > e2))) {
  152. int tmp = who[i1];
  153. who[i1] = who[i2];
  154. who[i2] = tmp;
  155. }
  156. }
  157. }
  158. /* Spoil each item */
  159. for (s = 0; s < n; s++) {
  160. int e;
  161. s32b v;
  162. /* Describe the kind */
  163. kind_info(buf, dam, wgt, &e, &v, who[s]);
  164. /* Dump it */
  165. file_putf(fff, " %-45s%8s%7s%5d%9ld\n",
  166. buf, dam, wgt, e, (long) (v));
  167. }
  168. /* Start a new set */
  169. n = 0;
  170. /* Notice the end */
  171. if (!group_item[i].tval)
  172. break;
  173. /* Start a new set */
  174. file_putf(fff, "\n\n%s\n\n", group_item[i].name);
  175. }
  176. /* Acquire legal item types */
  177. for (k = 1; k < z_info->k_max; k++) {
  178. object_kind *k_ptr = &k_info[k];
  179. /* Skip wrong tval's */
  180. if (k_ptr->tval != group_item[i].tval)
  181. continue;
  182. /* Hack -- Skip instant-artifacts */
  183. if (kf_has(k_ptr->flags_kind, KF_INSTA_ART))
  184. continue;
  185. /* Save the index */
  186. who[n++] = k;
  187. }
  188. }
  189. /* Check for errors */
  190. if (!file_close(fff)) {
  191. msg("Cannot close spoiler file.");
  192. return;
  193. }
  194. /* Message */
  195. msg("Successfully created a spoiler file.");
  196. }
  197. /*
  198. * Artifact Spoilers by: randy@PICARD.tamu.edu (Randy Hutson)
  199. */
  200. /**
  201. * Returns a "+" string if a number is non-negative and an empty
  202. * string if negative
  203. */
  204. #define POSITIZE(v) (((v) >= 0) ? "+" : "")
  205. /**
  206. * These are used to format the artifact spoiler file. INDENT1 is used
  207. * to indent all but the first line of an artifact spoiler. INDENT2 is
  208. * used when a line "wraps". (Bladeturner's resistances cause this.)
  209. */
  210. #define INDENT1 " "
  211. #define INDENT2 " "
  212. /**
  213. * MAX_LINE_LEN specifies when a line should wrap.
  214. */
  215. #define MAX_LINE_LEN 75
  216. /**
  217. * The artifacts categorized by type
  218. */
  219. static grouper group_artifact[] = {
  220. {TV_SWORD, "Edged Weapons"},
  221. {TV_POLEARM, "Polearms"},
  222. {TV_HAFTED, "Hafted Weapons"},
  223. {TV_BOW, "Bows"},
  224. {TV_SOFT_ARMOR, "Body Armor"},
  225. {TV_HARD_ARMOR, NULL},
  226. {TV_DRAG_ARMOR, NULL},
  227. {TV_CLOAK, "Cloaks"},
  228. {TV_SHIELD, "Shields"},
  229. {TV_HELM, "Helms/Crowns"},
  230. {TV_CROWN, NULL},
  231. {TV_GLOVES, "Gloves"},
  232. {TV_BOOTS, "Boots"},
  233. {TV_LIGHT, "Light Sources"},
  234. {TV_AMULET, "Amulets"},
  235. {TV_RING, "Rings"},
  236. {0, NULL}
  237. };
  238. /**
  239. * Pair together a constant flag with a textual description.
  240. *
  241. * Used by both "init.c" and "wiz-spo.c".
  242. *
  243. * Note that it sometimes more efficient to actually make an array
  244. * of textual names, where entry 'N' is assumed to be paired with
  245. * the flag whose value is "1L << N", but that requires hard-coding.
  246. */
  247. typedef struct flag_desc flag_desc;
  248. struct flag_desc {
  249. const int flag;
  250. const char *const desc;
  251. };
  252. /**
  253. * These are used for "+3 to STR, DEX", etc. These are separate from
  254. * the other pval affected traits to simplify the case where an object
  255. * affects all stats. In this case, "All stats" is used instead of
  256. * listing each stat individually.
  257. */
  258. const char *stat_desc[] = {
  259. "STR",
  260. "INT",
  261. "WIS",
  262. "DEX",
  263. "CON",
  264. "CHR"
  265. };
  266. /**
  267. * Besides stats, these are the other player traits
  268. * which may be affected by an object's pval
  269. */
  270. const char *bonus_desc[] = {
  271. "Magical Item Skill",
  272. "Stealth",
  273. "Searching",
  274. "Infravision",
  275. "Tunnelling",
  276. "Speed",
  277. "Extra Shots",
  278. "Extra Might"
  279. };
  280. /**
  281. * Slaying preferences for weapons
  282. */
  283. const char *slay_desc[] = {
  284. "Animal",
  285. "Evil",
  286. "Undead",
  287. "Demon",
  288. "Orc",
  289. "Troll",
  290. "Giant",
  291. "Dragon"
  292. };
  293. /**
  294. * Elemental brands for weapons
  295. */
  296. const char *brand_desc[] = {
  297. "Acid Brand",
  298. "Lightning Brand",
  299. "Flame Tongue",
  300. "Frost Brand",
  301. "Poison Brand"
  302. };
  303. /**
  304. * The basic resistances
  305. */
  306. const char *resist_desc[] = {
  307. "Acid",
  308. "Lightning",
  309. "Fire",
  310. "Cold",
  311. "Poison",
  312. "Light",
  313. "Dark",
  314. "Confusion",
  315. "Sound",
  316. "Shards",
  317. "Nexus",
  318. "Nether",
  319. "Chaos",
  320. "Disenchantment"
  321. };
  322. /**
  323. * Sustain stats - these are given their "own" line in the
  324. * spoiler file, mainly for simplicity
  325. */
  326. static const flag_desc sustain_flags_desc[] = {
  327. {OF_SUSTAIN_STR, "STR"},
  328. {OF_SUSTAIN_INT, "INT"},
  329. {OF_SUSTAIN_WIS, "WIS"},
  330. {OF_SUSTAIN_DEX, "DEX"},
  331. {OF_SUSTAIN_CON, "CON"},
  332. {OF_SUSTAIN_CHR, "CHR"},
  333. };
  334. static flag_desc flags_obj_desc[] = {
  335. {OF_THROWING, "Throwing weapon"},
  336. {OF_PERFECT_BALANCE, "Well-balanced"},
  337. {OF_SLOW_DIGEST, "Slow Digestion"},
  338. {OF_FEATHER, "Feather Falling"},
  339. {OF_LIGHT, "Permanent Light"},
  340. {OF_REGEN, "Regeneration"},
  341. {OF_TELEPATHY, "ESP"},
  342. {OF_SEE_INVIS, "See Invisible"},
  343. {OF_FREE_ACT, "Free Action"},
  344. {OF_HOLD_LIFE, "Hold Life"},
  345. {OF_FEARLESS, "Fearlessness"},
  346. {OF_SEEING, "Blindness resistance"},
  347. {OF_BLESSED, "Blessed Blade"},
  348. {OF_IMPACT, "Earthquake impact on hit"},
  349. {OF_PERMA_CURSE, "Permanently cursed"}
  350. };
  351. static flag_desc flags_curse_desc[] = {
  352. {CF_TELEPORT, "Induces random teleportation"},
  353. {CF_NO_TELEPORT, "Prevents teleportation"},
  354. {CF_AGGRO_PERM, "Aggravates"},
  355. {CF_AGGRO_RAND, "Aggravates randomly"},
  356. {CF_SLOW_REGEN, "Slows regeneration"},
  357. {CF_AFRAID, "Causes fear"},
  358. {CF_HUNGRY, "Fast digestion"},
  359. {CF_POIS_RAND, "Randomly poisons"},
  360. {CF_POIS_RAND_BAD, "Releases toxic clouds"},
  361. {CF_CUT_RAND, "Randomly cuts"},
  362. {CF_CUT_RAND_BAD, "Causes serious wounds"},
  363. {CF_HALLU_RAND, "Induces hallucination"},
  364. {CF_DROP_WEAPON, "Drops randomly"},
  365. {CF_ATTRACT_DEMON, "Summons demons"},
  366. {CF_ATTRACT_UNDEAD, "Calls undead"},
  367. {CF_STICKY_CARRY, "Cannot be removed"},
  368. {CF_STICKY_WIELD, "Cannot be dropped"},
  369. {CF_PARALYZE, "Paralyzes"},
  370. {CF_PARALYZE_ALL, "Paralyzes unresistably"},
  371. {CF_DRAIN_EXP, "Drains experience"},
  372. {CF_DRAIN_MANA, "Drains mana"},
  373. {CF_DRAIN_STAT, "Drains random stats"},
  374. {CF_DRAIN_CHARGE, "Drains magic devices"},
  375. };
  376. /**
  377. * An "object analysis structure"
  378. *
  379. * It will be filled with descriptive strings detailing an object's
  380. * various magical powers. The "ignore X" traits are not noted since
  381. * all artifacts ignore "normal" destruction.
  382. */
  383. typedef struct {
  384. /* "The Longsword Dragonsmiter (6d4) (+20, +25)" */
  385. char description[160];
  386. /* A list of stat boosts granted by an object */
  387. const char *stats[N_ELEMENTS(stat_desc) + 1];
  388. /* A list of other bonuses granted by an object */
  389. const char *bonus[N_ELEMENTS(bonus_desc) + 1];
  390. /* A list of an object's slaying preferences */
  391. const char *slays[N_ELEMENTS(slay_desc) + 1];
  392. /* A list if an object's elemental brands */
  393. const char *brands[N_ELEMENTS(brand_desc) + 1];
  394. /* A list of resistances granted by an object */
  395. const char *resistances[N_ELEMENTS(resist_desc) + 1];
  396. /* A list of stats sustained by an object */
  397. const char *sustains[N_ELEMENTS(sustain_flags_desc) - 1 + 1];
  398. /* A list of various magical qualities an object may have */
  399. const char *powers[N_ELEMENTS(flags_obj_desc) + 1];
  400. /* A list of various curses an object may have */
  401. const char *curses[N_ELEMENTS(flags_curse_desc) + 1 + 1];
  402. /* A string describing an artifact's activation */
  403. const char *activation;
  404. /* "Level 20, Rarity 30, 3.0 lbs, 20000 Gold" */
  405. char misc_desc[80];
  406. } obj_desc_list;
  407. /**
  408. * Write out `n' of the character `c' to the spoiler file
  409. */
  410. static void spoiler_out_n_chars(int n, char c)
  411. {
  412. while (--n >= 0)
  413. fputc(c, (FILE *) fff);
  414. }
  415. /**
  416. * Write out `n' blank lines to the spoiler file
  417. */
  418. static void spoiler_blanklines(int n)
  419. {
  420. spoiler_out_n_chars(n, '\n');
  421. }
  422. /**
  423. * Write a line to the spoiler file and then "underline" it with hypens
  424. */
  425. static void spoiler_underline(const char *str)
  426. {
  427. file_putf(fff, "%s\n", str);
  428. spoiler_out_n_chars(strlen(str), '-');
  429. file_putf(fff, "\n");
  430. }
  431. /**
  432. * These functions do most of the actual "analysis". Given a set of bit flags
  433. * (which will be from one of the flags fields from the object in question),
  434. * or directly the integer fields of the object
  435. * a "flag description structure", a "description list", and the number of
  436. * elements in the "flag description structure", or directly the integer
  437. * fields of the object, these functions set the "description list" members to
  438. * the appropriate descriptions.
  439. *
  440. * The possibly updated description pointer is returned.
  441. */
  442. static const char **spoiler_flag_aux(const bitflag * art_flags,
  443. const flag_desc * flag_x_ptr,
  444. const char **desc_x_ptr,
  445. const int n_elmnts)
  446. {
  447. int i;
  448. for (i = 0; i < n_elmnts; ++i) {
  449. if (of_has(art_flags, flag_x_ptr[i].flag)) {
  450. *desc_x_ptr++ = flag_x_ptr[i].desc;
  451. }
  452. }
  453. return desc_x_ptr;
  454. }
  455. static const char **spoiler_int_aux(const int *values, const int base,
  456. const char **desc,
  457. const char **desc_x_ptr,
  458. const int n_elmnts)
  459. {
  460. int i;
  461. for (i = 0; i < n_elmnts; ++i) {
  462. if (values[i] != base) {
  463. int value = (base == 0 ? values[i] : base - values[i]);
  464. *desc_x_ptr++ = format("%s%d%s%s", POSITIZE(value), value,
  465. (base == 0 ? " " : "% "), desc[i]);
  466. }
  467. }
  468. return desc_x_ptr;
  469. }
  470. static const char **spoiler_frac_aux(const int *values, const int base,
  471. const char **desc,
  472. const char **desc_x_ptr,
  473. const int n_elmnts)
  474. {
  475. int i;
  476. for (i = 0; i < n_elmnts; ++i) {
  477. if (values[i] != base) {
  478. *desc_x_ptr++ = format("x%d/%d %s", values[i], base, desc[i]);
  479. }
  480. }
  481. return desc_x_ptr;
  482. }
  483. /**
  484. * Acquire a "basic" description "The Cloak of Death [1,+10]"
  485. */
  486. static void analyze_general(object_type * o_ptr, char *desc_x_ptr)
  487. {
  488. /* Get a "useful" description of the object */
  489. object_desc(desc_x_ptr, sizeof(desc_x_ptr), o_ptr,
  490. ODESC_PREFIX | ODESC_COMBAT | ODESC_SPOIL);
  491. }
  492. /**
  493. * List stat bonuses.
  494. */
  495. static void analyze_stats(object_type * o_ptr, const char **stat_list)
  496. {
  497. /* Are any stats affected? */
  498. stat_list = spoiler_int_aux(o_ptr->bonus_stat, 0, stat_desc,
  499. stat_list, N_ELEMENTS(stat_desc));
  500. /* Terminate the description list */
  501. *stat_list = NULL;
  502. }
  503. /**
  504. * List other bonuses.
  505. */
  506. static void analyze_bonus(object_type * o_ptr, const char **bonus_list)
  507. {
  508. /* Are any stats affected? */
  509. bonus_list = spoiler_int_aux(o_ptr->bonus_other, 0, bonus_desc,
  510. bonus_list, N_ELEMENTS(bonus_desc));
  511. /* Terminate the description list */
  512. *bonus_list = NULL;
  513. }
  514. /**
  515. * Note the slaying specialties of a weapon
  516. */
  517. static void analyze_slay(object_type * o_ptr, const char **slay_list)
  518. {
  519. slay_list =
  520. spoiler_frac_aux(o_ptr->multiple_slay, MULTIPLE_BASE, slay_desc,
  521. slay_list, N_ELEMENTS(slay_desc));
  522. /* Terminate the description list */
  523. *slay_list = NULL;
  524. }
  525. /**
  526. * Note an object's elemental brands
  527. */
  528. static void analyze_brand(object_type * o_ptr, const char **brand_list)
  529. {
  530. brand_list = spoiler_frac_aux(o_ptr->multiple_brand, MULTIPLE_BASE,
  531. brand_desc, brand_list,
  532. N_ELEMENTS(brand_desc));
  533. /* Terminate the description list */
  534. *brand_list = NULL;
  535. }
  536. /**
  537. * Note the resistances granted by an object
  538. */
  539. static void analyze_resist(object_type * o_ptr, const char **resist_list)
  540. {
  541. resist_list =
  542. spoiler_int_aux(o_ptr->percent_res, RES_LEVEL_BASE, resist_desc,
  543. resist_list, N_ELEMENTS(resist_desc));
  544. /* Terminate the description list */
  545. *resist_list = NULL;
  546. }
  547. /**
  548. * Note which stats an object sustains
  549. */
  550. static void analyze_sustains(object_type * o_ptr,
  551. const char **sustain_list)
  552. {
  553. bitflag all_sustains[OF_SIZE];
  554. of_wipe(all_sustains);
  555. of_on(all_sustains, OF_SUSTAIN_STR);
  556. of_on(all_sustains, OF_SUSTAIN_INT);
  557. of_on(all_sustains, OF_SUSTAIN_WIS);
  558. of_on(all_sustains, OF_SUSTAIN_DEX);
  559. of_on(all_sustains, OF_SUSTAIN_CON);
  560. of_on(all_sustains, OF_SUSTAIN_CHR);
  561. /* Simplify things if an item sustains all stats */
  562. if (of_is_subset(o_ptr->flags_obj, all_sustains)) {
  563. *sustain_list++ = "All stats";
  564. }
  565. /* Should we bother? */
  566. else if (of_is_inter(o_ptr->flags_obj, all_sustains)) {
  567. sustain_list =
  568. spoiler_flag_aux(o_ptr->flags_obj, sustain_flags_desc,
  569. sustain_list, N_ELEMENTS(sustain_flags_desc));
  570. }
  571. /* Terminate the description list */
  572. *sustain_list = NULL;
  573. }
  574. /**
  575. * Note miscellaneous powers bestowed by an artifact such as see invisible,
  576. * free action, permanent light, etc.
  577. */
  578. static void analyze_powers(object_type * o_ptr, const char **power_list)
  579. {
  580. /* Hack - put perma curse in with curses */
  581. bitflag flags[OF_SIZE];
  582. of_copy(flags, o_ptr->flags_obj);
  583. of_off(flags, OF_PERMA_CURSE);
  584. /*
  585. * Special flags
  586. */
  587. power_list = spoiler_flag_aux(flags, flags_obj_desc, power_list,
  588. N_ELEMENTS(flags_obj_desc));
  589. /*
  590. * Artifact lights -- large radius light.
  591. */
  592. if ((o_ptr->tval == TV_LIGHT) && artifact_p(o_ptr)) {
  593. *power_list++ = "Permanent Light(3)";
  594. }
  595. /* Terminate the description list */
  596. *power_list = NULL;
  597. }
  598. /**
  599. * Note artifact curses
  600. */
  601. static void analyze_curses(object_type * o_ptr, const char **curse_list)
  602. {
  603. /*
  604. * Special flags
  605. */
  606. curse_list = spoiler_flag_aux(o_ptr->flags_curse, flags_curse_desc,
  607. curse_list,
  608. N_ELEMENTS(flags_curse_desc));
  609. /*
  610. * Artifact lights -- large radius light.
  611. */
  612. if (of_has(o_ptr->flags_obj, OF_PERMA_CURSE)) {
  613. *curse_list++ = "Permanently cursed";
  614. }
  615. /* Terminate the description list */
  616. *curse_list = NULL;
  617. }
  618. /**
  619. * Determine the minimum depth an artifact can appear, its rarity, its weight,
  620. * and its value in gold pieces
  621. */
  622. static void analyze_misc(object_type * o_ptr, char *misc_desc)
  623. {
  624. artifact_type *a_ptr = &a_info[o_ptr->name1];
  625. sprintf(misc_desc, "Level %u, Rarity %u, %d.%d lbs, %ld Gold",
  626. a_ptr->level, a_ptr->rarity, a_ptr->weight / 10,
  627. a_ptr->weight % 10, (long) a_ptr->cost);
  628. }
  629. /**
  630. * Fill in an object description structure for a given object
  631. */
  632. static void object_analyze(object_type * o_ptr, obj_desc_list * desc_x_ptr)
  633. {
  634. artifact_type *a_ptr = &a_info[o_ptr->name1];
  635. /* Oangband requires that activations be transferred to the object. */
  636. if (a_ptr->effect) {
  637. o_ptr->effect = a_ptr->effect;
  638. }
  639. analyze_general(o_ptr, desc_x_ptr->description);
  640. analyze_stats(o_ptr, desc_x_ptr->stats);
  641. analyze_bonus(o_ptr, desc_x_ptr->bonus);
  642. analyze_brand(o_ptr, desc_x_ptr->brands);
  643. analyze_slay(o_ptr, desc_x_ptr->slays);
  644. analyze_resist(o_ptr, desc_x_ptr->resistances);
  645. analyze_sustains(o_ptr, desc_x_ptr->sustains);
  646. analyze_powers(o_ptr, desc_x_ptr->powers);
  647. analyze_curses(o_ptr, desc_x_ptr->curses);
  648. analyze_misc(o_ptr, desc_x_ptr->misc_desc);
  649. }
  650. static void print_header(void)
  651. {
  652. char buf[80];
  653. sprintf(buf, "Artifact Spoilers for Beleriand Version %d.%d.%d",
  654. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  655. spoiler_underline(buf);
  656. }
  657. /*
  658. * This is somewhat ugly.
  659. *
  660. * Given a header ("Resist", e.g.), a list ("Fire", "Cold", Acid", e.g.),
  661. * and a separator character (',', e.g.), write the list to the spoiler file
  662. * in a "nice" format, such as:
  663. *
  664. * Resist Fire, Cold, Acid
  665. *
  666. * That was a simple example, but when the list is long, a line wrap
  667. * should occur, and this should induce a new level of indention if
  668. * a list is being spread across lines. So for example, Bladeturner's
  669. * list of resistances should look something like this
  670. *
  671. * Resist Acid, Lightning, Fire, Cold, Poison, Light, Dark, Blindness,
  672. * Confusion, Sound, Shards, Nether, Nexus, Chaos, Disenchantment
  673. *
  674. * However, the code distinguishes between a single list of many items vs.
  675. * many lists. (The separator is used to make this determination.) A single
  676. * list of many items will not cause line wrapping (since there is no
  677. * apparent reason to do so). So the lists of Ulmo's miscellaneous traits
  678. * might look like this:
  679. *
  680. * Free Action; Hold Life; See Invisible; Slow Digestion; Regeneration
  681. * Blessed Blade
  682. *
  683. * So comparing the two, "Regeneration" has no trailing separator and
  684. * "Blessed Blade" was not indented. (Also, Ulmo's lists have no headers,
  685. * but that's not relevant to line wrapping and indention.)
  686. */
  687. /**
  688. * ITEM_SEP separates items within a list
  689. */
  690. #define ITEM_SEP ','
  691. /**
  692. * LIST_SEP separates lists
  693. */
  694. #define LIST_SEP ';'
  695. static void spoiler_outlist(const char *header, const char **list,
  696. char separator)
  697. {
  698. int line_len, buf_len;
  699. char line[MAX_LINE_LEN + 1], buf[80];
  700. /* Ignore an empty list */
  701. if (*list == NULL)
  702. return;
  703. /* This function always indents */
  704. strcpy(line, INDENT1);
  705. /* Create header (if one was given) */
  706. if (header && (header[0])) {
  707. strcat(line, header);
  708. strcat(line, " ");
  709. }
  710. line_len = strlen(line);
  711. /* Now begin the tedious task */
  712. while (1) {
  713. /* Copy the current item to a buffer */
  714. strcpy(buf, *list);
  715. /* Note the buffer's length */
  716. buf_len = strlen(buf);
  717. /*
  718. * If there is an item following this one, pad with separator and
  719. * a space and adjust the buffer length
  720. */
  721. if (list[1]) {
  722. sprintf(buf + buf_len, "%c ", separator);
  723. buf_len += 2;
  724. }
  725. /*
  726. * If the buffer will fit on the current line, just append the
  727. * buffer to the line and adjust the line length accordingly.
  728. */
  729. if (line_len + buf_len <= MAX_LINE_LEN) {
  730. strcat(line, buf);
  731. line_len += buf_len;
  732. }
  733. /* Apply line wrapping and indention semantics described above */
  734. else {
  735. /*
  736. * Don't print a trailing list separator but do print a trailing
  737. * item separator.
  738. */
  739. if (line_len > 1 && line[line_len - 1] == ' '
  740. && line[line_len - 2] == LIST_SEP) {
  741. /* Ignore space and separator */
  742. line[line_len - 2] = '\0';
  743. /* Write to spoiler file */
  744. file_putf(fff, "%s\n", line);
  745. /* Begin new line at primary indention level */
  746. sprintf(line, "%s%s", INDENT1, buf);
  747. }
  748. else {
  749. /* Write to spoiler file */
  750. file_putf(fff, "%s\n", line);
  751. /* Begin new line at secondary indention level */
  752. sprintf(line, "%s%s", INDENT2, buf);
  753. }
  754. line_len = strlen(line);
  755. }
  756. /* Advance, with break */
  757. if (!*++list)
  758. break;
  759. }
  760. /* Write what's left to the spoiler file */
  761. file_putf(fff, "%s\n", line);
  762. }
  763. /**
  764. * Create a spoiler file entry for an artifact
  765. */
  766. static void spoiler_print_art(obj_desc_list * art_ptr)
  767. {
  768. /* Don't indent the first line */
  769. file_putf(fff, "%s\n", art_ptr->description);
  770. /* Now deal with the description lists */
  771. spoiler_outlist("", art_ptr->stats, ITEM_SEP);
  772. spoiler_outlist("", art_ptr->bonus, ITEM_SEP);
  773. spoiler_outlist("Slay", art_ptr->slays, ITEM_SEP);
  774. spoiler_outlist("", art_ptr->brands, LIST_SEP);
  775. spoiler_outlist("Resist", art_ptr->resistances, ITEM_SEP);
  776. spoiler_outlist("Sustain", art_ptr->sustains, ITEM_SEP);
  777. spoiler_outlist("", art_ptr->powers, LIST_SEP);
  778. spoiler_outlist("", art_ptr->curses, LIST_SEP);
  779. /* Write out the possible activation at the primary indention level */
  780. if (art_ptr->activation) {
  781. file_putf(fff, "%sActivates for %s\n", INDENT1,
  782. art_ptr->activation);
  783. }
  784. /* End with the miscellaneous facts */
  785. file_putf(fff, "%s%s\n\n", INDENT1, art_ptr->misc_desc);
  786. }
  787. /**
  788. * Hack -- Create a "forged" artifact
  789. */
  790. bool make_fake_artifact(object_type * o_ptr, int name1)
  791. {
  792. int i;
  793. artifact_type *a_ptr = &a_info[name1];
  794. /* Ignore "empty" artifacts */
  795. if (!a_ptr->name)
  796. return FALSE;
  797. /* Acquire the "kind" index */
  798. i = lookup_kind(a_ptr->tval, a_ptr->sval);
  799. /* Oops */
  800. if (!i)
  801. return (FALSE);
  802. /* Create the artifact */
  803. object_prep(o_ptr, i, MAXIMISE);
  804. /* Save the name */
  805. o_ptr->name1 = name1;
  806. /* Extract the fields */
  807. o_ptr->pval = a_ptr->pval;
  808. o_ptr->ac = a_ptr->ac;
  809. o_ptr->dd = a_ptr->dd;
  810. o_ptr->ds = a_ptr->ds;
  811. o_ptr->to_a = a_ptr->to_a;
  812. o_ptr->to_h = a_ptr->to_h;
  813. o_ptr->to_d = a_ptr->to_d;
  814. o_ptr->weight = a_ptr->weight;
  815. for (i = 0; i < MAX_P_RES; i++)
  816. o_ptr->percent_res[i] = a_ptr->percent_res[i];
  817. for (i = 0; i < A_MAX; i++)
  818. o_ptr->bonus_stat[i] = a_ptr->bonus_stat[i];
  819. for (i = 0; i < MAX_P_BONUS; i++)
  820. o_ptr->bonus_other[i] = a_ptr->bonus_other[i];
  821. for (i = 0; i < MAX_P_SLAY; i++)
  822. o_ptr->multiple_slay[i] = a_ptr->multiple_slay[i];
  823. for (i = 0; i < MAX_P_BRAND; i++)
  824. o_ptr->multiple_brand[i] = a_ptr->multiple_brand[i];
  825. of_copy(o_ptr->flags_obj, a_ptr->flags_obj);
  826. cf_copy(o_ptr->flags_curse, a_ptr->flags_curse);
  827. /* Transfer the activation information. */
  828. if (a_ptr->effect) {
  829. o_ptr->effect = a_ptr->effect;
  830. }
  831. /* Success */
  832. return (TRUE);
  833. }
  834. /**
  835. * Show what object kinds appear on the current level
  836. */
  837. static void spoil_obj_gen(const char *fname)
  838. {
  839. int i;
  840. /* Storage */
  841. u32b artifacts = 0L;
  842. u32b egoitems = 0L;
  843. u32b *object = malloc(z_info->k_max * sizeof(*object));
  844. u32b depth[MAX_DEPTH];
  845. object_type *i_ptr;
  846. object_type object_type_body;
  847. char o_name[120];
  848. char buf[1024];
  849. /* Build the filename */
  850. path_build(buf, 1024, ANGBAND_DIR_USER, fname);
  851. /* Open the file */
  852. fff = file_open(buf, MODE_WRITE, FTYPE_TEXT);
  853. /* Oops */
  854. if (!fff) {
  855. msg("Cannot create spoiler file.");
  856. free(object);
  857. return;
  858. }
  859. msg("This may take a while...");
  860. file_putf(fff,
  861. "Object Generation Spoiler for Beleriand Version %d.%d.%d\n",
  862. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  863. /* Clear storage. */
  864. for (i = 0; i < z_info->k_max; i++) {
  865. object[i] = 0L;
  866. }
  867. /* Clear storage. */
  868. for (i = 0; i < MAX_DEPTH; i++) {
  869. depth[i] = 0L;
  870. }
  871. /* Make a lot of objects, and print their names out. */
  872. for (i = 0L; i < 1000000L; i++) {
  873. if (i % 10000 == 0) {
  874. prt(format("%ld objects created", (long) i), 0, 0);
  875. }
  876. /* Get local object */
  877. i_ptr = &object_type_body;
  878. /* Wipe the object */
  879. object_wipe(i_ptr);
  880. /* Create an object - no special conditions */
  881. make_object(i_ptr, FALSE, FALSE, FALSE);
  882. /* Count artifacts. */
  883. if (i_ptr->name1)
  884. artifacts += 1L;
  885. /* Count ego-items. */
  886. if (i_ptr->name2)
  887. egoitems += 1L;
  888. /* Count object kinds. */
  889. object[i_ptr->k_idx] += 1L;
  890. /* Count objects of that level. */
  891. depth[k_info[i_ptr->k_idx].level] += 1L;
  892. /* Mega-Hack -- allow multiple artifacts XXX XXX XXX */
  893. if (artifact_p(i_ptr))
  894. a_info[i_ptr->name1].created = FALSE;
  895. }
  896. /* Print to file. */
  897. file_putf(fff, "\n\n\n");
  898. file_putf(fff, "artifacts: %ld\n", (long) artifacts);
  899. file_putf(fff, "ego-items: %ld\n", (long) egoitems);
  900. file_putf(fff, "\n\n");
  901. file_putf(fff, "Number of objects created (1,000,000 total)\n");
  902. file_putf(fff, " Generation Level: %d\n\n", p_ptr->danger);
  903. for (i = 1; i < z_info->k_max; i++) {
  904. if (object[i]) {
  905. object_kind *k_ptr = &k_info[i];
  906. char *t;
  907. const char *str = k_ptr->name;
  908. if (strlen(str) == 0)
  909. continue;
  910. /* Skip past leading characters */
  911. while ((*str == ' ') || (*str == '&'))
  912. str++;
  913. /* Copy useful chars */
  914. for (t = o_name; *str; str++) {
  915. if (*str != '~')
  916. *t++ = *str;
  917. }
  918. /* Terminate the new name */
  919. *t = '\0';
  920. file_putf(fff, "%-40s:%6ld\n", o_name, (long) object[i]);
  921. }
  922. }
  923. file_putf(fff, "\n\n\n");
  924. file_putf(fff, "Object distribution by depth\n\n");
  925. for (i = 0; i < MAX_DEPTH; i++) {
  926. if (depth[i])
  927. file_putf(fff, "Level %3d:%6ld\n", i, (long) depth[i]);
  928. }
  929. free(object);
  930. /* Check for errors */
  931. if (!file_close(fff)) {
  932. msg("Cannot close spoiler file.");
  933. return;
  934. }
  935. /* Message */
  936. msg("Successfully created a spoiler file.");
  937. }
  938. /**
  939. * Show what monster races appear on the current level
  940. */
  941. static void spoil_mon_gen(const char *fname)
  942. {
  943. int i, num;
  944. struct keypress key;
  945. /* Storage */
  946. u32b *monster = malloc(z_info->r_max * sizeof(*monster));
  947. u32b depth[MAX_DEPTH];
  948. bool quick;
  949. char buf[1024];
  950. /* Build the filename */
  951. path_build(buf, 1024, ANGBAND_DIR_USER, fname);
  952. /* Open the file */
  953. fff = file_open(buf, MODE_WRITE, FTYPE_TEXT);
  954. /* Oops */
  955. if (!fff) {
  956. msg("Cannot create spoiler file.");
  957. free(monster);
  958. return;
  959. }
  960. file_putf(fff,
  961. "Monster Generation Spoiler for Beleriand Version %d.%d.%d\n",
  962. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  963. /* Clear storage. */
  964. for (i = 0; i < z_info->r_max; i++) {
  965. monster[i] = 0L;
  966. }
  967. /* Clear storage. */
  968. for (i = 0; i < MAX_DEPTH; i++) {
  969. depth[i] = 0L;
  970. }
  971. /* Clear screen */
  972. Term_clear();
  973. /* Info */
  974. prt("Use the quick monster generator?.", 2, 5);
  975. /* Prompt for a monster selection method */
  976. prt("Monster generation uses a three-level table: The base probability, ", 5, 5);
  977. prt("gotten from r_info.txt, the modified probability as adjusted by , ", 6, 5);
  978. prt("special monster restrictions (like only dragons), and the final , ", 7, 5);
  979. prt("probability, which depends on values in the first two levels plus , ", 8, 5);
  980. prt("the current generation depth. , ", 9, 5);
  981. prt("The quick monster generator builds the third probability level only ,", 11, 5);
  982. prt("once, and then draws monsters from it. The standard method is to , ", 12, 5);
  983. prt("rebuild the third probability level for each monster", 13, 5);
  984. /* Prompt */
  985. prt("Command: ", 15, 0);
  986. /* Get a choice */
  987. key = inkey();
  988. i = key.code;
  989. if (i == 'y')
  990. quick = TRUE;
  991. else
  992. quick = FALSE;
  993. msg("This may take a while...");
  994. /* Initialize monster generation. */
  995. if (quick)
  996. (void) get_mon_num(p_ptr->danger);
  997. /* Make a lot of monsters, and print their names out. */
  998. for (i = 0L; i < 1000000L; i++) {
  999. if (i % 10000 == 0) {
  1000. prt(format("%ld monsters created", (long) i), 0, 0);
  1001. }
  1002. /* Get a monster index */
  1003. if (quick)
  1004. num = get_mon_num_quick(p_ptr->danger);
  1005. else
  1006. num = get_mon_num(p_ptr->danger);
  1007. /* Count monster races. */
  1008. monster[num] += 1L;
  1009. /* Count monsters of that level. */
  1010. depth[r_info[num].level] += 1L;
  1011. }
  1012. /* Print to file. */
  1013. file_putf(fff, "\n\n\n");
  1014. file_putf(fff,
  1015. "Number of monsters of various kinds (1,000,000 total)\n");
  1016. file_putf(fff, " Generation Level: %d\n\n", p_ptr->danger);
  1017. for (i = 1; i < z_info->r_max; i++) {
  1018. monster_race *r_ptr = &r_info[i];
  1019. const char *name = r_ptr->name;
  1020. if (monster[i]) {
  1021. file_putf(fff, "%-45s:%6ld\n", name, (long) monster[i]);
  1022. }
  1023. }
  1024. file_putf(fff, "\n\n\n");
  1025. file_putf(fff, "Monster distribution by depth\n\n");
  1026. for (i = 0; i < MAX_DEPTH; i++) {
  1027. if (depth[i])
  1028. file_putf(fff, "Level %3d:%6ld\n", i, (long) depth[i]);
  1029. }
  1030. free(monster);
  1031. /* Check for errors */
  1032. if (!file_close(fff)) {
  1033. msg("Cannot close spoiler file.");
  1034. return;
  1035. }
  1036. /* Message */
  1037. msg("Successfully created a spoiler file.");
  1038. }
  1039. /**
  1040. * Create a spoiler file for artifacts
  1041. */
  1042. static void spoil_artifact(const char *fname)
  1043. {
  1044. int i, j;
  1045. object_type *i_ptr;
  1046. object_type object_type_body;
  1047. obj_desc_list artifact;
  1048. char buf[1024];
  1049. /* Build the filename */
  1050. path_build(buf, 1024, ANGBAND_DIR_USER, fname);
  1051. /* Open the file */
  1052. fff = file_open(buf, MODE_WRITE, FTYPE_TEXT);
  1053. /* Oops */
  1054. if (!fff) {
  1055. msg("Cannot create spoiler file.");
  1056. return;
  1057. }
  1058. /* Dump the header */
  1059. print_header();
  1060. /* List the artifacts by tval */
  1061. for (i = 0; group_artifact[i].tval; i++) {
  1062. /* Write out the group title */
  1063. if (group_artifact[i].name) {
  1064. spoiler_blanklines(2);
  1065. spoiler_underline(group_artifact[i].name);
  1066. spoiler_blanklines(1);
  1067. }
  1068. /* Now search through all of the artifacts */
  1069. for (j = 1; j < z_info->a_max; ++j) {
  1070. artifact_type *a_ptr = &a_info[j];
  1071. /* We only want objects in the current group */
  1072. if (a_ptr->tval != group_artifact[i].tval)
  1073. continue;
  1074. /* Get local object */
  1075. i_ptr = &object_type_body;
  1076. /* Wipe the object */
  1077. object_wipe(i_ptr);
  1078. /* Attempt to "forge" the artifact */
  1079. if (!make_fake_artifact(i_ptr, j))
  1080. continue;
  1081. /* Analyze the artifact */
  1082. object_analyze(i_ptr, &artifact);
  1083. /* Write out the artifact description to the spoiler file */
  1084. spoiler_print_art(&artifact);
  1085. }
  1086. }
  1087. /* Check for errors */
  1088. if (!file_close(fff)) {
  1089. msg("Cannot close spoiler file.");
  1090. return;
  1091. }
  1092. /* Message */
  1093. msg("Successfully created a spoiler file.");
  1094. }
  1095. /**
  1096. * Create a spoiler file for monsters
  1097. */
  1098. static void spoil_mon_desc(const char *fname)
  1099. {
  1100. int i, n = 0;
  1101. char buf[1024];
  1102. char nam[80];
  1103. char lev[80];
  1104. char rar[80];
  1105. char spd[80];
  1106. char ac[80];
  1107. char hp[80];
  1108. char exp[80];
  1109. u16b *who;
  1110. /* Build the filename */
  1111. path_build(buf, 1024, ANGBAND_DIR_USER, fname);
  1112. /* Open the file */
  1113. fff = file_open(buf, MODE_WRITE, FTYPE_TEXT);
  1114. /* Oops */
  1115. if (!fff) {
  1116. msg("Cannot create spoiler file.");
  1117. return;
  1118. }
  1119. /* Dump the header */
  1120. file_putf(fff, "Monster Spoilers for Beleriand Version %d.%d.%d\n",
  1121. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  1122. file_putf(fff, "------------------------------------------\n\n");
  1123. /* Dump the header */
  1124. file_putf(fff, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n",
  1125. "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
  1126. file_putf(fff, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n",
  1127. "----", "---", "---", "---", "--", "--", "-----------");
  1128. /* Allocate the "who" array */
  1129. who = C_ZNEW(z_info->r_max, u16b);
  1130. /* Scan the monsters */
  1131. for (i = 1; i < z_info->r_max; i++) {
  1132. monster_race *r_ptr = &r_info[i];
  1133. /* Use that monster */
  1134. if (r_ptr->name)
  1135. who[n++] = i;
  1136. }
  1137. /* Sort the array by dungeon depth of monsters */
  1138. sort(who, n, sizeof(*who), cmp_monsters);
  1139. /* Scan again */
  1140. for (i = 0; i < n; i++) {
  1141. monster_race *r_ptr = &r_info[who[i]];
  1142. const char *name = r_ptr->name;
  1143. /* Get the "name" */
  1144. if (rf_has(r_ptr->flags, RF_QUESTOR)) {
  1145. sprintf(nam, "[Q] %s", name);
  1146. } else if (rf_has(r_ptr->flags, RF_UNIQUE)) {
  1147. sprintf(nam, "[U] %s", name);
  1148. } else {
  1149. sprintf(nam, "The %s", name);
  1150. }
  1151. /* Level */
  1152. sprintf(lev, "%d", r_ptr->level);
  1153. /* Rarity */
  1154. sprintf(rar, "%d", r_ptr->rarity);
  1155. /* Speed */
  1156. if (r_ptr->speed >= 110) {
  1157. sprintf(spd, "+%d", (r_ptr->speed - 110));
  1158. } else {
  1159. sprintf(spd, "-%d", (110 - r_ptr->speed));
  1160. }
  1161. /* Armor Class */
  1162. sprintf(ac, "%d", r_ptr->ac);
  1163. /* Hitpoints */
  1164. if ((rf_has(r_ptr->flags, RF_FORCE_MAXHP)) || (r_ptr->hside == 1)) {
  1165. sprintf(hp, "%d", r_ptr->hdice * r_ptr->hside);
  1166. } else {
  1167. sprintf(hp, "%dd%d", r_ptr->hdice, r_ptr->hside);
  1168. }
  1169. /* Experience */
  1170. sprintf(exp, "%ld", (long) (r_ptr->mexp));
  1171. /* Hack -- use visual instead */
  1172. sprintf(exp, "%s '%c'", attr_to_text(r_ptr->d_attr),
  1173. r_ptr->d_char);
  1174. /* Dump the info */
  1175. file_putf(fff, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n",
  1176. nam, lev, rar, spd, hp, ac, exp);
  1177. }
  1178. /* End it */
  1179. file_putf(fff, "\n");
  1180. /* Free the "who" array */
  1181. FREE(who);
  1182. /* Check for errors */
  1183. if (!file_close(fff)) {
  1184. msg("Cannot close spoiler file.");
  1185. return;
  1186. }
  1187. /* Worked */
  1188. msg("Successfully created a spoiler file.");
  1189. }
  1190. /*
  1191. * Monster spoilers by: smchorse@ringer.cs.utsa.edu (Shawn McHorse)
  1192. *
  1193. * Adapted from the "monster_desc()" code in "monster1.c"
  1194. */
  1195. /**
  1196. * Pronoun array
  1197. */
  1198. static const char *wd_che[3] = { "It", "He", "She" };
  1199. /**
  1200. * Pronoun array
  1201. */
  1202. static const char *wd_lhe[3] = { "it", "he", "she" };
  1203. /**
  1204. * Buffer text to the given file. (-SHAWN-)
  1205. * This is basically c_roff() from util.c with a few changes.
  1206. */
  1207. static void spoil_out(const char *str)
  1208. {
  1209. const char *r;
  1210. /* Line buffer */
  1211. static char roff_buf[256];
  1212. /* Current pointer into line roff_buf */
  1213. static char *roff_p = roff_buf;
  1214. /* Last space saved into roff_buf */
  1215. static char *roff_s = NULL;
  1216. /* Special handling for "new sequence" */
  1217. if (!str) {
  1218. if (roff_p != roff_buf)
  1219. roff_p--;
  1220. while (*roff_p == ' ' && roff_p != roff_buf)
  1221. roff_p--;
  1222. if (roff_p == roff_buf)
  1223. file_putf(fff, "\n");
  1224. else {
  1225. *(roff_p + 1) = '\0';
  1226. file_putf(fff, "%s\n\n", roff_buf);
  1227. }
  1228. roff_p = roff_buf;
  1229. roff_s = NULL;
  1230. roff_buf[0] = '\0';
  1231. return;
  1232. }
  1233. /* Scan the given string, character at a time */
  1234. for (; *str; str++) {
  1235. char ch = *str;
  1236. int wrap = (ch == '\n');
  1237. if (!isprint(ch))
  1238. ch = ' ';
  1239. if (roff_p >= roff_buf + 75)
  1240. wrap = 1;
  1241. if ((ch == ' ') && (roff_p + 2 >= roff_buf + 75))
  1242. wrap = 1;
  1243. /* Handle line-wrap */
  1244. if (wrap) {
  1245. *roff_p = '\0';
  1246. r = roff_p;
  1247. if (roff_s && (ch != ' ')) {
  1248. *roff_s = '\0';
  1249. r = roff_s + 1;
  1250. }
  1251. file_putf(fff, "%s\n", roff_buf);
  1252. roff_s = NULL;
  1253. roff_p = roff_buf;
  1254. while (*r)
  1255. *roff_p++ = *r++;
  1256. }
  1257. /* Save the char */
  1258. if ((roff_p > roff_buf) || (ch != ' ')) {
  1259. if (ch == ' ')
  1260. roff_s = roff_p;
  1261. *roff_p++ = ch;
  1262. }
  1263. }
  1264. }
  1265. /**
  1266. * Create a spoiler file for monsters (-SHAWN-)
  1267. */
  1268. static void spoil_mon_info(const char *fname)
  1269. {
  1270. char buf[1024];
  1271. int msex, vn, i, j, k, n;
  1272. bool breath, magic, sin;
  1273. const char *p, *q;
  1274. const char *vp[64];
  1275. int spower;
  1276. const char *name;
  1277. /* Build the filename */
  1278. path_build(buf, 1024, ANGBAND_DIR_USER, fname);
  1279. /* Open the file */
  1280. fff = file_open(buf, MODE_WRITE, FTYPE_TEXT);
  1281. /* Oops */
  1282. if (!fff) {
  1283. msg("Cannot create spoiler file.");
  1284. return;
  1285. }
  1286. /* Dump the header */
  1287. sprintf(buf, "Monster Spoilers for Beleriand Version %d.%d.%d\n",
  1288. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  1289. spoil_out(buf);
  1290. spoil_out("------------------------------------------\n\n");
  1291. /*
  1292. * List all monsters in order.
  1293. */
  1294. for (n = 1; n < z_info->r_max; n++) {
  1295. monster_race *r_ptr = &r_info[n];
  1296. /* Extract the flags */
  1297. breath = FALSE;
  1298. magic = FALSE;
  1299. spower = r_ptr->spell_power;
  1300. /* Get the monster name */
  1301. name = r_ptr->name;
  1302. /* Extract a gender (if applicable) */
  1303. if (rf_has(r_ptr->flags, RF_FEMALE))
  1304. msex = 2;
  1305. else if (rf_has(r_ptr->flags, RF_MALE))
  1306. msex = 1;
  1307. else
  1308. msex = 0;
  1309. /* Prefix */
  1310. if (rf_has(r_ptr->flags, RF_QUESTOR)) {
  1311. spoil_out("[Q] ");
  1312. } else if (rf_has(r_ptr->flags, RF_UNIQUE)) {
  1313. spoil_out("[U] ");
  1314. } else {
  1315. spoil_out("The ");
  1316. }
  1317. /* Name */
  1318. sprintf(buf, "%s (", r_ptr->name); /* ---)--- */
  1319. spoil_out(buf);
  1320. /* Color */
  1321. spoil_out(attr_to_text(r_ptr->d_attr));
  1322. /* Symbol --(-- */
  1323. sprintf(buf, " '%c')\n", r_ptr->d_char);
  1324. spoil_out(buf);
  1325. /* Indent */
  1326. sprintf(buf, "=== ");
  1327. spoil_out(buf);
  1328. /* Number */
  1329. sprintf(buf, "Num:%d ", n);
  1330. spoil_out(buf);
  1331. /* Level */
  1332. sprintf(buf, "Lev:%d ", r_ptr->level);
  1333. spoil_out(buf);
  1334. /* Rarity */
  1335. sprintf(buf, "Rar:%d ", r_ptr->rarity);
  1336. spoil_out(buf);
  1337. /* Speed */
  1338. if (r_ptr->speed >= 110) {
  1339. sprintf(buf, "Spd:+%d ", (r_ptr->speed - 110));
  1340. } else {
  1341. sprintf(buf, "Spd:-%d ", (110 - r_ptr->speed));
  1342. }
  1343. spoil_out(buf);
  1344. /* Hitpoints */
  1345. if ((rf_has(r_ptr->flags, RF_FORCE_MAXHP)) || (r_ptr->hside == 1)) {
  1346. sprintf(buf, "Hp:%d ", r_ptr->hdice * r_ptr->hside);
  1347. } else {
  1348. sprintf(buf, "Hp:%dd%d ", r_ptr->hdice, r_ptr->hside);
  1349. }
  1350. spoil_out(buf);
  1351. /* Armor Class */
  1352. sprintf(buf, "Ac:%d ", r_ptr->ac);
  1353. spoil_out(buf);
  1354. /* Experience */
  1355. sprintf(buf, "Exp:%ld\n", (long) (r_ptr->mexp));
  1356. spoil_out(buf);
  1357. /* Describe */
  1358. spoil_out(r_ptr->text);
  1359. spoil_out(" ");
  1360. spoil_out("This");
  1361. if (rf_has(r_ptr->flags, RF_ANIMAL))
  1362. spoil_out(" natural");
  1363. if (rf_has(r_ptr->flags, RF_EVIL))
  1364. spoil_out(" evil");
  1365. if (rf_has(r_ptr->flags, RF_UNDEAD))
  1366. spoil_out(" undead");
  1367. if (rf_has(r_ptr->flags, RF_DRAGON))
  1368. spoil_out(" dragon");
  1369. else if (rf_has(r_ptr->flags, RF_DEMON))
  1370. spoil_out(" demon");
  1371. else if (rf_has(r_ptr->flags, RF_GIANT))
  1372. spoil_out(" giant");
  1373. else if (rf_has(r_ptr->flags, RF_TROLL))
  1374. spoil_out(" troll");
  1375. else if (rf_has(r_ptr->flags, RF_ORC))
  1376. spoil_out(" orc");
  1377. else
  1378. spoil_out(" creature");
  1379. spoil_out(" moves");
  1380. if ((rf_has(r_ptr->flags, RF_RAND_50))
  1381. && (rf_has(r_ptr->flags, RF_RAND_25))) {
  1382. spoil_out(" extremely erratically");
  1383. } else if (rf_has(r_ptr->flags, RF_RAND_50)) {
  1384. spoil_out(" somewhat erratically");
  1385. } else if (rf_has(r_ptr->flags, RF_RAND_25)) {
  1386. spoil_out(" a bit erratically");
  1387. } else {
  1388. spoil_out(" normally");
  1389. }
  1390. if (rf_has(r_ptr->flags, RF_NEVER_MOVE)) {
  1391. spoil_out(", but does not deign to chase intruders");
  1392. }
  1393. spoil_out(". ");
  1394. if (rf_has(r_ptr->flags, RF_ESCORT)) {
  1395. sprintf(buf, "%s usually appears with ", wd_che[msex]);
  1396. spoil_out(buf);
  1397. if (rf_has(r_ptr->flags, RF_ESCORTS))
  1398. spoil_out("escorts. ");
  1399. else
  1400. spoil_out("an escort. ");
  1401. }
  1402. if ((rf_has(r_ptr->flags, RF_FRIEND))
  1403. || (rf_has(r_ptr->flags, RF_FRIENDS))) {
  1404. sprintf(buf, "%s usually appears in groups. ", wd_che[msex]);
  1405. spoil_out(buf);
  1406. }
  1407. /* Collect inate attacks */
  1408. vn = 0;
  1409. if (rsf_has(r_ptr->flags, RSF_SHRIEK))
  1410. vp[vn++] = "shriek for help";
  1411. if (rsf_has(r_ptr->flags, RSF_LASH))
  1412. vp[vn++] = "lash you if nearby";
  1413. if (rsf_has(r_ptr->flags, RSF_BOULDER)) {
  1414. if (spower < 10)
  1415. vp[vn++] = "throw rocks";
  1416. else
  1417. vp[vn++] = "throw boulders";
  1418. }
  1419. if (rsf_has(r_ptr->flags, RSF_SHOT)) {
  1420. if (spower < 5)
  1421. vp[vn++] = "sling pebbles";
  1422. else if (spower < 15)
  1423. vp[vn++] = "sling leaden pellets";
  1424. else
  1425. vp[vn++] = "sling seeker shot";
  1426. }
  1427. if (rsf_has(r_ptr->flags, RSF_ARROW)) {
  1428. if (spower < 8)
  1429. vp[vn++] = "shoot little arrows";
  1430. else if (spower < 15)
  1431. vp[vn++] = "shoot arrows";
  1432. else
  1433. vp[vn++] = "shoot seeker arrows";
  1434. }
  1435. if (rsf_has(r_ptr->flags, RSF_BOLT)) {
  1436. if (spower < 8)
  1437. vp[vn++] = "fire bolts";
  1438. else if (spower < 15)
  1439. vp[vn++] = "fire crossbow quarrels";
  1440. else
  1441. vp[vn++] = "fire seeker bolts";
  1442. }
  1443. if (rsf_has(r_ptr->flags, RSF_MISSL)) {
  1444. if (spower < 8)
  1445. vp[vn++] = "fire little missiles";
  1446. else if (spower < 15)
  1447. vp[vn++] = "fire missiles";
  1448. else
  1449. vp[vn++] = "fire heavy missiles";
  1450. }
  1451. if (rsf_has(r_ptr->flags, RSF_PMISSL)) {
  1452. if (rf_has(r_ptr->flags, RF_MORGUL_MAGIC))
  1453. vp[vn++] = "hurl black darts";
  1454. else
  1455. vp[vn++] = "whip poisoned darts";
  1456. }
  1457. if (vn) {
  1458. spoil_out(wd_che[msex]);
  1459. for (i = 0; i < vn; i++) {
  1460. if (!i) {
  1461. spoil_out(" may ");
  1462. if (rf_has(r_ptr->flags, RF_ARCHER))
  1463. spoil_out("frequently ");
  1464. } else if (i < vn - 1)
  1465. spoil_out(", ");
  1466. else
  1467. spoil_out(", or ");
  1468. spoil_out(vp[i]);
  1469. }
  1470. spoil_out(". ");
  1471. }
  1472. /* Collect breaths */
  1473. vn = 0;
  1474. if (rsf_has(r_ptr->flags, RSF_BRTH_ACID))
  1475. vp[vn++] = "acid";
  1476. if (rsf_has(r_ptr->flags, RSF_BRTH_ELEC))
  1477. vp[vn++] = "lightning";
  1478. if (rsf_has(r_ptr->flags, RSF_BRTH_FIRE))
  1479. vp[vn++] = "fire";
  1480. if (rsf_has(r_ptr->flags, RSF_BRTH_COLD))
  1481. vp[vn++] = "frost";
  1482. if (rsf_has(r_ptr->flags, RSF_BRTH_POIS))
  1483. vp[vn++] = "poison";
  1484. if (rsf_has(r_ptr->flags, RSF_BRTH_PLAS))
  1485. vp[vn++] = "plasma";
  1486. if (rsf_has(r_ptr->flags, RSF_BRTH_LIGHT))
  1487. vp[vn++] = "light";
  1488. if (rsf_has(r_ptr->flags, RSF_BRTH_DARK)) {
  1489. if (rf_has(r_ptr->flags, RF_MORGUL_MAGIC))
  1490. vp[vn++] = "Night";
  1491. else
  1492. vp[vn++] = "darkness";
  1493. }
  1494. if (rsf_has(r_ptr->flags, RSF_BRTH_CONFU))
  1495. vp[vn++] = "confusion";
  1496. if (rsf_has(r_ptr->flags, RSF_BRTH_SOUND))
  1497. vp[vn++] = "sound";
  1498. if (rsf_has(r_ptr->flags, RSF_BRTH_SHARD))
  1499. vp[vn++] = "shards";
  1500. if (rsf_has(r_ptr->flags, RSF_BRTH_INER))
  1501. vp[vn++] = "inertia";
  1502. if (rsf_has(r_ptr->flags, RSF_BRTH_GRAV))
  1503. vp[vn++] = "gravity";
  1504. if (rsf_has(r_ptr->flags, RSF_BRTH_FORCE))
  1505. vp[vn++] = "force";
  1506. if (rsf_has(r_ptr->flags, RSF_BRTH_NEXUS))
  1507. vp[vn++] = "nexus";
  1508. if (rsf_has(r_ptr->flags, RSF_BRTH_NETHR))
  1509. vp[vn++] = "nether";
  1510. if (rsf_has(r_ptr->flags, RSF_BRTH_CHAOS))
  1511. vp[vn++] = "chaos";
  1512. if (rsf_has(r_ptr->flags, RSF_BRTH_DISEN))
  1513. vp[vn++] = "disenchantment";
  1514. if (rsf_has(r_ptr->flags, RSF_BRTH_TIME))
  1515. vp[vn++] = "time";
  1516. if (rsf_has(r_ptr->flags, RSF_BRTH_STORM))
  1517. vp[vn++] = "storm";
  1518. if (rsf_has(r_ptr->flags, RSF_BRTH_DFIRE))
  1519. vp[vn++] = "dragonfire";
  1520. if (rsf_has(r_ptr->flags, RSF_BRTH_ICE))
  1521. vp[vn++] = "ice";
  1522. if (rsf_has(r_ptr->flags, RSF_BRTH_ALL))
  1523. vp[vn++] = "the elements";
  1524. if (rsf_has(r_ptr->flags, RSF_XXX1))
  1525. vp[vn++] = "something";
  1526. if (vn) {
  1527. breath = TRUE;
  1528. spoil_out(wd_che[msex]);
  1529. for (i = 0; i < vn; i++) {
  1530. if (!i)
  1531. spoil_out(" may breathe ");
  1532. else if (i < vn - 1)
  1533. spoil_out(", ");
  1534. else
  1535. spoil_out(" or ");
  1536. spoil_out(vp[i]);
  1537. }
  1538. if (rf_has(r_ptr->flags, RF_POWERFUL))
  1539. spoil_out(" powerfully");
  1540. }
  1541. /* Collect spells */
  1542. vn = 0;
  1543. if (rsf_has(r_ptr->flags, RSF_BALL_ACID)) {
  1544. if (spower < 70)
  1545. vp[vn++] = "produce acid balls";
  1546. else
  1547. vp[vn++] = "produce acid storms";
  1548. }
  1549. if (rsf_has(r_ptr->flags, RSF_BALL_ELEC)) {
  1550. if (spower < 70)
  1551. vp[vn++] = "produce lightning balls";
  1552. else
  1553. vp[vn++] = "produce lightning storms";
  1554. }
  1555. if (rsf_has(r_ptr->flags, RSF_BALL_FIRE)) {
  1556. if (rf_has(r_ptr->flags, RF_UDUN_MAGIC)) {
  1557. if (spower < 70)
  1558. vp[vn++] = "produce balls of hellfire";
  1559. else if (spower < 110)
  1560. vp[vn++] = "invoke storms of Udun-fire";
  1561. else
  1562. vp[vn++] = "call upon the fires of Udun";
  1563. } else {
  1564. if (spower < 70)
  1565. vp[vn++] = "produce fire balls";
  1566. else
  1567. vp[vn++] = "produce fire storms";
  1568. }
  1569. }
  1570. if (rsf_has(r_ptr->flags, RSF_BALL_COLD)) {
  1571. if (rf_has(r_ptr->flags, RF_MORGUL_MAGIC)) {
  1572. if (spower < 70)
  1573. vp[vn++] = "produce spheres of deadly cold";
  1574. else
  1575. vp[vn++] = "invoke storms of deadly cold";
  1576. } else {
  1577. if (spower < 70)
  1578. vp[vn++] = "produce frost balls";
  1579. else
  1580. vp[vn++] = "produce frost storms";
  1581. }
  1582. }
  1583. if (rsf_has(r_ptr->flags, RSF_BALL_POIS)) {
  1584. if (rf_has(r_ptr->flags, RF_MORGUL_MAGIC)) {
  1585. if (spower < 15)
  1586. vp[vn++] = "produce clouds of venom";
  1587. else if (spower < 70)
  1588. vp[vn++] = "produce venomous balls";
  1589. else
  1590. vp[vn++] = "raise storms of venom";
  1591. } else {
  1592. if (spower < 15)
  1593. vp[vn++] = "produce stinking clouds";
  1594. else if (spower < 70)
  1595. vp[vn++] = "produce poison balls";
  1596. else
  1597. vp[vn++] = "produce storms of poison";
  1598. }
  1599. }
  1600. if (rsf_has(r_ptr->flags, RSF_BALL_LIGHT)) {
  1601. if (spower < 15)
  1602. vp[vn++] = "produce spheres of light";
  1603. else if (spower < 70)
  1604. vp[vn++] = "produce explosions of light";
  1605. else
  1606. vp[vn++] = "invoke starbursts";
  1607. }
  1608. if (rsf_has(r_ptr->flags, RSF_BALL_DARK)) {
  1609. if (rf_has(r_ptr->flags, RF_MORGUL_MAGIC)) {
  1610. if (spower < 70)
  1611. vp[vn++] = "produce spheres of Night";
  1612. else
  1613. vp[vn++] = "conjure up storms of Night";
  1614. } else {
  1615. if (spower < 70)
  1616. vp[vn++] = "produce balls of darkness";
  1617. else
  1618. vp[vn++] = "produce storms of darkness";
  1619. }
  1620. }
  1621. if (rsf_has(r_ptr->flags, RSF_BALL_CONFU)) {
  1622. if (spower < 70)
  1623. vp[vn++] = "produce confusion balls";
  1624. else
  1625. vp[vn++] = "produce storms of confusion";
  1626. }
  1627. if (rsf_has(r_ptr->flags, RSF_BALL_SOUND)) {
  1628. if (spower < 15)
  1629. vp[vn++] = "produce explosions of sound";
  1630. else if (spower < 70)
  1631. vp[vn++] = "produce thunderclaps";
  1632. else
  1633. vp[vn++] = "unleash storms of sound";
  1634. }
  1635. if (rsf_has(r_ptr->flags, RSF_BALL_SHARD)) {
  1636. if (spower < 15)
  1637. vp[vn++] = "produce blasts of shards";
  1638. else if (spower < 90)
  1639. vp[vn++] = "produce whirlwinds of shards";
  1640. else
  1641. vp[vn++] = "call up shardstorms";
  1642. }
  1643. if (rsf_has(r_ptr->flags, RSF_BALL_STORM)) {
  1644. if (spower < 30)
  1645. vp[vn++] = "produce little storms";
  1646. else if (spower < 70)
  1647. vp[vn++] = "produce whirlpools";
  1648. else
  1649. vp[vn++] = "call up raging storms";
  1650. }
  1651. if (rsf_has(r_ptr->flags, RSF_BALL_NETHR)) {
  1652. if (spower < 30)
  1653. vp[vn++] = "produce nether orbs";
  1654. else if (spower < 70)
  1655. vp[vn++] = "produce nether balls";
  1656. else
  1657. vp[vn++] = "invoke nether storms";
  1658. }
  1659. if (rsf_has(r_ptr->flags, RSF_BALL_CHAOS)) {
  1660. if (spower < 20)
  1661. vp[vn++] = "produce spheres of chaos";
  1662. else if (spower < 70)
  1663. vp[vn++] = "produce explosions of chaos";
  1664. else
  1665. vp[vn++] = "call up maelstroms of raw chaos";
  1666. }
  1667. if (rsf_has(r_ptr->flags, RSF_BALL_MANA)) {
  1668. if (spower < 40)
  1669. vp[vn++] = "produce manabursts";
  1670. else if (spower < 90)
  1671. vp[vn++] = "produce balls of mana";
  1672. else
  1673. vp[vn++] = "invoke mana storms";
  1674. }
  1675. if (rsf_has(r_ptr->flags, RSF_BOLT_ACID))
  1676. vp[vn++] = "produce acid bolts";
  1677. if (rsf_has(r_ptr->flags, RSF_BOLT_ELEC))
  1678. vp[vn++] = "produce lightning bolts";
  1679. if (rsf_has(r_ptr->flags, RSF_BOLT_FIRE))
  1680. vp[vn++] = "produce fire bolts";
  1681. if (rsf_has(r_ptr->flags, RSF_BOLT_COLD))
  1682. vp[vn++] = "produce frost bolts";
  1683. if (rsf_has(r_ptr->flags, RSF_BOLT_POIS))
  1684. vp[vn++] = "produce poison bolts";
  1685. if (rsf_has(r_ptr->flags, RSF_BOLT_PLAS))
  1686. vp[vn++] = "produce plasma bolts";
  1687. if (rsf_has(r_ptr->flags, RSF_BOLT_ICE))
  1688. vp[vn++] = "produce ice bolts";
  1689. if (rsf_has(r_ptr->flags, RSF_BOLT_WATER))
  1690. vp[vn++] = "produce water bolts";
  1691. if (rsf_has(r_ptr->flags, RSF_BOLT_NETHR))
  1692. vp[vn++] = "produce nether bolts";
  1693. if (rsf_has(r_ptr->flags, RSF_BOLT_DARK))
  1694. vp[vn++] = "produce dark bolts";
  1695. if (rsf_has(r_ptr->flags, RSF_BEAM_ELEC))
  1696. vp[vn++] = "shoot sparks of lightning";
  1697. if (rsf_has(r_ptr->flags, RSF_BEAM_ICE))
  1698. vp[vn++] = "cast lances of ice";
  1699. if (rsf_has(r_ptr->flags, RSF_BEAM_NETHR)) {
  1700. if (spower < 40)
  1701. vp[vn++] = "cast lances of nether";
  1702. else if (spower < 90)
  1703. vp[vn++] = "shoot rays of death";
  1704. }
  1705. if (rsf_has(r_ptr->flags, RSF_ARC_HFIRE)) {
  1706. if (rf_has(r_ptr->flags, RF_UDUN_MAGIC)) {
  1707. if (spower < 50)
  1708. vp[vn++] = "produce a column of hellfire";
  1709. else if (spower < 100)
  1710. vp[vn++] = "envelop you in hellfire";
  1711. else
  1712. vp[vn++] = "breath like the Balrog";
  1713. } else {
  1714. if (spower < 50)
  1715. vp[vn++] = "produce a column of fire";
  1716. else if (spower < 100)
  1717. vp[vn++] = "envelop you in fire";
  1718. }
  1719. }
  1720. if (rsf_has(r_ptr->flags, RSF_ARC_FORCE)) {
  1721. if (spower < 50)
  1722. vp[vn++] = "thrust you away";
  1723. else if (spower < 100)
  1724. vp[vn++] = "hurls you away";
  1725. else
  1726. vp[vn++] = "snatches you up, and throws you away";
  1727. }
  1728. if (rsf_has(r_ptr->flags, RSF_HASTE))
  1729. vp[vn++] = "haste-self";
  1730. if (rsf_has(r_ptr->flags, RSF_ADD_MANA))
  1731. vp[vn++] = "restore mana";
  1732. if (rsf_has(r_ptr->flags, RSF_HEAL))
  1733. vp[vn++] = "heal-self";
  1734. if (rsf_has(r_ptr->flags, RSF_CURE))
  1735. vp[vn++] = "cure what ails it";
  1736. if (rsf_has(r_ptr->flags, RSF_BLINK))
  1737. vp[vn++] = "blink-self";
  1738. if (rsf_has(r_ptr->flags, RSF_TPORT))
  1739. vp[vn++] = "teleport-self";
  1740. if (rsf_has(r_ptr->flags, RSF_TELE_TO))
  1741. vp[vn++] = "teleport to";
  1742. if (rsf_has(r_ptr->flags, RSF_TELE_AWAY))
  1743. vp[vn++] = "teleport away";
  1744. if (rsf_has(r_ptr->flags, RSF_TELE_LEVEL))
  1745. vp[vn++] = "teleport level";
  1746. if (rsf_has(r_ptr->flags, RSF_DARKNESS))
  1747. vp[vn++] = "create darkness";
  1748. if (rsf_has(r_ptr->flags, RSF_TRAPS))
  1749. vp[vn++] = "create traps";
  1750. if (rsf_has(r_ptr->flags, RSF_FORGET))
  1751. vp[vn++] = "cause amnesia";
  1752. if (rsf_has(r_ptr->flags, RSF_DRAIN_MANA))
  1753. vp[vn++] = "drain mana";
  1754. if (rsf_has(r_ptr->flags, RSF_DISPEL))
  1755. vp[vn++] = "dispel magic";
  1756. if (rsf_has(r_ptr->flags, RSF_MIND_BLAST))
  1757. vp[vn++] = "cause mind blasting";
  1758. if (rsf_has(r_ptr->flags, RSF_BRAIN_SMASH))
  1759. vp[vn++] = "cause brain smashing";
  1760. if (rsf_has(r_ptr->flags, RSF_WOUND)) {
  1761. if (spower < 7)
  1762. vp[vn++] = "cause light wounds";
  1763. else if (spower < 15)
  1764. vp[vn++] = "cause medium wounds";
  1765. else if (spower < 30)
  1766. vp[vn++] = "cause serious wounds";
  1767. else if (spower < 50)
  1768. vp[vn++] = "cause critical wounds";
  1769. else
  1770. vp[vn++] = "cause mortal wounds";
  1771. }
  1772. if (rsf_has(r_ptr->flags, RSF_SHAPECHANGE))
  1773. vp[vn++] = "change shape";
  1774. if (rsf_has(r_ptr->flags, RSF_SCARE))
  1775. vp[vn++] = "terrify";
  1776. if (rsf_has(r_ptr->flags, RSF_BLIND))
  1777. vp[vn++] = "blind";
  1778. if (rsf_has(r_ptr->flags, RSF_CONF))
  1779. vp[vn++] = "confuse";
  1780. if (rsf_has(r_ptr->flags, RSF_SLOW))
  1781. vp[vn++] = "slow";
  1782. if (rsf_has(r_ptr->flags, RSF_HOLD))
  1783. vp[vn++] = "paralyze";
  1784. if (rsf_has(r_ptr->flags, RSF_S_MONSTER))
  1785. vp[vn++] = "summon a monster";
  1786. if (rsf_has(r_ptr->flags, RSF_S_MONSTERS))
  1787. vp[vn++] = "summon monsters";
  1788. if (rsf_has(r_ptr->flags, RSF_S_ANT))
  1789. vp[vn++] = "summon ants";
  1790. if (rsf_has(r_ptr->flags, RSF_S_SPIDER))
  1791. vp[vn++] = "summon spiders";
  1792. if (rsf_has(r_ptr->flags, RSF_S_HOUND))
  1793. vp[vn++] = "summon hounds";
  1794. if (rsf_has(r_ptr->flags, RSF_S_ANIMAL))
  1795. vp[vn++] = "summon natural creatures";
  1796. if (rsf_has(r_ptr->flags, RSF_S_THIEF))
  1797. vp[vn++] = "summon thieves";
  1798. if (rsf_has(r_ptr->flags, RSF_S_SWAMP))
  1799. vp[vn++] = "summon swamp creatures";
  1800. if (rsf_has(r_ptr->flags, RSF_S_DRAGON))
  1801. vp[vn++] = "summon a dragon";
  1802. if (rsf_has(r_ptr->flags, RSF_S_HI_DRAGON))
  1803. vp[vn++] = "summon Ancient Dragons";
  1804. if (rsf_has(r_ptr->flags, RSF_S_DEMON))
  1805. vp[vn++] = "summon a demon";
  1806. if (rsf_has(r_ptr->flags, RSF_S_HI_DEMON))
  1807. vp[vn++] = "summon Greater Demons";
  1808. if (rsf_has(r_ptr->flags, RSF_S_UNDEAD))
  1809. vp[vn++] = "summon an undead";
  1810. if (rsf_has(r_ptr->flags, RSF_S_HI_UNDEAD))
  1811. vp[vn++] = "summon Greater Undead";
  1812. if (rsf_has(r_ptr->flags, RSF_S_QUEST))
  1813. vp[vn++] = "summon the Quest monsters";
  1814. if (rsf_has(r_ptr->flags, RSF_S_UNIQUE))
  1815. vp[vn++] = "summon Unique Monsters";
  1816. if (vn) {
  1817. magic = TRUE;
  1818. if (breath) {
  1819. spoil_out(", and is also");
  1820. } else {
  1821. spoil_out(wd_che[msex]);
  1822. spoil_out(" is");
  1823. }
  1824. spoil_out(" magical, casting ");
  1825. /* Describe magic */
  1826. if ((rf_has(r_ptr->flags, RF_UDUN_MAGIC))
  1827. && (rf_has(r_ptr->flags, RF_MORGUL_MAGIC)))
  1828. spoil_out(" perilous spells of Udun and of Morgul");
  1829. if (rf_has(r_ptr->flags, RF_MORGUL_MAGIC))
  1830. spoil_out(" Morgul-spells");
  1831. else if (rf_has(r_ptr->flags, RF_UDUN_MAGIC))
  1832. spoil_out(" spells of Udun");
  1833. else
  1834. spoil_out(" spells");
  1835. if (rf_has(r_ptr->flags, RF_SMART))
  1836. spoil_out(" intelligently");
  1837. for (i = 0; i < vn; i++) {
  1838. if (!i)
  1839. spoil_out(" which ");
  1840. else if (i < vn - 1)
  1841. spoil_out(", ");
  1842. else
  1843. spoil_out(" or ");
  1844. spoil_out(vp[i]);
  1845. }
  1846. }
  1847. if (breath || magic) {
  1848. if (r_ptr->freq_ranged) {
  1849. sprintf(buf, "; 1 time in %d. ",
  1850. 100 / (r_ptr->freq_ranged));
  1851. spoil_out(buf);
  1852. } else {
  1853. sprintf(buf, "; never. ");
  1854. spoil_out(buf);
  1855. }
  1856. }
  1857. /* Collect special abilities. */
  1858. vn = 0;
  1859. if (rf_has(r_ptr->flags, RF_OPEN_DOOR))
  1860. vp[vn++] = "open doors";
  1861. if (rf_has(r_ptr->flags, RF_BASH_DOOR))
  1862. vp[vn++] = "bash down doors";
  1863. if (rf_has(r_ptr->flags, RF_PASS_WALL))
  1864. vp[vn++] = "pass through walls";
  1865. if (rf_has(r_ptr->flags, RF_KILL_WALL))
  1866. vp[vn++] = "bore through walls";
  1867. if (rf_has(r_ptr->flags, RF_MOVE_BODY))
  1868. vp[vn++] = "push past weaker monsters";
  1869. if (rf_has(r_ptr->flags, RF_KILL_BODY))
  1870. vp[vn++] = "destroy weaker monsters";
  1871. if (rf_has(r_ptr->flags, RF_TAKE_ITEM))
  1872. vp[vn++] = "pick up objects";
  1873. if (rf_has(r_ptr->flags, RF_KILL_ITEM))
  1874. vp[vn++] = "destroy objects";
  1875. if (vn) {
  1876. spoil_out(wd_che[msex]);
  1877. for (i = 0; i < vn; i++) {
  1878. if (!i)
  1879. spoil_out(" can ");
  1880. else if (i < vn - 1)
  1881. spoil_out(", ");
  1882. else
  1883. spoil_out(" and ");
  1884. spoil_out(vp[i]);
  1885. }
  1886. spoil_out(". ");
  1887. }
  1888. if (rf_has(r_ptr->flags, RF_PLAYER_GHOST)) {
  1889. spoil_out(wd_che[msex]);
  1890. spoil_out(" is a player ghost template. ");
  1891. }
  1892. if (rf_has(r_ptr->flags, RF_INVISIBLE)) {
  1893. spoil_out(wd_che[msex]);
  1894. spoil_out(" is invisible. ");
  1895. }
  1896. if (rf_has(r_ptr->flags, RF_COLD_BLOOD)) {
  1897. spoil_out(wd_che[msex]);
  1898. spoil_out(" is cold blooded. ");
  1899. }
  1900. if (rf_has(r_ptr->flags, RF_EMPTY_MIND)) {
  1901. spoil_out(wd_che[msex]);
  1902. spoil_out(" is not detected by telepathy. ");
  1903. }
  1904. if (rf_has(r_ptr->flags, RF_WEIRD_MIND)) {
  1905. spoil_out(wd_che[msex]);
  1906. spoil_out(" is rarely detected by telepathy. ");
  1907. }
  1908. if (rf_has(r_ptr->flags, RF_MULTIPLY)) {
  1909. spoil_out(wd_che[msex]);
  1910. spoil_out(" breeds explosively. ");
  1911. }
  1912. if (rf_has(r_ptr->flags, RF_REGENERATE)) {
  1913. spoil_out(wd_che[msex]);
  1914. spoil_out(" regenerates quickly. ");
  1915. }
  1916. /* Collect susceptibilities */
  1917. vn = 0;
  1918. if (rf_has(r_ptr->flags, RF_HURT_ROCK))
  1919. vp[vn++] = "rock remover";
  1920. if (rf_has(r_ptr->flags, RF_HURT_LIGHT))
  1921. vp[vn++] = "bright light";
  1922. if (rf_has(r_ptr->flags, RF_HURT_FIRE))
  1923. vp[vn++] = "fire";
  1924. if (rf_has(r_ptr->flags, RF_HURT_COLD))
  1925. vp[vn++] = "cold";
  1926. if (vn) {
  1927. spoil_out(wd_che[msex]);
  1928. for (i = 0; i < vn; i++) {
  1929. if (!i)
  1930. spoil_out(" is hurt by ");
  1931. else if (i < vn - 1)
  1932. spoil_out(", ");
  1933. else
  1934. spoil_out(" and ");
  1935. spoil_out(vp[i]);
  1936. }
  1937. spoil_out(". ");
  1938. }
  1939. /* Collect immunities */
  1940. vn = 0;
  1941. if (rf_has(r_ptr->flags, RF_IM_ACID))
  1942. vp[vn++] = "acid";
  1943. if (rf_has(r_ptr->flags, RF_IM_ELEC))
  1944. vp[vn++] = "lightning";
  1945. if (rf_has(r_ptr->flags, RF_IM_FIRE))
  1946. vp[vn++] = "fire";
  1947. if (rf_has(r_ptr->flags, RF_IM_COLD))
  1948. vp[vn++] = "cold";
  1949. if (rf_has(r_ptr->flags, RF_IM_POIS))
  1950. vp[vn++] = "poison";
  1951. if (vn) {
  1952. spoil_out(wd_che[msex]);
  1953. for (i = 0; i < vn; i++) {
  1954. if (!i)
  1955. spoil_out(" resists ");
  1956. else if (i < vn - 1)
  1957. spoil_out(", ");
  1958. else
  1959. spoil_out(" and ");
  1960. spoil_out(vp[i]);
  1961. }
  1962. spoil_out(". ");
  1963. }
  1964. /* Collect resistances */
  1965. vn = 0;
  1966. if (rsf_has(r_ptr->flags, RSF_BRTH_LIGHT))
  1967. vp[vn++] = "light";
  1968. if ((rsf_has(r_ptr->flags, RSF_BRTH_DARK)) ||
  1969. (rf_has(r_ptr->flags, RF_MORGUL_MAGIC)) ||
  1970. (rf_has(r_ptr->flags, RF_ORC)))
  1971. vp[vn++] = "darkness";
  1972. if (rsf_has(r_ptr->flags, RSF_BRTH_CONFU))
  1973. vp[vn++] = "confusion";
  1974. if (rsf_has(r_ptr->flags, RSF_BRTH_SOUND))
  1975. vp[vn++] = "sound";
  1976. if (rsf_has(r_ptr->flags, RSF_BRTH_SHARD))
  1977. vp[vn++] = "shards";
  1978. if (rsf_has(r_ptr->flags, RSF_BRTH_INER))
  1979. vp[vn++] = "inertia";
  1980. if (rsf_has(r_ptr->flags, RSF_BRTH_GRAV))
  1981. vp[vn++] = "gravity";
  1982. if (rsf_has(r_ptr->flags, RSF_BRTH_FORCE))
  1983. vp[vn++] = "force";
  1984. if ((rf_has(r_ptr->flags, RF_RES_WATE)) || (prefix(name, "Water")))
  1985. vp[vn++] = "water";
  1986. if ((rsf_has(r_ptr->flags, RSF_BRTH_PLAS))
  1987. || (rf_has(r_ptr->flags, RF_RES_PLAS)) || ((vn)
  1988. &&
  1989. ((rf_has
  1990. (r_ptr->flags,
  1991. RF_IM_ELEC))
  1992. ||
  1993. (rf_has
  1994. (r_ptr->flags,
  1995. RF_IM_FIRE))))
  1996. || prefix(name, "Plasma"))
  1997. vp[vn++] = "plasma";
  1998. if ((rf_has(r_ptr->flags, RF_RES_NEXUS)) || prefix(name, "Nexus")
  1999. || (rsf_has(r_ptr->flags, RSF_BRTH_NEXUS)))
  2000. vp[vn++] = "nexus";
  2001. if ((rf_has(r_ptr->flags, RF_UNDEAD))
  2002. || (rf_has(r_ptr->flags, RF_RES_NETH))
  2003. || (rsf_has(r_ptr->flags, RSF_BRTH_NETHR)))
  2004. vp[vn++] = "nether";
  2005. if ((rf_has(r_ptr->flags, RF_RES_DISE))
  2006. || (rsf_has(r_ptr->flags, RSF_BRTH_DISEN))
  2007. || prefix(name, "Disen"))
  2008. vp[vn++] = "disenchantment";
  2009. if (rsf_has(r_ptr->flags, RSF_BRTH_TIME))
  2010. vp[vn++] = "time";
  2011. if (vn) {
  2012. spoil_out(wd_che[msex]);
  2013. for (i = 0; i < vn; i++) {
  2014. if (!i)
  2015. spoil_out(" resists ");
  2016. else if (i < vn - 1)
  2017. spoil_out(", ");
  2018. else
  2019. spoil_out(" and ");
  2020. spoil_out(vp[i]);
  2021. }
  2022. spoil_out(". ");
  2023. }
  2024. /* Collect non-effects */
  2025. vn = 0;
  2026. if ((rf_has(r_ptr->flags, RF_NO_STUN))
  2027. || (rsf_has(r_ptr->flags, RSF_BRTH_SOUND))
  2028. || (rsf_has(r_ptr->flags, RSF_BRTH_FORCE)))
  2029. vp[vn++] = "stunned";
  2030. if (rf_has(r_ptr->flags, RF_NO_FEAR))
  2031. vp[vn++] = "frightened";
  2032. if ((rf_has(r_ptr->flags, RF_NO_CONF))
  2033. || (rsf_has(r_ptr->flags, RSF_BRTH_CONFU))
  2034. || (rsf_has(r_ptr->flags, RSF_BRTH_CHAOS)))
  2035. vp[vn++] = "confused";
  2036. if (rf_has(r_ptr->flags, RF_NO_SLEEP))
  2037. vp[vn++] = "slept";
  2038. if (vn) {
  2039. spoil_out(wd_che[msex]);
  2040. for (i = 0; i < vn; i++) {
  2041. if (!i)
  2042. spoil_out(" cannot be ");
  2043. else if (i < vn - 1)
  2044. spoil_out(", ");
  2045. else
  2046. spoil_out(" or ");
  2047. spoil_out(vp[i]);
  2048. }
  2049. spoil_out(". ");
  2050. }
  2051. spoil_out(wd_che[msex]);
  2052. if (r_ptr->sleep > 200)
  2053. spoil_out(" prefers to ignore");
  2054. else if (r_ptr->sleep > 95)
  2055. spoil_out(" pays very little attention to");
  2056. else if (r_ptr->sleep > 75)
  2057. spoil_out(" pays little attention to");
  2058. else if (r_ptr->sleep > 45)
  2059. spoil_out(" tends to overlook");
  2060. else if (r_ptr->sleep > 25)
  2061. spoil_out(" takes quite a while to see");
  2062. else if (r_ptr->sleep > 10)
  2063. spoil_out(" takes a while to see");
  2064. else if (r_ptr->sleep > 5)
  2065. spoil_out(" is fairly observant of");
  2066. else if (r_ptr->sleep > 3)
  2067. spoil_out(" is observant of");
  2068. else if (r_ptr->sleep > 1)
  2069. spoil_out(" is very observant of");
  2070. else if (r_ptr->sleep > 0)
  2071. spoil_out(" is vigilant for");
  2072. else
  2073. spoil_out(" is ever vigilant for");
  2074. sprintf(buf, " intruders, which %s may notice from %d feet. ",
  2075. wd_lhe[msex],
  2076. (OPT(adult_small_device) ? 5 : 10) * r_ptr->aaf);
  2077. spoil_out(buf);
  2078. i = 0;
  2079. if (rf_has(r_ptr->flags, RF_DROP_60))
  2080. i += 1;
  2081. if (rf_has(r_ptr->flags, RF_DROP_90))
  2082. i += 2;
  2083. if (rf_has(r_ptr->flags, RF_DROP_1D2))
  2084. i += 2;
  2085. if (rf_has(r_ptr->flags, RF_DROP_2D2))
  2086. i += 4;
  2087. if (rf_has(r_ptr->flags, RF_DROP_3D2))
  2088. i += 6;
  2089. if (rf_has(r_ptr->flags, RF_DROP_4D2))
  2090. i += 8;
  2091. /* Drops gold and/or items */
  2092. if (i) {
  2093. sin = FALSE;
  2094. spoil_out(wd_che[msex]);
  2095. spoil_out(" will carry");
  2096. if (i == 1) {
  2097. spoil_out(" a");
  2098. sin = TRUE;
  2099. } else if (i == 2) {
  2100. spoil_out(" one or two");
  2101. } else {
  2102. sprintf(buf, " up to %u", i);
  2103. spoil_out(buf);
  2104. }
  2105. if (rf_has(r_ptr->flags, RF_DROP_GREAT)) {
  2106. if (sin)
  2107. spoil_out("n");
  2108. spoil_out(" exceptional object");
  2109. } else if (rf_has(r_ptr->flags, RF_DROP_GOOD)) {
  2110. spoil_out(" good object");
  2111. } else if (rf_has(r_ptr->flags, RF_DROP_CHEST)) {
  2112. spoil_out(" chest");
  2113. } else if (rf_has(r_ptr->flags, RF_ONLY_ITEM)) {
  2114. if (sin)
  2115. spoil_out("n");
  2116. spoil_out(" object");
  2117. } else if (rf_has(r_ptr->flags, RF_ONLY_GOLD)) {
  2118. spoil_out(" treasure");
  2119. } else {
  2120. if (sin)
  2121. spoil_out("n");
  2122. spoil_out(" object");
  2123. if (i > 1)
  2124. spoil_out("s");
  2125. spoil_out(" or treasure");
  2126. }
  2127. if (i > 1)
  2128. spoil_out("s");
  2129. if (rf_has(r_ptr->flags, RF_DROP_CHOSEN)) {
  2130. spoil_out(", in addition to chosen objects");
  2131. }
  2132. spoil_out(". ");
  2133. }
  2134. /* Count the actual attacks */
  2135. for (i = 0, j = 0; j < 4; j++) {
  2136. if (r_ptr->blow[j].method)
  2137. i++;
  2138. }
  2139. /* Examine the actual attacks */
  2140. for (k = 0, j = 0; j < 4; j++) {
  2141. if (!r_ptr->blow[j].method)
  2142. continue;
  2143. /* No method yet */
  2144. p = "???";
  2145. /* Acquire the method */
  2146. switch (r_ptr->blow[j].method) {
  2147. case RBM_HIT:
  2148. p = "hit";
  2149. break;
  2150. case RBM_TOUCH:
  2151. p = "touch";
  2152. break;
  2153. case RBM_PUNCH:
  2154. p = "punch";
  2155. break;
  2156. case RBM_KICK:
  2157. p = "kick";
  2158. break;
  2159. case RBM_CLAW:
  2160. p = "claw";
  2161. break;
  2162. case RBM_BITE:
  2163. p = "bite";
  2164. break;
  2165. case RBM_STING:
  2166. p = "sting";
  2167. break;
  2168. case RBM_XXX1:
  2169. break;
  2170. case RBM_BUTT:
  2171. p = "butt";
  2172. break;
  2173. case RBM_CRUSH:
  2174. p = "crush";
  2175. break;
  2176. case RBM_ENGULF:
  2177. p = "engulf";
  2178. break;
  2179. case RBM_XXX2:
  2180. break;
  2181. case RBM_CRAWL:
  2182. p = "crawl on you";
  2183. break;
  2184. case RBM_DROOL:
  2185. p = "drool on you";
  2186. break;
  2187. case RBM_SPIT:
  2188. p = "spit";
  2189. break;
  2190. case RBM_XXX3:
  2191. break;
  2192. case RBM_GAZE:
  2193. p = "gaze";
  2194. break;
  2195. case RBM_WAIL:
  2196. p = "wail";
  2197. break;
  2198. case RBM_SPORE:
  2199. p = "release spores";
  2200. break;
  2201. case RBM_XXX4:
  2202. break;
  2203. case RBM_BEG:
  2204. p = "beg";
  2205. break;
  2206. case RBM_INSULT:
  2207. p = "insult";
  2208. break;
  2209. case RBM_SNEER:
  2210. p = "moan";
  2211. break;
  2212. case RBM_REQUEST:
  2213. p = "offer to trade";
  2214. break;
  2215. }
  2216. /* Default effect */
  2217. q = "???";
  2218. /* Acquire the effect */
  2219. switch (r_ptr->blow[j].effect) {
  2220. case RBE_HURT:
  2221. q = "attack";
  2222. break;
  2223. case RBE_POISON:
  2224. q = "poison";
  2225. break;
  2226. case RBE_UN_BONUS:
  2227. q = "disenchant";
  2228. break;
  2229. case RBE_UN_POWER:
  2230. q = "drain charges";
  2231. break;
  2232. case RBE_EAT_GOLD:
  2233. q = "steal gold";
  2234. break;
  2235. case RBE_EAT_ITEM:
  2236. q = "steal items";
  2237. break;
  2238. case RBE_EAT_FOOD:
  2239. q = "eat your food";
  2240. break;
  2241. case RBE_EAT_LIGHT:
  2242. q = "absorb light";
  2243. break;
  2244. case RBE_ACID:
  2245. q = "shoot acid";
  2246. break;
  2247. case RBE_ELEC:
  2248. q = "electrify";
  2249. break;
  2250. case RBE_FIRE:
  2251. q = "burn";
  2252. break;
  2253. case RBE_COLD:
  2254. q = "freeze";
  2255. break;
  2256. case RBE_BLIND:
  2257. q = "blind";
  2258. break;
  2259. case RBE_CONFUSE:
  2260. q = "confuse";
  2261. break;
  2262. case RBE_TERRIFY:
  2263. q = "terrify";
  2264. break;
  2265. case RBE_PARALYZE:
  2266. q = "paralyze";
  2267. break;
  2268. case RBE_LOSE_STR:
  2269. q = "reduce strength";
  2270. break;
  2271. case RBE_LOSE_INT:
  2272. q = "reduce intelligence";
  2273. break;
  2274. case RBE_LOSE_WIS:
  2275. q = "reduce wisdom";
  2276. break;
  2277. case RBE_LOSE_DEX:
  2278. q = "reduce dexterity";
  2279. break;
  2280. case RBE_LOSE_CON:
  2281. q = "reduce constitution";
  2282. break;
  2283. case RBE_LOSE_CHR:
  2284. q = "reduce charisma";
  2285. break;
  2286. case RBE_LOSE_ALL:
  2287. q = "reduce all stats";
  2288. break;
  2289. case RBE_SHATTER:
  2290. q = "shatter";
  2291. break;
  2292. case RBE_EXP_10:
  2293. q = "lower experience (by 10d6+)";
  2294. break;
  2295. case RBE_EXP_20:
  2296. q = "lower experience (by 20d6+)";
  2297. break;
  2298. case RBE_EXP_40:
  2299. q = "lower experience (by 40d6+)";
  2300. break;
  2301. case RBE_EXP_80:
  2302. q = "lower experience (by 80d6+)";
  2303. break;
  2304. }
  2305. if (!k) {
  2306. spoil_out(wd_che[msex]);
  2307. spoil_out(" can ");
  2308. } else if (k < i - 1) {
  2309. spoil_out(", ");
  2310. } else {
  2311. spoil_out(", and ");
  2312. }
  2313. /* Describe the method */
  2314. spoil_out(p);
  2315. /* Describe the effect, if any */
  2316. if (r_ptr->blow[j].effect) {
  2317. spoil_out(" to ");
  2318. spoil_out(q);
  2319. if (r_ptr->blow[j].d_dice && r_ptr->blow[j].d_side) {
  2320. spoil_out(" with damage");
  2321. if (r_ptr->blow[j].d_side == 1)
  2322. sprintf(buf, " %d", r_ptr->blow[j].d_dice);
  2323. else
  2324. sprintf(buf, " %dd%d",
  2325. r_ptr->blow[j].d_dice,
  2326. r_ptr->blow[j].d_side);
  2327. spoil_out(buf);
  2328. }
  2329. }
  2330. k++;
  2331. }
  2332. if (k) {
  2333. spoil_out(". ");
  2334. } else if (rf_has(r_ptr->flags, RF_NEVER_BLOW)) {
  2335. sprintf(buf, "%s has no physical attacks. ", wd_che[msex]);
  2336. spoil_out(buf);
  2337. }
  2338. spoil_out(NULL);
  2339. }
  2340. /* Check for errors */
  2341. if (!file_close(fff)) {
  2342. msg("Cannot close spoiler file.");
  2343. return;
  2344. }
  2345. msg("Successfully created a spoiler file.");
  2346. }
  2347. /**
  2348. * Forward declare
  2349. */
  2350. extern void do_cmd_spoilers(void);
  2351. /**
  2352. * Create Spoiler files
  2353. */
  2354. void do_cmd_spoilers(void)
  2355. {
  2356. int ch;
  2357. struct keypress key;
  2358. /* Save screen */
  2359. screen_save();
  2360. /* Drop priv's */
  2361. safe_setuid_drop();
  2362. /* Interact */
  2363. while (1) {
  2364. /* Clear screen */
  2365. Term_clear();
  2366. /* Info */
  2367. prt("Create a spoiler file.", 2, 0);
  2368. /* Prompt for a file */
  2369. prt("(1) Brief Object Info (obj-desc.spo)", 5, 5);
  2370. prt("(2) Brief Artifact Info (artifact.spo) (unavailable)", 6, 5);
  2371. prt("(3) Brief Monster Info (mon-desc.spo)", 7, 5);
  2372. prt("(4) Full Monster Info (mon-info.spo)", 8, 5);
  2373. prt("(5) See what objects appear on this level (obj-gen.spo)", 10,
  2374. 5);
  2375. prt("(6) See what monsters appear on this level (mon-gen.spo)", 11,
  2376. 5);
  2377. /* Prompt */
  2378. prt("Command: ", 12, 0);
  2379. /* Get a choice */
  2380. key = inkey();
  2381. ch = key.code;
  2382. /* Escape */
  2383. if (ch == ESCAPE) {
  2384. break;
  2385. }
  2386. /* Option (1) */
  2387. else if (ch == '1') {
  2388. spoil_obj_desc("obj-desc.spo");
  2389. }
  2390. /* Option (2) */
  2391. else if (ch == '2') {
  2392. bell("I said unavailable!");
  2393. if (0)
  2394. spoil_artifact("artifact.spo");
  2395. }
  2396. /* Option (3) */
  2397. else if (ch == '3') {
  2398. spoil_mon_desc("mon-desc.spo");
  2399. }
  2400. /* Option (4) */
  2401. else if (ch == '4') {
  2402. spoil_mon_info("mon-info.spo");
  2403. }
  2404. /* Option (5) */
  2405. else if (ch == '5') {
  2406. spoil_obj_gen("obj-gen.spo");
  2407. }
  2408. /* Option (6) */
  2409. else if (ch == '6') {
  2410. spoil_mon_gen("mon-gen.spo");
  2411. }
  2412. /* Oops */
  2413. else {
  2414. bell("Illegal command for spoilers!");
  2415. }
  2416. /* Flush messages */
  2417. message_flush();
  2418. }
  2419. /* Grab priv's */
  2420. safe_setuid_grab();
  2421. /* Load screen */
  2422. screen_load();
  2423. }
  2424. #else
  2425. #ifdef MACINTOSH
  2426. static int i = 0;
  2427. #endif
  2428. #endif