OSDN Git Service

[Fix] 重力、分解のブレスの属性が「不明」になるバグを修正
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-attack / mspell-breath.cpp
1 #include "mspell/mspell-attack/mspell-breath.h"
2 #include "core/disturbance.h"
3 #include "effect/attribute-types.h"
4 #include "effect/effect-processor.h"
5 #include "main/sound-definitions-table.h"
6 #include "main/sound-of-music.h"
7 #include "mind/drs-types.h"
8 #include "monster-race/race-ability-flags.h"
9 #include "monster-race/race-indice-types.h"
10 #include "monster/monster-info.h"
11 #include "monster/monster-update.h"
12 #include "mspell/mspell-checker.h"
13 #include "mspell/mspell-damage-calculator.h"
14 #include "mspell/mspell-data.h"
15 #include "mspell/mspell-result.h"
16 #include "mspell/mspell-util.h"
17 #include "system/floor-type-definition.h"
18 #include "system/monster-type-definition.h"
19 #include "system/player-type-definition.h"
20 #include "view/display-messages.h"
21
22 /*!
23  * @brief ブレスを吐くときにモンスター固有のセリフを表示する
24  * @param r_idx モンスター種族番号
25  * @param GF_TYPE 魔法効果
26  * @return 表示したらTRUE、しなかったらFALSE
27  */
28 static bool spell_RF4_BREATH_special_message(MonsterRaceId r_idx, AttributeType GF_TYPE, concptr m_name)
29 {
30     if (r_idx == MonsterRaceId::JAIAN && GF_TYPE == AttributeType::SOUND) {
31         msg_format(_("%^s「ボォエ~~~~~~」", "%^s sings, 'Booooeeeeee'"), m_name);
32         return true;
33     }
34     if (r_idx == MonsterRaceId::BOTEI && GF_TYPE == AttributeType::SHARDS) {
35         msg_format(_("%^s「ボ帝ビルカッター!!!」", "%^s shouts, 'Boty-Build cutter!!!'"), m_name);
36         return true;
37     }
38     if (r_idx == MonsterRaceId::RAOU && (GF_TYPE == AttributeType::FORCE)) {
39         if (one_in_(2)) {
40             msg_format(_("%^s「北斗剛掌波!!」", "%^s says, 'Hokuto Goh-Sho-Ha!!'"), m_name);
41         } else {
42             msg_format(_("%^s「受けてみい!!天将奔烈!!!」", "%^s says, 'Tensho-Honretsu!!'"), m_name);
43         }
44         return true;
45     }
46     return false;
47 }
48
49 static void message_breath(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type, std::string_view type_s, AttributeType GF_TYPE)
50 {
51     auto *floor_ptr = player_ptr->current_floor_ptr;
52     auto *m_ptr = &floor_ptr->m_list[m_idx];
53     auto see_either = see_monster(player_ptr, m_idx) || see_monster(player_ptr, t_idx);
54     auto known = monster_near_player(floor_ptr, m_idx, t_idx);
55     auto mon_to_mon = (target_type == MONSTER_TO_MONSTER);
56     auto mon_to_player = (target_type == MONSTER_TO_PLAYER);
57     GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
58     monster_name(player_ptr, m_idx, m_name);
59     monster_name(player_ptr, t_idx, t_name);
60
61     if (!spell_RF4_BREATH_special_message(m_ptr->r_idx, GF_TYPE, m_name)) {
62         if (player_ptr->blind) {
63             if (mon_to_player || (mon_to_mon && known && see_either)) {
64                 msg_format(_("%^sが何かのブレスを吐いた。", "%^s breathes."), m_name);
65             }
66         } else {
67             if (mon_to_player) {
68                 msg_format(_("%^sが%^sのブレスを吐いた。", "%^s breathes %^s."), m_name, type_s.data());
69             } else if (mon_to_mon && known && see_either) {
70                 _(msg_format("%^sが%^sに%^sのブレスを吐いた。", m_name, t_name, type_s.data()), msg_format("%^s breathes %^s at %^s.", m_name, type_s.data(), t_name));
71             }
72         }
73     }
74
75     if (mon_to_mon && known && !see_either) {
76         floor_ptr->monster_noise = true;
77     }
78
79     if (known || see_either) {
80         sound(SOUND_BREATH);
81     }
82 }
83
84 static std::pair<MonsterAbilityType, MSpellData> make_breath_elemental(MonsterAbilityType ms_type, AttributeType GF_TYPE, std::string_view type_s)
85 {
86     return { ms_type, { [type_s, GF_TYPE](auto *player_ptr, auto m_idx, auto t_idx, int target_type) {
87                            message_breath(player_ptr, m_idx, t_idx, target_type, type_s, GF_TYPE);
88                            return false;
89                        },
90                           GF_TYPE } };
91 };
92
93 static std::pair<MonsterAbilityType, MSpellData> make_breath_elemental(MonsterAbilityType ms_type, AttributeType GF_TYPE, std::string_view type_s, MSpellDrsData drs)
94 {
95     return { ms_type, { [type_s, GF_TYPE](auto *player_ptr, auto m_idx, auto t_idx, int target_type) {
96                            message_breath(player_ptr, m_idx, t_idx, target_type, type_s, GF_TYPE);
97                            return false;
98                        },
99                           GF_TYPE, drs } };
100 };
101
102 const std::unordered_map<MonsterAbilityType, MSpellData> breath_list = {
103     make_breath_elemental(MonsterAbilityType::BR_ACID, AttributeType::ACID, _("酸", "acid"), DRS_ACID),
104     make_breath_elemental(MonsterAbilityType::BR_ELEC, AttributeType::ELEC, _("稲妻", "lightning"), DRS_ELEC),
105     make_breath_elemental(MonsterAbilityType::BR_FIRE, AttributeType::FIRE, _("火炎", "fire"), DRS_FIRE),
106     make_breath_elemental(MonsterAbilityType::BR_COLD, AttributeType::COLD, _("冷気", "frost"), DRS_COLD),
107     make_breath_elemental(MonsterAbilityType::BR_POIS, AttributeType::POIS, _("ガス", "gas"), DRS_POIS),
108     make_breath_elemental(MonsterAbilityType::BR_NETH, AttributeType::NETHER, _("地獄", "nether"), DRS_NETH),
109     make_breath_elemental(MonsterAbilityType::BR_LITE, AttributeType::LITE, _("閃光", "light"), DRS_LITE),
110     make_breath_elemental(MonsterAbilityType::BR_DARK, AttributeType::DARK, _("暗黒", "darkness"), DRS_DARK),
111     make_breath_elemental(MonsterAbilityType::BR_CONF, AttributeType::CONFUSION, _("混乱", "confusion"), DRS_CONF),
112     make_breath_elemental(MonsterAbilityType::BR_SOUN, AttributeType::SOUND, _("轟音", "sound"), DRS_SOUND),
113     make_breath_elemental(MonsterAbilityType::BR_CHAO, AttributeType::CHAOS, _("カオス", "chaos"), DRS_CHAOS),
114     make_breath_elemental(MonsterAbilityType::BR_DISE, AttributeType::DISENCHANT, _("劣化", "disenchantment"), DRS_DISEN),
115     make_breath_elemental(MonsterAbilityType::BR_NEXU, AttributeType::NEXUS, _("因果混乱", "nexus"), DRS_NEXUS),
116     make_breath_elemental(MonsterAbilityType::BR_TIME, AttributeType::TIME, _("時間逆転", "time")),
117     make_breath_elemental(MonsterAbilityType::BR_INER, AttributeType::INERTIAL, _("遅鈍", "inertia")),
118     make_breath_elemental(MonsterAbilityType::BR_GRAV, AttributeType::GRAVITY, _("重力", "gravity")),
119     make_breath_elemental(MonsterAbilityType::BR_SHAR, AttributeType::SHARDS, _("破片", "shards"), DRS_SHARD),
120     make_breath_elemental(MonsterAbilityType::BR_PLAS, AttributeType::PLASMA, _("プラズマ", "plasma")),
121     make_breath_elemental(MonsterAbilityType::BR_FORC, AttributeType::FORCE, _("フォース", "force")),
122     make_breath_elemental(MonsterAbilityType::BR_MANA, AttributeType::MANA, _("魔力", "mana")),
123     make_breath_elemental(MonsterAbilityType::BR_NUKE, AttributeType::NUKE, _("放射性廃棄物", "toxic waste"), DRS_POIS),
124     make_breath_elemental(MonsterAbilityType::BR_DISI, AttributeType::DISINTEGRATE, _("分解", "disintegration")),
125     make_breath_elemental(MonsterAbilityType::BR_VOID, AttributeType::VOID_MAGIC, _("虚無", "void")),
126     make_breath_elemental(MonsterAbilityType::BR_ABYSS, AttributeType::ABYSS, _("深淵", "abyss")),
127 };
128
129 /*!
130  * @brief RF4_BR_*の処理。各種ブレス。 /
131  * @param player_ptr プレイヤーへの参照ポインタ
132  * @param GF_TYPE ブレスの属性
133  * @param y 対象の地点のy座標
134  * @param x 対象の地点のx座標
135  * @param m_idx 呪文を唱えるモンスターID
136  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
137  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
138  *
139  * プレイヤーに当たったらラーニング可。
140  */
141 MonsterSpellResult spell_RF4_BREATH(PlayerType *player_ptr, MonsterAbilityType ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
142 {
143     auto dam = 0;
144     auto mon_to_player = (target_type == MONSTER_TO_PLAYER);
145     std::unique_ptr<MSpellData> data;
146
147     if (breath_list.find(ms_type) != breath_list.end()) {
148         dam = monspell_damage(player_ptr, ms_type, m_idx, DAM_ROLL);
149         data = std::make_unique<MSpellData>(breath_list.at(ms_type));
150     } else {
151         dam = 0;
152         data = std::make_unique<MSpellData>([](auto *player_ptr, auto m_idx, auto t_idx, int target_type) {
153             message_breath(player_ptr, m_idx, t_idx, target_type, _("不明", "Unknown"), AttributeType::NONE);
154             return false;
155         },
156             AttributeType::NONE);
157     }
158
159     data->msg.output(player_ptr, m_idx, t_idx, target_type);
160
161     const auto proj_res = breath(player_ptr, y, x, m_idx, data->type, dam, 0, target_type);
162
163     if (mon_to_player) {
164         data->drs.execute(player_ptr, m_idx);
165     }
166
167     auto res = MonsterSpellResult::make_valid(dam);
168     res.learnable = proj_res.affected_player;
169
170     return res;
171 }