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

/src/monster/monster1.c

https://bitbucket.org/ekolis/jackband
C | 2042 lines | 1408 code | 323 blank | 311 comment | 412 complexity | 87a39863bef8e67259e977f96ca787a2 MD5 | raw file

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

  1. /*
  2. * File: monster1.c
  3. * Purpose: Monster description code.
  4. *
  5. * Copyright (c) 1997-2007 Ben Harrison, James E. Wilson, Robert A. Koeneke
  6. *
  7. * This work is free software; you can redistribute it and/or modify it
  8. * under the terms of either:
  9. *
  10. * a) the GNU General Public License as published by the Free Software
  11. * Foundation, version 2, or
  12. *
  13. * b) the "Angband licence":
  14. * This software may be copied and distributed for educational, research,
  15. * and not for profit purposes provided that this copyright and statement
  16. * are included in all such copies. Other copyrights may also apply.
  17. */
  18. #include "angband.h"
  19. #include "object/tvalsval.h"
  20. #include "monster/constants.h"
  21. /*
  22. * Pronoun arrays, by gender.
  23. */
  24. static cptr wd_he[3] = { "it", "he", "she" };
  25. static cptr wd_his[3] = { "its", "his", "her" };
  26. /*
  27. * Pluralizer. Args(count, singular, plural)
  28. */
  29. #define plural(c, s, p) (((c) == 1) ? (s) : (p))
  30. static void output_list(const char *list[], int num, byte attr)
  31. {
  32. int i;
  33. const char *conjunction = "and ";
  34. if (num < 0)
  35. {
  36. num = -num;
  37. conjunction = "or ";
  38. }
  39. for (i = 0; i < num; i++)
  40. {
  41. if (i)
  42. {
  43. if (num > 2)
  44. text_out(", ");
  45. else
  46. text_out(" ");
  47. if (i == num - 1)
  48. text_out(conjunction);
  49. }
  50. text_out_c(attr, list[i]);
  51. }
  52. }
  53. static void output_list_dam(const char *list[], int num, int col[], int dam[])
  54. {
  55. int i;
  56. const char *conjunction = "and ";
  57. if (num < 0)
  58. {
  59. num = -num;
  60. conjunction = "or ";
  61. }
  62. for (i = 0; i < num; i++)
  63. {
  64. if (i)
  65. {
  66. if (num > 2)
  67. text_out(", ");
  68. else
  69. text_out(" ");
  70. if (i == num - 1)
  71. text_out(conjunction);
  72. }
  73. text_out_c(col[i], list[i]);
  74. if(dam[i])
  75. {
  76. text_out_c(col[i], format(" (%d)", dam[i]));
  77. }
  78. }
  79. }
  80. static void output_desc_list(int msex, cptr intro, cptr list[], int n, byte attr)
  81. {
  82. if (n != 0)
  83. {
  84. /* Output intro */
  85. text_out(format("%^s %s ", wd_he[msex], intro));
  86. /* Output list */
  87. output_list(list, n, attr);
  88. /* Output end */
  89. text_out(". ");
  90. }
  91. }
  92. void get_attack_colors(int melee_colors[RBE_MAX], int spell_colors[RSF_MAX])
  93. {
  94. int i;
  95. bool known;
  96. bitflag f[OF_SIZE];
  97. player_state st;
  98. int tmp_col;
  99. calc_bonuses(inventory, &st, TRUE);
  100. /* Initialize the colors to green */
  101. for (i = 0; i < RBE_MAX; i++)
  102. melee_colors[i] = TERM_L_GREEN;
  103. for (i = 0; i < RSF_MAX; i++)
  104. spell_colors[i] = TERM_L_GREEN;
  105. /* Scan the inventory for potentially vulnerable items */
  106. for (i = 0; i < INVEN_TOTAL; i++)
  107. {
  108. object_type *o_ptr = &inventory[i];
  109. /* Only occupied slots */
  110. if (!o_ptr->k_idx) continue;
  111. object_flags_known(o_ptr, f);
  112. /* Don't reveal the nature of an object.
  113. * Assume the player is conservative with unknown items.
  114. */
  115. known = object_is_known(o_ptr);
  116. /* Drain charges - requires a charged item */
  117. if (i < INVEN_PACK && (!known || o_ptr->pval > 0) &&
  118. (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND))
  119. melee_colors[RBE_UN_POWER] = TERM_L_RED;
  120. /* Steal item - requires non-artifacts */
  121. if (i < INVEN_PACK && (!known || !artifact_p(o_ptr)) &&
  122. p_get_lev() + adj_dex_safe[st.stat_ind[A_DEX]] < 100)
  123. melee_colors[RBE_EAT_ITEM] = TERM_L_RED;
  124. /* Eat food - requries food */
  125. if (i < INVEN_PACK && o_ptr->tval == TV_FOOD)
  126. melee_colors[RBE_EAT_FOOD] = TERM_YELLOW;
  127. /* Eat light - requires a fuelled light */
  128. if (i == INVEN_LIGHT && !of_has(f, OF_NO_FUEL) &&
  129. o_ptr->timeout > 0)
  130. melee_colors[RBE_EAT_LIGHT] = TERM_YELLOW;
  131. /* Disenchantment - requires an enchanted item */
  132. if (i >= INVEN_WIELD && (!known || o_ptr->to_a > 0 ||
  133. o_ptr->to_h > 0 || o_ptr->to_d > 0) && !st.resist_disen)
  134. {
  135. melee_colors[RBE_UN_BONUS] = TERM_L_RED;
  136. spell_colors[RSF_BR_DISE] = TERM_L_RED;
  137. }
  138. }
  139. /* Acid */
  140. if (st.immune_acid)
  141. tmp_col = TERM_L_GREEN;
  142. else if (st.resist_acid)
  143. tmp_col = TERM_YELLOW;
  144. else
  145. tmp_col = TERM_ORANGE;
  146. melee_colors[RBE_ACID] = tmp_col;
  147. spell_colors[RSF_BR_ACID] = tmp_col;
  148. spell_colors[RSF_BO_ACID] = tmp_col;
  149. spell_colors[RSF_BA_ACID] = tmp_col;
  150. /* Cold and ice */
  151. if (st.immune_cold)
  152. tmp_col = TERM_L_GREEN;
  153. else if (st.resist_cold)
  154. tmp_col = TERM_YELLOW;
  155. else
  156. tmp_col = TERM_ORANGE;
  157. melee_colors[RBE_COLD] = tmp_col;
  158. spell_colors[RSF_BR_COLD] = tmp_col;
  159. spell_colors[RSF_BO_COLD] = tmp_col;
  160. spell_colors[RSF_BA_COLD] = tmp_col;
  161. spell_colors[RSF_BO_ICEE] = tmp_col;
  162. /* Elec */
  163. if (st.immune_elec)
  164. tmp_col = TERM_L_GREEN;
  165. else if (st.resist_elec)
  166. tmp_col = TERM_YELLOW;
  167. else
  168. tmp_col = TERM_ORANGE;
  169. melee_colors[RBE_ELEC] = tmp_col;
  170. spell_colors[RSF_BR_ELEC] = tmp_col;
  171. spell_colors[RSF_BO_ELEC] = tmp_col;
  172. spell_colors[RSF_BA_ELEC] = tmp_col;
  173. /* Fire */
  174. if (st.immune_fire)
  175. tmp_col = TERM_L_GREEN;
  176. else if (st.resist_fire)
  177. tmp_col = TERM_YELLOW;
  178. else
  179. tmp_col = TERM_ORANGE;
  180. melee_colors[RBE_FIRE] = tmp_col;
  181. spell_colors[RSF_BR_FIRE] = tmp_col;
  182. spell_colors[RSF_BO_FIRE] = tmp_col;
  183. spell_colors[RSF_BA_FIRE] = tmp_col;
  184. /* Poison */
  185. if (!st.resist_pois)
  186. {
  187. melee_colors[RBE_POISON] = TERM_ORANGE;
  188. spell_colors[RSF_BR_POIS] = TERM_ORANGE;
  189. spell_colors[RSF_BA_POIS] = TERM_ORANGE;
  190. }
  191. /* Nexus */
  192. if (!st.resist_nexus)
  193. {
  194. if(st.skills[SKILL_SAVE] < 100)
  195. spell_colors[RSF_BR_NEXU] = TERM_L_RED;
  196. else
  197. spell_colors[RSF_BR_NEXU] = TERM_YELLOW;
  198. }
  199. /* Nether */
  200. if (!st.resist_nethr)
  201. {
  202. spell_colors[RSF_BR_NETH] = TERM_ORANGE;
  203. spell_colors[RSF_BA_NETH] = TERM_ORANGE;
  204. spell_colors[RSF_BO_NETH] = TERM_ORANGE;
  205. }
  206. /* Inertia, gravity, and time */
  207. spell_colors[RSF_BR_INER] = TERM_ORANGE;
  208. spell_colors[RSF_BR_GRAV] = TERM_L_RED;
  209. spell_colors[RSF_BR_TIME] = TERM_L_RED;
  210. /* Sound, force, and plasma */
  211. if (!st.resist_sound)
  212. {
  213. spell_colors[RSF_BR_SOUN] = TERM_ORANGE;
  214. spell_colors[RSF_BR_WALL] = TERM_YELLOW;
  215. spell_colors[RSF_BR_PLAS] = TERM_ORANGE;
  216. spell_colors[RSF_BO_PLAS] = TERM_ORANGE;
  217. }
  218. else
  219. {
  220. spell_colors[RSF_BR_PLAS] = TERM_YELLOW;
  221. spell_colors[RSF_BO_PLAS] = TERM_YELLOW;
  222. }
  223. /* Shards */
  224. if(!st.resist_shard)
  225. spell_colors[RSF_BR_SHAR] = TERM_ORANGE;
  226. /* Confusion */
  227. if (!st.resist_confu)
  228. {
  229. melee_colors[RBE_CONFUSE] = TERM_ORANGE;
  230. spell_colors[RSF_BR_CONF] = TERM_ORANGE;
  231. }
  232. /* Chaos */
  233. if (!st.resist_chaos)
  234. spell_colors[RSF_BR_CHAO] = TERM_ORANGE;
  235. /* Light */
  236. if (!st.resist_light)
  237. spell_colors[RSF_BR_LIGHT] = TERM_ORANGE;
  238. /* Darkness */
  239. if (!st.resist_dark)
  240. {
  241. spell_colors[RSF_BR_DARK] = TERM_ORANGE;
  242. spell_colors[RSF_BA_DARK] = TERM_L_RED;
  243. }
  244. /* Water */
  245. if (!st.resist_confu || !st.resist_sound)
  246. {
  247. spell_colors[RSF_BA_WATE] = TERM_L_RED;
  248. spell_colors[RSF_BO_WATE] = TERM_L_RED;
  249. }
  250. else
  251. {
  252. spell_colors[RSF_BA_WATE] = TERM_ORANGE;
  253. spell_colors[RSF_BO_WATE] = TERM_ORANGE;
  254. }
  255. /* Mana */
  256. spell_colors[RSF_BR_MANA] = TERM_L_RED;
  257. spell_colors[RSF_BA_MANA] = TERM_L_RED;
  258. spell_colors[RSF_BO_MANA] = TERM_L_RED;
  259. /* These attacks only apply without a perfect save */
  260. if (st.skills[SKILL_SAVE] < 100)
  261. {
  262. /* Amnesia */
  263. spell_colors[RSF_FORGET] = TERM_YELLOW;
  264. /* Fear */
  265. if (!st.resist_fear)
  266. {
  267. melee_colors[RBE_TERRIFY] = TERM_YELLOW;
  268. spell_colors[RSF_SCARE] = TERM_YELLOW;
  269. }
  270. /* Paralysis and slow */
  271. if (!st.free_act)
  272. {
  273. melee_colors[RBE_PARALYZE] = TERM_L_RED;
  274. spell_colors[RSF_HOLD] = TERM_L_RED;
  275. spell_colors[RSF_SLOW] = TERM_ORANGE;
  276. }
  277. /* Blind */
  278. if (!st.resist_blind)
  279. spell_colors[RSF_BLIND] = TERM_ORANGE;
  280. /* Confusion */
  281. if (!st.resist_confu)
  282. spell_colors[RSF_CONF] = TERM_ORANGE;
  283. /* Cause wounds */
  284. spell_colors[RSF_CAUSE_1] = TERM_YELLOW;
  285. spell_colors[RSF_CAUSE_2] = TERM_YELLOW;
  286. spell_colors[RSF_CAUSE_3] = TERM_YELLOW;
  287. spell_colors[RSF_CAUSE_4] = TERM_YELLOW;
  288. /* Mind blast */
  289. spell_colors[RSF_MIND_BLAST] = (st.resist_confu ?
  290. TERM_YELLOW : TERM_ORANGE);
  291. /* Brain smash slows even when conf/blind resisted */
  292. spell_colors[RSF_BRAIN_SMASH] = (st.resist_blind && st.free_act &&
  293. st.resist_confu ? TERM_ORANGE : TERM_L_RED);
  294. }
  295. /* Gold theft */
  296. if (p_get_lev() + adj_dex_safe[st.stat_ind[A_DEX]] < 100 && p_ptr->au)
  297. melee_colors[RBE_EAT_GOLD] = TERM_YELLOW;
  298. /* Melee blindness and hallucinations */
  299. if (!st.resist_blind)
  300. melee_colors[RBE_BLIND] = TERM_YELLOW;
  301. if (!st.resist_chaos)
  302. melee_colors[RBE_HALLU] = TERM_YELLOW;
  303. /* Stat draining is bad */
  304. if (!st.sustain_str) melee_colors[RBE_LOSE_STR] = TERM_ORANGE;
  305. if (!st.sustain_int) melee_colors[RBE_LOSE_INT] = TERM_ORANGE;
  306. if (!st.sustain_wis) melee_colors[RBE_LOSE_WIS] = TERM_ORANGE;
  307. if (!st.sustain_dex) melee_colors[RBE_LOSE_DEX] = TERM_ORANGE;
  308. if (!st.sustain_con) melee_colors[RBE_LOSE_CON] = TERM_ORANGE;
  309. if (!st.sustain_chr) melee_colors[RBE_LOSE_CHR] = TERM_ORANGE;
  310. /* Drain all gets a red warning */
  311. if (!st.sustain_str || !st.sustain_int || !st.sustain_wis ||
  312. !st.sustain_dex || !st.sustain_con || !st.sustain_chr)
  313. melee_colors[RBE_LOSE_ALL] = TERM_L_RED;
  314. /* Hold life isn't 100% effective */
  315. melee_colors[RBE_EXP_10] = melee_colors[RBE_EXP_20] =
  316. melee_colors[RBE_EXP_40] = melee_colors[RBE_EXP_80] =
  317. st.hold_life ? TERM_YELLOW : TERM_ORANGE;
  318. /* Shatter is always noteworthy */
  319. melee_colors[RBE_SHATTER] = TERM_YELLOW;
  320. /* Heal (and drain mana) and haste are always noteworthy */
  321. spell_colors[RSF_HEAL] = TERM_YELLOW;
  322. spell_colors[RSF_DRAIN_MANA] = TERM_YELLOW;
  323. spell_colors[RSF_HASTE] = TERM_YELLOW;
  324. /* Player teleports and traps are annoying */
  325. spell_colors[RSF_TELE_TO] = TERM_YELLOW;
  326. spell_colors[RSF_TELE_AWAY] = TERM_YELLOW;
  327. if (!st.resist_nexus && st.skills[SKILL_SAVE] < 100)
  328. spell_colors[RSF_TELE_LEVEL] = TERM_YELLOW;
  329. spell_colors[RSF_TRAPS] = TERM_YELLOW;
  330. /* Summons are potentially dangerous */
  331. spell_colors[RSF_S_MONSTER] = TERM_ORANGE;
  332. spell_colors[RSF_S_MONSTERS] = TERM_ORANGE;
  333. spell_colors[RSF_S_KIN] = TERM_ORANGE;
  334. spell_colors[RSF_S_ANIMAL] = TERM_ORANGE;
  335. spell_colors[RSF_S_SPIDER] = TERM_ORANGE;
  336. spell_colors[RSF_S_HOUND] = TERM_ORANGE;
  337. spell_colors[RSF_S_HYDRA] = TERM_ORANGE;
  338. spell_colors[RSF_S_ANGEL] = TERM_ORANGE;
  339. spell_colors[RSF_S_DEMON] = TERM_ORANGE;
  340. spell_colors[RSF_S_DRAGON] = TERM_ORANGE;
  341. spell_colors[RSF_S_UNDEAD] = TERM_ORANGE;
  342. /* High level summons are very dangerous */
  343. spell_colors[RSF_S_HI_DEMON] = TERM_L_RED;
  344. spell_colors[RSF_S_HI_DRAGON] = TERM_L_RED;
  345. spell_colors[RSF_S_HI_UNDEAD] = TERM_L_RED;
  346. spell_colors[RSF_S_UNIQUE] = TERM_L_RED;
  347. spell_colors[RSF_S_WRAITH] = TERM_L_RED;
  348. /* Shrieking can lead to bad combos */
  349. spell_colors[RSF_SHRIEK] = TERM_ORANGE;
  350. /* Ranged attacks can't be resisted (only mitigated by accuracy)
  351. * They are colored yellow to indicate the damage is a hard value
  352. */
  353. spell_colors[RSF_ARROW_1] = TERM_YELLOW;
  354. spell_colors[RSF_ARROW_2] = TERM_YELLOW;
  355. spell_colors[RSF_ARROW_3] = TERM_YELLOW;
  356. spell_colors[RSF_ARROW_4] = TERM_YELLOW;
  357. spell_colors[RSF_BOULDER] = TERM_YELLOW;
  358. }
  359. /*
  360. * Determine if the "armor" is known
  361. * The higher the level, the fewer kills needed.
  362. */
  363. static bool know_armour(int r_idx, const monster_lore *l_ptr)
  364. {
  365. const monster_race *r_ptr = &r_info[r_idx];
  366. s32b level = r_ptr->level;
  367. s32b kills = l_ptr->tkills;
  368. /* Normal monsters */
  369. if (kills > 304 / (4 + level)) return (TRUE);
  370. /* Skip non-uniques */
  371. if (!rf_has(r_ptr->flags, RF_UNIQUE)) return (FALSE);
  372. /* Unique monsters */
  373. if (kills > 304 / (38 + (5 * level) / 4)) return (TRUE);
  374. /* Assume false */
  375. return (FALSE);
  376. }
  377. /*
  378. * Determine if the "damage" of the given attack is known
  379. * the higher the level of the monster, the fewer the attacks you need,
  380. * the more damage an attack does, the more attacks you need
  381. */
  382. static bool know_damage(int r_idx, const monster_lore *l_ptr, int i)
  383. {
  384. const monster_race *r_ptr = &r_info[r_idx];
  385. s32b level = r_ptr->level;
  386. s32b a = l_ptr->blows[i];
  387. s32b d1 = r_ptr->blow[i].d_dice;
  388. s32b d2 = r_ptr->blow[i].d_side;
  389. s32b d = d1 * d2;
  390. /* Normal monsters */
  391. if ((4 + level) * a >= 80 * d) return (TRUE);
  392. /* Skip non-uniques */
  393. if (!rf_has(r_ptr->flags, RF_UNIQUE)) return (FALSE);
  394. /* Unique monsters */
  395. if ((4 + level) * (2 * a) > 80 * d) return (TRUE);
  396. /* Assume false */
  397. return (FALSE);
  398. }
  399. /*
  400. * Dump flavour text
  401. */
  402. static void describe_monster_desc(int r_idx)
  403. {
  404. const monster_race *r_ptr = &r_info[r_idx];
  405. text_out("%s\n", r_text + r_ptr->text);
  406. }
  407. static void describe_monster_spells(int r_idx, const monster_lore *l_ptr, const int colors[RSF_MAX])
  408. {
  409. const monster_race *r_ptr = &r_info[r_idx];
  410. bitflag f[RF_SIZE];
  411. int m, n;
  412. int msex = 0;
  413. bool breath = FALSE;
  414. bool magic = FALSE;
  415. int vn; /* list size */
  416. cptr vp[64]; /* list item names */
  417. int vc[64]; /* list colors */
  418. int vd[64]; /* list avg damage values */
  419. int known_hp;
  420. /* Get the known monster flags */
  421. monster_flags_known(r_ptr, l_ptr, f);
  422. /* Extract a gender (if applicable) */
  423. if (rf_has(r_ptr->flags, RF_FEMALE)) msex = 2;
  424. else if (rf_has(r_ptr->flags, RF_MALE)) msex = 1;
  425. /* Collect innate attacks */
  426. vn = 0;
  427. for(m = 0; m < 64; m++) { vd[m] = 0; vc[m] = TERM_WHITE; }
  428. if (rsf_has(l_ptr->spell_flags, RSF_SHRIEK))
  429. {
  430. vp[vn] = "shriek for help";
  431. vc[vn++] = colors[RSF_SHRIEK];
  432. }
  433. if (rsf_has(l_ptr->spell_flags, RSF_ARROW_1))
  434. {
  435. vp[vn] = "fire an arrow";
  436. vc[vn] = colors[RSF_ARROW_1];
  437. vd[vn++] = ARROW1_DMG(r_ptr->level, AVERAGE);
  438. }
  439. if (rsf_has(l_ptr->spell_flags, RSF_ARROW_2))
  440. {
  441. vp[vn] = "fire arrows";
  442. vc[vn] = colors[RSF_ARROW_2];
  443. vd[vn++] = ARROW2_DMG(r_ptr->level, AVERAGE);
  444. }
  445. if (rsf_has(l_ptr->spell_flags, RSF_ARROW_3))
  446. {
  447. vp[vn] = "fire a missile";
  448. vc[vn] = colors[RSF_ARROW_3];
  449. vd[vn++] = ARROW3_DMG(r_ptr->level, AVERAGE);
  450. }
  451. if (rsf_has(l_ptr->spell_flags, RSF_ARROW_4))
  452. {
  453. vp[vn] = "fire missiles";
  454. vc[vn] = colors[RSF_ARROW_4];
  455. vd[vn++] = ARROW4_DMG(r_ptr->level, AVERAGE);
  456. }
  457. if (rsf_has(l_ptr->spell_flags, RSF_BOULDER))
  458. {
  459. vp[vn] = "throw boulders";
  460. vc[vn] = colors[RSF_BOULDER];
  461. vd[vn++] = BOULDER_DMG(r_ptr->level, AVERAGE);
  462. }
  463. /* Describe innate attacks */
  464. if(vn)
  465. {
  466. text_out("%^s may ", wd_he[msex]);
  467. output_list_dam(vp, -vn, vc, vd);
  468. text_out(". ");
  469. }
  470. /* Collect breaths */
  471. vn = 0;
  472. for(m = 0; m < 64; m++) { vd[m] = 0; vc[m] = TERM_WHITE; }
  473. known_hp = know_armour(r_idx, l_ptr) ? r_ptr->avg_hp : 0;
  474. if (rsf_has(l_ptr->spell_flags, RSF_BR_ACID))
  475. {
  476. vp[vn] = "acid";
  477. vc[vn] = colors[RSF_BR_ACID];
  478. vd[vn++] = MIN(known_hp / BR_ACID_DIVISOR, BR_ACID_MAX);
  479. }
  480. if (rsf_has(l_ptr->spell_flags, RSF_BR_ELEC))
  481. {
  482. vp[vn] = "lightning";
  483. vc[vn] = colors[RSF_BR_ELEC];
  484. vd[vn++] = MIN(known_hp / BR_ELEC_DIVISOR, BR_ELEC_MAX);
  485. }
  486. if (rsf_has(l_ptr->spell_flags, RSF_BR_FIRE))
  487. {
  488. vp[vn] = "fire";
  489. vc[vn] = colors[RSF_BR_FIRE];
  490. vd[vn++] = MIN(known_hp / BR_FIRE_DIVISOR, BR_FIRE_MAX);
  491. }
  492. if (rsf_has(l_ptr->spell_flags, RSF_BR_COLD))
  493. {
  494. vp[vn] = "frost";
  495. vc[vn] = colors[RSF_BR_COLD];
  496. vd[vn++] = MIN(known_hp / BR_COLD_DIVISOR, BR_COLD_MAX);
  497. }
  498. if (rsf_has(l_ptr->spell_flags, RSF_BR_POIS))
  499. {
  500. vp[vn] = "poison";
  501. vc[vn] = colors[RSF_BR_POIS];
  502. vd[vn++] = MIN(known_hp / BR_POIS_DIVISOR, BR_POIS_MAX);
  503. }
  504. if (rsf_has(l_ptr->spell_flags, RSF_BR_NETH))
  505. {
  506. vp[vn] = "nether";
  507. vc[vn] = colors[RSF_BR_NETH];
  508. vd[vn++] = MIN(known_hp / BR_NETH_DIVISOR, BR_NETH_MAX);
  509. }
  510. if (rsf_has(l_ptr->spell_flags, RSF_BR_LIGHT))
  511. {
  512. vp[vn] = "light";
  513. vc[vn] = colors[RSF_BR_LIGHT];
  514. vd[vn++] = MIN(known_hp / BR_LIGHT_DIVISOR, BR_LIGHT_MAX);
  515. }
  516. if (rsf_has(l_ptr->spell_flags, RSF_BR_DARK))
  517. {
  518. vp[vn] = "darkness";
  519. vc[vn] = colors[RSF_BR_DARK];
  520. vd[vn++] = MIN(known_hp / BR_DARK_DIVISOR, BR_DARK_MAX);
  521. }
  522. if (rsf_has(l_ptr->spell_flags, RSF_BR_CONF))
  523. {
  524. vp[vn] = "confusion";
  525. vc[vn] = colors[RSF_BR_CONF];
  526. vd[vn++] = MIN(known_hp / BR_CONF_DIVISOR, BR_CONF_MAX);
  527. }
  528. if (rsf_has(l_ptr->spell_flags, RSF_BR_SOUN))
  529. {
  530. vp[vn] = "sound";
  531. vc[vn] = colors[RSF_BR_SOUN];
  532. vd[vn++] = MIN(known_hp / BR_SOUN_DIVISOR, BR_SOUN_MAX);
  533. }
  534. if (rsf_has(l_ptr->spell_flags, RSF_BR_CHAO))
  535. {
  536. vp[vn] = "chaos";
  537. vc[vn] = colors[RSF_BR_CHAO];
  538. vd[vn++] = MIN(known_hp / BR_CHAO_DIVISOR, BR_CHAO_MAX);
  539. }
  540. if (rsf_has(l_ptr->spell_flags, RSF_BR_DISE))
  541. {
  542. vp[vn] = "disenchantment";
  543. vc[vn] = colors[RSF_BR_DISE];
  544. vd[vn++] = MIN(known_hp / BR_DISE_DIVISOR, BR_DISE_MAX);
  545. }
  546. if (rsf_has(l_ptr->spell_flags, RSF_BR_NEXU))
  547. {
  548. vp[vn] = "nexus";
  549. vc[vn] = colors[RSF_BR_NEXU];
  550. vd[vn++] = MIN(known_hp / BR_NEXU_DIVISOR, BR_NEXU_MAX);
  551. }
  552. if (rsf_has(l_ptr->spell_flags, RSF_BR_TIME))
  553. {
  554. vp[vn] = "time";
  555. vc[vn] = colors[RSF_BR_TIME];
  556. vd[vn++] = MIN(known_hp / BR_TIME_DIVISOR, BR_TIME_MAX);
  557. }
  558. if (rsf_has(l_ptr->spell_flags, RSF_BR_INER))
  559. {
  560. vp[vn] = "inertia";
  561. vc[vn] = colors[RSF_BR_INER];
  562. vd[vn++] = MIN(known_hp / BR_INER_DIVISOR, BR_INER_MAX);
  563. }
  564. if (rsf_has(l_ptr->spell_flags, RSF_BR_GRAV))
  565. {
  566. vp[vn] = "gravity";
  567. vc[vn] = colors[RSF_BR_GRAV];
  568. vd[vn++] = MIN(known_hp / BR_GRAV_DIVISOR, BR_GRAV_MAX);
  569. }
  570. if (rsf_has(l_ptr->spell_flags, RSF_BR_SHAR))
  571. {
  572. vp[vn] = "shards";
  573. vc[vn] = colors[RSF_BR_SHAR];
  574. vd[vn++] = MIN(known_hp / BR_SHAR_DIVISOR, BR_SHAR_MAX);
  575. }
  576. if (rsf_has(l_ptr->spell_flags, RSF_BR_PLAS))
  577. {
  578. vp[vn] = "plasma";
  579. vc[vn] = colors[RSF_BR_PLAS];
  580. vd[vn++] = MIN(known_hp / BR_PLAS_DIVISOR, BR_PLAS_MAX);
  581. }
  582. if (rsf_has(l_ptr->spell_flags, RSF_BR_WALL))
  583. {
  584. vp[vn] = "force";
  585. vc[vn] = colors[RSF_BR_WALL];
  586. vd[vn++] = MIN(known_hp / BR_FORC_DIVISOR, BR_FORC_MAX);
  587. }
  588. if (rsf_has(l_ptr->spell_flags, RSF_BR_MANA))
  589. {
  590. vp[vn] = "mana";
  591. vc[vn] = colors[RSF_BR_MANA];
  592. vd[vn++] = 0;
  593. }
  594. /* Describe breaths */
  595. if (vn)
  596. {
  597. /* Note breath */
  598. breath = TRUE;
  599. /* Display */
  600. text_out("%^s may ", wd_he[msex]);
  601. text_out_c(TERM_L_RED, "breathe ");
  602. output_list_dam(vp, -vn, vc, vd);
  603. }
  604. /* Collect spell information */
  605. vn = 0;
  606. for(m = 0; m < 64; m++) { vd[m] = 0; vc[m] = TERM_WHITE; }
  607. /* Ball spells */
  608. if (rsf_has(l_ptr->spell_flags, RSF_BA_MANA))
  609. {
  610. vp[vn] = "invoke mana storms";
  611. vc[vn] = colors[RSF_BA_MANA];
  612. vd[vn++] = BA_MANA_DMG(r_ptr->level, AVERAGE);
  613. }
  614. if (rsf_has(l_ptr->spell_flags, RSF_BA_DARK))
  615. {
  616. vp[vn] = "invoke darkness storms";
  617. vc[vn] = colors[RSF_BA_DARK];
  618. vd[vn++] = BA_DARK_DMG(r_ptr->level, AVERAGE);
  619. }
  620. if (rsf_has(l_ptr->spell_flags, RSF_BA_WATE))
  621. {
  622. vp[vn] = "produce water balls";
  623. vc[vn] = colors[RSF_BA_WATE];
  624. vd[vn++] = BA_WATE_DMG(r_ptr->level, AVERAGE);
  625. }
  626. if (rsf_has(l_ptr->spell_flags, RSF_BA_NETH))
  627. {
  628. vp[vn] = "produce nether balls";
  629. vc[vn] = colors[RSF_BA_NETH];
  630. vd[vn++] = BA_NETH_DMG(r_ptr->level, AVERAGE);
  631. }
  632. if (rsf_has(l_ptr->spell_flags, RSF_BA_FIRE))
  633. {
  634. vp[vn] = "produce fire balls";
  635. vc[vn] = colors[RSF_BA_FIRE];
  636. vd[vn++] = BA_FIRE_DMG(r_ptr->level, AVERAGE);
  637. }
  638. if (rsf_has(l_ptr->spell_flags, RSF_BA_ACID))
  639. {
  640. vp[vn] = "produce acid balls";
  641. vc[vn] = colors[RSF_BA_ACID];
  642. vd[vn++] = BA_ACID_DMG(r_ptr->level, AVERAGE);
  643. }
  644. if (rsf_has(l_ptr->spell_flags, RSF_BA_COLD))
  645. {
  646. vp[vn] = "produce frost balls";
  647. vc[vn] = colors[RSF_BA_COLD];
  648. vd[vn++] = BA_COLD_DMG(r_ptr->level, AVERAGE);
  649. }
  650. if (rsf_has(l_ptr->spell_flags, RSF_BA_ELEC))
  651. {
  652. vp[vn] = "produce lightning balls";
  653. vc[vn] = colors[RSF_BA_ELEC];
  654. vd[vn++] = BA_ELEC_DMG(r_ptr->level, AVERAGE);
  655. }
  656. if (rsf_has(l_ptr->spell_flags, RSF_BA_POIS))
  657. {
  658. vp[vn] = "produce poison balls";
  659. vc[vn] = colors[RSF_BA_POIS];
  660. vd[vn++] = BA_POIS_DMG(r_ptr->level, AVERAGE);
  661. }
  662. /* Bolt spells */
  663. if (rsf_has(l_ptr->spell_flags, RSF_BO_MANA))
  664. {
  665. vp[vn] = "produce mana bolts";
  666. vc[vn] = colors[RSF_BO_MANA];
  667. vd[vn++] = BO_MANA_DMG(r_ptr->level, AVERAGE);
  668. }
  669. if (rsf_has(l_ptr->spell_flags, RSF_BO_PLAS))
  670. {
  671. vp[vn] = "produce plasma bolts";
  672. vc[vn] = colors[RSF_BO_PLAS];
  673. vd[vn++] = BO_PLAS_DMG(r_ptr->level, AVERAGE);
  674. }
  675. if (rsf_has(l_ptr->spell_flags, RSF_BO_ICEE))
  676. {
  677. vp[vn] = "produce ice bolts";
  678. vc[vn] = colors[RSF_BO_ICEE];
  679. vd[vn++] = BO_ICEE_DMG(r_ptr->level, AVERAGE);
  680. }
  681. if (rsf_has(l_ptr->spell_flags, RSF_BO_WATE))
  682. {
  683. vp[vn] = "produce water bolts";
  684. vc[vn] = colors[RSF_BO_WATE];
  685. vd[vn++] = BO_WATE_DMG(r_ptr->level, AVERAGE);
  686. }
  687. if (rsf_has(l_ptr->spell_flags, RSF_BO_NETH))
  688. {
  689. vp[vn] = "produce nether bolts";
  690. vc[vn] = colors[RSF_BO_NETH];
  691. vd[vn++] = BO_NETH_DMG(r_ptr->level, AVERAGE);
  692. }
  693. if (rsf_has(l_ptr->spell_flags, RSF_BO_FIRE))
  694. {
  695. vp[vn] = "produce fire bolts";
  696. vc[vn] = colors[RSF_BO_FIRE];
  697. vd[vn++] = BO_FIRE_DMG(r_ptr->level, AVERAGE);
  698. }
  699. if (rsf_has(l_ptr->spell_flags, RSF_BO_ACID))
  700. {
  701. vp[vn] = "produce acid bolts";
  702. vc[vn] = colors[RSF_BO_ACID];
  703. vd[vn++] = BO_ACID_DMG(r_ptr->level, AVERAGE);
  704. }
  705. if (rsf_has(l_ptr->spell_flags, RSF_BO_COLD))
  706. {
  707. vp[vn] = "produce frost bolts";
  708. vc[vn] = colors[RSF_BO_COLD];
  709. vd[vn++] = BO_COLD_DMG(r_ptr->level, AVERAGE);
  710. }
  711. if (rsf_has(l_ptr->spell_flags, RSF_BO_ELEC))
  712. {
  713. vp[vn] = "produce lightning bolts";
  714. vc[vn] = colors[RSF_BO_ELEC];
  715. vd[vn++] = BO_ELEC_DMG(r_ptr->level, AVERAGE);
  716. }
  717. if (rsf_has(l_ptr->spell_flags, RSF_BO_POIS))
  718. {
  719. vp[vn] = "produce poison bolts";
  720. vc[vn] = colors[RSF_BO_POIS];
  721. vd[vn++] = 0;
  722. }
  723. if (rsf_has(l_ptr->spell_flags, RSF_MISSILE))
  724. {
  725. vp[vn] = "produce magic missiles";
  726. vc[vn] = colors[RSF_MISSILE];
  727. vd[vn++] = MISSILE_DMG(r_ptr->level, AVERAGE);
  728. }
  729. /* Curses */
  730. if (rsf_has(l_ptr->spell_flags, RSF_BRAIN_SMASH))
  731. {
  732. vp[vn] = "cause brain smashing";
  733. vc[vn] = colors[RSF_BRAIN_SMASH];
  734. vd[vn++] = BRAIN_SMASH_DMG(r_ptr->level, AVERAGE);
  735. }
  736. if (rsf_has(l_ptr->spell_flags, RSF_MIND_BLAST))
  737. {
  738. vp[vn] = "cause mind blasting";
  739. vc[vn] = colors[RSF_MIND_BLAST];
  740. vd[vn++] = MIND_BLAST_DMG(r_ptr->level, AVERAGE);
  741. }
  742. if (rsf_has(l_ptr->spell_flags, RSF_CAUSE_4))
  743. {
  744. vp[vn] = "cause mortal wounds";
  745. vc[vn] = colors[RSF_CAUSE_4];
  746. vd[vn++] = CAUSE4_DMG(r_ptr->level, AVERAGE);
  747. }
  748. if (rsf_has(l_ptr->spell_flags, RSF_CAUSE_3))
  749. {
  750. vp[vn] = "cause critical wounds";
  751. vc[vn] = colors[RSF_CAUSE_3];
  752. vd[vn++] = CAUSE3_DMG(r_ptr->level, AVERAGE);
  753. }
  754. if (rsf_has(l_ptr->spell_flags, RSF_CAUSE_2))
  755. {
  756. vp[vn] = "cause serious wounds";
  757. vc[vn] = colors[RSF_CAUSE_2];
  758. vd[vn++] = CAUSE2_DMG(r_ptr->level, AVERAGE);
  759. }
  760. if (rsf_has(l_ptr->spell_flags, RSF_CAUSE_1))
  761. {
  762. vp[vn] = "cause light wounds";
  763. vc[vn] = colors[RSF_CAUSE_1];
  764. vd[vn++] = CAUSE1_DMG(r_ptr->level, AVERAGE);
  765. }
  766. if (rsf_has(l_ptr->spell_flags, RSF_FORGET))
  767. {
  768. vp[vn] = "cause amnesia";
  769. vc[vn++] = colors[RSF_FORGET];
  770. }
  771. if (rsf_has(l_ptr->spell_flags, RSF_SCARE))
  772. {
  773. vp[vn] = "terrify";
  774. vc[vn++] = colors[RSF_SCARE];
  775. }
  776. if (rsf_has(l_ptr->spell_flags, RSF_BLIND))
  777. {
  778. vp[vn] = "blind";
  779. vc[vn++] = colors[RSF_BLIND];
  780. }
  781. if (rsf_has(l_ptr->spell_flags, RSF_CONF))
  782. {
  783. vp[vn] = "confuse";
  784. vc[vn++] = colors[RSF_CONF];
  785. }
  786. if (rsf_has(l_ptr->spell_flags, RSF_SLOW))
  787. {
  788. vp[vn] = "slow";
  789. vc[vn++] = colors[RSF_SLOW];
  790. }
  791. if (rsf_has(l_ptr->spell_flags, RSF_HOLD))
  792. {
  793. vp[vn] = "paralyze";
  794. vc[vn++] = colors[RSF_HOLD];
  795. }
  796. /* Healing and haste */
  797. if (rsf_has(l_ptr->spell_flags, RSF_DRAIN_MANA))
  798. {
  799. vp[vn] = "drain mana";
  800. vc[vn++] = colors[RSF_DRAIN_MANA];
  801. }
  802. if (rsf_has(l_ptr->spell_flags, RSF_HEAL))
  803. {
  804. vp[vn] = "heal-self";
  805. vc[vn++] = colors[RSF_HEAL];
  806. }
  807. if (rsf_has(l_ptr->spell_flags, RSF_HASTE))
  808. {
  809. vp[vn] = "haste-self";
  810. vc[vn++] = colors[RSF_HASTE];
  811. }
  812. /* Teleports */
  813. if (rsf_has(l_ptr->spell_flags, RSF_BLINK))
  814. {
  815. vp[vn] = "blink-self";
  816. vc[vn++] = colors[RSF_BLINK];
  817. }
  818. if (rsf_has(l_ptr->spell_flags, RSF_TPORT))
  819. {
  820. vp[vn] = "teleport-self";
  821. vc[vn++] = colors[RSF_TPORT];
  822. }
  823. if (rsf_has(l_ptr->spell_flags, RSF_TELE_TO))
  824. {
  825. vp[vn] = "teleport to";
  826. vc[vn++] = colors[RSF_TELE_TO];
  827. }
  828. if (rsf_has(l_ptr->spell_flags, RSF_TELE_AWAY))
  829. {
  830. vp[vn] = "teleport away";
  831. vc[vn++] = colors[RSF_TELE_AWAY];
  832. }
  833. if (rsf_has(l_ptr->spell_flags, RSF_TELE_LEVEL))
  834. {
  835. vp[vn] = "teleport level";
  836. vc[vn++] = colors[RSF_TELE_LEVEL];
  837. }
  838. /* Annoyances */
  839. if (rsf_has(l_ptr->spell_flags, RSF_DARKNESS))
  840. {
  841. vp[vn] = "create darkness";
  842. vc[vn++] = colors[RSF_DARKNESS];
  843. }
  844. if (rsf_has(l_ptr->spell_flags, RSF_TRAPS))
  845. {
  846. vp[vn] = "create traps";
  847. vc[vn++] = colors[RSF_TRAPS];
  848. }
  849. /* Summoning */
  850. if (rsf_has(l_ptr->spell_flags, RSF_S_KIN))
  851. {
  852. vp[vn] = "summon similar monsters";
  853. vc[vn++] = colors[RSF_S_KIN];
  854. }
  855. if (rsf_has(l_ptr->spell_flags, RSF_S_MONSTER))
  856. {
  857. vp[vn] = "summon a monster";
  858. vc[vn++] = colors[RSF_S_MONSTER];
  859. }
  860. if (rsf_has(l_ptr->spell_flags, RSF_S_MONSTERS))
  861. {
  862. vp[vn] = "summon monsters";
  863. vc[vn++] = colors[RSF_S_MONSTERS];
  864. }
  865. if (rsf_has(l_ptr->spell_flags, RSF_S_ANIMAL))
  866. {
  867. vp[vn] = "summon animals";
  868. vc[vn++] = colors[RSF_S_ANIMAL];
  869. }
  870. if (rsf_has(l_ptr->spell_flags, RSF_S_SPIDER))
  871. {
  872. vp[vn] = "summon spiders";
  873. vc[vn++] = colors[RSF_S_SPIDER];
  874. }
  875. if (rsf_has(l_ptr->spell_flags, RSF_S_HOUND))
  876. {
  877. vp[vn] = "summon hounds";
  878. vc[vn++] = colors[RSF_S_HOUND];
  879. }
  880. if (rsf_has(l_ptr->spell_flags, RSF_S_HYDRA))
  881. {
  882. vp[vn] = "summon hydras";
  883. vc[vn++] = colors[RSF_S_HYDRA];
  884. }
  885. if (rsf_has(l_ptr->spell_flags, RSF_S_ANGEL))
  886. {
  887. vp[vn] = "summon an angel";
  888. vc[vn++] = colors[RSF_S_ANGEL];
  889. }
  890. if (rsf_has(l_ptr->spell_flags, RSF_S_DEMON))
  891. {
  892. vp[vn] = "summon a demon";
  893. vc[vn++] = colors[RSF_S_DEMON];
  894. }
  895. if (rsf_has(l_ptr->spell_flags, RSF_S_UNDEAD))
  896. {
  897. vp[vn] = "summon an undead";
  898. vc[vn++] = colors[RSF_S_UNDEAD];
  899. }
  900. if (rsf_has(l_ptr->spell_flags, RSF_S_DRAGON))
  901. {
  902. vp[vn] = "summon a dragon";
  903. vc[vn++] = colors[RSF_S_DRAGON];
  904. }
  905. if (rsf_has(l_ptr->spell_flags, RSF_S_HI_UNDEAD))
  906. {
  907. vp[vn] = "summon greater undead";
  908. vc[vn++] = colors[RSF_S_HI_UNDEAD];
  909. }
  910. if (rsf_has(l_ptr->spell_flags, RSF_S_HI_DRAGON))
  911. {
  912. vp[vn] = "summon ancient dragons";
  913. vc[vn++] = colors[RSF_S_HI_DRAGON];
  914. }
  915. if (rsf_has(l_ptr->spell_flags, RSF_S_HI_DEMON))
  916. {
  917. vp[vn] = "summon greater demons";
  918. vc[vn++] = colors[RSF_S_HI_DEMON];
  919. }
  920. if (rsf_has(l_ptr->spell_flags, RSF_S_WRAITH))
  921. {
  922. vp[vn] = "summon ringwraiths";
  923. vc[vn++] = colors[RSF_S_WRAITH];
  924. }
  925. if (rsf_has(l_ptr->spell_flags, RSF_S_UNIQUE))
  926. {
  927. vp[vn] = "summon uniques";
  928. vc[vn++] = colors[RSF_S_UNIQUE];
  929. }
  930. /* Describe spells */
  931. if (vn)
  932. {
  933. /* Note magic */
  934. magic = TRUE;
  935. /* Intro */
  936. if (breath)
  937. text_out(", and may ");
  938. else
  939. text_out("%^s may ", wd_he[msex]);
  940. /* Verb Phrase */
  941. text_out_c(TERM_L_RED, "cast spells");
  942. /* Adverb */
  943. if (rf_has(f, RF_SMART)) text_out(" intelligently");
  944. /* List */
  945. text_out(" which ");
  946. output_list_dam(vp, -vn, vc, vd);
  947. }
  948. /* End the sentence about innate/other spells */
  949. if (breath || magic)
  950. {
  951. /* Total casting */
  952. m = l_ptr->cast_innate + l_ptr->cast_spell;
  953. /* Average frequency */
  954. n = (r_ptr->freq_innate + r_ptr->freq_spell) / 2;
  955. /* Describe the spell frequency */
  956. if (m > 100)
  957. {
  958. text_out("; ");
  959. text_out_c(TERM_L_GREEN, "1");
  960. text_out(" time in ");
  961. text_out_c(TERM_L_GREEN, "%d", 100 / n);
  962. }
  963. /* Guess at the frequency */
  964. else if (m)
  965. {
  966. n = ((n + 9) / 10) * 10;
  967. text_out("; about ");
  968. text_out_c(TERM_L_GREEN, "1");
  969. text_out(" time in ");
  970. text_out_c(TERM_L_GREEN, "%d", 100 / n);
  971. }
  972. /* End this sentence */
  973. text_out(". ");
  974. }
  975. }
  976. /*
  977. * Describe a monster's drop.
  978. */
  979. static void describe_monster_drop(int r_idx, const monster_lore *l_ptr)
  980. {
  981. const monster_race *r_ptr = &r_info[r_idx];
  982. bitflag f[RF_SIZE];
  983. int n;
  984. int msex = 0;
  985. /* Get the known monster flags */
  986. monster_flags_known(r_ptr, l_ptr, f);
  987. /* Extract a gender (if applicable) */
  988. if (rf_has(r_ptr->flags, RF_FEMALE)) msex = 2;
  989. else if (rf_has(r_ptr->flags, RF_MALE)) msex = 1;
  990. /* Drops gold and/or items */
  991. if (l_ptr->drop_gold || l_ptr->drop_item)
  992. {
  993. /* Intro */
  994. text_out("%^s may carry", wd_he[msex]);
  995. /* Count maximum drop */
  996. n = MAX(l_ptr->drop_gold, l_ptr->drop_item);
  997. /* Count drops */
  998. if (n == 1) text_out_c(TERM_BLUE, " a single ");
  999. else if (n == 2) text_out_c(TERM_BLUE, " one or two ");
  1000. else
  1001. {
  1002. text_out(" up to ");
  1003. text_out_c(TERM_BLUE, format("%d ", n));
  1004. }
  1005. /* Quality */
  1006. if (rf_has(f, RF_DROP_GREAT)) text_out_c(TERM_BLUE, "exceptional ");
  1007. else if (rf_has(f, RF_DROP_GOOD)) text_out_c(TERM_BLUE, "good ");
  1008. /* Objects */
  1009. if (l_ptr->drop_item)
  1010. {
  1011. /* Dump "object(s)" */
  1012. text_out_c(TERM_BLUE, "object%s", PLURAL(n));
  1013. /* Add conjunction if also dropping gold */
  1014. if (l_ptr->drop_gold) text_out_c(TERM_BLUE, " or ");
  1015. }
  1016. /* Treasures */
  1017. if (l_ptr->drop_gold)
  1018. {
  1019. /* Dump "treasure(s)" */
  1020. text_out_c(TERM_BLUE, "treasure%s", PLURAL(n));
  1021. }
  1022. /* End this sentence */
  1023. text_out(". ");
  1024. }
  1025. }
  1026. /*
  1027. * Describe all of a monster's attacks.
  1028. */
  1029. static void describe_monster_attack(int r_idx, const monster_lore *l_ptr, const int colors[RBE_MAX])
  1030. {
  1031. const monster_race *r_ptr = &r_info[r_idx];
  1032. bitflag f[RF_SIZE];
  1033. int m, n, r;
  1034. int msex = 0;
  1035. /* Get the known monster flags */
  1036. monster_flags_known(r_ptr, l_ptr, f);
  1037. /* Extract a gender (if applicable) */
  1038. if (rf_has(r_ptr->flags, RF_FEMALE)) msex = 2;
  1039. else if (rf_has(r_ptr->flags, RF_MALE)) msex = 1;
  1040. /* Count the number of "known" attacks */
  1041. for (n = 0, m = 0; m < MONSTER_BLOW_MAX; m++)
  1042. {
  1043. /* Skip non-attacks */
  1044. if (!r_ptr->blow[m].method) continue;
  1045. /* Count known attacks */
  1046. if (l_ptr->blows[m]) n++;
  1047. }
  1048. /* Examine (and count) the actual attacks */
  1049. for (r = 0, m = 0; m < MONSTER_BLOW_MAX; m++)
  1050. {
  1051. int method, effect, d1, d2;
  1052. const char *p = NULL;
  1053. const char *q = NULL;
  1054. /* Skip unknown and undefined attacks */
  1055. if (!r_ptr->blow[m].method || !l_ptr->blows[m]) continue;
  1056. /* Extract the attack info */
  1057. method = r_ptr->blow[m].method;
  1058. effect = r_ptr->blow[m].effect;
  1059. d1 = r_ptr->blow[m].d_dice;
  1060. d2 = r_ptr->blow[m].d_side;
  1061. /* Get the method */
  1062. switch (method)
  1063. {
  1064. case RBM_HIT: p = "hit"; break;
  1065. case RBM_TOUCH: p = "touch"; break;
  1066. case RBM_PUNCH: p = "punch"; break;
  1067. case RBM_KICK: p = "kick"; break;
  1068. case RBM_CLAW: p = "claw"; break;
  1069. case RBM_BITE: p = "bite"; break;
  1070. case RBM_STING: p = "sting"; break;
  1071. case RBM_BUTT: p = "butt"; break;
  1072. case RBM_CRUSH: p = "crush"; break;
  1073. case RBM_ENGULF: p = "engulf"; break;
  1074. case RBM_CRAWL: p = "crawl on you"; break;
  1075. case RBM_DROOL: p = "drool on you"; break;
  1076. case RBM_SPIT: p = "spit"; break;
  1077. case RBM_GAZE: p = "gaze"; break;
  1078. case RBM_WAIL: p = "wail"; break;
  1079. case RBM_SPORE: p = "release spores"; break;
  1080. case RBM_BEG: p = "beg"; break;
  1081. case RBM_INSULT: p = "insult"; break;
  1082. case RBM_MOAN: p = "moan"; break;
  1083. default: p = "do something weird";
  1084. }
  1085. /* Get the effect */
  1086. switch (effect)
  1087. {
  1088. case RBE_HURT: q = "attack"; break;
  1089. case RBE_POISON: q = "poison"; break;
  1090. case RBE_UN_BONUS: q = "disenchant"; break;
  1091. case RBE_UN_POWER: q = "drain charges"; break;
  1092. case RBE_EAT_GOLD: q = "steal gold"; break;
  1093. case RBE_EAT_ITEM: q = "steal items"; break;
  1094. case RBE_EAT_FOOD: q = "eat your food"; break;
  1095. case RBE_EAT_LIGHT: q = "absorb light"; break;
  1096. case RBE_ACID: q = "shoot acid"; break;
  1097. case RBE_ELEC: q = "electrify"; break;
  1098. case RBE_FIRE: q = "burn"; break;
  1099. case RBE_COLD: q = "freeze"; break;
  1100. case RBE_BLIND: q = "blind"; break;
  1101. case RBE_CONFUSE: q = "confuse"; break;
  1102. case RBE_TERRIFY: q = "terrify"; break;
  1103. case RBE_PARALYZE: q = "paralyze"; break;
  1104. case RBE_LOSE_STR: q = "reduce strength"; break;
  1105. case RBE_LOSE_INT: q = "reduce intelligence"; break;
  1106. case RBE_LOSE_WIS: q = "reduce wisdom"; break;
  1107. case RBE_LOSE_DEX: q = "reduce dexterity"; break;
  1108. case RBE_LOSE_CON: q = "reduce constitution"; break;
  1109. case RBE_LOSE_CHR: q = "reduce charisma"; break;
  1110. case RBE_LOSE_ALL: q = "reduce all stats"; break;
  1111. case RBE_SHATTER: q = "shatter"; break;
  1112. case RBE_EXP_10: q = "lower experience"; break;
  1113. case RBE_EXP_20: q = "lower experience"; break;
  1114. case RBE_EXP_40: q = "lower experience"; break;
  1115. case RBE_EXP_80: q = "lower experience"; break;
  1116. case RBE_HALLU: q = "cause hallucinations"; break;
  1117. }
  1118. /* Introduce the attack description */
  1119. if (!r)
  1120. text_out("%^s can ", wd_he[msex]);
  1121. else if (r < n - 1)
  1122. text_out(", ");
  1123. else
  1124. text_out(", and ");
  1125. /* Describe the method */
  1126. text_out(p);
  1127. /* Describe the effect (if any) */
  1128. if (q)
  1129. {
  1130. /* Describe the attack type */
  1131. text_out(" to ");
  1132. text_out_c(colors[effect], "%s", q);
  1133. /* Describe damage (if known) */
  1134. if (d1 && d2 && know_damage(r_idx, l_ptr, m))
  1135. {
  1136. text_out(" with damage ");
  1137. text_out_c(TERM_L_GREEN, "%dd%d", d1, d2);
  1138. }
  1139. }
  1140. /* Count the attacks as printed */
  1141. r++;
  1142. }
  1143. /* Finish sentence above */
  1144. if (r)
  1145. text_out(". ");
  1146. /* Notice lack of attacks */
  1147. else if (rf_has(f, RF_NEVER_BLOW))
  1148. text_out("%^s has no physical attacks. ", wd_he[msex]);
  1149. /* Or describe the lack of knowledge */
  1150. else
  1151. text_out("Nothing is known about %s attack. ", wd_his[msex]);
  1152. }
  1153. /*
  1154. * Describe special abilities of monsters.
  1155. */
  1156. static void describe_monster_abilities(int r_idx, const monster_lore *l_ptr)
  1157. {
  1158. const monster_race *r_ptr = &r_info[r_idx];
  1159. bitflag f[RF_SIZE];
  1160. int vn;
  1161. cptr vp[64];
  1162. bool prev = FALSE;
  1163. int msex = 0;
  1164. /* Get the known monster flags */
  1165. monster_flags_known(r_ptr, l_ptr, f);
  1166. /* Extract a gender (if applicable) */
  1167. if (rf_has(r_ptr->flags, RF_FEMALE)) msex = 2;
  1168. else if (rf_has(r_ptr->flags, RF_MALE)) msex = 1;
  1169. /* Collect special abilities. */
  1170. vn = 0;
  1171. if (rf_has(f, RF_OPEN_DOOR)) vp[vn++] = "open doors";
  1172. if (rf_has(f, RF_BASH_DOOR)) vp[vn++] = "bash down doors";
  1173. if (rf_has(f, RF_PASS_WALL)) vp[vn++] = "pass through walls";
  1174. if (rf_has(f, RF_KILL_WALL)) vp[vn++] = "bore through walls";
  1175. if (rf_has(f, RF_MOVE_BODY)) vp[vn++] = "push past weaker monsters";
  1176. if (rf_has(f, RF_KILL_BODY)) vp[vn++] = "destroy weaker monsters";
  1177. if (rf_has(f, RF_TAKE_ITEM)) vp[vn++] = "pick up objects";
  1178. if (rf_has(f, RF_KILL_ITEM)) vp[vn++] = "destroy objects";
  1179. /* Describe special abilities. */
  1180. output_desc_list(msex, "can", vp, vn, TERM_WHITE);
  1181. /* Describe detection traits */
  1182. vn = 0;
  1183. if (rf_has(f, RF_INVISIBLE)) vp[vn++] = "invisible";
  1184. if (rf_has(f, RF_COLD_BLOOD)) vp[vn++] = "cold blooded";
  1185. if (rf_has(f, RF_EMPTY_MIND)) vp[vn++] = "not detected by telepathy";
  1186. if (rf_has(f, RF_WEIRD_MIND)) vp[vn++] = "rarely detected by telepathy";
  1187. output_desc_list(msex, "is", vp, vn, TERM_WHITE);
  1188. /* Describe special things */
  1189. if (rf_has(f, RF_MULTIPLY))
  1190. text_out("%^s breeds explosively. ", wd_he[msex]);
  1191. if (rf_has(f, RF_REGENERATE))
  1192. text_out("%^s regenerates quickly. ", wd_he[msex]);
  1193. if (rf_has(f, RF_HAS_LITE))
  1194. text_out("%^s illuminates %s surroundings. ", wd_he[msex], wd_his[msex]);
  1195. /* Collect susceptibilities */
  1196. vn = 0;
  1197. if (rf_has(f, RF_HURT_ROCK)) vp[vn++] = "rock remover";
  1198. if (rf_has(f, RF_HURT_LIGHT)) vp[vn++] = "bright light";
  1199. if (rf_has(f, RF_HURT_FIRE)) vp[vn++] = "fire";
  1200. if (rf_has(f, RF_HURT_COLD)) vp[vn++] = "cold";
  1201. if (vn)
  1202. {
  1203. /* Output connecting text */
  1204. text_out("%^s is hurt by ", wd_he[msex]);
  1205. output_list(vp, vn, TERM_VIOLET);
  1206. prev = TRUE;
  1207. }
  1208. /* Collect immunities and resistances */
  1209. vn = 0;
  1210. if (rf_has(f, RF_IM_ACID)) vp[vn++] = "acid";
  1211. if (rf_has(f, RF_IM_ELEC)) vp[vn++] = "lightning";
  1212. if (rf_has(f, RF_IM_FIRE)) vp[vn++] = "fire";
  1213. if (rf_has(f, RF_IM_COLD)) vp[vn++] = "cold";
  1214. if (rf_has(f, RF_IM_POIS)) vp[vn++] = "poison";
  1215. if (rf_has(f, RF_IM_WATER)) vp[vn++] = "water";
  1216. if (rf_has(f, RF_RES_NETH)) vp[vn++] = "nether";
  1217. if (rf_has(f, RF_RES_PLAS)) vp[vn++] = "plasma";
  1218. if (rf_has(f, RF_RES_NEXUS)) vp[vn++] = "nexus";
  1219. if (rf_has(f, RF_RES_DISE)) vp[vn++] = "disenchantment";
  1220. /* Note lack of vulnerability as a resistance */
  1221. if (rf_has(l_ptr->flags, RF_HURT_LIGHT) && !rf_has(f, RF_HURT_LIGHT)) vp[vn++] = "bright light";
  1222. if (rf_has(l_ptr->flags, RF_HURT_ROCK) && !rf_has(f, RF_HURT_ROCK)) vp[vn++] = "rock remover";
  1223. if (vn)
  1224. {
  1225. /* Output connecting text */
  1226. if (prev)
  1227. text_out(", but resists ");
  1228. else
  1229. text_out("%^s resists ", wd_he[msex]);
  1230. /* Write the text */
  1231. output_list(vp, vn, TERM_L_UMBER);
  1232. prev = TRUE;
  1233. }
  1234. /* Collect non-effects */
  1235. vn = 0;
  1236. if (rf_has(f, RF_NO_STUN)) vp[vn++] = "stunned";
  1237. if (rf_has(f, RF_NO_FEAR)) vp[vn++] = "frightened";
  1238. if (rf_has(f, RF_NO_CONF)) vp[vn++] = "confused";
  1239. if (rf_has(f, RF_NO_SLEEP)) vp[vn++] = "slept";
  1240. if (vn)
  1241. {
  1242. /* Output connecting text */
  1243. if (prev)
  1244. text_out(", and cannot be ");
  1245. else
  1246. text_out("%^s cannot be ", wd_he[msex]);
  1247. output_list(vp, -vn, TERM_L_UMBER);
  1248. prev = TRUE;
  1249. }
  1250. /* Full stop. */
  1251. if (prev) text_out(". ");
  1252. /* Do we know how aware it is? */
  1253. if ((((int)l_ptr->wake * (int)l_ptr->wake) > r_ptr->sleep) ||
  1254. (l_ptr->ignore == MAX_UCHAR) ||
  1255. ((r_ptr->sleep == 0) && (l_ptr->tkills >= 10)))
  1256. {
  1257. cptr act;
  1258. if (r_ptr->sleep > 200) act = "prefers to ignore";
  1259. else if (r_ptr->sleep > 95) act = "pays very little attention to";
  1260. else if (r_ptr->sleep > 75) act = "pays little attention to";
  1261. else if (r_ptr->sleep > 45) act = "tends to overlook";
  1262. else if (r_ptr->sleep > 25) act = "takes quite a while to see";
  1263. else if (r_ptr->sleep > 10) act = "takes a while to see";
  1264. else if (r_ptr->sleep > 5) act = "is fairly observant of";
  1265. else if (r_ptr->sleep > 3) act = "is observant of";
  1266. else if (r_ptr->sleep > 1) act = "is very observant of";
  1267. else if (r_ptr->sleep > 0) act = "is vigilant for";
  1268. else act = "is ever vigilant for";
  1269. text_out("%^s %s intruders, which %s may notice from ", wd_he[msex], act, wd_he[msex]);
  1270. text_out_c(TERM_L_BLUE, "%d", 10 * r_ptr->aaf);
  1271. text_out(" feet. ");
  1272. }
  1273. /* Describe escorts */
  1274. if (flags_test(f, RF_SIZE, RF_ESCORT, RF_ESCORTS, FLAG_END))
  1275. {
  1276. text_out("%^s usually appears with escorts. ", wd_he[msex]);
  1277. }
  1278. /* Describe friends */
  1279. else if (flags_test(f, RF_SIZE, RF_FRIEND, RF_FRIENDS, FLAG_END))
  1280. {
  1281. text_out("%^s usually appears in groups. ", wd_he[msex]);
  1282. }
  1283. }
  1284. /*
  1285. * Describe how often the monster has killed/been killed.
  1286. */
  1287. static void describe_monster_kills(int r_idx, const monster_lore *l_ptr)
  1288. {
  1289. const monster_race *r_ptr = &r_info[r_idx];
  1290. bitflag f[RF_SIZE];
  1291. int msex = 0;
  1292. bool out = TRUE;
  1293. /* Get the known monster flags */
  1294. monster_flags_known(r_ptr, l_ptr, f);
  1295. /* Extract a gender (if applicable) */
  1296. if (rf_has(r_ptr->flags, RF_FEMALE)) msex = 2;
  1297. else if (rf_has(r_ptr->flags, RF_MALE)) msex = 1;
  1298. /* Treat uniques differently */
  1299. if (rf_has(f, RF_UNIQUE))
  1300. {
  1301. /* Hack -- Determine if the unique is "dead" */
  1302. bool dead = (r_ptr->max_num == 0) ? TRUE : FALSE;
  1303. /* We've been killed... */
  1304. if (l_ptr->deaths)
  1305. {
  1306. /* Killed ancestors */
  1307. text_out("%^s has slain %d of your ancestors", wd_he[msex], l_ptr->deaths);
  1308. /* But we've also killed it */
  1309. if (dead)
  1310. text_out(", but you have taken revenge! ");
  1311. /* Unavenged (ever) */
  1312. else
  1313. text_out(", who remain%s unavenged. ", PLURAL(l_ptr->deaths));
  1314. }
  1315. /* Dead unique who never hurt us */
  1316. else if (dead)
  1317. {
  1318. text_out("You have slain this foe. ");
  1319. }
  1320. else
  1321. {
  1322. /* Alive and never killed us */
  1323. out = FALSE;
  1324. }
  1325. }
  1326. /* Not unique, but killed us */
  1327. else if (l_ptr->deaths)
  1328. {
  1329. /* Dead ancestors */
  1330. text_out("%d of your ancestors %s been killed by this creature, ",
  1331. l_ptr->deaths, plural(l_ptr->deaths, "has", "have"));
  1332. /* Some kills this life */
  1333. if (l_ptr->pkills)
  1334. {
  1335. text_out("and you have exterminated at least %d of the creatures. ",
  1336. l_ptr->pkills);
  1337. }
  1338. /* Some kills past lives */
  1339. else if (l_ptr->tkills)
  1340. {
  1341. text_out("and %s have exterminated at least %d of the creatures. ",
  1342. "your ancestors", l_ptr->tkills);
  1343. }
  1344. /* No kills */
  1345. else
  1346. {
  1347. text_out_c(TERM_RED, "and %s is not ever known to have been defeated. ",
  1348. wd_he[msex]);
  1349. }
  1350. }
  1351. /* Normal monsters */
  1352. else
  1353. {
  1354. /* Killed some this life */
  1355. if (l_ptr->pkills)
  1356. {
  1357. text_out("You have killed at least %d of these creatures. ",
  1358. l_ptr->pkills);
  1359. }
  1360. /* Killed some last life */
  1361. else if (l_ptr->tkills)
  1362. {
  1363. text_out("Your ancestors have killed at least %d of these creatures. ",
  1364. l_ptr->tkills);
  1365. }
  1366. /* Killed none */
  1367. else
  1368. {
  1369. text_out("No battles to the death are recalled. ");
  1370. }
  1371. }
  1372. /* Separate */
  1373. if (out) text_out("\n");
  1374. }
  1375. /*
  1376. * Note how tough a monster is.
  1377. */
  1378. static void describe_monster_toughness(int r_idx, const monster_lore *l_ptr)
  1379. {
  1380. const monster_race *r_ptr = &r_info[r_idx];
  1381. bitflag f[RF_SIZE];
  1382. int msex = 0;
  1383. /* Get the known monster flags */
  1384. monster_flags_known(r_ptr, l_ptr, f);
  1385. /* Extract a gender (if applicable) */
  1386. if (rf_has(r_ptr->flags, RF_FEMALE)) msex = 2;
  1387. else if (rf_has(r_ptr->flags, RF_MALE)) msex = 1;
  1388. /* Describe monster "toughness" */
  1389. if (know_armour(r_idx, l_ptr))
  1390. {
  1391. /* Armor */
  1392. text_out("%^s has an armor rating of ", wd_he[msex]);
  1393. text_out_c(TERM_L_BLUE, "%d", r_ptr->ac);
  1394. text_out(", and a");
  1395. if (!rf_has(f, RF_UNIQUE))
  1396. text_out("n average");
  1397. text_out(" life rating of ");
  1398. text_out_c(TERM_L_BLUE, "%d", r_ptr->avg_hp);
  1399. text_out(". ");
  1400. }
  1401. }
  1402. static void describe_monster_exp(int r_idx, const monster_lore *l_ptr)
  1403. {
  1404. const monster_race *r_ptr = &r_info[r_idx];
  1405. bitflag f[RF_SIZE];
  1406. cptr p, q;
  1407. long i, j;
  1408. char buf[20] = "";
  1409. /* Get the known monster flags */
  1410. monster_flags_known(r_ptr, l_ptr, f);
  1411. /* Introduction */
  1412. if (rf_has(f, RF_UNIQUE))
  1413. text_out("Killing");
  1414. else
  1415. text_out("A kill of");
  1416. text_out(" this creature");
  1417. /* calculate the integer exp part */
  1418. i = (long)r_ptr->mexp * r_ptr->level / p_get_lev();
  1419. /* calculate the fractional exp part scaled by 100, */
  1420. /* must use long arithmetic to avoid overflow */
  1421. j = ((((long)r_ptr->mexp * r_ptr->level % p_get_lev()) *
  1422. (long)1000 / p_get_lev() + 5) / 10);
  1423. /* Calculate textual representation */
  1424. strnfmt(buf, sizeof(buf), "%ld", (long)i);
  1425. if (j) my_strcat(buf, format(".%02ld", (long)j), sizeof(buf));
  1426. /* Mention the experience */
  1427. text_out(" is worth ");
  1428. text_out_c(TERM_BLUE, format("%s point%s", buf, PLURAL((i == 1) && (j == 0))));
  1429. /* Take account of annoying English */
  1430. p = "th";
  1431. i = p_get_lev() % 10;
  1432. if ((p_get_lev() / 10) == 1) /* nothing */;
  1433. else if (i == 1) p = "st";
  1434. else if (i == 2) p = "nd";
  1435. else if (i == 3) p = "rd";
  1436. /* Take account of "leading vowels" in numbers */
  1437. q = "";
  1438. i = p_get_lev();
  1439. if ((i == 8) || (i == 11) || (i == 18)) q = "n";
  1440. /* Mention the dependance on the player's level */
  1441. text_out(" for a%s %lu%s level character. ", q, (long)i, p);
  1442. }
  1443. static void describe_monster_movement(int r_idx, const monster_lore *l_ptr)
  1444. {
  1445. const monster_race *r_ptr = &r_info[r_idx];
  1446. bitflag f[RF_SIZE];
  1447. bool old = FALSE;
  1448. /* Get the known monster flags */
  1449. monster_flags_known(r_ptr, l_ptr, f);
  1450. text_out("This");
  1451. if (rf_has(r_ptr->flags, RF_ANIMAL)) text_out_c(TERM_L_BLUE, " natural");
  1452. if (rf_has(r_ptr->flags, RF_EVIL)) text_out_c(TERM_L_BLUE, " evil");
  1453. if (rf_has(r_ptr->flags, RF_UNDEAD)) text_out_c(TERM_L_BLUE, " undead");
  1454. if (rf_has(r_ptr->flags, RF_METAL)) text_out_c(TERM_L_BLUE, " metal");
  1455. if (rf_has(r_ptr->flags, RF_DRAGON)) text_out_c(TERM_L_BLUE, " dragon");
  1456. else if (rf_has(r_ptr->flags, RF_DEMON)) text_out_c(TERM_L_BLUE, " demon");
  1457. else if (rf_has(r_ptr->flags, RF_GIANT)) text_out_c(TERM_L_BLUE, " giant");
  1458. else if (rf_has(r_ptr->flags, RF_TROLL)) text_out_c(TERM_L_BLUE, " troll");
  1459. else if (rf_has(r_ptr->flags, RF_ORC)) text_out_c(TERM_L_BLUE, " orc");
  1460. else text_out_c(TERM_L_BLUE, " creature");
  1461. /* Describe location */
  1462. if (r_ptr->level == 0)
  1463. {
  1464. text_out(" lives in the town");
  1465. old = TRUE;
  1466. }
  1467. else
  1468. {
  1469. byte colour = (r_ptr->level > p_ptr->max_depth) ? TERM_RED : TERM_L_BLUE;
  1470. if (rf_has(f, RF_FORCE_DEPTH))
  1471. text_out(" is found ");
  1472. else
  1473. text_out(" is normally found ");
  1474. text_out("at depths of ");
  1475. text_out_c(colour, "%d", r_ptr->level * 50);
  1476. text_out(" feet (level ");
  1477. text_out_c(colour, "%d", r_ptr->level);
  1478. text_out(")");
  1479. old = TRUE;
  1480. }
  1481. if (old) text_out(", and");
  1482. text_out(" moves");
  1483. /* Random-ness */
  1484. if (flags_test(f, RF_SIZE, RF_RAND_50, RF_RAND_25, FLAG_END))
  1485. {
  1486. /* Adverb */
  1487. if (rf_has(f, RF_RAND_50) && rf_has(f, RF_RAND_25))
  1488. text_out(" extremely");
  1489. else if (rf_has(f, RF_RAND_50))
  1490. text_out(" somewhat");
  1491. else if (rf_has(f, RF_RAND_25))
  1492. text_out(" a bit");
  1493. /* Adjective */
  1494. text_out(" erratically");
  1495. /* Hack -- Occasional conjunction */
  1496. if (r_ptr->speed != 110) text_out(", and");
  1497. }
  1498. /* Speed */
  1499. if (r_ptr->speed > 110)
  1500. {
  1501. if (r_ptr->speed > 130) text_out_c(TERM_GREEN, " incredibly");
  1502. else if (r_ptr->speed > 120) text_out_c(TERM_GREEN, " very");
  1503. text_out_c(TERM_GREEN, " quickly");
  1504. }
  1505. else if (r_ptr->speed < 110)
  1506. {
  1507. if (r_ptr->speed < 90) text_out_c(TERM_GREEN, " incredibly");
  1508. else if (r_ptr->speed < 100) text_out_c(TERM_GREEN, " very");
  1509. text_out_c(TERM_GREEN, " slowly");
  1510. }
  1511. else
  1512. {
  1513. text_out(" at ");
  1514. text_out_c(TERM_GREEN, "normal speed");
  1515. }
  1516. /* The code above includes "attack speed" */
  1517. if (rf_has(f, RF_NEVER_MOVE))
  1518. text_out(", but does not deign to chase intruders");
  1519. /* End this sentence */
  1520. text_out(". ");
  1521. }
  1522. /*
  1523. * Learn everything about a monster (by cheating)
  1524. */
  1525. static void cheat_monster_lore(int r_idx, monster_lore *l_ptr)
  1526. {
  1527. const monster_race *r_ptr = &r_info[r_idx];
  1528. int i;
  1529. /* Hack -- Maximal kills */
  1530. l_ptr->tkills = MAX_SHORT;
  1531. /* Hack -- Maximal info */
  1532. l_ptr->wake = l_ptr->ignore = MAX_UCHAR;
  1533. /* Observe "maximal" attacks */
  1534. for (i = 0; i < MONSTER_BLOW_MAX; i++)
  1535. {
  1536. /* Examine "actual" blows */
  1537. if (r_ptr->blow[i].effect || r_ptr->blow[i].method)
  1538. {
  1539. /* Hack -- maximal observations */
  1540. l_ptr->blows[i] = MAX_UCHAR;
  1541. }
  1542. }
  1543. /* Hack -- maximal drops */
  1544. if (rf_has(r_ptr->flags, RF_DROP_4))
  1545. l_ptr->drop_item = 6;
  1546. else if (rf_has(r_ptr->flags, RF_DROP_3))
  1547. l_ptr->drop_item = 4;
  1548. else if (rf_has(r_ptr->flags, RF_DROP_2))
  1549. l_ptr->drop_item = 3;
  1550. else if (rf_has(r_ptr->flags, RF_DROP_1))
  1551. l_ptr->drop_item = 3;
  1552. if (rf_has(r_ptr->flags, RF_DROP_40))
  1553. l_ptr->drop_item++;
  1554. if (rf_has(r_ptr->flags, RF_DROP_60))
  1555. l_ptr->drop_item++;
  1556. l_ptr->drop_gold = l_ptr->drop_item;
  1557. /* Hack -- but only "valid" drops */
  1558. if (rf_has(r_ptr->flags, RF_ONLY_GOLD)) l_ptr->drop_item = 0;
  1559. if (rf_has(r_ptr->flags, RF_ONLY_ITEM)) l_ptr->drop_gold = 0;
  1560. /* Hack -- observe many spells */
  1561. l_ptr->cast_innate = MAX_UCHAR;
  1562. l_ptr->cast_spell = MAX_UCHAR;
  1563. /* Hack -- know all the flags */
  1564. rsf_setall(l_ptr->flags);
  1565. rsf_copy(l_ptr->spell_flags, r_ptr->spell_flags);
  1566. }
  1567. /*
  1568. * Hack -- display monster information using "roff()"
  1569. *
  1570. * Note that there is now a compiler option to only read the monster
  1571. * descriptions from the raw file when they are actually needed, which
  1572. * saves about 60K of memory at the cost of disk access during monster
  1573. * recall, which is optional to the user.
  1574. *
  1575. * This function should only be called with the cursor placed at the
  1576. * left edge of the screen, on a cleared line, in which the recall is
  1577. * to take place. One extra blank line is left after the recall.
  1578. */
  1579. void describe_monster(int r_idx, bool spoilers)
  1580. {
  1581. monster_lore lore;
  1582. bitflag f[RF_SIZE];
  1583. int melee_colors[RBE_MAX], spell_colors[RSF_MAX];
  1584. /* Get the race and lore */
  1585. const monster_race *r_ptr = &r_info[r_idx];
  1586. monster_lore *l_ptr = &l_list[r_idx];
  1587. /* Determine the special attack colors */
  1588. get_attack_colors(melee_colors, spell_colors);
  1589. /* Hack -- create a copy of the monster-memory */
  1590. COPY(&lore, l_ptr, monster_lore);
  1591. /* Assume some "obvious" flags */
  1592. flags_set(lore.flags, RF_SIZE, RF_OBVIOUS_MASK, FLAG_END);
  1593. /* Killing a monster reveals some properties */
  1594. if (lore.tkills)
  1595. {
  1596. /* Know "race" flags */
  1597. flags_set(lore.flags, RF_SIZE, RF_RACE_MASK, FLAG_END);
  1598. /* Know "forced" flags */
  1599. rf_on(lore.flags, RF_FORCE_DEPTH);
  1600. }
  1601. /* Now get the known monster flags */
  1602. monster_flags_known(r_ptr, &lore, f);
  1603. /* Cheat -- know everything */
  1604. if (OPT(cheat_know) || spoilers) cheat_monster_lore(r_idx, &lore);
  1605. /* Show kills of monster vs. player(s) */
  1606. if (!spoilers) describe_monster_kills(r_idx, &lore);
  1607. /* Monster description */
  1608. describe_monster_desc(r_idx);
  1609. /* Describe the monster type, speed, life, and armor…

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