3 * @brief スナイパー技能の実装 / Sniping
6 * 2014 Deskull rearranged comment for Doxygen.\n
10 #include "player-status.h"
11 #include "cmd-basic.h"
13 #define MAX_SNIPE_POWERS 16
15 /*! スナイパー技能情報のtypedef */
16 typedef struct snipe_power snipe_power;
26 /*! スナイパー技能の解説メッセージ */
27 static concptr const snipe_tips[MAX_SNIPE_POWERS] =
30 "精神を集中する。射撃の威力、精度が上がり、高度な射撃術が使用できるようになる。",
31 "光る矢を放つ。光に弱いモンスターに威力を発揮する。",
32 "射撃を行った後、短距離の瞬間移動を行う。",
33 "軌道上の罠をすべて無効にする低空飛行の矢を放つ。",
35 "壁を粉砕する矢を放つ。岩でできたモンスターと無生物のモンスターに威力を発揮する。",
39 "善良なモンスターに威力を発揮する矢を放つ。",
40 "邪悪なモンスターに威力を発揮する矢を放つ。",
44 "敵の急所にめがけて矢を放つ。成功すると敵を一撃死させる。失敗すると1ダメージ。",
45 "全てのモンスターに高威力を発揮する矢を放つ。反動による副次効果を受ける。",
47 "Concentrate your mind fot shooting.",
48 "Shot an allow with brightness.",
49 "Blink after shooting.",
50 "Shot an allow able to shatter traps.",
51 "Deals extra damege of fire.",
52 "Shot an allow able to shatter rocks.",
53 "Deals extra damege of ice.",
54 "An allow rushes away a target.",
55 "An allow pierces some monsters.",
56 "Deals more damage to good monsters.",
57 "Deals more damage to evil monsters.",
58 "An allow explodes when it hits a monster.",
60 "Deals extra damege of lightning.",
61 "Deals quick death or 1 damage.",
62 "Deals great damage to all monsters, and some side effects to you.",
67 static snipe_power const snipe_powers[MAX_SNIPE_POWERS] =
69 /* Level gained, cost, name */
73 { 3, 1, "シュート&アウェイ" },
85 { 40, 3, "ニードルショット" },
86 { 48, 7, "セイントスターアロー" },
88 { 1, 0, "Concentration" },
89 { 2, 1, "Flush Arrow" },
90 { 3, 1, "Shoot & Away" },
91 { 5, 1, "Disarm Shot" },
92 { 8, 2, "Fire Shot" },
93 { 10, 2, "Shatter Arrow" },
94 { 13, 2, "Ice Shot" },
95 { 18, 2, "Rushing Arrow"},
96 { 22, 3, "Piercing Shot" },
97 { 25, 4, "Evil Shot"},
98 { 26, 4, "Holy Shot" },
100 { 32, 4, "Double Shot" },
101 { 36, 3, "Plasma Bolt" },
102 { 40, 3, "Needle Shot" },
103 { 48, 7, "Saint Stars Arrow" },
111 static bool snipe_concentrate(void)
113 if ((int)p_ptr->concent < (2 + (p_ptr->lev + 5) / 10)) p_ptr->concent++;
115 msg_format(_("集中した。(集中度 %d)", "You concentrate deeply. (lvl %d)"), p_ptr->concent);
116 reset_concent = FALSE;
118 p_ptr->update |= (PU_BONUS | PU_MONSTERS);
119 p_ptr->redraw |= (PR_STATUS);
124 * @brief スナイパーの集中度リセット
125 * @param msg TRUEならばメッセージを表示する
128 void reset_concentration(bool msg)
132 msg_print(_("集中力が途切れてしまった。", "Stop concentrating."));
136 reset_concent = FALSE;
138 p_ptr->update |= (PU_BONUS | PU_MONSTERS);
139 p_ptr->redraw |= (PR_STATUS);
143 * @brief スナイパーの集中度によるダメージボーナスを加算する
144 * @param tdam 算出中のダメージ
145 * @return 集中度修正を加えたダメージ
147 int boost_concentration_damage(int tdam)
149 tdam *= (10 + p_ptr->concent);
156 * @brief スナイパーの技能リストを表示する
159 void display_snipe_list(void)
164 PLAYER_LEVEL plev = p_ptr->lev;
168 /* Display a list of spells */
170 put_str(_("名前", "Name"), y, x + 5);
171 put_str(_("Lv MP", "Lv Mana"), y, x + 35);
173 for (i = 0; i < MAX_SNIPE_POWERS; i++)
175 /* Access the available spell */
176 spell = snipe_powers[i];
177 if (spell.min_lev > plev) continue;
178 if (spell.mana_cost > (int)p_ptr->concent) continue;
180 sprintf(psi_desc, " %c) %-30s%2d %4d",
181 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
183 Term_putstr(x, y + i + 1, -1, TERM_WHITE, psi_desc);
190 * @brief スナイパー技能を選択する
191 * @param sn 選択した特殊技能ID、キャンセルの場合-1、不正な選択の場合-2を返す
192 * @param only_browse 一覧を見るだけの場合TRUEを返す
193 * @return 発動可能な魔法を選択した場合TRUE、キャンセル処理か不正な選択が行われた場合FALSEを返す。
194 * Allow user to choose a mindcrafter power.\n
196 * If a valid spell is chosen, saves it in '*sn' and returns TRUE\n
197 * If the user hits escape, returns FALSE, and set '*sn' to -1\n
198 * If there are no legal choices, returns FALSE, and sets '*sn' to -2\n
200 * The "prompt" should be "cast", "recite", or "study"\n
201 * The "known" should be TRUE for cast/pray, FALSE for study\n
203 * nb: This function has a (trivial) display bug which will be obvious\n
204 * when you run it. It's probably easy to fix but I haven't tried,\n
207 static int get_snipe_power(COMMAND_CODE *sn, bool only_browse)
213 PLAYER_LEVEL plev = p_ptr->lev;
217 concptr p = _("射撃術", "power");
223 /* Assume cancelled */
226 /* Repeat previous command */
227 /* Get the spell, if available */
230 /* Verify the spell */
231 if ((snipe_powers[*sn].min_lev <= plev) && (snipe_powers[*sn].mana_cost <= (int)p_ptr->concent))
238 /* Nothing chosen yet */
244 for (i = 0; i < MAX_SNIPE_POWERS; i++)
246 if ((snipe_powers[i].min_lev <= plev) &&
247 ((only_browse) || (snipe_powers[i].mana_cost <= (int)p_ptr->concent)))
253 /* Build a prompt (accept all spells) */
256 (void)strnfmt(out_val, 78,
257 _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
258 p, I2A(0), I2A(num), p);
262 (void)strnfmt(out_val, 78,
263 _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
264 p, I2A(0), I2A(num), p);
267 choice = always_show_list ? ESCAPE : 1;
270 if(choice == ESCAPE) choice = ' ';
271 else if( !get_com(out_val, &choice, FALSE) )break;
274 if ((choice == ' ') || (choice == '*') || (choice == '?'))
281 if (!only_browse) screen_save();
283 /* Display a list of spells */
285 put_str(_("名前", "Name"), y, x + 5);
286 if (only_browse) put_str(_("Lv 集中度", "Lv Pow"), y, x + 35);
288 /* Dump the spells */
289 for (i = 0; i < MAX_SNIPE_POWERS; i++)
291 Term_erase(x, y + i + 1, 255);
293 /* Access the spell */
294 spell = snipe_powers[i];
295 if (spell.min_lev > plev) continue;
296 if (!only_browse && (spell.mana_cost > (int)p_ptr->concent)) continue;
298 /* Dump the spell --(-- */
300 sprintf(psi_desc, " %c) %-30s%2d %4d",
301 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
303 sprintf(psi_desc, " %c) %-30s", I2A(i), spell.name);
304 prt(psi_desc, y + i + 1, x);
307 /* Clear the bottom line */
308 prt("", y + i + 1, x);
316 if (!only_browse) screen_load();
324 ask = isupper(choice);
327 if (ask) choice = (char)tolower(choice);
329 /* Extract request */
330 i = (islower(choice) ? A2I(choice) : -1);
332 /* Totally Illegal */
333 if ((i < 0) || (i > num) ||
334 (!only_browse &&(snipe_powers[i].mana_cost > (int)p_ptr->concent)))
340 /* Save the spell index */
341 spell = snipe_powers[i];
349 (void) strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), snipe_powers[i].name);
351 /* Belay that order */
352 if (!get_check(tmp_val)) continue;
358 if (redraw && !only_browse) screen_load();
360 p_ptr->window |= (PW_SPELL);
363 /* Abort if needed */
364 if (!flag) return (FALSE);
366 /* Save the choice */
376 * @brief スナイバー技能のスレイ倍率計算を行う /
377 * Calcurate magnification of snipe technics
378 * @param mult スナイバー技能のスレイ効果以前に算出している多要素の倍率(/10倍)
379 * @param m_ptr 目標となるモンスターの構造体参照ポインタ
380 * @return スレイの倍率(/10倍)
382 MULTIPLY tot_dam_aux_snipe(MULTIPLY mult, monster_type *m_ptr, SPELL_IDX snipe_type)
384 monster_race *r_ptr = &r_info[m_ptr->r_idx];
385 bool seen = is_seen(m_ptr);
390 if (r_ptr->flags3 & (RF3_HURT_LITE))
392 MULTIPLY n = 20 + p_ptr->concent;
393 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
394 if (mult < n) mult = n;
398 if (r_ptr->flagsr & RFR_IM_FIRE)
400 if (seen) r_ptr->r_flagsr |= RFR_IM_FIRE;
404 MULTIPLY n = 15 + (p_ptr->concent * 3);
405 if (mult < n) mult = n;
409 if (r_ptr->flagsr & RFR_IM_COLD)
411 if (seen) r_ptr->r_flagsr |= RFR_IM_COLD;
415 MULTIPLY n = 15 + (p_ptr->concent * 3);
416 if (mult < n) mult = n;
420 if (r_ptr->flagsr & RFR_IM_ELEC)
422 if (seen) r_ptr->r_flagsr |= RFR_IM_ELEC;
426 MULTIPLY n = 18 + (p_ptr->concent * 4);
427 if (mult < n) mult = n;
431 if (r_ptr->flags3 & RF3_HURT_ROCK)
433 MULTIPLY n = 15 + (p_ptr->concent * 2);
434 if (seen) r_ptr->r_flags3 |= RF3_HURT_ROCK;
435 if (mult < n) mult = n;
437 else if (r_ptr->flags3 & RF3_NONLIVING)
439 MULTIPLY n = 15 + (p_ptr->concent * 2);
440 if (seen) r_ptr->r_flags3 |= RF3_NONLIVING;
441 if (mult < n) mult = n;
445 if (r_ptr->flags3 & RF3_GOOD)
447 MULTIPLY n = 15 + (p_ptr->concent * 4);
448 if (seen) r_ptr->r_flags3 |= RF3_GOOD;
449 if (mult < n) mult = n;
453 if (r_ptr->flags3 & RF3_EVIL)
455 MULTIPLY n = 12 + (p_ptr->concent * 3);
456 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
457 if (r_ptr->flags3 & (RF3_HURT_LITE))
459 n += (p_ptr->concent * 3);
460 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
462 if (mult < n) mult = n;
466 if (mult < 50) mult = 50;
475 * @brief スナイパー技能の発動 /
476 * do_cmd_cast calls this function if the player's class is 'snipe'.
477 * @param spell 発動する特殊技能のID
478 * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
480 static bool cast_sniper_spell(int spell)
482 object_type *o_ptr = &inventory[INVEN_BOW];
483 SPELL_IDX snipe_type = SP_NONE;
485 if (o_ptr->tval != TV_BOW)
487 msg_print(_("弓を装備していない!", "You wield no bow!"));
494 case 0: /* Concentration */
495 if (!snipe_concentrate()) return (FALSE);
496 take_turn(p_ptr, 100);
498 case 1: snipe_type = SP_LITE; break;
499 case 2: snipe_type = SP_AWAY; break;
500 case 3: snipe_type = SP_KILL_TRAP; break;
501 case 4: snipe_type = SP_FIRE; break;
502 case 5: snipe_type = SP_KILL_WALL; break;
503 case 6: snipe_type = SP_COLD; break;
504 case 7: snipe_type = SP_RUSH; break;
505 case 8: snipe_type = SP_PIERCE; break;
506 case 9: snipe_type = SP_EVILNESS; break;
507 case 10: snipe_type = SP_HOLYNESS; break;
508 case 11: snipe_type = SP_EXPLODE; break;
509 case 12: snipe_type = SP_DOUBLE; break;
510 case 13: snipe_type = SP_ELEC; break;
511 case 14: snipe_type = SP_NEEDLE; break;
512 case 15: snipe_type = SP_FINAL; break;
514 msg_print(_("なに?", "Zap?"));
518 do_cmd_fire(snipe_type);
524 * @brief スナイパー技能コマンドのメインルーチン /
527 void do_cmd_snipe(void)
532 if(cmd_limit_confused(p_ptr)) return;
533 if(cmd_limit_image(p_ptr)) return;
534 if(cmd_limit_stun(p_ptr)) return;
536 if (!get_snipe_power(&n, FALSE)) return;
539 cast = cast_sniper_spell(n);
542 p_ptr->redraw |= (PR_HP | PR_MANA);
543 p_ptr->window |= (PW_PLAYER);
544 p_ptr->window |= (PW_SPELL);
548 * @brief スナイパー技能コマンドの表示 /
551 void do_cmd_snipe_browse(void)
561 if (!get_snipe_power(&n, TRUE))
567 /* Clear lines, position cursor (really should use strlen here) */
568 Term_erase(12, 22, 255);
569 Term_erase(12, 21, 255);
570 Term_erase(12, 20, 255);
571 Term_erase(12, 19, 255);
572 Term_erase(12, 18, 255);
574 roff_to_buf(snipe_tips[n], 62, temp, sizeof(temp));
575 for(j = 0, line = 19; temp[j]; j += (1 + strlen(&temp[j])))
577 prt(&temp[j], line, 15);