2 * @brief スナイパー技能の実装 / Sniping
5 * 2014 Deskull rearranged comment for Doxygen.\n
8 #include "mind/mind-sniper.h"
9 #include "action/action-limited.h"
10 #include "cmd-action/cmd-shoot.h"
11 #include "core/asking-player.h"
12 #include "core/player-redraw-types.h"
13 #include "core/player-update-types.h"
14 #include "core/stuff-handler.h"
15 #include "core/window-redrawer.h"
16 #include "floor/geometry.h"
17 #include "game-option/text-display-options.h"
18 #include "grid/grid.h"
19 #include "inventory/inventory-slot-types.h"
20 #include "io/command-repeater.h"
21 #include "io/input-key-requester.h"
22 #include "main/sound-definitions-table.h"
23 #include "main/sound-of-music.h"
24 #include "mind/snipe-types.h"
25 #include "monster-race/race-flags-resistance.h"
26 #include "monster-race/race-flags3.h"
27 #include "monster-race/monster-race.h"
28 #include "player-status/player-energy.h"
29 #include "system/monster-race-definition.h"
30 #include "system/monster-type-definition.h"
31 #include "system/object-type-definition.h"
32 #include "system/player-type-definition.h"
33 #include "term/screen-processor.h"
34 #include "term/term-color-types.h"
35 #include "util/buffer-shaper.h"
36 #include "util/int-char-converter.h"
37 #include "view/display-messages.h"
39 #define MAX_SNIPE_POWERS 16
42 typedef struct snipe_power
49 /*! スナイパー技能の解説メッセージ */
50 static concptr const snipe_tips[MAX_SNIPE_POWERS] =
53 "精神を集中する。射撃の威力、精度が上がり、高度な射撃術が使用できるようになる。",
54 "光る矢を放つ。光に弱いモンスターに威力を発揮する。",
55 "射撃を行った後、短距離の瞬間移動を行う。",
56 "軌道上の罠をすべて無効にする低空飛行の矢を放つ。",
58 "壁を粉砕する矢を放つ。岩でできたモンスターと無生物のモンスターに威力を発揮する。",
62 "善良なモンスターに威力を発揮する矢を放つ。",
63 "邪悪なモンスターに威力を発揮する矢を放つ。",
67 "敵の急所にめがけて矢を放つ。成功すると敵を一撃死させる。失敗すると1ダメージ。",
68 "全てのモンスターに高威力を発揮する矢を放つ。反動による副次効果を受ける。",
70 "Concentrate your mind for shooting.",
71 "Shoot a glowing arrow effective against light-sensitive foes.",
72 "Blink after shooting.",
73 "Shoot an arrow able to shatter traps.",
74 "Deals extra damage of fire.",
75 "Shoot an arrow able to shatter rocks.",
76 "Deals extra damage of ice.",
77 "Shoot an arrow that pushes away the target.",
78 "Shoot an arrow that does not always stop at the first target on its path."
79 "Deals more damage to good monsters.",
80 "Deals more damage to evil monsters.",
81 "Shoot an arrow that explodes when it hits a monster.",
82 "Shoot two arrows at once.",
83 "Deals extra damage of lightning.",
84 "Deals quick death or 1 damage.",
85 "Deals great damage to all monsters, and some side effects to you.",
90 static snipe_power const snipe_powers[MAX_SNIPE_POWERS] =
92 /* Level gained, cost, name */
96 { 3, 1, "シュート&アウェイ" },
106 { 32, 4, "ダブルショット" },
107 { 36, 3, "プラズマボルト" },
108 { 40, 3, "ニードルショット" },
109 { 48, 7, "セイントスターアロー" },
111 { 1, 0, "Concentration" },
112 { 2, 1, "Flash Arrow" },
113 { 3, 1, "Shoot & Away" },
114 { 5, 1, "Disarm Shot" },
115 { 8, 2, "Fire Shot" },
116 { 10, 2, "Shatter Arrow" },
117 { 13, 2, "Ice Shot" },
118 { 18, 2, "Rushing Arrow"},
119 { 22, 3, "Piercing Shot" },
120 { 25, 4, "Evil Shot"},
121 { 26, 4, "Holy Shot" },
123 { 32, 4, "Double Shot" },
124 { 36, 3, "Plasma Bolt" },
125 { 40, 3, "Needle Shot" },
126 { 48, 7, "Saint Stars Arrow" },
134 static bool snipe_concentrate(player_type *creature_ptr)
136 if ((int)creature_ptr->concent < (2 + (creature_ptr->lev + 5) / 10)) creature_ptr->concent++;
138 msg_format(_("集中した。(集中度 %d)", "You concentrate deeply. (lvl %d)"), creature_ptr->concent);
139 creature_ptr->reset_concent = FALSE;
141 creature_ptr->update |= (PU_BONUS | PU_MONSTERS);
142 creature_ptr->redraw |= (PR_STATUS);
147 * @brief スナイパーの集中度リセット
148 * @param msg TRUEならばメッセージを表示する
151 void reset_concentration(player_type *creature_ptr, bool msg)
155 msg_print(_("集中力が途切れてしまった。", "Stop concentrating."));
158 creature_ptr->concent = 0;
159 creature_ptr->reset_concent = FALSE;
161 creature_ptr->update |= (PU_BONUS | PU_MONSTERS);
162 creature_ptr->redraw |= (PR_STATUS);
166 * @brief スナイパーの集中度によるダメージボーナスを加算する
167 * @param tdam 算出中のダメージ
168 * @return 集中度修正を加えたダメージ
170 int boost_concentration_damage(player_type *creature_ptr, int tdam)
172 tdam *= (10 + creature_ptr->concent);
179 * @brief スナイパーの技能リストを表示する
182 void display_snipe_list(player_type *sniper_ptr)
187 PLAYER_LEVEL plev = sniper_ptr->lev;
191 /* Display a list of spells */
193 put_str(_("名前", "Name"), y, x + 5);
194 put_str(_("Lv MP", "Lv Mana"), y, x + 35);
196 for (i = 0; i < MAX_SNIPE_POWERS; i++)
198 /* Access the available spell */
199 spell = snipe_powers[i];
200 if (spell.min_lev > plev) continue;
202 sprintf(psi_desc, " %c) %-30s%2d %4d",
203 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
205 if (spell.mana_cost > (int)sniper_ptr->concent)
206 term_putstr(x, y + i + 1, -1, TERM_SLATE, psi_desc);
208 term_putstr(x, y + i + 1, -1, TERM_WHITE, psi_desc);
215 * @brief スナイパー技能を選択する
216 * @param sn 選択した特殊技能ID、キャンセルの場合-1、不正な選択の場合-2を返す
217 * @param only_browse 一覧を見るだけの場合TRUEを返す
218 * @return 発動可能な魔法を選択した場合TRUE、キャンセル処理か不正な選択が行われた場合FALSEを返す。
219 * Allow user to choose a mindcrafter power.\n
221 * If a valid spell is chosen, saves it in '*sn' and returns TRUE\n
222 * If the user hits escape, returns FALSE, and set '*sn' to -1\n
223 * If there are no legal choices, returns FALSE, and sets '*sn' to -2\n
225 * The "prompt" should be "cast", "recite", or "study"\n
226 * The "known" should be TRUE for cast/pray, FALSE for study\n
228 * nb: This function has a (trivial) display bug which will be obvious\n
229 * when you run it. It's probably easy to fix but I haven't tried,\n
232 static int get_snipe_power(player_type *sniper_ptr, COMMAND_CODE *sn, bool only_browse)
238 PLAYER_LEVEL plev = sniper_ptr->lev;
242 concptr p = _("射撃術", "power");
248 /* Assume cancelled */
251 /* Repeat previous command */
252 /* Get the spell, if available */
255 /* Verify the spell */
256 if ((snipe_powers[*sn].min_lev <= plev) && (snipe_powers[*sn].mana_cost <= (int)sniper_ptr->concent))
266 for (i = 0; i < MAX_SNIPE_POWERS; i++)
268 if ((snipe_powers[i].min_lev <= plev) &&
269 ((only_browse) || (snipe_powers[i].mana_cost <= (int)sniper_ptr->concent)))
275 /* Build a prompt (accept all spells) */
278 (void)strnfmt(out_val, 78,
279 _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
280 p, I2A(0), I2A(num), p);
284 (void)strnfmt(out_val, 78,
285 _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
286 p, I2A(0), I2A(num), p);
289 choice = always_show_list ? ESCAPE : 1;
292 if(choice == ESCAPE) choice = ' ';
293 else if( !get_com(out_val, &choice, FALSE) )break;
296 if ((choice == ' ') || (choice == '*') || (choice == '?'))
304 if (!only_browse) screen_save();
306 /* Display a list of spells */
308 put_str(_("名前", "Name"), y, x + 5);
309 put_str(_("Lv 集中度", "Lv Pow"), y, x + 35);
311 /* Dump the spells */
312 for (i = 0; i < MAX_SNIPE_POWERS; i++)
314 term_color_type tcol = TERM_WHITE;
315 term_erase(x, y + i + 1, 255);
317 /* Access the spell */
318 spell = snipe_powers[i];
320 /* Dump the spell --(-- */
321 if (spell.min_lev > plev)
322 sprintf(psi_index, " ) ");
324 sprintf(psi_index, " %c) ", I2A(i));
326 sprintf(psi_desc, "%-30s%2d %4d",
327 spell.name, spell.min_lev, spell.mana_cost);
329 if (spell.min_lev > plev)
331 else if (spell.mana_cost > (int)sniper_ptr->concent)
334 term_putstr(x, y + i + 1, -1, tcol, psi_index);
335 term_putstr(x + 5, y + i + 1, -1, tcol, psi_desc);
338 /* Clear the bottom line */
339 prt("", y + i + 1, x);
347 if (!only_browse) screen_load();
355 ask = isupper(choice);
358 if (ask) choice = (char)tolower(choice);
360 /* Extract request */
361 i = (islower(choice) ? A2I(choice) : -1);
363 /* Totally Illegal */
364 if ((i < 0) || (i > num) ||
365 (!only_browse &&(snipe_powers[i].mana_cost > (int)sniper_ptr->concent)))
371 /* Save the spell index */
372 spell = snipe_powers[i];
380 (void) strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), snipe_powers[i].name);
382 /* Belay that order */
383 if (!get_check(tmp_val)) continue;
389 if (redraw && !only_browse) screen_load();
391 sniper_ptr->window_flags |= (PW_SPELL);
392 handle_stuff(sniper_ptr);
394 /* Abort if needed */
395 if (!flag) return FALSE;
397 /* Save the choice */
408 * @brief スナイバー技能のスレイ倍率計算を行う /
409 * Calcurate magnification of snipe technics
410 * @param mult スナイバー技能のスレイ効果以前に算出している多要素の倍率(/10倍)
411 * @param m_ptr 目標となるモンスターの構造体参照ポインタ
412 * @return スレイの倍率(/10倍)
414 MULTIPLY calc_snipe_damage_with_slay(player_type *sniper_ptr, MULTIPLY mult, monster_type *m_ptr, SPELL_IDX snipe_type)
416 monster_race *r_ptr = &r_info[m_ptr->r_idx];
417 bool seen = is_seen(sniper_ptr, m_ptr);
422 if (r_ptr->flags3 & (RF3_HURT_LITE))
424 MULTIPLY n = 20 + sniper_ptr->concent;
425 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
426 if (mult < n) mult = n;
430 if (r_ptr->flagsr & RFR_IM_FIRE)
432 if (seen) r_ptr->r_flagsr |= RFR_IM_FIRE;
436 MULTIPLY n = 15 + (sniper_ptr->concent * 3);
437 if (mult < n) mult = n;
441 if (r_ptr->flagsr & RFR_IM_COLD)
443 if (seen) r_ptr->r_flagsr |= RFR_IM_COLD;
447 MULTIPLY n = 15 + (sniper_ptr->concent * 3);
448 if (mult < n) mult = n;
452 if (r_ptr->flagsr & RFR_IM_ELEC)
454 if (seen) r_ptr->r_flagsr |= RFR_IM_ELEC;
458 MULTIPLY n = 18 + (sniper_ptr->concent * 4);
459 if (mult < n) mult = n;
463 if (r_ptr->flags3 & RF3_HURT_ROCK)
465 MULTIPLY n = 15 + (sniper_ptr->concent * 2);
466 if (seen) r_ptr->r_flags3 |= RF3_HURT_ROCK;
467 if (mult < n) mult = n;
469 else if (r_ptr->flags3 & RF3_NONLIVING)
471 MULTIPLY n = 15 + (sniper_ptr->concent * 2);
472 if (seen) r_ptr->r_flags3 |= RF3_NONLIVING;
473 if (mult < n) mult = n;
477 if (r_ptr->flags3 & RF3_GOOD)
479 MULTIPLY n = 15 + (sniper_ptr->concent * 4);
480 if (seen) r_ptr->r_flags3 |= RF3_GOOD;
481 if (mult < n) mult = n;
485 if (r_ptr->flags3 & RF3_EVIL)
487 MULTIPLY n = 12 + (sniper_ptr->concent * 3);
488 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
489 if (r_ptr->flags3 & (RF3_HURT_LITE))
491 n += (sniper_ptr->concent * 3);
492 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
494 if (mult < n) mult = n;
498 if (mult < 50) mult = 50;
507 * @brief スナイパー技能の発動 /
508 * do_cmd_cast calls this function if the player's class is 'snipe'.
509 * @param spell 発動する特殊技能のID
510 * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
512 static bool cast_sniper_spell(player_type *sniper_ptr, int spell)
514 object_type *o_ptr = &sniper_ptr->inventory_list[INVEN_BOW];
515 SPELL_IDX snipe_type = SP_NONE;
517 if (o_ptr->tval != TV_BOW)
519 msg_print(_("弓を装備していない!", "You wield no bow!"));
526 case 0: /* Concentration */
527 if (!snipe_concentrate(sniper_ptr)) return FALSE;
528 take_turn(sniper_ptr, 100);
530 case 1: snipe_type = SP_LITE; break;
531 case 2: snipe_type = SP_AWAY; break;
532 case 3: snipe_type = SP_KILL_TRAP; break;
533 case 4: snipe_type = SP_FIRE; break;
534 case 5: snipe_type = SP_KILL_WALL; break;
535 case 6: snipe_type = SP_COLD; break;
536 case 7: snipe_type = SP_RUSH; break;
537 case 8: snipe_type = SP_PIERCE; break;
538 case 9: snipe_type = SP_EVILNESS; break;
539 case 10: snipe_type = SP_HOLYNESS; break;
540 case 11: snipe_type = SP_EXPLODE; break;
541 case 12: snipe_type = SP_DOUBLE; break;
542 case 13: snipe_type = SP_ELEC; break;
543 case 14: snipe_type = SP_NEEDLE; break;
544 case 15: snipe_type = SP_FINAL; break;
546 msg_print(_("なに?", "Zap?"));
550 do_cmd_fire(sniper_ptr, snipe_type);
552 return (sniper_ptr->is_fired);
556 * @brief スナイパー技能コマンドのメインルーチン /
559 void do_cmd_snipe(player_type *sniper_ptr)
564 if(cmd_limit_confused(sniper_ptr)) return;
565 if(cmd_limit_image(sniper_ptr)) return;
566 if(cmd_limit_stun(sniper_ptr)) return;
568 if (!get_snipe_power(sniper_ptr, &n, FALSE)) return;
571 cast = cast_sniper_spell(sniper_ptr, n);
574 sniper_ptr->redraw |= (PR_HP | PR_MANA);
575 sniper_ptr->window_flags |= (PW_PLAYER);
576 sniper_ptr->window_flags |= (PW_SPELL);
580 * @brief スナイパー技能コマンドの表示 /
583 void do_cmd_snipe_browse(player_type *sniper_ptr)
593 if (!get_snipe_power(sniper_ptr, &n, TRUE))
599 /* Clear lines, position cursor (really should use strlen here) */
600 term_erase(12, 22, 255);
601 term_erase(12, 21, 255);
602 term_erase(12, 20, 255);
603 term_erase(12, 19, 255);
604 term_erase(12, 18, 255);
606 shape_buffer(snipe_tips[n], 62, temp, sizeof(temp));
607 for(j = 0, line = 19; temp[j]; j += (1 + strlen(&temp[j])))
609 prt(&temp[j], line, 15);