4 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
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.
15 * Pronoun arrays, by gender.
17 static cptr wd_he
[3] =
18 { "it", "he", "she" };
19 static cptr wd_his
[3] =
20 { "its", "his", "her" };
24 * Pluralizer. Args(count, singular, plural)
26 #define plural(c,s,p) \
27 (((c) == 1) ? (s) : (p))
35 * Determine if the "armor" is known
36 * The higher the level, the fewer kills needed.
38 static bool know_armour(int r_idx
, const monster_lore
*l_ptr
)
40 const monster_race
*r_ptr
= &r_info
[r_idx
];
42 s32b level
= r_ptr
->level
;
44 s32b kills
= l_ptr
->tkills
;
47 if (kills
> 304 / (4 + level
)) return (TRUE
);
49 /* Skip non-uniques */
50 if (!(r_ptr
->flags1
& RF1_UNIQUE
)) return (FALSE
);
53 if (kills
> 304 / (38 + (5 * level
) / 4)) return (TRUE
);
61 * Determine if the "damage" of the given attack is known
62 * the higher the level of the monster, the fewer the attacks you need,
63 * the more damage an attack does, the more attacks you need
65 static bool know_damage(int r_idx
, const monster_lore
*l_ptr
, int i
)
67 const monster_race
*r_ptr
= &r_info
[r_idx
];
69 s32b level
= r_ptr
->level
;
71 s32b a
= l_ptr
->blows
[i
];
73 s32b d1
= r_ptr
->blow
[i
].d_dice
;
74 s32b d2
= r_ptr
->blow
[i
].d_side
;
79 if ((4 + level
) * a
> 80 * d
) return (TRUE
);
81 /* Skip non-uniques */
82 if (!(r_ptr
->flags1
& RF1_UNIQUE
)) return (FALSE
);
85 if ((4 + level
) * (2 * a
) > 80 * d
) return (TRUE
);
92 static void describe_monster_desc(int r_idx
)
94 const monster_race
*r_ptr
= &r_info
[r_idx
];
98 my_strcpy(buf
, r_text
+ r_ptr
->text
, sizeof(buf
));
106 static void describe_monster_spells(int r_idx
, const monster_lore
*l_ptr
)
108 const monster_race
*r_ptr
= &r_info
[r_idx
];
117 /* Extract a gender (if applicable) */
118 if (r_ptr
->flags1
& RF1_FEMALE
) msex
= 2;
119 else if (r_ptr
->flags1
& RF1_MALE
) msex
= 1;
121 /* Collect innate attacks */
123 if (l_ptr
->flags4
& RF4_SHRIEK
) vp
[vn
++] = "shriek for help";
124 if (l_ptr
->flags4
& RF4_XXX2
) vp
[vn
++] = "do something";
125 if (l_ptr
->flags4
& RF4_XXX3
) vp
[vn
++] = "do something";
126 if (l_ptr
->flags4
& RF4_XXX4
) vp
[vn
++] = "do something";
127 if (l_ptr
->flags4
& RF4_ARROW_1
) vp
[vn
++] = "fire an arrow";
128 if (l_ptr
->flags4
& RF4_ARROW_2
) vp
[vn
++] = "fire arrows";
129 if (l_ptr
->flags4
& RF4_ARROW_3
) vp
[vn
++] = "fire a missile";
130 if (l_ptr
->flags4
& RF4_ARROW_4
) vp
[vn
++] = "fire missiles";
131 if (l_ptr
->flags4
& RF4_BOULDER
) vp
[vn
++] = "throw boulders";
133 /* Describe innate attacks */
137 text_out(format("%^s", wd_he
[msex
]));
140 for (n
= 0; n
< vn
; n
++)
143 if (n
== 0) text_out(" may ");
144 else if (n
< vn
-1) text_out(", ");
145 else text_out(" or ");
148 text_out_c(TERM_L_RED
, vp
[n
]);
156 /* Collect breaths */
158 if (l_ptr
->flags4
& RF4_BR_ACID
) vp
[vn
++] = "acid";
159 if (l_ptr
->flags4
& RF4_BR_ELEC
) vp
[vn
++] = "lightning";
160 if (l_ptr
->flags4
& RF4_BR_FIRE
) vp
[vn
++] = "fire";
161 if (l_ptr
->flags4
& RF4_BR_COLD
) vp
[vn
++] = "frost";
162 if (l_ptr
->flags4
& RF4_BR_POIS
) vp
[vn
++] = "poison";
163 if (l_ptr
->flags4
& RF4_BR_NETH
) vp
[vn
++] = "nether";
164 if (l_ptr
->flags4
& RF4_BR_LITE
) vp
[vn
++] = "light";
165 if (l_ptr
->flags4
& RF4_BR_DARK
) vp
[vn
++] = "darkness";
166 if (l_ptr
->flags4
& RF4_BR_CONF
) vp
[vn
++] = "confusion";
167 if (l_ptr
->flags4
& RF4_BR_SOUN
) vp
[vn
++] = "sound";
168 if (l_ptr
->flags4
& RF4_BR_CHAO
) vp
[vn
++] = "chaos";
169 if (l_ptr
->flags4
& RF4_BR_DISE
) vp
[vn
++] = "disenchantment";
170 if (l_ptr
->flags4
& RF4_BR_NEXU
) vp
[vn
++] = "nexus";
171 if (l_ptr
->flags4
& RF4_BR_TIME
) vp
[vn
++] = "time";
172 if (l_ptr
->flags4
& RF4_BR_INER
) vp
[vn
++] = "inertia";
173 if (l_ptr
->flags4
& RF4_BR_GRAV
) vp
[vn
++] = "gravity";
174 if (l_ptr
->flags4
& RF4_BR_SHAR
) vp
[vn
++] = "shards";
175 if (l_ptr
->flags4
& RF4_BR_PLAS
) vp
[vn
++] = "plasma";
176 if (l_ptr
->flags4
& RF4_BR_WALL
) vp
[vn
++] = "force";
177 if (l_ptr
->flags4
& RF4_BR_MANA
) vp
[vn
++] = "mana";
178 if (l_ptr
->flags4
& RF4_XXX5
) vp
[vn
++] = "something";
179 if (l_ptr
->flags4
& RF4_XXX6
) vp
[vn
++] = "something";
180 if (l_ptr
->flags4
& RF4_XXX7
) vp
[vn
++] = "something";
182 /* Describe breaths */
189 text_out(format("%^s", wd_he
[msex
]));
192 for (n
= 0; n
< vn
; n
++)
195 if (n
== 0) text_out(" may breathe ");
196 else if (n
< vn
-1) text_out(", ");
197 else text_out(" or ");
200 text_out_c(TERM_L_RED
, vp
[n
]);
207 if (l_ptr
->flags5
& RF5_BA_ACID
) vp
[vn
++] = "produce acid balls";
208 if (l_ptr
->flags5
& RF5_BA_ELEC
) vp
[vn
++] = "produce lightning balls";
209 if (l_ptr
->flags5
& RF5_BA_FIRE
) vp
[vn
++] = "produce fire balls";
210 if (l_ptr
->flags5
& RF5_BA_COLD
) vp
[vn
++] = "produce frost balls";
211 if (l_ptr
->flags5
& RF5_BA_POIS
) vp
[vn
++] = "produce poison balls";
212 if (l_ptr
->flags5
& RF5_BA_NETH
) vp
[vn
++] = "produce nether balls";
213 if (l_ptr
->flags5
& RF5_BA_WATE
) vp
[vn
++] = "produce water balls";
214 if (l_ptr
->flags5
& RF5_BA_MANA
) vp
[vn
++] = "invoke mana storms";
215 if (l_ptr
->flags5
& RF5_BA_DARK
) vp
[vn
++] = "invoke darkness storms";
216 if (l_ptr
->flags5
& RF5_DRAIN_MANA
) vp
[vn
++] = "drain mana";
217 if (l_ptr
->flags5
& RF5_MIND_BLAST
) vp
[vn
++] = "cause mind blasting";
218 if (l_ptr
->flags5
& RF5_BRAIN_SMASH
) vp
[vn
++] = "cause brain smashing";
219 if (l_ptr
->flags5
& RF5_CAUSE_1
) vp
[vn
++] = "cause light wounds";
220 if (l_ptr
->flags5
& RF5_CAUSE_2
) vp
[vn
++] = "cause serious wounds";
221 if (l_ptr
->flags5
& RF5_CAUSE_3
) vp
[vn
++] = "cause critical wounds";
222 if (l_ptr
->flags5
& RF5_CAUSE_4
) vp
[vn
++] = "cause mortal wounds";
223 if (l_ptr
->flags5
& RF5_BO_ACID
) vp
[vn
++] = "produce acid bolts";
224 if (l_ptr
->flags5
& RF5_BO_ELEC
) vp
[vn
++] = "produce lightning bolts";
225 if (l_ptr
->flags5
& RF5_BO_FIRE
) vp
[vn
++] = "produce fire bolts";
226 if (l_ptr
->flags5
& RF5_BO_COLD
) vp
[vn
++] = "produce frost bolts";
227 if (l_ptr
->flags5
& RF5_BO_POIS
) vp
[vn
++] = "produce poison bolts";
228 if (l_ptr
->flags5
& RF5_BO_NETH
) vp
[vn
++] = "produce nether bolts";
229 if (l_ptr
->flags5
& RF5_BO_WATE
) vp
[vn
++] = "produce water bolts";
230 if (l_ptr
->flags5
& RF5_BO_MANA
) vp
[vn
++] = "produce mana bolts";
231 if (l_ptr
->flags5
& RF5_BO_PLAS
) vp
[vn
++] = "produce plasma bolts";
232 if (l_ptr
->flags5
& RF5_BO_ICEE
) vp
[vn
++] = "produce ice bolts";
233 if (l_ptr
->flags5
& RF5_MISSILE
) vp
[vn
++] = "produce magic missiles";
234 if (l_ptr
->flags5
& RF5_SCARE
) vp
[vn
++] = "terrify";
235 if (l_ptr
->flags5
& RF5_BLIND
) vp
[vn
++] = "blind";
236 if (l_ptr
->flags5
& RF5_CONF
) vp
[vn
++] = "confuse";
237 if (l_ptr
->flags5
& RF5_SLOW
) vp
[vn
++] = "slow";
238 if (l_ptr
->flags5
& RF5_HOLD
) vp
[vn
++] = "paralyze";
239 if (l_ptr
->flags6
& RF6_HASTE
) vp
[vn
++] = "haste-self";
240 if (l_ptr
->flags6
& RF6_XXX1
) vp
[vn
++] = "do something";
241 if (l_ptr
->flags6
& RF6_HEAL
) vp
[vn
++] = "heal-self";
242 if (l_ptr
->flags6
& RF6_XXX2
) vp
[vn
++] = "do something";
243 if (l_ptr
->flags6
& RF6_BLINK
) vp
[vn
++] = "blink-self";
244 if (l_ptr
->flags6
& RF6_TPORT
) vp
[vn
++] = "teleport-self";
245 if (l_ptr
->flags6
& RF6_XXX3
) vp
[vn
++] = "do something";
246 if (l_ptr
->flags6
& RF6_XXX4
) vp
[vn
++] = "do something";
247 if (l_ptr
->flags6
& RF6_TELE_TO
) vp
[vn
++] = "teleport to";
248 if (l_ptr
->flags6
& RF6_TELE_AWAY
) vp
[vn
++] = "teleport away";
249 if (l_ptr
->flags6
& RF6_TELE_LEVEL
) vp
[vn
++] = "teleport level";
250 if (l_ptr
->flags6
& RF6_XXX5
) vp
[vn
++] = "do something";
251 if (l_ptr
->flags6
& RF6_DARKNESS
) vp
[vn
++] = "create darkness";
252 if (l_ptr
->flags6
& RF6_TRAPS
) vp
[vn
++] = "create traps";
253 if (l_ptr
->flags6
& RF6_FORGET
) vp
[vn
++] = "cause amnesia";
254 if (l_ptr
->flags6
& RF6_XXX6
) vp
[vn
++] = "do something";
255 if (l_ptr
->flags6
& RF6_S_KIN
) vp
[vn
++] = "summon similar monsters";
256 if (l_ptr
->flags6
& RF6_S_MONSTER
) vp
[vn
++] = "summon a monster";
257 if (l_ptr
->flags6
& RF6_S_MONSTERS
) vp
[vn
++] = "summon monsters";
258 if (l_ptr
->flags6
& RF6_S_ANIMAL
) vp
[vn
++] = "summon animals";
259 if (l_ptr
->flags6
& RF6_S_SPIDER
) vp
[vn
++] = "summon spiders";
260 if (l_ptr
->flags6
& RF6_S_HOUND
) vp
[vn
++] = "summon hounds";
261 if (l_ptr
->flags6
& RF6_S_HYDRA
) vp
[vn
++] = "summon hydras";
262 if (l_ptr
->flags6
& RF6_S_ANGEL
) vp
[vn
++] = "summon an angel";
263 if (l_ptr
->flags6
& RF6_S_DEMON
) vp
[vn
++] = "summon a demon";
264 if (l_ptr
->flags6
& RF6_S_UNDEAD
) vp
[vn
++] = "summon an undead";
265 if (l_ptr
->flags6
& RF6_S_DRAGON
) vp
[vn
++] = "summon a dragon";
266 if (l_ptr
->flags6
& RF6_S_HI_UNDEAD
) vp
[vn
++] = "summon Greater Undead";
267 if (l_ptr
->flags6
& RF6_S_HI_DRAGON
) vp
[vn
++] = "summon Ancient Dragons";
268 if (l_ptr
->flags6
& RF6_S_HI_DEMON
) vp
[vn
++] = "summon Greater Demons";
269 if (l_ptr
->flags6
& RF6_S_WRAITH
) vp
[vn
++] = "summon Ring Wraiths";
270 if (l_ptr
->flags6
& RF6_S_UNIQUE
) vp
[vn
++] = "summon Unique Monsters";
272 /* Describe spells */
281 text_out(", and is also");
285 text_out(format("%^s is", wd_he
[msex
]));
289 text_out(" magical, casting spells");
292 if (l_ptr
->flags2
& RF2_SMART
) text_out_c(TERM_ORANGE
, " intelligently");
295 for (n
= 0; n
< vn
; n
++)
298 if (n
== 0) text_out(" which ");
299 else if (n
< vn
-1) text_out(", ");
300 else text_out(" or ");
303 text_out_c(TERM_L_RED
, vp
[n
]);
308 /* End the sentence about innate/other spells */
312 m
= l_ptr
->cast_innate
+ l_ptr
->cast_spell
;
314 /* Average frequency */
315 n
= (r_ptr
->freq_innate
+ r_ptr
->freq_spell
) / 2;
317 /* Describe the spell frequency */
320 text_out(format("; 1 time in %d", 100 / n
));
323 /* Guess at the frequency */
326 n
= ((n
+ 9) / 10) * 10;
327 text_out(format("; about 1 time in %d", 100 / n
));
330 /* End this sentence */
336 static void describe_monster_drop(int r_idx
, const monster_lore
*l_ptr
)
338 const monster_race
*r_ptr
= &r_info
[r_idx
];
349 /* Extract a gender (if applicable) */
350 if (r_ptr
->flags1
& RF1_FEMALE
) msex
= 2;
351 else if (r_ptr
->flags1
& RF1_MALE
) msex
= 1;
353 /* Drops gold and/or items */
354 if (l_ptr
->drop_gold
|| l_ptr
->drop_item
)
357 text_out(format("%^s may carry", wd_he
[msex
]));
359 /* Count maximum drop */
360 n
= MAX(l_ptr
->drop_gold
, l_ptr
->drop_item
);
362 /* One drop (may need an "n") */
372 text_out(" one or two");
378 text_out(format(" up to %d", n
));
383 if (l_ptr
->flags1
& RF1_DROP_GREAT
)
388 /* Good (no "n" needed) */
389 else if (l_ptr
->flags1
& RF1_DROP_GOOD
)
403 if (l_ptr
->drop_item
)
405 /* Handle singular "an" */
406 if (sin
) text_out("n");
409 /* Dump "object(s)" */
412 if (n
!= 1) text_out("s");
414 /* Conjunction replaces variety, if needed for "gold" below */
419 if (l_ptr
->drop_gold
)
424 /* Handle singular "an" */
425 if (sin
) text_out("n");
427 /* Dump "treasure(s)" */
429 text_out(" treasure");
430 if (n
!= 1) text_out("s");
433 /* End this sentence */
439 static void describe_monster_attack(int r_idx
, const monster_lore
*l_ptr
)
441 const monster_race
*r_ptr
= &r_info
[r_idx
];
447 /* Extract a gender (if applicable) */
448 if (r_ptr
->flags1
& RF1_FEMALE
) msex
= 2;
449 else if (r_ptr
->flags1
& RF1_MALE
) msex
= 1;
452 /* Count the number of "known" attacks */
453 for (n
= 0, m
= 0; m
< MONSTER_BLOW_MAX
; m
++)
455 /* Skip non-attacks */
456 if (!r_ptr
->blow
[m
].method
) continue;
458 /* Count known attacks */
459 if (l_ptr
->blows
[m
]) n
++;
462 /* Examine (and count) the actual attacks */
463 for (r
= 0, m
= 0; m
< MONSTER_BLOW_MAX
; m
++)
465 int method
, effect
, d1
, d2
;
467 /* Skip non-attacks */
468 if (!r_ptr
->blow
[m
].method
) continue;
470 /* Skip unknown attacks */
471 if (!l_ptr
->blows
[m
]) continue;
474 /* Extract the attack info */
475 method
= r_ptr
->blow
[m
].method
;
476 effect
= r_ptr
->blow
[m
].effect
;
477 d1
= r_ptr
->blow
[m
].d_dice
;
478 d2
= r_ptr
->blow
[m
].d_side
;
487 case RBM_HIT
: p
= "hit"; break;
488 case RBM_TOUCH
: p
= "touch"; break;
489 case RBM_PUNCH
: p
= "punch"; break;
490 case RBM_KICK
: p
= "kick"; break;
491 case RBM_CLAW
: p
= "claw"; break;
492 case RBM_BITE
: p
= "bite"; break;
493 case RBM_STING
: p
= "sting"; break;
494 case RBM_XXX1
: break;
495 case RBM_BUTT
: p
= "butt"; break;
496 case RBM_CRUSH
: p
= "crush"; break;
497 case RBM_ENGULF
: p
= "engulf"; break;
498 case RBM_XXX2
: break;
499 case RBM_CRAWL
: p
= "crawl on you"; break;
500 case RBM_DROOL
: p
= "drool on you"; break;
501 case RBM_SPIT
: p
= "spit"; break;
502 case RBM_XXX3
: break;
503 case RBM_GAZE
: p
= "gaze"; break;
504 case RBM_WAIL
: p
= "wail"; break;
505 case RBM_SPORE
: p
= "release spores"; break;
506 case RBM_XXX4
: break;
507 case RBM_BEG
: p
= "beg"; break;
508 case RBM_INSULT
: p
= "insult"; break;
509 case RBM_MOAN
: p
= "moan"; break;
510 case RBM_XXX5
: break;
520 case RBE_HURT
: q
= "attack"; break;
521 case RBE_POISON
: q
= "poison"; break;
522 case RBE_UN_BONUS
: q
= "disenchant"; break;
523 case RBE_UN_POWER
: q
= "drain charges"; break;
524 case RBE_EAT_GOLD
: q
= "steal gold"; break;
525 case RBE_EAT_ITEM
: q
= "steal items"; break;
526 case RBE_EAT_FOOD
: q
= "eat your food"; break;
527 case RBE_EAT_LITE
: q
= "absorb light"; break;
528 case RBE_ACID
: q
= "shoot acid"; break;
529 case RBE_ELEC
: q
= "electrify"; break;
530 case RBE_FIRE
: q
= "burn"; break;
531 case RBE_COLD
: q
= "freeze"; break;
532 case RBE_BLIND
: q
= "blind"; break;
533 case RBE_CONFUSE
: q
= "confuse"; break;
534 case RBE_TERRIFY
: q
= "terrify"; break;
535 case RBE_PARALYZE
: q
= "paralyze"; break;
536 case RBE_LOSE_STR
: q
= "reduce strength"; break;
537 case RBE_LOSE_INT
: q
= "reduce intelligence"; break;
538 case RBE_LOSE_WIS
: q
= "reduce wisdom"; break;
539 case RBE_LOSE_DEX
: q
= "reduce dexterity"; break;
540 case RBE_LOSE_CON
: q
= "reduce constitution"; break;
541 case RBE_LOSE_CHR
: q
= "reduce charisma"; break;
542 case RBE_LOSE_ALL
: q
= "reduce all stats"; break;
543 case RBE_SHATTER
: q
= "shatter"; break;
544 case RBE_EXP_10
: q
= "lower experience"; break;
545 case RBE_EXP_20
: q
= "lower experience"; break;
546 case RBE_EXP_40
: q
= "lower experience"; break;
547 case RBE_EXP_80
: q
= "lower experience"; break;
548 case RBE_HALLU
: q
= "cause hallucinations"; break;
552 /* Introduce the attack description */
555 text_out(format("%^s can ", wd_he
[msex
]));
567 /* Hack -- force a method */
568 if (!p
) p
= "do something weird";
570 /* Describe the method */
574 /* Describe the effect (if any) */
577 /* Describe the attack type */
579 text_out_c(TERM_L_RED
, q
);
581 /* Describe damage (if known) */
582 if (d1
&& d2
&& know_damage(r_idx
, l_ptr
, m
))
584 /* Display the damage */
585 text_out(" with damage");
586 text_out(format(" %dd%d", d1
, d2
));
591 /* Count the attacks as printed */
595 /* Finish sentence above */
601 /* Notice lack of attacks */
602 else if (l_ptr
->flags1
& RF1_NEVER_BLOW
)
604 text_out(format("%^s has no physical attacks. ", wd_he
[msex
]));
607 /* Or describe the lack of knowledge */
610 text_out(format("Nothing is known about %s attack. ", wd_his
[msex
]));
615 static void describe_monster_abilities(int r_idx
, const monster_lore
*l_ptr
)
617 const monster_race
*r_ptr
= &r_info
[r_idx
];
627 /* Extract a gender (if applicable) */
628 if (r_ptr
->flags1
& RF1_FEMALE
) msex
= 2;
629 else if (r_ptr
->flags1
& RF1_MALE
) msex
= 1;
631 /* Collect special abilities. */
633 if (l_ptr
->flags2
& RF2_OPEN_DOOR
) vp
[vn
++] = "open doors";
634 if (l_ptr
->flags2
& RF2_BASH_DOOR
) vp
[vn
++] = "bash down doors";
635 if (l_ptr
->flags2
& RF2_PASS_WALL
) vp
[vn
++] = "pass through walls";
636 if (l_ptr
->flags2
& RF2_KILL_WALL
) vp
[vn
++] = "bore through walls";
637 if (l_ptr
->flags2
& RF2_MOVE_BODY
) vp
[vn
++] = "push past weaker monsters";
638 if (l_ptr
->flags2
& RF2_KILL_BODY
) vp
[vn
++] = "destroy weaker monsters";
639 if (l_ptr
->flags2
& RF2_TAKE_ITEM
) vp
[vn
++] = "pick up objects";
640 if (l_ptr
->flags2
& RF2_KILL_ITEM
) vp
[vn
++] = "destroy objects";
642 /* Describe special abilities. */
646 text_out(format("%^s", wd_he
[msex
]));
649 for (n
= 0; n
< vn
; n
++)
652 if (n
== 0) text_out(" can ");
653 else if (n
< vn
-1) text_out(", ");
654 else text_out(" and ");
665 /* Describe special abilities. */
666 if (l_ptr
->flags2
& RF2_INVISIBLE
)
668 text_out(format("%^s is invisible. ", wd_he
[msex
]));
670 if (l_ptr
->flags2
& RF2_COLD_BLOOD
)
672 text_out(format("%^s is cold blooded. ", wd_he
[msex
]));
674 if (l_ptr
->flags2
& RF2_EMPTY_MIND
)
676 text_out(format("%^s is not detected by telepathy. ", wd_he
[msex
]));
678 if (l_ptr
->flags2
& RF2_WEIRD_MIND
)
680 text_out(format("%^s is rarely detected by telepathy. ", wd_he
[msex
]));
682 if (l_ptr
->flags2
& RF2_MULTIPLY
)
684 text_out(format("%^s breeds explosively. ", wd_he
[msex
]));
686 if (l_ptr
->flags2
& RF2_REGENERATE
)
688 text_out(format("%^s regenerates quickly. ", wd_he
[msex
]));
692 /* Collect susceptibilities */
694 if (l_ptr
->flags3
& RF3_HURT_ROCK
) vp
[vn
++] = "rock remover";
695 if (l_ptr
->flags3
& RF3_HURT_LITE
) vp
[vn
++] = "bright light";
696 if (l_ptr
->flags3
& RF3_HURT_FIRE
) vp
[vn
++] = "fire";
697 if (l_ptr
->flags3
& RF3_HURT_COLD
) vp
[vn
++] = "cold";
699 /* Describe susceptibilities */
703 text_out(format("%^s", wd_he
[msex
]));
706 for (n
= 0; n
< vn
; n
++)
709 if (n
== 0) text_out(" is hurt by ");
710 else if (n
< vn
-1) text_out(", ");
711 else text_out(" and ");
714 text_out_c(TERM_YELLOW
, vp
[n
]);
722 /* Collect immunities and resistances */
724 if (l_ptr
->flags3
& RF3_IM_ACID
) vp
[vn
++] = "acid";
725 if (l_ptr
->flags3
& RF3_IM_ELEC
) vp
[vn
++] = "lightning";
726 if (l_ptr
->flags3
& RF3_IM_FIRE
) vp
[vn
++] = "fire";
727 if (l_ptr
->flags3
& RF3_IM_COLD
) vp
[vn
++] = "cold";
728 if (l_ptr
->flags3
& RF3_IM_POIS
) vp
[vn
++] = "poison";
729 if (l_ptr
->flags3
& RF3_IM_WATER
) vp
[vn
++] = "water";
730 if (l_ptr
->flags3
& RF3_RES_NETH
) vp
[vn
++] = "nether";
731 if (l_ptr
->flags3
& RF3_RES_PLAS
) vp
[vn
++] = "plasma";
732 if (l_ptr
->flags3
& RF3_RES_NEXUS
) vp
[vn
++] = "nexus";
733 if (l_ptr
->flags3
& RF3_RES_DISE
) vp
[vn
++] = "disenchantment";
735 /* Describe immunities and resistances */
739 text_out(format("%^s", wd_he
[msex
]));
742 for (n
= 0; n
< vn
; n
++)
745 if (n
== 0) text_out(" resists ");
746 else if (n
< vn
-1) text_out(", ");
747 else text_out(" and ");
750 text_out_c(TERM_ORANGE
, vp
[n
]);
758 /* Collect non-effects */
760 if (l_ptr
->flags3
& RF3_NO_STUN
) vp
[vn
++] = "stunned";
761 if (l_ptr
->flags3
& RF3_NO_FEAR
) vp
[vn
++] = "frightened";
762 if (l_ptr
->flags3
& RF3_NO_CONF
) vp
[vn
++] = "confused";
763 if (l_ptr
->flags3
& RF3_NO_SLEEP
) vp
[vn
++] = "slept";
765 /* Describe non-effects */
769 text_out(format("%^s", wd_he
[msex
]));
772 for (n
= 0; n
< vn
; n
++)
775 if (n
== 0) text_out(" cannot be ");
776 else if (n
< vn
-1) text_out(", ");
777 else text_out(" or ");
780 text_out_c(TERM_YELLOW
, vp
[n
]);
788 /* Do we know how aware it is? */
789 if ((((int)l_ptr
->wake
* (int)l_ptr
->wake
) > r_ptr
->sleep
) ||
790 (l_ptr
->ignore
== MAX_UCHAR
) ||
791 ((r_ptr
->sleep
== 0) && (l_ptr
->tkills
>= 10)))
795 if (r_ptr
->sleep
> 200)
797 act
= "prefers to ignore";
799 else if (r_ptr
->sleep
> 95)
801 act
= "pays very little attention to";
803 else if (r_ptr
->sleep
> 75)
805 act
= "pays little attention to";
807 else if (r_ptr
->sleep
> 45)
809 act
= "tends to overlook";
811 else if (r_ptr
->sleep
> 25)
813 act
= "takes quite a while to see";
815 else if (r_ptr
->sleep
> 10)
817 act
= "takes a while to see";
819 else if (r_ptr
->sleep
> 5)
821 act
= "is fairly observant of";
823 else if (r_ptr
->sleep
> 3)
825 act
= "is observant of";
827 else if (r_ptr
->sleep
> 1)
829 act
= "is very observant of";
831 else if (r_ptr
->sleep
> 0)
833 act
= "is vigilant for";
837 act
= "is ever vigilant for";
840 text_out(format("%^s %s intruders, which %s may notice from %d feet. ",
841 wd_he
[msex
], act
, wd_he
[msex
], 10 * r_ptr
->aaf
));
844 /* Describe escorts */
845 if ((l_ptr
->flags1
& RF1_ESCORT
) || (l_ptr
->flags1
& RF1_ESCORTS
))
847 text_out(format("%^s usually appears with escorts. ",
851 /* Describe friends */
852 else if ((l_ptr
->flags1
& RF1_FRIEND
) || (l_ptr
->flags1
& RF1_FRIENDS
))
854 text_out(format("%^s usually appears in groups. ",
860 static void describe_monster_kills(int r_idx
, const monster_lore
*l_ptr
)
862 const monster_race
*r_ptr
= &r_info
[r_idx
];
869 /* Extract a gender (if applicable) */
870 if (r_ptr
->flags1
& RF1_FEMALE
) msex
= 2;
871 else if (r_ptr
->flags1
& RF1_MALE
) msex
= 1;
874 /* Treat uniques differently */
875 if (l_ptr
->flags1
& RF1_UNIQUE
)
877 /* Hack -- Determine if the unique is "dead" */
878 bool dead
= (r_ptr
->max_num
== 0) ? TRUE
: FALSE
;
880 /* We've been killed... */
883 /* Killed ancestors */
884 text_out(format("%^s has slain %d of your ancestors",
885 wd_he
[msex
], l_ptr
->deaths
));
887 /* But we've also killed it */
890 text_out(", but you have taken revenge! ");
893 /* Unavenged (ever) */
896 text_out(format(", who %s unavenged. ",
897 plural(l_ptr
->deaths
, "remains", "remain")));
901 /* Dead unique who never hurt us */
904 text_out("You have slain this foe. ");
908 /* Alive and never killed us */
913 /* Not unique, but killed us */
914 else if (l_ptr
->deaths
)
917 text_out(format("%d of your ancestors %s been killed by this creature, ",
918 l_ptr
->deaths
, plural(l_ptr
->deaths
, "has", "have")));
920 /* Some kills this life */
923 text_out(format("and you have exterminated at least %d of the creatures. ",
927 /* Some kills past lives */
928 else if (l_ptr
->tkills
)
930 text_out(format("and %s have exterminated at least %d of the creatures. ",
931 "your ancestors", l_ptr
->tkills
));
937 text_out_c(TERM_RED
, format("and %s is not ever known to have been defeated. ",
942 /* Normal monsters */
945 /* Killed some this life */
948 text_out(format("You have killed at least %d of these creatures. ",
952 /* Killed some last life */
953 else if (l_ptr
->tkills
)
955 text_out(format("Your ancestors have killed at least %d of these creatures. ",
962 text_out("No battles to the death are recalled. ");
967 if (out
) text_out("\n");
971 static void describe_monster_toughness(int r_idx
, const monster_lore
*l_ptr
)
973 const monster_race
*r_ptr
= &r_info
[r_idx
];
978 /* Extract a gender (if applicable) */
979 if (r_ptr
->flags1
& RF1_FEMALE
) msex
= 2;
980 else if (r_ptr
->flags1
& RF1_MALE
) msex
= 1;
982 /* Describe monster "toughness" */
983 if (know_armour(r_idx
, l_ptr
))
986 text_out(format("%^s has an armor rating of %d",
987 wd_he
[msex
], r_ptr
->ac
));
989 /* Maximized hitpoints */
990 if (l_ptr
->flags1
& RF1_FORCE_MAXHP
)
992 text_out(format(" and a life rating of %d. ",
993 r_ptr
->hdice
* r_ptr
->hside
));
996 /* Variable hitpoints */
999 text_out(format(" and a life rating of %dd%d. ",
1000 r_ptr
->hdice
, r_ptr
->hside
));
1006 static void describe_monster_exp(int r_idx
, const monster_lore
*l_ptr
)
1008 const monster_race
*r_ptr
= &r_info
[r_idx
];
1015 /* Describe experience if known */
1019 if (l_ptr
->flags1
& RF1_UNIQUE
)
1020 text_out("Killing");
1022 text_out("A kill of");
1024 text_out(" this creature");
1026 /* calculate the integer exp part */
1027 i
= (long)r_ptr
->mexp
* r_ptr
->level
/ p_ptr
->lev
;
1029 /* calculate the fractional exp part scaled by 100, */
1030 /* must use long arithmetic to avoid overflow */
1031 j
= ((((long)r_ptr
->mexp
* r_ptr
->level
% p_ptr
->lev
) *
1032 (long)1000 / p_ptr
->lev
+ 5) / 10);
1034 /* Mention the experience */
1035 text_out(format(" is worth %ld.%02ld point%s",
1037 (((i
== 1) && (j
== 0)) ? "" : "s")));
1039 /* Take account of annoying English */
1041 i
= p_ptr
->lev
% 10;
1042 if ((p_ptr
->lev
/ 10) == 1) /* nothing */;
1043 else if (i
== 1) p
= "st";
1044 else if (i
== 2) p
= "nd";
1045 else if (i
== 3) p
= "rd";
1047 /* Take account of "leading vowels" in numbers */
1050 if ((i
== 8) || (i
== 11) || (i
== 18)) q
= "n";
1052 /* Mention the dependance on the player's level */
1053 text_out(format(" for a%s %lu%s level character. ",
1059 static void describe_monster_movement(int r_idx
, const monster_lore
*l_ptr
)
1061 const monster_race
*r_ptr
= &r_info
[r_idx
];
1068 if (l_ptr
->flags3
& RF3_ANIMAL
) text_out_c(TERM_L_BLUE
, " natural");
1069 if (l_ptr
->flags3
& RF3_EVIL
) text_out_c(TERM_L_BLUE
, " evil");
1070 if (l_ptr
->flags3
& RF3_UNDEAD
) text_out_c(TERM_L_BLUE
, " undead");
1072 if (l_ptr
->flags3
& RF3_DRAGON
) text_out_c(TERM_L_BLUE
, " dragon");
1073 else if (l_ptr
->flags3
& RF3_DEMON
) text_out_c(TERM_L_BLUE
, " demon");
1074 else if (l_ptr
->flags3
& RF3_GIANT
) text_out_c(TERM_L_BLUE
, " giant");
1075 else if (l_ptr
->flags3
& RF3_TROLL
) text_out_c(TERM_L_BLUE
, " troll");
1076 else if (l_ptr
->flags3
& RF3_ORC
) text_out_c(TERM_L_BLUE
, " orc");
1077 else text_out(" creature");
1079 /* Describe location */
1080 if (r_ptr
->level
== 0)
1082 text_out_c(TERM_SLATE
, " lives in the town");
1085 else if (l_ptr
->tkills
)
1087 if (l_ptr
->flags1
& RF1_FORCE_DEPTH
)
1088 text_out_c(TERM_SLATE
, " is found ");
1090 text_out_c(TERM_SLATE
, " is normally found ");
1094 text_out_c(TERM_SLATE
, format("at depths of %d feet",
1095 r_ptr
->level
* 50));
1099 text_out_c(TERM_SLATE
, format("on dungeon level %d",
1105 if (old
) text_out(", and");
1110 if ((l_ptr
->flags1
& RF1_RAND_50
) || (l_ptr
->flags1
& RF1_RAND_25
))
1113 if ((l_ptr
->flags1
& RF1_RAND_50
) && (l_ptr
->flags1
& RF1_RAND_25
))
1115 text_out(" extremely");
1117 else if (l_ptr
->flags1
& RF1_RAND_50
)
1119 text_out(" somewhat");
1121 else if (l_ptr
->flags1
& RF1_RAND_25
)
1127 text_out(" erratically");
1129 /* Hack -- Occasional conjunction */
1130 if (r_ptr
->speed
!= 110) text_out(", and");
1134 if (r_ptr
->speed
> 110)
1136 if (r_ptr
->speed
> 130) text_out_c(TERM_GREEN
, " incredibly");
1137 else if (r_ptr
->speed
> 120) text_out_c(TERM_GREEN
, " very");
1138 text_out_c(TERM_GREEN
, " quickly");
1140 else if (r_ptr
->speed
< 110)
1142 if (r_ptr
->speed
< 90) text_out_c(TERM_GREEN
, " incredibly");
1143 else if (r_ptr
->speed
< 100) text_out_c(TERM_GREEN
, " very");
1144 text_out_c(TERM_GREEN
, " slowly");
1148 text_out_c(TERM_GREEN
, " at normal speed");
1151 /* The code above includes "attack speed" */
1152 if (l_ptr
->flags1
& RF1_NEVER_MOVE
)
1154 text_out(", but does not deign to chase intruders");
1157 /* End this sentence */
1164 * Learn everything about a monster (by cheating)
1166 static void cheat_monster_lore(int r_idx
, monster_lore
*l_ptr
)
1168 const monster_race
*r_ptr
= &r_info
[r_idx
];
1173 /* Hack -- Maximal kills */
1174 l_ptr
->tkills
= MAX_SHORT
;
1176 /* Hack -- Maximal info */
1177 l_ptr
->wake
= l_ptr
->ignore
= MAX_UCHAR
;
1179 /* Observe "maximal" attacks */
1180 for (i
= 0; i
< MONSTER_BLOW_MAX
; i
++)
1182 /* Examine "actual" blows */
1183 if (r_ptr
->blow
[i
].effect
|| r_ptr
->blow
[i
].method
)
1185 /* Hack -- maximal observations */
1186 l_ptr
->blows
[i
] = MAX_UCHAR
;
1190 /* Hack -- maximal drops */
1191 l_ptr
->drop_gold
= l_ptr
->drop_item
=
1192 (((r_ptr
->flags1
& RF1_DROP_4D2
) ? 8 : 0) +
1193 ((r_ptr
->flags1
& RF1_DROP_3D2
) ? 6 : 0) +
1194 ((r_ptr
->flags1
& RF1_DROP_2D2
) ? 4 : 0) +
1195 ((r_ptr
->flags1
& RF1_DROP_1D2
) ? 2 : 0) +
1196 ((r_ptr
->flags1
& RF1_DROP_90
) ? 1 : 0) +
1197 ((r_ptr
->flags1
& RF1_DROP_60
) ? 1 : 0));
1199 /* Hack -- but only "valid" drops */
1200 if (r_ptr
->flags1
& RF1_ONLY_GOLD
) l_ptr
->drop_item
= 0;
1201 if (r_ptr
->flags1
& RF1_ONLY_ITEM
) l_ptr
->drop_gold
= 0;
1203 /* Hack -- observe many spells */
1204 l_ptr
->cast_innate
= MAX_UCHAR
;
1205 l_ptr
->cast_spell
= MAX_UCHAR
;
1207 /* Hack -- know all the flags */
1208 l_ptr
->flags1
= r_ptr
->flags1
;
1209 l_ptr
->flags2
= r_ptr
->flags2
;
1210 l_ptr
->flags3
= r_ptr
->flags3
;
1211 l_ptr
->flags4
= r_ptr
->flags4
;
1212 l_ptr
->flags5
= r_ptr
->flags5
;
1213 l_ptr
->flags6
= r_ptr
->flags6
;
1218 * Hack -- display monster information using "roff()"
1220 * Note that there is now a compiler option to only read the monster
1221 * descriptions from the raw file when they are actually needed, which
1222 * saves about 60K of memory at the cost of disk access during monster
1223 * recall, which is optional to the user.
1225 * This function should only be called with the cursor placed at the
1226 * left edge of the screen, on a cleared line, in which the recall is
1227 * to take place. One extra blank line is left after the recall.
1229 void describe_monster(int r_idx
, bool spoilers
)
1233 /* Get the race and lore */
1234 const monster_race
*r_ptr
= &r_info
[r_idx
];
1235 monster_lore
*l_ptr
= &l_list
[r_idx
];
1238 /* Hack -- create a copy of the monster-memory */
1239 COPY(&lore
, l_ptr
, monster_lore
);
1241 /* Assume some "obvious" flags */
1242 lore
.flags1
|= (r_ptr
->flags1
& RF1_OBVIOUS_MASK
);
1245 /* Killing a monster reveals some properties */
1248 /* Know "race" flags */
1249 lore
.flags3
|= (r_ptr
->flags3
& RF3_RACE_MASK
);
1251 /* Know "forced" flags */
1252 lore
.flags1
|= (r_ptr
->flags1
& (RF1_FORCE_DEPTH
| RF1_FORCE_MAXHP
));
1255 /* Cheat -- know everything */
1256 if (cheat_know
|| spoilers
) cheat_monster_lore(r_idx
, &lore
);
1258 /* Show kills of monster vs. player(s) */
1260 describe_monster_kills(r_idx
, &lore
);
1262 /* Monster description */
1263 describe_monster_desc(r_idx
);
1265 /* Describe the movement and level of the monster */
1266 describe_monster_movement(r_idx
, &lore
);
1268 /* Describe experience */
1269 if (!spoilers
) describe_monster_exp(r_idx
, &lore
);
1271 /* Describe spells and innate attacks */
1272 describe_monster_spells(r_idx
, &lore
);
1274 /* Describe monster "toughness" */
1275 if (!spoilers
) describe_monster_toughness(r_idx
, &lore
);
1277 /* Describe the abilities of the monster */
1278 describe_monster_abilities(r_idx
, &lore
);
1280 /* Describe the monster drop */
1281 describe_monster_drop(r_idx
, &lore
);
1283 /* Describe the known attacks */
1284 describe_monster_attack(r_idx
, &lore
);
1286 /* Notice "Quest" monsters */
1287 if (lore
.flags1
& RF1_QUESTOR
)
1289 text_out("You feel an intense desire to kill this monster... ");
1301 * Hack -- Display the "name" and "attr/chars" of a monster race
1303 void roff_top(int r_idx
)
1305 monster_race
*r_ptr
= &r_info
[r_idx
];
1320 /* Clear the top line */
1321 Term_erase(0, 0, 255);
1323 /* Reset the cursor */
1326 /* A title (use "The" for non-uniques) */
1327 if (!(r_ptr
->flags1
& RF1_UNIQUE
))
1329 Term_addstr(-1, TERM_WHITE
, "The ");
1333 Term_addstr(-1, TERM_WHITE
, (r_name
+ r_ptr
->name
));
1335 /* Append the "standard" attr/char info */
1336 Term_addstr(-1, TERM_WHITE
, " ('");
1338 Term_addstr(-1, TERM_WHITE
, "')");
1340 /* Append the "optional" attr/char info */
1341 Term_addstr(-1, TERM_WHITE
, "/('");
1343 if (use_bigtile
&& (a2
& 0x80)) Term_addch(255, -1);
1344 Term_addstr(-1, TERM_WHITE
, "'):");
1350 * Hack -- describe the given monster race at the top of the screen
1352 void screen_roff(int r_idx
)
1354 /* Flush messages */
1358 Term_erase(0, 1, 255);
1360 /* Output to the screen */
1361 text_out_hook
= text_out_to_screen
;
1363 /* Recall monster */
1364 describe_monster(r_idx
, FALSE
);
1366 /* Describe monster */
1374 * Hack -- describe the given monster race in the current "term" window
1376 void display_roff(int r_idx
)
1380 /* Erase the window */
1381 for (y
= 0; y
< Term
->hgt
; y
++)
1383 /* Erase the line */
1384 Term_erase(0, y
, 255);
1390 /* Output to the screen */
1391 text_out_hook
= text_out_to_screen
;
1393 /* Recall monster */
1394 describe_monster(r_idx
, FALSE
);
1396 /* Describe monster */