X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fspells2.c;h=35e95eceebaa0a3b5d4a8477e62ac28e0c5ab1fb;hb=c669f43936bbada842775ab38d3c67cac1982dc5;hp=4939345fb42f5339c9e4b7a357218917649315eb;hpb=55152c4da35a59498d59e8be2fdd60ea8150b79a;p=hengband%2Fhengband.git diff --git a/src/spells2.c b/src/spells2.c index 4939345fb..35e95ecee 100644 --- a/src/spells2.c +++ b/src/spells2.c @@ -13,2189 +13,567 @@ #include "angband.h" #include "grid.h" +#include "trap.h" +#include "monsterrace-hook.h" + /*! - * @brief 自己分析処理(Nethackからのアイデア) / self-knowledge... idea from nethack. - * @return なし - * @details - *
- * Useful for determining powers and
- * resistences of items.  It saves the screen, clears it, then starts listing
- * attributes, a screenful at a time.  (There are a LOT of attributes to
- * list.  It will probably take 2 or 3 screens for a powerful character whose
- * using several artifacts...) -CFT
- *
- * It is now a lot more efficient. -BEN-
- *
- * See also "identify_fully()".
- *
- * XXX XXX XXX Use the "show_file()" method, perhaps.
- * 
+ * @brief プレイヤー周辺の地形を感知する + * @param range 効果範囲 + * @param flag 特定地形ID + * @param known 地形から危険フラグを外すならTRUE + * @return 効力があった場合TRUEを返す */ -void self_knowledge(void) +static bool detect_feat_flag(POSITION range, int flag, bool known) { - int i = 0, j, k; + POSITION x, y; + bool detect = FALSE; + cave_type *c_ptr; + + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; + + /* Scan the current panel */ + for (y = 1; y < cur_hgt - 1; y++) + { + for (x = 1; x <= cur_wid - 1; x++) + { + int dist = distance(p_ptr->y, p_ptr->x, y, x); + if (dist > range) continue; + c_ptr = &cave[y][x]; + + /* Hack -- Safe */ + if (flag == FF_TRAP) + { + /* Mark as detected */ + if (dist <= range && known) + { + if (dist <= range - 1) c_ptr->info |= (CAVE_IN_DETECT); + + c_ptr->info &= ~(CAVE_UNSAFE); + + lite_spot(y, x); + } + } + + /* Detect flags */ + if (cave_have_flag_grid(c_ptr, flag)) + { + /* Detect secrets */ + disclose_grid(y, x); + + /* Hack -- Memorize */ + c_ptr->info |= (CAVE_MARK); + + lite_spot(y, x); - int v_nr = 0; - char v_string [8] [128]; - char s_string [6] [128]; + detect = TRUE; + } + } + } + return detect; +} - u32b flgs[TR_FLAG_SIZE]; - object_type *o_ptr; +/*! + * @brief プレイヤー周辺のトラップを感知する / Detect all traps on current panel + * @param range 効果範囲 + * @param known 感知外範囲を超える警告フラグを立てる場合TRUEを返す + * @return 効力があった場合TRUEを返す + */ +bool detect_traps(POSITION range, bool known) +{ + bool detect = detect_feat_flag(range, FF_TRAP, known); - char Dummy[80]; - char buf[2][80]; + if (known) p_ptr->dtrap = TRUE; - cptr info[220]; + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 0) detect = FALSE; + if (detect) + { + msg_print(_("トラップの存在を感じとった!", "You sense the presence of traps!")); + } + return detect; +} - int plev = p_ptr->lev; - int percent; +/*! + * @brief プレイヤー周辺のドアを感知する / Detect all doors on current panel + * @param range 効果範囲 + * @return 効力があった場合TRUEを返す + */ +bool detect_doors(POSITION range) +{ + bool detect = detect_feat_flag(range, FF_DOOR, TRUE); - for (j = 0; j < TR_FLAG_SIZE; j++) - flgs[j] = 0L; + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 0) detect = FALSE; + if (detect) + { + msg_print(_("ドアの存在を感じとった!", "You sense the presence of doors!")); + } + return detect; +} - p_ptr->knowledge |= (KNOW_STAT | KNOW_HPRATE); - strcpy(Dummy, ""); +/*! + * @brief プレイヤー周辺の階段を感知する / Detect all stairs on current panel + * @param range 効果範囲 + * @return 効力があった場合TRUEを返す + */ +bool detect_stairs(POSITION range) +{ + bool detect = detect_feat_flag(range, FF_STAIRS, TRUE); - percent = (int)(((long)p_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) / - (2 * p_ptr->hitdie + - ((PY_MAX_LEVEL - 1+3) * (p_ptr->hitdie + 1)))); + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 0) detect = FALSE; + if (detect) + { + msg_print(_("階段の存在を感じとった!", "You sense the presence of stairs!")); + } + return detect; +} - sprintf(Dummy, _("現在の体力ランク : %d/100", "Your current Life Rating is %d/100."), percent); - strcpy(buf[0], Dummy); - info[i++] = buf[0]; - info[i++] = ""; - chg_virtue(V_KNOWLEDGE, 1); - chg_virtue(V_ENLIGHTEN, 1); +/*! + * @brief プレイヤー周辺の地形財宝を感知する / Detect any treasure on the current panel + * @param range 効果範囲 + * @return 効力があった場合TRUEを返す + */ +bool detect_treasure(POSITION range) +{ + bool detect = detect_feat_flag(range, FF_HAS_GOLD, TRUE); - /* Acquire item flags from equipment */ - for (k = INVEN_RARM; k < INVEN_TOTAL; k++) + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 6) detect = FALSE; + if (detect) { - u32b tflgs[TR_FLAG_SIZE]; + msg_print(_("埋蔵された財宝の存在を感じとった!", "You sense the presence of buried treasure!")); + } + return detect; +} + + +/*! + * @brief プレイヤー周辺のアイテム財宝を感知する / Detect all "gold" objects on the current panel + * @param range 効果範囲 + * @return 効力があった場合TRUEを返す + */ +bool detect_objects_gold(POSITION range) +{ + OBJECT_IDX i; + POSITION y, x; + POSITION range2 = range; + + bool detect = FALSE; - o_ptr = &inventory[k]; + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range2 /= 3; + + /* Scan objects */ + for (i = 1; i < o_max; i++) + { + object_type *o_ptr = &o_list[i]; - /* Skip non-objects */ + /* Skip dead objects */ if (!o_ptr->k_idx) continue; - /* Extract the flags */ - object_flags(o_ptr, tflgs); - - /* Extract flags */ - for (j = 0; j < TR_FLAG_SIZE; j++) - flgs[j] |= tflgs[j]; - } - - info[i++] = _("能力の最大値", "Limits of maximum stats"); - - for (v_nr = 0; v_nr < 6; v_nr++) - { - char stat_desc[80]; - - sprintf(stat_desc, "%s 18/%d", stat_names[v_nr], p_ptr->stat_max_max[v_nr]-18); - - strcpy(s_string[v_nr], stat_desc); - - info[i++] = s_string[v_nr]; - } - info[i++] = ""; - - sprintf(Dummy, _("現在の属性 : %s(%ld)", "Your alighnment : %s(%ld)"), your_alignment(), (long int)p_ptr->align); - strcpy(buf[1], Dummy); - info[i++] = buf[1]; - for (v_nr = 0; v_nr < 8; v_nr++) - { - char vir_name [20]; - char vir_desc[80]; - int tester = p_ptr->virtues[v_nr]; - - strcpy(vir_name, virtue[(p_ptr->vir_types[v_nr])-1]); - - sprintf(vir_desc, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name); - if (tester < -100) - sprintf(vir_desc, _("[%s]の対極 (%d)", "You are the polar opposite of %s (%d)."), - vir_name, tester); - else if (tester < -80) - sprintf(vir_desc, _("[%s]の大敵 (%d)", "You are an arch-enemy of %s (%d)."), - vir_name, tester); - else if (tester < -60) - sprintf(vir_desc, _("[%s]の強敵 (%d)", "You are a bitter enemy of %s (%d)."), - vir_name, tester); - else if (tester < -40) - sprintf(vir_desc, _("[%s]の敵 (%d)", "You are an enemy of %s (%d)."), - vir_name, tester); - else if (tester < -20) - sprintf(vir_desc, _("[%s]の罪者 (%d)", "You have sinned against %s (%d)."), - vir_name, tester); - else if (tester < 0) - sprintf(vir_desc, _("[%s]の迷道者 (%d)", "You have strayed from the path of %s (%d)."), - vir_name, tester); - else if (tester == 0) - sprintf(vir_desc, _("[%s]の中立者 (%d)", "You are neutral to %s (%d)."), - vir_name, tester); - else if (tester < 20) - sprintf(vir_desc, _("[%s]の小徳者 (%d)", "You are somewhat virtuous in %s (%d)."), - vir_name, tester); - else if (tester < 40) - sprintf(vir_desc, _("[%s]の中徳者 (%d)", "You are virtuous in %s (%d)."), - vir_name, tester); - else if (tester < 60) - sprintf(vir_desc, _("[%s]の高徳者 (%d)", "You are very virtuous in %s (%d)."), - vir_name, tester); - else if (tester < 80) - sprintf(vir_desc, _("[%s]の覇者 (%d)", "You are a champion of %s (%d)."), - vir_name, tester); - else if (tester < 100) - sprintf(vir_desc, _("[%s]の偉大な覇者 (%d)", "You are a great champion of %s (%d)."), - vir_name, tester); - else - sprintf(vir_desc, _("[%s]の具現者 (%d)", "You are the living embodiment of %s (%d)."), - vir_name, tester); - - strcpy(v_string[v_nr], vir_desc); - - info[i++] = v_string[v_nr]; - } - info[i++] = ""; - - /* Racial powers... */ - if (p_ptr->mimic_form) - { - switch (p_ptr->mimic_form) - { - case MIMIC_DEMON: - case MIMIC_DEMON_LORD: - sprintf(Dummy, _("あなたは %d ダメージの地獄か火炎のブレスを吐くことができる。(%d MP)", - "You can nether breathe, dam. %d (cost %d)."), 3 * plev, 10+plev/3); + /* Skip held objects */ + if (o_ptr->held_m_idx) continue; - info[i++] = Dummy; - break; - case MIMIC_VAMPIRE: - if (plev > 1) - { - sprintf(Dummy, _("あなたは敵から %d-%d HP の生命力を吸収できる。(%d MP)", - "You can steal life from a foe, dam. %d-%d (cost %d)."), - plev + MAX(1, plev / 10), plev + plev * MAX(1, plev / 10), 1 + (plev / 3)); - info[i++] = Dummy; - } - break; + y = o_ptr->iy; + x = o_ptr->ix; + + /* Only detect nearby objects */ + if (distance(p_ptr->y, p_ptr->x, y, x) > range2) continue; + + /* Detect "gold" objects */ + if (o_ptr->tval == TV_GOLD) + { + o_ptr->marked |= OM_FOUND; + lite_spot(y, x); + detect = TRUE; } } - else + + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 6) detect = FALSE; + if (detect) { - switch (p_ptr->prace) + msg_print(_("財宝の存在を感じとった!", "You sense the presence of treasure!")); + } + + if (detect_monsters_string(range, "$")) { - case RACE_NIBELUNG: - case RACE_DWARF: - if (plev > 4) - info[i++] = _("あなたは罠とドアと階段を感知できる。(5 MP)", "You can find traps, doors and stairs (cost 5)."); - break; - case RACE_HOBBIT: - if (plev > 14) - { - info[i++] = _("あなたは食料を生成できる。(10 MP)", "You can produce food (cost 10)."); - } - break; - case RACE_GNOME: - if (plev > 4) - { - sprintf(Dummy, _("あなたは範囲 %d 以内にテレポートできる。(%d MP)", "You can teleport, range %d (cost %d)."), - (1 + plev), (5 + (plev / 5))); - info[i++] = Dummy; - } - break; - case RACE_HALF_ORC: - if (plev > 2) - info[i++] = _("あなたは恐怖を除去できる。(5 MP)", "You can remove fear (cost 5)."); - break; - case RACE_HALF_TROLL: - if (plev > 9) - info[i++] = _("あなたは狂暴化することができる。(12 MP) ", "You enter berserk fury (cost 12)."); - break; - case RACE_AMBERITE: - if (plev > 29) - info[i++] = _("あなたはシャドウシフトすることができる。(50 MP)", "You can Shift Shadows (cost 50)."); + detect = TRUE; + } + return (detect); +} - if (plev > 39) - info[i++] = _("あなたは「パターン」を心に描いて歩くことができる。(75 MP)", "You can mentally Walk the Pattern (cost 75)."); - break; - case RACE_BARBARIAN: - if (plev > 7) - info[i++] = _("あなたは狂暴化することができる。(10 MP) ", "You can enter berserk fury (cost 10)."); +/*! + * @brief 通常のアイテムオブジェクトを感知する / Detect all "normal" objects on the current panel + * @param range 効果範囲 + * @return 効力があった場合TRUEを返す + */ +bool detect_objects_normal(POSITION range) +{ + OBJECT_IDX i; + POSITION y, x; + POSITION range2 = range; - break; - case RACE_HALF_OGRE: - if (plev > 24) - info[i++] = _("あなたは爆発のルーンを仕掛けることができる。(35 MP)", "You can set an Explosive Rune (cost 35)."); + bool detect = FALSE; - break; - case RACE_HALF_GIANT: - if (plev > 19) - info[i++] = _("あなたは石の壁を壊すことができる。(10 MP)", "You can break stone walls (cost 10)."); - break; - case RACE_HALF_TITAN: - if (plev > 34) - info[i++] = _("あなたはモンスターをスキャンすることができる。(20 MP)", "You can probe monsters (cost 20)."); - break; - case RACE_CYCLOPS: - if (plev > 19) - { - sprintf(Dummy, _("あなたは %d ダメージの岩石を投げることができる。(15 MP)", - "You can throw a boulder, dam. %d (cost 15)."), 3 * plev); - info[i++] = Dummy; - } - break; - case RACE_YEEK: - if (plev > 14) - info[i++] = _("あなたは恐怖を呼び起こす叫び声を発することができる。(15 MP)", "You can make a terrifying scream (cost 15)."); - break; - case RACE_KLACKON: - if (plev > 8) - { - sprintf(Dummy, _("あなたは %d ダメージの酸を吹きかけることができる。(9 MP)", "You can spit acid, dam. %d (cost 9)."), plev); - info[i++] = Dummy; - } - break; - case RACE_KOBOLD: - if (plev > 11) - { - sprintf(Dummy, - _("あなたは %d ダメージの毒矢を投げることができる。(8 MP)", "You can throw a dart of poison, dam. %d (cost 8)."), plev); - info[i++] = Dummy; - } - break; - case RACE_DARK_ELF: - if (plev > 1) - { - sprintf(Dummy, _("あなたは %d ダメージのマジック・ミサイルの呪文を使える。(2 MP)", "You can cast a Magic Missile, dam %d (cost 2)."), - (3 + ((plev-1) / 5))); - info[i++] = Dummy; - } - break; - case RACE_DRACONIAN: - sprintf(Dummy, _("あなたは %d ダメージのブレスを吐くことができる。(%d MP)", "You can breathe, dam. %d (cost %d)."), 2 * plev, plev); - info[i++] = Dummy; - break; - case RACE_MIND_FLAYER: - if (plev > 14) - sprintf(Dummy, _("あなたは %d ダメージの精神攻撃をすることができる。(12 MP)", "You can mind blast your enemies, dam %d (cost 12)."), plev); - info[i++] = Dummy; - break; - case RACE_IMP: - if (plev > 29) - { - sprintf(Dummy, _("あなたは %d ダメージのファイア・ボールの呪文を使える。(15 MP)", "You can cast a Fire Ball, dam. %d (cost 15)."), plev); - info[i++] = Dummy; - } - else if (plev > 8) - { - sprintf(Dummy, _("あなたは %d ダメージのファイア・ボルトの呪文を使える。(15 MP)", "You can cast a Fire Bolt, dam. %d (cost 15)."), plev); - info[i++] = Dummy; - } - break; - case RACE_GOLEM: - if (plev > 19) - info[i++] = _("あなたは d20+30 ターンの間肌を石に変化させられる。(15 MP)", "You can turn your skin to stone, dur d20+30 (cost 15)."); - break; - case RACE_ZOMBIE: - case RACE_SKELETON: - if (plev > 29) - info[i++] = _("あなたは失った経験値を回復することができる。(30 MP)", "You can restore lost experience (cost 30)."); - break; - case RACE_VAMPIRE: - if (plev > 1) - { - sprintf(Dummy, _("あなたは敵から %d-%d HP の生命力を吸収できる。(%d MP)", "You can steal life from a foe, dam. %d-%d (cost %d)."), - plev + MAX(1, plev / 10), plev + plev * MAX(1, plev / 10), 1 + (plev / 3)); - info[i++] = Dummy; - } - break; - case RACE_SPECTRE: - if (plev > 3) - { - info[i++] = _("あなたは泣き叫んで敵を恐怖させることができる。(3 MP)", "You can wail to terrify your enemies (cost 3)."); - } - break; - case RACE_SPRITE: - if (plev > 11) - { - info[i++] = _("あなたは敵を眠らせる魔法の粉を投げることができる。(12 MP)", "You can throw magical dust which induces sleep (cost 12)."); - } - break; - case RACE_DEMON: - sprintf(Dummy, _("あなたは %d ダメージの地獄か火炎のブレスを吐くことができる。(%d MP)", - "You can breathe nether, dam. %d (cost %d)."), 3 * plev, 10+plev/3); + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range2 /= 3; - info[i++] = Dummy; - break; - case RACE_KUTAR: - if (plev > 19) - info[i++] = _("あなたは d20+30 ターンの間横に伸びることができる。(15 MP)", "You can expand horizontally, dur d20+30 (cost 15)."); - break; - case RACE_ANDROID: - if (plev < 10) - sprintf(Dummy, _("あなたは %d ダメージのレイガンを撃つことができる。(7 MP)", "You can fire a ray gun with damage %d (cost 7)."), - (plev + 1) / 2); - else if (plev < 25) - sprintf(Dummy, _("あなたは %d ダメージのブラスターを撃つことができる。(13 MP)", "You can fire a blaster with damage %d (cost 13)."), plev); - else if (plev < 35) - sprintf(Dummy, _("あなたは %d ダメージのバズーカを撃つことができる。(26 MP)", "You can fire a bazooka with damage %d (cost 26)."), plev * 2); - else if (plev < 45) - sprintf(Dummy, _("あなたは %d ダメージのビームキャノンを撃つことができる。(40 MP)", - "You can fire a beam cannon with damage %d (cost 40)."), plev * 2); - else - sprintf(Dummy, _("あなたは %d ダメージのロケットを撃つことができる。(60 MP)", - "You can fire a rocket with damage %d (cost 60)."), plev * 5); + /* Scan objects */ + for (i = 1; i < o_max; i++) + { + object_type *o_ptr = &o_list[i]; - info[i++] = Dummy; - break; - default: - break; + /* Skip dead objects */ + if (!o_ptr->k_idx) continue; + + /* Skip held objects */ + if (o_ptr->held_m_idx) continue; + + y = o_ptr->iy; + x = o_ptr->ix; + + /* Only detect nearby objects */ + if (distance(p_ptr->y, p_ptr->x, y, x) > range2) continue; + + /* Detect "real" objects */ + if (o_ptr->tval != TV_GOLD) + { + o_ptr->marked |= OM_FOUND; + lite_spot(y, x); + detect = TRUE; + } } + + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 6) detect = FALSE; + if (detect) + { + msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!")); } - switch(p_ptr->pclass) + if (detect_monsters_string(range, "!=?|/`")) { - case CLASS_WARRIOR: - if (plev > 39) - { - info[i++] = _("あなたはランダムな方向に対して数回攻撃することができる。(75 MP)", - "You can attack some random directions at a time (cost 75)."); - } - break; - case CLASS_HIGH_MAGE: - if (p_ptr->realm1 == REALM_HEX) break; - case CLASS_MAGE: - case CLASS_SORCERER: - if (plev > 24) - { - info[i++] = _("あなたはアイテムの魔力を吸収することができる。(1 MP)", - "You can absorb charges from an item (cost 1)."); - } - break; - case CLASS_PRIEST: - if (is_good_realm(p_ptr->realm1)) - { - if (plev > 34) - { - info[i++] = _("あなたは武器を祝福することができる。(70 MP)", "You can bless a weapon (cost 70)."); - } - } - else - { - if (plev > 41) - { - info[i++] = _("あなたは周りのすべてのモンスターを攻撃することができる。(40 MP)", "You can damages all monsters in sight (cost 40)."); - } - } - break; - case CLASS_ROGUE: - if (plev > 7) - { - info[i++] = _("あなたは攻撃して即座に逃げることができる。(12 MP)", "You can hit a monster and teleport at a time (cost 12)."); - } - break; - case CLASS_RANGER: - if (plev > 14) - { - info[i++] = _("あなたは怪物を調査することができる。(20 MP)", "You can prove monsters (cost 20)."); - } - break; - case CLASS_PALADIN: - if (is_good_realm(p_ptr->realm1)) - { - if (plev > 29) - { - info[i++] = _("あなたは聖なる槍を放つことができる。(30 MP)", "You can fires a holy spear (cost 30)."); - } - } - else - { - if (plev > 29) - { - info[i++] = _("あなたは生命力を減少させる槍を放つことができる。(30 MP)", "You can fires a spear which drains vitality (cost 30)."); - } - } - break; - case CLASS_WARRIOR_MAGE: - if (plev > 24) - { - info[i++] = _("あなたはHPをMPに変換することができる。(0 MP)", "You can convert HP to SP (cost 0)."); - info[i++] = _("あなたはMPをHPに変換することができる。(0 MP)", "You can convert SP to HP (cost 0)."); - } - break; - case CLASS_CHAOS_WARRIOR: - if (plev > 39) - { - info[i++] = _("あなたは周囲に怪物を惑わす光を発生させることができる。(50 MP)", - "You can radiate light which confuses nearby monsters (cost 50)."); - } - break; - case CLASS_MONK: - if (plev > 24) - { - info[i++] = _("あなたは構えることができる。(0 MP)", "You can assume a posture of special form (cost 0)."); - } - if (plev > 29) - { - info[i++] = _("あなたは通常の2倍の攻撃を行うことができる。(30 MP)", "You can perform double attacks in a time (cost 30)."); - } - break; - case CLASS_MINDCRAFTER: - case CLASS_FORCETRAINER: - if (plev > 14) - { - info[i++] = _("あなたは精神を集中してMPを回復させることができる。(0 MP)", "You can concentrate to regenerate your mana (cost 0)."); - } - break; - case CLASS_TOURIST: - info[i++] = _("あなたは写真を撮影することができる。(0 MP)", "You can take a photograph (cost 0)."); - if (plev > 24) - { - info[i++] = _("あなたはアイテムを完全に鑑定することができる。(20 MP)", "You can *identify* items (cost 20)."); - } - break; - case CLASS_IMITATOR: - if (plev > 29) - { - info[i++] = _("あなたは怪物の特殊攻撃をダメージ2倍でまねることができる。(100 MP)", - "You can imitate monster's special attacks with double damage (cost 100)."); - } - break; - case CLASS_BEASTMASTER: - info[i++] = _("あなたは1体の生命のあるモンスターを支配することができる。(レベル/4 MP)", "You can dominate a monster (cost level/4)."); - if (plev > 29) - { - info[i++] = _("あなたは視界内の生命のあるモンスターを支配することができる。((レベル+20)/2 MP)", - "You can dominate living monsters in sight (cost (level+20)/4)."); - } - break; - case CLASS_MAGIC_EATER: - info[i++] = _("あなたは杖/魔法棒/ロッドの魔力を自分のものにすることができる。", "You can absorb a staff, wand or rod itself."); - break; - case CLASS_RED_MAGE: - if (plev > 47) - { - info[i++] = _("あなたは1ターンに2回魔法を唱えることができる。(20 MP)", "You can cast two spells in one time (cost 20)."); - } - break; - case CLASS_SAMURAI: - { - info[i++] = _("あなたは精神を集中して気合いを溜めることができる。", "You can concentrate to regenerate your mana."); - } - if (plev > 24) - { - info[i++] = _("あなたは特殊な型で構えることができる。", "You can assume a posture of special form."); - } - break; - case CLASS_BLUE_MAGE: - info[i++] = _("あなたは相手に使われた魔法を学ぶことができる。", "You can study spells which your enemy casts on you."); - break; - case CLASS_CAVALRY: - if (plev > 9) - { - info[i++] = _("あなたはモンスターに乗って無理矢理ペットにすることができる。", "You can ride on a hostile monster forcibly to turn it into pet."); - } - break; - case CLASS_BERSERKER: - if (plev > 9) - { - info[i++] = _("あなたは街とダンジョンの間を行き来することができる。", "You can travel between town and the depths."); - } - break; - case CLASS_MIRROR_MASTER: - info[i++] = _("あなたは鏡を作り出すことができる。(2 MP)", "You can create a Mirror (cost 2)."); - info[i++] = _("あなたは鏡を割ることができる。(0 MP)", "You can break distant Mirrors (cost 0)."); - break; - case CLASS_NINJA: - if (plev > 19) - { - info[i++] = _("あなたは素早く移動することができる。", "You can walk extremery fast."); - } - break; - } - - if (p_ptr->muta1) - { - if (p_ptr->muta1 & MUT1_SPIT_ACID) - { - info[i++] = _("あなたは酸を吹きかけることができる。(ダメージ レベルX1)", "You can spit acid (dam lvl)."); - } - if (p_ptr->muta1 & MUT1_BR_FIRE) - { - info[i++] = _("あなたは炎のブレスを吐くことができる。(ダメージ レベルX2)", "You can breathe fire (dam lvl * 2)."); - } - if (p_ptr->muta1 & MUT1_HYPN_GAZE) - { - info[i++] = _("あなたの睨みは催眠効果をもつ。", "Your gaze is hypnotic."); - } - if (p_ptr->muta1 & MUT1_TELEKINES) - { - info[i++] = _("あなたは念動力をもっている。", "You are telekinetic."); - } - if (p_ptr->muta1 & MUT1_VTELEPORT) - { - info[i++] = _("あなたは自分の意思でテレポートできる。", "You can teleport at will."); - } - if (p_ptr->muta1 & MUT1_MIND_BLST) - { - info[i++] = _("あなたは精神攻撃を行える。(ダメージ 3~12d3)", "You can Mind Blast your enemies (3 to 12d3 dam)."); - } - if (p_ptr->muta1 & MUT1_RADIATION) - { - info[i++] = _("あなたは自分の意思で強い放射線を発生することができる。(ダメージ レベルX2)", "You can emit hard radiation at will (dam lvl * 2)."); - } - if (p_ptr->muta1 & MUT1_VAMPIRISM) - { - info[i++] = _("あなたは吸血鬼のように敵から生命力を吸収することができる。(ダメージ レベルX2)", - "You can drain life from a foe like a vampire (dam lvl * 2)."); - } - if (p_ptr->muta1 & MUT1_SMELL_MET) - { - info[i++] = _("あなたは近くにある貴金属をかぎ分けることができる。", "You can smell nearby precious metal."); - } - if (p_ptr->muta1 & MUT1_SMELL_MON) - { - info[i++] = _("あなたは近くのモンスターの存在をかぎ分けることができる。", "You can smell nearby monsters."); - } - if (p_ptr->muta1 & MUT1_BLINK) - { - info[i++] = _("あなたは短い距離をテレポートできる。", "You can teleport yourself short distances."); - } - if (p_ptr->muta1 & MUT1_EAT_ROCK) - { - info[i++] = _("あなたは硬い岩を食べることができる。", "You can consume solid rock."); - } - if (p_ptr->muta1 & MUT1_SWAP_POS) - { - info[i++] = _("あなたは他の者と場所を入れ替わることができる。", "You can switch locations with another being."); - } - if (p_ptr->muta1 & MUT1_SHRIEK) - { - info[i++] = _("あなたは身の毛もよだつ叫び声を発することができる。(ダメージ レベルX2)", "You can emit a horrible shriek (dam 2 * lvl)."); - } - if (p_ptr->muta1 & MUT1_ILLUMINE) - { - info[i++] = _("あなたは明るい光を放つことができる。", "You can emit bright light."); - } - if (p_ptr->muta1 & MUT1_DET_CURSE) - { - info[i++] = _("あなたは邪悪な魔法の危険を感じとることができる。", "You can feel the danger of evil magic."); - } - if (p_ptr->muta1 & MUT1_BERSERK) - { - info[i++] = _("あなたは自分の意思で狂乱戦闘状態になることができる。", "You can drive yourself into a berserk frenzy."); - } - if (p_ptr->muta1 & MUT1_POLYMORPH) - { - info[i++] = _("あなたは自分の意志で変化できる。", "You can polymorph yourself at will."); - } - if (p_ptr->muta1 & MUT1_MIDAS_TCH) - { - info[i++] = _("あなたは通常アイテムを金に変えることができる。", "You can turn ordinary items to gold."); - } - if (p_ptr->muta1 & MUT1_GROW_MOLD) - { - info[i++] = _("あなたは周囲にキノコを生やすことができる。", "You can cause mold to grow near you."); - } - if (p_ptr->muta1 & MUT1_RESIST) - { - info[i++] = _("あなたは元素の攻撃に対して身を硬くすることができる。", "You can harden yourself to the ravages of the elements."); - } - if (p_ptr->muta1 & MUT1_EARTHQUAKE) - { - info[i++] = _("あなたは周囲のダンジョンを崩壊させることができる。", "You can bring down the dungeon around your ears."); - } - if (p_ptr->muta1 & MUT1_EAT_MAGIC) - { - info[i++] = _("あなたは魔法のエネルギーを自分の物として使用できる。", "You can consume magic energy for your own use."); - } - if (p_ptr->muta1 & MUT1_WEIGH_MAG) - { - info[i++] = _("あなたは自分に影響を与える魔法の力を感じることができる。", "You can feel the strength of the magics affecting you."); - } - if (p_ptr->muta1 & MUT1_STERILITY) - { - info[i++] = _("あなたは集団的生殖不能を起こすことができる。", "You can cause mass impotence."); - } - if (p_ptr->muta1 & MUT1_PANIC_HIT) - { - info[i++] = _("あなたは攻撃した後身を守るため逃げることができる。", "You can run for your life after hitting something."); - } - if (p_ptr->muta1 & MUT1_DAZZLE) - { - info[i++] = _("あなたは混乱と盲目を引き起こす放射能を発生することができる。 ", "You can emit confusing, blinding radiation."); - } - if (p_ptr->muta1 & MUT1_LASER_EYE) - { - info[i++] = _("あなたは目からレーザー光線を発することができる。(ダメージ レベルX2)", "Your eyes can fire laser beams (dam 2 * lvl)."); - } - if (p_ptr->muta1 & MUT1_RECALL) - { - info[i++] = _("あなたは街とダンジョンの間を行き来することができる。", "You can travel between town and the depths."); - } - if (p_ptr->muta1 & MUT1_BANISH) - { - info[i++] = _("あなたは邪悪なモンスターを地獄に落とすことができる。", "You can send evil creatures directly to Hell."); - } - if (p_ptr->muta1 & MUT1_COLD_TOUCH) - { - info[i++] = _("あなたは敵を触って凍らせることができる。(ダメージ レベルX3)", "You can freeze things with a touch (dam 3 * lvl)."); - } - if (p_ptr->muta1 & MUT1_LAUNCHER) - { - info[i++] = _("あなたはアイテムを力強く投げることができる。", "You can hurl objects with great force."); - } - } - - if (p_ptr->muta2) - { - if (p_ptr->muta2 & MUT2_BERS_RAGE) - { - info[i++] = _("あなたは狂戦士化の発作を起こす。", "You are subject to berserker fits."); - } - if (p_ptr->muta2 & MUT2_COWARDICE) - { - info[i++] = _("あなたは時々臆病になる。", "You are subject to cowardice."); - } - if (p_ptr->muta2 & MUT2_RTELEPORT) - { - info[i++] = _("あなたはランダムにテレポートする。", "You are teleporting randomly."); - } - if (p_ptr->muta2 & MUT2_ALCOHOL) - { - info[i++] = _("あなたの体はアルコールを分泌する。", "Your body produces alcohol."); - } - if (p_ptr->muta2 & MUT2_HALLU) - { - info[i++] = _("あなたは幻覚を引き起こす精神錯乱に侵されている。", "You have a hallucinatory insanity."); - } - if (p_ptr->muta2 & MUT2_FLATULENT) - { - info[i++] = _("あなたは制御できない強烈な屁をこく。", "You are subject to uncontrollable flatulence."); - } - if (p_ptr->muta2 & MUT2_PROD_MANA) - { - info[i++] = _("あなたは制御不能な魔法のエネルギーを発している。", "You are producing magical energy uncontrollably."); - } - if (p_ptr->muta2 & MUT2_ATT_DEMON) - { - info[i++] = _("あなたはデーモンを引きつける。", "You attract demons."); - } - if (p_ptr->muta2 & MUT2_SCOR_TAIL) - { - info[i++] = _("あなたはサソリの尻尾が生えている。(毒、ダメージ 3d7)", "You have a scorpion tail (poison, 3d7)."); - } - if (p_ptr->muta2 & MUT2_HORNS) - { - info[i++] = _("あなたは角が生えている。(ダメージ 2d6)", "You have horns (dam. 2d6)."); - } - if (p_ptr->muta2 & MUT2_BEAK) - { - info[i++] = _("あなたはクチバシが生えている。(ダメージ 2d4)", "You have a beak (dam. 2d4)."); - } - if (p_ptr->muta2 & MUT2_SPEED_FLUX) - { - info[i++] = _("あなたはランダムに早く動いたり遅く動いたりする。", "You move faster or slower randomly."); - } - if (p_ptr->muta2 & MUT2_BANISH_ALL) - { - info[i++] = _("あなたは時々近くのモンスターを消滅させる。", "You sometimes cause nearby creatures to vanish."); - } - if (p_ptr->muta2 & MUT2_EAT_LIGHT) - { - info[i++] = _("あなたは時々周囲の光を吸収して栄養にする。", "You sometimes feed off of the light around you."); - } - if (p_ptr->muta2 & MUT2_TRUNK) - { - info[i++] = _("あなたは象のような鼻を持っている。(ダメージ 1d4)", "You have an elephantine trunk (dam 1d4)."); - } - if (p_ptr->muta2 & MUT2_ATT_ANIMAL) - { - info[i++] = _("あなたは動物を引きつける。", "You attract animals."); - } - if (p_ptr->muta2 & MUT2_TENTACLES) - { - info[i++] = _("あなたは邪悪な触手を持っている。(ダメージ 2d5)", "You have evil looking tentacles (dam 2d5)."); - } - if (p_ptr->muta2 & MUT2_RAW_CHAOS) - { - info[i++] = _("あなたはしばしば純カオスに包まれる。", "You occasionally are surrounded with raw chaos."); - } - if (p_ptr->muta2 & MUT2_NORMALITY) - { - info[i++] = _("あなたは変異していたが、回復してきている。", "You may be mutated, but you're recovering."); - } - if (p_ptr->muta2 & MUT2_WRAITH) - { - info[i++] = _("あなたの肉体は幽体化したり実体化したりする。", "You fade in and out of physical reality."); - } - if (p_ptr->muta2 & MUT2_POLY_WOUND) - { - info[i++] = _("あなたの健康はカオスの力に影響を受ける。", "Your health is subject to chaotic forces."); - } - if (p_ptr->muta2 & MUT2_WASTING) - { - info[i++] = _("あなたは衰弱する恐ろしい病気にかかっている。", "You have a horrible wasting disease."); - } - if (p_ptr->muta2 & MUT2_ATT_DRAGON) - { - info[i++] = _("あなたはドラゴンを引きつける。", "You attract dragons."); - } - if (p_ptr->muta2 & MUT2_WEIRD_MIND) - { - info[i++] = _("あなたの精神はランダムに拡大したり縮小したりしている。", "Your mind randomly expands and contracts."); - } - if (p_ptr->muta2 & MUT2_NAUSEA) - { - info[i++] = _("あなたの胃は非常に落ち着きがない。", "You have a seriously upset stomach."); - } - if (p_ptr->muta2 & MUT2_CHAOS_GIFT) - { - info[i++] = _("あなたはカオスの守護悪魔から褒美をうけとる。", "Chaos deities give you gifts."); - } - if (p_ptr->muta2 & MUT2_WALK_SHAD) - { - info[i++] = _("あなたはしばしば他の「影」に迷い込む。", "You occasionally stumble into other shadows."); - } - if (p_ptr->muta2 & MUT2_WARNING) - { - info[i++] = _("あなたは敵に関する警告を感じる。", "You receive warnings about your foes."); - } - if (p_ptr->muta2 & MUT2_INVULN) - { - info[i++] = _("あなたは時々負け知らずな気分になる。", "You occasionally feel invincible."); - } - if (p_ptr->muta2 & MUT2_SP_TO_HP) - { - info[i++] = _("あなたは時々血が筋肉にどっと流れる。", "Your blood sometimes rushes to your muscles."); - } - if (p_ptr->muta2 & MUT2_HP_TO_SP) - { - info[i++] = _("あなたは時々頭に血がどっと流れる。", "Your blood sometimes rushes to your head."); - } - if (p_ptr->muta2 & MUT2_DISARM) - { - info[i++] = _("あなたはよくつまづいて物を落とす。", "You occasionally stumble and drop things."); - } - } - - if (p_ptr->muta3) - { - if (p_ptr->muta3 & MUT3_HYPER_STR) - { - info[i++] = _("あなたは超人的に強い。(腕力+4)", "You are superhumanly strong (+4 STR)."); - } - if (p_ptr->muta3 & MUT3_PUNY) - { - info[i++] = _("あなたは虚弱だ。(腕力-4)", "You are puny (-4 STR)."); - } - if (p_ptr->muta3 & MUT3_HYPER_INT) - { - info[i++] = _("あなたの脳は生体コンピュータだ。(知能&賢さ+4)", "Your brain is a living computer (+4 INT/WIS)."); - } - if (p_ptr->muta3 & MUT3_MORONIC) - { - info[i++] = _("あなたは精神薄弱だ。(知能&賢さ-4)", "You are moronic (-4 INT/WIS)."); - } - if (p_ptr->muta3 & MUT3_RESILIENT) - { - info[i++] = _("あなたは非常にタフだ。(耐久+4)", "You are very resilient (+4 CON)."); - } - if (p_ptr->muta3 & MUT3_XTRA_FAT) - { - info[i++] = _("あなたは極端に太っている。(耐久+2,スピード-2)", "You are extremely fat (+2 CON, -2 speed)."); - } - if (p_ptr->muta3 & MUT3_ALBINO) - { - info[i++] = _("あなたはアルビノだ。(耐久-4)", "You are albino (-4 CON)."); - } - if (p_ptr->muta3 & MUT3_FLESH_ROT) - { - info[i++] = _("あなたの肉体は腐敗している。(耐久-2,魅力-1)", "Your flesh is rotting (-2 CON, -1 CHR)."); - } - if (p_ptr->muta3 & MUT3_SILLY_VOI) - { - info[i++] = _("あなたの声は間抜けなキーキー声だ。(魅力-4)", "Your voice is a silly squeak (-4 CHR)."); - } - if (p_ptr->muta3 & MUT3_BLANK_FAC) - { - info[i++] = _("あなたはのっぺらぼうだ。(魅力-1)", "Your face is featureless (-1 CHR)."); - } - if (p_ptr->muta3 & MUT3_ILL_NORM) - { - info[i++] = _("あなたは幻影に覆われている。", "Your appearance is masked with illusion."); - } - if (p_ptr->muta3 & MUT3_XTRA_EYES) - { - info[i++] = _("あなたは余分に二つの目を持っている。(探索+15)", "You have an extra pair of eyes (+15 search)."); - } - if (p_ptr->muta3 & MUT3_MAGIC_RES) - { - info[i++] = _("あなたは魔法への耐性をもっている。", "You are resistant to magic."); - } - if (p_ptr->muta3 & MUT3_XTRA_NOIS) - { - info[i++] = _("あなたは変な音を発している。(隠密-3)", "You make a lot of strange noise (-3 stealth)."); - } - if (p_ptr->muta3 & MUT3_INFRAVIS) - { - info[i++] = _("あなたは素晴らしい赤外線視力を持っている。(+3)", "You have remarkable infravision (+3)."); - } - if (p_ptr->muta3 & MUT3_XTRA_LEGS) - { - info[i++] = _("あなたは余分に二本の足が生えている。(加速+3)", "You have an extra pair of legs (+3 speed)."); - } - if (p_ptr->muta3 & MUT3_SHORT_LEG) - { - info[i++] = _("あなたの足は短い突起だ。(加速-3)", "Your legs are short stubs (-3 speed)."); - } - if (p_ptr->muta3 & MUT3_ELEC_TOUC) - { - info[i++] = _("あなたの血管には電流が流れている。", "Electricity is running through your veins."); - } - if (p_ptr->muta3 & MUT3_FIRE_BODY) - { - info[i++] = _("あなたの体は炎につつまれている。", "Your body is enveloped in flames."); - } - if (p_ptr->muta3 & MUT3_WART_SKIN) - { - info[i++] = _("あなたの肌はイボに被われている。(魅力-2, AC+5)", "Your skin is covered with warts (-2 CHR, +5 AC)."); - } - if (p_ptr->muta3 & MUT3_SCALES) - { - info[i++] = _("あなたの肌は鱗になっている。(魅力-1, AC+10)", "Your skin has turned into scales (-1 CHR, +10 AC)."); - } - if (p_ptr->muta3 & MUT3_IRON_SKIN) - { - info[i++] = _("あなたの肌は鉄でできている。(器用-1, AC+25)", "Your skin is made of steel (-1 DEX, +25 AC)."); - } - if (p_ptr->muta3 & MUT3_WINGS) - { - info[i++] = _("あなたは羽を持っている。", "You have wings."); - } - if (p_ptr->muta3 & MUT3_FEARLESS) - { - /* Unnecessary */ - } - if (p_ptr->muta3 & MUT3_REGEN) - { - /* Unnecessary */ - } - if (p_ptr->muta3 & MUT3_ESP) - { - /* Unnecessary */ - } - if (p_ptr->muta3 & MUT3_LIMBER) - { - info[i++] = _("あなたの体は非常にしなやかだ。(器用+3)", "Your body is very limber (+3 DEX)."); - } - if (p_ptr->muta3 & MUT3_ARTHRITIS) - { - info[i++] = _("あなたはいつも関節に痛みを感じている。(器用-3)", "Your joints ache constantly (-3 DEX)."); - } - if (p_ptr->muta3 & MUT3_VULN_ELEM) - { - info[i++] = _("あなたは元素の攻撃に弱い。", "You are susceptible to damage from the elements."); - } - if (p_ptr->muta3 & MUT3_MOTION) - { - info[i++] = _("あなたの動作は正確で力強い。(隠密+1)", "Your movements are precise and forceful (+1 STL)."); - } - if (p_ptr->muta3 & MUT3_GOOD_LUCK) - { - info[i++] = _("あなたは白いオーラにつつまれている。", "There is a white aura surrounding you."); - } - if (p_ptr->muta3 & MUT3_BAD_LUCK) - { - info[i++] = _("あなたは黒いオーラにつつまれている。", "There is a black aura surrounding you."); - } - } - - if (p_ptr->blind) - { - info[i++] = _("あなたは目が見えない。", "You cannot see."); - } - if (p_ptr->confused) - { - info[i++] = _("あなたは混乱している。", "You are confused."); - } - if (p_ptr->afraid) - { - info[i++] = _("あなたは恐怖に侵されている。", "You are terrified."); - } - if (p_ptr->cut) - { - info[i++] = _("あなたは出血している。", "You are bleeding."); - } - if (p_ptr->stun) - { - info[i++] = _("あなたはもうろうとしている。", "You are stunned."); - } - if (p_ptr->poisoned) - { - info[i++] = _("あなたは毒に侵されている。", "You are poisoned."); - } - if (p_ptr->image) - { - info[i++] = _("あなたは幻覚を見ている。", "You are hallucinating."); - } - if (p_ptr->cursed & TRC_TY_CURSE) - { - info[i++] = _("あなたは邪悪な怨念に包まれている。", "You carry an ancient foul curse."); - } - if (p_ptr->cursed & TRC_AGGRAVATE) - { - info[i++] = _("あなたはモンスターを怒らせている。", "You aggravate monsters."); - } - if (p_ptr->cursed & TRC_DRAIN_EXP) - { - info[i++] = _("あなたは経験値を吸われている。", "You are drained."); - } - if (p_ptr->cursed & TRC_SLOW_REGEN) - { - info[i++] = _("あなたの回復力は非常に遅い。", "You regenerate slowly."); - } - if (p_ptr->cursed & TRC_ADD_L_CURSE) - { - info[i++] = _("あなたの弱い呪いは増える。","Your weak curses multiply."); /* 暫定的 -- henkma */ - } - if (p_ptr->cursed & TRC_ADD_H_CURSE) - { - info[i++] = _("あなたの強い呪いは増える。","Your heavy curses multiply."); /* 暫定的 -- henkma */ - } - if (p_ptr->cursed & TRC_CALL_ANIMAL) - { - info[i++] = _("あなたは動物に狙われている。", "You attract animals."); - } - if (p_ptr->cursed & TRC_CALL_DEMON) - { - info[i++] = _("あなたは悪魔に狙われている。", "You attract demons."); - } - if (p_ptr->cursed & TRC_CALL_DRAGON) - { - info[i++] = _("あなたはドラゴンに狙われている。", "You attract dragons."); - } - if (p_ptr->cursed & TRC_COWARDICE) - { - info[i++] = _("あなたは時々臆病になる。", "You are subject to cowardice."); - } - if (p_ptr->cursed & TRC_TELEPORT) - { - info[i++] = _("あなたの位置はひじょうに不安定だ。", "Your position is very uncertain."); - } - if (p_ptr->cursed & TRC_LOW_MELEE) - { - info[i++] = _("あなたの武器は攻撃を外しやすい。", "Your weapon causes you to miss blows."); - } - if (p_ptr->cursed & TRC_LOW_AC) - { - info[i++] = _("あなたは攻撃を受けやすい。", "You are subject to be hit."); - } - if (p_ptr->cursed & TRC_LOW_MAGIC) - { - info[i++] = _("あなたは魔法を失敗しやすい。", "You are subject to fail spellcasting."); - } - if (p_ptr->cursed & TRC_FAST_DIGEST) - { - info[i++] = _("あなたはすぐお腹がへる。", "You have a good appetite."); - } - if (p_ptr->cursed & TRC_DRAIN_HP) - { - info[i++] = _("あなたは体力を吸われている。", "You are drained."); - } - if (p_ptr->cursed & TRC_DRAIN_MANA) - { - info[i++] = _("あなたは魔力を吸われている。", "You brain is drained."); - } - if (IS_BLESSED()) - { - info[i++] = _("あなたは高潔さを感じている。", "You feel rightous."); - } - if (IS_HERO()) - { - info[i++] = _("あなたはヒーロー気分だ。", "You feel heroic."); - } - if (p_ptr->shero) - { - info[i++] = _("あなたは戦闘狂だ。", "You are in a battle rage."); - } - if (p_ptr->protevil) - { - info[i++] = _("あなたは邪悪なる存在から守られている。", "You are protected from evil."); - } - if (p_ptr->shield) - { - info[i++] = _("あなたは神秘のシールドで守られている。", "You are protected by a mystic shield."); - } - if (IS_INVULN()) - { - info[i++] = _("あなたは現在傷つかない。", "You are temporarily invulnerable."); - } - if (p_ptr->wraith_form) - { - info[i++] = _("あなたは一時的に幽体化している。", "You are temporarily incorporeal."); - } - if (p_ptr->special_attack & ATTACK_CONFUSE) - { - info[i++] = _("あなたの手は赤く輝いている。", "Your hands are glowing dull red."); - } - if (p_ptr->special_attack & ATTACK_FIRE) - { - info[i++] = _("あなたの手は火炎に覆われている。", "You can strike the enemy with flame."); - } - if (p_ptr->special_attack & ATTACK_COLD) - { - info[i++] = _("あなたの手は冷気に覆われている。", "You can strike the enemy with cold."); - } - if (p_ptr->special_attack & ATTACK_ACID) - { - info[i++] = _("あなたの手は酸に覆われている。", "You can strike the enemy with acid."); - } - if (p_ptr->special_attack & ATTACK_ELEC) - { - info[i++] = _("あなたの手は電撃に覆われている。", "You can strike the enemy with electoric shock."); - } - if (p_ptr->special_attack & ATTACK_POIS) - { - info[i++] = _("あなたの手は毒に覆われている。", "You can strike the enemy with poison."); - } - switch (p_ptr->action) - { - case ACTION_SEARCH: - info[i++] = _("あなたはひじょうに注意深く周囲を見渡している。", "You are looking around very carefully."); - break; - } - if (p_ptr->new_spells) - { - info[i++] = _("あなたは呪文や祈りを学ぶことができる。", "You can learn some spells/prayers."); - } - if (p_ptr->word_recall) - { - info[i++] = _("あなたはすぐに帰還するだろう。", "You will soon be recalled."); - } - if (p_ptr->alter_reality) - { - info[i++] = _("あなたはすぐにこの世界を離れるだろう。", "You will soon be altered."); - } - if (p_ptr->see_infra) - { - info[i++] = _("あなたの瞳は赤外線に敏感である。", "Your eyes are sensitive to infrared light."); - } - if (p_ptr->see_inv) - { - info[i++] = _("あなたは透明なモンスターを見ることができる。", "You can see invisible creatures."); - } - if (p_ptr->levitation) - { - info[i++] = _("あなたは飛ぶことができる。", "You can fly."); - } - if (p_ptr->free_act) - { - info[i++] = _("あなたは麻痺知らずの効果を持っている。", "You have free action."); - } - if (p_ptr->regenerate) - { - info[i++] = _("あなたは素早く体力を回復する。", "You regenerate quickly."); - } - if (p_ptr->slow_digest) - { - info[i++] = _("あなたは食欲が少ない。", "Your appetite is small."); - } - if (p_ptr->telepathy) - { - info[i++] = _("あなたはテレパシー能力を持っている。", "You have ESP."); - } - if (p_ptr->esp_animal) - { - info[i++] = _("あなたは自然界の生物の存在を感じる能力を持っている。", "You sense natural creatures."); - } - if (p_ptr->esp_undead) - { - info[i++] = _("あなたはアンデッドの存在を感じる能力を持っている。", "You sense undead."); - } - if (p_ptr->esp_demon) - { - info[i++] = _("あなたは悪魔の存在を感じる能力を持っている。", "You sense demons."); - } - if (p_ptr->esp_orc) - { - info[i++] = _("あなたはオークの存在を感じる能力を持っている。", "You sense orcs."); - } - if (p_ptr->esp_troll) - { - info[i++] = _("あなたはトロルの存在を感じる能力を持っている。", "You sense trolls."); - } - if (p_ptr->esp_giant) - { - info[i++] = _("あなたは巨人の存在を感じる能力を持っている。", "You sense giants."); - } - if (p_ptr->esp_dragon) - { - info[i++] = _("あなたはドラゴンの存在を感じる能力を持っている。", "You sense dragons."); - } - if (p_ptr->esp_human) - { - info[i++] = _("あなたは人間の存在を感じる能力を持っている。", "You sense humans."); - } - if (p_ptr->esp_evil) - { - info[i++] = _("あなたは邪悪な生き物の存在を感じる能力を持っている。", "You sense evil creatures."); - } - if (p_ptr->esp_good) - { - info[i++] = _("あなたは善良な生き物の存在を感じる能力を持っている。", "You sense good creatures."); - } - if (p_ptr->esp_nonliving) - { - info[i++] = _("あなたは活動する無生物体の存在を感じる能力を持っている。", "You sense non-living creatures."); - } - if (p_ptr->esp_unique) - { - info[i++] = _("あなたは特別な強敵の存在を感じる能力を持っている。", "You sense unique monsters."); - } - if (p_ptr->hold_exp) - { - info[i++] = _("あなたは自己の経験値をしっかりと維持する。", "You have a firm hold on your experience."); - } - if (p_ptr->reflect) - { - info[i++] = _("あなたは矢の呪文を反射する。", "You reflect bolt spells."); - } - if (p_ptr->sh_fire) - { - info[i++] = _("あなたは炎のオーラに包まれている。", "You are surrounded with a fiery aura."); - } - if (p_ptr->sh_elec) - { - info[i++] = _("あなたは電気に包まれている。", "You are surrounded with electricity."); - } - if (p_ptr->sh_cold) - { - info[i++] = _("あなたは冷気のオーラに包まれている。", "You are surrounded with an aura of coldness."); - } - if (p_ptr->tim_sh_holy) - { - info[i++] = _("あなたは聖なるオーラに包まれている。", "You are surrounded with a holy aura."); - } - if (p_ptr->tim_sh_touki) - { - info[i++] = _("あなたは闘気のオーラに包まれている。", "You are surrounded with a energy aura."); - } - if (p_ptr->anti_magic) - { - info[i++] = _("あなたは反魔法シールドに包まれている。", "You are surrounded by an anti-magic shell."); - } - if (p_ptr->anti_tele) - { - info[i++] = _("あなたはテレポートできない。", "You cannot teleport."); - } - if (p_ptr->lite) - { - info[i++] = _("あなたの身体は光っている。", "You are carrying a permanent light."); - } - if (p_ptr->warning) - { - info[i++] = _("あなたは行動の前に危険を察知することができる。", "You will be warned before dangerous actions."); - } - if (p_ptr->dec_mana) - { - info[i++] = _("あなたは少ない消費魔力で魔法を唱えることができる。", "You can cast spells with fewer mana points."); - } - if (p_ptr->easy_spell) - { - info[i++] = _("あなたは低い失敗率で魔法を唱えることができる。", "Fail rate of your magic is decreased."); - } - if (p_ptr->heavy_spell) - { - info[i++] = _("あなたは高い失敗率で魔法を唱えなければいけない。", "Fail rate of your magic is increased."); - } - if (p_ptr->mighty_throw) - { - info[i++] = _("あなたは強く物を投げる。", "You can throw objects powerfully."); - } - - if (p_ptr->immune_acid) - { - info[i++] = _("あなたは酸に対する完全なる免疫を持っている。", "You are completely immune to acid."); - } - else if (p_ptr->resist_acid && IS_OPPOSE_ACID()) - { - info[i++] = _("あなたは酸への強力な耐性を持っている。", "You resist acid exceptionally well."); - } - else if (p_ptr->resist_acid || IS_OPPOSE_ACID()) - { - info[i++] = _("あなたは酸への耐性を持っている。", "You are resistant to acid."); - } - - if (p_ptr->immune_elec) - { - info[i++] = _("あなたは電撃に対する完全なる免疫を持っている。", "You are completely immune to lightning."); - } - else if (p_ptr->resist_elec && IS_OPPOSE_ELEC()) - { - info[i++] = _("あなたは電撃への強力な耐性を持っている。", "You resist lightning exceptionally well."); - } - else if (p_ptr->resist_elec || IS_OPPOSE_ELEC()) - { - info[i++] = _("あなたは電撃への耐性を持っている。", "You are resistant to lightning."); - } - - if (prace_is_(RACE_ANDROID) && !p_ptr->immune_elec) - { - info[i++] = _("あなたは電撃に弱い。", "You are susceptible to damage from lightning."); - } - - if (p_ptr->immune_fire) - { - info[i++] = _("あなたは火に対する完全なる免疫を持っている。", "You are completely immune to fire."); - } - else if (p_ptr->resist_fire && IS_OPPOSE_FIRE()) - { - info[i++] = _("あなたは火への強力な耐性を持っている。", "You resist fire exceptionally well."); - } - else if (p_ptr->resist_fire || IS_OPPOSE_FIRE()) - { - info[i++] = _("あなたは火への耐性を持っている。", "You are resistant to fire."); - } - - if (prace_is_(RACE_ENT) && !p_ptr->immune_fire) - { - info[i++] = _("あなたは火に弱い。", "You are susceptible to damage from fire."); - } - - if (p_ptr->immune_cold) - { - info[i++] = _("あなたは冷気に対する完全なる免疫を持っている。", "You are completely immune to cold."); - } - else if (p_ptr->resist_cold && IS_OPPOSE_COLD()) - { - info[i++] = _("あなたは冷気への強力な耐性を持っている。", "You resist cold exceptionally well."); - } - else if (p_ptr->resist_cold || IS_OPPOSE_COLD()) - { - info[i++] = _("あなたは冷気への耐性を持っている。", "You are resistant to cold."); - } - - if (p_ptr->resist_pois && IS_OPPOSE_POIS()) - { - info[i++] = _("あなたは毒への強力な耐性を持っている。", "You resist poison exceptionally well."); - } - else if (p_ptr->resist_pois || IS_OPPOSE_POIS()) - { - info[i++] = _("あなたは毒への耐性を持っている。", "You are resistant to poison."); - } - - if (p_ptr->resist_lite) - { - info[i++] = _("あなたは閃光への耐性を持っている。", "You are resistant to bright light."); - } - - if (prace_is_(RACE_VAMPIRE) || prace_is_(RACE_S_FAIRY) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) - { - info[i++] = _("あなたは閃光に弱い。", "You are susceptible to damage from bright light."); - } - - if (prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE) || p_ptr->wraith_form) - { - info[i++] = _("あなたは暗黒に対する完全なる免疫を持っている。", "You are completely immune to darkness."); - } - - else if (p_ptr->resist_dark) - { - info[i++] = _("あなたは暗黒への耐性を持っている。", "You are resistant to darkness."); - } - if (p_ptr->resist_conf) - { - info[i++] = _("あなたは混乱への耐性を持っている。", "You are resistant to confusion."); - } - if (p_ptr->resist_sound) - { - info[i++] = _("あなたは音波の衝撃への耐性を持っている。", "You are resistant to sonic attacks."); - } - if (p_ptr->resist_disen) - { - info[i++] = _("あなたは劣化への耐性を持っている。", "You are resistant to disenchantment."); - } - if (p_ptr->resist_chaos) - { - info[i++] = _("あなたはカオスの力への耐性を持っている。", "You are resistant to chaos."); - } - if (p_ptr->resist_shard) - { - info[i++] = _("あなたは破片の攻撃への耐性を持っている。", "You are resistant to blasts of shards."); - } - if (p_ptr->resist_nexus) - { - info[i++] = _("あなたは因果混乱の攻撃への耐性を持っている。", "You are resistant to nexus attacks."); - } - - if (prace_is_(RACE_SPECTRE)) - { - info[i++] = _("あなたは地獄の力を吸収できる。", "You can drain nether forces."); - } - else if (p_ptr->resist_neth) - { - info[i++] = _("あなたは地獄の力への耐性を持っている。", "You are resistant to nether forces."); - } - if (p_ptr->resist_fear) - { - info[i++] = _("あなたは全く恐怖を感じない。", "You are completely fearless."); - } - if (p_ptr->resist_blind) - { - info[i++] = _("あなたの目は盲目への耐性を持っている。", "Your eyes are resistant to blindness."); - } - if (p_ptr->resist_time) - { - info[i++] = _("あなたは時間逆転への耐性を持っている。", "You are resistant to time."); - } - - if (p_ptr->sustain_str) - { - info[i++] = _("あなたの腕力は維持されている。", "Your strength is sustained."); - } - if (p_ptr->sustain_int) - { - info[i++] = _("あなたの知能は維持されている。", "Your intelligence is sustained."); - } - if (p_ptr->sustain_wis) - { - info[i++] = _("あなたの賢さは維持されている。", "Your wisdom is sustained."); - } - if (p_ptr->sustain_con) - { - info[i++] = _("あなたの耐久力は維持されている。", "Your constitution is sustained."); - } - if (p_ptr->sustain_dex) - { - info[i++] = _("あなたの器用さは維持されている。", "Your dexterity is sustained."); - } - if (p_ptr->sustain_chr) - { - info[i++] = _("あなたの魅力は維持されている。", "Your charisma is sustained."); - } - - if (have_flag(flgs, TR_STR)) - { - info[i++] = _("あなたの腕力は装備によって影響を受けている。", "Your strength is affected by your equipment."); - } - if (have_flag(flgs, TR_INT)) - { - info[i++] = _("あなたの知能は装備によって影響を受けている。", "Your intelligence is affected by your equipment."); - } - if (have_flag(flgs, TR_WIS)) - { - info[i++] = _("あなたの賢さは装備によって影響を受けている。", "Your wisdom is affected by your equipment."); - } - if (have_flag(flgs, TR_DEX)) - { - info[i++] = _("あなたの器用さは装備によって影響を受けている。", "Your dexterity is affected by your equipment."); - } - if (have_flag(flgs, TR_CON)) - { - info[i++] = _("あなたの耐久力は装備によって影響を受けている。", "Your constitution is affected by your equipment."); - } - if (have_flag(flgs, TR_CHR)) - { - info[i++] = _("あなたの魅力は装備によって影響を受けている。", "Your charisma is affected by your equipment."); - } - - if (have_flag(flgs, TR_STEALTH)) - { - info[i++] = _("あなたの隠密行動能力は装備によって影響を受けている。", "Your stealth is affected by your equipment."); - } - if (have_flag(flgs, TR_SEARCH)) - { - info[i++] = _("あなたの探索能力は装備によって影響を受けている。", "Your searching ability is affected by your equipment."); - } - if (have_flag(flgs, TR_INFRA)) - { - info[i++] = _("あなたの赤外線視力は装備によって影響を受けている。", "Your infravision is affected by your equipment."); - } - if (have_flag(flgs, TR_TUNNEL)) - { - info[i++] = _("あなたの採掘能力は装備によって影響を受けている。", "Your digging ability is affected by your equipment."); - } - if (have_flag(flgs, TR_SPEED)) - { - info[i++] = _("あなたのスピードは装備によって影響を受けている。", "Your speed is affected by your equipment."); - } - if (have_flag(flgs, TR_BLOWS)) - { - info[i++] = _("あなたの攻撃速度は装備によって影響を受けている。", "Your attack speed is affected by your equipment."); - } - - - /* Access the current weapon */ - o_ptr = &inventory[INVEN_RARM]; - - /* Analyze the weapon */ - if (o_ptr->k_idx) - { - /* Indicate Blessing */ - if (have_flag(flgs, TR_BLESSED)) - { - info[i++] = _("あなたの武器は神の祝福を受けている。", "Your weapon has been blessed by the gods."); - } - - if (have_flag(flgs, TR_CHAOTIC)) - { - info[i++] = _("あなたの武器はログルスの徴の属性をもつ。", "Your weapon is branded with the Sign of Logrus."); - } - - /* Hack */ - if (have_flag(flgs, TR_IMPACT)) - { - info[i++] = _("あなたの武器は打撃で地震を発生することができる。", "The impact of your weapon can cause earthquakes."); - } - - if (have_flag(flgs, TR_VORPAL)) - { - info[i++] = _("あなたの武器は非常に鋭い。", "Your weapon is very sharp."); - } - - if (have_flag(flgs, TR_VAMPIRIC)) - { - info[i++] = _("あなたの武器は敵から生命力を吸収する。", "Your weapon drains life from your foes."); - } - - /* Special "Attack Bonuses" */ - if (have_flag(flgs, TR_BRAND_ACID)) - { - info[i++] = _("あなたの武器は敵を溶かす。", "Your weapon melts your foes."); - } - if (have_flag(flgs, TR_BRAND_ELEC)) - { - info[i++] = _("あなたの武器は敵を感電させる。", "Your weapon shocks your foes."); - } - if (have_flag(flgs, TR_BRAND_FIRE)) - { - info[i++] = _("あなたの武器は敵を燃やす。", "Your weapon burns your foes."); - } - if (have_flag(flgs, TR_BRAND_COLD)) - { - info[i++] = _("あなたの武器は敵を凍らせる。", "Your weapon freezes your foes."); - } - if (have_flag(flgs, TR_BRAND_POIS)) - { - info[i++] = _("あなたの武器は敵を毒で侵す。", "Your weapon poisons your foes."); - } - - /* Special "slay" flags */ - if (have_flag(flgs, TR_KILL_ANIMAL)) - { - info[i++] = _("あなたの武器は動物の天敵である。", "Your weapon is a great bane of animals."); - } - else if (have_flag(flgs, TR_SLAY_ANIMAL)) - { - info[i++] = _("あなたの武器は動物に対して強い力を発揮する。", "Your weapon strikes at animals with extra force."); - } - if (have_flag(flgs, TR_KILL_EVIL)) - { - info[i++] = _("あなたの武器は邪悪なる存在の天敵である。", "Your weapon is a great bane of evil."); - } - else if (have_flag(flgs, TR_SLAY_EVIL)) - { - info[i++] = _("あなたの武器は邪悪なる存在に対して強い力を発揮する。", "Your weapon strikes at evil with extra force."); - } - if (have_flag(flgs, TR_KILL_HUMAN)) - { - info[i++] = _("あなたの武器は人間の天敵である。", "Your weapon is a great bane of humans."); - } - else if (have_flag(flgs, TR_SLAY_HUMAN)) - { - info[i++] = _("あなたの武器は人間に対して特に強い力を発揮する。", "Your weapon is especially deadly against humans."); - } - if (have_flag(flgs, TR_KILL_UNDEAD)) - { - info[i++] = _("あなたの武器はアンデッドの天敵である。", "Your weapon is a great bane of undead."); - } - else if (have_flag(flgs, TR_SLAY_UNDEAD)) - { - info[i++] = _("あなたの武器はアンデッドに対して神聖なる力を発揮する。", "Your weapon strikes at undead with holy wrath."); - } - if (have_flag(flgs, TR_KILL_DEMON)) - { - info[i++] = _("あなたの武器はデーモンの天敵である。", "Your weapon is a great bane of demons."); - } - else if (have_flag(flgs, TR_SLAY_DEMON)) - { - info[i++] = _("あなたの武器はデーモンに対して神聖なる力を発揮する。", "Your weapon strikes at demons with holy wrath."); - } - if (have_flag(flgs, TR_KILL_ORC)) - { - info[i++] = _("あなたの武器はオークの天敵である。", "Your weapon is a great bane of orcs."); - } - else if (have_flag(flgs, TR_SLAY_ORC)) - { - info[i++] = _("あなたの武器はオークに対して特に強い力を発揮する。", "Your weapon is especially deadly against orcs."); - } - if (have_flag(flgs, TR_KILL_TROLL)) - { - info[i++] = _("あなたの武器はトロルの天敵である。", "Your weapon is a great bane of trolls."); - } - else if (have_flag(flgs, TR_SLAY_TROLL)) - { - info[i++] = _("あなたの武器はトロルに対して特に強い力を発揮する。", "Your weapon is especially deadly against trolls."); - } - if (have_flag(flgs, TR_KILL_GIANT)) - { - info[i++] = _("あなたの武器はジャイアントの天敵である。", "Your weapon is a great bane of giants."); - } - else if (have_flag(flgs, TR_SLAY_GIANT)) - { - info[i++] = _("あなたの武器はジャイアントに対して特に強い力を発揮する。", "Your weapon is especially deadly against giants."); - } - /* Special "kill" flags */ - if (have_flag(flgs, TR_KILL_DRAGON)) - { - info[i++] = _("あなたの武器はドラゴンの天敵である。", "Your weapon is a great bane of dragons."); - } - else if (have_flag(flgs, TR_SLAY_DRAGON)) - { - info[i++] = _("あなたの武器はドラゴンに対して特に強い力を発揮する。", "Your weapon is especially deadly against dragons."); - } - - if (have_flag(flgs, TR_FORCE_WEAPON)) - { - info[i++] = _("あなたの武器はMPを使って攻撃する。", "Your weapon causes greate damages using your MP."); - } - if (have_flag(flgs, TR_THROW)) - { - info[i++] = _("あなたの武器は投げやすい。", "Your weapon can be thrown well."); - } - } - - - /* Save the screen */ - screen_save(); - - /* Erase the screen */ - for (k = 1; k < 24; k++) prt("", k, 13); - - /* Label the information */ - prt(_(" あなたの状態:", " Your Attributes:"), 1, 15); - - /* We will print on top of the map (column 13) */ - for (k = 2, j = 0; j < i; j++) - { - /* Show the info */ - prt(info[j], k++, 15); - - /* Every 20 entries (lines 2 to 21), start over */ - if ((k == 22) && (j+1 < i)) - { - prt(_("-- 続く --", "-- more --"), k, 15); - inkey(); - for (; k > 2; k--) prt("", k, 15); - } - } - - /* Pause */ - prt(_("[何かキーを押すとゲームに戻ります]", "[Press any key to continue]"), k, 13); - inkey(); - - /* Restore the screen */ - screen_load(); -} - -/*! - * @brief 魔法効果時間のターン数に基づいて表現IDを返す。 - * @param dur 効果ターン数 - * @return 効果時間の表現ID - */ -static int report_magics_aux(int dur) -{ - if (dur <= 5) - { - return 0; - } - else if (dur <= 10) - { - return 1; - } - else if (dur <= 20) - { - return 2; - } - else if (dur <= 50) - { - return 3; - } - else if (dur <= 100) - { - return 4; - } - else if (dur <= 200) - { - return 5; - } - else - { - return 6; + detect = TRUE; } + return (detect); } -static cptr report_magic_durations[] = -{ -#ifdef JP -"ごく短い間", -"少しの間", -"しばらくの間", -"多少長い間", -"長い間", -"非常に長い間", -"信じ難いほど長い間", -"モンスターを攻撃するまで" -#else - "for a short time", - "for a little while", - "for a while", - "for a long while", - "for a long time", - "for a very long time", - "for an incredibly long time", - "until you hit a monster" -#endif - -}; - -/*! - * @brief 現在の一時的効果一覧を返す / Report all currently active magical effects. - * @return なし - */ -void report_magics(void) -{ - int i = 0, j, k; - char Dummy[80]; - cptr info[128]; - int info2[128]; - - - if (p_ptr->blind) - { - info2[i] = report_magics_aux(p_ptr->blind); - info[i++] = _("あなたは目が見えない", "You cannot see"); - } - if (p_ptr->confused) - { - info2[i] = report_magics_aux(p_ptr->confused); - info[i++] = _("あなたは混乱している", "You are confused"); - } - if (p_ptr->afraid) - { - info2[i] = report_magics_aux(p_ptr->afraid); - info[i++] = _("あなたは恐怖に侵されている", "You are terrified"); - } - if (p_ptr->poisoned) - { - info2[i] = report_magics_aux(p_ptr->poisoned); - info[i++] = _("あなたは毒に侵されている", "You are poisoned"); - } - if (p_ptr->image) - { - info2[i] = report_magics_aux(p_ptr->image); - info[i++] = _("あなたは幻覚を見ている", "You are hallucinating"); - } - if (p_ptr->blessed) - { - info2[i] = report_magics_aux(p_ptr->blessed); - info[i++] = _("あなたは高潔さを感じている", "You feel rightous"); - } - if (p_ptr->hero) - { - info2[i] = report_magics_aux(p_ptr->hero); - info[i++] = _("あなたはヒーロー気分だ", "You feel heroic"); - } - if (p_ptr->shero) - { - info2[i] = report_magics_aux(p_ptr->shero); - info[i++] = _("あなたは戦闘狂だ", "You are in a battle rage"); - } - if (p_ptr->protevil) - { - info2[i] = report_magics_aux(p_ptr->protevil); - info[i++] = _("あなたは邪悪なる存在から守られている", "You are protected from evil"); - } - if (p_ptr->shield) - { - info2[i] = report_magics_aux(p_ptr->shield); - info[i++] = _("あなたは神秘のシールドで守られている", "You are protected by a mystic shield"); - } - if (p_ptr->invuln) - { - info2[i] = report_magics_aux(p_ptr->invuln); - info[i++] = _("あなたは無敵だ", "You are invulnerable"); - } - if (p_ptr->wraith_form) - { - info2[i] = report_magics_aux(p_ptr->wraith_form); - info[i++] = _("あなたは幽体化している", "You are incorporeal"); - } - if (p_ptr->special_attack & ATTACK_CONFUSE) - { - info2[i] = 7; - info[i++] = _("あなたの手は赤く輝いている", "Your hands are glowing dull red."); - } - if (p_ptr->word_recall) - { - info2[i] = report_magics_aux(p_ptr->word_recall); - info[i++] = _("この後帰還の詔が発動する", "You are waiting to be recalled"); - } - if (p_ptr->alter_reality) - { - info2[i] = report_magics_aux(p_ptr->alter_reality); - info[i++] = _("この後現実変容が発動する", "You waiting to be altered"); - } - if (p_ptr->oppose_acid) - { - info2[i] = report_magics_aux(p_ptr->oppose_acid); - info[i++] = _("あなたは酸への耐性を持っている", "You are resistant to acid"); - } - if (p_ptr->oppose_elec) - { - info2[i] = report_magics_aux(p_ptr->oppose_elec); - info[i++] = _("あなたは電撃への耐性を持っている", "You are resistant to lightning"); - } - if (p_ptr->oppose_fire) - { - info2[i] = report_magics_aux(p_ptr->oppose_fire); - info[i++] = _("あなたは火への耐性を持っている", "You are resistant to fire"); - } - if (p_ptr->oppose_cold) - { - info2[i] = report_magics_aux(p_ptr->oppose_cold); - info[i++] = _("あなたは冷気への耐性を持っている", "You are resistant to cold"); - } - if (p_ptr->oppose_pois) - { - info2[i] = report_magics_aux(p_ptr->oppose_pois); - info[i++] = _("あなたは毒への耐性を持っている", "You are resistant to poison"); - } - - /* Save the screen */ - screen_save(); - - /* Erase the screen */ - for (k = 1; k < 24; k++) prt("", k, 13); - - /* Label the information */ - prt(_(" 現在かかっている魔法 :", " Your Current Magic:"), 1, 15); - - - /* We will print on top of the map (column 13) */ - for (k = 2, j = 0; j < i; j++) - { - /* Show the info */ - sprintf(Dummy, _("%-28s : 期間 - %s ", "%s %s."), info[j], - report_magic_durations[info2[j]]); - prt(Dummy, k++, 15); - - /* Every 20 entries (lines 2 to 21), start over */ - if ((k == 22) && (j + 1 < i)) - { - prt(_("-- 続く --", "-- more --"), k, 15); - inkey(); - for (; k > 2; k--) prt("", k, 15); - } - } - - /* Pause */ - prt(_("[何かキーを押すとゲームに戻ります]", "[Press any key to continue]"), k, 13); - inkey(); - - /* Restore the screen */ - screen_load(); -} /*! - * @brief プレイヤー周辺の地形を感知する + * @brief 魔法効果のあるのアイテムオブジェクトを感知する / Detect all "magic" objects on the current panel. * @param range 効果範囲 - * @param flag 特定地形ID - * @param known 地形から危険フラグを外すならTRUE * @return 効力があった場合TRUEを返す + * @details + *
+ * This will light up all spaces with "magic" items, including artifacts,
+ * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
+ * and "enchanted" items of the "good" variety.
+ *
+ * It can probably be argued that this function is now too powerful.
+ * 
*/ -static bool detect_feat_flag(int range, int flag, bool known) +bool detect_objects_magic(POSITION range) { - int x, y; - bool detect = FALSE; - cave_type *c_ptr; + OBJECT_TYPE_VALUE tv; + OBJECT_IDX i; + POSITION y, x; + + bool detect = FALSE; if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; - /* Scan the current panel */ - for (y = 1; y < cur_hgt - 1; y++) + /* Scan all objects */ + for (i = 1; i < o_max; i++) { - for (x = 1; x <= cur_wid - 1; x++) - { - int dist = distance(p_ptr->y, p_ptr->x, y, x); - if (dist > range) continue; - - /* Access the grid */ - c_ptr = &cave[y][x]; - - /* Hack -- Safe */ - if (flag == FF_TRAP) - { - /* Mark as detected */ - if (dist <= range && known) - { - if (dist <= range - 1) c_ptr->info |= (CAVE_IN_DETECT); - - c_ptr->info &= ~(CAVE_UNSAFE); - - /* Redraw */ - lite_spot(y, x); - } - } - - /* Detect flags */ - if (cave_have_flag_grid(c_ptr, flag)) - { - /* Detect secrets */ - disclose_grid(y, x); - - /* Hack -- Memorize */ - c_ptr->info |= (CAVE_MARK); - - /* Redraw */ - lite_spot(y, x); - - /* Obvious */ - detect = TRUE; - } - } - } - - /* Result */ - return detect; -} - - -/*! - * @brief プレイヤー周辺のトラップを感知する / Detect all traps on current panel - * @param range 効果範囲 - * @param known 感知外範囲を超える警告フラグを立てる場合TRUEを返す - * @return 効力があった場合TRUEを返す - */ -bool detect_traps(int range, bool known) -{ - bool detect = detect_feat_flag(range, FF_TRAP, known); - - if (known) p_ptr->dtrap = TRUE; - - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 0) detect = FALSE; + object_type *o_ptr = &o_list[i]; - /* Describe */ - if (detect) - { - msg_print(_("トラップの存在を感じとった!", "You sense the presence of traps!")); - } + /* Skip dead objects */ + if (!o_ptr->k_idx) continue; - /* Result */ - return detect; -} + /* Skip held objects */ + if (o_ptr->held_m_idx) continue; + y = o_ptr->iy; + x = o_ptr->ix; -/*! - * @brief プレイヤー周辺のドアを感知する / Detect all doors on current panel - * @param range 効果範囲 - * @return 効力があった場合TRUEを返す - */ -bool detect_doors(int range) -{ - bool detect = detect_feat_flag(range, FF_DOOR, TRUE); + /* Only detect nearby objects */ + if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 0) detect = FALSE; + /* Examine the tval */ + tv = o_ptr->tval; - /* Describe */ + /* Artifacts, misc magic items, or enchanted wearables */ + if (object_is_artifact(o_ptr) || + object_is_ego(o_ptr) || + (tv == TV_WHISTLE) || + (tv == TV_AMULET) || + (tv == TV_RING) || + (tv == TV_STAFF) || + (tv == TV_WAND) || + (tv == TV_ROD) || + (tv == TV_SCROLL) || + (tv == TV_POTION) || + (tv == TV_LIFE_BOOK) || + (tv == TV_SORCERY_BOOK) || + (tv == TV_NATURE_BOOK) || + (tv == TV_CHAOS_BOOK) || + (tv == TV_DEATH_BOOK) || + (tv == TV_TRUMP_BOOK) || + (tv == TV_ARCANE_BOOK) || + (tv == TV_CRAFT_BOOK) || + (tv == TV_DAEMON_BOOK) || + (tv == TV_CRUSADE_BOOK) || + (tv == TV_MUSIC_BOOK) || + (tv == TV_HISSATSU_BOOK) || + (tv == TV_HEX_BOOK) || + ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) + { + /* Memorize the item */ + o_ptr->marked |= OM_FOUND; + lite_spot(y, x); + detect = TRUE; + } + } if (detect) { - msg_print(_("ドアの存在を感じとった!", "You sense the presence of doors!")); + msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!")); } - /* Result */ - return detect; + /* Return result */ + return (detect); } /*! - * @brief プレイヤー周辺の階段を感知する / Detect all stairs on current panel + * @brief 一般のモンスターを感知する / Detect all "normal" monsters on the current panel * @param range 効果範囲 * @return 効力があった場合TRUEを返す */ -bool detect_stairs(int range) +bool detect_monsters_normal(POSITION range) { - bool detect = detect_feat_flag(range, FF_STAIRS, TRUE); + MONSTER_IDX i; + POSITION y, x; + + bool flag = FALSE; - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 0) detect = FALSE; + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; - /* Describe */ - if (detect) + /* Scan monsters */ + for (i = 1; i < m_max; i++) { - msg_print(_("階段の存在を感じとった!", "You sense the presence of stairs!")); - } + monster_type *m_ptr = &m_list[i]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Result */ - return detect; -} + /* Skip dead monsters */ + if (!m_ptr->r_idx) continue; + y = m_ptr->fy; + x = m_ptr->fx; -/*! - * @brief プレイヤー周辺の地形財宝を感知する / Detect any treasure on the current panel - * @param range 効果範囲 - * @return 効力があった場合TRUEを返す - */ -bool detect_treasure(int range) -{ - bool detect = detect_feat_flag(range, FF_HAS_GOLD, TRUE); + /* Only detect nearby monsters */ + if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 6) detect = FALSE; + /* Detect all non-invisible monsters */ + if (!(r_ptr->flags2 & RF2_INVISIBLE) || p_ptr->see_inv) + { + /* Repair visibility later */ + repair_monsters = TRUE; - /* Describe */ - if (detect) - { - msg_print(_("埋蔵された財宝の存在を感じとった!", "You sense the presence of buried treasure!")); + /* Hack -- Detect monster */ + m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); + update_monster(i, FALSE); + flag = TRUE; + } } - /* Result */ - return detect; + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 3) flag = FALSE; + if (flag) + { + /* Describe result */ + msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!")); + } + return (flag); } /*! - * @brief プレイヤー周辺のアイテム財宝を感知する / Detect all "gold" objects on the current panel + * @brief 不可視のモンスターを感知する / Detect all "invisible" monsters around the player * @param range 効果範囲 * @return 効力があった場合TRUEを返す */ -bool detect_objects_gold(int range) +bool detect_monsters_invis(POSITION range) { - int i, y, x; - int range2 = range; - - bool detect = FALSE; + MONSTER_IDX i; + POSITION y, x; + bool flag = FALSE; - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range2 /= 3; + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; - /* Scan objects */ - for (i = 1; i < o_max; i++) + /* Scan monsters */ + for (i = 1; i < m_max; i++) { - object_type *o_ptr = &o_list[i]; - - /* Skip dead objects */ - if (!o_ptr->k_idx) continue; + monster_type *m_ptr = &m_list[i]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Skip held objects */ - if (o_ptr->held_m_idx) continue; + /* Skip dead monsters */ + if (!m_ptr->r_idx) continue; - /* Location */ - y = o_ptr->iy; - x = o_ptr->ix; + y = m_ptr->fy; + x = m_ptr->fx; - /* Only detect nearby objects */ - if (distance(p_ptr->y, p_ptr->x, y, x) > range2) continue; + /* Only detect nearby monsters */ + if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - /* Detect "gold" objects */ - if (o_ptr->tval == TV_GOLD) + /* Detect invisible monsters */ + if (r_ptr->flags2 & RF2_INVISIBLE) { - /* Hack -- memorize it */ - o_ptr->marked |= OM_FOUND; + /* Update monster recall window */ + if (p_ptr->monster_race_idx == m_ptr->r_idx) + { + p_ptr->window |= (PW_MONSTER); + } - /* Redraw */ - lite_spot(y, x); + /* Repair visibility later */ + repair_monsters = TRUE; - /* Detect */ - detect = TRUE; + /* Hack -- Detect monster */ + m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); + update_monster(i, FALSE); + flag = TRUE; } } - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 6) detect = FALSE; - - /* Describe */ - if (detect) - { - msg_print(_("財宝の存在を感じとった!", "You sense the presence of treasure!")); - } - - if (detect_monsters_string(range, "$")) + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 3) flag = FALSE; + if (flag) { - detect = TRUE; + /* Describe result */ + msg_print(_("透明な生物の存在を感じとった!", "You sense the presence of invisible creatures!")); } - - /* Result */ - return (detect); + return (flag); } - /*! - * @brief 通常のアイテムオブジェクトを感知する / Detect all "normal" objects on the current panel + * @brief 邪悪なモンスターを感知する / Detect all "evil" monsters on current panel * @param range 効果範囲 * @return 効力があった場合TRUEを返す */ -bool detect_objects_normal(int range) +bool detect_monsters_evil(POSITION range) { - int i, y, x; - int range2 = range; - - bool detect = FALSE; + MONSTER_IDX i; + POSITION y, x; + bool flag = FALSE; - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range2 /= 3; + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; - /* Scan objects */ - for (i = 1; i < o_max; i++) + /* Scan monsters */ + for (i = 1; i < m_max; i++) { - object_type *o_ptr = &o_list[i]; - - /* Skip dead objects */ - if (!o_ptr->k_idx) continue; + monster_type *m_ptr = &m_list[i]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Skip held objects */ - if (o_ptr->held_m_idx) continue; + /* Skip dead monsters */ + if (!m_ptr->r_idx) continue; - /* Location */ - y = o_ptr->iy; - x = o_ptr->ix; + y = m_ptr->fy; + x = m_ptr->fx; - /* Only detect nearby objects */ - if (distance(p_ptr->y, p_ptr->x, y, x) > range2) continue; + /* Only detect nearby monsters */ + if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - /* Detect "real" objects */ - if (o_ptr->tval != TV_GOLD) + /* Detect evil monsters */ + if (r_ptr->flags3 & RF3_EVIL) { - /* Hack -- memorize it */ - o_ptr->marked |= OM_FOUND; - - /* Redraw */ - lite_spot(y, x); + if (is_original_ap(m_ptr)) + { + /* Take note that they are evil */ + r_ptr->r_flags3 |= (RF3_EVIL); - /* Detect */ - detect = TRUE; - } - } + /* Update monster recall window */ + if (p_ptr->monster_race_idx == m_ptr->r_idx) + { + p_ptr->window |= (PW_MONSTER); + } + } - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 6) detect = FALSE; + /* Repair visibility later */ + repair_monsters = TRUE; - /* Describe */ - if (detect) - { - msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!")); + /* Hack -- Detect monster */ + m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); + update_monster(i, FALSE); + flag = TRUE; + } } - - if (detect_monsters_string(range, "!=?|/`")) + if (flag) { - detect = TRUE; + /* Describe result */ + msg_print(_("邪悪なる生物の存在を感じとった!", "You sense the presence of evil creatures!")); } - - /* Result */ - return (detect); + return (flag); } - /*! - * @brief 魔法効果のあるのアイテムオブジェクトを感知する / Detect all "magic" objects on the current panel. + * @brief 無生命のモンスターを感知する(アンデッド、悪魔系を含む) / Detect all "nonliving", "undead" or "demonic" monsters on current panel * @param range 効果範囲 * @return 効力があった場合TRUEを返す - * @details - *
- * This will light up all spaces with "magic" items, including artifacts,
- * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
- * and "enchanted" items of the "good" variety.
- *
- * It can probably be argued that this function is now too powerful.
- * 
*/ -bool detect_objects_magic(int range) +bool detect_monsters_nonliving(POSITION range) { - int i, y, x, tv; - - bool detect = FALSE; + MONSTER_IDX i; + POSITION y, x; + bool flag = FALSE; if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; - /* Scan all objects */ - for (i = 1; i < o_max; i++) + /* Scan monsters */ + for (i = 1; i < m_max; i++) { - object_type *o_ptr = &o_list[i]; - - /* Skip dead objects */ - if (!o_ptr->k_idx) continue; + monster_type *m_ptr = &m_list[i]; - /* Skip held objects */ - if (o_ptr->held_m_idx) continue; + /* Skip dead monsters */ + if (!m_ptr->r_idx) continue; - /* Location */ - y = o_ptr->iy; - x = o_ptr->ix; + y = m_ptr->fy; + x = m_ptr->fx; - /* Only detect nearby objects */ + /* Only detect nearby monsters */ if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - /* Examine the tval */ - tv = o_ptr->tval; - - /* Artifacts, misc magic items, or enchanted wearables */ - if (object_is_artifact(o_ptr) || - object_is_ego(o_ptr) || - (tv == TV_WHISTLE) || - (tv == TV_AMULET) || - (tv == TV_RING) || - (tv == TV_STAFF) || - (tv == TV_WAND) || - (tv == TV_ROD) || - (tv == TV_SCROLL) || - (tv == TV_POTION) || - (tv == TV_LIFE_BOOK) || - (tv == TV_SORCERY_BOOK) || - (tv == TV_NATURE_BOOK) || - (tv == TV_CHAOS_BOOK) || - (tv == TV_DEATH_BOOK) || - (tv == TV_TRUMP_BOOK) || - (tv == TV_ARCANE_BOOK) || - (tv == TV_CRAFT_BOOK) || - (tv == TV_DAEMON_BOOK) || - (tv == TV_CRUSADE_BOOK) || - (tv == TV_MUSIC_BOOK) || - (tv == TV_HISSATSU_BOOK) || - (tv == TV_HEX_BOOK) || - ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) + /* Detect non-living monsters */ + if (!monster_living(m_ptr->r_idx)) { - /* Memorize the item */ - o_ptr->marked |= OM_FOUND; + /* Update monster recall window */ + if (p_ptr->monster_race_idx == m_ptr->r_idx) + { + p_ptr->window |= (PW_MONSTER); + } - /* Redraw */ - lite_spot(y, x); + /* Repair visibility later */ + repair_monsters = TRUE; - /* Detect */ - detect = TRUE; + /* Hack -- Detect monster */ + m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); + update_monster(i, FALSE); + flag = TRUE; } } - - /* Describe */ - if (detect) + if (flag) { - msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!")); + /* Describe result */ + msg_print(_("自然でないモンスターの存在を感じた!", "You sense the presence of unnatural beings!")); } - - /* Return result */ - return (detect); + return (flag); } - /*! - * @brief 一般のモンスターを感知する / Detect all "normal" monsters on the current panel + * @brief 精神のあるモンスターを感知する / Detect all monsters it has mind on current panel * @param range 効果範囲 * @return 効力があった場合TRUEを返す */ -bool detect_monsters_normal(int range) +bool detect_monsters_mind(POSITION range) { - int i, y, x; - + MONSTER_IDX i; + POSITION y, x; bool flag = FALSE; if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; @@ -2209,52 +587,49 @@ bool detect_monsters_normal(int range) /* Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ y = m_ptr->fy; x = m_ptr->fx; /* Only detect nearby monsters */ if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - /* Detect all non-invisible monsters */ - if (!(r_ptr->flags2 & RF2_INVISIBLE) || p_ptr->see_inv) + /* Detect non-living monsters */ + if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) { + /* Update monster recall window */ + if (p_ptr->monster_race_idx == m_ptr->r_idx) + { + p_ptr->window |= (PW_MONSTER); + } + /* Repair visibility later */ repair_monsters = TRUE; /* Hack -- Detect monster */ m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); - - /* Update the monster */ - update_mon(i, FALSE); - - /* Detect */ + update_monster(i, FALSE); flag = TRUE; } } - - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 3) flag = FALSE; - - /* Describe */ if (flag) { /* Describe result */ - msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!")); + msg_print(_("殺気を感じとった!", "You sense the presence of someone's mind!")); } - - /* Result */ return (flag); } /*! - * @brief 不可視のモンスターを感知する / Detect all "invisible" monsters around the player + * @brief 該当シンボルのモンスターを感知する / Detect all (string) monsters on current panel * @param range 効果範囲 + * @param Match 対応シンボルの混じったモンスター文字列(複数指定化) * @return 効力があった場合TRUEを返す */ -bool detect_monsters_invis(int range) +bool detect_monsters_string(POSITION range, cptr Match) { - int i, y, x; + MONSTER_IDX i; + POSITION y, x; bool flag = FALSE; if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; @@ -2268,20 +643,18 @@ bool detect_monsters_invis(int range) /* Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ y = m_ptr->fy; x = m_ptr->fx; /* Only detect nearby monsters */ if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; - /* Detect invisible monsters */ - if (r_ptr->flags2 & RF2_INVISIBLE) + /* Detect monsters with the same symbol */ + if (my_strchr(Match, r_ptr->d_char)) { /* Update monster recall window */ if (p_ptr->monster_race_idx == m_ptr->r_idx) { - /* Window stuff */ p_ptr->window |= (PW_MONSTER); } @@ -2290,37 +663,32 @@ bool detect_monsters_invis(int range) /* Hack -- Detect monster */ m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); - - /* Update the monster */ - update_mon(i, FALSE); - - /* Detect */ + update_monster(i, FALSE); flag = TRUE; } } - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 3) flag = FALSE; - - /* Describe */ + if (music_singing(MUSIC_DETECT) && SINGING_COUNT(p_ptr) > 3) flag = FALSE; if (flag) { /* Describe result */ - msg_print(_("透明な生物の存在を感じとった!", "You sense the presence of invisible creatures!")); + msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!")); } - - /* Result */ return (flag); } /*! - * @brief 邪悪なモンスターを感知する / Detect all "evil" monsters on current panel + * @brief flags3に対応するモンスターを感知する / A "generic" detect monsters routine, tagged to flags3 * @param range 効果範囲 + * @param match_flag 感知フラグ * @return 効力があった場合TRUEを返す */ -bool detect_monsters_evil(int range) +bool detect_monsters_xxx(POSITION range, u32b match_flag) { - int i, y, x; + MONSTER_IDX i; + POSITION y, x; bool flag = FALSE; + cptr desc_monsters = _("変なモンスター", "weird monsters"); if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; @@ -2333,7 +701,6 @@ bool detect_monsters_evil(int range) /* Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ y = m_ptr->fy; x = m_ptr->fx; @@ -2341,17 +708,16 @@ bool detect_monsters_evil(int range) if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; /* Detect evil monsters */ - if (r_ptr->flags3 & RF3_EVIL) + if (r_ptr->flags3 & (match_flag)) { if (is_original_ap(m_ptr)) { - /* Take note that they are evil */ - r_ptr->r_flags3 |= (RF3_EVIL); + /* Take note that they are something */ + r_ptr->r_flags3 |= (match_flag); /* Update monster recall window */ if (p_ptr->monster_race_idx == m_ptr->r_idx) { - /* Window stuff */ p_ptr->window |= (PW_MONSTER); } } @@ -2361,3679 +727,4400 @@ bool detect_monsters_evil(int range) /* Hack -- Detect monster */ m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); - - /* Update the monster */ - update_mon(i, FALSE); - - /* Detect */ + update_monster(i, FALSE); flag = TRUE; } } - - /* Describe */ if (flag) { + switch (match_flag) + { + case RF3_DEMON: + desc_monsters = _("デーモン", "demons"); + break; + case RF3_UNDEAD: + desc_monsters = _("アンデッド", "the undead"); + break; + } + /* Describe result */ - msg_print(_("邪悪なる生物の存在を感じとった!", "You sense the presence of evil creatures!")); + msg_format(_("%sの存在を感じとった!", "You sense the presence of %s!"), desc_monsters); + msg_print(NULL); } - - /* Result */ return (flag); } + /*! - * @brief 無生命のモンスターを感知する(アンデッド、悪魔系を含む) / Detect all "nonliving", "undead" or "demonic" monsters on current panel + * @brief 全感知処理 / Detect everything * @param range 効果範囲 * @return 効力があった場合TRUEを返す */ -bool detect_monsters_nonliving(int range) +bool detect_all(POSITION range) { - int i, y, x; - bool flag = FALSE; + bool detect = FALSE; - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; + /* Detect everything */ + if (detect_traps(range, TRUE)) detect = TRUE; + if (detect_doors(range)) detect = TRUE; + if (detect_stairs(range)) detect = TRUE; - /* Scan monsters */ + /* There are too many hidden treasure. So... */ + /* if (detect_treasure(range)) detect = TRUE; */ + + if (detect_objects_gold(range)) detect = TRUE; + if (detect_objects_normal(range)) detect = TRUE; + if (detect_monsters_invis(range)) detect = TRUE; + if (detect_monsters_normal(range)) detect = TRUE; + return (detect); +} + + +/*! + * @brief 視界内モンスターに魔法効果を与える / Apply a "project()" directly to all viewable monsters + * @param typ 属性効果 + * @param dam 効果量 + * @return 効力があった場合TRUEを返す + * @details + *
+ * Note that affected monsters are NOT auto-tracked by this usage.
+ *
+ * To avoid misbehavior when monster deaths have side-effects,
+ * this is done in two passes. -- JDL
+ * 
+ */ +bool project_hack(EFFECT_ID typ, HIT_POINT dam) +{ + MONSTER_IDX i; + POSITION x, y; + BIT_FLAGS flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE; + bool obvious = FALSE; + + + /* Mark all (nearby) monsters */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Skip dead monsters */ + /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ y = m_ptr->fy; x = m_ptr->fx; - /* Only detect nearby monsters */ - if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; + /* Require line of sight */ + if (!player_has_los_bold(y, x) || !projectable(p_ptr->y, p_ptr->x, y, x)) continue; - /* Detect non-living monsters */ - if (!monster_living(r_ptr)) - { - /* Update monster recall window */ - if (p_ptr->monster_race_idx == m_ptr->r_idx) - { - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); - } + /* Mark the monster */ + m_ptr->mflag |= (MFLAG_TEMP); + } - /* Repair visibility later */ - repair_monsters = TRUE; + /* Affect all marked monsters */ + for (i = 1; i < m_max; i++) + { + monster_type *m_ptr = &m_list[i]; - /* Hack -- Detect monster */ - m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); + /* Skip unmarked monsters */ + if (!(m_ptr->mflag & (MFLAG_TEMP))) continue; + + /* Remove mark */ + m_ptr->mflag &= ~(MFLAG_TEMP); - /* Update the monster */ - update_mon(i, FALSE); + y = m_ptr->fy; + x = m_ptr->fx; - /* Detect */ - flag = TRUE; - } + /* Jump directly to the target monster */ + if (project(0, 0, y, x, dam, typ, flg, -1)) obvious = TRUE; } + return (obvious); +} - /* Describe */ - if (flag) - { - /* Describe result */ - msg_print(_("自然でないモンスターの存在を感じた!", "You sense the presence of unnatural beings!")); - } - /* Result */ - return (flag); +/*! + * @brief 視界内モンスターを加速する処理 / Speed monsters + * @return 効力があった場合TRUEを返す + */ +bool speed_monsters(void) +{ + return (project_hack(GF_OLD_SPEED, p_ptr->lev)); +} + +/*! + * @brief 視界内モンスターを加速する処理 / Slow monsters + * @return 効力があった場合TRUEを返す + */ +bool slow_monsters(int power) +{ + return (project_hack(GF_OLD_SLOW, power)); +} + +/*! + * @brief 視界内モンスターを眠らせる処理 / Sleep monsters + * @return 効力があった場合TRUEを返す + */ +bool sleep_monsters(int power) +{ + return (project_hack(GF_OLD_SLEEP, power)); +} + +/*! + * @brief 視界内の邪悪なモンスターをテレポート・アウェイさせる処理 / Banish evil monsters + * @return 効力があった場合TRUEを返す + */ +bool banish_evil(int dist) +{ + return (project_hack(GF_AWAY_EVIL, dist)); +} + +/*! + * @brief 視界内のアンデッド・モンスターを恐怖させる処理 / Turn undead + * @return 効力があった場合TRUEを返す + */ +bool turn_undead(void) +{ + bool tester = (project_hack(GF_TURN_UNDEAD, p_ptr->lev)); + if (tester) + chg_virtue(V_UNLIFE, -1); + return tester; +} + +/*! + * @brief 視界内のアンデッド・モンスターにダメージを与える処理 / Dispel undead monsters + * @return 効力があった場合TRUEを返す + */ +bool dispel_undead(HIT_POINT dam) +{ + bool tester = (project_hack(GF_DISP_UNDEAD, dam)); + if (tester) + chg_virtue(V_UNLIFE, -2); + return tester; +} + +/*! + * @brief 視界内の邪悪なモンスターにダメージを与える処理 / Dispel evil monsters + * @return 効力があった場合TRUEを返す + */ +bool dispel_evil(HIT_POINT dam) +{ + return (project_hack(GF_DISP_EVIL, dam)); +} + +/*! + * @brief 視界内の善良なモンスターにダメージを与える処理 / Dispel good monsters + * @return 効力があった場合TRUEを返す + */ +bool dispel_good(HIT_POINT dam) +{ + return (project_hack(GF_DISP_GOOD, dam)); +} + +/*! + * @brief 視界内のあらゆるモンスターにダメージを与える処理 / Dispel all monsters + * @return 効力があった場合TRUEを返す + */ +bool dispel_monsters(HIT_POINT dam) +{ + return (project_hack(GF_DISP_ALL, dam)); +} + +/*! + * @brief 視界内の生命のあるモンスターにダメージを与える処理 / Dispel 'living' monsters + * @return 効力があった場合TRUEを返す + */ +bool dispel_living(HIT_POINT dam) +{ + return (project_hack(GF_DISP_LIVING, dam)); +} + +/*! + * @brief 視界内の悪魔系モンスターにダメージを与える処理 / Dispel 'living' monsters + * @return 効力があった場合TRUEを返す + */ +bool dispel_demons(HIT_POINT dam) +{ + return (project_hack(GF_DISP_DEMON, dam)); } /*! - * @brief 精神のあるモンスターを感知する / Detect all monsters it has mind on current panel - * @param range 効果範囲 + * @brief 視界内のモンスターに「聖戦」効果を与える処理 * @return 効力があった場合TRUEを返す */ -bool detect_monsters_mind(int range) +bool crusade(void) { - int i, y, x; - bool flag = FALSE; + return (project_hack(GF_CRUSADE, p_ptr->lev*4)); +} - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; +/*! + * @brief 視界内モンスターを怒らせる処理 / Wake up all monsters, and speed up "los" monsters. + * @param who 怒らせる原因を起こしたモンスター(0ならばプレイヤー) + * @return なし + */ +void aggravate_monsters(MONSTER_IDX who) +{ + MONSTER_IDX i; + bool sleep = FALSE; + bool speed = FALSE; - /* Scan monsters */ + /* Aggravate everyone nearby */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Skip dead monsters */ + /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ - y = m_ptr->fy; - x = m_ptr->fx; - - /* Only detect nearby monsters */ - if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; + /* Skip aggravating monster (or player) */ + if (i == who) continue; - /* Detect non-living monsters */ - if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) + /* Wake up nearby sleeping monsters */ + if (m_ptr->cdis < MAX_SIGHT * 2) { - /* Update monster recall window */ - if (p_ptr->monster_race_idx == m_ptr->r_idx) + /* Wake up */ + if (MON_CSLEEP(m_ptr)) { - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); + (void)set_monster_csleep(i, 0); + sleep = TRUE; } - - /* Repair visibility later */ - repair_monsters = TRUE; - - /* Hack -- Detect monster */ - m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); - - /* Update the monster */ - update_mon(i, FALSE); - - /* Detect */ - flag = TRUE; + if (!is_pet(m_ptr)) m_ptr->mflag2 |= MFLAG2_NOPET; } - } - /* Describe */ - if (flag) - { - /* Describe result */ - msg_print(_("殺気を感じとった!", "You sense the presence of someone's mind!")); + /* Speed up monsters in line of sight */ + if (player_has_los_bold(m_ptr->fy, m_ptr->fx)) + { + if (!is_pet(m_ptr)) + { + (void)set_monster_fast(i, MON_FAST(m_ptr) + 100); + speed = TRUE; + } + } } - /* Result */ - return (flag); + if (speed) msg_print(_("付近で何かが突如興奮したような感じを受けた!", "You feel a sudden stirring nearby!")); + else if (sleep) msg_print(_("何かが突如興奮したような騒々しい音が遠くに聞こえた!", "You hear a sudden stirring in the distance!")); + if (p_ptr->riding) p_ptr->update |= PU_BONUS; } /*! - * @brief 該当シンボルのモンスターを感知する / Detect all (string) monsters on current panel - * @param range 効果範囲 - * @param Match 対応シンボルの混じったモンスター文字列(複数指定化) + * @brief モンスターへの単体抹殺処理サブルーチン / Delete a non-unique/non-quest monster + * @param m_idx 抹殺するモンスターID + * @param power 抹殺の威力 + * @param player_cast プレイヤーの魔法によるものならば TRUE + * @param dam_side プレイヤーへの負担ダメージ量(1d(dam_side)) + * @param spell_name 抹殺効果を起こした魔法の名前 * @return 効力があった場合TRUEを返す */ -bool detect_monsters_string(int range, cptr Match) +bool genocide_aux(MONSTER_IDX m_idx, int power, bool player_cast, int dam_side, cptr spell_name) { - int i, y, x; - bool flag = FALSE; + int msec = delay_factor * delay_factor * delay_factor; + monster_type *m_ptr = &m_list[m_idx]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; + bool resist = FALSE; - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; + if (is_pet(m_ptr) && !player_cast) return FALSE; - /* Scan monsters */ - for (i = 1; i < m_max; i++) + /* Hack -- Skip Unique Monsters or Quest Monsters */ + if (r_ptr->flags1 & (RF1_UNIQUE | RF1_QUESTOR)) resist = TRUE; + else if (r_ptr->flags7 & RF7_UNIQUE2) resist = TRUE; + else if (m_idx == p_ptr->riding) resist = TRUE; + else if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) resist = TRUE; + else if (player_cast && (r_ptr->level > randint0(power))) resist = TRUE; + else if (player_cast && (m_ptr->mflag2 & MFLAG2_NOGENO)) resist = TRUE; + + + else { - monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; + if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) + { + char m_name[80]; - /* Skip dead monsters */ - if (!m_ptr->r_idx) continue; + monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); + do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_GENOCIDE, m_name); + } - /* Location */ - y = m_ptr->fy; - x = m_ptr->fx; + delete_monster_idx(m_idx); + } - /* Only detect nearby monsters */ - if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; + if (resist && player_cast) + { + bool see_m = is_seen(m_ptr); + char m_name[80]; - /* Detect monsters with the same symbol */ - if (my_strchr(Match, r_ptr->d_char)) + monster_desc(m_name, m_ptr, 0); + if (see_m) { - /* Update monster recall window */ - if (p_ptr->monster_race_idx == m_ptr->r_idx) + msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), m_name); + } + if (MON_CSLEEP(m_ptr)) + { + (void)set_monster_csleep(m_idx, 0); + if (m_ptr->ml) { - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); + msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name); } - - /* Repair visibility later */ - repair_monsters = TRUE; - - /* Hack -- Detect monster */ - m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); - - /* Update the monster */ - update_mon(i, FALSE); - - /* Detect */ - flag = TRUE; } + if (is_friendly(m_ptr) && !is_pet(m_ptr)) + { + if (see_m) + { + msg_format(_("%sは怒った!", "%^s gets angry!"), m_name); + } + set_hostile(m_ptr); + } + if (one_in_(13)) m_ptr->mflag2 |= MFLAG2_NOGENO; } - if (music_singing(MUSIC_DETECT) && p_ptr->magic_num1[2] > 3) flag = FALSE; - - /* Describe */ - if (flag) + if (player_cast) { - /* Describe result */ - msg_print(_("モンスターの存在を感じとった!", "You sense the presence of monsters!")); + take_hit(DAMAGE_GENO, randint1(dam_side), format(_("%^sの呪文を唱えた疲労", "the strain of casting %^s"), spell_name), -1); } - /* Result */ - return (flag); + /* Visual feedback */ + move_cursor_relative(p_ptr->y, p_ptr->x); + + p_ptr->redraw |= (PR_HP); + p_ptr->window |= (PW_PLAYER); + + /* Handle */ + handle_stuff(); + Term_fresh(); + + Term_xtra(TERM_XTRA_DELAY, msec); + + return !resist; } + /*! - * @brief flags3に対応するモンスターを感知する / A "generic" detect monsters routine, tagged to flags3 - * @param range 効果範囲 - * @param match_flag 感知フラグ + * @brief モンスターへのシンボル抹殺処理ルーチン / Delete all non-unique/non-quest monsters of a given "type" from the level + * @param power 抹殺の威力 + * @param player_cast プレイヤーの魔法によるものならば TRUE * @return 効力があった場合TRUEを返す */ -bool detect_monsters_xxx(int range, u32b match_flag) +bool symbol_genocide(int power, bool player_cast) { - int i, y, x; - bool flag = FALSE; - cptr desc_monsters = _("変なモンスター", "weird monsters"); + MONSTER_IDX i; + char typ; + bool result = FALSE; - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) range /= 3; + /* Prevent genocide in quest levels */ + if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) + { + return (FALSE); + } - /* Scan monsters */ + /* Mega-Hack -- Get a monster symbol */ + while (!get_com(_("どの種類(文字)のモンスターを抹殺しますか: ", "Choose a monster race (by symbol) to genocide: "), &typ, FALSE)) ; + + /* Delete the monsters of that "type" */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Skip dead monsters */ + /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ - y = m_ptr->fy; - x = m_ptr->fx; - - /* Only detect nearby monsters */ - if (distance(p_ptr->y, p_ptr->x, y, x) > range) continue; + /* Skip "wrong" monsters */ + if (r_ptr->d_char != typ) continue; - /* Detect evil monsters */ - if (r_ptr->flags3 & (match_flag)) - { - if (is_original_ap(m_ptr)) - { - /* Take note that they are something */ - r_ptr->r_flags3 |= (match_flag); + /* Take note */ + result |= genocide_aux(i, power, player_cast, 4, _("抹殺", "Genocide")); + } - /* Update monster recall window */ - if (p_ptr->monster_race_idx == m_ptr->r_idx) - { - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); - } - } + if (result) + { + chg_virtue(V_VITALITY, -2); + chg_virtue(V_CHANCE, -1); + } - /* Repair visibility later */ - repair_monsters = TRUE; + return result; +} - /* Hack -- Detect monster */ - m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW); - /* Update the monster */ - update_mon(i, FALSE); +/*! + * @brief モンスターへの周辺抹殺処理ルーチン / Delete all nearby (non-unique) monsters + * @param power 抹殺の威力 + * @param player_cast プレイヤーの魔法によるものならば TRUE + * @return 効力があった場合TRUEを返す + */ +bool mass_genocide(int power, bool player_cast) +{ + MONSTER_IDX i; + bool result = FALSE; - /* Detect */ - flag = TRUE; - } + /* Prevent mass genocide in quest levels */ + if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) + { + return (FALSE); } - /* Describe */ - if (flag) + /* Delete the (nearby) monsters */ + for (i = 1; i < m_max; i++) { - switch (match_flag) - { - case RF3_DEMON: - desc_monsters = _("デーモン", "demons"); - break; - case RF3_UNDEAD: - desc_monsters = _("アンデッド", "the undead"); - break; - } + monster_type *m_ptr = &m_list[i]; + + /* Paranoia -- Skip dead monsters */ + if (!m_ptr->r_idx) continue; + + /* Skip distant monsters */ + if (m_ptr->cdis > MAX_SIGHT) continue; - /* Describe result */ - msg_format(_("%sの存在を感じとった!", "You sense the presence of %s!"), desc_monsters); - msg_print(NULL); + /* Note effect */ + result |= genocide_aux(i, power, player_cast, 3, _("周辺抹殺", "Mass Genocide")); } - /* Result */ - return (flag); + if (result) + { + chg_virtue(V_VITALITY, -2); + chg_virtue(V_CHANCE, -1); + } + + return result; } /*! - * @brief 全感知処理 / Detect everything - * @param range 効果範囲 + * @brief アンデッド・モンスターへの周辺抹殺処理ルーチン / Delete all nearby (non-unique) undead + * @param power 抹殺の威力 + * @param player_cast プレイヤーの魔法によるものならば TRUE * @return 効力があった場合TRUEを返す */ -bool detect_all(int range) +bool mass_genocide_undead(int power, bool player_cast) { - bool detect = FALSE; + MONSTER_IDX i; + bool result = FALSE; - /* Detect everything */ - if (detect_traps(range, TRUE)) detect = TRUE; - if (detect_doors(range)) detect = TRUE; - if (detect_stairs(range)) detect = TRUE; + /* Prevent mass genocide in quest levels */ + if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) + { + return (FALSE); + } - /* There are too many hidden treasure. So... */ - /* if (detect_treasure(range)) detect = TRUE; */ + /* Delete the (nearby) monsters */ + for (i = 1; i < m_max; i++) + { + monster_type *m_ptr = &m_list[i]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; - if (detect_objects_gold(range)) detect = TRUE; - if (detect_objects_normal(range)) detect = TRUE; - if (detect_monsters_invis(range)) detect = TRUE; - if (detect_monsters_normal(range)) detect = TRUE; + /* Paranoia -- Skip dead monsters */ + if (!m_ptr->r_idx) continue; - /* Result */ - return (detect); + if (!(r_ptr->flags3 & RF3_UNDEAD)) continue; + + /* Skip distant monsters */ + if (m_ptr->cdis > MAX_SIGHT) continue; + + /* Note effect */ + result |= genocide_aux(i, power, player_cast, 3, _("アンデッド消滅", "Annihilate Undead")); + } + + if (result) + { + chg_virtue(V_UNLIFE, -2); + chg_virtue(V_CHANCE, -1); + } + + return result; } /*! - * @brief 視界内モンスターに魔法効果を与える / Apply a "project()" directly to all viewable monsters - * @param typ 属性効果 - * @param dam 効果量 + * @brief 周辺モンスターを調査する / Probe nearby monsters * @return 効力があった場合TRUEを返す - * @details - *
- * Note that affected monsters are NOT auto-tracked by this usage.
- *
- * To avoid misbehavior when monster deaths have side-effects,
- * this is done in two passes. -- JDL
- * 
*/ -bool project_hack(int typ, int dam) +bool probing(void) { - int i, x, y; - int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE; - bool obvious = FALSE; + int i; + SPEED speed; + bool_hack cu, cv; + bool probe = FALSE; + char buf[256]; + cptr align; + cu = Term->scr->cu; + cv = Term->scr->cv; + Term->scr->cu = 0; + Term->scr->cv = 1; - /* Mark all (nearby) monsters */ + /* Probe all (nearby) monsters */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; - /* Location */ - y = m_ptr->fy; - x = m_ptr->fx; - /* Require line of sight */ - if (!player_has_los_bold(y, x) || !projectable(p_ptr->y, p_ptr->x, y, x)) continue; + if (!player_has_los_bold(m_ptr->fy, m_ptr->fx)) continue; - /* Mark the monster */ - m_ptr->mflag |= (MFLAG_TEMP); - } + /* Probe visible monsters */ + if (m_ptr->ml) + { + char m_name[80]; - /* Affect all marked monsters */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; + /* Start the message */ + if (!probe) + { + msg_print(_("調査中...", "Probing...")); + } - /* Skip unmarked monsters */ - if (!(m_ptr->mflag & (MFLAG_TEMP))) continue; + msg_print(NULL); - /* Remove mark */ - m_ptr->mflag &= ~(MFLAG_TEMP); + if (!is_original_ap(m_ptr)) + { + if (m_ptr->mflag2 & MFLAG2_KAGE) + m_ptr->mflag2 &= ~(MFLAG2_KAGE); - /* Location */ - y = m_ptr->fy; - x = m_ptr->fx; + m_ptr->ap_r_idx = m_ptr->r_idx; + lite_spot(m_ptr->fy, m_ptr->fx); + } + /* Get "the monster" or "something" */ + monster_desc(m_name, m_ptr, MD_IGNORE_HALLU | MD_INDEF_HIDDEN); - /* Jump directly to the target monster */ - if (project(0, 0, y, x, dam, typ, flg, -1)) obvious = TRUE; - } + speed = m_ptr->mspeed - 110; + if (MON_FAST(m_ptr)) speed += 10; + if (MON_SLOW(m_ptr)) speed -= 10; + if (ironman_nightmare) speed += 5; - /* Result */ - return (obvious); -} + /* Get the monster's alignment */ + if ((r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) == (RF3_EVIL | RF3_GOOD)) align = _("善悪", "good&evil"); + else if (r_ptr->flags3 & RF3_EVIL) align = _("邪悪", "evil"); + else if (r_ptr->flags3 & RF3_GOOD) align = _("善良", "good"); + else if ((m_ptr->sub_align & (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) == (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) _(align = "中立(善悪)", "neutral(good&evil)"); + else if (m_ptr->sub_align & SUB_ALIGN_EVIL) align = _("中立(邪悪)", "neutral(evil)"); + else if (m_ptr->sub_align & SUB_ALIGN_GOOD) align = _("中立(善良)", "neutral(good)"); + else align = _("中立", "neutral"); + /* Describe the monster */ + sprintf(buf,_("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:"), + m_name, align, (int)m_ptr->hp, (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed); -/*! - * @brief 視界内モンスターを加速する処理 / Speed monsters - * @return 効力があった場合TRUEを返す - */ -bool speed_monsters(void) -{ - return (project_hack(GF_OLD_SPEED, p_ptr->lev)); -} + if (r_ptr->next_r_idx) + { + strcat(buf, format("%d/%d ", m_ptr->exp, r_ptr->next_exp)); + } + else + { + strcat(buf, "xxx "); + } -/*! - * @brief 視界内モンスターを加速する処理 / Slow monsters - * @return 効力があった場合TRUEを返す - */ -bool slow_monsters(int power) -{ - return (project_hack(GF_OLD_SLOW, power)); -} + if (MON_CSLEEP(m_ptr)) strcat(buf,_("睡眠 ", "sleeping ")); + if (MON_STUNNED(m_ptr)) strcat(buf, _("朦朧 ", "stunned ")); + if (MON_MONFEAR(m_ptr)) strcat(buf, _("恐怖 ", "scared ")); + if (MON_CONFUSED(m_ptr)) strcat(buf, _("混乱 ", "confused ")); + if (MON_INVULNER(m_ptr)) strcat(buf, _("無敵 ", "invulnerable ")); + buf[strlen(buf)-1] = '\0'; + prt(buf, 0, 0); -/*! - * @brief 視界内モンスターを眠らせる処理 / Sleep monsters - * @return 効力があった場合TRUEを返す - */ -bool sleep_monsters(int power) -{ - return (project_hack(GF_OLD_SLEEP, power)); -} + /* HACK : Add the line to message buffer */ + message_add(buf); + p_ptr->window |= (PW_MESSAGE); + window_stuff(); -/*! - * @brief 視界内の邪悪なモンスターをテレポート・アウェイさせる処理 / Banish evil monsters - * @return 効力があった場合TRUEを返す - */ -bool banish_evil(int dist) -{ - return (project_hack(GF_AWAY_EVIL, dist)); -} + if (m_ptr->ml) move_cursor_relative(m_ptr->fy, m_ptr->fx); + inkey(); -/*! - * @brief 視界内のアンデッド・モンスターを恐怖させる処理 / Turn undead - * @return 効力があった場合TRUEを返す - */ -bool turn_undead(void) -{ - bool tester = (project_hack(GF_TURN_UNDEAD, p_ptr->lev)); - if (tester) - chg_virtue(V_UNLIFE, -1); - return tester; -} + Term_erase(0, 0, 255); -/*! - * @brief 視界内のアンデッド・モンスターにダメージを与える処理 / Dispel undead monsters - * @return 効力があった場合TRUEを返す - */ -bool dispel_undead(int dam) -{ - bool tester = (project_hack(GF_DISP_UNDEAD, dam)); - if (tester) - chg_virtue(V_UNLIFE, -2); - return tester; -} + /* Learn everything about this monster */ + if (lore_do_probe(m_ptr->r_idx)) + { + /* Get base name of monster */ + strcpy(buf, (r_name + r_ptr->name)); -/*! - * @brief 視界内の邪悪なモンスターにダメージを与える処理 / Dispel evil monsters - * @return 効力があった場合TRUEを返す - */ -bool dispel_evil(int dam) -{ - return (project_hack(GF_DISP_EVIL, dam)); -} +#ifdef JP + /* Note that we learnt some new flags -Mogami- */ + msg_format("%sについてさらに詳しくなった気がする。", buf); +#else + /* Pluralize it */ + plural_aux(buf); -/*! - * @brief 視界内の善良なモンスターにダメージを与える処理 / Dispel good monsters - * @return 効力があった場合TRUEを返す - */ -bool dispel_good(int dam) -{ - return (project_hack(GF_DISP_GOOD, dam)); -} + /* Note that we learnt some new flags -Mogami- */ + msg_format("You now know more about %s.", buf); +#endif + /* Clear -more- prompt */ + msg_print(NULL); + } -/*! - * @brief 視界内のあらゆるモンスターにダメージを与える処理 / Dispel all monsters - * @return 効力があった場合TRUEを返す - */ -bool dispel_monsters(int dam) -{ - return (project_hack(GF_DISP_ALL, dam)); -} + /* Probe worked */ + probe = TRUE; + } + } -/*! - * @brief 視界内の生命のあるモンスターにダメージを与える処理 / Dispel 'living' monsters - * @return 効力があった場合TRUEを返す - */ -bool dispel_living(int dam) -{ - return (project_hack(GF_DISP_LIVING, dam)); + Term->scr->cu = cu; + Term->scr->cv = cv; + Term_fresh(); + + if (probe) + { + chg_virtue(V_KNOWLEDGE, 1); + msg_print(_("これで全部です。", "That's all.")); + } + return (probe); } -/*! - * @brief 視界内の悪魔系モンスターにダメージを与える処理 / Dispel 'living' monsters - * @return 効力があった場合TRUEを返す - */ -bool dispel_demons(int dam) -{ - return (project_hack(GF_DISP_DEMON, dam)); -} + /*! - * @brief 視界内のモンスターに「聖戦」効果を与える処理 + * @brief *破壊*処理を行う / The spell of destruction + * @param y1 破壊の中心Y座標 + * @param x1 破壊の中心X座標 + * @param r 破壊の半径 + * @param in_generate ダンジョンフロア生成中の処理ならばTRUE * @return 効力があった場合TRUEを返す + * @details + *
+ * This spell "deletes" monsters (instead of "killing" them).
+ *
+ * Later we may use one function for both "destruction" and
+ * "earthquake" by using the "full" to select "destruction".
+ * 
*/ -bool crusade(void) +bool destroy_area(POSITION y1, POSITION x1, POSITION r, bool in_generate) { - return (project_hack(GF_CRUSADE, p_ptr->lev*4)); -} + POSITION y, x; + int k, t; + cave_type *c_ptr; + bool flag = FALSE; -/*! - * @brief 視界内モンスターを怒らせる処理 / Wake up all monsters, and speed up "los" monsters. - * @param who 怒らせる原因を起こしたモンスター(0ならばプレイヤー) - * @return なし - */ -void aggravate_monsters(int who) -{ - int i; - bool sleep = FALSE; - bool speed = FALSE; + /* Prevent destruction of quest levels and town */ + if ((p_ptr->inside_quest && is_fixed_quest_idx(p_ptr->inside_quest)) || !dun_level) + { + return (FALSE); + } + /* Lose monster light */ + if (!in_generate) clear_mon_lite(); - /* Aggravate everyone nearby */ - for (i = 1; i < m_max; i++) + /* Big area of affect */ + for (y = (y1 - r); y <= (y1 + r); y++) { - monster_type *m_ptr = &m_list[i]; -/* monster_race *r_ptr = &r_info[m_ptr->r_idx]; */ + for (x = (x1 - r); x <= (x1 + r); x++) + { + /* Skip illegal grids */ + if (!in_bounds(y, x)) continue; - /* Paranoia -- Skip dead monsters */ - if (!m_ptr->r_idx) continue; + /* Extract the distance */ + k = distance(y1, x1, y, x); - /* Skip aggravating monster (or player) */ - if (i == who) continue; + /* Stay in the circle of death */ + if (k > r) continue; + c_ptr = &cave[y][x]; - /* Wake up nearby sleeping monsters */ - if (m_ptr->cdis < MAX_SIGHT * 2) - { - /* Wake up */ - if (MON_CSLEEP(m_ptr)) - { - (void)set_monster_csleep(i, 0); - sleep = TRUE; - } - if (!is_pet(m_ptr)) m_ptr->mflag2 |= MFLAG2_NOPET; - } + /* Lose room and vault */ + c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY); - /* Speed up monsters in line of sight */ - if (player_has_los_bold(m_ptr->fy, m_ptr->fx)) - { - if (!is_pet(m_ptr)) + /* Lose light and knowledge */ + c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN); + + if (!in_generate) /* Normal */ { - (void)set_monster_fast(i, MON_FAST(m_ptr) + 100); - speed = TRUE; - } - } - } + /* Lose unsafety */ + c_ptr->info &= ~(CAVE_UNSAFE); - /* Messages */ -#ifdef JP - if (speed) msg_print("付近で何かが突如興奮したような感じを受けた!"); - else if (sleep) msg_print("何かが突如興奮したような騒々しい音が遠くに聞こえた!"); -#else - if (speed) msg_print("You feel a sudden stirring nearby!"); - else if (sleep) msg_print("You hear a sudden stirring in the distance!"); -#endif - if (p_ptr->riding) p_ptr->update |= PU_BONUS; -} + /* Hack -- Notice player affect */ + if (player_bold(y, x)) + { + /* Hurt the player later */ + flag = TRUE; + /* Do not hurt this grid */ + continue; + } + } -/*! - * @brief モンスターへの単体抹殺処理サブルーチン / Delete a non-unique/non-quest monster - * @param m_idx 抹殺するモンスターID - * @param power 抹殺の威力 - * @param player_cast プレイヤーの魔法によるものならば TRUE - * @param dam_side プレイヤーへの負担ダメージ量(1d(dam_side)) - * @param spell_name 抹殺効果を起こした魔法の名前 - * @return 効力があった場合TRUEを返す - */ -bool genocide_aux(int m_idx, int power, bool player_cast, int dam_side, cptr spell_name) -{ - int msec = delay_factor * delay_factor * delay_factor; - monster_type *m_ptr = &m_list[m_idx]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - bool resist = FALSE; + /* Hack -- Skip the epicenter */ + if ((y == y1) && (x == x1)) continue; - if (is_pet(m_ptr) && !player_cast) return FALSE; + if (c_ptr->m_idx) + { + monster_type *m_ptr = &m_list[c_ptr->m_idx]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Hack -- Skip Unique Monsters or Quest Monsters */ - if (r_ptr->flags1 & (RF1_UNIQUE | RF1_QUESTOR)) resist = TRUE; + if (in_generate) /* In generation */ + { + /* Delete the monster (if any) */ + delete_monster(y, x); + } + else if (r_ptr->flags1 & RF1_QUESTOR) + { + /* Heal the monster */ + m_ptr->hp = m_ptr->maxhp; - else if (r_ptr->flags7 & RF7_UNIQUE2) resist = TRUE; + /* Try to teleport away quest monsters */ + if (!teleport_away(c_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) continue; + } + else + { + if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) + { + char m_name[80]; - else if (m_idx == p_ptr->riding) resist = TRUE; + monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); + do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name); + } - else if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) resist = TRUE; + /* Delete the monster (if any) */ + delete_monster(y, x); + } + } - else if (player_cast && (r_ptr->level > randint0(power))) resist = TRUE; + /* During generation, destroyed artifacts are "preserved" */ + if (preserve_mode || in_generate) + { + OBJECT_IDX this_o_idx, next_o_idx = 0; - else if (player_cast && (m_ptr->mflag2 & MFLAG2_NOGENO)) resist = TRUE; + /* Scan all objects in the grid */ + for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type *o_ptr; + o_ptr = &o_list[this_o_idx]; - /* Delete the monster */ - else - { - if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) - { - char m_name[80]; + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; - monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); - do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_GENOCIDE, m_name); - } + /* Hack -- Preserve unknown artifacts */ + if (object_is_fixed_artifact(o_ptr) && (!object_is_known(o_ptr) || in_generate)) + { + /* Mega-Hack -- Preserve the artifact */ + a_info[o_ptr->name1].cur_num = 0; - delete_monster_idx(m_idx); - } + if (in_generate && cheat_peek) + { + char o_name[MAX_NLEN]; + object_desc(o_name, o_ptr, (OD_NAME_ONLY | OD_STORE)); + msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), o_name); + } + } + else if (in_generate && cheat_peek && o_ptr->art_name) + { + msg_print(_("ランダム・アーティファクトの1つは生成中に*破壊*された。", + "One of the random artifacts was *destroyed* during generation.")); + } + } + } - if (resist && player_cast) - { - bool see_m = is_seen(m_ptr); - char m_name[80]; + /* Delete objects */ + delete_object(y, x); - monster_desc(m_name, m_ptr, 0); - if (see_m) - { - msg_format(_("%^sには効果がなかった。", "%^s is unaffected."), m_name); - } - if (MON_CSLEEP(m_ptr)) - { - (void)set_monster_csleep(m_idx, 0); - if (m_ptr->ml) - { - msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name); - } - } - if (is_friendly(m_ptr) && !is_pet(m_ptr)) - { - if (see_m) + /* Destroy "non-permanent" grids */ + if (!cave_perma_grid(c_ptr)) { - msg_format(_("%sは怒った!", "%^s gets angry!"), m_name); + /* Wall (or floor) type */ + t = randint0(200); + + if (!in_generate) /* Normal */ + { + if (t < 20) + { + /* Create granite wall */ + cave_set_feat(y, x, feat_granite); + } + else if (t < 70) + { + /* Create quartz vein */ + cave_set_feat(y, x, feat_quartz_vein); + } + else if (t < 100) + { + /* Create magma vein */ + cave_set_feat(y, x, feat_magma_vein); + } + else + { + /* Create floor */ + cave_set_feat(y, x, floor_type[randint0(100)]); + } + } + else /* In generation */ + { + if (t < 20) + { + /* Create granite wall */ + place_extra_grid(c_ptr); + } + else if (t < 70) + { + /* Create quartz vein */ + c_ptr->feat = feat_quartz_vein; + } + else if (t < 100) + { + /* Create magma vein */ + c_ptr->feat = feat_magma_vein; + } + else + { + /* Create floor */ + place_floor_grid(c_ptr); + } + + /* Clear garbage of hidden trap or door */ + c_ptr->mimic = 0; + } } - set_hostile(m_ptr); } - if (one_in_(13)) m_ptr->mflag2 |= MFLAG2_NOGENO; } - if (player_cast) + if (!in_generate) { - /* Take damage */ - take_hit(DAMAGE_GENO, randint1(dam_side), format(_("%^sの呪文を唱えた疲労", "the strain of casting %^s"), spell_name), -1); - } - - /* Visual feedback */ - move_cursor_relative(p_ptr->y, p_ptr->x); - - /* Redraw */ - p_ptr->redraw |= (PR_HP); - - /* Window stuff */ - p_ptr->window |= (PW_PLAYER); - - /* Handle */ - handle_stuff(); + /* Process "re-glowing" */ + for (y = (y1 - r); y <= (y1 + r); y++) + { + for (x = (x1 - r); x <= (x1 + r); x++) + { + /* Skip illegal grids */ + if (!in_bounds(y, x)) continue; - /* Fresh */ - Term_fresh(); + /* Extract the distance */ + k = distance(y1, x1, y, x); - /* Delay */ - Term_xtra(TERM_XTRA_DELAY, msec); + /* Stay in the circle of death */ + if (k > r) continue; + c_ptr = &cave[y][x]; - return !resist; -} + if (is_mirror_grid(c_ptr)) c_ptr->info |= CAVE_GLOW; + else if (!(d_info[dungeon_type].flags1 & DF1_DARKNESS)) + { + int i, yy, xx; + cave_type *cc_ptr; + for (i = 0; i < 9; i++) + { + yy = y + ddy_ddd[i]; + xx = x + ddx_ddd[i]; + if (!in_bounds2(yy, xx)) continue; + cc_ptr = &cave[yy][xx]; + if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) + { + c_ptr->info |= CAVE_GLOW; + break; + } + } + } + } + } -/*! - * @brief モンスターへのシンボル抹殺処理ルーチン / Delete all non-unique/non-quest monsters of a given "type" from the level - * @param power 抹殺の威力 - * @param player_cast プレイヤーの魔法によるものならば TRUE - * @return 効力があった場合TRUEを返す - */ -bool symbol_genocide(int power, bool player_cast) -{ - int i; - char typ; - bool result = FALSE; + /* Hack -- Affect player */ + if (flag) + { + msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!")); - /* Prevent genocide in quest levels */ - if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) - { - return (FALSE); - } + /* Blind the player */ + if (!p_ptr->resist_blind && !p_ptr->resist_lite) + { + /* Become blind */ + (void)set_blind(p_ptr->blind + 10 + randint1(10)); + } + } - /* Mega-Hack -- Get a monster symbol */ - while (!get_com(_("どの種類(文字)のモンスターを抹殺しますか: ", "Choose a monster race (by symbol) to genocide: "), &typ, FALSE)) ; + forget_flow(); - /* Delete the monsters of that "type" */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; + /* Mega-Hack -- Forget the view and lite */ + p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE); - /* Paranoia -- Skip dead monsters */ - if (!m_ptr->r_idx) continue; + p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS); - /* Skip "wrong" monsters */ - if (r_ptr->d_char != typ) continue; + p_ptr->redraw |= (PR_MAP); - /* Take note */ - result |= genocide_aux(i, power, player_cast, 4, _("抹殺", "Genocide")); - } + p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); - if (result) - { - chg_virtue(V_VITALITY, -2); - chg_virtue(V_CHANCE, -1); + if (p_ptr->special_defense & NINJA_S_STEALTH) + { + if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); + } } - return result; + /* Success */ + return (TRUE); } /*! - * @brief モンスターへの周辺抹殺処理ルーチン / Delete all nearby (non-unique) monsters - * @param power 抹殺の威力 - * @param player_cast プレイヤーの魔法によるものならば TRUE + * @brief 地震処理(サブルーチン) / + * Induce an "earthquake" of the given radius at the given location. * @return 効力があった場合TRUEを返す + * @param cy 中心Y座標 + * @param cx 中心X座標 + * @param r 効果半径 + * @param m_idx 地震を起こしたモンスターID(0ならばプレイヤー) + * @details + *
+ *
+ * This will turn some walls into floors and some floors into walls.
+ *
+ * The player will take damage and "jump" into a safe grid if possible,
+ * otherwise, he will "tunnel" through the rubble instantaneously.
+ *
+ * Monsters will take damage, and "jump" into a safe grid if possible,
+ * otherwise they will be "buried" in the rubble, disappearing from
+ * the level in the same way that they do when genocided.
+ *
+ * Note that thus the player and monsters (except eaters of walls and
+ * passers through walls) will never occupy the same grid as a wall.
+ * Note that as of now (2.7.8) no monster may occupy a "wall" grid, even
+ * for a single turn, unless that monster can pass_walls or kill_walls.
+ * This has allowed massive simplification of the "monster" code.
+ * 
*/ -bool mass_genocide(int power, bool player_cast) +bool earthquake_aux(POSITION cy, POSITION cx, POSITION r, MONSTER_IDX m_idx) { - int i; - bool result = FALSE; + DIRECTION i; + int t; + POSITION y, x, yy, xx, dy, dx; + int damage = 0; + int sn = 0; + POSITION sy = 0, sx = 0; + bool hurt = FALSE; + cave_type *c_ptr; + bool map[32][32]; - /* Prevent mass genocide in quest levels */ - if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) + + /* Prevent destruction of quest levels and town */ + if ((p_ptr->inside_quest && is_fixed_quest_idx(p_ptr->inside_quest)) || !dun_level) { return (FALSE); } - /* Delete the (nearby) monsters */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - - /* Paranoia -- Skip dead monsters */ - if (!m_ptr->r_idx) continue; - - /* Skip distant monsters */ - if (m_ptr->cdis > MAX_SIGHT) continue; - - /* Note effect */ - result |= genocide_aux(i, power, player_cast, 3, _("周辺抹殺", "Mass Genocide")); - } + /* Paranoia -- Enforce maximum range */ + if (r > 12) r = 12; - if (result) + /* Clear the "maximal blast" area */ + for (y = 0; y < 32; y++) { - chg_virtue(V_VITALITY, -2); - chg_virtue(V_CHANCE, -1); + for (x = 0; x < 32; x++) + { + map[y][x] = FALSE; + } } - return result; -} + /* Check around the epicenter */ + for (dy = -r; dy <= r; dy++) + { + for (dx = -r; dx <= r; dx++) + { + /* Extract the location */ + yy = cy + dy; + xx = cx + dx; + /* Skip illegal grids */ + if (!in_bounds(yy, xx)) continue; -/*! - * @brief アンデッド・モンスターへの周辺抹殺処理ルーチン / Delete all nearby (non-unique) undead - * @param power 抹殺の威力 - * @param player_cast プレイヤーの魔法によるものならば TRUE - * @return 効力があった場合TRUEを返す - */ -bool mass_genocide_undead(int power, bool player_cast) -{ - int i; - bool result = FALSE; + /* Skip distant grids */ + if (distance(cy, cx, yy, xx) > r) continue; + c_ptr = &cave[yy][xx]; - /* Prevent mass genocide in quest levels */ - if ((p_ptr->inside_quest && !random_quest_number(dun_level)) || p_ptr->inside_arena || p_ptr->inside_battle) - { - return (FALSE); - } + /* Lose room and vault */ + c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY | CAVE_UNSAFE); - /* Delete the (nearby) monsters */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; + /* Lose light and knowledge */ + c_ptr->info &= ~(CAVE_GLOW | CAVE_MARK | CAVE_KNOWN); - /* Paranoia -- Skip dead monsters */ - if (!m_ptr->r_idx) continue; + /* Skip the epicenter */ + if (!dx && !dy) continue; - if (!(r_ptr->flags3 & RF3_UNDEAD)) continue; + /* Skip most grids */ + if (randint0(100) < 85) continue; - /* Skip distant monsters */ - if (m_ptr->cdis > MAX_SIGHT) continue; + /* Damage this grid */ + map[16+yy-cy][16+xx-cx] = TRUE; - /* Note effect */ - result |= genocide_aux(i, power, player_cast, 3, _("アンデッド消滅", "Annihilate Undead")); + /* Hack -- Take note of player damage */ + if (player_bold(yy, xx)) hurt = TRUE; + } } - if (result) + /* First, affect the player (if necessary) */ + if (hurt && !p_ptr->pass_wall && !p_ptr->kill_wall) { - chg_virtue(V_UNLIFE, -2); - chg_virtue(V_CHANCE, -1); - } - - return result; -} + /* Check around the player */ + for (i = 0; i < 8; i++) + { + /* Access the location */ + y = p_ptr->y + ddy_ddd[i]; + x = p_ptr->x + ddx_ddd[i]; + /* Skip non-empty grids */ + if (!cave_empty_bold(y, x)) continue; -/*! - * @brief 周辺モンスターを調査する / Probe nearby monsters - * @return 効力があった場合TRUEを返す - */ -bool probing(void) -{ - int i, speed; - int cu, cv; - bool probe = FALSE; - char buf[256]; - cptr align; + /* Important -- Skip "quake" grids */ + if (map[16+y-cy][16+x-cx]) continue; - cu = Term->scr->cu; - cv = Term->scr->cv; - Term->scr->cu = 0; - Term->scr->cv = 1; + if (cave[y][x].m_idx) continue; - /* Probe all (nearby) monsters */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; + /* Count "safe" grids */ + sn++; - /* Paranoia -- Skip dead monsters */ - if (!m_ptr->r_idx) continue; + /* Randomize choice */ + if (randint0(sn) > 0) continue; - /* Require line of sight */ - if (!player_has_los_bold(m_ptr->fy, m_ptr->fx)) continue; + /* Save the safe location */ + sy = y; sx = x; + } - /* Probe visible monsters */ - if (m_ptr->ml) + /* Random message */ + switch (randint1(3)) { - char m_name[80]; - - /* Start the message */ - if (!probe) + case 1: { - msg_print(_("調査中...", "Probing...")); + msg_print(_("ダンジョンの壁が崩れた!", "The cave ceiling collapses!")); + break; } + case 2: + { + msg_print(_("ダンジョンの床が不自然にねじ曲がった!", "The cave floor twists in an unnatural way!")); + break; + } + default: + { + msg_print(_("ダンジョンが揺れた!崩れた岩が頭に降ってきた!", "The cave quakes! You are pummeled with debris!")); + break; + } + } - msg_print(NULL); + /* Hurt the player a lot */ + if (!sn) + { + /* Message and damage */ + msg_print(_("あなたはひどい怪我を負った!", "You are severely crushed!")); + damage = 200; + } - if (!is_original_ap(m_ptr)) + /* Destroy the grid, and push the player to safety */ + else + { + /* Calculate results */ + switch (randint1(3)) { - if (m_ptr->mflag2 & MFLAG2_KAGE) - m_ptr->mflag2 &= ~(MFLAG2_KAGE); - - m_ptr->ap_r_idx = m_ptr->r_idx; - lite_spot(m_ptr->fy, m_ptr->fx); + case 1: + { + msg_print(_("降り注ぐ岩をうまく避けた!", "You nimbly dodge the blast!")); + damage = 0; + break; + } + case 2: + { + msg_print(_("岩石があなたに直撃した!", "You are bashed by rubble!")); + damage = damroll(10, 4); + (void)set_stun(p_ptr->stun + randint1(50)); + break; + } + case 3: + { + msg_print(_("あなたは床と壁との間に挟まれてしまった!", "You are crushed between the floor and ceiling!")); + damage = damroll(10, 4); + (void)set_stun(p_ptr->stun + randint1(50)); + break; + } } - /* Get "the monster" or "something" */ - monster_desc(m_name, m_ptr, MD_IGNORE_HALLU | MD_INDEF_HIDDEN); - speed = m_ptr->mspeed - 110; - if (MON_FAST(m_ptr)) speed += 10; - if (MON_SLOW(m_ptr)) speed -= 10; + /* Move the player to the safe location */ + (void)move_player_effect(sy, sx, MPE_DONT_PICKUP); + } - /* Get the monster's alignment */ -#ifdef JP - if ((r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) == (RF3_EVIL | RF3_GOOD)) align = "善悪"; - else if (r_ptr->flags3 & RF3_EVIL) align = "邪悪"; - else if (r_ptr->flags3 & RF3_GOOD) align = "善良"; - else if ((m_ptr->sub_align & (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) == (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) align = "中立(善悪)"; - else if (m_ptr->sub_align & SUB_ALIGN_EVIL) align = "中立(邪悪)"; - else if (m_ptr->sub_align & SUB_ALIGN_GOOD) align = "中立(善良)"; - else align = "中立"; -#else - if ((r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) == (RF3_EVIL | RF3_GOOD)) align = "good&evil"; - else if (r_ptr->flags3 & RF3_EVIL) align = "evil"; - else if (r_ptr->flags3 & RF3_GOOD) align = "good"; - else if ((m_ptr->sub_align & (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) == (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) align = "neutral(good&evil)"; - else if (m_ptr->sub_align & SUB_ALIGN_EVIL) align = "neutral(evil)"; - else if (m_ptr->sub_align & SUB_ALIGN_GOOD) align = "neutral(good)"; - else align = "neutral"; -#endif + /* Important -- no wall on player */ + map[16+p_ptr->y-cy][16+p_ptr->x-cx] = FALSE; - /* Describe the monster */ - sprintf(buf,_("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:"), - m_name, align, (int)m_ptr->hp, (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed); + if (damage) + { + cptr killer; - if (r_ptr->next_r_idx) + if (m_idx) { - strcat(buf, format("%d/%d ", m_ptr->exp, r_ptr->next_exp)); + char m_name[80]; + monster_type *m_ptr = &m_list[m_idx]; + + /* Get the monster's real name */ + monster_desc(m_name, m_ptr, MD_IGNORE_HALLU | MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE); + + killer = format(_("%sの起こした地震", "an earthquake caused by %s"), m_name); } else { - strcat(buf, "xxx "); + killer = _("地震", "an earthquake"); } -#ifdef JP - if (MON_CSLEEP(m_ptr)) strcat(buf,"睡眠 "); - if (MON_STUNNED(m_ptr)) strcat(buf,"朦朧 "); - if (MON_MONFEAR(m_ptr)) strcat(buf,"恐怖 "); - if (MON_CONFUSED(m_ptr)) strcat(buf,"混乱 "); - if (MON_INVULNER(m_ptr)) strcat(buf,"無敵 "); -#else - if (MON_CSLEEP(m_ptr)) strcat(buf,"sleeping "); - if (MON_STUNNED(m_ptr)) strcat(buf,"stunned "); - if (MON_MONFEAR(m_ptr)) strcat(buf,"scared "); - if (MON_CONFUSED(m_ptr)) strcat(buf,"confused "); - if (MON_INVULNER(m_ptr)) strcat(buf,"invulnerable "); -#endif - buf[strlen(buf)-1] = '\0'; - prt(buf,0,0); + take_hit(DAMAGE_ATTACK, damage, killer, -1); + } + } - /* HACK : Add the line to message buffer */ - message_add(buf); - p_ptr->window |= (PW_MESSAGE); - window_stuff(); + /* Examine the quaked region */ + for (dy = -r; dy <= r; dy++) + { + for (dx = -r; dx <= r; dx++) + { + /* Extract the location */ + yy = cy + dy; + xx = cx + dx; - if (m_ptr->ml) move_cursor_relative(m_ptr->fy, m_ptr->fx); - inkey(); + /* Skip unaffected grids */ + if (!map[16+yy-cy][16+xx-cx]) continue; + c_ptr = &cave[yy][xx]; - Term_erase(0, 0, 255); + if (c_ptr->m_idx == p_ptr->riding) continue; - /* Learn everything about this monster */ - if (lore_do_probe(m_ptr->r_idx)) + /* Process monsters */ + if (c_ptr->m_idx) { - /* Get base name of monster */ - strcpy(buf, (r_name + r_ptr->name)); - -#ifdef JP - /* Note that we learnt some new flags -Mogami- */ - msg_format("%sについてさらに詳しくなった気がする。", buf); -#else - /* Pluralize it */ - plural_aux(buf); - - /* Note that we learnt some new flags -Mogami- */ - msg_format("You now know more about %s.", buf); -#endif - /* Clear -more- prompt */ - msg_print(NULL); - } + monster_type *m_ptr = &m_list[c_ptr->m_idx]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Probe worked */ - probe = TRUE; - } - } + /* Quest monsters */ + if (r_ptr->flags1 & RF1_QUESTOR) + { + /* No wall on quest monsters */ + map[16+yy-cy][16+xx-cx] = FALSE; - Term->scr->cu = cu; - Term->scr->cv = cv; - Term_fresh(); + continue; + } - /* Done */ - if (probe) - { - chg_virtue(V_KNOWLEDGE, 1); - msg_print(_("これで全部です。", "That's all.")); - } + /* Most monsters cannot co-exist with rock */ + if (!(r_ptr->flags2 & (RF2_KILL_WALL)) && + !(r_ptr->flags2 & (RF2_PASS_WALL))) + { + char m_name[80]; - /* Result */ - return (probe); -} + /* Assume not safe */ + sn = 0; + /* Monster can move to escape the wall */ + if (!(r_ptr->flags1 & (RF1_NEVER_MOVE))) + { + /* Look for safety */ + for (i = 0; i < 8; i++) + { + y = yy + ddy_ddd[i]; + x = xx + ddx_ddd[i]; + /* Skip non-empty grids */ + if (!cave_empty_bold(y, x)) continue; -/*! - * @brief *破壊*処理を行う / The spell of destruction - * @param y1 破壊の中心Y座標 - * @param x1 破壊の中心X座標 - * @param r 破壊の半径 - * @param in_generate ダンジョンフロア生成中の処理ならばTRUE - * @return 効力があった場合TRUEを返す - * @details - *
- * This spell "deletes" monsters (instead of "killing" them).
- *
- * Later we may use one function for both "destruction" and
- * "earthquake" by using the "full" to select "destruction".
- * 
- */ -bool destroy_area(int y1, int x1, int r, bool in_generate) -{ - int y, x, k, t; - cave_type *c_ptr; - bool flag = FALSE; + /* Hack -- no safety on glyph of warding */ + if (is_glyph_grid(&cave[y][x])) continue; + if (is_explosive_rune_grid(&cave[y][x])) continue; - /* Prevent destruction of quest levels and town */ - if ((p_ptr->inside_quest && is_fixed_quest_idx(p_ptr->inside_quest)) || !dun_level) - { - return (FALSE); - } + /* ... nor on the Pattern */ + if (pattern_tile(y, x)) continue; - /* Lose monster light */ - if (!in_generate) clear_mon_lite(); + /* Important -- Skip "quake" grids */ + if (map[16+y-cy][16+x-cx]) continue; - /* Big area of affect */ - for (y = (y1 - r); y <= (y1 + r); y++) - { - for (x = (x1 - r); x <= (x1 + r); x++) - { - /* Skip illegal grids */ - if (!in_bounds(y, x)) continue; + if (cave[y][x].m_idx) continue; + if (player_bold(y, x)) continue; - /* Extract the distance */ - k = distance(y1, x1, y, x); + /* Count "safe" grids */ + sn++; - /* Stay in the circle of death */ - if (k > r) continue; + /* Randomize choice */ + if (randint0(sn) > 0) continue; - /* Access the grid */ - c_ptr = &cave[y][x]; + /* Save the safe grid */ + sy = y; sx = x; + } + } - /* Lose room and vault */ - c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY); + /* Describe the monster */ + monster_desc(m_name, m_ptr, 0); - /* Lose light and knowledge */ - c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN); + /* Scream in pain */ + if (!ignore_unview || is_seen(m_ptr)) msg_format(_("%^sは苦痛で泣きわめいた!", "%^s wails out in pain!"), m_name); - if (!in_generate) /* Normal */ - { - /* Lose unsafety */ - c_ptr->info &= ~(CAVE_UNSAFE); + /* Take damage from the quake */ + damage = (sn ? damroll(4, 8) : (m_ptr->hp + 1)); - /* Hack -- Notice player affect */ - if (player_bold(y, x)) - { - /* Hurt the player later */ - flag = TRUE; + /* Monster is certainly awake */ + (void)set_monster_csleep(c_ptr->m_idx, 0); - /* Do not hurt this grid */ - continue; - } - } + /* Apply damage directly */ + m_ptr->hp -= damage; - /* Hack -- Skip the epicenter */ - if ((y == y1) && (x == x1)) continue; + /* Delete (not kill) "dead" monsters */ + if (m_ptr->hp < 0) + { + if (!ignore_unview || is_seen(m_ptr)) + msg_format(_("%^sは岩石に埋もれてしまった!", "%^s is embedded in the rock!"), m_name); - if (c_ptr->m_idx) - { - monster_type *m_ptr = &m_list[c_ptr->m_idx]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; + if (c_ptr->m_idx) + { + if (record_named_pet && is_pet(&m_list[c_ptr->m_idx]) && m_list[c_ptr->m_idx].nickname) + { + char m2_name[80]; - if (in_generate) /* In generation */ - { - /* Delete the monster (if any) */ - delete_monster(y, x); - } - else if (r_ptr->flags1 & RF1_QUESTOR) - { - /* Heal the monster */ - m_ptr->hp = m_ptr->maxhp; + monster_desc(m2_name, m_ptr, MD_INDEF_VISIBLE); + do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_EARTHQUAKE, m2_name); + } + } - /* Try to teleport away quest monsters */ - if (!teleport_away(c_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) continue; - } - else - { - if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) - { - char m_name[80]; - monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); - do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name); + delete_monster(yy, xx); + + /* No longer safe */ + sn = 0; } - /* Delete the monster (if any) */ - delete_monster(y, x); - } - } + /* Hack -- Escape from the rock */ + if (sn) + { + IDX m_idx_aux = cave[yy][xx].m_idx; - /* During generation, destroyed artifacts are "preserved" */ - if (preserve_mode || in_generate) - { - s16b this_o_idx, next_o_idx = 0; + /* Update the old location */ + cave[yy][xx].m_idx = 0; - /* Scan all objects in the grid */ - for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type *o_ptr; + /* Update the new location */ + cave[sy][sx].m_idx = m_idx_aux; - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; + /* Move the monster */ + m_ptr->fy = sy; + m_ptr->fx = sx; - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; + /* Update the monster (new location) */ + update_monster(m_idx, TRUE); - /* Hack -- Preserve unknown artifacts */ - if (object_is_fixed_artifact(o_ptr) && (!object_is_known(o_ptr) || in_generate)) - { - /* Mega-Hack -- Preserve the artifact */ - a_info[o_ptr->name1].cur_num = 0; + /* Redraw the old grid */ + lite_spot(yy, xx); - if (in_generate && cheat_peek) - { - char o_name[MAX_NLEN]; - object_desc(o_name, o_ptr, (OD_NAME_ONLY | OD_STORE)); - msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), o_name); - } - } - else if (in_generate && cheat_peek && o_ptr->art_name) - { - msg_print(_("ランダム・アーティファクトの1つは生成中に*破壊*された。", - "One of the random artifacts was *destroyed* during generation.")); + /* Redraw the new grid */ + lite_spot(sy, sx); } } } + } + } - /* Delete objects */ - delete_object(y, x); + /* Lose monster light */ + clear_mon_lite(); - /* Destroy "non-permanent" grids */ - if (!cave_perma_grid(c_ptr)) + /* Examine the quaked region */ + for (dy = -r; dy <= r; dy++) + { + for (dx = -r; dx <= r; dx++) + { + /* Extract the location */ + yy = cy + dy; + xx = cx + dx; + + /* Skip unaffected grids */ + if (!map[16+yy-cy][16+xx-cx]) continue; + + /* Access the cave grid */ + c_ptr = &cave[yy][xx]; + + /* Paranoia -- never affect player */ +/* if (player_bold(yy, xx)) continue; */ + + /* Destroy location (if valid) */ + if (cave_valid_bold(yy, xx)) { + /* Delete objects */ + delete_object(yy, xx); + /* Wall (or floor) type */ - t = randint0(200); + t = cave_have_flag_bold(yy, xx, FF_PROJECT) ? randint0(100) : 200; - if (!in_generate) /* Normal */ + /* Granite */ + if (t < 20) { - if (t < 20) - { - /* Create granite wall */ - cave_set_feat(y, x, feat_granite); - } - else if (t < 70) - { - /* Create quartz vein */ - cave_set_feat(y, x, feat_quartz_vein); - } - else if (t < 100) - { - /* Create magma vein */ - cave_set_feat(y, x, feat_magma_vein); - } - else - { - /* Create floor */ - cave_set_feat(y, x, floor_type[randint0(100)]); - } + /* Create granite wall */ + cave_set_feat(yy, xx, feat_granite); } - else /* In generation */ + + /* Quartz */ + else if (t < 70) { - if (t < 20) - { - /* Create granite wall */ - place_extra_grid(c_ptr); - } - else if (t < 70) - { - /* Create quartz vein */ - c_ptr->feat = feat_quartz_vein; - } - else if (t < 100) - { - /* Create magma vein */ - c_ptr->feat = feat_magma_vein; - } - else - { - /* Create floor */ - place_floor_grid(c_ptr); - } + /* Create quartz vein */ + cave_set_feat(yy, xx, feat_quartz_vein); + } - /* Clear garbage of hidden trap or door */ - c_ptr->mimic = 0; + /* Magma */ + else if (t < 100) + { + /* Create magma vein */ + cave_set_feat(yy, xx, feat_magma_vein); + } + + /* Floor */ + else + { + /* Create floor */ + cave_set_feat(yy, xx, floor_type[randint0(100)]); } } } } - if (!in_generate) + + /* Process "re-glowing" */ + for (dy = -r; dy <= r; dy++) { - /* Process "re-glowing" */ - for (y = (y1 - r); y <= (y1 + r); y++) + for (dx = -r; dx <= r; dx++) { - for (x = (x1 - r); x <= (x1 + r); x++) - { - /* Skip illegal grids */ - if (!in_bounds(y, x)) continue; + /* Extract the location */ + yy = cy + dy; + xx = cx + dx; - /* Extract the distance */ - k = distance(y1, x1, y, x); + /* Skip illegal grids */ + if (!in_bounds(yy, xx)) continue; - /* Stay in the circle of death */ - if (k > r) continue; + /* Skip distant grids */ + if (distance(cy, cx, yy, xx) > r) continue; + c_ptr = &cave[yy][xx]; - /* Access the grid */ - c_ptr = &cave[y][x]; + if (is_mirror_grid(c_ptr)) c_ptr->info |= CAVE_GLOW; + else if (!(d_info[dungeon_type].flags1 & DF1_DARKNESS)) + { + int ii, yyy, xxx; + cave_type *cc_ptr; - if (is_mirror_grid(c_ptr)) c_ptr->info |= CAVE_GLOW; - else if (!(d_info[dungeon_type].flags1 & DF1_DARKNESS)) + for (ii = 0; ii < 9; ii++) { - int i, yy, xx; - cave_type *cc_ptr; - - for (i = 0; i < 9; i++) + yyy = yy + ddy_ddd[ii]; + xxx = xx + ddx_ddd[ii]; + if (!in_bounds2(yyy, xxx)) continue; + cc_ptr = &cave[yyy][xxx]; + if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) { - yy = y + ddy_ddd[i]; - xx = x + ddx_ddd[i]; - if (!in_bounds2(yy, xx)) continue; - cc_ptr = &cave[yy][xx]; - if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) - { - c_ptr->info |= CAVE_GLOW; - break; - } + c_ptr->info |= CAVE_GLOW; + break; } } } } + } - /* Hack -- Affect player */ - if (flag) - { - /* Message */ - msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!")); - - /* Blind the player */ - if (!p_ptr->resist_blind && !p_ptr->resist_lite) - { - /* Become blind */ - (void)set_blind(p_ptr->blind + 10 + randint1(10)); - } - } - forget_flow(); + /* Mega-Hack -- Forget the view and lite */ + p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE); - /* Mega-Hack -- Forget the view and lite */ - p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE); + p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS); - /* Update stuff */ - p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS); + /* Update the health bar */ + p_ptr->redraw |= (PR_HEALTH | PR_UHEALTH); - /* Redraw map */ - p_ptr->redraw |= (PR_MAP); + p_ptr->redraw |= (PR_MAP); - /* Window stuff */ - p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); + p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); - if (p_ptr->special_defense & NINJA_S_STEALTH) - { - if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); - } + if (p_ptr->special_defense & NINJA_S_STEALTH) + { + if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); } /* Success */ return (TRUE); } - /*! - * @brief 地震処理(サブルーチン) / + * @brief 地震処理(プレイヤーの中心発動) / * Induce an "earthquake" of the given radius at the given location. * @return 効力があった場合TRUEを返す * @param cy 中心Y座標 * @param cx 中心X座標 * @param r 効果半径 - * @param m_idx 地震を起こしたモンスターID(0ならばプレイヤー) - * @details - *
- *
- * This will turn some walls into floors and some floors into walls.
- *
- * The player will take damage and "jump" into a safe grid if possible,
- * otherwise, he will "tunnel" through the rubble instantaneously.
- *
- * Monsters will take damage, and "jump" into a safe grid if possible,
- * otherwise they will be "buried" in the rubble, disappearing from
- * the level in the same way that they do when genocided.
- *
- * Note that thus the player and monsters (except eaters of walls and
- * passers through walls) will never occupy the same grid as a wall.
- * Note that as of now (2.7.8) no monster may occupy a "wall" grid, even
- * for a single turn, unless that monster can pass_walls or kill_walls.
- * This has allowed massive simplification of the "monster" code.
- * 
*/ -bool earthquake_aux(int cy, int cx, int r, int m_idx) +bool earthquake(POSITION cy, POSITION cx, POSITION r) { - int i, t, y, x, yy, xx, dy, dx; - int damage = 0; - int sn = 0; - POSITION sy = 0, sx = 0; - bool hurt = FALSE; - cave_type *c_ptr; - bool map[32][32]; + return earthquake_aux(cy, cx, r, 0); +} +/*! + * @brief ペット爆破処理 / + * @return なし + */ +void discharge_minion(void) +{ + MONSTER_IDX i; + bool okay = TRUE; - /* Prevent destruction of quest levels and town */ - if ((p_ptr->inside_quest && is_fixed_quest_idx(p_ptr->inside_quest)) || !dun_level) + for (i = 1; i < m_max; i++) { - return (FALSE); + monster_type *m_ptr = &m_list[i]; + if (!m_ptr->r_idx || !is_pet(m_ptr)) continue; + if (m_ptr->nickname) okay = FALSE; + } + if (!okay || p_ptr->riding) + { + if (!get_check(_("本当に全ペットを爆破しますか?", "You will blast all pets. Are you sure? "))) + return; } + for (i = 1; i < m_max; i++) + { + HIT_POINT dam; + monster_type *m_ptr = &m_list[i]; + monster_race *r_ptr; - /* Paranoia -- Enforce maximum range */ - if (r > 12) r = 12; + if (!m_ptr->r_idx || !is_pet(m_ptr)) continue; + r_ptr = &r_info[m_ptr->r_idx]; - /* Clear the "maximal blast" area */ - for (y = 0; y < 32; y++) - { - for (x = 0; x < 32; x++) + /* Uniques resist discharging */ + if (r_ptr->flags1 & RF1_UNIQUE) { - map[y][x] = FALSE; + char m_name[80]; + monster_desc(m_name, m_ptr, 0x00); + msg_format(_("%sは爆破されるのを嫌がり、勝手に自分の世界へと帰った。", "%^s resists to be blasted, and run away."), m_name); + delete_monster_idx(i); + continue; + } + dam = m_ptr->maxhp / 2; + if (dam > 100) dam = (dam-100)/2 + 100; + if (dam > 400) dam = (dam-400)/2 + 400; + if (dam > 800) dam = 800; + project(i, 2+(r_ptr->level/20), m_ptr->fy, + m_ptr->fx, dam, GF_PLASMA, + PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL, -1); + + if (record_named_pet && m_ptr->nickname) + { + char m_name[80]; + + monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); + do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_BLAST, m_name); } + + delete_monster_idx(i); } +} - /* Check around the epicenter */ - for (dy = -r; dy <= r; dy++) + +/*! + * @brief 部屋全体を照らすサブルーチン + * @return なし + * @details + *
+ * This routine clears the entire "temp" set.
+ * This routine will Perma-Lite all "temp" grids.
+ * This routine is used (only) by "lite_room()"
+ * Dark grids are illuminated.
+ * Also, process all affected monsters.
+ *
+ * SMART monsters always wake up when illuminated
+ * NORMAL monsters wake up 1/4 the time when illuminated
+ * STUPID monsters wake up 1/10 the time when illuminated
+ * 
+ */ +static void cave_temp_room_lite(void) +{ + int i; + + /* Clear them all */ + for (i = 0; i < temp_n; i++) { - for (dx = -r; dx <= r; dx++) - { - /* Extract the location */ - yy = cy + dy; - xx = cx + dx; + POSITION y = temp_y[i]; + POSITION x = temp_x[i]; - /* Skip illegal grids */ - if (!in_bounds(yy, xx)) continue; + cave_type *c_ptr = &cave[y][x]; - /* Skip distant grids */ - if (distance(cy, cx, yy, xx) > r) continue; + /* No longer in the array */ + c_ptr->info &= ~(CAVE_TEMP); - /* Access the grid */ - c_ptr = &cave[yy][xx]; + /* Update only non-CAVE_GLOW grids */ + /* if (c_ptr->info & (CAVE_GLOW)) continue; */ - /* Lose room and vault */ - c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY | CAVE_UNSAFE); + /* Perma-Lite */ + c_ptr->info |= (CAVE_GLOW); - /* Lose light and knowledge */ - c_ptr->info &= ~(CAVE_GLOW | CAVE_MARK | CAVE_KNOWN); + /* Process affected monsters */ + if (c_ptr->m_idx) + { + int chance = 25; - /* Skip the epicenter */ - if (!dx && !dy) continue; + monster_type *m_ptr = &m_list[c_ptr->m_idx]; - /* Skip most grids */ - if (randint0(100) < 85) continue; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; + update_monster(c_ptr->m_idx, FALSE); - /* Damage this grid */ - map[16+yy-cy][16+xx-cx] = TRUE; + /* Stupid monsters rarely wake up */ + if (r_ptr->flags2 & (RF2_STUPID)) chance = 10; - /* Hack -- Take note of player damage */ - if (player_bold(yy, xx)) hurt = TRUE; + /* Smart monsters always wake up */ + if (r_ptr->flags2 & (RF2_SMART)) chance = 100; + + /* Sometimes monsters wake up */ + if (MON_CSLEEP(m_ptr) && (randint0(100) < chance)) + { + /* Wake up! */ + (void)set_monster_csleep(c_ptr->m_idx, 0); + + /* Notice the "waking up" */ + if (m_ptr->ml) + { + char m_name[80]; + monster_desc(m_name, m_ptr, 0); + msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name); + } + } } + + /* Note */ + note_spot(y, x); + + lite_spot(y, x); + + update_local_illumination(y, x); } - /* First, affect the player (if necessary) */ - if (hurt && !p_ptr->pass_wall && !p_ptr->kill_wall) - { - /* Check around the player */ - for (i = 0; i < 8; i++) - { - /* Access the location */ - y = p_ptr->y + ddy_ddd[i]; - x = p_ptr->x + ddx_ddd[i]; + /* None left */ + temp_n = 0; +} - /* Skip non-empty grids */ - if (!cave_empty_bold(y, x)) continue; - /* Important -- Skip "quake" grids */ - if (map[16+y-cy][16+x-cx]) continue; - if (cave[y][x].m_idx) continue; +/*! + * @brief 部屋全体を暗くするサブルーチン + * @return なし + * @details + *
+ * This routine clears the entire "temp" set.
+ * This routine will "darken" all "temp" grids.
+ * In addition, some of these grids will be "unmarked".
+ * This routine is used (only) by "unlite_room()"
+ * Also, process all affected monsters
+ * 
+ */ +static void cave_temp_room_unlite(void) +{ + int i; - /* Count "safe" grids */ - sn++; + /* Clear them all */ + for (i = 0; i < temp_n; i++) + { + POSITION y = temp_y[i]; + POSITION x = temp_x[i]; + int j; - /* Randomize choice */ - if (randint0(sn) > 0) continue; + cave_type *c_ptr = &cave[y][x]; + bool do_dark = !is_mirror_grid(c_ptr); - /* Save the safe location */ - sy = y; sx = x; - } + /* No longer in the array */ + c_ptr->info &= ~(CAVE_TEMP); - /* Random message */ - switch (randint1(3)) + /* Darken the grid */ + if (do_dark) { - case 1: - { - msg_print(_("ダンジョンの壁が崩れた!", "The cave ceiling collapses!")); - break; - } - case 2: - { - msg_print(_("ダンジョンの床が不自然にねじ曲がった!", "The cave floor twists in an unnatural way!")); - break; - } - default: + if (dun_level || !is_daytime()) { - msg_print(_("ダンジョンが揺れた!崩れた岩が頭に降ってきた!", "The cave quakes! You are pummeled with debris!")); - break; - } - } + for (j = 0; j < 9; j++) + { + int by = y + ddy_ddd[j]; + int bx = x + ddx_ddd[j]; - /* Hurt the player a lot */ - if (!sn) - { - /* Message and damage */ - msg_print(_("あなたはひどい怪我を負った!", "You are severely crushed!")); - damage = 200; - } + if (in_bounds2(by, bx)) + { + cave_type *cc_ptr = &cave[by][bx]; - /* Destroy the grid, and push the player to safety */ - else - { - /* Calculate results */ - switch (randint1(3)) - { - case 1: - { - msg_print(_("降り注ぐ岩をうまく避けた!", "You nimbly dodge the blast!")); - damage = 0; - break; - } - case 2: - { - msg_print(_("岩石があなたに直撃した!", "You are bashed by rubble!")); - damage = damroll(10, 4); - (void)set_stun(p_ptr->stun + randint1(50)); - break; - } - case 3: - { - msg_print(_("あなたは床と壁との間に挟まれてしまった!", "You are crushed between the floor and ceiling!")); - damage = damroll(10, 4); - (void)set_stun(p_ptr->stun + randint1(50)); - break; + if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) + { + do_dark = FALSE; + break; + } + } } - } - - /* Move the player to the safe location */ - (void)move_player_effect(sy, sx, MPE_DONT_PICKUP); - } - /* Important -- no wall on player */ - map[16+p_ptr->y-cy][16+p_ptr->x-cx] = FALSE; + if (!do_dark) continue; + } - /* Take some damage */ - if (damage) - { - cptr killer; + c_ptr->info &= ~(CAVE_GLOW); - if (m_idx) + /* Hack -- Forget "boring" grids */ + if (!have_flag(f_info[get_feat_mimic(c_ptr)].flags, FF_REMEMBER)) { - char m_name[80]; - monster_type *m_ptr = &m_list[m_idx]; - - /* Get the monster's real name */ - monster_desc(m_name, m_ptr, MD_IGNORE_HALLU | MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE); + /* Forget the grid */ + if (!view_torch_grids) c_ptr->info &= ~(CAVE_MARK); - killer = format(_("%sの起こした地震", "an earthquake caused by %s"), m_name); + note_spot(y, x); } - else + + /* Process affected monsters */ + if (c_ptr->m_idx) { - killer = _("地震", "an earthquake"); + update_monster(c_ptr->m_idx, FALSE); } - take_hit(DAMAGE_ATTACK, damage, killer, -1); + lite_spot(y, x); + + update_local_illumination(y, x); } } - /* Examine the quaked region */ - for (dy = -r; dy <= r; dy++) - { - for (dx = -r; dx <= r; dx++) - { - /* Extract the location */ - yy = cy + dy; - xx = cx + dx; + /* None left */ + temp_n = 0; +} - /* Skip unaffected grids */ - if (!map[16+yy-cy][16+xx-cx]) continue; - /* Access the grid */ - c_ptr = &cave[yy][xx]; +/*! + * @brief 周辺に関数ポインタの条件に該当する地形がいくつあるかを計算する / Determine how much contiguous open space this grid is next to + * @param cy Y座標 + * @param cx X座標 + * @param pass_bold 地形条件を返す関数ポインタ + * @return 該当地形の数 + */ +static int next_to_open(POSITION cy, POSITION cx, bool (*pass_bold)(POSITION, POSITION)) +{ + int i; + POSITION y, x; + int len = 0; + int blen = 0; - if (c_ptr->m_idx == p_ptr->riding) continue; + for (i = 0; i < 16; i++) + { + y = cy + ddy_cdd[i % 8]; + x = cx + ddx_cdd[i % 8]; - /* Process monsters */ - if (c_ptr->m_idx) + /* Found a wall, break the length */ + if (!pass_bold(y, x)) + { + /* Track best length */ + if (len > blen) { - monster_type *m_ptr = &m_list[c_ptr->m_idx]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - - /* Quest monsters */ - if (r_ptr->flags1 & RF1_QUESTOR) - { - /* No wall on quest monsters */ - map[16+yy-cy][16+xx-cx] = FALSE; + blen = len; + } - continue; - } + len = 0; + } + else + { + len++; + } + } - /* Most monsters cannot co-exist with rock */ - if (!(r_ptr->flags2 & (RF2_KILL_WALL)) && - !(r_ptr->flags2 & (RF2_PASS_WALL))) - { - char m_name[80]; + return (MAX(len, blen)); +} - /* Assume not safe */ - sn = 0; +/*! + * @brief 周辺に関数ポインタの条件に該当する地形がいくつあるかを計算する / Determine how much contiguous open space this grid is next to + * @param cy Y座標 + * @param cx X座標 + * @param pass_bold 地形条件を返す関数ポインタ + * @return 該当地形の数 + */ +static int next_to_walls_adj(POSITION cy, POSITION cx, bool (*pass_bold)(POSITION, POSITION)) +{ + DIRECTION i; + POSITION y, x; + int c = 0; - /* Monster can move to escape the wall */ - if (!(r_ptr->flags1 & (RF1_NEVER_MOVE))) - { - /* Look for safety */ - for (i = 0; i < 8; i++) - { - /* Access the grid */ - y = yy + ddy_ddd[i]; - x = xx + ddx_ddd[i]; + for (i = 0; i < 8; i++) + { + y = cy + ddy_ddd[i]; + x = cx + ddx_ddd[i]; - /* Skip non-empty grids */ - if (!cave_empty_bold(y, x)) continue; + if (!pass_bold(y, x)) c++; + } - /* Hack -- no safety on glyph of warding */ - if (is_glyph_grid(&cave[y][x])) continue; - if (is_explosive_rune_grid(&cave[y][x])) continue; + return c; +} - /* ... nor on the Pattern */ - if (pattern_tile(y, x)) continue; - /* Important -- Skip "quake" grids */ - if (map[16+y-cy][16+x-cx]) continue; +/*! + * @brief 部屋内にある一点の周囲に該当する地形数かいくつあるかをグローバル変数temp_nに返す / Aux function -- see below + * @param y 部屋内のy座標1点 + * @param x 部屋内のx座標1点 + * @param only_room 部屋内地形のみをチェック対象にするならば TRUE + * @param pass_bold 地形条件を返す関数ポインタ + * @return 該当地形の数 + */ +static void cave_temp_room_aux(POSITION y, POSITION x, bool only_room, bool (*pass_bold)(POSITION, POSITION)) +{ + cave_type *c_ptr; - if (cave[y][x].m_idx) continue; - if (player_bold(y, x)) continue; + /* Get the grid */ + c_ptr = &cave[y][x]; - /* Count "safe" grids */ - sn++; + /* Avoid infinite recursion */ + if (c_ptr->info & (CAVE_TEMP)) return; - /* Randomize choice */ - if (randint0(sn) > 0) continue; + /* Do not "leave" the current room */ + if (!(c_ptr->info & (CAVE_ROOM))) + { + if (only_room) return; - /* Save the safe grid */ - sy = y; sx = x; - } - } + /* Verify */ + if (!in_bounds2(y, x)) return; - /* Describe the monster */ - monster_desc(m_name, m_ptr, 0); + /* Do not exceed the maximum spell range */ + if (distance(p_ptr->y, p_ptr->x, y, x) > MAX_RANGE) return; - /* Scream in pain */ - if (!ignore_unview || is_seen(m_ptr)) msg_format(_("%^sは苦痛で泣きわめいた!", "%^s wails out in pain!"), m_name); + /* Verify this grid */ + /* + * The reason why it is ==6 instead of >5 is that 8 is impossible + * due to the check for cave_bold above. + * 7 lights dead-end corridors (you need to do this for the + * checkboard interesting rooms, so that the boundary is lit + * properly. + * This leaves only a check for 6 bounding walls! + */ + if (in_bounds(y, x) && pass_bold(y, x) && + (next_to_walls_adj(y, x, pass_bold) == 6) && (next_to_open(y, x, pass_bold) <= 1)) return; + } - /* Take damage from the quake */ - damage = (sn ? damroll(4, 8) : (m_ptr->hp + 1)); + /* Paranoia -- verify space */ + if (temp_n == TEMP_MAX) return; - /* Monster is certainly awake */ - (void)set_monster_csleep(c_ptr->m_idx, 0); + /* Mark the grid as "seen" */ + c_ptr->info |= (CAVE_TEMP); - /* Apply damage directly */ - m_ptr->hp -= damage; + /* Add it to the "seen" set */ + temp_y[temp_n] = y; + temp_x[temp_n] = x; + temp_n++; +} - /* Delete (not kill) "dead" monsters */ - if (m_ptr->hp < 0) - { - /* Message */ - if (!ignore_unview || is_seen(m_ptr)) - msg_format(_("%^sは岩石に埋もれてしまった!", "%^s is embedded in the rock!"), m_name); +/*! + * @brief 指定のマスが光を通すか(LOSフラグを持つか)を返す。 / Aux function -- see below + * @param y 指定Y座標 + * @param x 指定X座標 + * @return 光を通すならばtrueを返す。 + */ +static bool cave_pass_lite_bold(POSITION y, POSITION x) +{ + return cave_los_bold(y, x); +} - if (c_ptr->m_idx) - { - if (record_named_pet && is_pet(&m_list[c_ptr->m_idx]) && m_list[c_ptr->m_idx].nickname) - { - char m2_name[80]; +/*! + * @brief 部屋内にある一点の周囲がいくつ光を通すかをグローバル変数temp_nに返す / Aux function -- see below + * @param y 指定Y座標 + * @param x 指定X座標 + * @return なし + */ +static void cave_temp_lite_room_aux(POSITION y, POSITION x) +{ + cave_temp_room_aux(y, x, FALSE, cave_pass_lite_bold); +} - monster_desc(m2_name, m_ptr, MD_INDEF_VISIBLE); - do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_EARTHQUAKE, m2_name); - } - } +/*! + * @brief 指定のマスが光を通さず射線のみを通すかを返す。 / Aux function -- see below + * @param y 指定Y座標 + * @param x 指定X座標 + * @return 射線を通すならばtrueを返す。 + */ +static bool cave_pass_dark_bold(POSITION y, POSITION x) +{ + return cave_have_flag_bold(y, x, FF_PROJECT); +} - /* Delete the monster */ - delete_monster(yy, xx); - /* No longer safe */ - sn = 0; - } +/*! + * @brief 部屋内にある一点の周囲がいくつ射線を通すかをグローバル変数temp_nに返す / Aux function -- see below + * @param y 指定Y座標 + * @param x 指定X座標 + * @return なし + */ +static void cave_temp_unlite_room_aux(POSITION y, POSITION x) +{ + cave_temp_room_aux(y, x, TRUE, cave_pass_dark_bold); +} - /* Hack -- Escape from the rock */ - if (sn) - { - IDX m_idx_aux = cave[yy][xx].m_idx; - /* Update the old location */ - cave[yy][xx].m_idx = 0; +/*! + * @brief 指定された部屋内を照らす / Illuminate any room containing the given location. + * @param y1 指定Y座標 + * @param x1 指定X座標 + * @return なし + */ +void lite_room(POSITION y1, POSITION x1) +{ + int i; + POSITION x, y; - /* Update the new location */ - cave[sy][sx].m_idx = m_idx_aux; + /* Add the initial grid */ + cave_temp_lite_room_aux(y1, x1); - /* Move the monster */ - m_ptr->fy = sy; - m_ptr->fx = sx; + /* While grids are in the queue, add their neighbors */ + for (i = 0; i < temp_n; i++) + { + x = temp_x[i], y = temp_y[i]; - /* Update the monster (new location) */ - update_mon(m_idx, TRUE); + /* Walls get lit, but stop light */ + if (!cave_pass_lite_bold(y, x)) continue; - /* Redraw the old grid */ - lite_spot(yy, xx); + /* Spread adjacent */ + cave_temp_lite_room_aux(y + 1, x); + cave_temp_lite_room_aux(y - 1, x); + cave_temp_lite_room_aux(y, x + 1); + cave_temp_lite_room_aux(y, x - 1); - /* Redraw the new grid */ - lite_spot(sy, sx); - } - } - } - } + /* Spread diagonal */ + cave_temp_lite_room_aux(y + 1, x + 1); + cave_temp_lite_room_aux(y - 1, x - 1); + cave_temp_lite_room_aux(y - 1, x + 1); + cave_temp_lite_room_aux(y + 1, x - 1); } - /* Lose monster light */ - clear_mon_lite(); + /* Now, lite them all up at once */ + cave_temp_room_lite(); - /* Examine the quaked region */ - for (dy = -r; dy <= r; dy++) + if (p_ptr->special_defense & NINJA_S_STEALTH) { - for (dx = -r; dx <= r; dx++) - { - /* Extract the location */ - yy = cy + dy; - xx = cx + dx; - - /* Skip unaffected grids */ - if (!map[16+yy-cy][16+xx-cx]) continue; - - /* Access the cave grid */ - c_ptr = &cave[yy][xx]; + if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); + } +} - /* Paranoia -- never affect player */ -/* if (player_bold(yy, xx)) continue; */ - /* Destroy location (if valid) */ - if (cave_valid_bold(yy, xx)) - { - /* Delete objects */ - delete_object(yy, xx); +/*! + * @brief 指定された部屋内を暗くする / Darken all rooms containing the given location + * @param y1 指定Y座標 + * @param x1 指定X座標 + * @return なし + */ +void unlite_room(POSITION y1, POSITION x1) +{ + int i; + POSITION x, y; - /* Wall (or floor) type */ - t = cave_have_flag_bold(yy, xx, FF_PROJECT) ? randint0(100) : 200; + /* Add the initial grid */ + cave_temp_unlite_room_aux(y1, x1); - /* Granite */ - if (t < 20) - { - /* Create granite wall */ - cave_set_feat(yy, xx, feat_granite); - } + /* Spread, breadth first */ + for (i = 0; i < temp_n; i++) + { + x = temp_x[i], y = temp_y[i]; - /* Quartz */ - else if (t < 70) - { - /* Create quartz vein */ - cave_set_feat(yy, xx, feat_quartz_vein); - } + /* Walls get dark, but stop darkness */ + if (!cave_pass_dark_bold(y, x)) continue; - /* Magma */ - else if (t < 100) - { - /* Create magma vein */ - cave_set_feat(yy, xx, feat_magma_vein); - } + /* Spread adjacent */ + cave_temp_unlite_room_aux(y + 1, x); + cave_temp_unlite_room_aux(y - 1, x); + cave_temp_unlite_room_aux(y, x + 1); + cave_temp_unlite_room_aux(y, x - 1); - /* Floor */ - else - { - /* Create floor */ - cave_set_feat(yy, xx, floor_type[randint0(100)]); - } - } - } + /* Spread diagonal */ + cave_temp_unlite_room_aux(y + 1, x + 1); + cave_temp_unlite_room_aux(y - 1, x - 1); + cave_temp_unlite_room_aux(y - 1, x + 1); + cave_temp_unlite_room_aux(y + 1, x - 1); } + /* Now, darken them all at once */ + cave_temp_room_unlite(); +} - /* Process "re-glowing" */ - for (dy = -r; dy <= r; dy++) - { - for (dx = -r; dx <= r; dx++) - { - /* Extract the location */ - yy = cy + dy; - xx = cx + dx; - - /* Skip illegal grids */ - if (!in_bounds(yy, xx)) continue; - - /* Skip distant grids */ - if (distance(cy, cx, yy, xx) > r) continue; - /* Access the grid */ - c_ptr = &cave[yy][xx]; - if (is_mirror_grid(c_ptr)) c_ptr->info |= CAVE_GLOW; - else if (!(d_info[dungeon_type].flags1 & DF1_DARKNESS)) - { - int ii, yyy, xxx; - cave_type *cc_ptr; +/*! + * @brief プレイヤー位置を中心にLITE_WEAK属性を通じた照明処理を行う / Hack -- call light around the player Affect all monsters in the projection radius + * @param dam 威力 + * @param rad 効果半径 + * @return 作用が実際にあった場合TRUEを返す + */ +bool lite_area(HIT_POINT dam, POSITION rad) +{ + BIT_FLAGS flg = PROJECT_GRID | PROJECT_KILL; - for (ii = 0; ii < 9; ii++) - { - yyy = yy + ddy_ddd[ii]; - xxx = xx + ddx_ddd[ii]; - if (!in_bounds2(yyy, xxx)) continue; - cc_ptr = &cave[yyy][xxx]; - if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) - { - c_ptr->info |= CAVE_GLOW; - break; - } - } - } - } + if (d_info[dungeon_type].flags1 & DF1_DARKNESS) + { + msg_print(_("ダンジョンが光を吸収した。", "The darkness of this dungeon absorb your light.")); + return FALSE; } + /* Hack -- Message */ + if (!p_ptr->blind) + { + msg_print(_("白い光が辺りを覆った。", "You are surrounded by a white light.")); + } - /* Mega-Hack -- Forget the view and lite */ - p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE); + /* Hook into the "project()" function */ + (void)project(0, rad, p_ptr->y, p_ptr->x, dam, GF_LITE_WEAK, flg, -1); - /* Update stuff */ - p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS); + /* Lite up the room */ + lite_room(p_ptr->y, p_ptr->x); - /* Update the health bar */ - p_ptr->redraw |= (PR_HEALTH | PR_UHEALTH); + /* Assume seen */ + return (TRUE); +} - /* Redraw map */ - p_ptr->redraw |= (PR_MAP); - /* Window stuff */ - p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); +/*! + * @brief プレイヤー位置を中心にLITE_DARK属性を通じた消灯処理を行う / Hack -- call light around the player Affect all monsters in the projection radius + * @param dam 威力 + * @param rad 効果半径 + * @return 作用が実際にあった場合TRUEを返す + */ +bool unlite_area(HIT_POINT dam, POSITION rad) +{ + BIT_FLAGS flg = PROJECT_GRID | PROJECT_KILL; - if (p_ptr->special_defense & NINJA_S_STEALTH) + /* Hack -- Message */ + if (!p_ptr->blind) { - if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); + msg_print(_("暗闇が辺りを覆った。", "Darkness surrounds you.")); } - /* Success */ + /* Hook into the "project()" function */ + (void)project(0, rad, p_ptr->y, p_ptr->x, dam, GF_DARK_WEAK, flg, -1); + + /* Lite up the room */ + unlite_room(p_ptr->y, p_ptr->x); + + /* Assume seen */ return (TRUE); } -/*! - * @brief 地震処理(プレイヤーの中心発動) / - * Induce an "earthquake" of the given radius at the given location. - * @return 効力があった場合TRUEを返す - * @param cy 中心Y座標 - * @param cx 中心X座標 - * @param r 効果半径 - */ -bool earthquake(int cy, int cx, int r) -{ - return earthquake_aux(cy, cx, r, 0); -} + /*! - * @brief ペット爆破処理 / - * @return なし + * @brief ボール系スペルの発動 / Cast a ball spell + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @param rad 半径 + * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ * 
*/ -void discharge_minion(void) +bool fire_ball(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, POSITION rad) { - int i; - bool okay = TRUE; + POSITION tx, ty; - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - if (!m_ptr->r_idx || !is_pet(m_ptr)) continue; - if (m_ptr->nickname) okay = FALSE; - } - if (!okay || p_ptr->riding) + BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; + + if (typ == GF_CHARM_LIVING) flg|= PROJECT_HIDE; + /* Use the given direction */ + tx = p_ptr->x + 99 * ddx[dir]; + ty = p_ptr->y + 99 * ddy[dir]; + + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) { - if (!get_check(_("本当に全ペットを爆破しますか?", "You will blast all pets. Are you sure? "))) - return; + flg &= ~(PROJECT_STOP); + tx = target_col; + ty = target_row; } - for (i = 1; i < m_max; i++) - { - int dam; - monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr; - if (!m_ptr->r_idx || !is_pet(m_ptr)) continue; - r_ptr = &r_info[m_ptr->r_idx]; + /* Analyze the "dir" and the "target". Hurt items on floor. */ + return (project(0, rad, ty, tx, dam, typ, flg, -1)); +} - /* Uniques resist discharging */ - if (r_ptr->flags1 & RF1_UNIQUE) - { - char m_name[80]; - monster_desc(m_name, m_ptr, 0x00); - msg_format(_("%sは爆破されるのを嫌がり、勝手に自分の世界へと帰った。", "%^s resists to be blasted, and run away."), m_name); - delete_monster_idx(i); - continue; - } - dam = m_ptr->maxhp / 2; - if (dam > 100) dam = (dam-100)/2 + 100; - if (dam > 400) dam = (dam-400)/2 + 400; - if (dam > 800) dam = 800; - project(i, 2+(r_ptr->level/20), m_ptr->fy, - m_ptr->fx, dam, GF_PLASMA, - PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL, -1); +/*! +* @brief ブレス系スペルの発動 / Cast a breath spell +* @param typ 効果属性 +* @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) +* @param dam 威力 +* @param rad 半径 +* @return 作用が実際にあった場合TRUEを返す +* @details +*
+* Stop if we hit a monster, act as a "ball"
+* Allow "target" mode to pass over monsters
+* Affect grids, objects, and monsters
+* 
+*/ +bool fire_breath(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, POSITION rad) +{ + return fire_ball(typ, dir, dam, -rad); +} - if (record_named_pet && m_ptr->nickname) - { - char m_name[80]; - monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); - do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_BLAST, m_name); - } +/*! + * @brief ロケット系スペルの発動(詳細な差は確認中) / Cast a ball spell + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @param rad 半径 + * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
+ * 
+ */ +bool fire_rocket(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, POSITION rad) +{ + POSITION tx, ty; + BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; - delete_monster_idx(i); + /* Use the given direction */ + tx = p_ptr->x + 99 * ddx[dir]; + ty = p_ptr->y + 99 * ddy[dir]; + + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) + { + tx = target_col; + ty = target_row; } + + /* Analyze the "dir" and the "target". Hurt items on floor. */ + return (project(0, rad, ty, tx, dam, typ, flg, -1)); } /*! - * @brief 部屋全体を照らすサブルーチン - * @return なし + * @brief ボール(ハイド)系スペルの発動 / Cast a ball spell + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @param rad 半径 + * @return 作用が実際にあった場合TRUEを返す * @details *
- * This routine clears the entire "temp" set.
- * This routine will Perma-Lite all "temp" grids.
- * This routine is used (only) by "lite_room()"
- * Dark grids are illuminated.
- * Also, process all affected monsters.
- *
- * SMART monsters always wake up when illuminated
- * NORMAL monsters wake up 1/4 the time when illuminated
- * STUPID monsters wake up 1/10 the time when illuminated
+ * Stop if we hit a monster, act as a "ball"
+ * Allow "target" mode to pass over monsters
+ * Affect grids, objects, and monsters
  * 
*/ -static void cave_temp_room_lite(void) +bool fire_ball_hide(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, POSITION rad) { - int i; - - /* Clear them all */ - for (i = 0; i < temp_n; i++) - { - int y = temp_y[i]; - int x = temp_x[i]; + POSITION tx, ty; + BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_HIDE; - cave_type *c_ptr = &cave[y][x]; + /* Use the given direction */ + tx = p_ptr->x + 99 * ddx[dir]; + ty = p_ptr->y + 99 * ddy[dir]; - /* No longer in the array */ - c_ptr->info &= ~(CAVE_TEMP); + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) + { + flg &= ~(PROJECT_STOP); + tx = target_col; + ty = target_row; + } - /* Update only non-CAVE_GLOW grids */ - /* if (c_ptr->info & (CAVE_GLOW)) continue; */ + /* Analyze the "dir" and the "target". Hurt items on floor. */ + return (project(0, rad, ty, tx, dam, typ, flg, -1)); +} - /* Perma-Lite */ - c_ptr->info |= (CAVE_GLOW); - /* Process affected monsters */ - if (c_ptr->m_idx) - { - int chance = 25; +/*! + * @brief メテオ系スペルの発動 / Cast a meteor spell + * @param who スぺル詠唱者のモンスターID(0=プレイヤー) + * @param typ 効果属性 + * @param dam 威力 + * @param rad 半径 + * @param y 中心点Y座標 + * @param x 中心点X座標 + * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * Cast a meteor spell, defined as a ball spell cast by an arbitary monster, 
+ * player, or outside source, that starts out at an arbitrary location, and 
+ * leaving no trail from the "caster" to the target.  This function is 
+ * especially useful for bombardments and similar. -LM-
+ * Option to hurt the player.
+ * 
+ */ +bool fire_meteor(MONSTER_IDX who, EFFECT_ID typ, POSITION y, POSITION x, HIT_POINT dam, POSITION rad) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; - monster_type *m_ptr = &m_list[c_ptr->m_idx]; + /* Analyze the "target" and the caster. */ + return (project(who, rad, y, x, dam, typ, flg, -1)); +} - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - /* Update the monster */ - update_mon(c_ptr->m_idx, FALSE); +/*! + * @brief ブラスト系スペルの発動 / Cast a blast spell + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dd 威力ダイス数 + * @param ds 威力ダイス目 + * @param num 基本回数 + * @param dev 回数分散 + * @return 作用が実際にあった場合TRUEを返す + */ +bool fire_blast(EFFECT_ID typ, DIRECTION dir, int dd, int ds, int num, int dev) +{ + POSITION ly, lx; + int ld; + POSITION ty, tx, y, x; + int i; - /* Stupid monsters rarely wake up */ - if (r_ptr->flags2 & (RF2_STUPID)) chance = 10; + BIT_FLAGS flg = PROJECT_FAST | PROJECT_THRU | PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE | PROJECT_GRID; - /* Smart monsters always wake up */ - if (r_ptr->flags2 & (RF2_SMART)) chance = 100; + /* Assume okay */ + bool result = TRUE; - /* Sometimes monsters wake up */ - if (MON_CSLEEP(m_ptr) && (randint0(100) < chance)) - { - /* Wake up! */ - (void)set_monster_csleep(c_ptr->m_idx, 0); + /* Use the given direction */ + if (dir != 5) + { + ly = ty = p_ptr->y + 20 * ddy[dir]; + lx = tx = p_ptr->x + 20 * ddx[dir]; + } - /* Notice the "waking up" */ - if (m_ptr->ml) - { - char m_name[80]; + /* Use an actual "target" */ + else /* if (dir == 5) */ + { + tx = target_col; + ty = target_row; - /* Acquire the monster name */ - monster_desc(m_name, m_ptr, 0); + lx = 20 * (tx - p_ptr->x) + p_ptr->x; + ly = 20 * (ty - p_ptr->y) + p_ptr->y; + } - /* Dump a message */ - msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name); - } - } - } + ld = distance(p_ptr->y, p_ptr->x, ly, lx); - /* Note */ - note_spot(y, x); + /* Blast */ + for (i = 0; i < num; i++) + { + while (1) + { + /* Get targets for some bolts */ + y = rand_spread(ly, ld * dev / 20); + x = rand_spread(lx, ld * dev / 20); - /* Redraw */ - lite_spot(y, x); + if (distance(ly, lx, y, x) <= ld * dev / 20) break; + } - update_local_illumination(y, x); + /* Analyze the "dir" and the "target". */ + if (!project(0, 0, y, x, damroll(dd, ds), typ, flg, -1)) + { + result = FALSE; + } } - /* None left */ - temp_n = 0; + return (result); } - /*! - * @brief 部屋全体を暗くするサブルーチン - * @return なし - * @details - *
- * This routine clears the entire "temp" set.
- * This routine will "darken" all "temp" grids.
- * In addition, some of these grids will be "unmarked".
- * This routine is used (only) by "unlite_room()"
- * Also, process all affected monsters
- * 
+ * @brief モンスターとの位置交換処理 / Switch position with a monster. + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す */ -static void cave_temp_room_unlite(void) +bool teleport_swap(DIRECTION dir) { - int i; + POSITION tx, ty; + cave_type* c_ptr; + monster_type* m_ptr; + monster_race* r_ptr; - /* Clear them all */ - for (i = 0; i < temp_n; i++) + if ((dir == 5) && target_okay()) { - int y = temp_y[i]; - int x = temp_x[i]; - int j; + tx = target_col; + ty = target_row; + } + else + { + tx = p_ptr->x + ddx[dir]; + ty = p_ptr->y + ddy[dir]; + } + c_ptr = &cave[ty][tx]; - cave_type *c_ptr = &cave[y][x]; - bool do_dark = !is_mirror_grid(c_ptr); + if (p_ptr->anti_tele) + { + msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!")); + return FALSE; + } - /* No longer in the array */ - c_ptr->info &= ~(CAVE_TEMP); + if (!c_ptr->m_idx || (c_ptr->m_idx == p_ptr->riding)) + { + msg_print(_("それとは場所を交換できません。", "You can't trade places with that!")); - /* Darken the grid */ - if (do_dark) - { - if (dun_level || !is_daytime()) - { - for (j = 0; j < 9; j++) - { - int by = y + ddy_ddd[j]; - int bx = x + ddx_ddd[j]; + /* Failure */ + return FALSE; + } - if (in_bounds2(by, bx)) - { - cave_type *cc_ptr = &cave[by][bx]; + if ((c_ptr->info & CAVE_ICKY) || (distance(ty, tx, p_ptr->y, p_ptr->x) > p_ptr->lev * 3 / 2 + 10)) + { + msg_print(_("失敗した。", "Failed to swap.")); - if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) - { - do_dark = FALSE; - break; - } - } - } + /* Failure */ + return FALSE; + } - if (!do_dark) continue; - } + m_ptr = &m_list[c_ptr->m_idx]; + r_ptr = &r_info[m_ptr->r_idx]; - c_ptr->info &= ~(CAVE_GLOW); + (void)set_monster_csleep(c_ptr->m_idx, 0); - /* Hack -- Forget "boring" grids */ - if (!have_flag(f_info[get_feat_mimic(c_ptr)].flags, FF_REMEMBER)) - { - /* Forget the grid */ - if (!view_torch_grids) c_ptr->info &= ~(CAVE_MARK); + if (r_ptr->flagsr & RFR_RES_TELE) + { + msg_print(_("テレポートを邪魔された!", "Your teleportation is blocked!")); - /* Notice */ - note_spot(y, x); - } + if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= RFR_RES_TELE; - /* Process affected monsters */ - if (c_ptr->m_idx) - { - /* Update the monster */ - update_mon(c_ptr->m_idx, FALSE); - } + /* Failure */ + return FALSE; + } - /* Redraw */ - lite_spot(y, x); + sound(SOUND_TELEPORT); - update_local_illumination(y, x); - } - } + /* Swap the player and monster */ + (void)move_player_effect(ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP); - /* None left */ - temp_n = 0; + /* Success */ + return TRUE; } /*! - * @brief 周辺に関数ポインタの条件に該当する地形がいくつあるかを計算する / Determine how much contiguous open space this grid is next to - * @param cy Y座標 - * @param cx X座標 - * @param pass_bold 地形条件を返す関数ポインタ - * @return 該当地形の数 + * @brief 指定方向に飛び道具を飛ばす(フラグ任意指定) / Hack -- apply a "projection()" in a direction (or at the target) + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @param flg フラグ + * @return 作用が実際にあった場合TRUEを返す */ -static int next_to_open(int cy, int cx, bool (*pass_bold)(int, int)) +bool project_hook(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, BIT_FLAGS flg) { - int i; + int tx, ty; - int y, x; + /* Pass through the target if needed */ + flg |= (PROJECT_THRU); - int len = 0; - int blen = 0; + /* Use the given direction */ + tx = p_ptr->x + ddx[dir]; + ty = p_ptr->y + ddy[dir]; - for (i = 0; i < 16; i++) + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) { - y = cy + ddy_cdd[i % 8]; - x = cx + ddx_cdd[i % 8]; + tx = target_col; + ty = target_row; + } - /* Found a wall, break the length */ - if (!pass_bold(y, x)) - { - /* Track best length */ - if (len > blen) - { - blen = len; - } + /* Analyze the "dir" and the "target", do NOT explode */ + return (project(0, 0, ty, tx, dam, typ, flg, -1)); +} - len = 0; - } - else - { - len++; - } + +/*! + * @brief ボルト系スペルの発動 / Cast a bolt spell. + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * Stop if we hit a monster, as a "bolt".
+ * Affect monsters and grids (not objects).
+ * 
+ */ +bool fire_bolt(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_GRID; + if (typ != GF_ARROW) flg |= PROJECT_REFLECTABLE; + return (project_hook(typ, dir, dam, flg)); +} + + +/*! + * @brief ビーム系スペルの発動 / Cast a beam spell. + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * Pass through monsters, as a "beam".
+ * Affect monsters, grids and objects.
+ * 
+ */ +bool fire_beam(EFFECT_ID typ, DIRECTION dir, HIT_POINT dam) +{ + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM; + return (project_hook(typ, dir, dam, flg)); +} + + +/*! + * @brief 確率に応じたボルト系/ビーム系スペルの発動 / Cast a bolt spell, or rarely, a beam spell. + * @param prob ビーム化する確率(%) + * @param typ 効果属性 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * Pass through monsters, as a "beam".
+ * Affect monsters, grids and objects.
+ * 
+ */ +bool fire_bolt_or_beam(PERCENTAGE prob, EFFECT_ID typ, DIRECTION dir, HIT_POINT dam) +{ + if (randint0(100) < prob) + { + return (fire_beam(typ, dir, dam)); + } + else + { + return (fire_bolt(typ, dir, dam)); } +} - return (MAX(len, blen)); +/*! + * @brief LITE_WEAK属性による光源ビーム処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す + */ +bool lite_line(DIRECTION dir, HIT_POINT dam) +{ + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_KILL; + return (project_hook(GF_LITE_WEAK, dir, dam, flg)); +} + +/*! + * @brief 衰弱ボルト処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す + */ +bool hypodynamic_bolt(DIRECTION dir, HIT_POINT dam) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_HYPODYNAMIA, dir, dam, flg)); } /*! - * @brief 周辺に関数ポインタの条件に該当する地形がいくつあるかを計算する / Determine how much contiguous open space this grid is next to - * @param cy Y座標 - * @param cx X座標 - * @param pass_bold 地形条件を返す関数ポインタ - * @return 該当地形の数 + * @brief 岩石溶解処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す */ -static int next_to_walls_adj(int cy, int cx, bool (*pass_bold)(int, int)) +bool wall_to_mud(DIRECTION dir, HIT_POINT dam) { - int i; - - int y, x; - - int c = 0; - - for (i = 0; i < 8; i++) - { - y = cy + ddy_ddd[i]; - x = cx + ddx_ddd[i]; - - if (!pass_bold(y, x)) c++; - } - - return c; + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; + return (project_hook(GF_KILL_WALL, dir, dam, flg)); } - /*! - * @brief 部屋内にある一点の周囲に該当する地形数かいくつあるかをグローバル変数temp_nに返す / Aux function -- see below - * @param y 部屋内のy座標1点 - * @param x 部屋内のx座標1点 - * @param only_room 部屋内地形のみをチェック対象にするならば TRUE - * @param pass_bold 地形条件を返す関数ポインタ - * @return 該当地形の数 + * @brief 魔法の施錠処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す */ -static void cave_temp_room_aux(int y, int x, bool only_room, bool (*pass_bold)(int, int)) +bool wizard_lock(DIRECTION dir) { - cave_type *c_ptr; - - /* Get the grid */ - c_ptr = &cave[y][x]; - - /* Avoid infinite recursion */ - if (c_ptr->info & (CAVE_TEMP)) return; - - /* Do not "leave" the current room */ - if (!(c_ptr->info & (CAVE_ROOM))) - { - if (only_room) return; - - /* Verify */ - if (!in_bounds2(y, x)) return; - - /* Do not exceed the maximum spell range */ - if (distance(p_ptr->y, p_ptr->x, y, x) > MAX_RANGE) return; - - /* Verify this grid */ - /* - * The reason why it is ==6 instead of >5 is that 8 is impossible - * due to the check for cave_bold above. - * 7 lights dead-end corridors (you need to do this for the - * checkboard interesting rooms, so that the boundary is lit - * properly. - * This leaves only a check for 6 bounding walls! - */ - if (in_bounds(y, x) && pass_bold(y, x) && - (next_to_walls_adj(y, x, pass_bold) == 6) && (next_to_open(y, x, pass_bold) <= 1)) return; - } - - /* Paranoia -- verify space */ - if (temp_n == TEMP_MAX) return; - - /* Mark the grid as "seen" */ - c_ptr->info |= (CAVE_TEMP); - - /* Add it to the "seen" set */ - temp_y[temp_n] = y; - temp_x[temp_n] = x; - temp_n++; + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; + return (project_hook(GF_JAM_DOOR, dir, 20 + randint1(30), flg)); } /*! - * @brief 指定のマスが光を通すか(LOSフラグを持つか)を返す。 / Aux function -- see below - * @param y 指定Y座標 - * @param x 指定X座標 - * @return 光を通すならばtrueを返す。 + * @brief ドア破壊処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す */ -static bool cave_pass_lite_bold(int y, int x) +bool destroy_door(DIRECTION dir) { - return cave_los_bold(y, x); + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM; + return (project_hook(GF_KILL_DOOR, dir, 0, flg)); } /*! - * @brief 部屋内にある一点の周囲がいくつ光を通すかをグローバル変数temp_nに返す / Aux function -- see below - * @param y 指定Y座標 - * @param x 指定X座標 - * @return なし + * @brief トラップ解除処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す */ -static void cave_temp_lite_room_aux(int y, int x) +bool disarm_trap(DIRECTION dir) { - cave_temp_room_aux(y, x, FALSE, cave_pass_lite_bold); + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM; + return (project_hook(GF_KILL_TRAP, dir, 0, flg)); } /*! - * @brief 指定のマスが光を通さず射線のみを通すかを返す。 / Aux function -- see below - * @param y 指定Y座標 - * @param x 指定X座標 - * @return 射線を通すならばtrueを返す。 + * @brief モンスター回復処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す */ -static bool cave_pass_dark_bold(int y, int x) +bool heal_monster(DIRECTION dir, HIT_POINT dam) { - return cave_have_flag_bold(y, x, FF_PROJECT); + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_OLD_HEAL, dir, dam, flg)); } - /*! - * @brief 部屋内にある一点の周囲がいくつ射線を通すかをグローバル変数temp_nに返す / Aux function -- see below - * @param y 指定Y座標 - * @param x 指定X座標 - * @return なし + * @brief モンスター加速処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す */ -static void cave_temp_unlite_room_aux(int y, int x) +bool speed_monster(DIRECTION dir, int power) { - cave_temp_room_aux(y, x, TRUE, cave_pass_dark_bold); + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_OLD_SPEED, dir, power, flg)); } - /*! - * @brief 指定された部屋内を照らす / Illuminate any room containing the given location. - * @param y1 指定Y座標 - * @param x1 指定X座標 - * @return なし + * @brief モンスター減速処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す */ -void lite_room(int y1, int x1) +bool slow_monster(DIRECTION dir, int power) { - int i, x, y; - - /* Add the initial grid */ - cave_temp_lite_room_aux(y1, x1); - - /* While grids are in the queue, add their neighbors */ - for (i = 0; i < temp_n; i++) - { - x = temp_x[i], y = temp_y[i]; - - /* Walls get lit, but stop light */ - if (!cave_pass_lite_bold(y, x)) continue; - - /* Spread adjacent */ - cave_temp_lite_room_aux(y + 1, x); - cave_temp_lite_room_aux(y - 1, x); - cave_temp_lite_room_aux(y, x + 1); - cave_temp_lite_room_aux(y, x - 1); - - /* Spread diagonal */ - cave_temp_lite_room_aux(y + 1, x + 1); - cave_temp_lite_room_aux(y - 1, x - 1); - cave_temp_lite_room_aux(y - 1, x + 1); - cave_temp_lite_room_aux(y + 1, x - 1); - } - - /* Now, lite them all up at once */ - cave_temp_room_lite(); - - if (p_ptr->special_defense & NINJA_S_STEALTH) - { - if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); - } + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_OLD_SLOW, dir, power, flg)); } +/*! + * @brief モンスター催眠処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す + */ +bool sleep_monster(DIRECTION dir, int power) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_OLD_SLEEP, dir, power, flg)); +} /*! - * @brief 指定された部屋内を暗くする / Darken all rooms containing the given location - * @param y1 指定Y座標 - * @param x1 指定X座標 - * @return なし + * @brief モンスター拘束(STASIS)処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す + * @details 威力はプレイヤーレベル*2に固定 */ -void unlite_room(int y1, int x1) +bool stasis_monster(DIRECTION dir) { - int i, x, y; + return (fire_ball_hide(GF_STASIS, dir, p_ptr->lev*2, 0)); +} - /* Add the initial grid */ - cave_temp_unlite_room_aux(y1, x1); +/*! + * @brief 邪悪なモンスター拘束(STASIS)処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す + * @details 威力はプレイヤーレベル*2に固定 + */ +bool stasis_evil(DIRECTION dir) +{ + return (fire_ball_hide(GF_STASIS_EVIL, dir, p_ptr->lev*2, 0)); +} - /* Spread, breadth first */ - for (i = 0; i < temp_n; i++) - { - x = temp_x[i], y = temp_y[i]; +/*! + * @brief モンスター混乱処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(=効力) + * @return 作用が実際にあった場合TRUEを返す + */ +bool confuse_monster(DIRECTION dir, PLAYER_LEVEL plev) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_OLD_CONF, dir, plev, flg)); +} - /* Walls get dark, but stop darkness */ - if (!cave_pass_dark_bold(y, x)) continue; +/*! + * @brief モンスター朦朧処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(=効力) + * @return 作用が実際にあった場合TRUEを返す + */ +bool stun_monster(DIRECTION dir, PLAYER_LEVEL plev) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_STUN, dir, plev, flg)); +} - /* Spread adjacent */ - cave_temp_unlite_room_aux(y + 1, x); - cave_temp_unlite_room_aux(y - 1, x); - cave_temp_unlite_room_aux(y, x + 1); - cave_temp_unlite_room_aux(y, x - 1); +/*! + * @brief チェンジモンスター処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す + */ +bool poly_monster(DIRECTION dir, int power) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + bool tester = (project_hook(GF_OLD_POLY, dir, power, flg)); + if (tester) + chg_virtue(V_CHANCE, 1); + return(tester); +} - /* Spread diagonal */ - cave_temp_unlite_room_aux(y + 1, x + 1); - cave_temp_unlite_room_aux(y - 1, x - 1); - cave_temp_unlite_room_aux(y - 1, x + 1); - cave_temp_unlite_room_aux(y + 1, x - 1); - } +/*! + * @brief クローンモンスター処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す + */ +bool clone_monster(DIRECTION dir) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_OLD_CLONE, dir, 0, flg)); +} - /* Now, darken them all at once */ - cave_temp_room_unlite(); +/*! + * @brief モンスター恐慌処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(=効力) + * @return 作用が実際にあった場合TRUEを返す + */ +bool fear_monster(DIRECTION dir, PLAYER_LEVEL plev) +{ + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_TURN_ALL, dir, plev, flg)); } - - /*! - * @brief プレイヤー位置を中心にLITE_WEAK属性を通じた照明処理を行う / Hack -- call light around the player Affect all monsters in the projection radius - * @param dam 威力 - * @param rad 効果半径 + * @brief 死の光線処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(効力はplev*200) * @return 作用が実際にあった場合TRUEを返す */ -bool lite_area(int dam, int rad) +bool death_ray(DIRECTION dir, PLAYER_LEVEL plev) { - int flg = PROJECT_GRID | PROJECT_KILL; - - if (d_info[dungeon_type].flags1 & DF1_DARKNESS) - { - msg_print(_("ダンジョンが光を吸収した。", "The darkness of this dungeon absorb your light.")); - return FALSE; - } - - /* Hack -- Message */ - if (!p_ptr->blind) - { - msg_print(_("白い光が辺りを覆った。", "You are surrounded by a white light.")); - } - - /* Hook into the "project()" function */ - (void)project(0, rad, p_ptr->y, p_ptr->x, dam, GF_LITE_WEAK, flg, -1); - - /* Lite up the room */ - lite_room(p_ptr->y, p_ptr->x); - - /* Assume seen */ - return (TRUE); + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; + return (project_hook(GF_DEATH_RAY, dir, plev * 200, flg)); } - /*! - * @brief プレイヤー位置を中心にLITE_DARK属性を通じた消灯処理を行う / Hack -- call light around the player Affect all monsters in the projection radius - * @param dam 威力 - * @param rad 効果半径 + * @brief モンスター用テレポート処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param distance 移動距離 * @return 作用が実際にあった場合TRUEを返す */ -bool unlite_area(int dam, int rad) +bool teleport_monster(DIRECTION dir, int distance) { - int flg = PROJECT_GRID | PROJECT_KILL; - - /* Hack -- Message */ - if (!p_ptr->blind) - { - msg_print(_("暗闇が辺りを覆った。", "Darkness surrounds you.")); - } - - /* Hook into the "project()" function */ - (void)project(0, rad, p_ptr->y, p_ptr->x, dam, GF_DARK_WEAK, flg, -1); - - /* Lite up the room */ - unlite_room(p_ptr->y, p_ptr->x); - - /* Assume seen */ - return (TRUE); + BIT_FLAGS flg = PROJECT_BEAM | PROJECT_KILL; + return (project_hook(GF_AWAY_ALL, dir, distance, flg)); } - - /*! - * @brief ボール系スペルの発動 / Cast a ball spell - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @param rad 半径 + * @brief ドア生成処理(プレイヤー中心に周囲1マス) / Hooks -- affect adjacent grids (radius 1 ball attack) * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Stop if we hit a monster, act as a "ball"
- * Allow "target" mode to pass over monsters
- * Affect grids, objects, and monsters
- * 
*/ -bool fire_ball(int typ, int dir, int dam, int rad) +bool door_creation(void) { - int tx, ty; - - int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; - - if (typ == GF_CONTROL_LIVING) flg|= PROJECT_HIDE; - /* Use the given direction */ - tx = p_ptr->x + 99 * ddx[dir]; - ty = p_ptr->y + 99 * ddy[dir]; - - /* Hack -- Use an actual "target" */ - if ((dir == 5) && target_okay()) - { - flg &= ~(PROJECT_STOP); - tx = target_col; - ty = target_row; - } + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; + return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_MAKE_DOOR, flg, -1)); +} - /* Analyze the "dir" and the "target". Hurt items on floor. */ - return (project(0, rad, ty, tx, dam, typ, flg, -1)); +/*! + * @brief トラップ生成処理(起点から周囲1マス) + * @param y 起点Y座標 + * @param x 起点X座標 + * @return 作用が実際にあった場合TRUEを返す + */ +bool trap_creation(POSITION y, POSITION x) +{ + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; + return (project(0, 1, y, x, 0, GF_MAKE_TRAP, flg, -1)); } +/*! + * @brief 森林生成処理(プレイヤー中心に周囲1マス) + * @return 作用が実際にあった場合TRUEを返す + */ +bool tree_creation(void) +{ + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; + return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_MAKE_TREE, flg, -1)); +} +/*! + * @brief 魔法のルーン生成処理(プレイヤー中心に周囲1マス) + * @return 作用が実際にあった場合TRUEを返す + */ +bool glyph_creation(void) +{ + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM; + return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_MAKE_GLYPH, flg, -1)); +} /*! - * @brief ロケット系スペルの発動(詳細な差は確認中) / Cast a ball spell - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @param rad 半径 + * @brief 壁生成処理(プレイヤー中心に周囲1マス) * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Stop if we hit a monster, act as a "ball"
- * Allow "target" mode to pass over monsters
- * Affect grids, objects, and monsters
- * 
*/ -bool fire_rocket(int typ, int dir, int dam, int rad) +bool wall_stone(void) { - int tx, ty; + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; + bool dummy = (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_STONE_WALL, flg, -1)); - /* Use the given direction */ - tx = p_ptr->x + 99 * ddx[dir]; - ty = p_ptr->y + 99 * ddy[dir]; + p_ptr->update |= (PU_FLOW); - /* Hack -- Use an actual "target" */ - if ((dir == 5) && target_okay()) - { - tx = target_col; - ty = target_row; - } + p_ptr->redraw |= (PR_MAP); - /* Analyze the "dir" and the "target". Hurt items on floor. */ - return (project(0, rad, ty, tx, dam, typ, flg, -1)); + return dummy; } - /*! - * @brief ボール(ハイド)系スペルの発動 / Cast a ball spell - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @param rad 半径 + * @brief ドア破壊処理(プレイヤー中心に周囲1マス) * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Stop if we hit a monster, act as a "ball"
- * Allow "target" mode to pass over monsters
- * Affect grids, objects, and monsters
- * 
*/ -bool fire_ball_hide(int typ, int dir, int dam, int rad) +bool destroy_doors_touch(void) { - int tx, ty; + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; + return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_KILL_DOOR, flg, -1)); +} - int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_HIDE; +/*! + * @brief トラップ解除処理(プレイヤー中心に周囲1マス) + * @return 作用が実際にあった場合TRUEを返す + */ +bool disarm_traps_touch(void) +{ + BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; + return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_KILL_TRAP, flg, -1)); +} - /* Use the given direction */ - tx = p_ptr->x + 99 * ddx[dir]; - ty = p_ptr->y + 99 * ddy[dir]; +/*! + * @brief スリープモンスター処理(プレイヤー中心に周囲1マス) + * @return 作用が実際にあった場合TRUEを返す + */ +bool sleep_monsters_touch(void) +{ + BIT_FLAGS flg = PROJECT_KILL | PROJECT_HIDE; + return (project(0, 1, p_ptr->y, p_ptr->x, p_ptr->lev, GF_OLD_SLEEP, flg, -1)); +} - /* Hack -- Use an actual "target" */ - if ((dir == 5) && target_okay()) - { - flg &= ~(PROJECT_STOP); - tx = target_col; - ty = target_row; - } - /* Analyze the "dir" and the "target". Hurt items on floor. */ - return (project(0, rad, ty, tx, dam, typ, flg, -1)); +/*! + * @brief 死者復活処理(起点より周囲5マス) + * @param who 術者モンスターID(0ならばプレイヤー) + * @param y 起点Y座標 + * @param x 起点X座標 + * @return 作用が実際にあった場合TRUEを返す + */ +bool animate_dead(MONSTER_IDX who, POSITION y, POSITION x) +{ + BIT_FLAGS flg = PROJECT_ITEM | PROJECT_HIDE; + return (project(who, 5, y, x, 0, GF_ANIM_DEAD, flg, -1)); } - /*! - * @brief メテオ系スペルの発動 / Cast a meteor spell - * @param who スぺル詠唱者のモンスターID(0=プレイヤー) - * @param typ 効果属性 - * @param dam 威力 - * @param rad 半径 - * @param y 中心点Y座標 - * @param x 中心点X座標 + * @brief 混沌招来処理 * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Cast a meteor spell, defined as a ball spell cast by an arbitary monster, 
- * player, or outside source, that starts out at an arbitrary location, and 
- * leaving no trail from the "caster" to the target.  This function is 
- * especially useful for bombardments and similar. -LM-
- * Option to hurt the player.
- * 
*/ -bool fire_meteor(int who, int typ, int y, int x, int dam, int rad) +void call_chaos(void) { - int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; + int Chaos_type, dummy, dir; + PLAYER_LEVEL plev = p_ptr->lev; + bool line_chaos = FALSE; - /* Analyze the "target" and the caster. */ - return (project(who, rad, y, x, dam, typ, flg, -1)); -} + int hurt_types[31] = + { + GF_ELEC, GF_POIS, GF_ACID, GF_COLD, + GF_FIRE, GF_MISSILE, GF_ARROW, GF_PLASMA, + GF_HOLY_FIRE, GF_WATER, GF_LITE, GF_DARK, + GF_FORCE, GF_INERTIAL, GF_MANA, GF_METEOR, + GF_ICE, GF_CHAOS, GF_NETHER, GF_DISENCHANT, + GF_SHARDS, GF_SOUND, GF_NEXUS, GF_CONFUSION, + GF_TIME, GF_GRAVITY, GF_ROCKET, GF_NUKE, + GF_HELL_FIRE, GF_DISINTEGRATE, GF_PSY_SPEAR + }; + + Chaos_type = hurt_types[randint0(31)]; + if (one_in_(4)) line_chaos = TRUE; + if (one_in_(6)) + { + for (dummy = 1; dummy < 10; dummy++) + { + if (dummy - 5) + { + if (line_chaos) + fire_beam(Chaos_type, dummy, 150); + else + fire_ball(Chaos_type, dummy, 150, 2); + } + } + } + else if (one_in_(3)) + { + fire_ball(Chaos_type, 0, 500, 8); + } + else + { + if (!get_aim_dir(&dir)) return; + if (line_chaos) + fire_beam(Chaos_type, dir, 250); + else + fire_ball(Chaos_type, dir, 250, 3 + (plev / 35)); + } +} /*! - * @brief ブラスト系スペルの発動 / Cast a blast spell - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dd 威力ダイス数 - * @param ds 威力ダイス目 - * @param num 基本回数 - * @param dev 回数分散 + * @brief TY_CURSE処理発動 / Activate the evil Topi Ylinen curse + * @param stop_ty 再帰処理停止フラグ + * @param count 発動回数 * @return 作用が実際にあった場合TRUEを返す + * @details + *
+ * rr9: Stop the nasty things when a Cyberdemon is summoned
+ * or the player gets paralyzed.
+ * 
*/ -bool fire_blast(int typ, int dir, int dd, int ds, int num, int dev) +bool activate_ty_curse(bool stop_ty, int *count) { - int ly, lx, ld; - int ty, tx, y, x; - int i; - - int flg = PROJECT_FAST | PROJECT_THRU | PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE | PROJECT_GRID; - - /* Assume okay */ - bool result = TRUE; - - /* Use the given direction */ - if (dir != 5) - { - ly = ty = p_ptr->y + 20 * ddy[dir]; - lx = tx = p_ptr->x + 20 * ddx[dir]; - } - - /* Use an actual "target" */ - else /* if (dir == 5) */ - { - tx = target_col; - ty = target_row; - - lx = 20 * (tx - p_ptr->x) + p_ptr->x; - ly = 20 * (ty - p_ptr->y) + p_ptr->y; - } + int i = 0; - ld = distance(p_ptr->y, p_ptr->x, ly, lx); + BIT_FLAGS flg = (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP); - /* Blast */ - for (i = 0; i < num; i++) + do { - while (1) + switch (randint1(34)) { - /* Get targets for some bolts */ - y = rand_spread(ly, ld * dev / 20); - x = rand_spread(lx, ld * dev / 20); - - if (distance(ly, lx, y, x) <= ld * dev / 20) break; - } + case 28: case 29: + if (!(*count)) + { + msg_print(_("地面が揺れた...", "The ground trembles...")); + earthquake(p_ptr->y, p_ptr->x, 5 + randint0(10)); + if (!one_in_(6)) break; + } + case 30: case 31: + if (!(*count)) + { + HIT_POINT dam = damroll(10, 10); + msg_print(_("純粋な魔力の次元への扉が開いた!", "A portal opens to a plane of raw mana!")); + project(0, 8, p_ptr->y, p_ptr->x, dam, GF_MANA, flg, -1); + take_hit(DAMAGE_NOESCAPE, dam, _("純粋な魔力の解放", "released pure mana"), -1); + if (!one_in_(6)) break; + } + case 32: case 33: + if (!(*count)) + { + msg_print(_("周囲の空間が歪んだ!", "Space warps about you!")); + teleport_player(damroll(10, 10), TELEPORT_PASSIVE); + if (randint0(13)) (*count) += activate_hi_summon(p_ptr->y, p_ptr->x, FALSE); + if (!one_in_(6)) break; + } + case 34: + msg_print(_("エネルギーのうねりを感じた!", "You feel a surge of energy!")); + wall_breaker(); + if (!randint0(7)) + { + project(0, 7, p_ptr->y, p_ptr->x, 50, GF_KILL_WALL, flg, -1); + take_hit(DAMAGE_NOESCAPE, 50, _("エネルギーのうねり", "surge of energy"), -1); + } + if (!one_in_(6)) break; + case 1: case 2: case 3: case 16: case 17: + aggravate_monsters(0); + if (!one_in_(6)) break; + case 4: case 5: case 6: + (*count) += activate_hi_summon(p_ptr->y, p_ptr->x, FALSE); + if (!one_in_(6)) break; + case 7: case 8: case 9: case 18: + (*count) += summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)); + if (!one_in_(6)) break; + case 10: case 11: case 12: + msg_print(_("経験値が体から吸い取られた気がする!", "You feel your experience draining away...")); + lose_exp(p_ptr->exp / 16); + if (!one_in_(6)) break; + case 13: case 14: case 15: case 19: case 20: + if (stop_ty || (p_ptr->free_act && (randint1(125) < p_ptr->skill_sav)) || (p_ptr->pclass == CLASS_BERSERKER)) + { + /* Do nothing */ ; + } + else + { + msg_print(_("彫像になった気分だ!", "You feel like a statue!")); + if (p_ptr->free_act) + set_paralyzed(p_ptr->paralyzed + randint1(3)); + else + set_paralyzed(p_ptr->paralyzed + randint1(13)); + stop_ty = TRUE; + } + if (!one_in_(6)) break; + case 21: case 22: case 23: + (void)do_dec_stat(randint0(6)); + if (!one_in_(6)) break; + case 24: + msg_print(_("ほえ?私は誰?ここで何してる?", "Huh? Who am I? What am I doing here?")); + lose_all_info(); + if (!one_in_(6)) break; + case 25: + /* + * Only summon Cyberdemons deep in the dungeon. + */ + if ((dun_level > 65) && !stop_ty) + { + (*count) += summon_cyber(-1, p_ptr->y, p_ptr->x); + stop_ty = TRUE; + break; + } + if (!one_in_(6)) break; + default: + while (i < 6) + { + do + { + (void)do_dec_stat(i); + } + while (one_in_(2)); - /* Analyze the "dir" and the "target". */ - if (!project(0, 0, y, x, damroll(dd, ds), typ, flg, -1)) - { - result = FALSE; + i++; + } } } + while (one_in_(3) && !stop_ty); - return (result); + return stop_ty; } - /*! - * @brief モンスターとの位置交換処理 / Switch position with a monster. - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @brief HI_SUMMON(上級召喚)処理発動 + * @param y 召喚位置Y座標 + * @param x 召喚位置X座標 + * @param can_pet プレイヤーのペットとなる可能性があるならばTRUEにする * @return 作用が実際にあった場合TRUEを返す */ -bool teleport_swap(int dir) +int activate_hi_summon(POSITION y, POSITION x, bool can_pet) { - int tx, ty; - cave_type * c_ptr; - monster_type * m_ptr; - monster_race * r_ptr; - - if ((dir == 5) && target_okay()) - { - tx = target_col; - ty = target_row; - } - else - { - tx = p_ptr->x + ddx[dir]; - ty = p_ptr->y + ddy[dir]; - } - c_ptr = &cave[ty][tx]; - - if (p_ptr->anti_tele) - { - msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!")); - return FALSE; - } - - if (!c_ptr->m_idx || (c_ptr->m_idx == p_ptr->riding)) - { - msg_print(_("それとは場所を交換できません。", "You can't trade places with that!")); - - /* Failure */ - return FALSE; - } + int i; + int count = 0; + DEPTH summon_lev; + BIT_FLAGS mode = PM_ALLOW_GROUP; + bool pet = FALSE; - if ((c_ptr->info & CAVE_ICKY) || (distance(ty, tx, p_ptr->y, p_ptr->x) > p_ptr->lev * 3 / 2 + 10)) + if (can_pet) { - msg_print(_("失敗した。", "Failed to swap.")); - - /* Failure */ - return FALSE; + if (one_in_(4)) + { + mode |= PM_FORCE_FRIENDLY; + } + else + { + mode |= PM_FORCE_PET; + pet = TRUE; + } } - m_ptr = &m_list[c_ptr->m_idx]; - r_ptr = &r_info[m_ptr->r_idx]; + if (!pet) mode |= PM_NO_PET; - (void)set_monster_csleep(c_ptr->m_idx, 0); + summon_lev = (pet ? p_ptr->lev * 2 / 3 + randint1(p_ptr->lev / 2) : dun_level); - if (r_ptr->flagsr & RFR_RES_TELE) + for (i = 0; i < (randint1(7) + (dun_level / 40)); i++) { - msg_print(_("テレポートを邪魔された!", "Your teleportation is blocked!")); - - if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= RFR_RES_TELE; - - /* Failure */ - return FALSE; + switch (randint1(25) + (dun_level / 20)) + { + case 1: case 2: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_ANT, mode); + break; + case 3: case 4: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_SPIDER, mode); + break; + case 5: case 6: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HOUND, mode); + break; + case 7: case 8: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HYDRA, mode); + break; + case 9: case 10: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_ANGEL, mode); + break; + case 11: case 12: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_UNDEAD, mode); + break; + case 13: case 14: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_DRAGON, mode); + break; + case 15: case 16: + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_DEMON, mode); + break; + case 17: + if (can_pet) break; + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_AMBERITES, (mode | PM_ALLOW_UNIQUE)); + break; + case 18: case 19: + if (can_pet) break; + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_UNIQUE, (mode | PM_ALLOW_UNIQUE)); + break; + case 20: case 21: + if (!can_pet) mode |= PM_ALLOW_UNIQUE; + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HI_UNDEAD, mode); + break; + case 22: case 23: + if (!can_pet) mode |= PM_ALLOW_UNIQUE; + count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HI_DRAGON, mode); + break; + case 24: + count += summon_specific((pet ? -1 : 0), y, x, 100, SUMMON_CYBER, mode); + break; + default: + if (!can_pet) mode |= PM_ALLOW_UNIQUE; + count += summon_specific((pet ? -1 : 0), y, x,pet ? summon_lev : (((summon_lev * 3) / 2) + 5), 0, mode); + } } - sound(SOUND_TELEPORT); - - /* Swap the player and monster */ - (void)move_player_effect(ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP); - - /* Success */ - return TRUE; + return count; } /*! - * @brief 指定方向に飛び道具を飛ばす(フラグ任意指定) / Hack -- apply a "projection()" in a direction (or at the target) - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @param flg フラグ + * @brief サイバーデーモンの召喚 + * @param who 召喚主のモンスターID(0ならばプレイヤー) + * @param y 召喚位置Y座標 + * @param x 召喚位置X座標 * @return 作用が実際にあった場合TRUEを返す */ -bool project_hook(int typ, int dir, int dam, int flg) +int summon_cyber(MONSTER_IDX who, POSITION y, POSITION x) { - int tx, ty; + int i; + int max_cyber = (easy_band ? 1 : (dun_level / 50) + randint1(2)); + int count = 0; + BIT_FLAGS mode = PM_ALLOW_GROUP; - /* Pass through the target if needed */ - flg |= (PROJECT_THRU); + /* Summoned by a monster */ + if (who > 0) + { + monster_type *m_ptr = &m_list[who]; + if (is_pet(m_ptr)) mode |= PM_FORCE_PET; + } - /* Use the given direction */ - tx = p_ptr->x + ddx[dir]; - ty = p_ptr->y + ddy[dir]; + if (max_cyber > 4) max_cyber = 4; - /* Hack -- Use an actual "target" */ - if ((dir == 5) && target_okay()) + for (i = 0; i < max_cyber; i++) { - tx = target_col; - ty = target_row; + count += summon_specific(who, y, x, 100, SUMMON_CYBER, mode); } - /* Analyze the "dir" and the "target", do NOT explode */ - return (project(0, 0, ty, tx, dam, typ, flg, -1)); + return count; } - /*! - * @brief ボルト系スペルの発動 / Cast a bolt spell. - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 + * @brief 周辺破壊効果(プレイヤー中心) * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Stop if we hit a monster, as a "bolt".
- * Affect monsters and grids (not objects).
- * 
*/ -bool fire_bolt(int typ, int dir, int dam) +void wall_breaker(void) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_GRID; - if (typ != GF_ARROW) flg |= PROJECT_REFLECTABLE; - return (project_hook(typ, dir, dam, flg)); -} + int i; + POSITION y = 0, x = 0; + int attempts = 1000; + if (randint1(80 + p_ptr->lev) < 70) + { + while (attempts--) + { + scatter(&y, &x, p_ptr->y, p_ptr->x, 4, 0); -/*! - * @brief ビーム系スペルの発動 / Cast a beam spell. - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Pass through monsters, as a "beam".
- * Affect monsters, grids and objects.
- * 
- */ -bool fire_beam(int typ, int dir, int dam) -{ - int flg = PROJECT_BEAM | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM; - return (project_hook(typ, dir, dam, flg)); -} + if (!cave_have_flag_bold(y, x, FF_PROJECT)) continue; + if (!player_bold(y, x)) break; + } -/*! - * @brief 確率に応じたボルト系/ビーム系スペルの発動 / Cast a bolt spell, or rarely, a beam spell. - * @param prob ビーム化する確率(%) - * @param typ 効果属性 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * Pass through monsters, as a "beam".
- * Affect monsters, grids and objects.
- * 
- */ -bool fire_bolt_or_beam(int prob, int typ, int dir, int dam) -{ - if (randint0(100) < prob) + project(0, 0, y, x, 20 + randint1(30), GF_KILL_WALL, + (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL), -1); + } + else if (randint1(100) > 30) { - return (fire_beam(typ, dir, dam)); + earthquake(p_ptr->y, p_ptr->x, 1); } else { - return (fire_bolt(typ, dir, dam)); - } -} - -/*! - * @brief LITE_WEAK属性による光源ビーム処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool lite_line(int dir, int dam) -{ - int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_KILL; - return (project_hook(GF_LITE_WEAK, dir, dam, flg)); -} - -/*! - * @brief 吸血ボルト処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool drain_life(int dir, int dam) -{ - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_DRAIN, dir, dam, flg)); -} - -/*! - * @brief 岩石溶解処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool wall_to_mud(int dir, int dam) -{ - int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; - return (project_hook(GF_KILL_WALL, dir, dam, flg)); -} + int num = damroll(5, 3); -/*! - * @brief 魔法の施錠処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @return 作用が実際にあった場合TRUEを返す - */ -bool wizard_lock(int dir) -{ - int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL; - return (project_hook(GF_JAM_DOOR, dir, 20 + randint1(30), flg)); -} + for (i = 0; i < num; i++) + { + while (1) + { + scatter(&y, &x, p_ptr->y, p_ptr->x, 10, 0); -/*! - * @brief ドア破壊処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @return 作用が実際にあった場合TRUEを返す - */ -bool destroy_door(int dir) -{ - int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM; - return (project_hook(GF_KILL_DOOR, dir, 0, flg)); -} + if (!player_bold(y, x)) break; + } -/*! - * @brief トラップ解除処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @return 作用が実際にあった場合TRUEを返す - */ -bool disarm_trap(int dir) -{ - int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM; - return (project_hook(GF_KILL_TRAP, dir, 0, flg)); + project(0, 0, y, x, 20 + randint1(30), GF_KILL_WALL, + (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL), -1); + } + } } -/*! - * @brief モンスター回復処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param dam 威力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool heal_monster(int dir, int dam) -{ - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_HEAL, dir, dam, flg)); -} /*! - * @brief モンスター加速処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param power 効力 + * @brief パニック・モンスター効果(プレイヤー視界範囲内) / Confuse monsters + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool speed_monster(int dir, int power) +bool confuse_monsters(HIT_POINT dam) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_SPEED, dir, power, flg)); + return (project_hack(GF_OLD_CONF, dam)); } -/*! - * @brief モンスター減速処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param power 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool slow_monster(int dir, int power) -{ - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_SLOW, dir, power, flg)); -} /*! - * @brief モンスター催眠処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param power 効力 + * @brief チャーム・モンスター効果(プレイヤー視界範囲内) / Charm monsters + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool sleep_monster(int dir, int power) +bool charm_monsters(HIT_POINT dam) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_SLEEP, dir, power, flg)); + return (project_hack(GF_CHARM, dam)); } -/*! - * @brief モンスター拘束(STASIS)処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @return 作用が実際にあった場合TRUEを返す - * @details 威力はプレイヤーレベル*2に固定 - */ -bool stasis_monster(int dir) -{ - return (fire_ball_hide(GF_STASIS, dir, p_ptr->lev*2, 0)); -} /*! - * @brief 邪悪なモンスター拘束(STASIS)処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @brief 動物魅了効果(プレイヤー視界範囲内) / Charm Animals + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す - * @details 威力はプレイヤーレベル*2に固定 */ -bool stasis_evil(int dir) +bool charm_animals(HIT_POINT dam) { - return (fire_ball_hide(GF_STASIS_EVIL, dir, p_ptr->lev*2, 0)); + return (project_hack(GF_CONTROL_ANIMAL, dam)); } -/*! - * @brief モンスター混乱処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev プレイヤーレベル(=効力) - * @return 作用が実際にあった場合TRUEを返す - */ -bool confuse_monster(int dir, int plev) -{ - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_CONF, dir, plev, flg)); -} /*! - * @brief モンスター朦朧処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev プレイヤーレベル(=効力) + * @brief モンスター朦朧効果(プレイヤー視界範囲内) / Stun monsters + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool stun_monster(int dir, int plev) +bool stun_monsters(HIT_POINT dam) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_STUN, dir, plev, flg)); + return (project_hack(GF_STUN, dam)); } -/*! - * @brief チェンジモンスター処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param power 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool poly_monster(int dir, int power) -{ - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - bool tester = (project_hook(GF_OLD_POLY, dir, power, flg)); - if (tester) - chg_virtue(V_CHANCE, 1); - return(tester); -} /*! - * @brief クローンモンスター処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @brief モンスター停止効果(プレイヤー視界範囲内) / Stasis monsters + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool clone_monster(int dir) +bool stasis_monsters(HIT_POINT dam) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_OLD_CLONE, dir, 0, flg)); + return (project_hack(GF_STASIS, dam)); } + /*! - * @brief モンスター恐慌処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev プレイヤーレベル(=効力) + * @brief モンスター精神攻撃効果(プレイヤー視界範囲内) / Mindblast monsters + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool fear_monster(int dir, int plev) +bool mindblast_monsters(HIT_POINT dam) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_TURN_ALL, dir, plev, flg)); + return (project_hack(GF_PSI, dam)); } + /*! - * @brief 死の光線処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev プレイヤーレベル(効力はplev*200) + * @brief モンスター追放効果(プレイヤー視界範囲内) / Banish all monsters + * @param dist 効力(距離) * @return 作用が実際にあった場合TRUEを返す */ -bool death_ray(int dir, int plev) +bool banish_monsters(int dist) { - int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE; - return (project_hook(GF_DEATH_RAY, dir, plev * 200, flg)); + return (project_hack(GF_AWAY_ALL, dist)); } + /*! - * @brief モンスター用テレポート処理 - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param distance 移動距離 + * @brief 邪悪退散効果(プレイヤー視界範囲内) / Turn evil + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool teleport_monster(int dir, int distance) +bool turn_evil(HIT_POINT dam) { - int flg = PROJECT_BEAM | PROJECT_KILL; - return (project_hook(GF_AWAY_ALL, dir, distance, flg)); + return (project_hack(GF_TURN_EVIL, dam)); } + /*! - * @brief ドア生成処理(プレイヤー中心に周囲1マス) / Hooks -- affect adjacent grids (radius 1 ball attack) + * @brief 全モンスター退散効果(プレイヤー視界範囲内) / Turn everyone + * @param dam 効力 * @return 作用が実際にあった場合TRUEを返す */ -bool door_creation(void) +bool turn_monsters(HIT_POINT dam) { - int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_MAKE_DOOR, flg, -1)); + return (project_hack(GF_TURN_ALL, dam)); } + /*! - * @brief トラップ生成処理(起点から周囲1マス) - * @param y 起点Y座標 - * @param x 起点X座標 + * @brief 死の光線(プレイヤー視界範囲内) / Death-ray all monsters (note: OBSCENELY powerful) * @return 作用が実際にあった場合TRUEを返す */ -bool trap_creation(int y, int x) +bool deathray_monsters(void) { - int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - return (project(0, 1, y, x, 0, GF_MAKE_TRAP, flg, -1)); + return (project_hack(GF_DEATH_RAY, p_ptr->lev * 200)); } /*! - * @brief 森林生成処理(プレイヤー中心に周囲1マス) + * @brief チャーム・モンスター(1体) + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev パワー * @return 作用が実際にあった場合TRUEを返す */ -bool tree_creation(void) +bool charm_monster(DIRECTION dir, PLAYER_LEVEL plev) { - int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_MAKE_TREE, flg, -1)); + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL; + return (project_hook(GF_CHARM, dir, plev, flg)); } /*! - * @brief 魔法のルーン生成処理(プレイヤー中心に周囲1マス) + * @brief アンデッド支配(1体) + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev パワー * @return 作用が実際にあった場合TRUEを返す */ -bool glyph_creation(void) +bool control_one_undead(DIRECTION dir, PLAYER_LEVEL plev) { - int flg = PROJECT_GRID | PROJECT_ITEM; - return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_MAKE_GLYPH, flg, -1)); + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL; + return (project_hook(GF_CONTROL_UNDEAD, dir, plev, flg)); } /*! - * @brief 壁生成処理(プレイヤー中心に周囲1マス) + * @brief 悪魔支配(1体) + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev パワー * @return 作用が実際にあった場合TRUEを返す */ -bool wall_stone(void) +bool control_one_demon(DIRECTION dir, PLAYER_LEVEL plev) { - int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - - bool dummy = (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_STONE_WALL, flg, -1)); - - /* Update stuff */ - p_ptr->update |= (PU_FLOW); - - /* Redraw map */ - p_ptr->redraw |= (PR_MAP); - - return dummy; + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL; + return (project_hook(GF_CONTROL_DEMON, dir, plev, flg)); } /*! - * @brief ドア破壊処理(プレイヤー中心に周囲1マス) + * @brief 動物支配(1体) + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev パワー * @return 作用が実際にあった場合TRUEを返す */ -bool destroy_doors_touch(void) +bool charm_animal(DIRECTION dir, PLAYER_LEVEL plev) { - int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_KILL_DOOR, flg, -1)); + BIT_FLAGS flg = PROJECT_STOP | PROJECT_KILL; + return (project_hook(GF_CONTROL_ANIMAL, dir, plev, flg)); } + /*! - * @brief トラップ解除処理(プレイヤー中心に周囲1マス) + * @brief 変わり身処理 + * @param success 判定成功上の処理ならばTRUE * @return 作用が実際にあった場合TRUEを返す */ -bool disarm_traps_touch(void) +bool kawarimi(bool success) { - int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; - return (project(0, 1, p_ptr->y, p_ptr->x, 0, GF_KILL_TRAP, flg, -1)); + object_type forge; + object_type *q_ptr = &forge; + POSITION y, x; + + if (p_ptr->is_dead) return FALSE; + if (p_ptr->confused || p_ptr->blind || p_ptr->paralyzed || p_ptr->image) return FALSE; + if (randint0(200) < p_ptr->stun) return FALSE; + + if (!success && one_in_(3)) + { + msg_print(_("失敗!逃げられなかった。", "Failed! You couldn't run away.")); + p_ptr->special_defense &= ~(NINJA_KAWARIMI); + p_ptr->redraw |= (PR_STATUS); + return FALSE; + } + + y = p_ptr->y; + x = p_ptr->x; + + teleport_player(10 + randint1(90), 0L); + + object_wipe(q_ptr); + + object_prep(q_ptr, lookup_kind(TV_STATUE, SV_WOODEN_STATUE)); + + q_ptr->pval = MON_NINJA; + + /* Drop it in the dungeon */ + (void)drop_near(q_ptr, -1, y, x); + +#ifdef JP + if (success) msg_print("攻撃を受ける前に素早く身をひるがえした。"); + else msg_print("失敗!攻撃を受けてしまった。"); +#else + if (success) msg_print("You have turned around just before the attack hit you."); + else msg_print("Failed! You are hit by the attack."); +#endif + + p_ptr->special_defense &= ~(NINJA_KAWARIMI); + p_ptr->redraw |= (PR_STATUS); + + /* Teleported */ + return TRUE; } + /*! - * @brief スリープモンスター処理(プレイヤー中心に周囲1マス) - * @return 作用が実際にあった場合TRUEを返す + * @brief 入身処理 / "Rush Attack" routine for Samurai or Ninja + * @param mdeath 目標モンスターが死亡したかを返す + * @return 作用が実際にあった場合TRUEを返す / Return value is for checking "done" */ -bool sleep_monsters_touch(void) +bool rush_attack(bool *mdeath) { - int flg = PROJECT_KILL | PROJECT_HIDE; - return (project(0, 1, p_ptr->y, p_ptr->x, p_ptr->lev, GF_OLD_SLEEP, flg, -1)); + DIRECTION dir; + int tx, ty; + int tm_idx = 0; + u16b path_g[32]; + int path_n, i; + bool tmp_mdeath = FALSE; + bool moved = FALSE; + + if (mdeath) *mdeath = FALSE; + + project_length = 5; + if (!get_aim_dir(&dir)) return FALSE; + + /* Use the given direction */ + tx = p_ptr->x + project_length * ddx[dir]; + ty = p_ptr->y + project_length * ddy[dir]; + + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) + { + tx = target_col; + ty = target_row; + } + + if (in_bounds(ty, tx)) tm_idx = cave[ty][tx].m_idx; + + path_n = project_path(path_g, project_length, p_ptr->y, p_ptr->x, ty, tx, PROJECT_STOP | PROJECT_KILL); + project_length = 0; + + /* No need to move */ + if (!path_n) return TRUE; + + /* Use ty and tx as to-move point */ + ty = p_ptr->y; + tx = p_ptr->x; + + /* Project along the path */ + for (i = 0; i < path_n; i++) + { + monster_type *m_ptr; + + int ny = GRID_Y(path_g[i]); + int nx = GRID_X(path_g[i]); + + if (cave_empty_bold(ny, nx) && player_can_enter(cave[ny][nx].feat, 0)) + { + ty = ny; + tx = nx; + + /* Go to next grid */ + continue; + } + + if (!cave[ny][nx].m_idx) + { + if (tm_idx) + { + msg_print(_("失敗!", "Failed!")); + } + else + { + msg_print(_("ここには入身では入れない。", "You can't move to that place.")); + } + + /* Exit loop */ + break; + } + + /* Move player before updating the monster */ + if (!player_bold(ty, tx)) teleport_player_to(ty, tx, TELEPORT_NONMAGICAL); + update_monster(cave[ny][nx].m_idx, TRUE); + + /* Found a monster */ + m_ptr = &m_list[cave[ny][nx].m_idx]; + + if (tm_idx != cave[ny][nx].m_idx) + { +#ifdef JP + msg_format("%s%sが立ちふさがっている!", tm_idx ? "別の" : "", + m_ptr->ml ? "モンスター" : "何か"); +#else + msg_format("There is %s in the way!", m_ptr->ml ? (tm_idx ? "another monster" : "a monster") : "someone"); +#endif + } + else if (!player_bold(ty, tx)) + { + /* Hold the monster name */ + char m_name[80]; + + /* Get the monster name (BEFORE polymorphing) */ + monster_desc(m_name, m_ptr, 0); + msg_format(_("素早く%sの懐に入り込んだ!", "You quickly jump in and attack %s!"), m_name); + } + + if (!player_bold(ty, tx)) teleport_player_to(ty, tx, TELEPORT_NONMAGICAL); + moved = TRUE; + tmp_mdeath = py_attack(ny, nx, HISSATSU_NYUSIN); + + break; + } + + if (!moved && !player_bold(ty, tx)) teleport_player_to(ty, tx, TELEPORT_NONMAGICAL); + + if (mdeath) *mdeath = tmp_mdeath; + return TRUE; } /*! - * @brief 死者復活処理(起点より周囲5マス) - * @param who 術者モンスターID(0ならばプレイやー) - * @param y 起点Y座標 - * @param x 起点X座標 - * @return 作用が実際にあった場合TRUEを返す + * @brief 全鏡の消去 / Remove all mirrors in this floor + * @param explode 爆発処理を伴うならばTRUE + * @return なし */ -bool animate_dead(int who, int y, int x) +void remove_all_mirrors(bool explode) { - int flg = PROJECT_ITEM | PROJECT_HIDE; - return (project(who, 5, y, x, 0, GF_ANIM_DEAD, flg, -1)); + POSITION x, y; + + for (x = 0; x < cur_wid; x++) + { + for (y = 0; y < cur_hgt; y++) + { + if (is_mirror_grid(&cave[y][x])) + { + remove_mirror(y, x); + if (explode) + project(0, 2, y, x, p_ptr->lev / 2 + 5, GF_SHARDS, + (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI), -1); + } + } + } } /*! - * @brief 混沌招来処理 - * @return 作用が実際にあった場合TRUEを返す + * @brief 『一つの指輪』の効果処理 / + * Hack -- activate the ring of power + * @param dir 発動の方向ID + * @return なし */ -void call_chaos(void) +void ring_of_power(DIRECTION dir) { - int Chaos_type, dummy, dir; - int plev = p_ptr->lev; - bool line_chaos = FALSE; - - int hurt_types[31] = + /* Pick a random effect */ + switch (randint1(10)) { - GF_ELEC, GF_POIS, GF_ACID, GF_COLD, - GF_FIRE, GF_MISSILE, GF_ARROW, GF_PLASMA, - GF_HOLY_FIRE, GF_WATER, GF_LITE, GF_DARK, - GF_FORCE, GF_INERTIAL, GF_MANA, GF_METEOR, - GF_ICE, GF_CHAOS, GF_NETHER, GF_DISENCHANT, - GF_SHARDS, GF_SOUND, GF_NEXUS, GF_CONFUSION, - GF_TIME, GF_GRAVITY, GF_ROCKET, GF_NUKE, - GF_HELL_FIRE, GF_DISINTEGRATE, GF_PSY_SPEAR - }; + case 1: + case 2: + { + msg_print(_("あなたは悪性のオーラに包み込まれた。", "You are surrounded by a malignant aura.")); + sound(SOUND_EVIL); - Chaos_type = hurt_types[randint0(31)]; - if (one_in_(4)) line_chaos = TRUE; + /* Decrease all stats (permanently) */ + (void)dec_stat(A_STR, 50, TRUE); + (void)dec_stat(A_INT, 50, TRUE); + (void)dec_stat(A_WIS, 50, TRUE); + (void)dec_stat(A_DEX, 50, TRUE); + (void)dec_stat(A_CON, 50, TRUE); + (void)dec_stat(A_CHR, 50, TRUE); - if (one_in_(6)) + /* Lose some experience (permanently) */ + p_ptr->exp -= (p_ptr->exp / 4); + p_ptr->max_exp -= (p_ptr->exp / 4); + check_experience(); + + break; + } + + case 3: { - for (dummy = 1; dummy < 10; dummy++) - { - if (dummy - 5) - { - if (line_chaos) - fire_beam(Chaos_type, dummy, 150); - else - fire_ball(Chaos_type, dummy, 150, 2); - } - } + msg_print(_("あなたは強力なオーラに包み込まれた。", "You are surrounded by a powerful aura.")); + + /* Dispel monsters */ + dispel_monsters(1000); + + break; } - else if (one_in_(3)) + + case 4: + case 5: + case 6: { - fire_ball(Chaos_type, 0, 500, 8); + /* Mana Ball */ + fire_ball(GF_MANA, dir, 600, 3); + + break; } - else + + case 7: + case 8: + case 9: + case 10: { - if (!get_aim_dir(&dir)) return; - if (line_chaos) - fire_beam(Chaos_type, dir, 250); - else - fire_ball(Chaos_type, dir, 250, 3 + (plev / 35)); + /* Mana Bolt */ + fire_bolt(GF_MANA, dir, 500); + + break; + } } } /*! - * @brief TY_CURSE処理発動 / Activate the evil Topi Ylinen curse - * @param stop_ty 再帰処理停止フラグ - * @param count 発動回数 - * @return 作用が実際にあった場合TRUEを返す - * @details - *
- * rr9: Stop the nasty things when a Cyberdemon is summoned
- * or the player gets paralyzed.
- * 
- */ -bool activate_ty_curse(bool stop_ty, int *count) +* @brief 運命の輪、並びにカオス的な効果の発動 +* @param spell ランダムな効果を選択するための基準ID +* @return なし +*/ +void wild_magic(int spell) { - int i = 0; + int counter = 0; + int type = SUMMON_MOLD + randint0(6); - int flg = (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP); + if (type < SUMMON_MOLD) type = SUMMON_MOLD; + else if (type > SUMMON_MIMIC) type = SUMMON_MIMIC; - do + switch (randint1(spell) + randint1(8) + 1) { - switch (randint1(34)) + case 1: + case 2: + case 3: + teleport_player(10, TELEPORT_PASSIVE); + break; + case 4: + case 5: + case 6: + teleport_player(100, TELEPORT_PASSIVE); + break; + case 7: + case 8: + teleport_player(200, TELEPORT_PASSIVE); + break; + case 9: + case 10: + case 11: + unlite_area(10, 3); + break; + case 12: + case 13: + case 14: + lite_area(damroll(2, 3), 2); + break; + case 15: + destroy_doors_touch(); + break; + case 16: case 17: + wall_breaker(); + case 18: + sleep_monsters_touch(); + break; + case 19: + case 20: + trap_creation(p_ptr->y, p_ptr->x); + break; + case 21: + case 22: + door_creation(); + break; + case 23: + case 24: + case 25: + aggravate_monsters(0); + break; + case 26: + earthquake(p_ptr->y, p_ptr->x, 5); + break; + case 27: + case 28: + (void)gain_random_mutation(0); + break; + case 29: + case 30: + apply_disenchant(1); + break; + case 31: + lose_all_info(); + break; + case 32: + fire_ball(GF_CHAOS, 0, spell + 5, 1 + (spell / 10)); + break; + case 33: + wall_stone(); + break; + case 34: + case 35: + while (counter++ < 8) { - case 28: case 29: - if (!(*count)) - { - msg_print(_("地面が揺れた...", "The ground trembles...")); - earthquake(p_ptr->y, p_ptr->x, 5 + randint0(10)); - if (!one_in_(6)) break; - } - case 30: case 31: - if (!(*count)) - { - int dam = damroll(10, 10); - msg_print(_("純粋な魔力の次元への扉が開いた!", "A portal opens to a plane of raw mana!")); - project(0, 8, p_ptr->y, p_ptr->x, dam, GF_MANA, flg, -1); - take_hit(DAMAGE_NOESCAPE, dam, _("純粋な魔力の解放", "released pure mana"), -1); - if (!one_in_(6)) break; - } - case 32: case 33: - if (!(*count)) - { - msg_print(_("周囲の空間が歪んだ!", "Space warps about you!")); - teleport_player(damroll(10, 10), TELEPORT_PASSIVE); - if (randint0(13)) (*count) += activate_hi_summon(p_ptr->y, p_ptr->x, FALSE); - if (!one_in_(6)) break; - } - case 34: - msg_print(_("エネルギーのうねりを感じた!", "You feel a surge of energy!")); - wall_breaker(); - if (!randint0(7)) - { - project(0, 7, p_ptr->y, p_ptr->x, 50, GF_KILL_WALL, flg, -1); - take_hit(DAMAGE_NOESCAPE, 50, _("エネルギーのうねり", "surge of energy"), -1); - } - if (!one_in_(6)) break; - case 1: case 2: case 3: case 16: case 17: - aggravate_monsters(0); - if (!one_in_(6)) break; - case 4: case 5: case 6: - (*count) += activate_hi_summon(p_ptr->y, p_ptr->x, FALSE); - if (!one_in_(6)) break; - case 7: case 8: case 9: case 18: - (*count) += summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)); - if (!one_in_(6)) break; - case 10: case 11: case 12: - msg_print(_("経験値が体から吸い取られた気がする!", "You feel your experience draining away...")); - lose_exp(p_ptr->exp / 16); - if (!one_in_(6)) break; - case 13: case 14: case 15: case 19: case 20: - if (stop_ty || (p_ptr->free_act && (randint1(125) < p_ptr->skill_sav)) || (p_ptr->pclass == CLASS_BERSERKER)) - { - /* Do nothing */ ; - } - else - { - msg_print(_("彫像になった気分だ!", "You feel like a statue!")); - if (p_ptr->free_act) - set_paralyzed(p_ptr->paralyzed + randint1(3)); - else - set_paralyzed(p_ptr->paralyzed + randint1(13)); - stop_ty = TRUE; - } - if (!one_in_(6)) break; - case 21: case 22: case 23: - (void)do_dec_stat(randint0(6)); - if (!one_in_(6)) break; - case 24: - msg_print(_("ほえ?私は誰?ここで何してる?", "Huh? Who am I? What am I doing here?")); - lose_all_info(); - if (!one_in_(6)) break; - case 25: - /* - * Only summon Cyberdemons deep in the dungeon. - */ - if ((dun_level > 65) && !stop_ty) - { - (*count) += summon_cyber(-1, p_ptr->y, p_ptr->x); - stop_ty = TRUE; - break; - } - if (!one_in_(6)) break; - default: - while (i < 6) - { - do - { - (void)do_dec_stat(i); - } - while (one_in_(2)); - - i++; - } + (void)summon_specific(0, p_ptr->y, p_ptr->x, (dun_level * 3) / 2, type, (PM_ALLOW_GROUP | PM_NO_PET)); } + break; + case 36: + case 37: + activate_hi_summon(p_ptr->y, p_ptr->x, FALSE); + break; + case 38: + (void)summon_cyber(-1, p_ptr->y, p_ptr->x); + break; + default: + { + int count = 0; + (void)activate_ty_curse(FALSE, &count); + break; + } } - while (one_in_(3) && !stop_ty); - return stop_ty; + return; } /*! - * @brief HI_SUMMON(上級召喚)処理発動 - * @param y 召喚位置Y座標 - * @param x 召喚位置X座標 - * @param can_pet プレイヤーのペットとなる可能性があるならばTRUEにする - * @return 作用が実際にあった場合TRUEを返す - */ -int activate_hi_summon(int y, int x, bool can_pet) +* @brief カオス魔法「流星群」の処理としてプレイヤーを中心に隕石落下処理を10+1d10回繰り返す。 +* / Drop 10+1d10 meteor ball at random places near the player +* @param dam ダメージ +* @param rad 効力の半径 +* @return なし +*/ +void cast_meteor(HIT_POINT dam, POSITION rad) { int i; - int count = 0; - int summon_lev; - u32b mode = PM_ALLOW_GROUP; - bool pet = FALSE; + int b = 10 + randint1(10); - if (can_pet) + for (i = 0; i < b; i++) { - if (one_in_(4)) - { - mode |= PM_FORCE_FRIENDLY; - } - else + POSITION y = 0, x = 0; + int count; + + for (count = 0; count <= 20; count++) { - mode |= PM_FORCE_PET; - pet = TRUE; - } - } + int dy, dx, d; - if (!pet) mode |= PM_NO_PET; + x = p_ptr->x - 8 + randint0(17); + y = p_ptr->y - 8 + randint0(17); - summon_lev = (pet ? p_ptr->lev * 2 / 3 + randint1(p_ptr->lev / 2) : dun_level); + dx = (p_ptr->x > x) ? (p_ptr->x - x) : (x - p_ptr->x); + dy = (p_ptr->y > y) ? (p_ptr->y - y) : (y - p_ptr->y); - for (i = 0; i < (randint1(7) + (dun_level / 40)); i++) - { - switch (randint1(25) + (dun_level / 20)) - { - case 1: case 2: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_ANT, mode); - break; - case 3: case 4: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_SPIDER, mode); - break; - case 5: case 6: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HOUND, mode); - break; - case 7: case 8: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HYDRA, mode); - break; - case 9: case 10: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_ANGEL, mode); - break; - case 11: case 12: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_UNDEAD, mode); - break; - case 13: case 14: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_DRAGON, mode); - break; - case 15: case 16: - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_DEMON, mode); - break; - case 17: - if (can_pet) break; - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_AMBERITES, (mode | PM_ALLOW_UNIQUE)); - break; - case 18: case 19: - if (can_pet) break; - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_UNIQUE, (mode | PM_ALLOW_UNIQUE)); - break; - case 20: case 21: - if (!can_pet) mode |= PM_ALLOW_UNIQUE; - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HI_UNDEAD, mode); - break; - case 22: case 23: - if (!can_pet) mode |= PM_ALLOW_UNIQUE; - count += summon_specific((pet ? -1 : 0), y, x, summon_lev, SUMMON_HI_DRAGON, mode); - break; - case 24: - count += summon_specific((pet ? -1 : 0), y, x, 100, SUMMON_CYBER, mode); - break; - default: - if (!can_pet) mode |= PM_ALLOW_UNIQUE; - count += summon_specific((pet ? -1 : 0), y, x,pet ? summon_lev : (((summon_lev * 3) / 2) + 5), 0, mode); + /* Approximate distance */ + d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1)); + + if (d >= 9) continue; + + if (!in_bounds(y, x) || !projectable(p_ptr->y, p_ptr->x, y, x) + || !cave_have_flag_bold(y, x, FF_PROJECT)) continue; + + /* Valid position */ + break; } - } - return count; + if (count > 20) continue; + + project(0, rad, y, x, dam, GF_METEOR, PROJECT_KILL | PROJECT_JUMP | PROJECT_ITEM, -1); + } } /*! - * @brief サイバーデーモンの召喚 - * @param who 召喚主のモンスターID(0ならばプレイヤー) - * @param y 召喚位置Y座標 - * @param x 召喚位置X座標 - * @return 作用が実際にあった場合TRUEを返す - */ -int summon_cyber(int who, int y, int x) +* @brief 破邪魔法「神の怒り」の処理としてターゲットを指定した後分解のボールを最大20回発生させる。 +* @param dam ダメージ +* @param rad 効力の半径 +* @return ターゲットを指定し、実行したならばTRUEを返す。 +*/ +bool cast_wrath_of_the_god(HIT_POINT dam, POSITION rad) { + POSITION x, y, tx, ty; + POSITION nx, ny; + DIRECTION dir; int i; - int max_cyber = (easy_band ? 1 : (dun_level / 50) + randint1(2)); - int count = 0; - u32b mode = PM_ALLOW_GROUP; + int b = 10 + randint1(10); - /* Summoned by a monster */ - if (who > 0) + if (!get_aim_dir(&dir)) return FALSE; + + /* Use the given direction */ + tx = p_ptr->x + 99 * ddx[dir]; + ty = p_ptr->y + 99 * ddy[dir]; + + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) { - monster_type *m_ptr = &m_list[who]; - if (is_pet(m_ptr)) mode |= PM_FORCE_PET; + tx = target_col; + ty = target_row; } - if (max_cyber > 4) max_cyber = 4; + x = p_ptr->x; + y = p_ptr->y; - for (i = 0; i < max_cyber; i++) + while (1) { - count += summon_specific(who, y, x, 100, SUMMON_CYBER, mode); + /* Hack -- Stop at the target */ + if ((y == ty) && (x == tx)) break; + + ny = y; + nx = x; + mmove2(&ny, &nx, p_ptr->y, p_ptr->x, ty, tx); + + /* Stop at maximum range */ + if (MAX_RANGE <= distance(p_ptr->y, p_ptr->x, ny, nx)) break; + + /* Stopped by walls/doors */ + if (!cave_have_flag_bold(ny, nx, FF_PROJECT)) break; + + /* Stopped by monsters */ + if ((dir != 5) && cave[ny][nx].m_idx != 0) break; + + /* Save the new location */ + x = nx; + y = ny; } + tx = x; + ty = y; - return count; + for (i = 0; i < b; i++) + { + int count = 20, d = 0; + + while (count--) + { + int dx, dy; + + x = tx - 5 + randint0(11); + y = ty - 5 + randint0(11); + + dx = (tx > x) ? (tx - x) : (x - tx); + dy = (ty > y) ? (ty - y) : (y - ty); + + /* Approximate distance */ + d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1)); + /* Within the radius */ + if (d < 5) break; + } + + if (count < 0) continue; + + /* Cannot penetrate perm walls */ + if (!in_bounds(y, x) || + cave_stop_disintegration(y, x) || + !in_disintegration_range(ty, tx, y, x)) + continue; + + project(0, rad, y, x, dam, GF_DISINTEGRATE, PROJECT_JUMP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL, -1); + } + + return TRUE; } /*! - * @brief 周辺破壊効果(プレイヤー中心) - * @return 作用が実際にあった場合TRUEを返す - */ -void wall_breaker(void) +* @brief 「ワンダー」のランダムな効果を決定して処理する。 +* @param dir 方向ID +* @return なし +* @details +* This spell should become more useful (more controlled) as the\n +* player gains experience levels. Thus, add 1/5 of the player's\n +* level to the die roll. This eliminates the worst effects later on,\n +* while keeping the results quite random. It also allows some potent\n +* effects only at high level. +*/ +void cast_wonder(DIRECTION dir) { - int i; - POSITION y = 0, x = 0; - int attempts = 1000; + PLAYER_LEVEL plev = p_ptr->lev; + int die = randint1(100) + plev / 5; + int vir = virtue_number(V_CHANCE); - if (randint1(80 + p_ptr->lev) < 70) + if (vir) { - while (attempts--) + if (p_ptr->virtues[vir - 1] > 0) { - scatter(&y, &x, p_ptr->y, p_ptr->x, 4, 0); + while (randint1(400) < p_ptr->virtues[vir - 1]) die++; + } + else + { + while (randint1(400) < (0 - p_ptr->virtues[vir - 1])) die--; + } + } - if (!cave_have_flag_bold(y, x, FF_PROJECT)) continue; + if (die < 26) + chg_virtue(V_CHANCE, 1); - if (!player_bold(y, x)) break; + if (die > 100) + { + msg_print(_("あなたは力がみなぎるのを感じた!", "You feel a surge of power!")); + } + + if (die < 8) clone_monster(dir); + else if (die < 14) speed_monster(dir, plev); + else if (die < 26) heal_monster(dir, damroll(4, 6)); + else if (die < 31) poly_monster(dir, plev); + else if (die < 36) + fire_bolt_or_beam(beam_chance() - 10, GF_MISSILE, dir, + damroll(3 + ((plev - 1) / 5), 4)); + else if (die < 41) confuse_monster(dir, plev); + else if (die < 46) fire_ball(GF_POIS, dir, 20 + (plev / 2), 3); + else if (die < 51) (void)lite_line(dir, damroll(6, 8)); + else if (die < 56) + fire_bolt_or_beam(beam_chance() - 10, GF_ELEC, dir, + damroll(3 + ((plev - 5) / 4), 8)); + else if (die < 61) + fire_bolt_or_beam(beam_chance() - 10, GF_COLD, dir, + damroll(5 + ((plev - 5) / 4), 8)); + else if (die < 66) + fire_bolt_or_beam(beam_chance(), GF_ACID, dir, + damroll(6 + ((plev - 5) / 4), 8)); + else if (die < 71) + fire_bolt_or_beam(beam_chance(), GF_FIRE, dir, + damroll(8 + ((plev - 5) / 4), 8)); + else if (die < 76) hypodynamic_bolt(dir, 75); + else if (die < 81) fire_ball(GF_ELEC, dir, 30 + plev / 2, 2); + else if (die < 86) fire_ball(GF_ACID, dir, 40 + plev, 2); + else if (die < 91) fire_ball(GF_ICE, dir, 70 + plev, 3); + else if (die < 96) fire_ball(GF_FIRE, dir, 80 + plev, 3); + else if (die < 101) hypodynamic_bolt(dir, 100 + plev); + else if (die < 104) + { + earthquake(p_ptr->y, p_ptr->x, 12); + } + else if (die < 106) + { + (void)destroy_area(p_ptr->y, p_ptr->x, 13 + randint0(5), FALSE); + } + else if (die < 108) + { + symbol_genocide(plev + 50, TRUE); + } + else if (die < 110) dispel_monsters(120); + else /* RARE */ + { + dispel_monsters(150); + slow_monsters(plev); + sleep_monsters(plev); + hp_player(300); + } +} + + +/*! +* @brief 「悪霊召喚」のランダムな効果を決定して処理する。 +* @param dir 方向ID +* @return なし +*/ +void cast_invoke_spirits(DIRECTION dir) +{ + PLAYER_LEVEL plev = p_ptr->lev; + int die = randint1(100) + plev / 5; + int vir = virtue_number(V_CHANCE); + + if (vir) + { + if (p_ptr->virtues[vir - 1] > 0) + { + while (randint1(400) < p_ptr->virtues[vir - 1]) die++; } + else + { + while (randint1(400) < (0 - p_ptr->virtues[vir - 1])) die--; + } + } - project(0, 0, y, x, 20 + randint1(30), GF_KILL_WALL, - (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL), -1); + msg_print(_("あなたは死者たちの力を招集した...", "You call on the power of the dead...")); + if (die < 26) + chg_virtue(V_CHANCE, 1); + + if (die > 100) + { + msg_print(_("あなたはおどろおどろしい力のうねりを感じた!", "You feel a surge of eldritch force!")); } - else if (randint1(100) > 30) + + if (die < 8) { - earthquake(p_ptr->y, p_ptr->x, 1); + msg_print(_("なんてこった!あなたの周りの地面から朽ちた人影が立ち上がってきた!", + "Oh no! Mouldering forms rise from the earth around you!")); + + (void)summon_specific(0, p_ptr->y, p_ptr->x, dun_level, SUMMON_UNDEAD, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)); + chg_virtue(V_UNLIFE, 1); } - else + else if (die < 14) { - int num = damroll(5, 3); + msg_print(_("名状し難い邪悪な存在があなたの心を通り過ぎて行った...", "An unnamable evil brushes against your mind...")); - for (i = 0; i < num; i++) - { - while (1) - { - scatter(&y, &x, p_ptr->y, p_ptr->x, 10, 0); + set_afraid(p_ptr->afraid + randint1(4) + 4); + } + else if (die < 26) + { + msg_print(_("あなたの頭に大量の幽霊たちの騒々しい声が押し寄せてきた...", + "Your head is invaded by a horde of gibbering spectral voices...")); - if (!player_bold(y, x)) break; - } + set_confused(p_ptr->confused + randint1(4) + 4); + } + else if (die < 31) + { + poly_monster(dir, plev); + } + else if (die < 36) + { + fire_bolt_or_beam(beam_chance() - 10, GF_MISSILE, dir, + damroll(3 + ((plev - 1) / 5), 4)); + } + else if (die < 41) + { + confuse_monster(dir, plev); + } + else if (die < 46) + { + fire_ball(GF_POIS, dir, 20 + (plev / 2), 3); + } + else if (die < 51) + { + (void)lite_line(dir, damroll(6, 8)); + } + else if (die < 56) + { + fire_bolt_or_beam(beam_chance() - 10, GF_ELEC, dir, + damroll(3 + ((plev - 5) / 4), 8)); + } + else if (die < 61) + { + fire_bolt_or_beam(beam_chance() - 10, GF_COLD, dir, + damroll(5 + ((plev - 5) / 4), 8)); + } + else if (die < 66) + { + fire_bolt_or_beam(beam_chance(), GF_ACID, dir, + damroll(6 + ((plev - 5) / 4), 8)); + } + else if (die < 71) + { + fire_bolt_or_beam(beam_chance(), GF_FIRE, dir, + damroll(8 + ((plev - 5) / 4), 8)); + } + else if (die < 76) + { + hypodynamic_bolt(dir, 75); + } + else if (die < 81) + { + fire_ball(GF_ELEC, dir, 30 + plev / 2, 2); + } + else if (die < 86) + { + fire_ball(GF_ACID, dir, 40 + plev, 2); + } + else if (die < 91) + { + fire_ball(GF_ICE, dir, 70 + plev, 3); + } + else if (die < 96) + { + fire_ball(GF_FIRE, dir, 80 + plev, 3); + } + else if (die < 101) + { + hypodynamic_bolt(dir, 100 + plev); + } + else if (die < 104) + { + earthquake(p_ptr->y, p_ptr->x, 12); + } + else if (die < 106) + { + (void)destroy_area(p_ptr->y, p_ptr->x, 13 + randint0(5), FALSE); + } + else if (die < 108) + { + symbol_genocide(plev + 50, TRUE); + } + else if (die < 110) + { + dispel_monsters(120); + } + else + { /* RARE */ + dispel_monsters(150); + slow_monsters(plev); + sleep_monsters(plev); + hp_player(300); + } - project(0, 0, y, x, 20 + randint1(30), GF_KILL_WALL, - (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL), -1); - } + if (die < 31) + { + msg_print(_("陰欝な声がクスクス笑う。「もうすぐおまえは我々の仲間になるだろう。弱き者よ。」", + "Sepulchral voices chuckle. 'Soon you will join us, mortal.'")); } } - /*! - * @brief パニック・モンスター効果(プレイヤー視界範囲内) / Confuse monsters - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool confuse_monsters(int dam) +* @brief トランプ領域の「シャッフル」の効果をランダムに決めて処理する。 +* @return なし +*/ +void cast_shuffle(void) { - return (project_hack(GF_OLD_CONF, dam)); -} - + PLAYER_LEVEL plev = p_ptr->lev; + DIRECTION dir; + int die; + int vir = virtue_number(V_CHANCE); + int i; -/*! - * @brief チャーム・モンスター効果(プレイヤー視界範囲内) / Charm monsters - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool charm_monsters(int dam) -{ - return (project_hack(GF_CHARM, dam)); -} + /* Card sharks and high mages get a level bonus */ + if ((p_ptr->pclass == CLASS_ROGUE) || + (p_ptr->pclass == CLASS_HIGH_MAGE) || + (p_ptr->pclass == CLASS_SORCERER)) + die = (randint1(110)) + plev / 5; + else + die = randint1(120); -/*! - * @brief 動物魅了効果(プレイヤー視界範囲内) / Charm Animals - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool charm_animals(int dam) -{ - return (project_hack(GF_CONTROL_ANIMAL, dam)); -} + if (vir) + { + if (p_ptr->virtues[vir - 1] > 0) + { + while (randint1(400) < p_ptr->virtues[vir - 1]) die++; + } + else + { + while (randint1(400) < (0 - p_ptr->virtues[vir - 1])) die--; + } + } + msg_print(_("あなたはカードを切って一枚引いた...", "You shuffle the deck and draw a card...")); -/*! - * @brief モンスター朦朧効果(プレイヤー視界範囲内) / Stun monsters - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool stun_monsters(int dam) -{ - return (project_hack(GF_STUN, dam)); -} + if (die < 30) + chg_virtue(V_CHANCE, 1); + if (die < 7) + { + msg_print(_("なんてこった!《死》だ!", "Oh no! It's Death!")); -/*! - * @brief モンスター停止効果(プレイヤー視界範囲内) / Stasis monsters - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool stasis_monsters(int dam) -{ - return (project_hack(GF_STASIS, dam)); -} + for (i = 0; i < randint1(3); i++) + activate_hi_summon(p_ptr->y, p_ptr->x, FALSE); + } + else if (die < 14) + { + msg_print(_("なんてこった!《悪魔》だ!", "Oh no! It's the Devil!")); + summon_specific(0, p_ptr->y, p_ptr->x, dun_level, SUMMON_DEMON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)); + } + else if (die < 18) + { + int count = 0; + msg_print(_("なんてこった!《吊られた男》だ!", "Oh no! It's the Hanged Man.")); + activate_ty_curse(FALSE, &count); + } + else if (die < 22) + { + msg_print(_("《不調和の剣》だ。", "It's the swords of discord.")); + aggravate_monsters(0); + } + else if (die < 26) + { + msg_print(_("《愚者》だ。", "It's the Fool.")); + do_dec_stat(A_INT); + do_dec_stat(A_WIS); + } + else if (die < 30) + { + msg_print(_("奇妙なモンスターの絵だ。", "It's the picture of a strange monster.")); + trump_summoning(1, FALSE, p_ptr->y, p_ptr->x, (dun_level * 3 / 2), (32 + randint1(6)), PM_ALLOW_GROUP | PM_ALLOW_UNIQUE); + } + else if (die < 33) + { + msg_print(_("《月》だ。", "It's the Moon.")); + unlite_area(10, 3); + } + else if (die < 38) + { + msg_print(_("《運命の輪》だ。", "It's the Wheel of Fortune.")); + wild_magic(randint0(32)); + } + else if (die < 40) + { + msg_print(_("テレポート・カードだ。", "It's a teleport trump card.")); + teleport_player(10, TELEPORT_PASSIVE); + } + else if (die < 42) + { + msg_print(_("《正義》だ。", "It's Justice.")); + set_blessed(p_ptr->lev, FALSE); + } + else if (die < 47) + { + msg_print(_("テレポート・カードだ。", "It's a teleport trump card.")); + teleport_player(100, TELEPORT_PASSIVE); + } + else if (die < 52) + { + msg_print(_("テレポート・カードだ。", "It's a teleport trump card.")); + teleport_player(200, TELEPORT_PASSIVE); + } + else if (die < 60) + { + msg_print(_("《塔》だ。", "It's the Tower.")); + wall_breaker(); + } + else if (die < 72) + { + msg_print(_("《節制》だ。", "It's Temperance.")); + sleep_monsters_touch(); + } + else if (die < 80) + { + msg_print(_("《塔》だ。", "It's the Tower.")); + earthquake(p_ptr->y, p_ptr->x, 5); + } + else if (die < 82) + { + msg_print(_("友好的なモンスターの絵だ。", "It's the picture of a friendly monster.")); + trump_summoning(1, TRUE, p_ptr->y, p_ptr->x, (dun_level * 3 / 2), SUMMON_MOLD, 0L); + } + else if (die < 84) + { + msg_print(_("友好的なモンスターの絵だ。", "It's the picture of a friendly monster.")); + trump_summoning(1, TRUE, p_ptr->y, p_ptr->x, (dun_level * 3 / 2), SUMMON_BAT, 0L); + } + else if (die < 86) + { + msg_print(_("友好的なモンスターの絵だ。", "It's the picture of a friendly monster.")); + trump_summoning(1, TRUE, p_ptr->y, p_ptr->x, (dun_level * 3 / 2), SUMMON_VORTEX, 0L); + } + else if (die < 88) + { + msg_print(_("友好的なモンスターの絵だ。", "It's the picture of a friendly monster.")); + trump_summoning(1, TRUE, p_ptr->y, p_ptr->x, (dun_level * 3 / 2), SUMMON_COIN_MIMIC, 0L); + } + else if (die < 96) + { + msg_print(_("《恋人》だ。", "It's the Lovers.")); -/*! - * @brief モンスター精神攻撃効果(プレイヤー視界範囲内) / Mindblast monsters - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool mindblast_monsters(int dam) -{ - return (project_hack(GF_PSI, dam)); + if (get_aim_dir(&dir)) + charm_monster(dir, MIN(p_ptr->lev, 20)); + } + else if (die < 101) + { + msg_print(_("《隠者》だ。", "It's the Hermit.")); + wall_stone(); + } + else if (die < 111) + { + msg_print(_("《審判》だ。", "It's the Judgement.")); + do_cmd_rerate(FALSE); + lose_all_mutations(); + } + else if (die < 120) + { + msg_print(_("《太陽》だ。", "It's the Sun.")); + chg_virtue(V_KNOWLEDGE, 1); + chg_virtue(V_ENLIGHTEN, 1); + wiz_lite(FALSE); + } + else + { + msg_print(_("《世界》だ。", "It's the World.")); + if (p_ptr->exp < PY_MAX_EXP) + { + s32b ee = (p_ptr->exp / 25) + 1; + if (ee > 5000) ee = 5000; + msg_print(_("更に経験を積んだような気がする。", "You feel more experienced.")); + gain_exp(ee); + } + } } - -/*! - * @brief モンスター追放効果(プレイヤー視界範囲内) / Banish all monsters - * @param dist 効力(距離) - * @return 作用が実際にあった場合TRUEを返す - */ -bool banish_monsters(int dist) +bool_hack life_stream(bool_hack message, bool_hack virtue) { - return (project_hack(GF_AWAY_ALL, dist)); -} + if(virtue) + { + chg_virtue(V_VITALITY, 1); + chg_virtue(V_UNLIFE, -5); + } + if(message) + { + msg_print(_("体中に生命力が満ちあふれてきた!", "You feel life flow through your body!")); + } + restore_level(); + (void)set_poisoned(0); + (void)set_blind(0); + (void)set_confused(0); + (void)set_image(0); + (void)set_stun(0); + (void)set_cut(0); + (void)restore_all_status(); + (void)set_shero(0, TRUE); + handle_stuff(); + hp_player(5000); + return TRUE; +} -/*! - * @brief 邪悪退散効果(プレイヤー視界範囲内) / Turn evil - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool turn_evil(int dam) +bool_hack heroism(int base) { - return (project_hack(GF_TURN_EVIL, dam)); + bool_hack ident = FALSE; + if(set_afraid(0)) ident = TRUE; + if(set_hero(p_ptr->hero + randint1(base) + base, FALSE)) ident = TRUE; + if(hp_player(10)) ident = TRUE; + return ident; } - -/*! - * @brief 全モンスター退散効果(プレイヤー視界範囲内) / Turn everyone - * @param dam 効力 - * @return 作用が実際にあった場合TRUEを返す - */ -bool turn_monsters(int dam) +bool_hack berserk(int base) { - return (project_hack(GF_TURN_ALL, dam)); + bool_hack ident = FALSE; + if (set_afraid(0)) ident = TRUE; + if (set_shero(p_ptr->hero + randint1(base) + base, FALSE)) ident = TRUE; + if (hp_player(30)) ident = TRUE; + return ident; } - -/*! - * @brief 死の光線(プレイヤー視界範囲内) / Death-ray all monsters (note: OBSCENELY powerful) - * @return 作用が実際にあった場合TRUEを返す - */ -bool deathray_monsters(void) +bool_hack cure_light_wounds(DICE_NUMBER dice, DICE_SID sides) { - return (project_hack(GF_DEATH_RAY, p_ptr->lev * 200)); + bool_hack ident = FALSE; + if (hp_player(damroll(dice, sides))) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_cut(p_ptr->cut - 10)) ident = TRUE; + if (set_shero(0, TRUE)) ident = TRUE; + return ident; } -/*! - * @brief チャーム・モンスター(1体) - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev パワー - * @return 作用が実際にあった場合TRUEを返す - */ -bool charm_monster(int dir, int plev) +bool_hack cure_serious_wounds(DICE_NUMBER dice, DICE_SID sides) { - int flg = PROJECT_STOP | PROJECT_KILL; - return (project_hook(GF_CHARM, dir, plev, flg)); + bool_hack ident = FALSE; + if (hp_player(damroll(dice, sides))) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_cut((p_ptr->cut / 2) - 50)) ident = TRUE; + if (set_shero(0, TRUE)) ident = TRUE; + return ident; } -/*! - * @brief アンデッド支配(1体) - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev パワー - * @return 作用が実際にあった場合TRUEを返す - */ -bool control_one_undead(int dir, int plev) +bool_hack cure_critical_wounds(HIT_POINT pow) { - int flg = PROJECT_STOP | PROJECT_KILL; - return (project_hook(GF_CONTROL_UNDEAD, dir, plev, flg)); + bool_hack ident = FALSE; + if (hp_player(pow)) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + if (set_shero(0, TRUE)) ident = TRUE; + return ident; } -/*! - * @brief 悪魔支配(1体) - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev パワー - * @return 作用が実際にあった場合TRUEを返す - */ -bool control_one_demon(int dir, int plev) +bool_hack true_healing(HIT_POINT pow) { - int flg = PROJECT_STOP | PROJECT_KILL; - return (project_hook(GF_CONTROL_DEMON, dir, plev, flg)); + bool_hack ident = FALSE; + if (hp_player(pow)) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + if (set_image(0)) ident = TRUE; + return ident; } -/*! - * @brief 動物支配(1体) - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev パワー - * @return 作用が実際にあった場合TRUEを返す - */ -bool charm_animal(int dir, int plev) +bool_hack restore_mana(bool_hack magic_eater) { - int flg = PROJECT_STOP | PROJECT_KILL; - return (project_hook(GF_CONTROL_ANIMAL, dir, plev, flg)); + bool_hack ident = FALSE; + + if (p_ptr->pclass == CLASS_MAGIC_EATER && magic_eater) + { + int i; + for (i = 0; i < EATER_EXT * 2; i++) + { + p_ptr->magic_num1[i] += (p_ptr->magic_num2[i] < 10) ? EATER_CHARGE * 3 : p_ptr->magic_num2[i] * EATER_CHARGE / 3; + if (p_ptr->magic_num1[i] > p_ptr->magic_num2[i] * EATER_CHARGE) p_ptr->magic_num1[i] = p_ptr->magic_num2[i] * EATER_CHARGE; + } + for (; i < EATER_EXT * 3; i++) + { + KIND_OBJECT_IDX k_idx = lookup_kind(TV_ROD, i - EATER_EXT * 2); + p_ptr->magic_num1[i] -= ((p_ptr->magic_num2[i] < 10) ? EATER_ROD_CHARGE * 3 : p_ptr->magic_num2[i] * EATER_ROD_CHARGE / 3)*k_info[k_idx].pval; + if (p_ptr->magic_num1[i] < 0) p_ptr->magic_num1[i] = 0; + } + msg_print(_("頭がハッキリとした。", "You feel your head clear.")); + p_ptr->window |= (PW_PLAYER); + ident = TRUE; + } + else if (p_ptr->csp < p_ptr->msp) + { + p_ptr->csp = p_ptr->msp; + p_ptr->csp_frac = 0; + msg_print(_("頭がハッキリとした。", "You feel your head clear.")); + p_ptr->redraw |= (PR_MANA); + p_ptr->window |= (PW_PLAYER); + p_ptr->window |= (PW_SPELL); + ident = TRUE; + } + + return ident; } -/*! - * @brief 生物支配(1体) - * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) - * @param plev パワー - * @return 作用が実際にあった場合TRUEを返す - */ -bool charm_living(int dir, int plev) +bool restore_all_status(void) { - int flg = PROJECT_STOP | PROJECT_KILL; - return (project_hook(GF_CONTROL_LIVING, dir, plev, flg)); + bool ident = FALSE; + if (do_res_stat(A_STR)) ident = TRUE; + if (do_res_stat(A_INT)) ident = TRUE; + if (do_res_stat(A_WIS)) ident = TRUE; + if (do_res_stat(A_DEX)) ident = TRUE; + if (do_res_stat(A_CON)) ident = TRUE; + if (do_res_stat(A_CHR)) ident = TRUE; + return ident; } /*! - * @brief 変わり身処理 - * @param success 判定成功上の処理ならばTRUE - * @return 作用が実際にあった場合TRUEを返す + * @brief 口を使う継続的な処理を中断する + * @return なし */ -bool kawarimi(bool success) +void stop_mouth(void) { - object_type forge; - object_type *q_ptr = &forge; - int y, x; + if (music_singing_any()) stop_singing(); + if (hex_spelling_any()) stop_hex_spell_all(); +} - if (p_ptr->is_dead) return FALSE; - if (p_ptr->confused || p_ptr->blind || p_ptr->paralyzed || p_ptr->image) return FALSE; - if (randint0(200) < p_ptr->stun) return FALSE; - if (!success && one_in_(3)) +bool_hack vampirism(void) +{ + DIRECTION dir; + POSITION x, y; + int dummy; + cave_type *c_ptr; + + if (d_info[dungeon_type].flags1 & DF1_NO_MELEE) { - msg_print(_("失敗!逃げられなかった。", "Failed! You couldn't run away.")); - p_ptr->special_defense &= ~(NINJA_KAWARIMI); - p_ptr->redraw |= (PR_STATUS); + msg_print(_("なぜか攻撃することができない。", "Something prevent you from attacking.")); return FALSE; } - y = p_ptr->y; - x = p_ptr->x; - - teleport_player(10 + randint1(90), 0L); - - object_wipe(q_ptr); + /* Only works on adjacent monsters */ + if (!get_direction(&dir, FALSE, FALSE)) return FALSE; + y = p_ptr->y + ddy[dir]; + x = p_ptr->x + ddx[dir]; + c_ptr = &cave[y][x]; - object_prep(q_ptr, lookup_kind(TV_STATUE, SV_WOODEN_STATUE)); + stop_mouth(); - q_ptr->pval = MON_NINJA; + if (!(c_ptr->m_idx)) + { + msg_print(_("何もない場所に噛みついた!", "You bite into thin air!")); + return FALSE; + } - /* Drop it in the dungeon */ - (void)drop_near(q_ptr, -1, y, x); + msg_print(_("あなたはニヤリとして牙をむいた...", "You grin and bare your fangs...")); -#ifdef JP - if (success) msg_print("攻撃を受ける前に素早く身をひるがえした。"); - else msg_print("失敗!攻撃を受けてしまった。"); -#else - if (success) msg_print("You have turned around just before the attack hit you."); - else msg_print("Failed! You are hit by the attack."); -#endif + dummy = p_ptr->lev * 2; - p_ptr->special_defense &= ~(NINJA_KAWARIMI); - p_ptr->redraw |= (PR_STATUS); + if (hypodynamic_bolt(dir, dummy)) + { + if (p_ptr->food < PY_FOOD_FULL) + /* No heal if we are "full" */ + (void)hp_player(dummy); + else + msg_print(_("あなたは空腹ではありません。", "You were not hungry.")); - /* Teleported */ + /* Gain nutritional sustenance: 150/hp drained */ + /* A Food ration gives 5000 food points (by contrast) */ + /* Don't ever get more than "Full" this way */ + /* But if we ARE Gorged, it won't cure us */ + dummy = p_ptr->food + MIN(5000, 100 * dummy); + if (p_ptr->food < PY_FOOD_MAX) /* Not gorged already */ + (void)set_food(dummy >= PY_FOOD_MAX ? PY_FOOD_MAX - 1 : dummy); + } + else + msg_print(_("げぇ!ひどい味だ。", "Yechh. That tastes foul.")); return TRUE; } - -/*! - * @brief 入身処理 / "Rush Attack" routine for Samurai or Ninja - * @param mdeath 目標モンスターが死亡したかを返す - * @return 作用が実際にあった場合TRUEを返す / Return value is for checking "done" - */ -bool rush_attack(bool *mdeath) +bool panic_hit(void) { - int dir; - int tx, ty; - int tm_idx = 0; - u16b path_g[32]; - int path_n, i; - bool tmp_mdeath = FALSE; - bool moved = FALSE; - - if (mdeath) *mdeath = FALSE; - - project_length = 5; - if (!get_aim_dir(&dir)) return FALSE; - - /* Use the given direction */ - tx = p_ptr->x + project_length * ddx[dir]; - ty = p_ptr->y + project_length * ddy[dir]; + DIRECTION dir; + POSITION x, y; - /* Hack -- Use an actual "target" */ - if ((dir == 5) && target_okay()) + if (!get_direction(&dir, FALSE, FALSE)) return FALSE; + y = p_ptr->y + ddy[dir]; + x = p_ptr->x + ddx[dir]; + if (cave[y][x].m_idx) { - tx = target_col; - ty = target_row; + py_attack(y, x, 0); + if (randint0(p_ptr->skill_dis) < 7) + msg_print(_("うまく逃げられなかった。", "You failed to run away.")); + else + teleport_player(30, 0L); + return TRUE; + } + else + { + msg_print(_("その方向にはモンスターはいません。", "You don't see any monster in this direction")); + msg_print(NULL); + return FALSE; } - if (in_bounds(ty, tx)) tm_idx = cave[ty][tx].m_idx; +} - path_n = project_path(path_g, project_length, p_ptr->y, p_ptr->x, ty, tx, PROJECT_STOP | PROJECT_KILL); - project_length = 0; +/*! +* @brief 超能力者のサイコメトリー処理/ Forcibly pseudo-identify an object in the inventory (or on the floor) +* @return なし +* @note +* currently this function allows pseudo-id of any object, +* including silly ones like potions & scrolls, which always +* get '{average}'. This should be changed, either to stop such +* items from being pseudo-id'd, or to allow psychometry to +* detect whether the unidentified potion/scroll/etc is +* good (Cure Light Wounds, Restore Strength, etc) or +* bad (Poison, Weakness etc) or 'useless' (Slime Mold Juice, etc). +*/ +bool psychometry(void) +{ + OBJECT_IDX item; + object_type *o_ptr; + char o_name[MAX_NLEN]; + byte feel; + cptr q, s; + bool okay = FALSE; - /* No need to move */ - if (!path_n) return TRUE; + item_tester_no_ryoute = TRUE; + q = _("どのアイテムを調べますか?", "Meditate on which item? "); + s = _("調べるアイテムがありません。", "You have nothing appropriate."); - /* Use ty and tx as to-move point */ - ty = p_ptr->y; - tx = p_ptr->x; + if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR))) return (FALSE); - /* Project along the path */ - for (i = 0; i < path_n; i++) + /* Get the item (in the pack) */ + if (item >= 0) { - monster_type *m_ptr; - - int ny = GRID_Y(path_g[i]); - int nx = GRID_X(path_g[i]); - - if (cave_empty_bold(ny, nx) && player_can_enter(cave[ny][nx].feat, 0)) - { - ty = ny; - tx = nx; - - /* Go to next grid */ - continue; - } + o_ptr = &inventory[item]; + } - if (!cave[ny][nx].m_idx) - { - if (tm_idx) - { - msg_print(_("失敗!", "Failed!")); - } - else - { - msg_print(_("ここには入身では入れない。", "You can't move to that place.")); - } + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } - /* Exit loop */ - break; - } + /* It is fully known, no information needed */ + if (object_is_known(o_ptr)) + { + msg_print(_("何も新しいことは判らなかった。", "You cannot find out anything more about that.")); + return TRUE; + } - /* Move player before updating the monster */ - if (!player_bold(ty, tx)) teleport_player_to(ty, tx, TELEPORT_NONMAGICAL); + /* Check for a feeling */ + feel = value_check_aux1(o_ptr); - /* Update the monster */ - update_mon(cave[ny][nx].m_idx, TRUE); + /* Get an object description */ + object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); - /* Found a monster */ - m_ptr = &m_list[cave[ny][nx].m_idx]; + /* Skip non-feelings */ + if (!feel) + { + msg_format(_("%sからは特に変わった事は感じとれなかった。", "You do not perceive anything unusual about the %s."), o_name); + return TRUE; + } - if (tm_idx != cave[ny][nx].m_idx) - { #ifdef JP - msg_format("%s%sが立ちふさがっている!", tm_idx ? "別の" : "", - m_ptr->ml ? "モンスター" : "何か"); + msg_format("%sは%sという感じがする...", + o_name, game_inscriptions[feel]); #else - msg_format("There is %s in the way!", m_ptr->ml ? (tm_idx ? "another monster" : "a monster") : "someone"); + msg_format("You feel that the %s %s %s...", + o_name, ((o_ptr->number == 1) ? "is" : "are"), + game_inscriptions[feel]); #endif - } - else if (!player_bold(ty, tx)) - { - /* Hold the monster name */ - char m_name[80]; - - /* Get the monster name (BEFORE polymorphing) */ - monster_desc(m_name, m_ptr, 0); - msg_format(_("素早く%sの懐に入り込んだ!", "You quickly jump in and attack %s!"), m_name); - } - if (!player_bold(ty, tx)) teleport_player_to(ty, tx, TELEPORT_NONMAGICAL); - moved = TRUE; - tmp_mdeath = py_attack(ny, nx, HISSATSU_NYUSIN); + /* We have "felt" it */ + o_ptr->ident |= (IDENT_SENSE); + + /* "Inscribe" it */ + o_ptr->feeling = feel; + + /* Player touches it */ + o_ptr->marked |= OM_TOUCHED; + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + /* Valid "tval" codes */ + switch (o_ptr->tval) + { + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + case TV_BOW: + case TV_DIGGING: + case TV_HAFTED: + case TV_POLEARM: + case TV_SWORD: + case TV_BOOTS: + case TV_GLOVES: + case TV_HELM: + case TV_CROWN: + case TV_SHIELD: + case TV_CLOAK: + case TV_SOFT_ARMOR: + case TV_HARD_ARMOR: + case TV_DRAG_ARMOR: + case TV_CARD: + case TV_RING: + case TV_AMULET: + case TV_LITE: + case TV_FIGURINE: + okay = TRUE; break; } - if (!moved && !player_bold(ty, tx)) teleport_player_to(ty, tx, TELEPORT_NONMAGICAL); - - if (mdeath) *mdeath = tmp_mdeath; - return TRUE; -} - - -/*! - * @brief 全鏡の消去 / Remove all mirrors in this floor - * @param explode 爆発処理を伴うならばTRUE - * @return なし - */ -void remove_all_mirrors(bool explode) -{ - int x, y; + /* Auto-inscription/destroy */ + autopick_alter_item(item, (bool)(okay && destroy_feeling)); - for (x = 0; x < cur_wid; x++) - { - for (y = 0; y < cur_hgt; y++) - { - if (is_mirror_grid(&cave[y][x])) - { - remove_mirror(y, x); - if (explode) - project(0, 2, y, x, p_ptr->lev / 2 + 5, GF_SHARDS, - (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI), -1); - } - } - } + /* Something happened */ + return (TRUE); }