OSDN Git Service

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