OSDN Git Service

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