OSDN Git Service

[Refactor] #38844 Continued removing inclusion of monster-race.h in angband.h
[hengband/hengband.git] / src / spell-realm / spells-hex.c
1 #include "spell-realm/spells-hex.h"
2 #include "core/asking-player.h"
3 #include "floor/floor.h"
4 #include "monster-race/monster-race.h"
5 #include "player/player-effects.h" // todo 相互参照している.
6 #include "player/player-skill.h"
7 #include "realm/realm-hex-numbers.h"
8 #include "spell/spells3.h"
9 #include "spell/spells-execution.h"
10 #include "term/screen-processor.h"
11 #include "util/int-char-converter.h"
12 #include "view/display-messages.h"
13
14 #define MAX_KEEP 4 /*!<呪術の最大詠唱数 */
15
16 /*!
17  * @brief プレイヤーが詠唱中の全呪術を停止する
18  * @return なし
19  */
20 bool stop_hex_spell_all(player_type *caster_ptr)
21 {
22     SPELL_IDX i;
23
24     for (i = 0; i < 32; i++) {
25         if (hex_spelling(caster_ptr, i))
26             exe_spell(caster_ptr, REALM_HEX, i, SPELL_STOP);
27     }
28
29     casting_hex_flags(caster_ptr) = 0;
30     casting_hex_num(caster_ptr) = 0;
31
32     if (caster_ptr->action == ACTION_SPELL)
33         set_action(caster_ptr, ACTION_NONE);
34
35     caster_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS);
36     caster_ptr->redraw |= (PR_EXTRA | PR_HP | PR_MANA);
37
38     return TRUE;
39 }
40
41 /*!
42  * @brief プレイヤーが詠唱中の呪術から一つを選んで停止する
43  * @return なし
44  */
45 bool stop_hex_spell(player_type *caster_ptr)
46 {
47     int spell;
48     char choice = 0;
49     char out_val[160];
50     bool flag = FALSE;
51     TERM_LEN y = 1;
52     TERM_LEN x = 20;
53     int sp[MAX_KEEP];
54
55     if (!hex_spelling_any(caster_ptr)) {
56         msg_print(_("呪文を詠唱していません。", "You are casting no spell."));
57         return FALSE;
58     }
59
60     /* Stop all spells */
61     else if ((casting_hex_num(caster_ptr) == 1) || (caster_ptr->lev < 35)) {
62         return stop_hex_spell_all(caster_ptr);
63     } else {
64         strnfmt(out_val, 78, _("どの呪文の詠唱を中断しますか?(呪文 %c-%c, 'l'全て, ESC)", "Which spell do you stop casting? (Spell %c-%c, 'l' to all, ESC)"),
65             I2A(0), I2A(casting_hex_num(caster_ptr) - 1));
66
67         screen_save();
68
69         while (!flag) {
70             int n = 0;
71             Term_erase(x, y, 255);
72             prt(_("     名前", "     Name"), y, x + 5);
73             for (spell = 0; spell < 32; spell++) {
74                 if (hex_spelling(caster_ptr, spell)) {
75                     Term_erase(x, y + n + 1, 255);
76                     put_str(format("%c)  %s", I2A(n), exe_spell(caster_ptr, REALM_HEX, spell, SPELL_NAME)), y + n + 1, x + 2);
77                     sp[n++] = spell;
78                 }
79             }
80
81             if (!get_com(out_val, &choice, TRUE))
82                 break;
83             if (isupper(choice))
84                 choice = (char)tolower(choice);
85
86             if (choice == 'l') /* All */
87             {
88                 screen_load();
89                 return stop_hex_spell_all(caster_ptr);
90             }
91             if ((choice < I2A(0)) || (choice > I2A(casting_hex_num(caster_ptr) - 1)))
92                 continue;
93             flag = TRUE;
94         }
95     }
96
97     screen_load();
98
99     if (flag) {
100         int n = sp[A2I(choice)];
101
102         exe_spell(caster_ptr, REALM_HEX, n, SPELL_STOP);
103         casting_hex_flags(caster_ptr) &= ~(1L << n);
104         casting_hex_num(caster_ptr)--;
105     }
106
107     caster_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS);
108     caster_ptr->redraw |= (PR_EXTRA | PR_HP | PR_MANA);
109
110     return flag;
111 }
112
113 /*!
114  * @brief 一定時間毎に呪術で消費するMPを処理する /
115  * Upkeeping hex spells Called from dungeon.c
116  * @return なし
117  */
118 void check_hex(player_type *caster_ptr)
119 {
120     int spell;
121     MANA_POINT need_mana;
122     u32b need_mana_frac;
123     bool res = FALSE;
124
125     /* Spells spelled by player */
126     if (caster_ptr->realm1 != REALM_HEX)
127         return;
128     if (!casting_hex_flags(caster_ptr) && !caster_ptr->magic_num1[1])
129         return;
130
131     if (caster_ptr->magic_num1[1]) {
132         caster_ptr->magic_num1[0] = caster_ptr->magic_num1[1];
133         caster_ptr->magic_num1[1] = 0;
134         res = TRUE;
135     }
136
137     /* Stop all spells when anti-magic ability is given */
138     if (caster_ptr->anti_magic) {
139         stop_hex_spell_all(caster_ptr);
140         return;
141     }
142
143     need_mana = 0;
144     for (spell = 0; spell < 32; spell++) {
145         if (hex_spelling(caster_ptr, spell)) {
146             const magic_type *s_ptr;
147             s_ptr = &technic_info[REALM_HEX - MIN_TECHNIC][spell];
148             need_mana += mod_need_mana(caster_ptr, s_ptr->smana, spell, REALM_HEX);
149         }
150     }
151
152     /* Culcurates final mana cost */
153     need_mana_frac = 0;
154     s64b_div(&need_mana, &need_mana_frac, 0, 3); /* Divide by 3 */
155     need_mana += (casting_hex_num(caster_ptr) - 1);
156
157     /* Not enough mana */
158     if (s64b_cmp(caster_ptr->csp, caster_ptr->csp_frac, need_mana, need_mana_frac) < 0) {
159         stop_hex_spell_all(caster_ptr);
160         return;
161     }
162
163     /* Enough mana */
164     else {
165         s64b_sub(&(caster_ptr->csp), &(caster_ptr->csp_frac), need_mana, need_mana_frac);
166
167         caster_ptr->redraw |= PR_MANA;
168         if (res) {
169             msg_print(_("詠唱を再開した。", "You restart casting."));
170
171             caster_ptr->action = ACTION_SPELL;
172
173             caster_ptr->update |= (PU_BONUS | PU_HP);
174             caster_ptr->redraw |= (PR_MAP | PR_STATUS | PR_STATE);
175             caster_ptr->update |= (PU_MONSTERS);
176             caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
177         }
178     }
179
180     /* Gain experiences of spelling spells */
181     for (spell = 0; spell < 32; spell++) {
182         const magic_type *s_ptr;
183
184         if (!hex_spelling(caster_ptr, spell))
185             continue;
186
187         s_ptr = &technic_info[REALM_HEX - MIN_TECHNIC][spell];
188
189         if (caster_ptr->spell_exp[spell] < SPELL_EXP_BEGINNER)
190             caster_ptr->spell_exp[spell] += 5;
191         else if (caster_ptr->spell_exp[spell] < SPELL_EXP_SKILLED) {
192             if (one_in_(2) && (caster_ptr->current_floor_ptr->dun_level > 4) && ((caster_ptr->current_floor_ptr->dun_level + 10) > caster_ptr->lev))
193                 caster_ptr->spell_exp[spell] += 1;
194         } else if (caster_ptr->spell_exp[spell] < SPELL_EXP_EXPERT) {
195             if (one_in_(5) && ((caster_ptr->current_floor_ptr->dun_level + 5) > caster_ptr->lev)
196                 && ((caster_ptr->current_floor_ptr->dun_level + 5) > s_ptr->slevel))
197                 caster_ptr->spell_exp[spell] += 1;
198         } else if (caster_ptr->spell_exp[spell] < SPELL_EXP_MASTER) {
199             if (one_in_(5) && ((caster_ptr->current_floor_ptr->dun_level + 5) > caster_ptr->lev) && (caster_ptr->current_floor_ptr->dun_level > s_ptr->slevel))
200                 caster_ptr->spell_exp[spell] += 1;
201         }
202     }
203
204     /* Do any effects of continual spells */
205     for (spell = 0; spell < 32; spell++) {
206         if (hex_spelling(caster_ptr, spell)) {
207             exe_spell(caster_ptr, REALM_HEX, spell, SPELL_CONT);
208         }
209     }
210 }
211
212 /*!
213  * @brief プレイヤーの呪術詠唱枠がすでに最大かどうかを返す
214  * @return すでに全枠を利用しているならTRUEを返す
215  */
216 bool hex_spell_fully(player_type *caster_ptr)
217 {
218     int k_max = 0;
219     k_max = (caster_ptr->lev / 15) + 1;
220     k_max = MIN(k_max, MAX_KEEP);
221     if (casting_hex_num(caster_ptr) < k_max)
222         return FALSE;
223     return TRUE;
224 }
225
226 /*!
227  * @brief 一定ゲームターン毎に復讐処理の残り期間の判定を行う
228  * @return なし
229  */
230 void revenge_spell(player_type *caster_ptr)
231 {
232     if (caster_ptr->realm1 != REALM_HEX)
233         return;
234     if (hex_revenge_turn(caster_ptr) <= 0)
235         return;
236
237     switch (hex_revenge_type(caster_ptr)) {
238     case 1:
239         exe_spell(caster_ptr, REALM_HEX, HEX_PATIENCE, SPELL_CONT);
240         break;
241     case 2:
242         exe_spell(caster_ptr, REALM_HEX, HEX_REVENGE, SPELL_CONT);
243         break;
244     }
245 }
246
247 /*!
248  * @brief 復讐ダメージの追加を行う
249  * @param dam 蓄積されるダメージ量
250  * @return なし
251  */
252 void revenge_store(player_type *caster_ptr, HIT_POINT dam)
253 {
254     if (caster_ptr->realm1 != REALM_HEX)
255         return;
256     if (hex_revenge_turn(caster_ptr) <= 0)
257         return;
258
259     hex_revenge_power(caster_ptr) += dam;
260 }
261
262 /*!
263  * @brief 反テレポート結界の判定
264  * @param m_idx 判定の対象となるモンスターID
265  * @return 反テレポートの効果が適用されるならTRUEを返す
266  */
267 bool teleport_barrier(player_type *caster_ptr, MONSTER_IDX m_idx)
268 {
269     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
270     monster_race *r_ptr = &r_info[m_ptr->r_idx];
271
272     if (!hex_spelling(caster_ptr, HEX_ANTI_TELE))
273         return FALSE;
274     if ((caster_ptr->lev * 3 / 2) < randint1(r_ptr->level))
275         return FALSE;
276
277     return TRUE;
278 }
279
280 /*!
281  * @brief 反魔法結界の判定
282  * @param m_idx 判定の対象となるモンスターID
283  * @return 反魔法の効果が適用されるならTRUEを返す
284  */
285 bool magic_barrier(player_type *target_ptr, MONSTER_IDX m_idx)
286 {
287     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
288     monster_race *r_ptr = &r_info[m_ptr->r_idx];
289
290     if (!hex_spelling(target_ptr, HEX_ANTI_MAGIC))
291         return FALSE;
292     if ((target_ptr->lev * 3 / 2) < randint1(r_ptr->level))
293         return FALSE;
294
295     return TRUE;
296 }
297
298 /*!
299  * @brief 反増殖結界の判定
300  * @param m_idx 判定の対象となるモンスターID
301  * @return 反増殖の効果が適用されるならTRUEを返す
302  */
303 bool multiply_barrier(player_type *caster_ptr, MONSTER_IDX m_idx)
304 {
305     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
306     monster_race *r_ptr = &r_info[m_ptr->r_idx];
307
308     if (!hex_spelling(caster_ptr, HEX_ANTI_MULTI))
309         return FALSE;
310     if ((caster_ptr->lev * 3 / 2) < randint1(r_ptr->level))
311         return FALSE;
312
313     return TRUE;
314 }
315
316 bool hex_spelling(player_type *caster_ptr, int hex) { return (caster_ptr->realm1 == REALM_HEX) && (caster_ptr->magic_num1[0] & (1L << (hex))); }