OSDN Git Service

[Refactor] #40413 Separated sound-of-music.c/h from util.c/h
[hengband/hengband.git] / src / combat / attack-accuracy.c
1 #include "combat/attack-accuracy.h"
2 #include "main/sound-definitions-table.h"
3 #include "main/sound-of-music.h"
4 #include "monster-race/race-flags-resistance.h"
5 #include "specific-object/death-scythe.h"
6 #include "sv-definition/sv-weapon-types.h"
7
8 /*!
9  * @brief プレイヤーからモンスターへの打撃命中判定 /
10  * Determine if the player "hits" a monster (normal combat).
11  * @param chance 基本命中値
12  * @param ac モンスターのAC
13  * @param visible 目標を視界に捕らえているならばTRUEを指定
14  * @return 命中と判定された場合TRUEを返す
15  * @note Always miss 5%, always hit 5%, otherwise random.
16  */
17 bool test_hit_norm(player_type *attacker_ptr, HIT_RELIABILITY chance, ARMOUR_CLASS ac, bool visible)
18 {
19     if (!visible)
20         chance = (chance + 1) / 2;
21     return hit_chance(attacker_ptr, chance, ac) >= randint1(100);
22 }
23
24 /*!
25  * @brief モンスターへの命中率の計算
26  * @param player_ptr プレーヤーへの参照ポインタ
27  * @param to_h 命中値
28  * @param ac 敵AC
29  * @return 命中確率
30  */
31 PERCENTAGE hit_chance(player_type *attacker_ptr, HIT_RELIABILITY reli, ARMOUR_CLASS ac)
32 {
33     PERCENTAGE chance = 5, chance_left = 90;
34     if (reli <= 0)
35         return 5;
36     if (attacker_ptr->pseikaku == PERSONALITY_LAZY)
37         chance_left = (chance_left * 19 + 9) / 20;
38     chance += (100 - ((ac * 75) / reli)) * chance_left / 100;
39     if (chance < 5)
40         chance = 5;
41     return chance;
42 }
43
44 /*!
45  * @brief モンスター打撃の命中を判定する /
46  * Determine if a monster attack against the player succeeds.
47  * @param power 打撃属性毎の基本命中値
48  * @param level モンスターのレベル
49  * @param stun モンスターの朦朧値
50  * @return TRUEならば命中判定
51  * @details
52  * Always miss 5% of the time, Always hit 5% of the time.
53  * Otherwise, match monster power against player armor.
54  */
55 int check_hit_from_monster_to_player(player_type *target_ptr, int power, DEPTH level, int stun)
56 {
57     int k = randint0(100);
58     if (stun && one_in_(2))
59         return FALSE;
60     if (k < 10)
61         return (k < 5);
62     int i = (power + (level * 3));
63
64     int ac = target_ptr->ac + target_ptr->to_a;
65     if (target_ptr->special_attack & ATTACK_SUIKEN)
66         ac += (target_ptr->lev * 2);
67
68     if ((i > 0) && (randint1(i) > ((ac * 3) / 4)))
69         return TRUE;
70     return FALSE;
71 }
72
73 /*!
74  * @brief モンスターから敵モンスターへの命中判定
75  * @param power 打撃属性による基本命中値
76  * @param level 攻撃側モンスターのレベル
77  * @param ac 目標モンスターのAC
78  * @param stun 攻撃側モンスターが朦朧状態ならTRUEを返す
79  * @return 命中ならばTRUEを返す
80  */
81 int check_hit_from_monster_to_monster(int power, DEPTH level, ARMOUR_CLASS ac, int stun)
82 {
83     int k = randint0(100);
84     if (stun && one_in_(2))
85         return FALSE;
86     if (k < 10)
87         return (k < 5);
88     int i = (power + (level * 3));
89
90     if ((i > 0) && (randint1(i) > ((ac * 3) / 4)))
91         return TRUE;
92     return FALSE;
93 }
94
95 /*!
96  * @brief 攻撃が当たるかどうかを判定する
97  * @param attacker_ptr プレーヤーへの参照ポインタ
98  * @param pa_ptr 直接攻撃構造体への参照ポインタ
99  * @param chance 基本命中値
100  * @return なし
101  */
102 static bool decide_attack_hit(player_type *attacker_ptr, player_attack_type *pa_ptr, int chance)
103 {
104     bool success_hit = FALSE;
105     object_type *o_ptr = &attacker_ptr->inventory_list[INVEN_RARM + pa_ptr->hand];
106     monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
107     if (((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE)) || (pa_ptr->mode == HISSATSU_KYUSHO)) {
108         int n = 1;
109
110         if (attacker_ptr->migite && attacker_ptr->hidarite)
111             n *= 2;
112
113         if (pa_ptr->mode == HISSATSU_3DAN)
114             n *= 2;
115
116         success_hit = one_in_(n);
117     } else if ((attacker_ptr->pclass == CLASS_NINJA) && ((pa_ptr->backstab || pa_ptr->surprise_attack) && !(r_ptr->flagsr & RFR_RES_ALL)))
118         success_hit = TRUE;
119     else
120         success_hit = test_hit_norm(attacker_ptr, chance, r_ptr->ac, pa_ptr->m_ptr->ml);
121
122     if ((pa_ptr->mode == HISSATSU_MAJIN) && one_in_(2))
123         success_hit = FALSE;
124
125     return success_hit;
126 }
127
128 /*!
129  * @brief 直接攻撃の命中を処理するメインルーチン
130  * @param attacker_ptr プレーヤーへの参照ポインタ
131  * @param pa_ptr 直接攻撃構造体への参照ポインタ
132  * @param chance 基本命中値
133  * @return 当たればTRUE、外れればFALSE
134  */
135 bool process_attack_hit(player_type *attacker_ptr, player_attack_type *pa_ptr, int chance)
136 {
137     object_type *o_ptr = &attacker_ptr->inventory_list[INVEN_RARM + pa_ptr->hand];
138     if (decide_attack_hit(attacker_ptr, pa_ptr, chance))
139         return TRUE;
140
141     pa_ptr->backstab = FALSE; /* Clumsy! */
142     pa_ptr->surprise_attack = FALSE; /* Clumsy! */
143
144     if ((o_ptr->tval == TV_POLEARM) && (o_ptr->sval == SV_DEATH_SCYTHE) && one_in_(3)) {
145         process_death_scythe_reflection(attacker_ptr, pa_ptr);
146     } else {
147         sound(SOUND_MISS);
148         msg_format(_("ミス! %sにかわされた。", "You miss %s."), pa_ptr->m_name);
149     }
150
151     return FALSE;
152 }