OSDN Git Service

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