OSDN Git Service

[Refactor] #40521 Moved toggle_inventory_equipment() from player-inventory.c/h to...
[hengband/hengband.git] / src / view / display-player.c
1 /*!
2  * @brief プレーヤーのステータス表示メインルーチン群
3  * @date 2020/02/25
4  * @author Hourier
5  * @details
6  * ここにこれ以上関数を引っ越してくるのは禁止
7  */
8
9 #include "view/display-player.h"
10 #include "info-reader/fixed-map-parser.h"
11 #include "dungeon/quest.h"
12 #include "floor/floor-util.h"
13 #include "floor/floor.h"
14 #include "game-option/text-display-options.h"
15 #include "knowledge/knowledge-mutations.h"
16 #include "object/object-kind.h"
17 #include "object/object-info.h"
18 #include "player/mimic-info-table.h"
19 #include "player/patron.h"
20 #include "player/player-class.h"
21 #include "player/player-personality.h"
22 #include "player/player-sex.h"
23 #include "realm/realm-names-table.h"
24 #include "status-first-page.h"
25 #include "system/system-variables.h" // 暫定。後で消す
26 #include "term/screen-processor.h"
27 #include "term/term-color-types.h"
28 #include "util/buffer-shaper.h"
29 #include "view/display-characteristic.h"
30 #include "view/display-player-middle.h"
31 #include "view/display-player-misc-info.h"
32 #include "view/display-player-stat-info.h"
33 #include "view/display-util.h"
34 #include "world/world.h"
35
36 /*!
37  * @brief
38  * @param creature_ptr プレーヤーへの参照ポインタ
39  * @param mode ステータス表示モード
40  * @return どれかの処理をこなしたらTRUE、何もしなかったらFALSE
41  */
42 static bool display_player_info(player_type *creature_ptr, int mode)
43 {
44         if (mode == 2)
45         {
46                 display_player_misc_info(creature_ptr);
47                 display_player_stat_info(creature_ptr);
48                 display_player_flag_info_1(creature_ptr, display_player_equippy);
49                 return TRUE;
50         }
51
52         if (mode == 3)
53         {
54                 display_player_flag_info_2(creature_ptr, display_player_equippy);
55                 return TRUE;
56         }
57
58         if (mode == 4)
59         {
60                 do_cmd_knowledge_mutations(creature_ptr);
61                 return TRUE;
62         }
63
64         return FALSE;
65 }
66
67
68 /*!
69  * @brief 名前、性別、種族、職業を表示する
70  * @param creature_ptr プレーヤーへの参照ポインタ
71  */
72 static void display_player_basic_info(player_type *creature_ptr)
73 {
74         char tmp[64];
75 #ifdef JP
76         sprintf(tmp, "%s%s%s", ap_ptr->title, ap_ptr->no == 1 ? "の" : "", creature_ptr->name);
77 #else
78         sprintf(tmp, "%s %s", ap_ptr->title, creature_ptr->name);
79 #endif
80
81         display_player_one_line(ENTRY_NAME, tmp, TERM_L_BLUE);
82         display_player_one_line(ENTRY_SEX, sp_ptr->title, TERM_L_BLUE);
83         display_player_one_line(ENTRY_RACE, (creature_ptr->mimic_form ? mimic_info[creature_ptr->mimic_form].title : rp_ptr->title), TERM_L_BLUE);
84         display_player_one_line(ENTRY_CLASS, cp_ptr->title, TERM_L_BLUE);
85 }
86
87
88 /*!
89  * @brief 魔法領域を表示する
90  * @param creature_ptr プレーヤーへの参照ポインタ
91  * @return なし
92  */
93 static void display_magic_realms(player_type *creature_ptr)
94 {
95         if (creature_ptr->realm1 == 0) return;
96
97         char tmp[64];
98         if (creature_ptr->realm2)
99                 sprintf(tmp, "%s, %s", realm_names[creature_ptr->realm1], realm_names[creature_ptr->realm2]);
100         else
101                 strcpy(tmp, realm_names[creature_ptr->realm1]);
102
103         display_player_one_line(ENTRY_REALM, tmp, TERM_L_BLUE);
104 }
105
106
107 /*!
108  * @ brief 年齢、身長、体重、社会的地位を表示する
109  * @param creature_ptr プレーヤーへの参照ポインタ
110  * @return なし
111  * @details
112  * 日本語版では、身長はcmに、体重はkgに変更してある
113  */
114 static void display_phisique(player_type *creature_ptr)
115 {
116 #ifdef JP
117         display_player_one_line(ENTRY_AGE, format("%d才", (int)creature_ptr->age), TERM_L_BLUE);
118         display_player_one_line(ENTRY_HEIGHT, format("%dcm", (int)((creature_ptr->ht * 254) / 100)), TERM_L_BLUE);
119         display_player_one_line(ENTRY_WEIGHT, format("%dkg", (int)((creature_ptr->wt * 4536) / 10000)), TERM_L_BLUE);
120         display_player_one_line(ENTRY_SOCIAL, format("%d  ", (int)creature_ptr->sc), TERM_L_BLUE);
121 #else
122         display_player_one_line(ENTRY_AGE, format("%d", (int)creature_ptr->age), TERM_L_BLUE);
123         display_player_one_line(ENTRY_HEIGHT, format("%d", (int)creature_ptr->ht), TERM_L_BLUE);
124         display_player_one_line(ENTRY_WEIGHT, format("%d", (int)creature_ptr->wt), TERM_L_BLUE);
125         display_player_one_line(ENTRY_SOCIAL, format("%d", (int)creature_ptr->sc), TERM_L_BLUE);
126 #endif
127         display_player_one_line(ENTRY_ALIGN, format("%s", your_alignment(creature_ptr)), TERM_L_BLUE);
128 }
129
130
131 /*!
132  * @brief 能力値を (減少していたら色を変えて)表示する
133  * @param creature_ptr プレーヤーへの参照ポインタ
134  */
135 static void display_player_stats(player_type *creature_ptr)
136 {
137         char buf[80];
138         for (int i = 0; i < A_MAX; i++)
139         {
140                 if (creature_ptr->stat_cur[i] < creature_ptr->stat_max[i])
141                 {
142                         put_str(stat_names_reduced[i], 3 + i, 53);
143                         int value = creature_ptr->stat_use[i];
144                         cnv_stat(value, buf);
145                         c_put_str(TERM_YELLOW, buf, 3 + i, 60);
146                         value = creature_ptr->stat_top[i];
147                         cnv_stat(value, buf);
148                         c_put_str(TERM_L_GREEN, buf, 3 + i, 67);
149                 }
150                 else
151                 {
152                         put_str(stat_names[i], 3 + i, 53);
153                         cnv_stat(creature_ptr->stat_use[i], buf);
154                         c_put_str(TERM_L_GREEN, buf, 3 + i, 60);
155                 }
156
157                 if (creature_ptr->stat_max[i] == creature_ptr->stat_max_max[i])
158                         c_put_str(TERM_WHITE, "!", 3 + i, _(58, 58 - 2));
159         }
160 }
161
162
163 /*!
164  * @brief ゲームオーバーの原因を探る (生きていたら何もしない)
165  * @param creature_ptr プレーヤーへの参照ポインタ
166  * @param statmsg メッセージバッファ
167  * @return 生きていたらFALSE、死んでいたらTRUE
168  */
169 static bool search_death_cause(player_type *creature_ptr, char *statmsg)
170 {
171         floor_type *floor_ptr = creature_ptr->current_floor_ptr;
172         if (!creature_ptr->is_dead) return FALSE;
173
174         if (current_world_ptr->total_winner)
175         {
176                 sprintf(statmsg, _("…あなたは勝利の後%sした。", "...You %s after winning."),
177                         streq(creature_ptr->died_from, "Seppuku") ? _("切腹", "committed seppuku") : _("引退", "retired from the adventure"));
178
179                 return TRUE;
180         }
181         
182         if (!floor_ptr->dun_level)
183         {
184 #ifdef JP
185                 sprintf(statmsg, "…あなたは%sで%sに殺された。", map_name(creature_ptr), creature_ptr->died_from);
186 #else
187                 sprintf(statmsg, "...You were killed by %s in %s.", creature_ptr->died_from, map_name(creature_ptr));
188 #endif
189                 return TRUE;
190         }
191         
192         if (floor_ptr->inside_quest && is_fixed_quest_idx(floor_ptr->inside_quest))
193         {
194                 /* Get the quest text */
195                 /* Bewere that INIT_ASSIGN resets the cur_num. */
196                 init_flags = INIT_NAME_ONLY;
197                 parse_fixed_map(creature_ptr, "q_info.txt", 0, 0, 0, 0);
198 #ifdef JP
199                 sprintf(statmsg, "…あなたは、クエスト「%s」で%sに殺された。", quest[floor_ptr->inside_quest].name, creature_ptr->died_from);
200 #else
201                 sprintf(statmsg, "...You were killed by %s in the quest '%s'.", creature_ptr->died_from, quest[floor_ptr->inside_quest].name);
202 #endif
203                 return TRUE;
204         }
205
206 #ifdef JP
207         sprintf(statmsg, "…あなたは、%sの%d階で%sに殺された。", map_name(creature_ptr), (int)floor_ptr->dun_level, creature_ptr->died_from);
208 #else
209         sprintf(statmsg, "...You were killed by %s on level %d of %s.", creature_ptr->died_from, floor_ptr->dun_level, map_name(creature_ptr));
210 #endif
211
212         return TRUE;
213 }
214
215
216 /*!
217  * @brief クエストフロアで生きている場合、クエスト名をバッファに詰める
218  * @param creature_ptr プレーヤーへの参照ポインタ
219  * @param statmsg メッセージバッファ
220  * @return クエスト内であればTRUE、いなければFALSE
221  */
222 static bool decide_death_in_quest(player_type *creature_ptr, char *statmsg)
223 {
224         floor_type *floor_ptr = creature_ptr->current_floor_ptr;
225         if (!floor_ptr->inside_quest || !is_fixed_quest_idx(floor_ptr->inside_quest))
226                 return FALSE;
227
228         for (int i = 0; i < 10; i++)
229                 quest_text[i][0] = '\0';
230
231         quest_text_line = 0;
232         init_flags = INIT_NAME_ONLY;
233         parse_fixed_map(creature_ptr, "q_info.txt", 0, 0, 0, 0);
234         sprintf(statmsg, _("…あなたは現在、 クエスト「%s」を遂行中だ。", "...Now, you are in the quest '%s'."), quest[floor_ptr->inside_quest].name);
235         return TRUE;
236 }
237
238
239 /*!
240  * @brief 現在いるフロアを、または死んでいたらどこでどう死んだかをバッファに詰める
241  * @param creature_ptr プレーヤーへの参照ポインタ
242  * @param statmsg メッセージバッファ
243  * @return なし
244  */
245 static void decide_current_floor(player_type *creature_ptr, char *statmsg)
246 {
247         if (search_death_cause(creature_ptr, statmsg)) return;
248         if (!current_world_ptr->character_dungeon) return;
249
250         floor_type *floor_ptr = creature_ptr->current_floor_ptr;
251         if (floor_ptr->dun_level == 0)
252         {
253                 sprintf(statmsg, _("…あなたは現在、 %s にいる。", "...Now, you are in %s."), map_name(creature_ptr));
254                 return;
255         }
256         
257         if (decide_death_in_quest(creature_ptr, statmsg)) return;
258
259 #ifdef JP
260         sprintf(statmsg, "…あなたは現在、 %s の %d 階で探索している。", map_name(creature_ptr), (int)floor_ptr->dun_level);
261 #else
262         sprintf(statmsg, "...Now, you are exploring level %d of %s.", (int)floor_ptr->dun_level, map_name(creature_ptr));
263 #endif
264 }
265
266
267 /*!
268  * @brief 今いる、または死亡した場所を表示する
269  * @param statmsg メッセージバッファ
270  * @return なし
271  */
272 static void display_current_floor(char *statmsg)
273 {
274         char temp[128];
275         shape_buffer(statmsg, 60, temp, sizeof(temp));
276         char  *t;
277         t = temp;
278         for (int i = 0; i < 2; i++)
279         {
280                 if (t[0] == 0) return;
281
282                 put_str(t, i + 5 + 12, 10);
283                 t += strlen(t) + 1;
284         }
285 }
286
287
288 /*!
289  * @brief プレイヤーのステータス表示メイン処理
290  * Display the character on the screen (various modes)
291  * @param creature_ptr プレーヤーへの参照ポインタ
292  * @param mode 表示モードID
293  * @return なし
294  * @details
295  * <pre>
296  * The top one and bottom two lines are left blank.
297  * Mode 0 = standard display with skills
298  * Mode 1 = standard display with history
299  * Mode 2 = summary of various things
300  * Mode 3 = summary of various things (part 2)
301  * Mode 4 = mutations
302  * </pre>
303  */
304 void display_player(player_type *creature_ptr, int mode)
305 {
306         if ((creature_ptr->muta1 || creature_ptr->muta2 || creature_ptr->muta3) && display_mutations)
307                 mode = (mode % 5);
308         else
309                 mode = (mode % 4);
310
311         clear_from(0);
312         if (display_player_info(creature_ptr, mode)) return;
313
314         display_player_basic_info(creature_ptr);
315         display_magic_realms(creature_ptr);
316
317         if ((creature_ptr->pclass == CLASS_CHAOS_WARRIOR) || (creature_ptr->muta2 & MUT2_CHAOS_GIFT))
318                 display_player_one_line(ENTRY_PATRON, chaos_patrons[creature_ptr->chaos_patron], TERM_L_BLUE);
319
320         display_phisique(creature_ptr);
321         display_player_stats(creature_ptr);
322
323         if (mode == 0)
324         {
325                 display_player_middle(creature_ptr);
326                 display_player_various(creature_ptr);
327                 return;
328         }
329
330         char statmsg[1000];
331         put_str(_("(キャラクターの生い立ち)", "(Character Background)"), 11, 25);
332         for (int i = 0; i < 4; i++)
333                 put_str(creature_ptr->history[i], i + 12, 10);
334
335         *statmsg = '\0';
336         decide_current_floor(creature_ptr, statmsg);
337         if (!*statmsg) return;
338
339         display_current_floor(statmsg);
340 }
341
342
343 /*!
344  * todo y = 6、x = 0、mode = 0で固定。何とかする
345  * @brief プレイヤーの装備一覧をシンボルで並べる
346  * Equippy chars
347  * @param creature_ptr プレーヤーへの参照ポインタ
348  * @param y 表示するコンソールの行
349  * @param x 表示するコンソールの列
350  * @param mode オプション
351  * @return なし
352  */
353 void display_player_equippy(player_type *creature_ptr, TERM_LEN y, TERM_LEN x, BIT_FLAGS16 mode)
354 {
355         int max_i = (mode & DP_WP) ? INVEN_LARM + 1 : INVEN_TOTAL;
356         for (int i = INVEN_RARM; i < max_i; i++)
357         {
358                 object_type *o_ptr;
359                 o_ptr = &creature_ptr->inventory_list[i];
360
361                 TERM_COLOR a = object_attr(o_ptr);
362                 SYMBOL_CODE c = object_char(o_ptr);
363
364                 if (!equippy_chars || !o_ptr->k_idx)
365                 {
366                         c = ' ';
367                         a = TERM_DARK;
368                 }
369
370                 Term_putch(x + i - INVEN_RARM, y, a, c);
371         }
372 }