OSDN Git Service

[Refactor] format 関数の戻り値を std::string にする
[hengbandforosx/hengbandosx.git] / src / avatar / avatar.cpp
1 /*!
2  * @brief ウルティマ4を参考にした徳のシステムの実装 / Enable an Ultima IV style "avatar" game where you try to achieve perfection in various virtues.
3  * @date 2013/12/23
4  * @author
5  * Topi Ylinen 1998
6  * f1toyl@uta.fi
7  * topi.ylinen@noodi.fi
8  *
9  * Copyright (c) 1989 James E. Wilson, Christopher J. Stuart
10  * This software may be copied and distributed for educational, research, and
11  * not for profit purposes provided that this copyright and statement are
12  * included in all such copies.
13  */
14
15 #include "avatar/avatar.h"
16 #include "core/player-update-types.h"
17 #include "game-option/text-display-options.h"
18 #include "player-info/class-info.h"
19 #include "player-info/race-types.h"
20 #include "realm/realm-names-table.h"
21 #include "system/player-type-definition.h"
22
23 /*!
24  * 徳の名称 / The names of the virtues
25  */
26 concptr virtue[MAX_VIRTUE] = {
27     _("情", "Compassion"),
28     _("誉", "Honour"),
29     _("正", "Justice"),
30     _("犠", "Sacrifice"),
31     _("識", "Knowledge"),
32     _("誠", "Faith"),
33     _("啓", "Enlightenment"),
34     _("秘", "Mysticism"),
35     _("運", "Chance"),
36     _("然", "Nature"),
37     _("調", "Harmony"),
38     _("活", "Vitality"),
39     _("死", "Unlife"),
40     _("忍", "Patience"),
41     _("節", "Temperance"),
42     _("勤", "Diligence"),
43     _("勇", "Valour"),
44     _("個", "Individualism"),
45 };
46
47 /*!
48  * @brief 該当の徳がプレイヤーに指定されているか否かに応じつつ、大小を比較する。
49  * @details 徳がない場合は値0として比較する。
50  * @param type 比較したい徳のID
51  * @param num 比較基準値
52  * @param tekitou VIRTUE_LARGE = 基準値より大きいか / VIRTUE_SMALL = 基準値より小さいか
53  * @return 比較の真偽値を返す
54  * @todo 引数名を直しておく
55  */
56 bool compare_virtue(PlayerType *player_ptr, int type, int num, int tekitou)
57 {
58     int vir = virtue_number(player_ptr, type) ? player_ptr->virtues[virtue_number(player_ptr, type) - 1] : 0;
59     switch (tekitou) {
60     case VIRTUE_LARGE:
61         if (vir > num) {
62             return true;
63         } else {
64             return false;
65         }
66     case VIRTUE_SMALL:
67         if (vir < num) {
68             return true;
69         } else {
70             return false;
71         }
72     default:
73         return false;
74     }
75 }
76
77 /*!
78  * @brief プレイヤーの指定の徳が何番目のスロットに登録されているかを返す。 / Aux function
79  * @param type 確認したい徳のID
80  * @return スロットがあるならばスロットのID(0~7)+1、ない場合は0を返す。
81  */
82 int virtue_number(PlayerType *player_ptr, int type)
83 {
84     for (int i = 0; i < 8; i++) {
85         if (player_ptr->vir_types[i] == type) {
86             return i + 1;
87         }
88     }
89
90     return 0;
91 }
92
93 /*!
94  * @brief プレイヤーの職業や種族に依存しないランダムな徳を取得する / Aux function
95  * @param which 確認したい徳のID
96  */
97 static void get_random_virtue(PlayerType *player_ptr, int which)
98 {
99     int type = 0;
100     while (!(type) || virtue_number(player_ptr, type)) {
101         switch (randint1(29)) {
102         case 1:
103         case 2:
104         case 3:
105             type = V_SACRIFICE;
106             break;
107         case 4:
108         case 5:
109         case 6:
110             type = V_COMPASSION;
111             break;
112         case 7:
113         case 8:
114         case 9:
115         case 10:
116         case 11:
117         case 12:
118             type = V_VALOUR;
119             break;
120         case 13:
121         case 14:
122         case 15:
123         case 16:
124         case 17:
125             type = V_HONOUR;
126             break;
127         case 18:
128         case 19:
129         case 20:
130         case 21:
131             type = V_JUSTICE;
132             break;
133         case 22:
134         case 23:
135             type = V_TEMPERANCE;
136             break;
137         case 24:
138         case 25:
139             type = V_HARMONY;
140             break;
141         case 26:
142         case 27:
143         case 28:
144             type = V_PATIENCE;
145             break;
146         default:
147             type = V_DILIGENCE;
148             break;
149         }
150     }
151
152     player_ptr->vir_types[which] = (int16_t)type;
153 }
154
155 /*!
156  * @brief プレイヤーの選んだ魔法領域に応じて対応する徳を返す。
157  * @param realm 魔法領域のID
158  * @return 対応する徳のID
159  */
160 static enum virtue_idx get_realm_virtues(PlayerType *player_ptr, int16_t realm)
161 {
162     switch (realm) {
163     case REALM_LIFE:
164         if (virtue_number(player_ptr, V_VITALITY)) {
165             return V_TEMPERANCE;
166         } else {
167             return V_VITALITY;
168         }
169     case REALM_SORCERY:
170         if (virtue_number(player_ptr, V_KNOWLEDGE)) {
171             return V_ENCHANT;
172         } else {
173             return V_KNOWLEDGE;
174         }
175     case REALM_NATURE:
176         if (virtue_number(player_ptr, V_NATURE)) {
177             return V_HARMONY;
178         } else {
179             return V_NATURE;
180         }
181     case REALM_CHAOS:
182         if (virtue_number(player_ptr, V_CHANCE)) {
183             return V_INDIVIDUALISM;
184         } else {
185             return V_CHANCE;
186         }
187     case REALM_DEATH:
188         return V_UNLIFE;
189     case REALM_TRUMP:
190         return V_KNOWLEDGE;
191     case REALM_ARCANE:
192         return V_NONE;
193     case REALM_CRAFT:
194         if (virtue_number(player_ptr, V_ENCHANT)) {
195             return V_INDIVIDUALISM;
196         } else {
197             return V_ENCHANT;
198         }
199     case REALM_DAEMON:
200         if (virtue_number(player_ptr, V_JUSTICE)) {
201             return V_FAITH;
202         } else {
203             return V_JUSTICE;
204         }
205     case REALM_CRUSADE:
206         if (virtue_number(player_ptr, V_JUSTICE)) {
207             return V_HONOUR;
208         } else {
209             return V_JUSTICE;
210         }
211     case REALM_HEX:
212         if (virtue_number(player_ptr, V_COMPASSION)) {
213             return V_JUSTICE;
214         } else {
215             return V_COMPASSION;
216         }
217     default:
218         return V_NONE;
219     };
220 }
221
222 /*!
223  * @brief 作成中のプレイヤーキャラクターに徳8種類を与える。 / Select virtues & reset values for a new character
224  * @details 職業に応じて1~4種が固定、種族に応じて1種類が与えられ、後は重複なくランダムに選択される。
225  */
226 void initialize_virtues(PlayerType *player_ptr)
227 {
228     int i = 0, j = 0;
229     int16_t tmp_vir;
230
231     /* Reset */
232     for (i = 0; i < 8; i++) {
233         player_ptr->virtues[i] = 0;
234         player_ptr->vir_types[i] = 0;
235     }
236
237     i = 0;
238
239     /* Get pre-defined types */
240     /* 1 or more virtues based on class */
241     switch (player_ptr->pclass) {
242     case PlayerClassType::WARRIOR:
243     case PlayerClassType::SAMURAI:
244         player_ptr->vir_types[i++] = V_VALOUR;
245         player_ptr->vir_types[i++] = V_HONOUR;
246         break;
247     case PlayerClassType::MAGE:
248         player_ptr->vir_types[i++] = V_KNOWLEDGE;
249         player_ptr->vir_types[i++] = V_ENCHANT;
250         break;
251     case PlayerClassType::PRIEST:
252         player_ptr->vir_types[i++] = V_FAITH;
253         player_ptr->vir_types[i++] = V_TEMPERANCE;
254         break;
255     case PlayerClassType::ROGUE:
256     case PlayerClassType::SNIPER:
257         player_ptr->vir_types[i++] = V_HONOUR;
258         break;
259     case PlayerClassType::RANGER:
260     case PlayerClassType::ARCHER:
261         player_ptr->vir_types[i++] = V_NATURE;
262         player_ptr->vir_types[i++] = V_TEMPERANCE;
263         break;
264     case PlayerClassType::PALADIN:
265         player_ptr->vir_types[i++] = V_JUSTICE;
266         player_ptr->vir_types[i++] = V_VALOUR;
267         player_ptr->vir_types[i++] = V_HONOUR;
268         player_ptr->vir_types[i++] = V_FAITH;
269         break;
270     case PlayerClassType::WARRIOR_MAGE:
271     case PlayerClassType::RED_MAGE:
272         player_ptr->vir_types[i++] = V_ENCHANT;
273         player_ptr->vir_types[i++] = V_VALOUR;
274         break;
275     case PlayerClassType::CHAOS_WARRIOR:
276         player_ptr->vir_types[i++] = V_CHANCE;
277         player_ptr->vir_types[i++] = V_INDIVIDUALISM;
278         break;
279     case PlayerClassType::MONK:
280     case PlayerClassType::FORCETRAINER:
281         player_ptr->vir_types[i++] = V_FAITH;
282         player_ptr->vir_types[i++] = V_HARMONY;
283         player_ptr->vir_types[i++] = V_TEMPERANCE;
284         player_ptr->vir_types[i++] = V_PATIENCE;
285         break;
286     case PlayerClassType::MINDCRAFTER:
287     case PlayerClassType::MIRROR_MASTER:
288         player_ptr->vir_types[i++] = V_HARMONY;
289         player_ptr->vir_types[i++] = V_ENLIGHTEN;
290         player_ptr->vir_types[i++] = V_PATIENCE;
291         break;
292     case PlayerClassType::HIGH_MAGE:
293     case PlayerClassType::SORCERER:
294         player_ptr->vir_types[i++] = V_ENLIGHTEN;
295         player_ptr->vir_types[i++] = V_ENCHANT;
296         player_ptr->vir_types[i++] = V_KNOWLEDGE;
297         break;
298     case PlayerClassType::TOURIST:
299         player_ptr->vir_types[i++] = V_ENLIGHTEN;
300         player_ptr->vir_types[i++] = V_CHANCE;
301         break;
302     case PlayerClassType::IMITATOR:
303         player_ptr->vir_types[i++] = V_CHANCE;
304         break;
305     case PlayerClassType::BLUE_MAGE:
306         player_ptr->vir_types[i++] = V_CHANCE;
307         player_ptr->vir_types[i++] = V_KNOWLEDGE;
308         break;
309     case PlayerClassType::BEASTMASTER:
310         player_ptr->vir_types[i++] = V_NATURE;
311         player_ptr->vir_types[i++] = V_CHANCE;
312         player_ptr->vir_types[i++] = V_VITALITY;
313         break;
314     case PlayerClassType::MAGIC_EATER:
315         player_ptr->vir_types[i++] = V_ENCHANT;
316         player_ptr->vir_types[i++] = V_KNOWLEDGE;
317         break;
318     case PlayerClassType::BARD:
319         player_ptr->vir_types[i++] = V_HARMONY;
320         player_ptr->vir_types[i++] = V_COMPASSION;
321         break;
322     case PlayerClassType::CAVALRY:
323         player_ptr->vir_types[i++] = V_VALOUR;
324         player_ptr->vir_types[i++] = V_HARMONY;
325         break;
326     case PlayerClassType::BERSERKER:
327         player_ptr->vir_types[i++] = V_VALOUR;
328         player_ptr->vir_types[i++] = V_INDIVIDUALISM;
329         break;
330     case PlayerClassType::SMITH:
331         player_ptr->vir_types[i++] = V_HONOUR;
332         player_ptr->vir_types[i++] = V_KNOWLEDGE;
333         break;
334     case PlayerClassType::NINJA:
335         player_ptr->vir_types[i++] = V_PATIENCE;
336         player_ptr->vir_types[i++] = V_KNOWLEDGE;
337         player_ptr->vir_types[i++] = V_FAITH;
338         player_ptr->vir_types[i++] = V_UNLIFE;
339         break;
340     case PlayerClassType::ELEMENTALIST:
341         player_ptr->vir_types[i++] = V_NATURE;
342         break;
343     case PlayerClassType::MAX:
344         break;
345     };
346
347     /* Get one virtue based on race */
348     switch (player_ptr->prace) {
349     case PlayerRaceType::HUMAN:
350     case PlayerRaceType::HALF_ELF:
351     case PlayerRaceType::DUNADAN:
352         player_ptr->vir_types[i++] = V_INDIVIDUALISM;
353         break;
354     case PlayerRaceType::ELF:
355     case PlayerRaceType::SPRITE:
356     case PlayerRaceType::ENT:
357     case PlayerRaceType::MERFOLK:
358         player_ptr->vir_types[i++] = V_NATURE;
359         break;
360     case PlayerRaceType::HOBBIT:
361     case PlayerRaceType::HALF_OGRE:
362         player_ptr->vir_types[i++] = V_TEMPERANCE;
363         break;
364     case PlayerRaceType::DWARF:
365     case PlayerRaceType::KLACKON:
366     case PlayerRaceType::ANDROID:
367         player_ptr->vir_types[i++] = V_DILIGENCE;
368         break;
369     case PlayerRaceType::GNOME:
370     case PlayerRaceType::CYCLOPS:
371         player_ptr->vir_types[i++] = V_KNOWLEDGE;
372         break;
373     case PlayerRaceType::HALF_ORC:
374     case PlayerRaceType::AMBERITE:
375     case PlayerRaceType::KOBOLD:
376         player_ptr->vir_types[i++] = V_HONOUR;
377         break;
378     case PlayerRaceType::HALF_TROLL:
379     case PlayerRaceType::BARBARIAN:
380         player_ptr->vir_types[i++] = V_VALOUR;
381         break;
382     case PlayerRaceType::HIGH_ELF:
383     case PlayerRaceType::KUTAR:
384         player_ptr->vir_types[i++] = V_VITALITY;
385         break;
386     case PlayerRaceType::HALF_GIANT:
387     case PlayerRaceType::GOLEM:
388     case PlayerRaceType::ARCHON:
389     case PlayerRaceType::BALROG:
390         player_ptr->vir_types[i++] = V_JUSTICE;
391         break;
392     case PlayerRaceType::HALF_TITAN:
393         player_ptr->vir_types[i++] = V_HARMONY;
394         break;
395     case PlayerRaceType::YEEK:
396         player_ptr->vir_types[i++] = V_SACRIFICE;
397         break;
398     case PlayerRaceType::MIND_FLAYER:
399         player_ptr->vir_types[i++] = V_ENLIGHTEN;
400         break;
401     case PlayerRaceType::DARK_ELF:
402     case PlayerRaceType::DRACONIAN:
403     case PlayerRaceType::S_FAIRY:
404         player_ptr->vir_types[i++] = V_ENCHANT;
405         break;
406     case PlayerRaceType::NIBELUNG:
407         player_ptr->vir_types[i++] = V_PATIENCE;
408         break;
409     case PlayerRaceType::IMP:
410         player_ptr->vir_types[i++] = V_FAITH;
411         break;
412     case PlayerRaceType::ZOMBIE:
413     case PlayerRaceType::SKELETON:
414     case PlayerRaceType::VAMPIRE:
415     case PlayerRaceType::SPECTRE:
416         player_ptr->vir_types[i++] = V_UNLIFE;
417         break;
418     case PlayerRaceType::BEASTMAN:
419         player_ptr->vir_types[i++] = V_CHANCE;
420         break;
421     case PlayerRaceType::MAX:
422         break;
423     }
424
425     /* Get a virtue for realms */
426     if (player_ptr->realm1) {
427         tmp_vir = get_realm_virtues(player_ptr, player_ptr->realm1);
428         if (tmp_vir) {
429             player_ptr->vir_types[i++] = tmp_vir;
430         }
431     }
432
433     if (player_ptr->realm2) {
434         tmp_vir = get_realm_virtues(player_ptr, player_ptr->realm2);
435         if (tmp_vir) {
436             player_ptr->vir_types[i++] = tmp_vir;
437         }
438     }
439
440     /* Eliminate doubles */
441     for (i = 0; i < 8; i++) {
442         for (j = i + 1; j < 8; j++) {
443             if ((player_ptr->vir_types[j] != 0) && (player_ptr->vir_types[j] == player_ptr->vir_types[i])) {
444                 player_ptr->vir_types[j] = 0;
445             }
446         }
447     }
448
449     /* Fill in the blanks */
450     for (i = 0; i < 8; i++) {
451         if (player_ptr->vir_types[i] == 0) {
452             get_random_virtue(player_ptr, i);
453         }
454     }
455 }
456
457 /*!
458  * @brief 対応する徳をプレイヤーがスロットに登録している場合に加減を行う。
459  * @details 範囲は-125~125、基本的に絶対値が大きいほど絶対値が上がり辛くなる。
460  * @param virtue 徳のID
461  * @param amount 加減量
462  */
463 void chg_virtue(PlayerType *player_ptr, int virtue_id, int amount)
464 {
465     for (int i = 0; i < 8; i++) {
466         if (player_ptr->vir_types[i] != virtue_id) {
467             continue;
468         }
469
470         if (amount > 0) {
471             if ((amount + player_ptr->virtues[i] > 50) && one_in_(2)) {
472                 player_ptr->virtues[i] = std::max<short>(player_ptr->virtues[i], 50);
473                 return;
474             }
475
476             if ((amount + player_ptr->virtues[i] > 80) && one_in_(2)) {
477                 player_ptr->virtues[i] = std::max<short>(player_ptr->virtues[i], 80);
478                 return;
479             }
480
481             if ((amount + player_ptr->virtues[i] > 100) && one_in_(2)) {
482                 player_ptr->virtues[i] = std::max<short>(player_ptr->virtues[i], 100);
483                 return;
484             }
485
486             if (amount + player_ptr->virtues[i] > 125) {
487                 player_ptr->virtues[i] = 125;
488             } else {
489                 player_ptr->virtues[i] = player_ptr->virtues[i] + amount;
490             }
491         } else {
492             if ((amount + player_ptr->virtues[i] < -50) && one_in_(2)) {
493                 player_ptr->virtues[i] = std::min<short>(player_ptr->virtues[i], -50);
494                 return;
495             }
496
497             if ((amount + player_ptr->virtues[i] < -80) && one_in_(2)) {
498                 player_ptr->virtues[i] = std::min<short>(player_ptr->virtues[i], -80);
499                 return;
500             }
501
502             if ((amount + player_ptr->virtues[i] < -100) && one_in_(2)) {
503                 player_ptr->virtues[i] = std::min<short>(player_ptr->virtues[i], -100);
504                 return;
505             }
506
507             if (amount + player_ptr->virtues[i] < -125) {
508                 player_ptr->virtues[i] = -125;
509             } else {
510                 player_ptr->virtues[i] = player_ptr->virtues[i] + amount;
511             }
512         }
513
514         player_ptr->update |= PU_BONUS;
515         return;
516     }
517 }
518
519 /*!
520  * @brief 対応する徳をプレイヤーがスロットに登録している場合に固定値をセットする
521  * @param virtue 徳のID
522  * @param amount セットしたい値
523  */
524 void set_virtue(PlayerType *player_ptr, int virtue_id, int amount)
525 {
526     for (int i = 0; i < 8; i++) {
527         if (player_ptr->vir_types[i] == virtue_id) {
528             player_ptr->virtues[i] = (int16_t)amount;
529             return;
530         }
531     }
532 }
533
534 /*!
535  * @brief 徳のダンプ表示を行う
536  * @param out_file ファイルポインタ
537  */
538 void dump_virtues(PlayerType *player_ptr, FILE *out_file)
539 {
540     if (!out_file) {
541         return;
542     }
543
544     for (int v_nr = 0; v_nr < 8; v_nr++) {
545         GAME_TEXT vir_name[20];
546         int tester = player_ptr->virtues[v_nr];
547         strcpy(vir_name, virtue[(player_ptr->vir_types[v_nr]) - 1]);
548         const std::string vir_val_str = format(" (%d)", tester);
549         const auto vir_val = show_actual_value ? vir_val_str.data() : "";
550         if (player_ptr->vir_types[v_nr] == 0 || player_ptr->vir_types[v_nr] > MAX_VIRTUE) {
551             fprintf(out_file, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name);
552         }
553
554         else if (tester < -100) {
555             fprintf(out_file, _("[%s]の対極%s", "You are the polar opposite of %s.%s"), vir_name, vir_val);
556         } else if (tester < -80) {
557             fprintf(out_file, _("[%s]の大敵%s", "You are an arch-enemy of %s.%s"), vir_name, vir_val);
558         } else if (tester < -60) {
559             fprintf(out_file, _("[%s]の強敵%s", "You are a bitter enemy of %s.%s"), vir_name, vir_val);
560         } else if (tester < -40) {
561             fprintf(out_file, _("[%s]の敵%s", "You are an enemy of %s.%s"), vir_name, vir_val);
562         } else if (tester < -20) {
563             fprintf(out_file, _("[%s]の罪者%s", "You have sinned against %s.%s"), vir_name, vir_val);
564         } else if (tester < 0) {
565             fprintf(out_file, _("[%s]の迷道者%s", "You have strayed from the path of %s.%s"), vir_name, vir_val);
566         } else if (tester == 0) {
567             fprintf(out_file, _("[%s]の中立者%s", "You are neutral to %s.%s"), vir_name, vir_val);
568         } else if (tester < 20) {
569             fprintf(out_file, _("[%s]の小徳者%s", "You are somewhat virtuous in %s.%s"), vir_name, vir_val);
570         } else if (tester < 40) {
571             fprintf(out_file, _("[%s]の中徳者%s", "You are virtuous in %s.%s"), vir_name, vir_val);
572         } else if (tester < 60) {
573             fprintf(out_file, _("[%s]の高徳者%s", "You are very virtuous in %s.%s"), vir_name, vir_val);
574         } else if (tester < 80) {
575             fprintf(out_file, _("[%s]の覇者%s", "You are a champion of %s.%s"), vir_name, vir_val);
576         } else if (tester < 100) {
577             fprintf(out_file, _("[%s]の偉大な覇者%s", "You are a great champion of %s.%s"), vir_name, vir_val);
578         } else {
579             fprintf(out_file, _("[%s]の具現者%s", "You are the living embodiment of %s.%s"), vir_name, vir_val);
580         }
581
582         fprintf(out_file, "\n");
583     }
584 }