OSDN Git Service

309f2799767944b09d26bd787a14422f9a83b5e4
[hengbandforosx/hengbandosx.git] / src / avatar / avatar-changer.cpp
1 /*
2  * @brief 敵への攻撃によって徳を変化させる処理
3  * @date 2021/08/05
4  * @author Hourier
5  */
6
7 #include "avatar/avatar-changer.h"
8 #include "avatar/avatar.h"
9 #include "dungeon/dungeon.h"
10 #include "monster-race/monster-race.h"
11 #include "monster-race/race-ability-mask.h"
12 #include "monster-race/race-flags1.h"
13 #include "monster-race/race-flags2.h"
14 #include "monster-race/race-flags3.h"
15 #include "monster-race/race-indice-types.h"
16 #include "system/floor-type-definition.h"
17 #include "system/monster-race-definition.h"
18 #include "system/monster-type-definition.h"
19 #include "system/player-type-definition.h"
20 #include "util/bit-flags-calculator.h"
21
22 /*!
23  * @brief AvaterChangerコンストラクタ
24  */
25 AvatarChanger::AvatarChanger(player_type *player_ptr, monster_type *m_ptr)
26     : player_ptr(player_ptr)
27     , m_ptr(m_ptr)
28 {
29 }
30
31 /*!
32  * @brief 徳変化処理のメインルーチン
33  */
34 void AvatarChanger::change_virtue()
35 {
36     this->change_virtue_non_beginner();
37     this->change_virtue_unique();
38     auto *r_ptr = &r_info[m_ptr->r_idx];
39     if (m_ptr->r_idx == MON_BEGGAR || m_ptr->r_idx == MON_LEPER) {
40         chg_virtue(this->player_ptr, V_COMPASSION, -1);
41     }
42
43     this->change_virtue_good_evil();
44     if (any_bits(r_ptr->flags3, RF3_UNDEAD) && any_bits(r_ptr->flags1, RF1_UNIQUE)) {
45         chg_virtue(this->player_ptr, V_VITALITY, 2);
46     }
47
48     this->change_virtue_revenge();
49     if (any_bits(r_ptr->flags2, RF2_MULTIPLY) && (r_ptr->r_akills > 1000) && one_in_(10)) {
50         chg_virtue(this->player_ptr, V_VALOUR, -1);
51     }
52
53     this->change_virtue_wild_thief();
54     this->change_virtue_good_animal();
55 }
56
57 /*!
58  * @brief 非BEGINNERダンジョン時に伴う徳の変化処理
59  */
60 void AvatarChanger::change_virtue_non_beginner()
61 {
62     auto *floor_ptr = this->player_ptr->current_floor_ptr;
63     auto *r_ptr = &r_info[m_ptr->r_idx];
64     if (d_info[this->player_ptr->dungeon_idx].flags.has(DF::BEGINNER)) {
65         return;
66     }
67
68     if ((floor_ptr->dun_level == 0) && !this->player_ptr->ambush_flag && !floor_ptr->inside_arena) {
69         chg_virtue(this->player_ptr, V_VALOUR, -1);
70     } else if (r_ptr->level > floor_ptr->dun_level) {
71         if (randint1(10) <= (r_ptr->level - floor_ptr->dun_level)) {
72             chg_virtue(this->player_ptr, V_VALOUR, 1);
73         }
74     }
75
76     if (r_ptr->level > 60) {
77         chg_virtue(this->player_ptr, V_VALOUR, 1);
78     }
79
80     if (r_ptr->level >= 2 * (this->player_ptr->lev + 1)) {
81         chg_virtue(this->player_ptr, V_VALOUR, 2);
82     }
83 }
84
85 /*!
86  * @brief ユニークを攻撃対象にした場合限定の徳変化処理
87  */
88 void AvatarChanger::change_virtue_unique()
89 {
90     auto *r_ptr = &r_info[m_ptr->r_idx];
91     if (none_bits(r_ptr->flags1, RF1_UNIQUE)) {
92         return;
93     }
94
95     if (any_bits(r_ptr->flags3, RF3_EVIL | RF3_GOOD)) {
96         chg_virtue(this->player_ptr, V_HARMONY, 2);
97     }
98
99     if (any_bits(r_ptr->flags3, RF3_GOOD)) {
100         chg_virtue(this->player_ptr, V_UNLIFE, 2);
101         chg_virtue(this->player_ptr, V_VITALITY, -2);
102     }
103
104     if (one_in_(3)) {
105         chg_virtue(this->player_ptr, V_INDIVIDUALISM, -1);
106     }
107 }
108
109 /*!
110  * @brief 攻撃を与えたモンスターが天使か悪魔だった場合、徳を変化させる
111  * @details 天使かつ悪魔だった場合、天使であることが優先される
112  */
113 void AvatarChanger::change_virtue_good_evil()
114 {
115     auto *floor_ptr = this->player_ptr->current_floor_ptr;
116     auto *r_ptr = &r_info[m_ptr->r_idx];
117     if (any_bits(r_ptr->flags3, RF3_GOOD) && ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100))) {
118         chg_virtue(this->player_ptr, V_UNLIFE, 1);
119     }
120
121     if (any_bits(r_ptr->flags3, RF3_ANGEL)) {
122         if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
123             chg_virtue(this->player_ptr, V_FAITH, -2);
124         } else if ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)) {
125             auto change_value = any_bits(r_ptr->flags3, RF3_GOOD) ? -1 : 1;
126             chg_virtue(this->player_ptr, V_FAITH, change_value);
127         }
128
129         return;
130     }
131
132     if (any_bits(r_ptr->flags3, RF3_DEMON)) {
133         if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
134             chg_virtue(this->player_ptr, V_FAITH, 2);
135         } else if ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)) {
136             chg_virtue(this->player_ptr, V_FAITH, 1);
137         }
138     }
139 }
140
141 /*!
142  * @brief 過去に@を殺したことがあるユニークにリゾンべを果たせたら徳を上げる
143  */
144 void AvatarChanger::change_virtue_revenge()
145 {
146     auto *floor_ptr = this->player_ptr->current_floor_ptr;
147     auto *r_ptr = &r_info[m_ptr->r_idx];
148     if (r_ptr->r_deaths == 0) {
149         return;
150     }
151
152     if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
153         chg_virtue(this->player_ptr, V_HONOUR, 10);
154         return;
155     }
156
157     if ((r_ptr->level) / 10 + (2 * floor_ptr->dun_level) >= randint1(100)) {
158         chg_virtue(this->player_ptr, V_HONOUR, 1);
159     }
160 }
161
162 /*!
163  * @brief 盗み逃げをするモンスター及び地上のモンスターを攻撃した際に徳を変化させる
164  */
165 void AvatarChanger::change_virtue_wild_thief()
166 {
167     auto *floor_ptr = this->player_ptr->current_floor_ptr;
168     auto *r_ptr = &r_info[m_ptr->r_idx];
169     auto innocent = true;
170     auto thief = false;
171     for (auto i = 0; i < MAX_NUM_BLOWS; i++) {
172         if (r_ptr->blow[i].d_dice != 0) {
173             innocent = false;
174         }
175
176         if ((r_ptr->blow[i].effect == RaceBlowEffectType::EAT_ITEM) || (r_ptr->blow[i].effect == RaceBlowEffectType::EAT_GOLD)) {
177             thief = true;
178         }
179     }
180
181     if (r_ptr->level > 0) {
182         innocent = false;
183     }
184
185     if (thief) {
186         if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
187             chg_virtue(this->player_ptr, V_JUSTICE, 3);
188             return;
189         }
190
191         if (1 + ((r_ptr->level) / 10 + (2 * floor_ptr->dun_level)) >= randint1(100)) {
192             chg_virtue(this->player_ptr, V_JUSTICE, 1);
193         }
194
195         return;
196     }
197
198     if (innocent) {
199         chg_virtue(this->player_ptr, V_JUSTICE, -1);
200     }
201 }
202
203 /*!
204  * @brief 邪悪でなく、魔法も持たない動物を攻撃した時に徳を下げる
205  */
206 void AvatarChanger::change_virtue_good_animal()
207 {
208     auto *r_ptr = &r_info[m_ptr->r_idx];
209     auto magic_ability_flags = r_ptr->ability_flags;
210     magic_ability_flags.reset(RF_ABILITY_NOMAGIC_MASK);
211     if (none_bits(r_ptr->flags3, RF3_ANIMAL) || any_bits(r_ptr->flags3, RF3_EVIL) || magic_ability_flags.any()) {
212         return;
213     }
214
215     if (one_in_(4)) {
216         chg_virtue(this->player_ptr, V_NATURE, -1);
217     }
218 }