OSDN Git Service

[Refactor] struct player_type を class PlayerType に置換。
[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     case VIRTUE_SMALL:
66         if (vir < num)
67             return true;
68         else
69             return false;
70     default:
71         return false;
72     }
73 }
74
75 /*!
76  * @brief プレイヤーの指定の徳が何番目のスロットに登録されているかを返す。 / Aux function
77  * @param type 確認したい徳のID
78  * @return スロットがあるならばスロットのID(0~7)+1、ない場合は0を返す。
79  */
80 int virtue_number(PlayerType *player_ptr, int type)
81 {
82     for (int i = 0; i < 8; i++)
83         if (player_ptr->vir_types[i] == type)
84             return i + 1;
85
86     return 0;
87 }
88
89 /*!
90  * @brief プレイヤーの職業や種族に依存しないランダムな徳を取得する / Aux function
91  * @param which 確認したい徳のID
92  */
93 static void get_random_virtue(PlayerType *player_ptr, int which)
94 {
95     int type = 0;
96     while (!(type) || virtue_number(player_ptr, type)) {
97         switch (randint1(29)) {
98         case 1:
99         case 2:
100         case 3:
101             type = V_SACRIFICE;
102             break;
103         case 4:
104         case 5:
105         case 6:
106             type = V_COMPASSION;
107             break;
108         case 7:
109         case 8:
110         case 9:
111         case 10:
112         case 11:
113         case 12:
114             type = V_VALOUR;
115             break;
116         case 13:
117         case 14:
118         case 15:
119         case 16:
120         case 17:
121             type = V_HONOUR;
122             break;
123         case 18:
124         case 19:
125         case 20:
126         case 21:
127             type = V_JUSTICE;
128             break;
129         case 22:
130         case 23:
131             type = V_TEMPERANCE;
132             break;
133         case 24:
134         case 25:
135             type = V_HARMONY;
136             break;
137         case 26:
138         case 27:
139         case 28:
140             type = V_PATIENCE;
141             break;
142         default:
143             type = V_DILIGENCE;
144             break;
145         }
146     }
147
148     player_ptr->vir_types[which] = (int16_t)type;
149 }
150
151 /*!
152  * @brief プレイヤーの選んだ魔法領域に応じて対応する徳を返す。
153  * @param realm 魔法領域のID
154  * @return 対応する徳のID
155  */
156 static enum virtue_idx get_realm_virtues(PlayerType *player_ptr, int16_t realm)
157 {
158     switch (realm) {
159     case REALM_LIFE:
160         if (virtue_number(player_ptr, V_VITALITY))
161             return V_TEMPERANCE;
162         else
163             return V_VITALITY;
164     case REALM_SORCERY:
165         if (virtue_number(player_ptr, V_KNOWLEDGE))
166             return V_ENCHANT;
167         else
168             return V_KNOWLEDGE;
169     case REALM_NATURE:
170         if (virtue_number(player_ptr, V_NATURE))
171             return V_HARMONY;
172         else
173             return V_NATURE;
174     case REALM_CHAOS:
175         if (virtue_number(player_ptr, V_CHANCE))
176             return V_INDIVIDUALISM;
177         else
178             return V_CHANCE;
179     case REALM_DEATH:
180         return V_UNLIFE;
181     case REALM_TRUMP:
182         return V_KNOWLEDGE;
183     case REALM_ARCANE:
184         return V_NONE;
185     case REALM_CRAFT:
186         if (virtue_number(player_ptr, V_ENCHANT))
187             return V_INDIVIDUALISM;
188         else
189             return V_ENCHANT;
190     case REALM_DAEMON:
191         if (virtue_number(player_ptr, V_JUSTICE))
192             return V_FAITH;
193         else
194             return V_JUSTICE;
195     case REALM_CRUSADE:
196         if (virtue_number(player_ptr, V_JUSTICE))
197             return V_HONOUR;
198         else
199             return V_JUSTICE;
200     case REALM_HEX:
201         if (virtue_number(player_ptr, V_COMPASSION))
202             return V_JUSTICE;
203         else
204             return V_COMPASSION;
205     default:
206         return V_NONE;
207     };
208 }
209
210 /*!
211  * @brief 作成中のプレイヤーキャラクターに徳8種類を与える。 / Select virtues & reset values for a new character
212  * @details 職業に応じて1~4種が固定、種族に応じて1種類が与えられ、後は重複なくランダムに選択される。
213  */
214 void initialize_virtues(PlayerType *player_ptr)
215 {
216     int i = 0, j = 0;
217     int16_t tmp_vir;
218
219     /* Reset */
220     for (i = 0; i < 8; i++) {
221         player_ptr->virtues[i] = 0;
222         player_ptr->vir_types[i] = 0;
223     }
224
225     i = 0;
226
227     /* Get pre-defined types */
228     /* 1 or more virtues based on class */
229     switch (player_ptr->pclass) {
230     case PlayerClassType::WARRIOR:
231     case PlayerClassType::SAMURAI:
232         player_ptr->vir_types[i++] = V_VALOUR;
233         player_ptr->vir_types[i++] = V_HONOUR;
234         break;
235     case PlayerClassType::MAGE:
236         player_ptr->vir_types[i++] = V_KNOWLEDGE;
237         player_ptr->vir_types[i++] = V_ENCHANT;
238         break;
239     case PlayerClassType::PRIEST:
240         player_ptr->vir_types[i++] = V_FAITH;
241         player_ptr->vir_types[i++] = V_TEMPERANCE;
242         break;
243     case PlayerClassType::ROGUE:
244     case PlayerClassType::SNIPER:
245         player_ptr->vir_types[i++] = V_HONOUR;
246         break;
247     case PlayerClassType::RANGER:
248     case PlayerClassType::ARCHER:
249         player_ptr->vir_types[i++] = V_NATURE;
250         player_ptr->vir_types[i++] = V_TEMPERANCE;
251         break;
252     case PlayerClassType::PALADIN:
253         player_ptr->vir_types[i++] = V_JUSTICE;
254         player_ptr->vir_types[i++] = V_VALOUR;
255         player_ptr->vir_types[i++] = V_HONOUR;
256         player_ptr->vir_types[i++] = V_FAITH;
257         break;
258     case PlayerClassType::WARRIOR_MAGE:
259     case PlayerClassType::RED_MAGE:
260         player_ptr->vir_types[i++] = V_ENCHANT;
261         player_ptr->vir_types[i++] = V_VALOUR;
262         break;
263     case PlayerClassType::CHAOS_WARRIOR:
264         player_ptr->vir_types[i++] = V_CHANCE;
265         player_ptr->vir_types[i++] = V_INDIVIDUALISM;
266         break;
267     case PlayerClassType::MONK:
268     case PlayerClassType::FORCETRAINER:
269         player_ptr->vir_types[i++] = V_FAITH;
270         player_ptr->vir_types[i++] = V_HARMONY;
271         player_ptr->vir_types[i++] = V_TEMPERANCE;
272         player_ptr->vir_types[i++] = V_PATIENCE;
273         break;
274     case PlayerClassType::MINDCRAFTER:
275     case PlayerClassType::MIRROR_MASTER:
276         player_ptr->vir_types[i++] = V_HARMONY;
277         player_ptr->vir_types[i++] = V_ENLIGHTEN;
278         player_ptr->vir_types[i++] = V_PATIENCE;
279         break;
280     case PlayerClassType::HIGH_MAGE:
281     case PlayerClassType::SORCERER:
282         player_ptr->vir_types[i++] = V_ENLIGHTEN;
283         player_ptr->vir_types[i++] = V_ENCHANT;
284         player_ptr->vir_types[i++] = V_KNOWLEDGE;
285         break;
286     case PlayerClassType::TOURIST:
287         player_ptr->vir_types[i++] = V_ENLIGHTEN;
288         player_ptr->vir_types[i++] = V_CHANCE;
289         break;
290     case PlayerClassType::IMITATOR:
291         player_ptr->vir_types[i++] = V_CHANCE;
292         break;
293     case PlayerClassType::BLUE_MAGE:
294         player_ptr->vir_types[i++] = V_CHANCE;
295         player_ptr->vir_types[i++] = V_KNOWLEDGE;
296         break;
297     case PlayerClassType::BEASTMASTER:
298         player_ptr->vir_types[i++] = V_NATURE;
299         player_ptr->vir_types[i++] = V_CHANCE;
300         player_ptr->vir_types[i++] = V_VITALITY;
301         break;
302     case PlayerClassType::MAGIC_EATER:
303         player_ptr->vir_types[i++] = V_ENCHANT;
304         player_ptr->vir_types[i++] = V_KNOWLEDGE;
305         break;
306     case PlayerClassType::BARD:
307         player_ptr->vir_types[i++] = V_HARMONY;
308         player_ptr->vir_types[i++] = V_COMPASSION;
309         break;
310     case PlayerClassType::CAVALRY:
311         player_ptr->vir_types[i++] = V_VALOUR;
312         player_ptr->vir_types[i++] = V_HARMONY;
313         break;
314     case PlayerClassType::BERSERKER:
315         player_ptr->vir_types[i++] = V_VALOUR;
316         player_ptr->vir_types[i++] = V_INDIVIDUALISM;
317         break;
318     case PlayerClassType::SMITH:
319         player_ptr->vir_types[i++] = V_HONOUR;
320         player_ptr->vir_types[i++] = V_KNOWLEDGE;
321         break;
322     case PlayerClassType::NINJA:
323         player_ptr->vir_types[i++] = V_PATIENCE;
324         player_ptr->vir_types[i++] = V_KNOWLEDGE;
325         player_ptr->vir_types[i++] = V_FAITH;
326         player_ptr->vir_types[i++] = V_UNLIFE;
327         break;
328     case PlayerClassType::ELEMENTALIST:
329         player_ptr->vir_types[i++] = V_NATURE;
330         break;
331     case PlayerClassType::MAX:
332         break;
333     };
334
335     /* Get one virtue based on race */
336     switch (player_ptr->prace) {
337     case PlayerRaceType::HUMAN:
338     case PlayerRaceType::HALF_ELF:
339     case PlayerRaceType::DUNADAN:
340         player_ptr->vir_types[i++] = V_INDIVIDUALISM;
341         break;
342     case PlayerRaceType::ELF:
343     case PlayerRaceType::SPRITE:
344     case PlayerRaceType::ENT:
345     case PlayerRaceType::MERFOLK:
346         player_ptr->vir_types[i++] = V_NATURE;
347         break;
348     case PlayerRaceType::HOBBIT:
349     case PlayerRaceType::HALF_OGRE:
350         player_ptr->vir_types[i++] = V_TEMPERANCE;
351         break;
352     case PlayerRaceType::DWARF:
353     case PlayerRaceType::KLACKON:
354     case PlayerRaceType::ANDROID:
355         player_ptr->vir_types[i++] = V_DILIGENCE;
356         break;
357     case PlayerRaceType::GNOME:
358     case PlayerRaceType::CYCLOPS:
359         player_ptr->vir_types[i++] = V_KNOWLEDGE;
360         break;
361     case PlayerRaceType::HALF_ORC:
362     case PlayerRaceType::AMBERITE:
363     case PlayerRaceType::KOBOLD:
364         player_ptr->vir_types[i++] = V_HONOUR;
365         break;
366     case PlayerRaceType::HALF_TROLL:
367     case PlayerRaceType::BARBARIAN:
368         player_ptr->vir_types[i++] = V_VALOUR;
369         break;
370     case PlayerRaceType::HIGH_ELF:
371     case PlayerRaceType::KUTAR:
372         player_ptr->vir_types[i++] = V_VITALITY;
373         break;
374     case PlayerRaceType::HALF_GIANT:
375     case PlayerRaceType::GOLEM:
376     case PlayerRaceType::ARCHON:
377     case PlayerRaceType::BALROG:
378         player_ptr->vir_types[i++] = V_JUSTICE;
379         break;
380     case PlayerRaceType::HALF_TITAN:
381         player_ptr->vir_types[i++] = V_HARMONY;
382         break;
383     case PlayerRaceType::YEEK:
384         player_ptr->vir_types[i++] = V_SACRIFICE;
385         break;
386     case PlayerRaceType::MIND_FLAYER:
387         player_ptr->vir_types[i++] = V_ENLIGHTEN;
388         break;
389     case PlayerRaceType::DARK_ELF:
390     case PlayerRaceType::DRACONIAN:
391     case PlayerRaceType::S_FAIRY:
392         player_ptr->vir_types[i++] = V_ENCHANT;
393         break;
394     case PlayerRaceType::NIBELUNG:
395         player_ptr->vir_types[i++] = V_PATIENCE;
396         break;
397     case PlayerRaceType::IMP:
398         player_ptr->vir_types[i++] = V_FAITH;
399         break;
400     case PlayerRaceType::ZOMBIE:
401     case PlayerRaceType::SKELETON:
402     case PlayerRaceType::VAMPIRE:
403     case PlayerRaceType::SPECTRE:
404         player_ptr->vir_types[i++] = V_UNLIFE;
405         break;
406     case PlayerRaceType::BEASTMAN:
407         player_ptr->vir_types[i++] = V_CHANCE;
408         break;
409     case PlayerRaceType::MAX:
410         break;
411     }
412
413     /* Get a virtue for realms */
414     if (player_ptr->realm1) {
415         tmp_vir = get_realm_virtues(player_ptr, player_ptr->realm1);
416         if (tmp_vir)
417             player_ptr->vir_types[i++] = tmp_vir;
418     }
419
420     if (player_ptr->realm2) {
421         tmp_vir = get_realm_virtues(player_ptr, player_ptr->realm2);
422         if (tmp_vir)
423             player_ptr->vir_types[i++] = tmp_vir;
424     }
425
426     /* Eliminate doubles */
427     for (i = 0; i < 8; i++)
428         for (j = i + 1; j < 8; j++)
429             if ((player_ptr->vir_types[j] != 0) && (player_ptr->vir_types[j] == player_ptr->vir_types[i]))
430                 player_ptr->vir_types[j] = 0;
431
432     /* Fill in the blanks */
433     for (i = 0; i < 8; i++)
434         if (player_ptr->vir_types[i] == 0)
435             get_random_virtue(player_ptr, i);
436 }
437
438 /*!
439  * @brief 対応する徳をプレイヤーがスロットに登録している場合に加減を行う。
440  * @details 範囲は-125~125、基本的に絶対値が大きいほど絶対値が上がり辛くなる。
441  * @param virtue 徳のID
442  * @param amount 加減量
443  */
444 void chg_virtue(PlayerType *player_ptr, int virtue_id, int amount)
445 {
446     for (int i = 0; i < 8; i++) {
447         if (player_ptr->vir_types[i] != virtue_id)
448             continue;
449
450         if (amount > 0) {
451             if ((amount + player_ptr->virtues[i] > 50) && one_in_(2)) {
452                 player_ptr->virtues[i] = std::max<short>(player_ptr->virtues[i], 50);
453                 return;
454             }
455
456             if ((amount + player_ptr->virtues[i] > 80) && one_in_(2)) {
457                 player_ptr->virtues[i] = std::max<short>(player_ptr->virtues[i], 80);
458                 return;
459             }
460
461             if ((amount + player_ptr->virtues[i] > 100) && one_in_(2)) {
462                 player_ptr->virtues[i] = std::max<short>(player_ptr->virtues[i], 100);
463                 return;
464             }
465
466             if (amount + player_ptr->virtues[i] > 125)
467                 player_ptr->virtues[i] = 125;
468             else
469                 player_ptr->virtues[i] = player_ptr->virtues[i] + amount;
470         } else {
471             if ((amount + player_ptr->virtues[i] < -50) && one_in_(2)) {
472                 player_ptr->virtues[i] = std::min<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::min<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::min<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
492         player_ptr->update |= PU_BONUS;
493         return;
494     }
495 }
496
497 /*!
498  * @brief 対応する徳をプレイヤーがスロットに登録している場合に固定値をセットする
499  * @param virtue 徳のID
500  * @param amount セットしたい値
501  */
502 void set_virtue(PlayerType *player_ptr, int virtue_id, int amount)
503 {
504     for (int i = 0; i < 8; i++)
505         if (player_ptr->vir_types[i] == virtue_id) {
506             player_ptr->virtues[i] = (int16_t)amount;
507             return;
508         }
509 }
510
511 /*!
512  * @brief 徳のダンプ表示を行う
513  * @param out_file ファイルポインタ
514  */
515 void dump_virtues(PlayerType *player_ptr, FILE *out_file)
516 {
517     if (!out_file)
518         return;
519
520     for (int v_nr = 0; v_nr < 8; v_nr++) {
521         GAME_TEXT vir_name[20];
522         int tester = player_ptr->virtues[v_nr];
523         strcpy(vir_name, virtue[(player_ptr->vir_types[v_nr]) - 1]);
524         concptr vir_val = show_actual_value ? format(" (%d)", tester) : "";
525         if (player_ptr->vir_types[v_nr] == 0 || player_ptr->vir_types[v_nr] > MAX_VIRTUE)
526             fprintf(out_file, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name);
527
528         else if (tester < -100)
529             fprintf(out_file, _("[%s]の対極%s", "You are the polar opposite of %s.%s"), vir_name, vir_val);
530         else if (tester < -80)
531             fprintf(out_file, _("[%s]の大敵%s", "You are an arch-enemy of %s.%s"), vir_name, vir_val);
532         else if (tester < -60)
533             fprintf(out_file, _("[%s]の強敵%s", "You are a bitter enemy of %s.%s"), vir_name, vir_val);
534         else if (tester < -40)
535             fprintf(out_file, _("[%s]の敵%s", "You are an enemy of %s.%s"), vir_name, vir_val);
536         else if (tester < -20)
537             fprintf(out_file, _("[%s]の罪者%s", "You have sinned against %s.%s"), vir_name, vir_val);
538         else if (tester < 0)
539             fprintf(out_file, _("[%s]の迷道者%s", "You have strayed from the path of %s.%s"), vir_name, vir_val);
540         else if (tester == 0)
541             fprintf(out_file, _("[%s]の中立者%s", "You are neutral to %s.%s"), vir_name, vir_val);
542         else if (tester < 20)
543             fprintf(out_file, _("[%s]の小徳者%s", "You are somewhat virtuous in %s.%s"), vir_name, vir_val);
544         else if (tester < 40)
545             fprintf(out_file, _("[%s]の中徳者%s", "You are virtuous in %s.%s"), vir_name, vir_val);
546         else if (tester < 60)
547             fprintf(out_file, _("[%s]の高徳者%s", "You are very virtuous in %s.%s"), vir_name, vir_val);
548         else if (tester < 80)
549             fprintf(out_file, _("[%s]の覇者%s", "You are a champion of %s.%s"), vir_name, vir_val);
550         else if (tester < 100)
551             fprintf(out_file, _("[%s]の偉大な覇者%s", "You are a great champion of %s.%s"), vir_name, vir_val);
552         else
553             fprintf(out_file, _("[%s]の具現者%s", "You are the living embodiment of %s.%s"), vir_name, vir_val);
554
555         fprintf(out_file, "\n");
556     }
557 }