OSDN Git Service

Merge branch 'Release-3.0.0Alpha' into release/3.0.0Alpha
[hengband/hengband.git] / src / combat / attack-criticality.c
1 #include "combat/attack-criticality.h"
2 #include "combat/combat-options-type.h"
3 #include "inventory/inventory-slot-types.h"
4 #include "monster-race/monster-race.h"
5 #include "monster-race/race-flags1.h"
6 #include "monster-race/race-flags7.h"
7 #include "sv-definition/sv-weapon-types.h"
8 #include "view/display-messages.h"
9
10 /*!
11  * @brief プレイヤーからモンスターへの打撃クリティカル判定 /
12  * Critical hits (by player) Factor in weapon weight, total plusses, player melee bonus
13  * @param weight 矢弾の重量
14  * @param plus 武器の命中修正
15  * @param dam 現在算出中のダメージ値
16  * @param meichuu 打撃の基本命中力
17  * @param mode オプションフラグ
18  * @return クリティカル修正が入ったダメージ値
19  */
20 HIT_POINT critical_norm(player_type *attacker_ptr, WEIGHT weight, int plus, HIT_POINT dam, s16b meichuu, combat_options mode)
21 {
22     /* Extract "blow" power */
23     int i = (weight + (meichuu * 3 + plus * 5) + attacker_ptr->skill_thn);
24
25     /* Chance */
26     bool is_special_option = randint1((attacker_ptr->pclass == CLASS_NINJA) ? 4444 : 5000) <= i;
27     is_special_option |= mode == HISSATSU_MAJIN;
28     is_special_option |= mode == HISSATSU_3DAN;
29     if (!is_special_option)
30         return dam;
31
32     int k = weight + randint1(650);
33     if ((mode == HISSATSU_MAJIN) || (mode == HISSATSU_3DAN))
34         k += randint1(650);
35
36     if (k < 400) {
37         msg_print(_("手ごたえがあった!", "It was a good hit!"));
38
39         dam = 2 * dam + 5;
40         return dam;
41     }
42
43     if (k < 700) {
44         msg_print(_("かなりの手ごたえがあった!", "It was a great hit!"));
45         dam = 2 * dam + 10;
46         return dam;
47     }
48
49     if (k < 900) {
50         msg_print(_("会心の一撃だ!", "It was a superb hit!"));
51         dam = 3 * dam + 15;
52         return dam;
53     }
54
55     if (k < 1300) {
56         msg_print(_("最高の会心の一撃だ!", "It was a *GREAT* hit!"));
57         dam = 3 * dam + 20;
58         return dam;
59     }
60
61     msg_print(_("比類なき最高の会心の一撃だ!", "It was a *SUPERB* hit!"));
62     dam = ((7 * dam) / 2) + 25;
63     return dam;
64 }
65
66 /*!
67  * @brief モンスター打撃のクリティカルランクを返す /
68  * Critical blow. All hits that do 95% of total possible damage,
69  * @param dice モンスター打撃のダイス数
70  * @param sides モンスター打撃の最大ダイス目
71  * @param dam プレイヤーに与えたダメージ
72  * @details
73  * and which also do at least 20 damage, or, sometimes, N damage.
74  * This is used only to determine "cuts" and "stuns".
75  */
76 int calc_monster_critical(DICE_NUMBER dice, DICE_SID sides, HIT_POINT dam)
77 {
78     int total = dice * sides;
79     if (dam < total * 19 / 20)
80         return 0;
81
82     if ((dam < 20) && (randint0(100) >= dam))
83         return 0;
84
85     int max = 0;
86     if ((dam >= total) && (dam >= 40))
87         max++;
88
89     if (dam >= 20)
90         while (randint0(100) < 2)
91             max++;
92
93     if (dam > 45)
94         return (6 + max);
95
96     if (dam > 33)
97         return (5 + max);
98
99     if (dam > 25)
100         return (4 + max);
101
102     if (dam > 18)
103         return (3 + max);
104
105     if (dam > 11)
106         return (2 + max);
107
108     return (1 + max);
109 }
110
111 /*!
112  * todo 3つの処理をdetailsに書くよりは関数自体を分割すべきだが、一旦後回しにする。他の項目と一緒に処理する
113  * @brief 忍者ヒットで急所を突く
114  * @param attacker_ptr プレーヤーへの参照ポインタ
115  * @param pa_ptr 直接攻撃構造体への参照ポインタ
116  * @return なし
117  * @details 闇討ち&追討ちを実施した後に致命傷チェックを行う
118  * チェックを通ったら、ユニークならば2倍ダメージ、それ以外は一撃死
119  */
120 static void ninja_critical(player_type *attacker_ptr, player_attack_type *pa_ptr)
121 {
122     monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
123     int maxhp = pa_ptr->m_ptr->maxhp;
124     if (one_in_(pa_ptr->backstab ? 13 : (pa_ptr->stab_fleeing || pa_ptr->surprise_attack) ? 15 : 27)) {
125         pa_ptr->attack_damage *= 5;
126         pa_ptr->drain_result *= 2;
127         msg_format(_("刃が%sに深々と突き刺さった!", "You critically injured %s!"), pa_ptr->m_name);
128         return;
129     }
130
131
132     bool is_weaken = pa_ptr->m_ptr->hp < maxhp / 2;
133     bool is_unique = ((r_ptr->flags1 & RF1_UNIQUE) != 0) || ((r_ptr->flags7 & RF7_UNIQUE2) != 0);
134     bool is_critical = (is_weaken && one_in_((attacker_ptr->num_blow[0] + attacker_ptr->num_blow[1] + 1) * 10))
135         || ((one_in_(666) || ((pa_ptr->backstab || pa_ptr->surprise_attack) && one_in_(11))) && !(is_unique));
136     if (!is_critical)
137         return;
138
139     if (is_unique || !is_weaken) {
140         pa_ptr->attack_damage = MAX(pa_ptr->attack_damage * 5, pa_ptr->m_ptr->hp / 2);
141         pa_ptr->drain_result *= 2;
142         msg_format(_("%sに致命傷を負わせた!", "You fatally injured %s!"), pa_ptr->m_name);
143     } else {
144         pa_ptr->attack_damage = pa_ptr->m_ptr->hp + 1;
145         msg_format(_("刃が%sの急所を貫いた!", "You hit %s on a fatal spot!"), pa_ptr->m_name);
146     }
147 }
148
149 /*!
150  * @brief 急所を突く
151  * @param attacker_ptr プレーヤーへの参照ポインタ
152  * @param pa_ptr 直接攻撃構造体への参照ポインタ
153  * @return なし
154  */
155 void critical_attack(player_type *attacker_ptr, player_attack_type *pa_ptr)
156 {
157     object_type *o_ptr = &attacker_ptr->inventory_list[INVEN_RARM + pa_ptr->hand];
158     monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
159     if (((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE)) || (pa_ptr->mode == HISSATSU_KYUSHO)) {
160         if ((randint1(randint1(r_ptr->level / 7) + 5) == 1) && !(r_ptr->flags1 & RF1_UNIQUE) && !(r_ptr->flags7 & RF7_UNIQUE2)) {
161             pa_ptr->attack_damage = pa_ptr->m_ptr->hp + 1;
162             msg_format(_("%sの急所を突き刺した!", "You hit %s on a fatal spot!"), pa_ptr->m_name);
163         } else
164             pa_ptr->attack_damage = 1;
165
166         return;
167     }
168
169     bool is_ninja_hit = (attacker_ptr->pclass == CLASS_NINJA) && has_melee_weapon(attacker_ptr, INVEN_RARM + pa_ptr->hand)
170         && !attacker_ptr->icky_wield[pa_ptr->hand] && ((attacker_ptr->cur_lite <= 0) || one_in_(7));
171     if (is_ninja_hit)
172         ninja_critical(attacker_ptr, pa_ptr);
173 }