OSDN Git Service

a3d62ec78ccb9dcced72f3104b6d61d21c3b53a7
[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-race/race-resistance-mask.h"
12 #include "monster/monster-info.h"
13 #include "object-enchant/tr-types.h"
14 #include "object/object-flags.h"
15 #include "object/tval-types.h"
16 #include "player-base/player-class.h"
17 #include "player/attack-defense-types.h"
18 #include "realm/realm-hex-numbers.h"
19 #include "specific-object/torch.h"
20 #include "spell-realm/spells-hex.h"
21 #include "system/item-entity.h"
22 #include "system/monster-entity.h"
23 #include "system/monster-race-info.h"
24 #include "system/player-type-definition.h"
25 #include "system/redrawing-flags-updater.h"
26 #include "util/bit-flags-calculator.h"
27
28 /*!
29  * @brief プレイヤー攻撃の種族スレイング倍率計算
30  * @param player_ptr プレイヤーへの参照ポインタ
31  * @param mult 算出前の基本倍率(/10倍)
32  * @param flags スレイフラグ配列
33  * @param m_ptr 目標モンスターの構造体参照ポインタ
34  * @return スレイング加味後の倍率(/10倍)
35  */
36 MULTIPLY mult_slaying(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr)
37 {
38     static const struct slay_table_t {
39         tr_type slay_flag;
40         MonsterKindType affect_race_flag;
41         MULTIPLY slay_mult;
42     } slay_table[] = {
43         { TR_SLAY_ANIMAL, MonsterKindType::ANIMAL, 25 },
44         { TR_KILL_ANIMAL, MonsterKindType::ANIMAL, 40 },
45         { TR_SLAY_EVIL, MonsterKindType::EVIL, 20 },
46         { TR_KILL_EVIL, MonsterKindType::EVIL, 35 },
47         { TR_SLAY_GOOD, MonsterKindType::GOOD, 20 },
48         { TR_KILL_GOOD, MonsterKindType::GOOD, 35 },
49         { TR_SLAY_HUMAN, MonsterKindType::HUMAN, 25 },
50         { TR_KILL_HUMAN, MonsterKindType::HUMAN, 40 },
51         { TR_SLAY_UNDEAD, MonsterKindType::UNDEAD, 30 },
52         { TR_KILL_UNDEAD, MonsterKindType::UNDEAD, 50 },
53         { TR_SLAY_DEMON, MonsterKindType::DEMON, 30 },
54         { TR_KILL_DEMON, MonsterKindType::DEMON, 50 },
55         { TR_SLAY_ORC, MonsterKindType::ORC, 30 },
56         { TR_KILL_ORC, MonsterKindType::ORC, 50 },
57         { TR_SLAY_TROLL, MonsterKindType::TROLL, 30 },
58         { TR_KILL_TROLL, MonsterKindType::TROLL, 50 },
59         { TR_SLAY_GIANT, MonsterKindType::GIANT, 30 },
60         { TR_KILL_GIANT, MonsterKindType::GIANT, 50 },
61         { TR_SLAY_DRAGON, MonsterKindType::DRAGON, 30 },
62         { TR_KILL_DRAGON, MonsterKindType::DRAGON, 50 },
63     };
64
65     auto *r_ptr = &monraces_info[m_ptr->r_idx];
66     for (size_t i = 0; i < sizeof(slay_table) / sizeof(slay_table[0]); ++i) {
67         const struct slay_table_t *p = &slay_table[i];
68
69         if (flags.has_not(p->slay_flag) || r_ptr->kind_flags.has_not(p->affect_race_flag)) {
70             continue;
71         }
72
73         if (is_original_ap_and_seen(player_ptr, m_ptr)) {
74             r_ptr->r_kind_flags.set(p->affect_race_flag);
75         }
76
77         mult = std::max(mult, p->slay_mult);
78     }
79
80     return mult;
81 }
82
83 /*!
84  * @brief プレイヤー攻撃の属性スレイング倍率計算
85  * @param player_ptr プレイヤーへの参照ポインタ
86  * @param mult 算出前の基本倍率(/10倍)
87  * @param flags スレイフラグ配列
88  * @param m_ptr 目標モンスターの構造体参照ポインタ
89  * @return スレイング加味後の倍率(/10倍)
90  */
91 MULTIPLY mult_brand(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr)
92 {
93     static const struct brand_table_t {
94         tr_type brand_flag;
95         EnumClassFlagGroup<MonsterResistanceType> resist_mask;
96         MonsterResistanceType hurt_flag;
97     } brand_table[] = {
98         { TR_BRAND_ACID, RFR_EFF_IM_ACID_MASK, MonsterResistanceType::MAX },
99         { TR_BRAND_ELEC, RFR_EFF_IM_ELEC_MASK, MonsterResistanceType::MAX },
100         { TR_BRAND_FIRE, RFR_EFF_IM_FIRE_MASK, MonsterResistanceType::HURT_FIRE },
101         { TR_BRAND_COLD, RFR_EFF_IM_COLD_MASK, MonsterResistanceType::HURT_COLD },
102         { TR_BRAND_POIS, RFR_EFF_IM_POISON_MASK, MonsterResistanceType::MAX },
103     };
104
105     auto *r_ptr = &monraces_info[m_ptr->r_idx];
106     for (size_t i = 0; i < sizeof(brand_table) / sizeof(brand_table[0]); ++i) {
107         const struct brand_table_t *p = &brand_table[i];
108
109         if (flags.has_not(p->brand_flag)) {
110             continue;
111         }
112
113         /* Notice immunity */
114         if (r_ptr->resistance_flags.has_any_of(p->resist_mask)) {
115             if (is_original_ap_and_seen(player_ptr, m_ptr)) {
116                 r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & p->resist_mask);
117             }
118
119             continue;
120         }
121
122         /* Otherwise, take the damage */
123         if (r_ptr->resistance_flags.has(p->hurt_flag)) {
124             if (is_original_ap_and_seen(player_ptr, m_ptr)) {
125                 r_ptr->r_resistance_flags.set(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 int calc_attack_damage_with_slay(PlayerType *player_ptr, ItemEntity *o_ptr, int tdam, MonsterEntity *m_ptr, combat_options mode, bool thrown)
155 {
156     auto flags = object_flags(o_ptr);
157     torch_flags(o_ptr, flags); /* torches has secret flags */
158
159     if (!thrown) {
160         if (player_ptr->special_attack & (ATTACK_ACID)) {
161             flags.set(TR_BRAND_ACID);
162         }
163         if (player_ptr->special_attack & (ATTACK_COLD)) {
164             flags.set(TR_BRAND_COLD);
165         }
166         if (player_ptr->special_attack & (ATTACK_ELEC)) {
167             flags.set(TR_BRAND_ELEC);
168         }
169         if (player_ptr->special_attack & (ATTACK_FIRE)) {
170             flags.set(TR_BRAND_FIRE);
171         }
172         if (player_ptr->special_attack & (ATTACK_POIS)) {
173             flags.set(TR_BRAND_POIS);
174         }
175     }
176
177     if (SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD)) {
178         flags.set(TR_SLAY_GOOD);
179     }
180
181     MULTIPLY mult = 10;
182     switch (o_ptr->bi_key.tval()) {
183     case ItemKindType::SHOT:
184     case ItemKindType::ARROW:
185     case ItemKindType::BOLT:
186     case ItemKindType::HAFTED:
187     case ItemKindType::POLEARM:
188     case ItemKindType::SWORD:
189     case ItemKindType::DIGGING:
190     case ItemKindType::LITE: {
191         mult = mult_slaying(player_ptr, mult, flags, m_ptr);
192
193         mult = mult_brand(player_ptr, mult, flags, m_ptr);
194
195         PlayerClass pc(player_ptr);
196         if (pc.equals(PlayerClassType::SAMURAI)) {
197             mult = mult_hissatsu(player_ptr, mult, flags, m_ptr, mode);
198         }
199
200         if (!pc.equals(PlayerClassType::SAMURAI) && (flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
201             player_ptr->csp -= (1 + (o_ptr->dd * o_ptr->ds / 5));
202             RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
203             mult = mult * 3 / 2 + 20;
204         }
205
206         if ((o_ptr->is_specific_artifact(FixedArtifactId::NOTHUNG)) && (m_ptr->r_idx == MonsterRaceId::FAFNER)) {
207             mult = 150;
208         }
209         break;
210     }
211
212     default:
213         break;
214     }
215
216     if (mult > 150) {
217         mult = 150;
218     }
219     return tdam * mult / 10;
220 }
221
222 AttributeFlags melee_attribute(PlayerType *player_ptr, ItemEntity *o_ptr, combat_options mode)
223 {
224     AttributeFlags attribute_flags{};
225     attribute_flags.set(AttributeType::PLAYER_MELEE);
226
227     if (PlayerClass(player_ptr).equals(PlayerClassType::SAMURAI)) {
228         static const struct samurai_convert_table_t {
229             combat_options hissatsu_type;
230             AttributeType attribute;
231         } samurai_convert_table[] = {
232             { HISSATSU_FIRE, AttributeType::FIRE },
233             { HISSATSU_COLD, AttributeType::COLD },
234             { HISSATSU_ELEC, AttributeType::ELEC },
235             { HISSATSU_POISON, AttributeType::POIS },
236             { HISSATSU_HAGAN, AttributeType::KILL_WALL },
237         };
238
239         for (size_t i = 0; i < sizeof(samurai_convert_table) / sizeof(samurai_convert_table[0]); ++i) {
240             const struct samurai_convert_table_t *p = &samurai_convert_table[i];
241
242             if (mode == p->hissatsu_type) {
243                 attribute_flags.set(p->attribute);
244             }
245         }
246     }
247
248     auto flags = object_flags(o_ptr);
249
250     if (player_ptr->special_attack & (ATTACK_ACID)) {
251         flags.set(TR_BRAND_ACID);
252     }
253     if (player_ptr->special_attack & (ATTACK_COLD)) {
254         flags.set(TR_BRAND_COLD);
255     }
256     if (player_ptr->special_attack & (ATTACK_ELEC)) {
257         flags.set(TR_BRAND_ELEC);
258     }
259     if (player_ptr->special_attack & (ATTACK_FIRE)) {
260         flags.set(TR_BRAND_FIRE);
261     }
262     if (player_ptr->special_attack & (ATTACK_POIS)) {
263         flags.set(TR_BRAND_POIS);
264     }
265
266     if (SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD)) {
267         flags.set(TR_SLAY_GOOD);
268     }
269
270     static const struct brand_convert_table_t {
271         tr_type brand_type;
272         AttributeType attribute;
273     } brand_convert_table[] = {
274         { TR_BRAND_ACID, AttributeType::ACID },
275         { TR_BRAND_FIRE, AttributeType::FIRE },
276         { TR_BRAND_ELEC, AttributeType::ELEC },
277         { TR_BRAND_COLD, AttributeType::COLD },
278         { TR_BRAND_POIS, AttributeType::POIS },
279         { TR_SLAY_GOOD, AttributeType::HELL_FIRE },
280         { TR_KILL_GOOD, AttributeType::HELL_FIRE },
281         { TR_SLAY_EVIL, AttributeType::HOLY_FIRE },
282         { TR_KILL_EVIL, AttributeType::HOLY_FIRE },
283     };
284
285     for (size_t i = 0; i < sizeof(brand_convert_table) / sizeof(brand_convert_table[0]); ++i) {
286         const struct brand_convert_table_t *p = &brand_convert_table[i];
287
288         if (flags.has(p->brand_type)) {
289             attribute_flags.set(p->attribute);
290         }
291     }
292
293     if ((flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
294         attribute_flags.set(AttributeType::MANA);
295     }
296
297     return attribute_flags;
298 }