3 * @brief スナイパー技能の実装 / Sniping
6 * 2014 Deskull rearranged comment for Doxygen.\n
11 #define MAX_SNIPE_POWERS 16
13 /*! スナイパー技能情報のtypedef */
14 typedef struct snipe_power snipe_power;
24 /*! スナイパー技能の解説メッセージ */
25 static cptr const snipe_tips[MAX_SNIPE_POWERS] =
28 "精神を集中する。射撃の威力、精度が上がり、高度な射撃術が使用できるようになる。",
29 "光る矢を放つ。光に弱いモンスターに威力を発揮する。",
30 "射撃を行った後、短距離の瞬間移動を行う。",
31 "軌道上の罠をすべて無効にする低空飛行の矢を放つ。",
33 "壁を粉砕する矢を放つ。岩でできたモンスターと無生物のモンスターに威力を発揮する。",
37 "善良なモンスターに威力を発揮する矢を放つ。",
38 "邪悪なモンスターに威力を発揮する矢を放つ。",
42 "敵の急所にめがけて矢を放つ。成功すると敵を一撃死させる。失敗すると1ダメージ。",
43 "全てのモンスターに高威力を発揮する矢を放つ。反動による副次効果を受ける。",
45 "Concentrate your mind fot shooting.",
46 "Shot an allow with brightness.",
47 "Blink after shooting.",
48 "Shot an allow able to shatter traps.",
49 "Deals extra damege of fire.",
50 "Shot an allow able to shatter rocks.",
51 "Deals extra damege of ice.",
52 "An allow rushes away a target.",
53 "An allow pierces some monsters.",
54 "Deals more damage to good monsters.",
55 "Deals more damage to evil monsters.",
56 "An allow explodes when it hits a monster.",
58 "Deals extra damege of lightning.",
59 "Deals quick death or 1 damage.",
60 "Deals great damage to all monsters, and some side effects to you.",
65 static snipe_power const snipe_powers[MAX_SNIPE_POWERS] =
67 /* Level gained, cost, name */
71 { 3, 1, "シュート&アウェイ" },
83 { 40, 3, "ニードルショット" },
84 { 48, 7, "セイントスターアロー" },
86 { 1, 0, "Concentration" },
87 { 2, 1, "Flush Arrow" },
88 { 3, 1, "Shoot & Away" },
89 { 5, 1, "Disarm Shot" },
90 { 8, 2, "Fire Shot" },
91 { 10, 2, "Shatter Arrow" },
92 { 13, 2, "Ice Shot" },
93 { 18, 2, "Rushing Arrow"},
94 { 22, 3, "Piercing Shot" },
95 { 25, 4, "Evil Shot"},
96 { 26, 4, "Holy Shot" },
98 { 32, 4, "Double Shot" },
99 { 36, 3, "Plasma Bolt" },
100 { 40, 3, "Needle Shot" },
101 { 48, 7, "Saint Stars Arrow" },
109 static bool snipe_concentrate(void)
111 if ((int)p_ptr->concent < (2 + (p_ptr->lev + 5) / 10)) p_ptr->concent++;
113 msg_format(_("集中した。(集中度 %d)", "You concentrate deeply. (lvl %d)"), p_ptr->concent);
114 reset_concent = FALSE;
116 /* Recalculate bonuses */
117 p_ptr->update |= (PU_BONUS);
119 p_ptr->redraw |= (PR_STATUS);
121 /* Update the monsters */
122 p_ptr->update |= (PU_MONSTERS);
128 * @brief スナイパーの集中度リセット
129 * @param msg TRUEならばメッセージを表示する
132 void reset_concentration(bool msg)
136 msg_print(_("集中力が途切れてしまった。", "Stop concentrating."));
140 reset_concent = FALSE;
142 /* Recalculate bonuses */
143 p_ptr->update |= (PU_BONUS);
145 p_ptr->redraw |= (PR_STATUS);
147 /* Update the monsters */
148 p_ptr->update |= (PU_MONSTERS);
152 * @brief スナイパーの集中度によるダメージボーナスを加算する
153 * @param tdam 算出中のダメージ
154 * @return 集中度修正を加えたダメージ
156 int boost_concentration_damage(int tdam)
158 tdam *= (10 + p_ptr->concent);
165 * @brief スナイパーの技能リストを表示する
168 void display_snipe_list(void)
173 PLAYER_LEVEL plev = p_ptr->lev;
177 /* Display a list of spells */
180 put_str("名前", y, x + 5);
181 put_str("Lv MP", y, x + 35);
183 put_str("Name", y, x + 5);
184 put_str("Lv Mana", y, x + 35);
187 /* Dump the spells */
188 for (i = 0; i < MAX_SNIPE_POWERS; i++)
190 /* Access the available spell */
191 spell = snipe_powers[i];
192 if (spell.min_lev > plev) continue;
193 if (spell.mana_cost > (int)p_ptr->concent) continue;
196 sprintf(psi_desc, " %c) %-30s%2d %4d",
197 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
199 Term_putstr(x, y + i + 1, -1, TERM_WHITE, psi_desc);
206 * @brief スナイパー技能を選択する
207 * @param sn 選択した特殊技能ID、キャンセルの場合-1、不正な選択の場合-2を返す
208 * @param only_browse 一覧を見るだけの場合TRUEを返す
209 * @return 発動可能な魔法を選択した場合TRUE、キャンセル処理か不正な選択が行われた場合FALSEを返す。
210 * Allow user to choose a mindcrafter power.\n
212 * If a valid spell is chosen, saves it in '*sn' and returns TRUE\n
213 * If the user hits escape, returns FALSE, and set '*sn' to -1\n
214 * If there are no legal choices, returns FALSE, and sets '*sn' to -2\n
216 * The "prompt" should be "cast", "recite", or "study"\n
217 * The "known" should be TRUE for cast/pray, FALSE for study\n
219 * nb: This function has a (trivial) display bug which will be obvious\n
220 * when you run it. It's probably easy to fix but I haven't tried,\n
223 static int get_snipe_power(COMMAND_CODE *sn, bool only_browse)
229 PLAYER_LEVEL plev = p_ptr->lev;
233 cptr p = _("射撃術", "power");
237 #ifdef ALLOW_REPEAT /* TNB */
241 /* Assume cancelled */
244 /* Repeat previous command */
245 /* Get the spell, if available */
248 /* Verify the spell */
249 if ((snipe_powers[*sn].min_lev <= plev) && (snipe_powers[*sn].mana_cost <= (int)p_ptr->concent))
256 #endif /* ALLOW_REPEAT -- TNB */
258 /* Nothing chosen yet */
264 for (i = 0; i < MAX_SNIPE_POWERS; i++)
266 if ((snipe_powers[i].min_lev <= plev) &&
267 ((only_browse) || (snipe_powers[i].mana_cost <= (int)p_ptr->concent)))
273 /* Build a prompt (accept all spells) */
276 (void)strnfmt(out_val, 78,
277 _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
278 p, I2A(0), I2A(num), p);
282 (void)strnfmt(out_val, 78,
283 _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
284 p, I2A(0), I2A(num), p);
287 /* Get a spell from the user */
288 choice = always_show_list ? ESCAPE : 1;
291 if(choice == ESCAPE) choice = ' ';
292 else if( !get_com(out_val, &choice, FALSE) )break;
295 if ((choice == ' ') || (choice == '*') || (choice == '?'))
305 /* Save the screen */
306 if (!only_browse) screen_save();
308 /* Display a list of spells */
311 put_str("名前", y, x + 5);
312 if (only_browse) put_str("Lv 集中度", y, x + 35);
314 put_str("Name", y, x + 5);
315 if (only_browse) put_str("Lv Pow", y, x + 35);
318 /* Dump the spells */
319 for (i = 0; i < MAX_SNIPE_POWERS; i++)
321 Term_erase(x, y + i + 1, 255);
323 /* Access the spell */
324 spell = snipe_powers[i];
325 if (spell.min_lev > plev) continue;
326 if (!only_browse && (spell.mana_cost > (int)p_ptr->concent)) continue;
328 /* Dump the spell --(-- */
330 sprintf(psi_desc, " %c) %-30s%2d %4d",
331 I2A(i), spell.name, spell.min_lev, spell.mana_cost);
333 sprintf(psi_desc, " %c) %-30s", I2A(i), spell.name);
334 prt(psi_desc, y + i + 1, x);
337 /* Clear the bottom line */
338 prt("", y + i + 1, x);
347 /* Restore the screen */
348 if (!only_browse) screen_load();
356 ask = isupper(choice);
359 if (ask) choice = (char)tolower(choice);
361 /* Extract request */
362 i = (islower(choice) ? A2I(choice) : -1);
364 /* Totally Illegal */
365 if ((i < 0) || (i > num) ||
366 (!only_browse &&(snipe_powers[i].mana_cost > (int)p_ptr->concent)))
372 /* Save the spell index */
373 spell = snipe_powers[i];
381 (void) strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), snipe_powers[i].name);
383 /* Belay that order */
384 if (!get_check(tmp_val)) continue;
391 /* Restore the screen */
392 if (redraw && !only_browse) screen_load();
395 p_ptr->window |= (PW_SPELL);
399 /* Abort if needed */
400 if (!flag) return (FALSE);
402 /* Save the choice */
405 #ifdef ALLOW_REPEAT /* TNB */
409 #endif /* ALLOW_REPEAT -- TNB */
416 * @brief スナイバー技能のスレイ倍率計算を行う /
417 * Calcurate magnification of snipe technics
418 * @param mult スナイバー技能のスレイ効果以前に算出している多要素の倍率(/10倍)
419 * @param m_ptr 目標となるモンスターの構造体参照ポインタ
420 * @return スレイの倍率(/10倍)
422 int tot_dam_aux_snipe(int mult, monster_type *m_ptr)
424 monster_race *r_ptr = &r_info[m_ptr->r_idx];
425 bool seen = is_seen(m_ptr);
430 if (r_ptr->flags3 & (RF3_HURT_LITE))
432 int n = 20 + p_ptr->concent;
433 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
434 if (mult < n) mult = n;
438 if (r_ptr->flagsr & RFR_IM_FIRE)
440 if (seen) r_ptr->r_flagsr |= RFR_IM_FIRE;
444 int n = 15 + (p_ptr->concent * 3);
445 if (mult < n) mult = n;
449 if (r_ptr->flagsr & RFR_IM_COLD)
451 if (seen) r_ptr->r_flagsr |= RFR_IM_COLD;
455 int n = 15 + (p_ptr->concent * 3);
456 if (mult < n) mult = n;
460 if (r_ptr->flagsr & RFR_IM_ELEC)
462 if (seen) r_ptr->r_flagsr |= RFR_IM_ELEC;
466 int n = 18 + (p_ptr->concent * 4);
467 if (mult < n) mult = n;
471 if (r_ptr->flags3 & RF3_HURT_ROCK)
473 int n = 15 + (p_ptr->concent * 2);
474 if (seen) r_ptr->r_flags3 |= RF3_HURT_ROCK;
475 if (mult < n) mult = n;
477 else if (r_ptr->flags3 & RF3_NONLIVING)
479 int n = 15 + (p_ptr->concent * 2);
480 if (seen) r_ptr->r_flags3 |= RF3_NONLIVING;
481 if (mult < n) mult = n;
485 if (r_ptr->flags3 & RF3_GOOD)
487 int n = 15 + (p_ptr->concent * 4);
488 if (seen) r_ptr->r_flags3 |= RF3_GOOD;
489 if (mult < n) mult = n;
493 if (r_ptr->flags3 & RF3_EVIL)
495 int n = 12 + (p_ptr->concent * 3);
496 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
497 if (r_ptr->flags3 & (RF3_HURT_LITE))
499 n += (p_ptr->concent * 3);
500 if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
502 if (mult < n) mult = n;
506 if (mult < 50) mult = 50;
515 * @brief スナイパー技能の発動 /
516 * do_cmd_cast calls this function if the player's class is 'snipe'.
517 * @param spell 発動する特殊技能のID
518 * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
520 static bool cast_sniper_spell(int spell)
522 object_type *o_ptr = &inventory[INVEN_BOW];
524 if (o_ptr->tval != TV_BOW)
526 msg_print(_("弓を装備していない!", "You wield no bow!"));
533 case 0: /* Concentration */
534 if (!snipe_concentrate()) return (FALSE);
535 p_ptr->energy_use = 100;
537 case 1: snipe_type = SP_LITE; break;
538 case 2: snipe_type = SP_AWAY; break;
539 case 3: snipe_type = SP_KILL_TRAP; break;
540 case 4: snipe_type = SP_FIRE; break;
541 case 5: snipe_type = SP_KILL_WALL; break;
542 case 6: snipe_type = SP_COLD; break;
543 case 7: snipe_type = SP_RUSH; break;
544 case 8: snipe_type = SP_PIERCE; break;
545 case 9: snipe_type = SP_EVILNESS; break;
546 case 10: snipe_type = SP_HOLYNESS; break;
547 case 11: snipe_type = SP_EXPLODE; break;
548 case 12: snipe_type = SP_DOUBLE; break;
549 case 13: snipe_type = SP_ELEC; break;
550 case 14: snipe_type = SP_NEEDLE; break;
551 case 15: snipe_type = SP_FINAL; break;
553 msg_print(_("なに?", "Zap?"));
564 * @brief スナイパー技能コマンドのメインルーチン /
567 void do_cmd_snipe(void)
573 /* not if confused */
576 msg_print(_("混乱していて集中できない!", "You are too confused!"));
580 /* not if hullucinated */
583 msg_print(_("幻覚が見えて集中できない!", "You are too hallucinated!"));
590 msg_print(_("頭が朦朧としていて集中できない!", "You are too stuned!"));
595 if (!get_snipe_power(&n, FALSE)) return;
600 cast = cast_sniper_spell(n);
604 p_ptr->energy_use = 100;
607 p_ptr->redraw |= (PR_HP | PR_MANA);
609 p_ptr->window |= (PW_PLAYER);
610 p_ptr->window |= (PW_SPELL);
614 * @brief スナイパー技能コマンドの表示 /
617 void do_cmd_snipe_browse(void)
628 if (!get_snipe_power(&n, TRUE))
634 /* Clear lines, position cursor (really should use strlen here) */
635 Term_erase(12, 22, 255);
636 Term_erase(12, 21, 255);
637 Term_erase(12, 20, 255);
638 Term_erase(12, 19, 255);
639 Term_erase(12, 18, 255);
641 roff_to_buf(snipe_tips[n], 62, temp, sizeof(temp));
642 for(j = 0, line = 19; temp[j]; j += (1 + strlen(&temp[j])))
644 prt(&temp[j], line, 15);