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

/src/wizard1.c

https://github.com/NickMcConnell/Beleriand
C | 2954 lines | 1948 code | 525 blank | 481 comment | 572 complexity | 02deae2cea7e36ca32cab78fa1531faa MD5 | raw file

Large files files are truncated, but you can click here to view the full 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_pt

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