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 "util/bit-flags-calculator.h"
28 * @brief プレイヤー攻撃の種族スレイング倍率計算
29 * @param player_ptr プレイヤーへの参照ポインタ
30 * @param mult 算出前の基本倍率(/10倍)
31 * @param flags スレイフラグ配列
32 * @param m_ptr 目標モンスターの構造体参照ポインタ
33 * @return スレイング加味後の倍率(/10倍)
35 MULTIPLY mult_slaying(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr)
37 static const struct slay_table_t {
39 MonsterKindType affect_race_flag;
42 { TR_SLAY_ANIMAL, MonsterKindType::ANIMAL, 25 },
43 { TR_KILL_ANIMAL, MonsterKindType::ANIMAL, 40 },
44 { TR_SLAY_EVIL, MonsterKindType::EVIL, 20 },
45 { TR_KILL_EVIL, MonsterKindType::EVIL, 35 },
46 { TR_SLAY_GOOD, MonsterKindType::GOOD, 20 },
47 { TR_KILL_GOOD, MonsterKindType::GOOD, 35 },
48 { TR_SLAY_HUMAN, MonsterKindType::HUMAN, 25 },
49 { TR_KILL_HUMAN, MonsterKindType::HUMAN, 40 },
50 { TR_SLAY_UNDEAD, MonsterKindType::UNDEAD, 30 },
51 { TR_KILL_UNDEAD, MonsterKindType::UNDEAD, 50 },
52 { TR_SLAY_DEMON, MonsterKindType::DEMON, 30 },
53 { TR_KILL_DEMON, MonsterKindType::DEMON, 50 },
54 { TR_SLAY_ORC, MonsterKindType::ORC, 30 },
55 { TR_KILL_ORC, MonsterKindType::ORC, 50 },
56 { TR_SLAY_TROLL, MonsterKindType::TROLL, 30 },
57 { TR_KILL_TROLL, MonsterKindType::TROLL, 50 },
58 { TR_SLAY_GIANT, MonsterKindType::GIANT, 30 },
59 { TR_KILL_GIANT, MonsterKindType::GIANT, 50 },
60 { TR_SLAY_DRAGON, MonsterKindType::DRAGON, 30 },
61 { TR_KILL_DRAGON, MonsterKindType::DRAGON, 50 },
64 auto *r_ptr = &monraces_info[m_ptr->r_idx];
65 for (size_t i = 0; i < sizeof(slay_table) / sizeof(slay_table[0]); ++i) {
66 const struct slay_table_t *p = &slay_table[i];
68 if (flags.has_not(p->slay_flag) || r_ptr->kind_flags.has_not(p->affect_race_flag)) {
72 if (is_original_ap_and_seen(player_ptr, m_ptr)) {
73 r_ptr->r_kind_flags.set(p->affect_race_flag);
76 mult = std::max(mult, p->slay_mult);
83 * @brief プレイヤー攻撃の属性スレイング倍率計算
84 * @param player_ptr プレイヤーへの参照ポインタ
85 * @param mult 算出前の基本倍率(/10倍)
86 * @param flags スレイフラグ配列
87 * @param m_ptr 目標モンスターの構造体参照ポインタ
88 * @return スレイング加味後の倍率(/10倍)
90 MULTIPLY mult_brand(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr)
92 static const struct brand_table_t {
94 EnumClassFlagGroup<MonsterResistanceType> resist_mask;
95 MonsterResistanceType hurt_flag;
97 { TR_BRAND_ACID, RFR_EFF_IM_ACID_MASK, MonsterResistanceType::MAX },
98 { TR_BRAND_ELEC, RFR_EFF_IM_ELEC_MASK, MonsterResistanceType::MAX },
99 { TR_BRAND_FIRE, RFR_EFF_IM_FIRE_MASK, MonsterResistanceType::HURT_FIRE },
100 { TR_BRAND_COLD, RFR_EFF_IM_COLD_MASK, MonsterResistanceType::HURT_COLD },
101 { TR_BRAND_POIS, RFR_EFF_IM_POISON_MASK, MonsterResistanceType::MAX },
104 auto *r_ptr = &monraces_info[m_ptr->r_idx];
105 for (size_t i = 0; i < sizeof(brand_table) / sizeof(brand_table[0]); ++i) {
106 const struct brand_table_t *p = &brand_table[i];
108 if (flags.has_not(p->brand_flag)) {
112 /* Notice immunity */
113 if (r_ptr->resistance_flags.has_any_of(p->resist_mask)) {
114 if (is_original_ap_and_seen(player_ptr, m_ptr)) {
115 r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & p->resist_mask);
121 /* Otherwise, take the damage */
122 if (r_ptr->resistance_flags.has(p->hurt_flag)) {
123 if (is_original_ap_and_seen(player_ptr, m_ptr)) {
124 r_ptr->r_resistance_flags.set(p->hurt_flag);
127 mult = std::max<short>(mult, 50);
131 mult = std::max<short>(mult, 25);
138 * @brief ダメージにスレイ要素を加える総合処理ルーチン /
139 * Extract the "total damage" from a given object hitting a given monster.
140 * @param o_ptr 使用武器オブジェクトの構造体参照ポインタ
141 * @param tdam 現在算出途中のダメージ値
142 * @param m_ptr 目標モンスターの構造体参照ポインタ
144 * @param thrown 投擲処理ならばTRUEを指定する
145 * @return 総合的なスレイを加味したダメージ値
147 * Note that "flasks of oil" do NOT do fire damage, although they\n
148 * certainly could be made to do so. XXX XXX\n
150 * Note that most brands and slays are x3, except Slay Animal (x2),\n
151 * Slay Evil (x2), and Kill dragon (x5).\n
153 int calc_attack_damage_with_slay(PlayerType *player_ptr, ItemEntity *o_ptr, int tdam, MonsterEntity *m_ptr, combat_options mode, bool thrown)
155 auto flags = object_flags(o_ptr);
156 torch_flags(o_ptr, flags); /* torches has secret flags */
159 if (player_ptr->special_attack & (ATTACK_ACID)) {
160 flags.set(TR_BRAND_ACID);
162 if (player_ptr->special_attack & (ATTACK_COLD)) {
163 flags.set(TR_BRAND_COLD);
165 if (player_ptr->special_attack & (ATTACK_ELEC)) {
166 flags.set(TR_BRAND_ELEC);
168 if (player_ptr->special_attack & (ATTACK_FIRE)) {
169 flags.set(TR_BRAND_FIRE);
171 if (player_ptr->special_attack & (ATTACK_POIS)) {
172 flags.set(TR_BRAND_POIS);
176 if (SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD)) {
177 flags.set(TR_SLAY_GOOD);
181 switch (o_ptr->bi_key.tval()) {
182 case ItemKindType::SHOT:
183 case ItemKindType::ARROW:
184 case ItemKindType::BOLT:
185 case ItemKindType::HAFTED:
186 case ItemKindType::POLEARM:
187 case ItemKindType::SWORD:
188 case ItemKindType::DIGGING:
189 case ItemKindType::LITE: {
190 mult = mult_slaying(player_ptr, mult, flags, m_ptr);
192 mult = mult_brand(player_ptr, mult, flags, m_ptr);
194 PlayerClass pc(player_ptr);
195 if (pc.equals(PlayerClassType::SAMURAI)) {
196 mult = mult_hissatsu(player_ptr, mult, flags, m_ptr, mode);
199 if (!pc.equals(PlayerClassType::SAMURAI) && (flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
200 player_ptr->csp -= (1 + (o_ptr->dd * o_ptr->ds / 5));
201 player_ptr->redraw |= (PR_MP);
202 mult = mult * 3 / 2 + 20;
205 if ((o_ptr->is_specific_artifact(FixedArtifactId::NOTHUNG)) && (m_ptr->r_idx == MonsterRaceId::FAFNER)) {
218 return tdam * mult / 10;
221 AttributeFlags melee_attribute(PlayerType *player_ptr, ItemEntity *o_ptr, combat_options mode)
223 AttributeFlags attribute_flags{};
224 attribute_flags.set(AttributeType::PLAYER_MELEE);
226 if (PlayerClass(player_ptr).equals(PlayerClassType::SAMURAI)) {
227 static const struct samurai_convert_table_t {
228 combat_options hissatsu_type;
229 AttributeType attribute;
230 } samurai_convert_table[] = {
231 { HISSATSU_FIRE, AttributeType::FIRE },
232 { HISSATSU_COLD, AttributeType::COLD },
233 { HISSATSU_ELEC, AttributeType::ELEC },
234 { HISSATSU_POISON, AttributeType::POIS },
235 { HISSATSU_HAGAN, AttributeType::KILL_WALL },
238 for (size_t i = 0; i < sizeof(samurai_convert_table) / sizeof(samurai_convert_table[0]); ++i) {
239 const struct samurai_convert_table_t *p = &samurai_convert_table[i];
241 if (mode == p->hissatsu_type) {
242 attribute_flags.set(p->attribute);
247 auto flags = object_flags(o_ptr);
249 if (player_ptr->special_attack & (ATTACK_ACID)) {
250 flags.set(TR_BRAND_ACID);
252 if (player_ptr->special_attack & (ATTACK_COLD)) {
253 flags.set(TR_BRAND_COLD);
255 if (player_ptr->special_attack & (ATTACK_ELEC)) {
256 flags.set(TR_BRAND_ELEC);
258 if (player_ptr->special_attack & (ATTACK_FIRE)) {
259 flags.set(TR_BRAND_FIRE);
261 if (player_ptr->special_attack & (ATTACK_POIS)) {
262 flags.set(TR_BRAND_POIS);
265 if (SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD)) {
266 flags.set(TR_SLAY_GOOD);
269 static const struct brand_convert_table_t {
271 AttributeType attribute;
272 } brand_convert_table[] = {
273 { TR_BRAND_ACID, AttributeType::ACID },
274 { TR_BRAND_FIRE, AttributeType::FIRE },
275 { TR_BRAND_ELEC, AttributeType::ELEC },
276 { TR_BRAND_COLD, AttributeType::COLD },
277 { TR_BRAND_POIS, AttributeType::POIS },
278 { TR_SLAY_GOOD, AttributeType::HELL_FIRE },
279 { TR_KILL_GOOD, AttributeType::HELL_FIRE },
280 { TR_SLAY_EVIL, AttributeType::HOLY_FIRE },
281 { TR_KILL_EVIL, AttributeType::HOLY_FIRE },
284 for (size_t i = 0; i < sizeof(brand_convert_table) / sizeof(brand_convert_table[0]); ++i) {
285 const struct brand_convert_table_t *p = &brand_convert_table[i];
287 if (flags.has(p->brand_type)) {
288 attribute_flags.set(p->attribute);
292 if ((flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
293 attribute_flags.set(AttributeType::MANA);
296 return attribute_flags;