PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/object/obj-info.c

https://bitbucket.org/ekolis/jackband
C | 1308 lines | 884 code | 237 blank | 187 comment | 262 complexity | 624d1e3974c16cd86c454803e9cc4a93 MD5 | raw file
  1. /*
  2. * File: obj-info.c
  3. * Purpose: Object description code.
  4. *
  5. * Copyright (c) 2002,2007,2008 Andi Sidwell <andi@takkaria.org>
  6. * Copyright (c) 2002,2003,2004 Robert Ruehlmann <rr9@thangorodrim.net>
  7. *
  8. * This work is free software; you can redistribute it and/or modify it
  9. * under the terms of either:
  10. *
  11. * a) the GNU General Public License as published by the Free Software
  12. * Foundation, version 2, or
  13. *
  14. * b) the "Angband licence":
  15. * This software may be copied and distributed for educational, research,
  16. * and not for profit purposes provided that this copyright and statement
  17. * are included in all such copies. Other copyrights may also apply.
  18. */
  19. #include "angband.h"
  20. #include "effects.h"
  21. #include "cmds.h"
  22. #include "tvalsval.h"
  23. /*
  24. * Describes a flag-name pair.
  25. */
  26. typedef struct
  27. {
  28. int flag;
  29. const char *name;
  30. } flag_type;
  31. /*** Utility code ***/
  32. /*
  33. * Given an array of strings, as so:
  34. * { "intelligence", "fish", "lens", "prime", "number" },
  35. *
  36. * ... output a list like "intelligence, fish, lens, prime, number.\n".
  37. */
  38. static void info_out_list(const char *list[], size_t count)
  39. {
  40. size_t i;
  41. for (i = 0; i < count; i++)
  42. {
  43. text_out(list[i]);
  44. if (i != (count - 1)) text_out(", ");
  45. }
  46. text_out(".\n");
  47. }
  48. /*
  49. *
  50. */
  51. static size_t info_collect(const flag_type list[], size_t max, const bitflag flags[OF_SIZE], const char *recepticle[])
  52. {
  53. size_t i, count = 0;
  54. for (i = 0; i < max; i++)
  55. {
  56. if (of_has(flags, list[i].flag))
  57. recepticle[count++] = list[i].name;
  58. }
  59. return count;
  60. }
  61. /*** Big fat data tables ***/
  62. static const flag_type pval_flags[] =
  63. {
  64. { OF_STR, "strength" },
  65. { OF_INT, "intelligence" },
  66. { OF_WIS, "wisdom" },
  67. { OF_DEX, "dexterity" },
  68. { OF_CON, "constitution" },
  69. { OF_CHR, "charisma" },
  70. { OF_STEALTH, "stealth" },
  71. { OF_INFRA, "infravision" },
  72. { OF_TUNNEL, "tunneling" },
  73. { OF_SPEED, "speed" },
  74. { OF_BLOWS, "attack speed" },
  75. { OF_SHOTS, "shooting speed" },
  76. { OF_MIGHT, "shooting power" },
  77. };
  78. static const flag_type immunity_flags[] =
  79. {
  80. { OF_IM_ACID, "acid" },
  81. { OF_IM_ELEC, "lightning" },
  82. { OF_IM_FIRE, "fire" },
  83. { OF_IM_COLD, "cold" },
  84. };
  85. static const flag_type vuln_flags[] =
  86. {
  87. { OF_VULN_ACID, "acid" },
  88. { OF_VULN_ELEC, "electricity" },
  89. { OF_VULN_FIRE, "fire" },
  90. { OF_VULN_COLD, "cold" },
  91. };
  92. static const flag_type resist_flags[] =
  93. {
  94. { OF_RES_ACID, "acid" },
  95. { OF_RES_ELEC, "lightning" },
  96. { OF_RES_FIRE, "fire" },
  97. { OF_RES_COLD, "cold" },
  98. { OF_RES_POIS, "poison" },
  99. { OF_RES_FEAR, "fear" },
  100. { OF_RES_LIGHT, "light" },
  101. { OF_RES_DARK, "dark" },
  102. { OF_RES_BLIND, "blindness" },
  103. { OF_RES_CONFU, "confusion" },
  104. { OF_RES_SOUND, "sound" },
  105. { OF_RES_SHARD, "shards" },
  106. { OF_RES_NEXUS, "nexus" },
  107. { OF_RES_NETHR, "nether" },
  108. { OF_RES_CHAOS, "chaos" },
  109. { OF_RES_DISEN, "disenchantment" },
  110. };
  111. static const flag_type ignore_flags[] =
  112. {
  113. { OF_IGNORE_ACID, "acid" },
  114. { OF_IGNORE_ELEC, "electricity" },
  115. { OF_IGNORE_FIRE, "fire" },
  116. { OF_IGNORE_COLD, "cold" },
  117. };
  118. static const flag_type sustain_flags[] =
  119. {
  120. { OF_SUST_STR, "strength" },
  121. { OF_SUST_INT, "intelligence" },
  122. { OF_SUST_WIS, "wisdom" },
  123. { OF_SUST_DEX, "dexterity" },
  124. { OF_SUST_CON, "constitution" },
  125. { OF_SUST_CHR, "charisma" },
  126. };
  127. static const flag_type misc_flags[] =
  128. {
  129. { OF_BLESSED, "Blessed by the gods" },
  130. { OF_SLOW_DIGEST, "Slows your metabolism" },
  131. { OF_IMPAIR_HP, "Impairs hitpoint recovery" },
  132. { OF_IMPAIR_MANA, "Impairs mana recovery" },
  133. { OF_AFRAID, "Makes you afraid of melee, and worse at shooting and casting spells" },
  134. { OF_FEATHER, "Feather Falling" },
  135. { OF_REGEN, "Speeds regeneration" },
  136. { OF_FREE_ACT, "Prevents paralysis" },
  137. { OF_HOLD_LIFE, "Sustains your life force" },
  138. { OF_TELEPATHY, "Grants telepathy" },
  139. { OF_SEE_INVIS, "Grants the ability to see invisible things" },
  140. { OF_AGGRAVATE, "Aggravates creatures nearby" },
  141. { OF_DRAIN_EXP, "Drains experience" },
  142. { OF_TELEPORT, "Induces random teleportation" },
  143. };
  144. /** Slays **/
  145. /*
  146. * Entries in this table should be in ascending order of multiplier, to
  147. * ensure that the highest one takes precedence
  148. * object flag, vulnerable flag, resist flag, multiplier, ranged verb,
  149. * melee verb, verb describing what the thing branded does when it is active,
  150. * description of affected creatures, brand
  151. */
  152. const slay_t slay_table[] =
  153. {
  154. { OF_SLAY_ANIMAL, RF_ANIMAL, FLAG_END, 2,
  155. "pierces", "smite", "glows", "animals", NULL },
  156. { OF_SLAY_EVIL, RF_EVIL, FLAG_END, 2,
  157. "pierces", "smite", "glows", "evil creatures", NULL },
  158. { OF_SLAY_UNDEAD, RF_UNDEAD, FLAG_END, 3,
  159. "pierces", "smite", "glows", "undead", NULL },
  160. { OF_SLAY_DEMON, RF_DEMON, FLAG_END, 3,
  161. "pierces", "smite", "glows", "demons", NULL },
  162. { OF_SLAY_ORC, RF_ORC, FLAG_END, 3,
  163. "pierces", "smite", "glows", "orcs", NULL },
  164. { OF_SLAY_TROLL, RF_TROLL, FLAG_END, 3,
  165. "pierces", "smite", "glows", "trolls", NULL },
  166. { OF_SLAY_GIANT, RF_GIANT, FLAG_END, 3,
  167. "pierces", "smite", "glows", "giants", NULL },
  168. { OF_SLAY_DRAGON, RF_DRAGON, FLAG_END, 3,
  169. "pierces", "smite", "glows", "dragons", NULL },
  170. { OF_BRAND_ACID, FLAG_END, RF_IM_ACID, 3,
  171. "corrodes", "corrode", "spits", "creatures not resistant to acid", "acid" },
  172. { OF_BRAND_ELEC, FLAG_END, RF_IM_ELEC, 3,
  173. "zaps", "zap", "crackles", "creatures not resistant to electricity", "lightning" },
  174. { OF_BRAND_FIRE, FLAG_END, RF_IM_FIRE, 3,
  175. "burns", "burn", "flares", "creatures not resistant to fire", "flames" },
  176. { OF_BRAND_COLD, FLAG_END, RF_IM_COLD, 3,
  177. "freezes" , "freeze", "grows cold", "creatures not resistant to cold", "frost" },
  178. { OF_BRAND_POIS, FLAG_END, RF_IM_POIS, 3,
  179. "poisons", "poison", "seethes", "creatures not resistant to poison", "venom" },
  180. { OF_KILL_DRAGON, RF_DRAGON, FLAG_END, 5,
  181. "deeply pierces", "fiercely smite", "glows brightly", "dragons", NULL },
  182. { OF_KILL_DEMON, RF_DEMON, FLAG_END, 5,
  183. "deeply pierces", "fiercely smite", "glows brightly", "demons", NULL },
  184. { OF_KILL_UNDEAD, RF_UNDEAD, FLAG_END, 5,
  185. "deeply pierces", "fiercely smite", "glows brightly", "undead", NULL },
  186. { FLAG_END, FLAG_END, FLAG_END, 0, NULL, NULL, NULL, NULL, NULL }
  187. };
  188. /*
  189. * Slays which are in some sense duplicates. *Slay* dragon supercedes slay
  190. * dragon, for example.
  191. */
  192. const struct {
  193. u16b minor;
  194. u16b major;
  195. } slay_dups[] =
  196. {
  197. { OF_SLAY_DRAGON, OF_KILL_DRAGON },
  198. { OF_SLAY_DEMON, OF_KILL_DEMON },
  199. { OF_SLAY_UNDEAD, OF_KILL_UNDEAD },
  200. };
  201. /*
  202. * Helper function to externalise N_ELEMENTS(slay_table), which itself is not
  203. * available outside this compilation unit
  204. */
  205. size_t num_slays(void)
  206. {
  207. return N_ELEMENTS(slay_table);
  208. }
  209. /*** Code that makes use of the data tables ***/
  210. /*
  211. * Describe an item's curses.
  212. */
  213. static bool describe_curses(const object_type *o_ptr, const bitflag flags[OF_SIZE])
  214. {
  215. if (of_has(flags, OF_PERMA_CURSE))
  216. text_out_c(TERM_L_RED, "Permanently cursed.\n");
  217. else if (of_has(flags, OF_HEAVY_CURSE))
  218. text_out_c(TERM_L_RED, "Heavily cursed.\n");
  219. else if (of_has(flags, OF_LIGHT_CURSE))
  220. text_out_c(TERM_L_RED, "Cursed.\n");
  221. else
  222. return FALSE;
  223. return TRUE;
  224. }
  225. /*
  226. * Describe stat modifications.
  227. */
  228. static bool describe_stats(const object_type *o_ptr, const bitflag flags[OF_SIZE], oinfo_detail_t
  229. mode)
  230. {
  231. cptr descs[N_ELEMENTS(pval_flags)];
  232. size_t count;
  233. bool full = mode & OINFO_FULL;
  234. bool dummy = mode & OINFO_DUMMY;
  235. if (!o_ptr->pval && !dummy) return FALSE;
  236. count = info_collect(pval_flags, N_ELEMENTS(pval_flags), flags, descs);
  237. if (count)
  238. {
  239. if ((object_pval_is_visible(o_ptr) || full) && !dummy)
  240. {
  241. text_out_c((o_ptr->pval > 0) ? TERM_L_GREEN : TERM_RED,
  242. "%+i ", o_ptr->pval);
  243. info_out_list(descs, count);
  244. }
  245. else
  246. {
  247. text_out("Affects your ");
  248. info_out_list(descs, count);
  249. }
  250. }
  251. if (of_has(flags, OF_SEARCH))
  252. {
  253. if ((object_pval_is_visible(o_ptr) || full) && !dummy)
  254. {
  255. text_out_c((o_ptr->pval > 0) ? TERM_L_GREEN : TERM_RED,
  256. "%+i%% ", o_ptr->pval * 5);
  257. text_out("to searching.\n");
  258. }
  259. else if (count) text_out("Also affects your searching skill.\n");
  260. else text_out("Affects your searching skill.\n");
  261. }
  262. return TRUE;
  263. }
  264. /*
  265. * Describe immunities granted by an object.
  266. */
  267. static bool describe_immune(const bitflag flags[OF_SIZE])
  268. {
  269. const char *i_descs[N_ELEMENTS(immunity_flags)];
  270. const char *r_descs[N_ELEMENTS(resist_flags)];
  271. const char *v_descs[N_ELEMENTS(vuln_flags)];
  272. size_t count;
  273. bool prev = FALSE;
  274. /* Immunities */
  275. count = info_collect(immunity_flags, N_ELEMENTS(immunity_flags), flags, i_descs);
  276. if (count)
  277. {
  278. text_out("Provides immunity to ");
  279. info_out_list(i_descs, count);
  280. prev = TRUE;
  281. }
  282. /* Resistances */
  283. count = info_collect(resist_flags, N_ELEMENTS(resist_flags), flags, r_descs);
  284. if (count)
  285. {
  286. text_out("Provides resistance to ");
  287. info_out_list(r_descs, count);
  288. prev = TRUE;
  289. }
  290. /* Vulnerabilities */
  291. count = info_collect(vuln_flags, N_ELEMENTS(vuln_flags), flags, v_descs);
  292. if (count)
  293. {
  294. text_out("Makes you vulnerable to ");
  295. info_out_list(v_descs, count);
  296. prev = TRUE;
  297. }
  298. return prev;
  299. }
  300. /*
  301. * Describe 'ignores' of an object.
  302. */
  303. static bool describe_ignores(const bitflag flags[OF_SIZE])
  304. {
  305. const char *descs[N_ELEMENTS(ignore_flags)];
  306. size_t count = info_collect(ignore_flags, N_ELEMENTS(ignore_flags), flags, descs);
  307. if (!count) return FALSE;
  308. text_out("Cannot be harmed by ");
  309. info_out_list(descs, count);
  310. return TRUE;
  311. }
  312. /*
  313. * Describe stat sustains.
  314. */
  315. static bool describe_sustains(const bitflag flags[OF_SIZE])
  316. {
  317. const char *descs[N_ELEMENTS(sustain_flags)];
  318. size_t count = info_collect(sustain_flags, N_ELEMENTS(sustain_flags), flags, descs);
  319. if (!count) return FALSE;
  320. text_out("Sustains ");
  321. info_out_list(descs, count);
  322. return TRUE;
  323. }
  324. /*
  325. * Describe miscellaneous powers.
  326. */
  327. static bool describe_misc_magic(const bitflag flags[OF_SIZE])
  328. {
  329. size_t i;
  330. bool printed = FALSE;
  331. for (i = 0; i < N_ELEMENTS(misc_flags); i++)
  332. {
  333. if (of_has(flags, misc_flags[i].flag))
  334. {
  335. text_out("%s. ", misc_flags[i].name);
  336. printed = TRUE;
  337. }
  338. }
  339. if (printed) text_out("\n");
  340. return printed;
  341. }
  342. /*
  343. * Describe slays and brands on weapons
  344. */
  345. static bool describe_slays(const bitflag flags[OF_SIZE], int tval)
  346. {
  347. bool printed = FALSE;
  348. const char *slay_descs[N_ELEMENTS(slay_table)];
  349. const char *kill_descs[N_ELEMENTS(slay_table)];
  350. const char *brand_descs[N_ELEMENTS(slay_table)];
  351. const slay_t *s_ptr;
  352. bitflag slay_mask[OF_SIZE], kill_mask[OF_SIZE], brand_mask[OF_SIZE];
  353. size_t x = 0;
  354. size_t y = 0;
  355. size_t z = 0;
  356. bool fulldesc;
  357. flags_init(slay_mask, OF_SIZE, OF_SLAY_MASK, FLAG_END);
  358. flags_init(kill_mask, OF_SIZE, OF_KILL_MASK, FLAG_END);
  359. flags_init(brand_mask, OF_SIZE, OF_BRAND_MASK, FLAG_END);
  360. if ((tval == TV_SWORD) || (tval == TV_HAFTED) || (tval == TV_POLEARM)
  361. || (tval == TV_DIGGING ) || (tval == TV_BOW) || (tval == TV_SHOT)
  362. || (tval == TV_ARROW) || (tval == TV_BOLT) || (tval == TV_FLASK))
  363. fulldesc = FALSE;
  364. else fulldesc = TRUE;
  365. for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++)
  366. {
  367. if (!of_has(flags, s_ptr->slay_flag)) continue;
  368. if (of_has(slay_mask, s_ptr->slay_flag))
  369. slay_descs[x++] = s_ptr->desc;
  370. else if (of_has(kill_mask, s_ptr->slay_flag))
  371. kill_descs[y++] = s_ptr->desc;
  372. else if (of_has(brand_mask, s_ptr->slay_flag))
  373. brand_descs[z++] = s_ptr->brand;
  374. }
  375. /* Slays */
  376. if (x)
  377. {
  378. if (fulldesc) text_out("It causes your melee attacks to slay ");
  379. else text_out("Slays ");
  380. info_out_list(slay_descs, x);
  381. printed = TRUE;
  382. }
  383. /* Kills */
  384. if (y)
  385. {
  386. if (fulldesc) text_out("It causes your melee attacks to *slay* ");
  387. else text_out("*Slays* ");
  388. info_out_list(kill_descs, y);
  389. printed = TRUE;
  390. }
  391. /* Brands */
  392. if (z)
  393. {
  394. if (fulldesc) text_out("It brands your melee attacks with ");
  395. else text_out("Branded with ");
  396. info_out_list(brand_descs, z);
  397. printed = TRUE;
  398. }
  399. return printed;
  400. }
  401. /*
  402. * list[] and mult[] must be > 16 in size
  403. */
  404. static int collect_slays(const char *desc[], int mult[], bitflag *flags)
  405. {
  406. int cnt = 0;
  407. u16b i;
  408. const slay_t *s_ptr;
  409. /* Remove "duplicate" flags e.g. *slay* and slay the same
  410. * monster type
  411. */
  412. for (i = 0; i < N_ELEMENTS(slay_dups); i++) {
  413. if (of_has(flags, slay_dups[i].minor) &&
  414. of_has(flags, slay_dups[i].major)) {
  415. of_off(flags, slay_dups[i].minor);
  416. }
  417. }
  418. /* Collect slays */
  419. for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++)
  420. {
  421. if (of_has(flags, s_ptr->slay_flag))
  422. {
  423. mult[cnt] = s_ptr->mult;
  424. desc[cnt++] = s_ptr->desc;
  425. }
  426. }
  427. return cnt;
  428. }
  429. /*
  430. * Account for criticals in the calculation of melee prowess
  431. *
  432. * Note -- This relies on the criticals being an affine function
  433. * of previous damage, since we are used to transform the mean
  434. * of a roll.
  435. *
  436. * Also note -- rounding error makes this not completely accurate
  437. * (but for the big crit weapons like Grond an odd point of damage
  438. * won't be missed)
  439. *
  440. * This code written according to the KISS principle. 650 adds
  441. * are cheaper than a FOV call and get the job done fine.
  442. */
  443. static void calculate_melee_crits(player_state *state, int weight,
  444. int plus, int *mult, int *add, int *div)
  445. {
  446. int k, to_crit = weight + 5*(state->to_h + plus) + 3*p_get_lev();
  447. to_crit = MIN(5000, MAX(0, to_crit));
  448. *mult = *add = 0;
  449. for (k = weight; k < weight + 650; k++)
  450. {
  451. if (k < 400) { *mult += 4; *add += 10; continue; }
  452. if (k < 700) { *mult += 4; *add += 20; continue; }
  453. if (k < 900) { *mult += 6; *add += 30; continue; }
  454. if (k < 1300) { *mult += 6; *add += 40; continue; }
  455. *mult += 7; *add += 50;
  456. }
  457. /*
  458. * Scale the output down to a more reasonable size, to prevent
  459. * integer overflow downstream.
  460. */
  461. *mult = 100 + to_crit*(*mult - 1300)/(50*1300);
  462. *add = *add * to_crit / (500*50);
  463. *div = 100;
  464. }
  465. /*
  466. * Missile crits follow the same approach as melee crits.
  467. */
  468. static void calculate_missile_crits(player_state *state, int weight,
  469. int plus, int *mult, int *add, int *div)
  470. {
  471. int k, to_crit = weight + 4*(state->to_h + plus) + 2*p_get_lev();
  472. to_crit = MIN(5000, MAX(0, to_crit));
  473. *mult = *add = 0;
  474. for (k = weight; k < weight + 500; k++)
  475. {
  476. if (k < 500) { *mult += 2; *add += 5; continue; }
  477. if (k < 1000) { *mult += 2; *add += 10; continue; }
  478. *mult += 3; *add += 15;
  479. }
  480. *mult = 100 + to_crit*(*mult - 500)/(500*50);
  481. *add = *add * to_crit / (500*50);
  482. *div = 100;
  483. }
  484. /*
  485. * Describe combat advantages.
  486. */
  487. static bool describe_combat(const object_type *o_ptr, oinfo_detail_t mode)
  488. {
  489. bool full = mode & OINFO_FULL;
  490. const char *desc[16];
  491. int i;
  492. int mult[16];
  493. int cnt, dam, total_dam, plus = 0;
  494. int xtra_postcrit = 0, xtra_precrit = 0;
  495. int crit_mult, crit_div, crit_add;
  496. int str_plus, dex_plus, old_blows, new_blows, extra_blows;
  497. int str_done = -1;
  498. object_type *j_ptr = &inventory[INVEN_BOW];
  499. bitflag f[OF_SIZE];
  500. bitflag tmp_f[OF_SIZE];
  501. bool weapon = (wield_slot(o_ptr) == INVEN_WIELD);
  502. bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) &&
  503. (j_ptr->k_idx);
  504. int multiplier = 1;
  505. /* Abort if we've nothing to say */
  506. if (mode & OINFO_DUMMY) return FALSE;
  507. if (!weapon && !ammo)
  508. {
  509. /* Potions can have special text */
  510. if (o_ptr->tval != TV_POTION) return FALSE;
  511. if (!o_ptr->dd || !o_ptr->ds) return FALSE;
  512. if (!object_flavor_is_aware(o_ptr)) return FALSE;
  513. text_out("It can be thrown at creatures with damaging effect.\n");
  514. return TRUE;
  515. }
  516. if (full)
  517. object_flags(o_ptr, f);
  518. else
  519. object_flags_known(o_ptr, f);
  520. text_out_c(TERM_L_WHITE, "Combat info:\n");
  521. if (weapon)
  522. {
  523. /*
  524. * Get the player's hypothetical state, were they to be
  525. * wielding this item.
  526. */
  527. player_state state;
  528. int dex_plus_bound;
  529. int str_plus_bound;
  530. object_type inven[INVEN_TOTAL];
  531. memcpy(inven, inventory, INVEN_TOTAL * sizeof(object_type));
  532. inven[INVEN_WIELD] = *o_ptr;
  533. if (full) object_know_all_flags(&inven[INVEN_WIELD]);
  534. calc_bonuses(inven, &state, TRUE);
  535. dex_plus_bound = STAT_RANGE - state.stat_ind[A_DEX];
  536. str_plus_bound = STAT_RANGE - state.stat_ind[A_STR];
  537. dam = ((o_ptr->ds + 1) * o_ptr->dd * 5);
  538. xtra_postcrit = state.dis_to_d * 10;
  539. if (object_attack_plusses_are_visible(o_ptr))
  540. {
  541. xtra_precrit += o_ptr->to_d * 10;
  542. plus += o_ptr->to_h;
  543. }
  544. calculate_melee_crits(&state, o_ptr->weight, plus,
  545. &crit_mult, &crit_add, &crit_div);
  546. /* Warn about heavy weapons */
  547. if (adj_str_hold[state.stat_ind[A_STR]] < o_ptr->weight / 10)
  548. text_out_c(TERM_L_RED, "You are too weak to use this weapon.\n");
  549. text_out_c(TERM_L_GREEN, "%d ", state.num_blow);
  550. text_out("blow%s/round.\n", (state.num_blow > 1) ? "s" : "");
  551. /* Check to see if extra STR or DEX would yield extra blows */
  552. old_blows = state.num_blow;
  553. extra_blows = 0;
  554. /* First we need to look for extra blows on other items, as
  555. * state does not track these */
  556. for (i = INVEN_BOW; i < INVEN_TOTAL; i++)
  557. {
  558. object_flags_known(&inventory[i], tmp_f);
  559. if (of_has(tmp_f, OF_BLOWS))
  560. extra_blows += inventory[i].pval;
  561. }
  562. /* Then we add blows from the weapon being examined */
  563. if (of_has(f, OF_BLOWS)) extra_blows += o_ptr->pval;
  564. /* Then we check for extra "real" blows */
  565. for (dex_plus = 0; dex_plus < dex_plus_bound; dex_plus++)
  566. {
  567. for (str_plus = 0; str_plus < str_plus_bound; str_plus++)
  568. {
  569. state.stat_ind[A_STR] += str_plus;
  570. state.stat_ind[A_DEX] += dex_plus;
  571. new_blows = calc_blows(o_ptr, &state)
  572. + extra_blows;
  573. /* Test to make sure that this extra blow is a
  574. * new str/dex combination, not a repeat
  575. */
  576. if ((new_blows > old_blows) &&
  577. ((str_plus < str_done) ||
  578. (str_done == -1)))
  579. {
  580. text_out("With an additional %d strength and %d dex you would get %d blows\n",
  581. str_plus, dex_plus, new_blows);
  582. state.stat_ind[A_STR] -= str_plus;
  583. state.stat_ind[A_DEX] -= dex_plus;
  584. str_done = str_plus;
  585. break;
  586. }
  587. state.stat_ind[A_STR] -= str_plus;
  588. state.stat_ind[A_DEX] -= dex_plus;
  589. }
  590. }
  591. }
  592. else
  593. {
  594. int tdis = 6 + 2 * p_ptr->state.ammo_mult;
  595. if (object_attack_plusses_are_visible(o_ptr))
  596. plus += o_ptr->to_h;
  597. calculate_missile_crits(&p_ptr->state, o_ptr->weight, plus,
  598. &crit_mult, &crit_add, &crit_div);
  599. /* Calculate damage */
  600. dam = ((o_ptr->ds + 1) * o_ptr->dd * 5);
  601. if (object_attack_plusses_are_visible(o_ptr))
  602. dam += (o_ptr->to_d * 10);
  603. if (object_attack_plusses_are_visible(j_ptr))
  604. dam += (j_ptr->to_d * 10);
  605. /* Apply brands from the shooter to the ammo */
  606. object_flags(j_ptr, tmp_f);
  607. of_union(f, tmp_f);
  608. text_out("Hits targets up to ");
  609. text_out_c(TERM_L_GREEN, format("%d", tdis * 10));
  610. text_out(" feet away.\n");
  611. }
  612. /* Collect slays */
  613. /* Melee weapons get slays and brands from other items now */
  614. if (weapon)
  615. {
  616. bool nonweap = FALSE;
  617. for (i = INVEN_LEFT; i < INVEN_TOTAL; i++)
  618. {
  619. object_flags_known(&inventory[i], tmp_f);
  620. flags_mask(tmp_f, OF_SIZE, OF_ALL_SLAY_MASK, FLAG_END);
  621. if (of_union(f, tmp_f))
  622. nonweap = TRUE;
  623. }
  624. if (nonweap)
  625. text_out("This weapon may benefit from one or more off-weapon brands or slays.\n");
  626. }
  627. text_out("Average damage/hit: ");
  628. if (ammo) multiplier = p_ptr->state.ammo_mult;
  629. cnt = collect_slays(desc, mult, f);
  630. for (i = 0; i < cnt; i++)
  631. {
  632. /* Include bonus damage and slay in stated average */
  633. total_dam = dam * (multiplier + mult[i]) + xtra_precrit;
  634. total_dam = (total_dam * crit_mult + crit_add) / crit_div;
  635. total_dam += xtra_postcrit;
  636. if (total_dam <= 0)
  637. text_out_c(TERM_L_RED, "%d", 0);
  638. else if (total_dam % 10)
  639. text_out_c(TERM_L_GREEN, "%d.%d",
  640. total_dam / 10, total_dam % 10);
  641. else
  642. text_out_c(TERM_L_GREEN, "%d", total_dam / 10);
  643. text_out(" vs. %s, ", desc[i]);
  644. }
  645. if (cnt) text_out("and ");
  646. /* Include bonus damage in stated average */
  647. total_dam = dam * multiplier + xtra_precrit;
  648. total_dam = (total_dam * crit_mult + crit_add) / crit_div;
  649. total_dam += xtra_postcrit;
  650. if (total_dam <= 0)
  651. text_out_c(TERM_L_RED, "%d", 0);
  652. else if (total_dam % 10)
  653. text_out_c(TERM_L_GREEN, "%d.%d",
  654. total_dam / 10, total_dam % 10);
  655. else
  656. text_out_c(TERM_L_GREEN, "%d", total_dam / 10);
  657. if (cnt) text_out(" vs. others");
  658. text_out(".\n");
  659. /* Note the impact flag */
  660. if (of_has(f, OF_IMPACT))
  661. text_out("Sometimes creates earthquakes on impact.\n");
  662. /* Add breakage chance */
  663. if (ammo)
  664. {
  665. text_out_c(TERM_L_GREEN, "%d%%", breakage_chance(o_ptr));
  666. text_out(" chance of breaking upon contact.\n");
  667. }
  668. /* You always have something to say... */
  669. return TRUE;
  670. }
  671. /*
  672. * Describe objects that can be used for digging.
  673. */
  674. static bool describe_digger(const object_type *o_ptr, oinfo_detail_t mode)
  675. {
  676. bool full = mode & OINFO_FULL;
  677. player_state st;
  678. object_type inven[INVEN_TOTAL];
  679. int sl = wield_slot(o_ptr);
  680. int i;
  681. bitflag f[OF_SIZE];
  682. int chances[4]; /* These are out of 1600 */
  683. static const char *names[4] = { "rubble", "magma veins", "quartz veins", "granite" };
  684. /* abort if we are a dummy object */
  685. if (mode & OINFO_DUMMY) return FALSE;
  686. if (full)
  687. object_flags(o_ptr, f);
  688. else
  689. object_flags_known(o_ptr, f);
  690. if (sl < 0 || (sl != INVEN_WIELD && !of_has(f, OF_TUNNEL)))
  691. return FALSE;
  692. memcpy(inven, inventory, INVEN_TOTAL * sizeof(object_type));
  693. /*
  694. * Hack -- if we examine a ring that is worn on the right finger,
  695. * we shouldn't put a copy of it on the left finger before calculating
  696. * digging skills.
  697. */
  698. if (o_ptr != &inventory[INVEN_RIGHT])
  699. inven[sl] = *o_ptr;
  700. calc_bonuses(inven, &st, TRUE);
  701. chances[0] = st.skills[SKILL_DIGGING] * 8;
  702. chances[1] = (st.skills[SKILL_DIGGING] - 10) * 4;
  703. chances[2] = (st.skills[SKILL_DIGGING] - 20) * 2;
  704. chances[3] = (st.skills[SKILL_DIGGING] - 40) * 1;
  705. for (i = 0; i < 4; i++)
  706. {
  707. int chance = MAX(0, MIN(1600, chances[i]));
  708. int decis = chance ? (16000 / chance) : 0;
  709. if (i == 0 && chance > 0)
  710. {
  711. if (sl == INVEN_WIELD) text_out("Clears ");
  712. else text_out("With this item, your current weapon clears ");
  713. }
  714. if (i == 3 || (i != 0 && chance == 0))
  715. text_out("and ");
  716. if (chance == 0)
  717. {
  718. text_out_c(TERM_L_RED, "doesn't affect ");
  719. text_out("%s.\n", names[i]);
  720. break;
  721. }
  722. text_out("%s in ", names[i]);
  723. if (chance == 1600) {
  724. text_out_c(TERM_L_GREEN, "1 ");
  725. } else if (decis < 100) {
  726. text_out_c(TERM_GREEN, "%d.%d ", decis/10, decis%10);
  727. } else {
  728. text_out_c((decis < 1000) ? TERM_YELLOW : TERM_RED,
  729. "%d ", (decis+5)/10);
  730. }
  731. text_out("turn%s%s", decis == 10 ? "" : "s",
  732. (i == 3) ? ".\n" : ", ");
  733. }
  734. return TRUE;
  735. }
  736. static bool describe_food(const object_type *o_ptr, bool subjective, bool full)
  737. {
  738. /* Describe boring bits */
  739. if ((o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION) &&
  740. o_ptr->pval)
  741. {
  742. /* Sometimes adjust for player speed */
  743. int multiplier = extract_energy[p_ptr->state.speed];
  744. if (!subjective) multiplier = 10;
  745. if (object_is_known(o_ptr) || full)
  746. {
  747. text_out("Nourishes for around ");
  748. text_out_c(TERM_L_GREEN, "%d", (o_ptr->pval / 2) *
  749. multiplier / 10);
  750. text_out(" turns.\n");
  751. }
  752. else text_out("Provides some nourishment.\n");
  753. return TRUE;
  754. }
  755. return FALSE;
  756. }
  757. /*
  758. * Describe things that look like lights.
  759. */
  760. static bool describe_light(const object_type *o_ptr, const bitflag flags[OF_SIZE], bool terse)
  761. {
  762. int rad = 0;
  763. bool artifact = artifact_p(o_ptr);
  764. bool no_fuel = of_has(flags, OF_NO_FUEL) ? TRUE : FALSE;
  765. bool is_light = (o_ptr->tval == TV_LIGHT) ? TRUE : FALSE;
  766. if (o_ptr->tval != TV_LIGHT && !of_has(flags, OF_LIGHT))
  767. return FALSE;
  768. /* Work out radius */
  769. if (artifact && is_light) rad = 3;
  770. else if (is_light) rad = 2;
  771. if (of_has(flags, OF_LIGHT)) rad++;
  772. /* Describe here */
  773. text_out("Radius ");
  774. text_out_c(TERM_L_GREEN, format("%d", rad));
  775. if (no_fuel && !artifact)
  776. text_out(" light. No fuel required.");
  777. else if (is_light && o_ptr->sval == SV_LIGHT_TORCH)
  778. text_out(" light, reduced when running out of fuel.");
  779. else
  780. text_out (" light.");
  781. if (!terse && is_light && !no_fuel)
  782. {
  783. const char *name = (o_ptr->sval == SV_LIGHT_TORCH) ? "torches" : "lanterns";
  784. int turns = (o_ptr->sval == SV_LIGHT_TORCH) ? FUEL_TORCH : FUEL_LAMP;
  785. text_out(" Refills other %s up to %d turns of fuel.", name, turns);
  786. }
  787. text_out("\n");
  788. return TRUE;
  789. }
  790. /*
  791. * Describe an object's effect, if any.
  792. */
  793. static bool describe_effect(const object_type *o_ptr, bool full,
  794. bool only_artifacts, bool subjective)
  795. {
  796. const object_kind *k_ptr = &k_info[o_ptr->k_idx];
  797. const char *desc;
  798. random_value timeout = {0, 0, 0, 0};
  799. int effect = 0, fail;
  800. if (o_ptr->name1)
  801. {
  802. const artifact_type *a_ptr = &a_info[o_ptr->name1];
  803. if (object_effect_is_known(o_ptr) || full)
  804. {
  805. effect = a_ptr->effect;
  806. timeout = a_ptr->time;
  807. }
  808. else if (object_effect(o_ptr))
  809. {
  810. text_out("It can be activated.\n");
  811. return TRUE;
  812. }
  813. }
  814. else
  815. {
  816. /* Sometimes only print artifact activation info */
  817. if (only_artifacts == TRUE) return FALSE;
  818. if (object_effect_is_known(o_ptr) || full)
  819. {
  820. effect = k_ptr->effect;
  821. timeout = k_ptr->time;
  822. }
  823. else if (object_effect(o_ptr) != 0)
  824. {
  825. if (effect_aim(k_ptr->effect))
  826. text_out("It can be aimed.\n");
  827. else if (o_ptr->tval == TV_FOOD)
  828. text_out("It can be eaten.\n");
  829. else if (o_ptr->tval == TV_POTION)
  830. text_out("It can be drunk.\n");
  831. else if (o_ptr->tval == TV_SCROLL)
  832. text_out("It can be read.\n");
  833. else text_out("It can be activated.\n");
  834. return TRUE;
  835. }
  836. }
  837. /* Forget it without an effect */
  838. if (!effect) return FALSE;
  839. /* Obtain the description */
  840. desc = effect_desc(effect);
  841. if (!desc) return FALSE;
  842. if (effect_aim(effect))
  843. text_out("When aimed, it ");
  844. else if (o_ptr->tval == TV_FOOD)
  845. text_out("When eaten, it ");
  846. else if (o_ptr->tval == TV_POTION)
  847. text_out("When drunk, it ");
  848. else if (o_ptr->tval == TV_SCROLL)
  849. text_out("When read, it ");
  850. else
  851. text_out("When activated, it ");
  852. /* Print a colourised description */
  853. do
  854. {
  855. if (isdigit((unsigned char) *desc))
  856. text_out_c(TERM_L_GREEN, "%c", *desc);
  857. else
  858. text_out("%c", *desc);
  859. } while (*desc++);
  860. text_out(".\n");
  861. if (randcalc(timeout, 0, MAXIMISE) > 0)
  862. {
  863. int min_time, max_time;
  864. /* Sometimes adjust for player speed */
  865. int multiplier = extract_energy[p_ptr->state.speed];
  866. if (!subjective) multiplier = 10;
  867. text_out("Takes ");
  868. /* Correct for player speed */
  869. min_time = randcalc(timeout, 0, MINIMISE) * multiplier / 10;
  870. max_time = randcalc(timeout, 0, MAXIMISE) * multiplier / 10;
  871. text_out_c(TERM_L_GREEN, "%d", min_time);
  872. if (min_time != max_time)
  873. {
  874. text_out(" to ");
  875. text_out_c(TERM_L_GREEN, "%d", max_time);
  876. }
  877. text_out(" turns to recharge");
  878. if (subjective && p_ptr->state.speed != 110)
  879. text_out(" at your current speed");
  880. text_out(".\n");
  881. }
  882. if (!subjective || o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION ||
  883. o_ptr->tval == TV_SCROLL)
  884. {
  885. return TRUE;
  886. }
  887. else
  888. {
  889. fail = get_use_device_chance(o_ptr);
  890. text_out("Your chance of success is %d.%d%%\n", (1000 - fail) /
  891. 10, (1000 - fail) % 10);
  892. }
  893. return TRUE;
  894. }
  895. /*** Different ways to present the data ***/
  896. /*
  897. * Print name, origin, and descriptive text for a given object.
  898. */
  899. void object_info_header(const object_type *o_ptr)
  900. {
  901. char o_name[120];
  902. char origin_text[80];
  903. /* Object name */
  904. object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL);
  905. text_out_c(TERM_L_BLUE, "%^s\n", o_name);
  906. /* Display the origin */
  907. if (o_ptr->origin_depth)
  908. strnfmt(origin_text, sizeof(origin_text), "%d feet (level %d)",
  909. o_ptr->origin_depth * 50, o_ptr->origin_depth);
  910. else
  911. my_strcpy(origin_text, "town", sizeof(origin_text));
  912. switch (o_ptr->origin)
  913. {
  914. case ORIGIN_NONE:
  915. case ORIGIN_MIXED:
  916. break;
  917. case ORIGIN_BIRTH:
  918. text_out("(an inheritance from your family)\n");
  919. break;
  920. case ORIGIN_STORE:
  921. text_out("(from a store)\n");
  922. break;
  923. case ORIGIN_FLOOR:
  924. text_out("(lying on the floor %s %s)\n",
  925. (o_ptr->origin_depth ? "at" : "in"),
  926. origin_text);
  927. break;
  928. case ORIGIN_DROP:
  929. {
  930. const char *name = r_name + r_info[o_ptr->origin_xtra].name;
  931. bool unique = rf_has(r_info[o_ptr->origin_xtra].flags, RF_UNIQUE) ? TRUE : FALSE;
  932. text_out("(dropped by ");
  933. if (unique)
  934. text_out("%s", name);
  935. else
  936. text_out("%s%s", is_a_vowel(name[0]) ? "an " : "a ", name);
  937. text_out(" %s %s)\n",
  938. (o_ptr->origin_depth ? "at" : "in"),
  939. origin_text);
  940. break;
  941. }
  942. case ORIGIN_DROP_UNKNOWN:
  943. {
  944. text_out("(dropped by an unknown monster %s %s)\n",
  945. (o_ptr->origin_depth ? "at" : "in"),
  946. origin_text);
  947. break;
  948. }
  949. case ORIGIN_ACQUIRE:
  950. {
  951. text_out("(conjured forth by magic %s %s)\n",
  952. (o_ptr->origin_depth ? "at" : "in"),
  953. origin_text);
  954. break;
  955. }
  956. case ORIGIN_CHEAT:
  957. text_out("(created by debug option)\n");
  958. break;
  959. case ORIGIN_CHEST:
  960. {
  961. text_out("(found in a chest from %s)\n",
  962. origin_text);
  963. break;
  964. }
  965. }
  966. text_out("\n");
  967. /* Display the known artifact description */
  968. if (!OPT(adult_randarts) && o_ptr->name1 &&
  969. object_is_known(o_ptr) && a_info[o_ptr->name1].text)
  970. {
  971. text_out(a_text + a_info[o_ptr->name1].text);
  972. text_out("\n\n");
  973. }
  974. /* Display the known object description */
  975. else if (object_flavor_is_aware(o_ptr) || object_is_known(o_ptr))
  976. {
  977. bool did_desc = FALSE;
  978. if (k_info[o_ptr->k_idx].text)
  979. {
  980. text_out(k_text + k_info[o_ptr->k_idx].text);
  981. did_desc = TRUE;
  982. }
  983. /* Display an additional ego-item description */
  984. if (object_ego_is_visible(o_ptr) && e_info[o_ptr->name2].text)
  985. {
  986. if (did_desc) text_out(" ");
  987. text_out(e_text + e_info[o_ptr->name2].text);
  988. text_out("\n\n");
  989. }
  990. else if (did_desc)
  991. {
  992. text_out("\n\n");
  993. }
  994. }
  995. return;
  996. }
  997. /*
  998. * Output object information
  999. */
  1000. static bool object_info_out(const object_type *o_ptr, oinfo_detail_t mode)
  1001. {
  1002. bitflag flags[OF_SIZE];
  1003. bool something = FALSE;
  1004. bool known = object_is_known(o_ptr);
  1005. bool full = mode & OINFO_FULL;
  1006. bool terse = mode & OINFO_TERSE;
  1007. bool subjective = mode & OINFO_SUBJ;
  1008. /* Grab the object flags */
  1009. if (full)
  1010. object_flags(o_ptr, flags);
  1011. else
  1012. object_flags_known(o_ptr, flags);
  1013. if (!full && !known)
  1014. {
  1015. text_out("You do not know the full extent of this item's powers.\n");
  1016. something = TRUE;
  1017. }
  1018. if (describe_curses(o_ptr, flags)) something = TRUE;
  1019. if (describe_stats(o_ptr, flags, mode)) something = TRUE;
  1020. if (describe_slays(flags, o_ptr->tval)) something = TRUE;
  1021. if (describe_immune(flags)) something = TRUE;
  1022. if (describe_ignores(flags)) something = TRUE;
  1023. if (describe_sustains(flags)) something = TRUE;
  1024. if (describe_misc_magic(flags)) something = TRUE;
  1025. if (something) text_out("\n");
  1026. if (describe_effect(o_ptr, full, terse, subjective))
  1027. {
  1028. something = TRUE;
  1029. text_out("\n");
  1030. }
  1031. if (subjective && describe_combat(o_ptr, mode))
  1032. {
  1033. something = TRUE;
  1034. text_out("\n");
  1035. }
  1036. if (!terse && describe_food(o_ptr, subjective, full)) something = TRUE;
  1037. if (describe_light(o_ptr, flags, terse)) something = TRUE;
  1038. if (!terse && subjective && describe_digger(o_ptr, mode)) something = TRUE;
  1039. return something;
  1040. }
  1041. /**
  1042. * Provide information on an item, including how it would affect the current
  1043. * player's state.
  1044. *
  1045. * mode OINFO_FULL should be set if actual player knowledge should be ignored
  1046. * in favour of full knowledge.
  1047. *
  1048. * returns TRUE if anything is printed.
  1049. */
  1050. bool object_info(const object_type *o_ptr, oinfo_detail_t mode)
  1051. {
  1052. mode |= OINFO_SUBJ;
  1053. return object_info_out(o_ptr, mode);
  1054. }
  1055. /**
  1056. * Provide information on an item suitable for writing to the character dump - keep it brief.
  1057. */
  1058. bool object_info_chardump(const object_type *o_ptr)
  1059. {
  1060. return object_info_out(o_ptr, OINFO_TERSE | OINFO_SUBJ);
  1061. }
  1062. /**
  1063. * Provide spoiler information on an item.
  1064. *
  1065. * Practically, this means that we should not print anything which relies upon the player's
  1066. * current state, since that is not suitable for spoiler material.
  1067. */
  1068. bool object_info_spoil(const object_type *o_ptr)
  1069. {
  1070. return object_info_out(o_ptr, OINFO_FULL);
  1071. }