Angband 3.0.9b.
[angband.git] / src / obj-info.c
blob5f9c888a32a908ea01e5518c069d1e0fa89dbfb4
1 /* File: obj-info.c */
3 /*
4 * Copyright (c) 2002 Andrew Sidwell, Robert Ruehlmann
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
9 */
11 #include "angband.h"
12 #include "cmds.h"
14 /* TRUE if a paragraph break should be output before next p_text_out() */
15 static bool new_paragraph = FALSE;
18 static void p_text_out(cptr str)
20 if (new_paragraph)
22 text_out("\n\n ");
23 new_paragraph = FALSE;
26 text_out(str);
30 static void output_list(cptr list[], int n)
32 int i;
34 cptr conjunction = "and ";
36 if (n < 0)
38 n = -n;
39 conjunction = "or ";
42 for (i = 0; i < n; i++)
44 if (i != 0)
46 p_text_out((i == 1 && i == n - 1) ? " " : ", ");
48 if (i == n - 1) p_text_out(conjunction);
51 p_text_out(list[i]);
56 static void output_desc_list(cptr intro, cptr list[], int n)
58 if (n != 0)
60 /* Output intro */
61 p_text_out(intro);
63 /* Output list */
64 output_list(list, n);
66 /* Output end */
67 p_text_out(". ");
73 * Describe stat modifications.
75 static bool describe_stats(const object_type *o_ptr, u32b f1)
77 cptr descs[A_MAX];
78 int cnt = 0;
79 int pval = (o_ptr->pval > 0 ? o_ptr->pval : -o_ptr->pval);
81 /* Abort if the pval is zero */
82 if (!pval) return (FALSE);
84 /* Collect stat bonuses */
85 if (f1 & (TR1_STR)) descs[cnt++] = stat_names_full[A_STR];
86 if (f1 & (TR1_INT)) descs[cnt++] = stat_names_full[A_INT];
87 if (f1 & (TR1_WIS)) descs[cnt++] = stat_names_full[A_WIS];
88 if (f1 & (TR1_DEX)) descs[cnt++] = stat_names_full[A_DEX];
89 if (f1 & (TR1_CON)) descs[cnt++] = stat_names_full[A_CON];
90 if (f1 & (TR1_CHR)) descs[cnt++] = stat_names_full[A_CHR];
92 /* Skip */
93 if (cnt == 0) return (FALSE);
95 /* Shorten to "all stats", if appropriate. */
96 if (cnt == A_MAX)
98 p_text_out(format("It %s all your stats", (o_ptr->pval > 0 ? "increases" : "decreases")));
100 else
102 p_text_out(format("It %s your ", (o_ptr->pval > 0 ? "increases" : "decreases")));
104 /* Output list */
105 output_list(descs, cnt);
108 /* Output end */
109 p_text_out(format(" by %i. ", pval));
111 /* We found something */
112 return (TRUE);
117 * Describe "secondary bonuses" of an item.
119 static bool describe_secondary(const object_type *o_ptr, u32b f1)
121 cptr descs[8];
122 int cnt = 0;
123 int pval = (o_ptr->pval > 0 ? o_ptr->pval : -o_ptr->pval);
125 /* Collect */
126 if (f1 & (TR1_STEALTH)) descs[cnt++] = "stealth";
127 if (f1 & (TR1_SEARCH)) descs[cnt++] = "searching";
128 if (f1 & (TR1_INFRA)) descs[cnt++] = "infravision";
129 if (f1 & (TR1_TUNNEL)) descs[cnt++] = "tunneling";
130 if (f1 & (TR1_SPEED)) descs[cnt++] = "speed";
131 if (f1 & (TR1_BLOWS)) descs[cnt++] = "attack speed";
132 if (f1 & (TR1_SHOTS)) descs[cnt++] = "shooting speed";
133 if (f1 & (TR1_MIGHT)) descs[cnt++] = "shooting power";
135 /* Skip */
136 if (!cnt) return (FALSE);
138 /* Start */
139 p_text_out(format("It %s your ", (o_ptr->pval > 0 ? "increases" : "decreases")));
141 /* Output list */
142 output_list(descs, cnt);
144 /* Output end */
145 p_text_out(format(" by %i. ", pval));
147 /* We found something */
148 return (TRUE);
153 * Describe the special slays and executes of an item.
155 static bool describe_slay(const object_type *o_ptr, u32b f1)
157 cptr slays[8], execs[3];
158 int slcnt = 0, excnt = 0;
160 /* Unused parameter */
161 (void)o_ptr;
163 /* Collect brands */
164 if (f1 & (TR1_SLAY_ANIMAL)) slays[slcnt++] = "animals";
165 if (f1 & (TR1_SLAY_ORC)) slays[slcnt++] = "orcs";
166 if (f1 & (TR1_SLAY_TROLL)) slays[slcnt++] = "trolls";
167 if (f1 & (TR1_SLAY_GIANT)) slays[slcnt++] = "giants";
169 /* Dragon slay/execute */
170 if (f1 & TR1_KILL_DRAGON)
171 execs[excnt++] = "dragons";
172 else if (f1 & TR1_SLAY_DRAGON)
173 slays[slcnt++] = "dragons";
175 /* Demon slay/execute */
176 if (f1 & TR1_KILL_DEMON)
177 execs[excnt++] = "demons";
178 else if (f1 & TR1_SLAY_DEMON)
179 slays[slcnt++] = "demons";
181 /* Undead slay/execute */
182 if (f1 & TR1_KILL_UNDEAD)
183 execs[excnt++] = "undead";
184 else if (f1 & TR1_SLAY_UNDEAD)
185 slays[slcnt++] = "undead";
187 if (f1 & (TR1_SLAY_EVIL)) slays[slcnt++] = "all evil creatures";
189 /* Describe */
190 if (slcnt)
192 /* Output intro */
193 p_text_out("It slays ");
195 /* Output list */
196 output_list(slays, slcnt);
198 /* Output end (if needed) */
199 if (!excnt) p_text_out(". ");
202 if (excnt)
204 /* Output intro */
205 if (slcnt) p_text_out(", and is especially deadly against ");
206 else p_text_out("It is especially deadly against ");
208 /* Output list */
209 output_list(execs, excnt);
211 /* Output end */
212 p_text_out(". ");
215 /* We are done here */
216 return ((excnt || slcnt) ? TRUE : FALSE);
221 * Describe elemental brands.
223 static bool describe_brand(const object_type *o_ptr, u32b f1)
225 cptr descs[5];
226 int cnt = 0;
228 /* Unused parameter */
229 (void)o_ptr;
231 /* Collect brands */
232 if (f1 & (TR1_BRAND_ACID)) descs[cnt++] = "acid";
233 if (f1 & (TR1_BRAND_ELEC)) descs[cnt++] = "electricity";
234 if (f1 & (TR1_BRAND_FIRE)) descs[cnt++] = "fire";
235 if (f1 & (TR1_BRAND_COLD)) descs[cnt++] = "frost";
236 if (f1 & (TR1_BRAND_POIS)) descs[cnt++] = "poison";
238 /* Describe brands */
239 output_desc_list("It is branded with ", descs, cnt);
241 /* We are done here */
242 return (cnt ? TRUE : FALSE);
247 * Describe immunities granted by an object.
249 * ToDo - Merge intro describe_resist() below.
251 static bool describe_immune(const object_type *o_ptr, u32b f2)
253 cptr descs[4];
254 int cnt = 0;
256 /* Unused parameter */
257 (void)o_ptr;
259 /* Collect immunities */
260 if (f2 & (TR2_IM_ACID)) descs[cnt++] = "acid";
261 if (f2 & (TR2_IM_ELEC)) descs[cnt++] = "lightning";
262 if (f2 & (TR2_IM_FIRE)) descs[cnt++] = "fire";
263 if (f2 & (TR2_IM_COLD)) descs[cnt++] = "cold";
265 /* Describe immunities */
266 output_desc_list("It provides immunity to ", descs, cnt);
268 /* We are done here */
269 return (cnt ? TRUE : FALSE);
274 * Describe resistances granted by an object.
276 static bool describe_resist(const object_type *o_ptr, u32b f2, u32b f3)
278 cptr vp[17];
279 int vn = 0;
281 /* Unused parameter */
282 (void)o_ptr;
284 /* Collect resistances */
285 if ((f2 & (TR2_RES_ACID)) && !(f2 & (TR2_IM_ACID)))
286 vp[vn++] = "acid";
287 if ((f2 & (TR2_RES_ELEC)) && !(f2 & (TR2_IM_ELEC)))
288 vp[vn++] = "lightning";
289 if ((f2 & (TR2_RES_FIRE)) && !(f2 & (TR2_IM_FIRE)))
290 vp[vn++] = "fire";
291 if ((f2 & (TR2_RES_COLD)) && !(f2 & (TR2_IM_COLD)))
292 vp[vn++] = "cold";
294 if (f2 & (TR2_RES_POIS)) vp[vn++] = "poison";
295 if (f2 & (TR2_RES_FEAR)) vp[vn++] = "fear";
296 if (f2 & (TR2_RES_LITE)) vp[vn++] = "light";
297 if (f2 & (TR2_RES_DARK)) vp[vn++] = "dark";
298 if (f2 & (TR2_RES_BLIND)) vp[vn++] = "blindness";
299 if (f2 & (TR2_RES_CONFU)) vp[vn++] = "confusion";
300 if (f2 & (TR2_RES_SOUND)) vp[vn++] = "sound";
301 if (f2 & (TR2_RES_SHARD)) vp[vn++] = "shards";
302 if (f2 & (TR2_RES_NEXUS)) vp[vn++] = "nexus" ;
303 if (f2 & (TR2_RES_NETHR)) vp[vn++] = "nether";
304 if (f2 & (TR2_RES_CHAOS)) vp[vn++] = "chaos";
305 if (f2 & (TR2_RES_DISEN)) vp[vn++] = "disenchantment";
306 if (f3 & (TR3_HOLD_LIFE)) vp[vn++] = "life draining";
308 /* Describe resistances */
309 output_desc_list("It provides resistance to ", vp, vn);
311 /* We are done here */
312 return (vn ? TRUE : FALSE);
317 * Describe 'ignores' of an object.
319 static bool describe_ignores(const object_type *o_ptr, u32b f3)
321 cptr list[4];
322 int n = 0;
324 /* Unused parameter */
325 (void)o_ptr;
327 /* Collect the ignores */
328 if (f3 & (TR3_IGNORE_ACID)) list[n++] = "acid";
329 if (f3 & (TR3_IGNORE_ELEC)) list[n++] = "electricity";
330 if (f3 & (TR3_IGNORE_FIRE)) list[n++] = "fire";
331 if (f3 & (TR3_IGNORE_COLD)) list[n++] = "cold";
333 /* Describe ignores */
334 if (n == 4)
335 p_text_out("It cannot be harmed by the elements. ");
336 else
337 output_desc_list("It cannot be harmed by ", list, -n);
339 return ((n > 0) ? TRUE : FALSE);
344 * Describe stat sustains.
346 static bool describe_sustains(const object_type *o_ptr, u32b f2)
348 cptr list[A_MAX];
349 int n = 0;
351 /* Unused parameter */
352 (void)o_ptr;
354 /* Collect the sustains */
355 if (f2 & (TR2_SUST_STR)) list[n++] = stat_names_full[A_STR];
356 if (f2 & (TR2_SUST_INT)) list[n++] = stat_names_full[A_INT];
357 if (f2 & (TR2_SUST_WIS)) list[n++] = stat_names_full[A_WIS];
358 if (f2 & (TR2_SUST_DEX)) list[n++] = stat_names_full[A_DEX];
359 if (f2 & (TR2_SUST_CON)) list[n++] = stat_names_full[A_CON];
360 if (f2 & (TR2_SUST_CHR)) list[n++] = stat_names_full[A_CHR];
362 /* Describe immunities */
363 if (n == A_MAX)
364 p_text_out("It sustains all your stats. ");
365 else
366 output_desc_list("It sustains your ", list, n);
368 /* We are done here */
369 return (n ? TRUE : FALSE);
374 * Describe miscellaneous powers such as see invisible, free action,
375 * permanent light, etc; also note curses and penalties.
377 static bool describe_misc_magic(const object_type *o_ptr, u32b f3)
379 cptr good[6], bad[4];
380 int gc = 0, bc = 0;
381 bool something = FALSE;
383 /* Describe lights */
384 if (o_ptr->tval == TV_LITE || (f3 & TR3_LITE))
386 bool artifact = artifact_p(o_ptr);
387 bool no_fuel = (f3 & TR3_NO_FUEL) ? TRUE : FALSE;
388 int rad = 0;
390 if (artifact)
391 rad = 3;
392 else if (o_ptr->tval == TV_LITE)
393 rad = 2;
395 if (f3 & TR3_LITE) rad++;
397 p_text_out("It usually provides light of radius ");
398 text_out_c(TERM_L_GREEN, format("%d", rad));
399 if (no_fuel && !artifact)
400 text_out(", and never needs refuelling");
401 else if (o_ptr->tval == TV_LITE && o_ptr->sval == SV_LITE_TORCH)
402 text_out(", though this is reduced when running of out fuel");
403 text_out(". ");
405 something = TRUE;
408 /* Collect stuff which can't be categorized */
409 if (f3 & (TR3_BLESSED)) good[gc++] = "is blessed by the gods";
410 if (f3 & (TR3_IMPACT)) good[gc++] = "creates earthquakes on impact";
411 if (f3 & (TR3_SLOW_DIGEST)) good[gc++] = "slows your metabolism";
412 if (f3 & (TR3_FEATHER)) good[gc++] = "makes you fall like a feather";
413 if (f3 & (TR3_REGEN)) good[gc++] = "speeds your regeneration";
415 /* Describe */
416 output_desc_list("It ", good, gc);
418 /* Set "something" */
419 if (gc) something = TRUE;
421 /* Collect granted powers */
422 gc = 0;
423 if (f3 & (TR3_FREE_ACT)) good[gc++] = "immunity to paralysis";
424 if (f3 & (TR3_TELEPATHY)) good[gc++] = "the power of telepathy";
425 if (f3 & (TR3_SEE_INVIS)) good[gc++] = "the ability to see invisible things";
427 /* Collect penalties */
428 if (f3 & (TR3_AGGRAVATE)) bad[bc++] = "aggravates creatures around you";
429 if (f3 & (TR3_DRAIN_EXP)) bad[bc++] = "drains experience";
430 if (f3 & (TR3_TELEPORT)) bad[bc++] = "induces random teleportation";
432 /* Deal with cursed stuff */
433 if (cursed_p(o_ptr))
435 if (f3 & (TR3_PERMA_CURSE)) bad[bc++] = "is permanently cursed";
436 else if (f3 & (TR3_HEAVY_CURSE)) bad[bc++] = "is heavily cursed";
437 else if (object_known_p(o_ptr)) bad[bc++] = "is cursed";
440 /* Describe */
441 if (gc)
443 /* Output intro */
444 p_text_out("It grants you ");
446 /* Output list */
447 output_list(good, gc);
449 /* Output end (if needed) */
450 if (!bc) p_text_out(". ");
453 if (bc)
455 /* Output intro */
456 if (gc) p_text_out(", but it also ");
457 else p_text_out("It ");
459 /* Output list */
460 output_list(bad, bc);
462 /* Output end */
463 p_text_out(". ");
466 /* Set "something" */
467 if (gc || bc) something = TRUE;
469 /* Return "something" */
470 return (something);
475 * Describe an object's activation, if any.
477 static bool describe_activation(const object_type *o_ptr, u32b f3)
479 /* Check for the activation flag */
480 if (f3 & TR3_ACTIVATE)
482 p_text_out("It activates for ");
483 describe_item_activation(o_ptr);
484 p_text_out(". ");
486 return (TRUE);
489 /* No activation */
490 return (FALSE);
495 * Output object information
497 bool object_info_out(const object_type *o_ptr)
499 u32b f1, f2, f3;
500 bool something = FALSE;
502 /* Grab the object flags */
503 object_info_out_flags(o_ptr, &f1, &f2, &f3);
505 /* Describe the object */
506 if (describe_stats(o_ptr, f1)) something = TRUE;
507 if (describe_secondary(o_ptr, f1)) something = TRUE;
508 if (describe_slay(o_ptr, f1)) something = TRUE;
509 if (describe_brand(o_ptr, f1)) something = TRUE;
510 if (describe_immune(o_ptr, f2)) something = TRUE;
511 if (describe_resist(o_ptr, f2, f3)) something = TRUE;
512 if (describe_sustains(o_ptr, f2)) something = TRUE;
513 if (describe_misc_magic(o_ptr, f3)) something = TRUE;
514 if (describe_activation(o_ptr, f3)) something = TRUE;
515 if (describe_ignores(o_ptr, f3)) something = TRUE;
517 /* Unknown extra powers (ego-item with random extras or artifact) */
518 if (object_known_p(o_ptr) && (!(o_ptr->ident & IDENT_MENTAL)) &&
519 ((o_ptr->xtra1) || artifact_p(o_ptr)))
521 /* Hack -- Put this in a separate paragraph if screen dump */
522 if (text_out_hook == text_out_to_screen)
523 new_paragraph = TRUE;
525 p_text_out("It might have hidden powers.");
526 something = TRUE;
529 /* We are done. */
530 return something;
535 * Header for additional information when printing to screen.
537 * Return TRUE if an object description was displayed.
539 static bool screen_out_head(const object_type *o_ptr)
541 char *o_name;
542 int name_size = Term->wid;
543 bool has_description = FALSE;
545 /* Allocate memory to the size of the screen */
546 o_name = C_RNEW(name_size, char);
548 /* Description */
549 object_desc(o_name, name_size, o_ptr, TRUE, 3);
551 /* Print, in colour */
552 text_out_c(TERM_YELLOW, format("%^s", o_name));
554 /* Free up the memory */
555 FREE(o_name);
557 /* Display the known artifact description */
558 if (!adult_randarts && o_ptr->name1 &&
559 object_known_p(o_ptr) && a_info[o_ptr->name1].text)
561 p_text_out("\n\n ");
562 p_text_out(a_text + a_info[o_ptr->name1].text);
563 has_description = TRUE;
566 /* Display the known object description */
567 else if (object_aware_p(o_ptr) || object_known_p(o_ptr))
569 if (k_info[o_ptr->k_idx].text)
571 p_text_out("\n\n ");
572 p_text_out(k_text + k_info[o_ptr->k_idx].text);
573 has_description = TRUE;
576 /* Display an additional ego-item description */
577 if (o_ptr->name2 && object_known_p(o_ptr) && e_info[o_ptr->name2].text)
579 p_text_out("\n\n ");
580 p_text_out(e_text + e_info[o_ptr->name2].text);
581 has_description = TRUE;
585 return (has_description);
590 * Place an item description on the screen.
592 void object_info_screen(const object_type *o_ptr)
594 bool has_description, has_info;
596 /* Redirect output to the screen */
597 text_out_hook = text_out_to_screen;
599 /* Save the screen */
600 screen_save();
602 has_description = screen_out_head(o_ptr);
604 object_info_out_flags = object_flags_known;
606 /* Dump the info */
607 new_paragraph = TRUE;
608 has_info = object_info_out(o_ptr);
609 new_paragraph = FALSE;
611 if (!object_known_p(o_ptr))
612 p_text_out("\n\n This item has not been identified.");
613 else if (!has_description && !has_info)
614 p_text_out("\n\n This item does not seem to possess any special abilities.");
616 text_out_c(TERM_L_BLUE, "\n\n[Press any key to continue]\n");
618 /* Wait for input */
619 (void)anykey();
621 /* Load the screen */
622 screen_load();
624 /* Hack -- Browse book, then prompt for a command */
625 if (o_ptr->tval == cp_ptr->spell_book)
627 /* Call the aux function */
628 do_cmd_browse_aux(o_ptr);