OSDN Git Service

Merge pull request #1345 from sikabane-works/feature/refactor-cfm_type-comment
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-summon.cpp
1 #include "monster-floor/monster-summon.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "floor/geometry.h"
5 #include "floor/wild.h"
6 #include "main/sound-definitions-table.h"
7 #include "main/sound-of-music.h"
8 #include "monster-floor/monster-generator.h"
9 #include "monster-floor/place-monster-types.h"
10 #include "monster-race/monster-race-hook.h"
11 #include "monster-race/monster-race.h"
12 #include "monster-race/race-flags1.h"
13 #include "monster-race/race-flags7.h"
14 #include "monster/monster-info.h"
15 #include "monster/monster-list.h"
16 #include "monster/monster-util.h"
17 #include "mspell/summon-checker.h"
18 #include "spell/summon-types.h"
19 #include "system/floor-type-definition.h"
20 #include "system/monster-race-definition.h"
21 #include "system/monster-type-definition.h"
22 #include "system/player-type-definition.h"
23
24 /*!
25  * @var summon_specific_who
26  * @brief 召喚を行ったプレイヤーあるいはモンスターのIDを示すグローバル変数 / Hack -- the index of the summoning monster
27  * @todo summon_specific_who グローバル変数の除去と関数引数への代替を行う
28  */
29 int summon_specific_who = -1;
30
31 /*!
32  * @var summon_unique_okay
33  * @brief 召喚対象にユニークを含めるかを示すグローバル変数 / summoning unique enable
34  * @todo summon_unique_okay グローバル変数の除去と関数引数への代替を行う
35  */
36 bool summon_unique_okay = false;
37
38 /*!
39  * @brief モンスターが召喚の基本条件に合っているかをチェックする / Hack -- help decide if a monster race is "okay" to summon
40  * @param r_idx チェックするモンスター種族ID
41  * @return 召喚対象にできるならばTRUE
42  */
43 static bool summon_specific_okay(player_type *player_ptr, MONRACE_IDX r_idx)
44 {
45     monster_race *r_ptr = &r_info[r_idx];
46     if (!mon_hook_dungeon(player_ptr, r_idx))
47         return false;
48
49     if (summon_specific_who > 0) {
50         monster_type *m_ptr = &player_ptr->current_floor_ptr->m_list[summon_specific_who];
51         if (monster_has_hostile_align(player_ptr, m_ptr, 0, 0, r_ptr))
52             return false;
53     } else if (summon_specific_who < 0) {
54         if (monster_has_hostile_align(player_ptr, NULL, 10, -10, r_ptr) && !one_in_(ABS(player_ptr->alignment) / 2 + 1))
55             return false;
56     }
57
58     if (!summon_unique_okay && ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL)))
59         return false;
60
61     if (!summon_specific_type)
62         return true;
63
64     if ((summon_specific_who < 0) && ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL))
65         && monster_has_hostile_align(player_ptr, NULL, 10, -10, r_ptr))
66         return false;
67
68     if ((r_ptr->flags7 & RF7_CHAMELEON) && d_info[player_ptr->dungeon_idx].flags.has(DF::CHAMELEON))
69         return true;
70
71     if (summon_specific_who > 0) {
72         monster_type *m_ptr = &player_ptr->current_floor_ptr->m_list[summon_specific_who];
73         return check_summon_specific(player_ptr, m_ptr->r_idx, r_idx);
74     } else {
75         return check_summon_specific(player_ptr, 0, r_idx);
76     }
77 }
78
79 /*!
80  * @brief モンスター死亡時に召喚されうるモンスターかどうかの判定
81  * @param type モンスター種族ID
82  * @return 召喚されうるならばTRUE (あやしい影として生成されない)
83  */
84 static bool is_dead_summoning(summon_type type)
85 {
86     bool summoning = type == SUMMON_BLUE_HORROR;
87     summoning |= type == SUMMON_DAWN;
88     summoning |= type == SUMMON_TOTEM_MOAI;
89     return summoning;
90 }
91
92 /*!
93  * @brief 荒野のレベルを含めた階層レベルを返す
94  * @param player_ptr プレーヤーへの参照ポインタ
95  * @return 階層レベル
96  * @details
97  * ダンジョン及びクエストはdun_level>0となる。
98  * 荒野はdun_level==0なので、その場合荒野レベルを返す。
99  */
100 DEPTH get_dungeon_or_wilderness_level(player_type *player_ptr)
101 {
102     floor_type *floor_ptr = player_ptr->current_floor_ptr;
103     if (floor_ptr->dun_level > 0)
104         return floor_ptr->dun_level;
105
106     return wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
107 }
108
109 /*!
110  * @brief モンスターを召喚により配置する / Place a monster (of the specified "type") near the given location. Return TRUE if a monster was actually summoned.
111  * @param player_ptr プレーヤーへの参照ポインタ
112  * @param who 召喚主のモンスター情報ID
113  * @param y1 目標地点y座標
114  * @param x1 目標地点x座標
115  * @param lev 相当生成階
116  * @param type 召喚種別
117  * @param mode 生成オプション
118  * @return 召喚できたらtrueを返す
119  */
120 bool summon_specific(player_type *player_ptr, MONSTER_IDX who, POSITION y1, POSITION x1, DEPTH lev, summon_type type, BIT_FLAGS mode)
121 {
122     floor_type *floor_ptr = player_ptr->current_floor_ptr;
123     if (floor_ptr->inside_arena)
124         return false;
125
126     POSITION x, y;
127     if (!mon_scatter(player_ptr, 0, &y, &x, y1, x1, 2))
128         return false;
129
130     summon_specific_who = who;
131     summon_specific_type = type;
132     summon_unique_okay = (mode & PM_ALLOW_UNIQUE) != 0;
133     get_mon_num_prep(player_ptr, summon_specific_okay, get_monster_hook2(player_ptr, y, x));
134
135     DEPTH dlev = get_dungeon_or_wilderness_level(player_ptr);
136     MONRACE_IDX r_idx = get_mon_num(player_ptr, 0, (dlev + lev) / 2 + 5, 0);
137     if (!r_idx) {
138         summon_specific_type = SUMMON_NONE;
139         return false;
140     }
141
142     if (is_dead_summoning(type))
143         mode |= PM_NO_KAGE;
144
145     if (!place_monster_aux(player_ptr, who, y, x, r_idx, mode)) {
146         summon_specific_type = SUMMON_NONE;
147         return false;
148     }
149
150     summon_specific_type = SUMMON_NONE;
151
152     bool notice = false;
153     if (who <= 0) {
154         notice = true;
155     } else {
156         monster_type *m_ptr = &player_ptr->current_floor_ptr->m_list[who];
157         if (is_pet(m_ptr)) {
158             notice = true;
159         } else if (is_seen(player_ptr, m_ptr)) {
160             notice = true;
161         } else if (player_can_see_bold(player_ptr, x, y)) {
162             notice = true;
163         }
164     }
165
166     if (notice) {
167         sound(SOUND_SUMMON);
168     }
169
170     return true;
171 }
172
173 /*!
174  * @brief 特定モンスター種族を召喚により生成する / A "dangerous" function, creates a pet of the specified type
175  * @param player_ptr プレーヤーへの参照ポインタ
176  * @param who 召喚主のモンスター情報ID
177  * @param oy 目標地点y座標
178  * @param ox 目標地点x座標
179  * @param r_idx 生成するモンスター種族ID
180  * @param mode 生成オプション
181  * @return 召喚できたらtrueを返す
182  */
183 bool summon_named_creature(player_type *player_ptr, MONSTER_IDX who, POSITION oy, POSITION ox, MONRACE_IDX r_idx, BIT_FLAGS mode)
184 {
185     if ((r_idx <= 0) || (r_idx >= max_r_idx)) {
186         return false;
187     }
188     
189     POSITION x, y;
190     if (player_ptr->current_floor_ptr->inside_arena || !mon_scatter(player_ptr, r_idx, &y, &x, oy, ox, 2)) {
191         return false;
192     }
193     
194     return place_monster_aux(player_ptr, who, y, x, r_idx, (mode | PM_NO_KAGE));
195 }