2 * @brief モンスターの思い出を表示する処理
7 #include "view/display-lore.h"
8 #include "game-option/text-display-options.h"
9 #include "locale/english.h"
10 #include "locale/japanese.h"
11 #include "lore/lore-calculator.h"
12 #include "lore/monster-lore.h"
13 #include "monster-race/monster-race.h"
14 #include "monster-race/race-flags1.h"
15 #include "monster-race/race-flags2.h"
16 #include "monster-race/race-flags3.h"
17 #include "monster-race/race-flags4.h"
18 #include "monster-race/race-flags7.h"
19 #include "monster-race/race-indice-types.h"
20 #include "mspell/mspell-type.h"
21 #include "term/screen-processor.h"
22 #include "term/term-color-types.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
27 * 英語の複数系記述用マクロ / Pluralizer. Args(count, singular, plural)
29 #define plural(c, s, p) (((c) == 1) ? (s) : (p))
32 * @brief モンスター情報のヘッダを記述する
33 * Hack -- Display the "name" and "attr/chars" of a monster race
34 * @param r_idx モンスターの種族ID
37 void roff_top(MONRACE_IDX r_idx)
39 monster_race *r_ptr = &r_info[r_idx];
40 char c1 = r_ptr->d_char;
41 char c2 = r_ptr->x_char;
43 TERM_COLOR a1 = r_ptr->d_attr;
44 TERM_COLOR a2 = r_ptr->x_attr;
46 Term_erase(0, 0, 255);
51 if (!(r_ptr->flags1 & RF1_UNIQUE)) {
52 Term_addstr(-1, TERM_WHITE, "The ");
56 Term_addstr(-1, TERM_WHITE, (r_name + r_ptr->name));
58 Term_addstr(-1, TERM_WHITE, " ('");
59 Term_add_bigch(a1, c1);
60 Term_addstr(-1, TERM_WHITE, "')");
62 Term_addstr(-1, TERM_WHITE, "/('");
63 Term_add_bigch(a2, c2);
64 Term_addstr(-1, TERM_WHITE, "'):");
66 if (!current_world_ptr->wizard)
70 sprintf(buf, "%d", r_idx);
71 Term_addstr(-1, TERM_WHITE, " (");
72 Term_addstr(-1, TERM_L_BLUE, buf);
73 Term_addch(TERM_WHITE, ')');
77 * @brief モンスター情報の表示と共に画面を一時消去するサブルーチン /
78 * Hack -- describe the given monster race at the top of the screen
79 * @param r_idx モンスターの種族ID
83 void screen_roff(player_type *player_ptr, MONRACE_IDX r_idx, BIT_FLAGS mode)
86 Term_erase(0, 1, 255);
88 process_monster_lore(player_ptr, r_idx, mode);
93 * @brief モンスター情報の現在のウィンドウに表示する /
94 * Hack -- describe the given monster race in the current "term" window
95 * @param r_idx モンスターの種族ID
98 void display_roff(player_type *player_ptr)
100 for (int y = 0; y < Term->hgt; y++) {
101 Term_erase(0, y, 255);
105 hook_c_roff = c_roff;
106 MONRACE_IDX r_idx = player_ptr->monster_race_idx;
107 process_monster_lore(player_ptr, r_idx, 0);
112 * @brief モンスター詳細情報を自動スポイラー向けに出力する /
113 * Hack -- output description of the given monster race
114 * @param r_idx モンスターの種族ID
115 * @param roff_func 出力処理を行う関数ポインタ
118 void output_monster_spoiler(player_type *player_ptr, MONRACE_IDX r_idx, void (*roff_func)(TERM_COLOR attr, concptr str))
120 hook_c_roff = roff_func;
121 process_monster_lore(player_ptr, r_idx, 0x03);
124 static bool display_kill_unique(lore_type *lore_ptr)
126 if ((lore_ptr->flags1 & RF1_UNIQUE) == 0)
129 bool dead = (lore_ptr->r_ptr->max_num == 0);
130 if (lore_ptr->r_ptr->r_deaths) {
131 hooked_roff(format(_("%^sはあなたの先祖を %d 人葬っている", "%^s has slain %d of your ancestors"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->r_deaths));
135 _(format("が、すでに仇討ちは果たしている!"), format(", but you have avenged %s! ", plural(lore_ptr->r_ptr->r_deaths, "him", "them"))));
138 _(format("のに、まだ仇討ちを果たしていない。"), format(", who %s unavenged. ", plural(lore_ptr->r_ptr->r_deaths, "remains", "remain"))));
143 hooked_roff(_("あなたはこの仇敵をすでに葬り去っている。", "You have slain this foe. "));
150 static bool display_killed(lore_type *lore_ptr)
152 if (lore_ptr->r_ptr->r_deaths == 0)
155 hooked_roff(_(format("このモンスターはあなたの先祖を %d 人葬っている", lore_ptr->r_ptr->r_deaths),
156 format("%d of your ancestors %s been killed by this creature, ", lore_ptr->r_ptr->r_deaths, plural(lore_ptr->r_ptr->r_deaths, "has", "have"))));
158 if (lore_ptr->r_ptr->r_pkills) {
159 hooked_roff(format(_("が、あなたはこのモンスターを少なくとも %d 体は倒している。", "and you have exterminated at least %d of the creatures. "),
160 lore_ptr->r_ptr->r_pkills));
161 } else if (lore_ptr->r_ptr->r_tkills) {
163 _("が、あなたの先祖はこのモンスターを少なくとも %d 体は倒している。", "and your ancestors have exterminated at least %d of the creatures. "),
164 lore_ptr->r_ptr->r_tkills));
166 hooked_roff(format(_("が、まだ%sを倒したことはない。", "and %s is not ever known to have been defeated. "), wd_he[lore_ptr->msex]));
173 void display_kill_numbers(lore_type *lore_ptr)
175 if ((lore_ptr->mode & 0x02) != 0)
178 if (display_kill_unique(lore_ptr))
181 if (display_killed(lore_ptr))
184 if (lore_ptr->r_ptr->r_pkills) {
186 _("あなたはこのモンスターを少なくとも %d 体は殺している。", "You have killed at least %d of these creatures. "), lore_ptr->r_ptr->r_pkills));
187 } else if (lore_ptr->r_ptr->r_tkills) {
188 hooked_roff(format(_("あなたの先祖はこのモンスターを少なくとも %d 体は殺している。", "Your ancestors have killed at least %d of these creatures. "),
189 lore_ptr->r_ptr->r_tkills));
191 hooked_roff(_("このモンスターを倒したことはない。", "No battles to the death are recalled. "));
198 * @brief どこに出没するかを表示する
199 * @param lore_ptr モンスターの思い出構造体への参照ポインタ
200 * @return たぬきならFALSE、それ以外はTRUE
202 bool display_where_to_appear(lore_type *lore_ptr)
204 lore_ptr->old = FALSE;
205 if (lore_ptr->r_ptr->level == 0) {
206 hooked_roff(format(_("%^sは町に住み", "%^s lives in the town"), wd_he[lore_ptr->msex]));
207 lore_ptr->old = TRUE;
208 } else if (lore_ptr->r_ptr->r_tkills || lore_ptr->know_everything) {
211 _("%^sは通常地下 %d フィートで出現し", "%^s is normally found at depths of %d feet"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->level * 50));
213 hooked_roff(format(_("%^sは通常地下 %d 階で出現し", "%^s is normally found on dungeon level %d"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->level));
216 lore_ptr->old = TRUE;
219 if (lore_ptr->r_idx == MON_CHAMELEON) {
220 hooked_roff(_("、他のモンスターに化ける。", "and can take the shape of other monster."));
225 hooked_roff(_("、", ", and "));
227 hooked_roff(format(_("%^sは", "%^s "), wd_he[lore_ptr->msex]));
228 lore_ptr->old = TRUE;
234 void display_monster_move(lore_type *lore_ptr)
238 hooked_roff("moves");
241 display_random_move(lore_ptr);
242 if (lore_ptr->speed > 110) {
243 if (lore_ptr->speed > 139)
244 hook_c_roff(TERM_RED, _("信じ難いほど", " incredibly"));
245 else if (lore_ptr->speed > 134)
246 hook_c_roff(TERM_ORANGE, _("猛烈に", " extremely"));
247 else if (lore_ptr->speed > 129)
248 hook_c_roff(TERM_ORANGE, _("非常に", " very"));
249 else if (lore_ptr->speed > 124)
250 hook_c_roff(TERM_UMBER, _("かなり", " fairly"));
251 else if (lore_ptr->speed < 120)
252 hook_c_roff(TERM_L_UMBER, _("やや", " somewhat"));
253 hook_c_roff(TERM_L_RED, _("素早く", " quickly"));
254 } else if (lore_ptr->speed < 110) {
255 if (lore_ptr->speed < 90)
256 hook_c_roff(TERM_L_GREEN, _("信じ難いほど", " incredibly"));
257 else if (lore_ptr->speed < 95)
258 hook_c_roff(TERM_BLUE, _("非常に", " very"));
259 else if (lore_ptr->speed < 100)
260 hook_c_roff(TERM_BLUE, _("かなり", " fairly"));
261 else if (lore_ptr->speed > 104)
262 hook_c_roff(TERM_GREEN, _("やや", " somewhat"));
263 hook_c_roff(TERM_L_BLUE, _("ゆっくりと", " slowly"));
265 hooked_roff(_("普通の速さで", " at normal speed"));
269 hooked_roff("動いている");
273 void display_random_move(lore_type *lore_ptr)
275 if (((lore_ptr->flags1 & RF1_RAND_50) == 0) && ((lore_ptr->flags1 & RF1_RAND_25) == 0))
278 if ((lore_ptr->flags1 & RF1_RAND_50) && (lore_ptr->flags1 & RF1_RAND_25)) {
279 hooked_roff(_("かなり", " extremely"));
280 } else if (lore_ptr->flags1 & RF1_RAND_50) {
281 hooked_roff(_("幾分", " somewhat"));
282 } else if (lore_ptr->flags1 & RF1_RAND_25) {
283 hooked_roff(_("少々", " a bit"));
286 hooked_roff(_("不規則に", " erratically"));
287 if (lore_ptr->speed != 110)
288 hooked_roff(_("、かつ", ", and"));
291 void display_monster_never_move(lore_type *lore_ptr)
293 if ((lore_ptr->flags1 & RF1_NEVER_MOVE) == 0)
297 hooked_roff(_("、しかし", ", but "));
299 hooked_roff(format(_("%^sは", "%^s "), wd_he[lore_ptr->msex]));
300 lore_ptr->old = TRUE;
303 hooked_roff(_("侵入者を追跡しない", "does not deign to chase intruders"));
306 void display_monster_kind(lore_type *lore_ptr)
308 if (((lore_ptr->flags3 & (RF3_DRAGON | RF3_DEMON | RF3_GIANT | RF3_TROLL | RF3_ORC | RF3_ANGEL)) == 0) && ((lore_ptr->flags2 & (RF2_QUANTUM | RF2_HUMAN)) == 0)) {
309 hooked_roff(_("モンスター", " creature"));
313 if (lore_ptr->flags3 & RF3_DRAGON)
314 hook_c_roff(TERM_ORANGE, _("ドラゴン", " dragon"));
316 if (lore_ptr->flags3 & RF3_DEMON)
317 hook_c_roff(TERM_VIOLET, _("デーモン", " demon"));
319 if (lore_ptr->flags3 & RF3_GIANT)
320 hook_c_roff(TERM_L_UMBER, _("巨人", " giant"));
322 if (lore_ptr->flags3 & RF3_TROLL)
323 hook_c_roff(TERM_BLUE, _("トロル", " troll"));
325 if (lore_ptr->flags3 & RF3_ORC)
326 hook_c_roff(TERM_UMBER, _("オーク", " orc"));
328 if (lore_ptr->flags2 & RF2_HUMAN)
329 hook_c_roff(TERM_L_WHITE, _("人間", " human"));
331 if (lore_ptr->flags2 & RF2_QUANTUM)
332 hook_c_roff(TERM_VIOLET, _("量子生物", " quantum creature"));
334 if (lore_ptr->flags3 & RF3_ANGEL)
335 hook_c_roff(TERM_YELLOW, _("天使", " angel"));
338 void display_monster_alignment(lore_type *lore_ptr)
340 if (lore_ptr->flags2 & RF2_ELDRITCH_HORROR)
341 hook_c_roff(TERM_VIOLET, _("狂気を誘う", " sanity-blasting"));
343 if (lore_ptr->flags3 & RF3_ANIMAL)
344 hook_c_roff(TERM_L_GREEN, _("自然界の", " natural"));
346 if (lore_ptr->flags3 & RF3_EVIL)
347 hook_c_roff(TERM_L_DARK, _("邪悪なる", " evil"));
349 if (lore_ptr->flags3 & RF3_GOOD)
350 hook_c_roff(TERM_YELLOW, _("善良な", " good"));
352 if (lore_ptr->flags3 & RF3_UNDEAD)
353 hook_c_roff(TERM_VIOLET, _("アンデッドの", " undead"));
355 if (lore_ptr->flags3 & RF3_AMBERITE)
356 hook_c_roff(TERM_VIOLET, _("アンバーの王族の", " Amberite"));
359 void display_monster_exp(player_type *player_ptr, lore_type *lore_ptr)
362 hooked_roff("を倒すことは");
364 long exp_integer = (long)lore_ptr->r_ptr->mexp * lore_ptr->r_ptr->level / (player_ptr->max_plv + 2) * 3 / 2;
366 = ((((long)lore_ptr->r_ptr->mexp * lore_ptr->r_ptr->level % (player_ptr->max_plv + 2) * 3 / 2) * (long)1000 / (player_ptr->max_plv + 2) + 5) / 10);
369 hooked_roff(format(" %d レベルのキャラクタにとって 約%ld.%02ld ポイントの経験となる。", player_ptr->lev, (long)exp_integer, (long)exp_decimal));
371 hooked_roff(format(" is worth about %ld.%02ld point%s", (long)exp_integer, (long)exp_decimal, ((exp_integer == 1) && (exp_decimal == 0)) ? "" : "s"));
375 exp_integer = player_ptr->lev % 10;
376 if ((player_ptr->lev / 10) != 1) {
377 if (exp_integer == 1)
379 else if (exp_integer == 2)
381 else if (exp_integer == 3)
387 exp_integer = player_ptr->lev;
388 if ((exp_integer == 8) || (exp_integer == 11) || (exp_integer == 18))
391 hooked_roff(format(" for a%s %lu%s level character. ", vowel, (long)exp_integer, ordinal));
395 void display_monster_aura(lore_type *lore_ptr)
397 if ((lore_ptr->flags2 & RF2_AURA_FIRE) && (lore_ptr->flags2 & RF2_AURA_ELEC) && (lore_ptr->flags3 & RF3_AURA_COLD))
399 TERM_VIOLET, format(_("%^sは炎と氷とスパークに包まれている。", "%^s is surrounded by flames, ice and electricity. "), wd_he[lore_ptr->msex]));
400 else if ((lore_ptr->flags2 & RF2_AURA_FIRE) && (lore_ptr->flags2 & RF2_AURA_ELEC))
401 hook_c_roff(TERM_L_RED, format(_("%^sは炎とスパークに包まれている。", "%^s is surrounded by flames and electricity. "), wd_he[lore_ptr->msex]));
402 else if ((lore_ptr->flags2 & RF2_AURA_FIRE) && (lore_ptr->flags3 & RF3_AURA_COLD))
403 hook_c_roff(TERM_BLUE, format(_("%^sは炎と氷に包まれている。", "%^s is surrounded by flames and ice. "), wd_he[lore_ptr->msex]));
404 else if ((lore_ptr->flags3 & RF3_AURA_COLD) && (lore_ptr->flags2 & RF2_AURA_ELEC))
405 hook_c_roff(TERM_L_GREEN, format(_("%^sは氷とスパークに包まれている。", "%^s is surrounded by ice and electricity. "), wd_he[lore_ptr->msex]));
406 else if (lore_ptr->flags2 & RF2_AURA_FIRE)
407 hook_c_roff(TERM_RED, format(_("%^sは炎に包まれている。", "%^s is surrounded by flames. "), wd_he[lore_ptr->msex]));
408 else if (lore_ptr->flags3 & RF3_AURA_COLD)
409 hook_c_roff(TERM_BLUE, format(_("%^sは氷に包まれている。", "%^s is surrounded by ice. "), wd_he[lore_ptr->msex]));
410 else if (lore_ptr->flags2 & RF2_AURA_ELEC)
411 hook_c_roff(TERM_L_BLUE, format(_("%^sはスパークに包まれている。", "%^s is surrounded by electricity. "), wd_he[lore_ptr->msex]));
414 void display_lore_this(player_type *player_ptr, lore_type *lore_ptr)
416 if ((lore_ptr->r_ptr->r_tkills == 0) && !lore_ptr->know_everything)
422 if (lore_ptr->flags1 & RF1_UNIQUE) {
423 hooked_roff("Killing this");
425 hooked_roff("A kill of this");
429 display_monster_alignment(lore_ptr);
430 display_monster_kind(lore_ptr);
431 display_monster_exp(player_ptr, lore_ptr);
434 static void display_monster_escort_contents(lore_type *lore_ptr)
436 if (!lore_ptr->reinforce)
439 hooked_roff(_("護衛の構成は", "These escorts"));
440 if ((lore_ptr->flags1 & RF1_ESCORT) || (lore_ptr->flags1 & RF1_ESCORTS)) {
441 hooked_roff(_("少なくとも", " at the least"));
446 hooked_roff(" contain ");
449 for (int n = 0; n < A_MAX; n++) {
450 bool is_reinforced = lore_ptr->r_ptr->reinforce_id[n] > 0;
451 is_reinforced &= lore_ptr->r_ptr->reinforce_dd[n] > 0;
452 is_reinforced &= lore_ptr->r_ptr->reinforce_ds[n] > 0;
456 monster_race *rf_ptr = &r_info[lore_ptr->r_ptr->reinforce_id[n]];
457 if (rf_ptr->flags1 & RF1_UNIQUE) {
458 hooked_roff(format(_("、%s", ", %s"), r_name + rf_ptr->name));
463 hooked_roff(format("、 %dd%d 体の%s", lore_ptr->r_ptr->reinforce_dd[n], lore_ptr->r_ptr->reinforce_ds[n], r_name + rf_ptr->name));
465 bool plural = (lore_ptr->r_ptr->reinforce_dd[n] * lore_ptr->r_ptr->reinforce_ds[n] > 1);
466 GAME_TEXT name[MAX_NLEN];
467 strcpy(name, r_name + rf_ptr->name);
470 hooked_roff(format(",%dd%d %s", lore_ptr->r_ptr->reinforce_dd[n], lore_ptr->r_ptr->reinforce_ds[n], name));
474 hooked_roff(_("で成り立っている。", "."));
477 void display_monster_collective(lore_type *lore_ptr)
479 if ((lore_ptr->flags1 & RF1_ESCORT) || (lore_ptr->flags1 & RF1_ESCORTS) || lore_ptr->reinforce) {
480 hooked_roff(format(_("%^sは通常護衛を伴って現れる。", "%^s usually appears with escorts. "), wd_he[lore_ptr->msex]));
481 display_monster_escort_contents(lore_ptr);
483 else if (lore_ptr->flags1 & RF1_FRIENDS) {
484 hooked_roff(format(_("%^sは通常集団で現れる。", "%^s usually appears in groups. "), wd_he[lore_ptr->msex]));
488 void display_monster_launching(player_type *player_ptr, lore_type *lore_ptr)
490 if (lore_ptr->flags4 & RF4_ROCKET) {
491 set_damage(player_ptr, lore_ptr->r_idx, (MS_ROCKET), _("ロケット%sを発射する", "shoot a rocket%s"), lore_ptr->tmp_msg[lore_ptr->vn]);
492 lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
493 lore_ptr->color[lore_ptr->vn++] = TERM_UMBER;
496 if ((lore_ptr->flags4 & RF4_SHOOT) == 0)
499 for (int m = 0; m < 4; m++) {
500 if (lore_ptr->r_ptr->blow[m].method != RBM_SHOOT)
503 if (know_armour(lore_ptr->r_idx))
504 sprintf(lore_ptr->tmp_msg[lore_ptr->vn], _("威力 %dd%d の射撃をする", "fire an arrow (Power:%dd%d)"), lore_ptr->r_ptr->blow[m].d_side,
505 lore_ptr->r_ptr->blow[m].d_dice);
507 sprintf(lore_ptr->tmp_msg[lore_ptr->vn], _("射撃をする", "fire an arrow"));
508 lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
509 lore_ptr->color[lore_ptr->vn++] = TERM_UMBER;
514 void display_monster_sometimes(lore_type *lore_ptr)
516 if (lore_ptr->vn <= 0)
519 hooked_roff(format(_("%^sは", "%^s"), wd_he[lore_ptr->msex]));
520 for (int n = 0; n < lore_ptr->vn; n++) {
522 if (n != lore_ptr->vn - 1) {
523 jverb(lore_ptr->vp[n], lore_ptr->jverb_buf, JVERB_OR);
524 hook_c_roff(lore_ptr->color[n], lore_ptr->jverb_buf);
525 hook_c_roff(lore_ptr->color[n], "り");
528 hook_c_roff(lore_ptr->color[n], lore_ptr->vp[n]);
531 hooked_roff(" may ");
532 else if (n < lore_ptr->vn - 1)
537 hook_c_roff(lore_ptr->color[n], lore_ptr->vp[n]);
541 hooked_roff(_("ことがある。", ". "));
544 void display_monster_guardian(lore_type *lore_ptr)
546 bool is_kingpin = (lore_ptr->flags1 & RF1_QUESTOR) != 0;
547 is_kingpin &= lore_ptr->r_ptr->r_sights > 0;
548 is_kingpin &= lore_ptr->r_ptr->max_num > 0;
549 is_kingpin &= (lore_ptr->r_idx == MON_OBERON) || (lore_ptr->r_idx == MON_SERPENT);
551 hook_c_roff(TERM_VIOLET, _("あなたはこのモンスターを殺したいという強い欲望を感じている...", "You feel an intense desire to kill this monster... "));
552 } else if (lore_ptr->flags7 & RF7_GUARDIAN) {
553 hook_c_roff(TERM_L_RED, _("このモンスターはダンジョンの主である。", "This monster is the master of a dungeon."));