OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[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 "monster-race/monster-kind-mask.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 "monster/monster-info.h"
17 #include "system/dungeon-info.h"
18 #include "system/floor-type-definition.h"
19 #include "system/monster-entity.h"
20 #include "system/monster-race-info.h"
21 #include "system/player-type-definition.h"
22 #include "util/bit-flags-calculator.h"
23
24 /*!
25  * @brief AvaterChangerコンストラクタ
26  */
27 AvatarChanger::AvatarChanger(PlayerType *player_ptr, MonsterEntity *m_ptr)
28     : player_ptr(player_ptr)
29     , m_ptr(m_ptr)
30 {
31 }
32
33 /*!
34  * @brief 徳変化処理のメインルーチン
35  */
36 void AvatarChanger::change_virtue()
37 {
38     this->change_virtue_non_beginner();
39     this->change_virtue_unique();
40     const auto &r_ref = this->m_ptr->get_real_r_ref();
41     if (m_ptr->r_idx == MonsterRaceId::BEGGAR || m_ptr->r_idx == MonsterRaceId::LEPER) {
42         chg_virtue(this->player_ptr, Virtue::COMPASSION, -1);
43     }
44
45     this->change_virtue_good_evil();
46     if (r_ref.kind_flags.has(MonsterKindType::UNDEAD) && r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
47         chg_virtue(this->player_ptr, Virtue::VITALITY, 2);
48     }
49
50     this->change_virtue_revenge();
51     if (any_bits(r_ref.flags2, RF2_MULTIPLY) && (r_ref.r_akills > 1000) && one_in_(10)) {
52         chg_virtue(this->player_ptr, Virtue::VALOUR, -1);
53     }
54
55     this->change_virtue_wild_thief();
56     this->change_virtue_good_animal();
57 }
58
59 /*!
60  * @brief 非BEGINNERダンジョン時に伴う徳の変化処理
61  */
62 void AvatarChanger::change_virtue_non_beginner()
63 {
64     auto *floor_ptr = this->player_ptr->current_floor_ptr;
65     auto *r_ptr = &monraces_info[m_ptr->r_idx];
66     if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::BEGINNER)) {
67         return;
68     }
69
70     if ((floor_ptr->dun_level == 0) && !this->player_ptr->ambush_flag && !floor_ptr->inside_arena) {
71         chg_virtue(this->player_ptr, Virtue::VALOUR, -1);
72     } else if (r_ptr->level > floor_ptr->dun_level) {
73         if (randint1(10) <= (r_ptr->level - floor_ptr->dun_level)) {
74             chg_virtue(this->player_ptr, Virtue::VALOUR, 1);
75         }
76     }
77
78     if (r_ptr->level > 60) {
79         chg_virtue(this->player_ptr, Virtue::VALOUR, 1);
80     }
81
82     if (r_ptr->level >= 2 * (this->player_ptr->lev + 1)) {
83         chg_virtue(this->player_ptr, Virtue::VALOUR, 2);
84     }
85 }
86
87 /*!
88  * @brief ユニークを攻撃対象にした場合限定の徳変化処理
89  */
90 void AvatarChanger::change_virtue_unique()
91 {
92     auto *r_ptr = &monraces_info[m_ptr->r_idx];
93     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
94         return;
95     }
96
97     if (r_ptr->kind_flags.has_any_of(alignment_mask)) {
98         chg_virtue(this->player_ptr, Virtue::HARMONY, 2);
99     }
100
101     if (r_ptr->kind_flags.has(MonsterKindType::GOOD)) {
102         chg_virtue(this->player_ptr, Virtue::UNLIFE, 2);
103         chg_virtue(this->player_ptr, Virtue::VITALITY, -2);
104     }
105
106     if (one_in_(3)) {
107         chg_virtue(this->player_ptr, Virtue::INDIVIDUALISM, -1);
108     }
109 }
110
111 /*!
112  * @brief 攻撃を与えたモンスターが天使か悪魔だった場合、徳を変化させる
113  * @details 天使かつ悪魔だった場合、天使であることが優先される
114  */
115 void AvatarChanger::change_virtue_good_evil()
116 {
117     auto *floor_ptr = this->player_ptr->current_floor_ptr;
118     auto *r_ptr = &monraces_info[m_ptr->r_idx];
119     if (r_ptr->kind_flags.has(MonsterKindType::GOOD) && ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100))) {
120         chg_virtue(this->player_ptr, Virtue::UNLIFE, 1);
121     }
122
123     if (r_ptr->kind_flags.has(MonsterKindType::ANGEL)) {
124         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
125             chg_virtue(this->player_ptr, Virtue::FAITH, -2);
126         } else if ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)) {
127             auto change_value = r_ptr->kind_flags.has(MonsterKindType::GOOD) ? -1 : 1;
128             chg_virtue(this->player_ptr, Virtue::FAITH, change_value);
129         }
130
131         return;
132     }
133
134     if (r_ptr->kind_flags.has(MonsterKindType::DEMON)) {
135         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
136             chg_virtue(this->player_ptr, Virtue::FAITH, 2);
137         } else if ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)) {
138             chg_virtue(this->player_ptr, Virtue::FAITH, 1);
139         }
140     }
141 }
142
143 /*!
144  * @brief 過去に@を殺したことがあるユニークにリゾンべを果たせたら徳を上げる
145  */
146 void AvatarChanger::change_virtue_revenge()
147 {
148     auto *floor_ptr = this->player_ptr->current_floor_ptr;
149     auto *r_ptr = &monraces_info[m_ptr->r_idx];
150     if (r_ptr->r_deaths == 0) {
151         return;
152     }
153
154     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
155         chg_virtue(this->player_ptr, Virtue::HONOUR, 10);
156         return;
157     }
158
159     if ((r_ptr->level) / 10 + (2 * floor_ptr->dun_level) >= randint1(100)) {
160         chg_virtue(this->player_ptr, Virtue::HONOUR, 1);
161     }
162 }
163
164 /*!
165  * @brief 盗み逃げをするモンスター及び地上のモンスターを攻撃した際に徳を変化させる
166  */
167 void AvatarChanger::change_virtue_wild_thief()
168 {
169     auto *floor_ptr = this->player_ptr->current_floor_ptr;
170     auto *r_ptr = &monraces_info[m_ptr->r_idx];
171     auto innocent = true;
172     auto thief = false;
173     for (const auto &blow : r_ptr->blows) {
174         if (blow.d_dice != 0) {
175             innocent = false;
176         }
177
178         if ((blow.effect == RaceBlowEffectType::EAT_ITEM) || (blow.effect == RaceBlowEffectType::EAT_GOLD)) {
179             thief = true;
180         }
181     }
182
183     if (r_ptr->level > 0) {
184         innocent = false;
185     }
186
187     if (thief) {
188         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
189             chg_virtue(this->player_ptr, Virtue::JUSTICE, 3);
190             return;
191         }
192
193         if (1 + ((r_ptr->level) / 10 + (2 * floor_ptr->dun_level)) >= randint1(100)) {
194             chg_virtue(this->player_ptr, Virtue::JUSTICE, 1);
195         }
196
197         return;
198     }
199
200     if (innocent) {
201         chg_virtue(this->player_ptr, Virtue::JUSTICE, -1);
202     }
203 }
204
205 /*!
206  * @brief 邪悪でなく、魔法も持たない動物を攻撃した時に徳を下げる
207  */
208 void AvatarChanger::change_virtue_good_animal()
209 {
210     auto *r_ptr = &monraces_info[m_ptr->r_idx];
211     auto magic_ability_flags = r_ptr->ability_flags;
212     magic_ability_flags.reset(RF_ABILITY_NOMAGIC_MASK);
213     if (r_ptr->kind_flags.has_not(MonsterKindType::ANIMAL) || r_ptr->kind_flags.has(MonsterKindType::EVIL) || magic_ability_flags.any()) {
214         return;
215     }
216
217     if (one_in_(4)) {
218         chg_virtue(this->player_ptr, Virtue::NATURE, -1);
219     }
220 }