OSDN Git Service

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