OSDN Git Service

21b5ecd91da27fc2465c77e456a6f25cb6cf1c4b
[hengbandforosx/hengbandosx.git] / src / combat / slaying.cpp
1 #include "combat/slaying.h"
2 #include "artifact/fixed-art-types.h"
3 #include "core/player-redraw-types.h"
4 #include "effect/attribute-types.h"
5 #include "mind/mind-samurai.h"
6 #include "monster-race/monster-race.h"
7 #include "monster-race/race-flags-resistance.h"
8 #include "monster-race/race-flags2.h"
9 #include "monster-race/race-flags3.h"
10 #include "monster-race/race-indice-types.h"
11 #include "monster/monster-info.h"
12 #include "object-enchant/tr-types.h"
13 #include "object/object-flags.h"
14 #include "object/tval-types.h"
15 #include "player-base/player-class.h"
16 #include "player/attack-defense-types.h"
17 #include "realm/realm-hex-numbers.h"
18 #include "specific-object/torch.h"
19 #include "spell-realm/spells-hex.h"
20 #include "system/monster-race-definition.h"
21 #include "system/monster-type-definition.h"
22 #include "system/object-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "util/bit-flags-calculator.h"
25
26 /*!
27  * @brief プレイヤー攻撃の種族スレイング倍率計算
28  * @param player_ptr プレイヤーへの参照ポインタ
29  * @param mult 算出前の基本倍率(/10倍)
30  * @param flgs スレイフラグ配列
31  * @param m_ptr 目標モンスターの構造体参照ポインタ
32  * @return スレイング加味後の倍率(/10倍)
33  */
34 MULTIPLY mult_slaying(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flgs, monster_type *m_ptr)
35 {
36     static const struct slay_table_t {
37         tr_type slay_flag;
38         MonsterKindType affect_race_flag;
39         MULTIPLY slay_mult;
40     } slay_table[] = {
41         { TR_SLAY_ANIMAL, MonsterKindType::ANIMAL, 25 },
42         { TR_KILL_ANIMAL, MonsterKindType::ANIMAL, 40 },
43         { TR_SLAY_EVIL, MonsterKindType::EVIL, 20 },
44         { TR_KILL_EVIL, MonsterKindType::EVIL, 35 },
45         { TR_SLAY_GOOD, MonsterKindType::GOOD, 20 },
46         { TR_KILL_GOOD, MonsterKindType::GOOD, 35 },
47         { TR_SLAY_HUMAN, MonsterKindType::HUMAN, 25 },
48         { TR_KILL_HUMAN, MonsterKindType::HUMAN, 40 },
49         { TR_SLAY_UNDEAD, MonsterKindType::UNDEAD, 30 },
50         { TR_KILL_UNDEAD, MonsterKindType::UNDEAD, 50 },
51         { TR_SLAY_DEMON, MonsterKindType::DEMON, 30 },
52         { TR_KILL_DEMON, MonsterKindType::DEMON, 50 },
53         { TR_SLAY_ORC, MonsterKindType::ORC, 30 },
54         { TR_KILL_ORC, MonsterKindType::ORC, 50 },
55         { TR_SLAY_TROLL, MonsterKindType::TROLL, 30 },
56         { TR_KILL_TROLL, MonsterKindType::TROLL, 50 },
57         { TR_SLAY_GIANT, MonsterKindType::GIANT, 30 },
58         { TR_KILL_GIANT, MonsterKindType::GIANT, 50 },
59         { TR_SLAY_DRAGON, MonsterKindType::DRAGON, 30 },
60         { TR_KILL_DRAGON, MonsterKindType::DRAGON, 50 },
61     };
62
63     auto *r_ptr = &r_info[m_ptr->r_idx];
64     for (size_t i = 0; i < sizeof(slay_table) / sizeof(slay_table[0]); ++i) {
65         const struct slay_table_t *p = &slay_table[i];
66
67         if (flgs.has_not(p->slay_flag) || r_ptr->kind_flags.has(p->affect_race_flag))
68             continue;
69
70         if (is_original_ap_and_seen(player_ptr, m_ptr)) {
71             r_ptr->r_kind_flags.set(p->affect_race_flag);
72         }
73
74         mult = std::max(mult, p->slay_mult);
75     }
76
77     return mult;
78 }
79
80 /*!
81  * @brief プレイヤー攻撃の属性スレイング倍率計算
82  * @param player_ptr プレイヤーへの参照ポインタ
83  * @param mult 算出前の基本倍率(/10倍)
84  * @param flgs スレイフラグ配列
85  * @param m_ptr 目標モンスターの構造体参照ポインタ
86  * @return スレイング加味後の倍率(/10倍)
87  */
88 MULTIPLY mult_brand(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flgs, monster_type *m_ptr)
89 {
90     static const struct brand_table_t {
91         tr_type brand_flag;
92         BIT_FLAGS resist_mask;
93         BIT_FLAGS hurt_flag;
94     } brand_table[] = {
95         { TR_BRAND_ACID, RFR_EFF_IM_ACID_MASK, 0U },
96         { TR_BRAND_ELEC, RFR_EFF_IM_ELEC_MASK, 0U },
97         { TR_BRAND_FIRE, RFR_EFF_IM_FIRE_MASK, RF3_HURT_FIRE },
98         { TR_BRAND_COLD, RFR_EFF_IM_COLD_MASK, RF3_HURT_COLD },
99         { TR_BRAND_POIS, RFR_EFF_IM_POIS_MASK, 0U },
100     };
101
102     auto *r_ptr = &r_info[m_ptr->r_idx];
103     for (size_t i = 0; i < sizeof(brand_table) / sizeof(brand_table[0]); ++i) {
104         const struct brand_table_t *p = &brand_table[i];
105
106         if (flgs.has_not(p->brand_flag))
107             continue;
108
109         /* Notice immunity */
110         if (r_ptr->flagsr & p->resist_mask) {
111             if (is_original_ap_and_seen(player_ptr, m_ptr)) {
112                 r_ptr->r_flagsr |= (r_ptr->flagsr & p->resist_mask);
113             }
114
115             continue;
116         }
117
118         /* Otherwise, take the damage */
119         if (r_ptr->flags3 & p->hurt_flag) {
120             if (is_original_ap_and_seen(player_ptr, m_ptr)) {
121                 r_ptr->r_flags3 |= p->hurt_flag;
122             }
123
124             mult = std::max<short>(mult, 50);
125             continue;
126         }
127
128         mult = std::max<short>(mult, 25);
129     }
130
131     return mult;
132 }
133
134 /*!
135  * @brief ダメージにスレイ要素を加える総合処理ルーチン /
136  * Extract the "total damage" from a given object hitting a given monster.
137  * @param o_ptr 使用武器オブジェクトの構造体参照ポインタ
138  * @param tdam 現在算出途中のダメージ値
139  * @param m_ptr 目標モンスターの構造体参照ポインタ
140  * @param mode 剣術のID
141  * @param thrown 投擲処理ならばTRUEを指定する
142  * @return 総合的なスレイを加味したダメージ値
143  * @note
144  * Note that "flasks of oil" do NOT do fire damage, although they\n
145  * certainly could be made to do so.  XXX XXX\n
146  *\n
147  * Note that most brands and slays are x3, except Slay Animal (x2),\n
148  * Slay Evil (x2), and Kill dragon (x5).\n
149  */
150 HIT_POINT calc_attack_damage_with_slay(PlayerType *player_ptr, ObjectType *o_ptr, HIT_POINT tdam, monster_type *m_ptr, combat_options mode, bool thrown)
151 {
152     auto flgs = object_flags(o_ptr);
153     torch_flags(o_ptr, flgs); /* torches has secret flags */
154
155     if (!thrown) {
156         if (player_ptr->special_attack & (ATTACK_ACID))
157             flgs.set(TR_BRAND_ACID);
158         if (player_ptr->special_attack & (ATTACK_COLD))
159             flgs.set(TR_BRAND_COLD);
160         if (player_ptr->special_attack & (ATTACK_ELEC))
161             flgs.set(TR_BRAND_ELEC);
162         if (player_ptr->special_attack & (ATTACK_FIRE))
163             flgs.set(TR_BRAND_FIRE);
164         if (player_ptr->special_attack & (ATTACK_POIS))
165             flgs.set(TR_BRAND_POIS);
166     }
167
168     if (SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD))
169         flgs.set(TR_SLAY_GOOD);
170
171     MULTIPLY mult = 10;
172     switch (o_ptr->tval) {
173     case ItemKindType::SHOT:
174     case ItemKindType::ARROW:
175     case ItemKindType::BOLT:
176     case ItemKindType::HAFTED:
177     case ItemKindType::POLEARM:
178     case ItemKindType::SWORD:
179     case ItemKindType::DIGGING:
180     case ItemKindType::LITE: {
181         mult = mult_slaying(player_ptr, mult, flgs, m_ptr);
182
183         mult = mult_brand(player_ptr, mult, flgs, m_ptr);
184
185         PlayerClass pc(player_ptr);
186         if (pc.equals(PlayerClassType::SAMURAI)) {
187             mult = mult_hissatsu(player_ptr, mult, flgs, m_ptr, mode);
188         }
189
190         if (!pc.equals(PlayerClassType::SAMURAI) && (flgs.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
191             player_ptr->csp -= (1 + (o_ptr->dd * o_ptr->ds / 5));
192             player_ptr->redraw |= (PR_MANA);
193             mult = mult * 3 / 2 + 20;
194         }
195
196         if ((o_ptr->name1 == ART_NOTHUNG) && (m_ptr->r_idx == MON_FAFNER))
197             mult = 150;
198         break;
199     }
200
201     default:
202         break;
203     }
204
205     if (mult > 150)
206         mult = 150;
207     return tdam * mult / 10;
208 }
209
210 AttributeFlags melee_attribute(PlayerType *player_ptr, ObjectType *o_ptr, combat_options mode)
211 {
212     AttributeFlags attribute_flags{};
213     attribute_flags.set(AttributeType::PLAYER_MELEE);
214
215     if (PlayerClass(player_ptr).equals(PlayerClassType::SAMURAI)) {
216         static const struct samurai_convert_table_t {
217             combat_options hissatsu_type;
218             AttributeType attribute;
219         } samurai_convert_table[] = {
220             { HISSATSU_FIRE, AttributeType::FIRE },
221             { HISSATSU_COLD, AttributeType::COLD },
222             { HISSATSU_ELEC, AttributeType::ELEC },
223             { HISSATSU_POISON, AttributeType::POIS },
224             { HISSATSU_HAGAN, AttributeType::KILL_WALL },
225         };
226
227         for (size_t i = 0; i < sizeof(samurai_convert_table) / sizeof(samurai_convert_table[0]); ++i) {
228             const struct samurai_convert_table_t *p = &samurai_convert_table[i];
229
230             if (mode == p->hissatsu_type)
231                 attribute_flags.set(p->attribute);
232         }
233     }
234
235     auto flgs = object_flags(o_ptr);
236
237     if (player_ptr->special_attack & (ATTACK_ACID))
238         flgs.set(TR_BRAND_ACID);
239     if (player_ptr->special_attack & (ATTACK_COLD))
240         flgs.set(TR_BRAND_COLD);
241     if (player_ptr->special_attack & (ATTACK_ELEC))
242         flgs.set(TR_BRAND_ELEC);
243     if (player_ptr->special_attack & (ATTACK_FIRE))
244         flgs.set(TR_BRAND_FIRE);
245     if (player_ptr->special_attack & (ATTACK_POIS))
246         flgs.set(TR_BRAND_POIS);
247
248     if (SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD))
249         flgs.set(TR_SLAY_GOOD);
250
251     static const struct brand_convert_table_t {
252         tr_type brand_type;
253         AttributeType attribute;
254     } brand_convert_table[] = {
255         { TR_BRAND_ACID, AttributeType::ACID },
256         { TR_BRAND_FIRE, AttributeType::FIRE },
257         { TR_BRAND_ELEC, AttributeType::ELEC },
258         { TR_BRAND_COLD, AttributeType::COLD },
259         { TR_BRAND_POIS, AttributeType::POIS },
260         { TR_SLAY_GOOD, AttributeType::HELL_FIRE },
261         { TR_KILL_GOOD, AttributeType::HELL_FIRE },
262         { TR_SLAY_EVIL, AttributeType::HOLY_FIRE },
263         { TR_KILL_EVIL, AttributeType::HOLY_FIRE },
264     };
265
266     for (size_t i = 0; i < sizeof(brand_convert_table) / sizeof(brand_convert_table[0]); ++i) {
267         const struct brand_convert_table_t *p = &brand_convert_table[i];
268
269         if (flgs.has(p->brand_type))
270             attribute_flags.set(p->attribute);
271     }
272
273     if ((flgs.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
274         attribute_flags.set(AttributeType::MANA);
275     }
276
277     return attribute_flags;
278 }