3 * @brief スナイパー技能の実装 / Sniping
6 * 2014 Deskull rearranged comment for Doxygen.\n
14 #include "player-status.h"
15 #include "cmd-basic.h"
17 #include "monsterrace.h"
18 #include "view-mainwindow.h"
20 #define MAX_SNIPE_POWERS 16
22 /*! スナイパー技能情報のtypedef */
23 typedef struct snipe_power snipe_power;
33 /*! スナイパー技能の解説メッセージ */
34 static concptr const snipe_tips[MAX_SNIPE_POWERS] =
37 "精神を集中する。射撃の威力、精度が上がり、高度な射撃術が使用できるようになる。",
38 "光る矢を放つ。光に弱いモンスターに威力を発揮する。",
39 "射撃を行った後、短距離の瞬間移動を行う。",
40 "軌道上の罠をすべて無効にする低空飛行の矢を放つ。",
42 "壁を粉砕する矢を放つ。岩でできたモンスターと無生物のモンスターに威力を発揮する。",
46 "善良なモンスターに威力を発揮する矢を放つ。",
47 "邪悪なモンスターに威力を発揮する矢を放つ。",
51 "敵の急所にめがけて矢を放つ。成功すると敵を一撃死させる。失敗すると1ダメージ。",
52 "全てのモンスターに高威力を発揮する矢を放つ。反動による副次効果を受ける。",
54 "Concentrate your mind fot shooting.",
55 "Shot an allow with brightness.",
56 "Blink after shooting.",
57 "Shot an allow able to shatter traps.",
58 "Deals extra damege of fire.",
59 "Shot an allow able to shatter rocks.",
60 "Deals extra damege of ice.",
61 "An allow rushes away a target.",
62 "An allow pierces some monsters.",
63 "Deals more damage to good monsters.",
64 "Deals more damage to evil monsters.",
65 "An allow explodes when it hits a monster.",
67 "Deals extra damege of lightning.",
68 "Deals quick death or 1 damage.",
69 "Deals great damage to all monsters, and some side effects to you.",
74 static snipe_power const snipe_powers[MAX_SNIPE_POWERS] =
76 /* Level gained, cost, name */
80 { 3, 1, "シュート&アウェイ" },
92 { 40, 3, "ニードルショット" },
93 { 48, 7, "セイントスターアロー" },
95 { 1, 0, "Concentration" },
96 { 2, 1, "Flush Arrow" },
97 { 3, 1, "Shoot & Away" },
98 { 5, 1, "Disarm Shot" },
99 { 8, 2, "Fire Shot" },
100 { 10, 2, "Shatter Arrow" },
101 { 13, 2, "Ice Shot" },
102 { 18, 2, "Rushing Arrow"},
103 { 22, 3, "Piercing Shot" },
104 { 25, 4, "Evil Shot"},
105 { 26, 4, "Holy Shot" },
107 { 32, 4, "Double Shot" },
108 { 36, 3, "Plasma Bolt" },
109 { 40, 3, "Needle Shot" },
110 { 48, 7, "Saint Stars Arrow" },
118 static bool snipe_concentrate(void)
120 if ((int)p_ptr->concent < (2 + (p_ptr->lev + 5) / 10)) p_ptr->concent++;
122 msg_format(_("集中した。(集中度 %d)", "You concentrate deeply. (lvl %d)"), p_ptr->concent);
123 p_ptr->reset_concent = FALSE;
125 p_ptr->update |= (PU_BONUS | PU_MONSTERS);
126 p_ptr->redraw |= (PR_STATUS);
131 * @brief スナイパーの集中度リセット
132 * @param msg TRUEならばメッセージを表示する
135 void reset_concentration(bool msg)
139 msg_print(_("集中力が途切れてしまった。", "Stop concentrating."));
143 p_ptr->reset_concent = FALSE;
145 p_ptr->update |= (PU_BONUS | PU_MONSTERS);
146 p_ptr->redraw |= (PR_STATUS);
150 * @brief スナイパーの集中度によるダメージボーナスを加算する
151 * @param tdam 算出中のダメージ
152 * @return 集中度修正を加えたダメージ
154 int boost_concentration_damage(int tdam)
156 tdam *= (10 + p_ptr->concent);
163 * @brief スナイパーの技能リストを表示する
166 void display_snipe_list(void)
171 PLAYER_LEVEL plev = p_ptr->lev;
175 /* Display a list of spells */
177 put_str(_("名前", "Name"), y, x + 5);
178 put_str(_("Lv MP", "Lv Mana"), y, x + 35);
180 for (i = 0; i < MAX_SNIPE_POWERS; i++)
182 /* Access the available spell */
183 spell = snipe_powers[i];
184 if (spell.min_lev > plev) continue;
185 if (spell.mana_cost > (int)p_ptr->concent) continue;
187 sprintf(psi_desc, " %c) %-30s%2d %4d",
188 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
190 Term_putstr(x, y + i + 1, -1, TERM_WHITE, psi_desc);
197 * @brief スナイパー技能を選択する
198 * @param sn 選択した特殊技能ID、キャンセルの場合-1、不正な選択の場合-2を返す
199 * @param only_browse 一覧を見るだけの場合TRUEを返す
200 * @return 発動可能な魔法を選択した場合TRUE、キャンセル処理か不正な選択が行われた場合FALSEを返す。
201 * Allow user to choose a mindcrafter power.\n
203 * If a valid spell is chosen, saves it in '*sn' and returns TRUE\n
204 * If the user hits escape, returns FALSE, and set '*sn' to -1\n
205 * If there are no legal choices, returns FALSE, and sets '*sn' to -2\n
207 * The "prompt" should be "cast", "recite", or "study"\n
208 * The "known" should be TRUE for cast/pray, FALSE for study\n
210 * nb: This function has a (trivial) display bug which will be obvious\n
211 * when you run it. It's probably easy to fix but I haven't tried,\n
214 static int get_snipe_power(COMMAND_CODE *sn, bool only_browse)
220 PLAYER_LEVEL plev = p_ptr->lev;
224 concptr p = _("射撃術", "power");
230 /* Assume cancelled */
233 /* Repeat previous command */
234 /* Get the spell, if available */
237 /* Verify the spell */
238 if ((snipe_powers[*sn].min_lev <= plev) && (snipe_powers[*sn].mana_cost <= (int)p_ptr->concent))
245 /* Nothing chosen yet */
251 for (i = 0; i < MAX_SNIPE_POWERS; i++)
253 if ((snipe_powers[i].min_lev <= plev) &&
254 ((only_browse) || (snipe_powers[i].mana_cost <= (int)p_ptr->concent)))
260 /* Build a prompt (accept all spells) */
263 (void)strnfmt(out_val, 78,
264 _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
265 p, I2A(0), I2A(num), p);
269 (void)strnfmt(out_val, 78,
270 _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
271 p, I2A(0), I2A(num), p);
274 choice = always_show_list ? ESCAPE : 1;
277 if(choice == ESCAPE) choice = ' ';
278 else if( !get_com(out_val, &choice, FALSE) )break;
281 if ((choice == ' ') || (choice == '*') || (choice == '?'))
288 if (!only_browse) screen_save();
290 /* Display a list of spells */
292 put_str(_("名前", "Name"), y, x + 5);
293 if (only_browse) put_str(_("Lv 集中度", "Lv Pow"), y, x + 35);
295 /* Dump the spells */
296 for (i = 0; i < MAX_SNIPE_POWERS; i++)
298 Term_erase(x, y + i + 1, 255);
300 /* Access the spell */
301 spell = snipe_powers[i];
302 if (spell.min_lev > plev) continue;
303 if (!only_browse && (spell.mana_cost > (int)p_ptr->concent)) continue;
305 /* Dump the spell --(-- */
307 sprintf(psi_desc, " %c) %-30s%2d %4d",
308 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
310 sprintf(psi_desc, " %c) %-30s", I2A(i), spell.name);
311 prt(psi_desc, y + i + 1, x);
314 /* Clear the bottom line */
315 prt("", y + i + 1, x);
323 if (!only_browse) screen_load();
331 ask = isupper(choice);
334 if (ask) choice = (char)tolower(choice);
336 /* Extract request */
337 i = (islower(choice) ? A2I(choice) : -1);
339 /* Totally Illegal */
340 if ((i < 0) || (i > num) ||
341 (!only_browse &&(snipe_powers[i].mana_cost > (int)p_ptr->concent)))
347 /* Save the spell index */
348 spell = snipe_powers[i];
356 (void) strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), snipe_powers[i].name);
358 /* Belay that order */
359 if (!get_check(tmp_val)) continue;
365 if (redraw && !only_browse) screen_load();
367 p_ptr->window |= (PW_SPELL);
370 /* Abort if needed */
371 if (!flag) return (FALSE);
373 /* Save the choice */
383 * @brief スナイバー技能のスレイ倍率計算を行う /
384 * Calcurate magnification of snipe technics
385 * @param mult スナイバー技能のスレイ効果以前に算出している多要素の倍率(/10倍)
386 * @param m_ptr 目標となるモンスターの構造体参照ポインタ
387 * @return スレイの倍率(/10倍)
389 MULTIPLY tot_dam_aux_snipe(MULTIPLY mult, monster_type *m_ptr, SPELL_IDX snipe_type)
391 monster_race *r_ptr = &r_info[m_ptr->r_idx];
392 bool seen = is_seen(m_ptr);
397 if (r_ptr->flags3 & (RF3_HURT_LITE))
399 MULTIPLY n = 20 + p_ptr->concent;
400 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
401 if (mult < n) mult = n;
405 if (r_ptr->flagsr & RFR_IM_FIRE)
407 if (seen) r_ptr->r_flagsr |= RFR_IM_FIRE;
411 MULTIPLY n = 15 + (p_ptr->concent * 3);
412 if (mult < n) mult = n;
416 if (r_ptr->flagsr & RFR_IM_COLD)
418 if (seen) r_ptr->r_flagsr |= RFR_IM_COLD;
422 MULTIPLY n = 15 + (p_ptr->concent * 3);
423 if (mult < n) mult = n;
427 if (r_ptr->flagsr & RFR_IM_ELEC)
429 if (seen) r_ptr->r_flagsr |= RFR_IM_ELEC;
433 MULTIPLY n = 18 + (p_ptr->concent * 4);
434 if (mult < n) mult = n;
438 if (r_ptr->flags3 & RF3_HURT_ROCK)
440 MULTIPLY n = 15 + (p_ptr->concent * 2);
441 if (seen) r_ptr->r_flags3 |= RF3_HURT_ROCK;
442 if (mult < n) mult = n;
444 else if (r_ptr->flags3 & RF3_NONLIVING)
446 MULTIPLY n = 15 + (p_ptr->concent * 2);
447 if (seen) r_ptr->r_flags3 |= RF3_NONLIVING;
448 if (mult < n) mult = n;
452 if (r_ptr->flags3 & RF3_GOOD)
454 MULTIPLY n = 15 + (p_ptr->concent * 4);
455 if (seen) r_ptr->r_flags3 |= RF3_GOOD;
456 if (mult < n) mult = n;
460 if (r_ptr->flags3 & RF3_EVIL)
462 MULTIPLY n = 12 + (p_ptr->concent * 3);
463 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
464 if (r_ptr->flags3 & (RF3_HURT_LITE))
466 n += (p_ptr->concent * 3);
467 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
469 if (mult < n) mult = n;
473 if (mult < 50) mult = 50;
482 * @brief スナイパー技能の発動 /
483 * do_cmd_cast calls this function if the player's class is 'snipe'.
484 * @param spell 発動する特殊技能のID
485 * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
487 static bool cast_sniper_spell(int spell)
489 object_type *o_ptr = &p_ptr->inventory_list[INVEN_BOW];
490 SPELL_IDX snipe_type = SP_NONE;
492 if (o_ptr->tval != TV_BOW)
494 msg_print(_("弓を装備していない!", "You wield no bow!"));
501 case 0: /* Concentration */
502 if (!snipe_concentrate()) return (FALSE);
503 take_turn(p_ptr, 100);
505 case 1: snipe_type = SP_LITE; break;
506 case 2: snipe_type = SP_AWAY; break;
507 case 3: snipe_type = SP_KILL_TRAP; break;
508 case 4: snipe_type = SP_FIRE; break;
509 case 5: snipe_type = SP_KILL_WALL; break;
510 case 6: snipe_type = SP_COLD; break;
511 case 7: snipe_type = SP_RUSH; break;
512 case 8: snipe_type = SP_PIERCE; break;
513 case 9: snipe_type = SP_EVILNESS; break;
514 case 10: snipe_type = SP_HOLYNESS; break;
515 case 11: snipe_type = SP_EXPLODE; break;
516 case 12: snipe_type = SP_DOUBLE; break;
517 case 13: snipe_type = SP_ELEC; break;
518 case 14: snipe_type = SP_NEEDLE; break;
519 case 15: snipe_type = SP_FINAL; break;
521 msg_print(_("なに?", "Zap?"));
525 do_cmd_fire(snipe_type);
527 return (p_ptr->is_fired);
531 * @brief スナイパー技能コマンドのメインルーチン /
534 void do_cmd_snipe(void)
539 if(cmd_limit_confused(p_ptr)) return;
540 if(cmd_limit_image(p_ptr)) return;
541 if(cmd_limit_stun(p_ptr)) return;
543 if (!get_snipe_power(&n, FALSE)) return;
546 cast = cast_sniper_spell(n);
549 p_ptr->redraw |= (PR_HP | PR_MANA);
550 p_ptr->window |= (PW_PLAYER);
551 p_ptr->window |= (PW_SPELL);
555 * @brief スナイパー技能コマンドの表示 /
558 void do_cmd_snipe_browse(void)
568 if (!get_snipe_power(&n, TRUE))
574 /* Clear lines, position cursor (really should use strlen here) */
575 Term_erase(12, 22, 255);
576 Term_erase(12, 21, 255);
577 Term_erase(12, 20, 255);
578 Term_erase(12, 19, 255);
579 Term_erase(12, 18, 255);
581 roff_to_buf(snipe_tips[n], 62, temp, sizeof(temp));
582 for(j = 0, line = 19; temp[j]; j += (1 + strlen(&temp[j])))
584 prt(&temp[j], line, 15);