OSDN Git Service

[Refactor] #37353 コメント整理 / Refactor comments.
[hengband/hengband.git] / src / hissatsu.c
1 /*!
2  * @file hissatsu.c
3  * @brief 剣術の実装 / Blade arts
4  * @date 2014/01/17
5  * @author
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
7  * This software may be copied and distributed for educational, research,\n
8  * and not for profit purposes provided that this copyright and statement\n
9  * are included in all such copies.  Other copyrights may also apply.\n
10  * 2014 Deskull rearranged comment for Doxygen.\n
11  */
12
13 #include "angband.h"
14
15 #define TECHNIC_HISSATSU (REALM_HISSATSU - MIN_TECHNIC)
16
17
18 /*!
19  * @brief 使用可能な剣術を選択する /
20  * Allow user to choose a blade arts.
21  * @param sn 選択した特殊技能ID、キャンセルの場合-1、不正な選択の場合-2を返す
22  * @return 発動可能な魔法を選択した場合TRUE、キャンセル処理か不正な選択が行われた場合FALSEを返す。
23  * @details
24  * If a valid spell is chosen, saves it in '*sn' and returns TRUE\n
25  * If the user hits escape, returns FALSE, and set '*sn' to -1\n
26  * If there are no legal choices, returns FALSE, and sets '*sn' to -2\n
27  *\n
28  * The "prompt" should be "cast", "recite", or "study"\n
29  * The "known" should be TRUE for cast/pray, FALSE for study\n
30  *\n
31  * nb: This function has a (trivial) display bug which will be obvious\n
32  * when you run it. It's probably easy to fix but I haven't tried,\n
33  * sorry.\n
34  */
35 static int get_hissatsu_power(SPELL_IDX *sn)
36 {
37         SPELL_IDX i;
38         int j = 0;
39         int num = 0;
40         POSITION y = 1;
41         POSITION x = 15;
42         PLAYER_LEVEL plev = p_ptr->lev;
43         int ask = TRUE;
44         char choice;
45         char out_val[160];
46         SPELL_IDX sentaku[32];
47         cptr p = _("必殺剣", "special attack");
48         COMMAND_CODE code;
49         magic_type spell;
50         bool flag, redraw;
51         int menu_line = (use_menu ? 1 : 0);
52
53         /* Assume cancelled */
54         *sn = (-1);
55
56         /* Get the spell, if available */
57         if (repeat_pull(&code))
58         {
59                 *sn = (SPELL_IDX)code;
60                 /* Verify the spell */
61                 if (technic_info[TECHNIC_HISSATSU][*sn].slevel <= plev)
62                 {
63                         /* Success */
64                         return (TRUE);
65                 }
66         }
67
68         /* Nothing chosen yet */
69         flag = FALSE;
70
71         /* No redraw yet */
72         redraw = FALSE;
73
74         for (i = 0; i < 32; i++)
75         {
76                 if (technic_info[TECHNIC_HISSATSU][i].slevel <= PY_MAX_LEVEL)
77                 {
78                         sentaku[num] = i;
79                         num++;
80                 }
81         }
82
83         /* Build a prompt (accept all spells) */
84         (void) strnfmt(out_val, 78, 
85                        _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
86                        p, I2A(0), "abcdefghijklmnopqrstuvwxyz012345"[num-1], p);
87
88         if (use_menu) screen_save();
89
90         /* Get a spell from the user */
91
92         choice= always_show_list ? ESCAPE:1 ;
93         while (!flag)
94         {
95                 if(choice==ESCAPE) choice = ' '; 
96                 else if( !get_com(out_val, &choice, FALSE) )break;
97
98                 if (use_menu && choice != ' ')
99                 {
100                         switch(choice)
101                         {
102                                 case '0':
103                                 {
104                                         screen_load();
105                                         return (FALSE);
106                                 }
107
108                                 case '8':
109                                 case 'k':
110                                 case 'K':
111                                 {
112                                         do
113                                         {
114                                                 menu_line += 31;
115                                                 if (menu_line > 32) menu_line -= 32;
116                                         } while(!(p_ptr->spell_learned1 & (1L << (menu_line-1))));
117                                         break;
118                                 }
119
120                                 case '2':
121                                 case 'j':
122                                 case 'J':
123                                 {
124                                         do
125                                         {
126                                                 menu_line++;
127                                                 if (menu_line > 32) menu_line -= 32;
128                                         } while(!(p_ptr->spell_learned1 & (1L << (menu_line-1))));
129                                         break;
130                                 }
131
132                                 case '4':
133                                 case 'h':
134                                 case 'H':
135                                 case '6':
136                                 case 'l':
137                                 case 'L':
138                                 {
139                                         bool reverse = FALSE;
140                                         if ((choice == '4') || (choice == 'h') || (choice == 'H')) reverse = TRUE;
141                                         if (menu_line > 16)
142                                         {
143                                                 menu_line -= 16;
144                                                 reverse = TRUE;
145                                         }
146                                         else menu_line+=16;
147                                         while(!(p_ptr->spell_learned1 & (1L << (menu_line-1))))
148                                         {
149                                                 if (reverse)
150                                                 {
151                                                         menu_line--;
152                                                         if (menu_line < 2) reverse = FALSE;
153                                                 }
154                                                 else
155                                                 {
156                                                         menu_line++;
157                                                         if (menu_line > 31) reverse = TRUE;
158                                                 }
159                                         }
160                                         break;
161                                 }
162
163                                 case 'x':
164                                 case 'X':
165                                 case '\r':
166                                 case '\n':
167                                 {
168                                         i = menu_line - 1;
169                                         ask = FALSE;
170                                         break;
171                                 }
172                         }
173                 }
174                 /* Request redraw */
175                 if ((choice == ' ') || (choice == '*') || (choice == '?') || (use_menu && ask))
176                 {
177                         /* Show the list */
178                         if (!redraw || use_menu)
179                         {
180                                 char psi_desc[80];
181                                 int line;
182
183                                 /* Show list */
184                                 redraw = TRUE;
185
186                                 /* Save the screen */
187                                 if (!use_menu) screen_save();
188
189                                 /* Display a list of spells */
190                                 prt("", y, x);
191                                 put_str(_("名前              Lv  MP      名前              Lv  MP ", 
192                                                   "name              Lv  SP      name              Lv  SP "), y, x + 5);
193                                 prt("", y+1, x);
194                                 /* Dump the spells */
195                                 for (i = 0, line = 0; i < 32; i++)
196                                 {
197                                         spell = technic_info[TECHNIC_HISSATSU][i];
198
199                                         if (spell.slevel > PY_MAX_LEVEL) continue;
200                                         line++;
201                                         if (!(p_ptr->spell_learned1 >> i)) break;
202
203                                         /* Access the spell */
204                                         if (spell.slevel > plev)   continue;
205                                         if (!(p_ptr->spell_learned1 & (1L << i))) continue;
206                                         if (use_menu)
207                                         {
208                                                 if (i == (menu_line-1))
209                                                         strcpy(psi_desc, _("  》", "  > "));
210                                                 else strcpy(psi_desc, "    ");
211                                                 
212                                         }
213                                         else
214                                         {
215                                                 char letter;
216                                                 if (line <= 26)
217                                                         letter = I2A(line-1);
218                                                 else
219                                                         letter = '0' + line - 27;
220                                                 sprintf(psi_desc, "  %c)",letter);
221                                         }
222
223                                         /* Dump the spell --(-- */
224                                         strcat(psi_desc, format(" %-18s%2d %3d",
225                                                 do_spell(REALM_HISSATSU, i, SPELL_NAME),
226                                                 spell.slevel, spell.smana));
227                                         prt(psi_desc, y + (line%17) + (line >= 17), x+(line/17)*30);
228                                         prt("", y + (line%17) + (line >= 17) + 1, x+(line/17)*30);
229                                 }
230                         }
231
232                         /* Hide the list */
233                         else
234                         {
235                                 /* Hide list */
236                                 redraw = FALSE;
237
238                                 /* Restore the screen */
239                                 screen_load();
240                         }
241
242                         /* Redo asking */
243                         continue;
244                 }
245
246                 if (!use_menu)
247                 {
248                         if (isalpha(choice))
249                         {
250                                 /* Note verify */
251                                 ask = (isupper(choice));
252
253                                 /* Lowercase */
254                                 if (ask) choice = (char)tolower(choice);
255
256                                 /* Extract request */
257                                 i = (islower(choice) ? A2I(choice) : -1);
258                         }
259                         else
260                         {
261                                 ask = FALSE; /* Can't uppercase digits */
262
263                                 i = choice - '0' + 26;
264                         }
265                 }
266
267                 /* Totally Illegal */
268                 if ((i < 0) || (i >= 32) || !(p_ptr->spell_learned1 & (1 << sentaku[i])))
269                 {
270                         bell();
271                         continue;
272                 }
273
274                 j = sentaku[i];
275
276                 /* Verify it */
277                 if (ask)
278                 {
279                         char tmp_val[160];
280
281                         /* Prompt */
282                         (void) strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), do_spell(REALM_HISSATSU, j, SPELL_NAME));
283
284                         /* Belay that order */
285                         if (!get_check(tmp_val)) continue;
286                 }
287
288                 /* Stop the loop */
289                 flag = TRUE;
290         }
291
292         /* Restore the screen */
293         if (redraw) screen_load();
294
295         /* Show choices */
296         p_ptr->window |= (PW_SPELL);
297
298         window_stuff();
299
300
301         /* Abort if needed */
302         if (!flag) return (FALSE);
303
304         /* Save the choice */
305         (*sn) = j;
306
307         repeat_push((COMMAND_CODE)j);
308
309         /* Success */
310         return (TRUE);
311 }
312
313
314 /*!
315  * @brief 剣術コマンドのメインルーチン
316  * @return なし
317  */
318 void do_cmd_hissatsu(void)
319 {
320         SPELL_IDX       n = 0;
321         magic_type      spell;
322
323         /* not if confused */
324         if (p_ptr->confused)
325         {
326                 msg_print(_("混乱していて集中できない!", "You are too confused!"));
327                 return;
328         }
329         if (!buki_motteruka(INVEN_RARM) && !buki_motteruka(INVEN_LARM))
330         {
331                 if (flush_failure) flush();
332                 msg_print(_("武器を持たないと必殺技は使えない!", "You need to wield a weapon!"));
333                 return;
334         }
335         if (!p_ptr->spell_learned1)
336         {
337                 msg_print(_("何も技を知らない。", "You don't know any special attacks."));
338                 return;
339         }
340
341         if (p_ptr->special_defense & KATA_MASK)
342         {
343                 set_action(ACTION_NONE);
344         }
345
346         /* get power */
347         if (!get_hissatsu_power(&n)) return;
348
349         spell = technic_info[TECHNIC_HISSATSU][n];
350
351         /* Verify "dangerous" spells */
352         if (spell.smana > p_ptr->csp)
353         {
354                 if (flush_failure) flush();
355                 /* Warning */
356                 msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
357                 msg_print(NULL);
358                 return;
359         }
360
361         sound(SOUND_ZAP);
362
363         /* Cast the spell */
364         if (!do_spell(REALM_HISSATSU, n, SPELL_CAST)) return;
365
366         p_ptr->energy_use = 100;
367
368         /* Use some mana */
369         p_ptr->csp -= spell.smana;
370
371         /* Limit */
372         if (p_ptr->csp < 0) p_ptr->csp = 0;
373
374         /* Redraw mana */
375         p_ptr->redraw |= (PR_MANA);
376
377         p_ptr->window |= (PW_PLAYER);
378         p_ptr->window |= (PW_SPELL);
379 }
380
381
382 /*!
383  * @brief 剣術コマンドの学習
384  * @return なし
385  */
386 void do_cmd_gain_hissatsu(void)
387 {
388         OBJECT_IDX item;
389         int i, j;
390
391         object_type *o_ptr;
392         cptr q, s;
393
394         bool gain = FALSE;
395
396         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))
397         {
398                 set_action(ACTION_NONE);
399         }
400
401         if (p_ptr->blind || no_lite())
402         {
403                 msg_print(_("目が見えない!", "You cannot see!"));
404                 return;
405         }
406
407         if (p_ptr->confused)
408         {
409                 msg_print(_("混乱していて読めない!", "You are too confused!"));
410                 return;
411         }
412
413         if (!(p_ptr->new_spells))
414         {
415                 msg_print(_("新しい必殺技を覚えることはできない!", "You cannot learn any new special attacks!"));
416                 return;
417         }
418
419 #ifdef JP
420         if( p_ptr->new_spells < 10 ){
421                 msg_format("あと %d つの必殺技を学べる。", p_ptr->new_spells);
422         }else{
423                 msg_format("あと %d 個の必殺技を学べる。", p_ptr->new_spells);
424         }
425 #else
426         msg_format("You can learn %d new special attack%s.", p_ptr->new_spells,
427                 (p_ptr->new_spells == 1?"":"s"));
428 #endif
429
430         item_tester_tval = TV_HISSATSU_BOOK;
431
432         q = _("どの書から学びますか? ", "Study which book? ");
433         s = _("読める書がない。", "You have no books that you can read.");
434
435         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
436
437         /* Get the item (in the pack) */
438         if (item >= 0)
439         {
440                 o_ptr = &inventory[item];
441         }
442
443         /* Get the item (on the floor) */
444         else
445         {
446                 o_ptr = &o_list[0 - item];
447         }
448
449         for (i = o_ptr->sval * 8; i < o_ptr->sval * 8 + 8; i++)
450         {
451                 if (p_ptr->spell_learned1 & (1L << i)) continue;
452                 if (technic_info[TECHNIC_HISSATSU][i].slevel > p_ptr->lev) continue;
453
454                 p_ptr->spell_learned1 |= (1L << i);
455                 p_ptr->spell_worked1 |= (1L << i);
456                 msg_format(_("%sの技を覚えた。", "You have learned the special attack of %s."), do_spell(REALM_HISSATSU, i, SPELL_NAME));
457                 for (j = 0; j < 64; j++)
458                 {
459                         /* Stop at the first empty space */
460                         if (p_ptr->spell_order[j] == 99) break;
461                 }
462                 p_ptr->spell_order[j] = i;
463                 gain = TRUE;
464         }
465
466         /* No gain ... */
467         if (!gain)
468                 msg_print(_("何も覚えられなかった。", "You were not able to learn any special attacks."));
469
470         else
471                 p_ptr->energy_use = 100;
472
473         p_ptr->update |= (PU_SPELLS);
474 }
475
476
477 /*!
478  * @brief 剣術のスレイ倍率計算を行う /
479  * Calcurate magnification of hissatsu technics
480  * @param mult 剣術のスレイ効果以前に算出している多要素の倍率(/10倍)
481  * @param flgs 剣術に使用する武器のスレイフラグ配列
482  * @param m_ptr 目標となるモンスターの構造体参照ポインタ
483  * @param mode 剣術のスレイ型ID
484  * @return スレイの倍率(/10倍)
485  */
486 MULTIPLY mult_hissatsu(MULTIPLY mult, BIT_FLAGS *flgs, monster_type *m_ptr, BIT_FLAGS mode)
487 {
488         monster_race *r_ptr = &r_info[m_ptr->r_idx];
489
490         /* Burning Strike (Fire) */
491         if (mode == HISSATSU_FIRE)
492         {
493                 /* Notice immunity */
494                 if (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK)
495                 {
496                         if (is_original_ap_and_seen(m_ptr))
497                         {
498                                 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK);
499                         }
500                 }
501
502                 /* Otherwise, take the damage */
503                 else if (have_flag(flgs, TR_BRAND_FIRE))
504                 {
505                         if (r_ptr->flags3 & RF3_HURT_FIRE)
506                         {
507                                 if (mult < 70) mult = 70;
508                                 if (is_original_ap_and_seen(m_ptr))
509                                 {
510                                         r_ptr->r_flags3 |= RF3_HURT_FIRE;
511                                 }
512                         }
513                         else if (mult < 35) mult = 35;
514                 }
515                 else
516                 {
517                         if (r_ptr->flags3 & RF3_HURT_FIRE)
518                         {
519                                 if (mult < 50) mult = 50;
520                                 if (is_original_ap_and_seen(m_ptr))
521                                 {
522                                         r_ptr->r_flags3 |= RF3_HURT_FIRE;
523                                 }
524                         }
525                         else if (mult < 25) mult = 25;
526                 }
527         }
528
529         /* Serpent's Tongue (Poison) */
530         if (mode == HISSATSU_POISON)
531         {
532                 /* Notice immunity */
533                 if (r_ptr->flagsr & RFR_EFF_IM_POIS_MASK)
534                 {
535                         if (is_original_ap_and_seen(m_ptr))
536                         {
537                                 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_POIS_MASK);
538                         }
539                 }
540
541                 /* Otherwise, take the damage */
542                 else if (have_flag(flgs, TR_BRAND_POIS))
543                 {
544                         if (mult < 35) mult = 35;
545                 }
546                 else
547                 {
548                         if (mult < 25) mult = 25;
549                 }
550         }
551
552         /* Zammaken (Nonliving Evil) */
553         if (mode == HISSATSU_ZANMA)
554         {
555                 if (!monster_living(r_ptr) && (r_ptr->flags3 & RF3_EVIL))
556                 {
557                         if (mult < 15) mult = 25;
558                         else if (mult < 50) mult = MIN(50, mult+20);
559                 }
560         }
561
562         /* Rock Smash (Hurt Rock) */
563         if (mode == HISSATSU_HAGAN)
564         {
565                 if (r_ptr->flags3 & RF3_HURT_ROCK)
566                 {
567                         if (is_original_ap_and_seen(m_ptr))
568                         {
569                                 r_ptr->r_flags3 |= RF3_HURT_ROCK;
570                         }
571                         if (mult == 10) mult = 40;
572                         else if (mult < 60) mult = 60;
573                 }
574         }
575
576         /* Midare-Setsugekka (Cold) */
577         if (mode == HISSATSU_COLD)
578         {
579                 /* Notice immunity */
580                 if (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK)
581                 {
582                         if (is_original_ap_and_seen(m_ptr))
583                         {
584                                 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK);
585                         }
586                 }
587                 /* Otherwise, take the damage */
588                 else if (have_flag(flgs, TR_BRAND_COLD))
589                 {
590                         if (r_ptr->flags3 & RF3_HURT_COLD)
591                         {
592                                 if (mult < 70) mult = 70;
593                                 if (is_original_ap_and_seen(m_ptr))
594                                 {
595                                         r_ptr->r_flags3 |= RF3_HURT_COLD;
596                                 }
597                         }
598                         else if (mult < 35) mult = 35;
599                 }
600                 else
601                 {
602                         if (r_ptr->flags3 & RF3_HURT_COLD)
603                         {
604                                 if (mult < 50) mult = 50;
605                                 if (is_original_ap_and_seen(m_ptr))
606                                 {
607                                         r_ptr->r_flags3 |= RF3_HURT_COLD;
608                                 }
609                         }
610                         else if (mult < 25) mult = 25;
611                 }
612         }
613
614         /* Lightning Eagle (Elec) */
615         if (mode == HISSATSU_ELEC)
616         {
617                 /* Notice immunity */
618                 if (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK)
619                 {
620                         if (is_original_ap_and_seen(m_ptr))
621                         {
622                                 r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK);
623                         }
624                 }
625
626                 /* Otherwise, take the damage */
627                 else if (have_flag(flgs, TR_BRAND_ELEC))
628                 {
629                         if (mult < 70) mult = 70;
630                 }
631                 else
632                 {
633                         if (mult < 50) mult = 50;
634                 }
635         }
636
637         /* Bloody Maelstrom */
638         if ((mode == HISSATSU_SEKIRYUKA) && p_ptr->cut && monster_living(r_ptr))
639         {
640                 MULTIPLY tmp = MIN(100, MAX(10, p_ptr->cut / 10));
641                 if (mult < tmp) mult = tmp;
642         }
643
644         /* Keiun-Kininken */
645         if (mode == HISSATSU_UNDEAD)
646         {
647                 if (r_ptr->flags3 & RF3_UNDEAD)
648                 {
649                         if (is_original_ap_and_seen(m_ptr))
650                         {
651                                 r_ptr->r_flags3 |= RF3_UNDEAD;
652                         }
653                         if (mult == 10) mult = 70;
654                         else if (mult < 140) mult = MIN(140, mult+60);
655                 }
656                 if (mult == 10) mult = 40;
657                 else if (mult < 60) mult = MIN(60, mult+30);
658         }
659
660         if (mult > 150) mult = 150;
661
662         return mult;
663 }