OSDN Git Service

Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband
[hengband/hengband.git] / src / spell-kind / spells-polymorph.c
1 #include "spell-kind/spells-polymorph.h"
2 #include "core/stuff-handler.h"
3 #include "floor/floor-object.h"
4 #include "grid/grid.h"
5 #include "monster-floor/monster-generator.h"
6 #include "monster-floor/monster-remover.h"
7 #include "monster-floor/place-monster-types.h"
8 #include "monster-race/monster-race.h"
9 #include "monster-race/race-flags1.h"
10 #include "monster/monster-flag-types.h"
11 #include "monster/monster-info.h"
12 #include "monster/monster-list.h"
13 #include "monster/monster-status.h"
14 #include "monster/monster-util.h"
15 #include "system/floor-type-definition.h"
16 #include "system/object-type-definition.h"
17 #include "target/target-checker.h"
18
19 /*!
20  * @brief 変身処理向けにモンスターの近隣レベル帯モンスターを返す /
21  * Helper function -- return a "nearby" race for polymorphing
22  * @param floor_ptr 配置するフロアの参照ポインタ
23  * @param r_idx 基準となるモンスター種族ID
24  * @return 変更先のモンスター種族ID
25  * @details
26  * Note that this function is one of the more "dangerous" ones...
27  */
28 static MONRACE_IDX poly_r_idx(player_type *caster_ptr, MONRACE_IDX r_idx)
29 {
30     monster_race *r_ptr = &r_info[r_idx];
31     if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags1 & RF1_QUESTOR))
32         return (r_idx);
33
34     DEPTH lev1 = r_ptr->level - ((randint1(20) / randint1(9)) + 1);
35     DEPTH lev2 = r_ptr->level + ((randint1(20) / randint1(9)) + 1);
36     MONRACE_IDX r;
37     for (int i = 0; i < 1000; i++) {
38         r = get_mon_num(caster_ptr, (caster_ptr->current_floor_ptr->dun_level + r_ptr->level) / 2 + 5, 0);
39         if (!r)
40             break;
41
42         r_ptr = &r_info[r];
43         if (r_ptr->flags1 & RF1_UNIQUE)
44             continue;
45         if ((r_ptr->level < lev1) || (r_ptr->level > lev2))
46             continue;
47
48         r_idx = r;
49         break;
50     }
51
52     return r_idx;
53 }
54
55 /*!
56  * @brief 指定座標にいるモンスターを変身させる /
57  * Helper function -- return a "nearby" race for polymorphing
58  * @param caster_ptr プレーヤーへの参照ポインタ
59  * @param y 指定のY座標
60  * @param x 指定のX座標
61  * @return 実際に変身したらTRUEを返す
62  */
63 bool polymorph_monster(player_type *caster_ptr, POSITION y, POSITION x)
64 {
65     floor_type *floor_ptr = caster_ptr->current_floor_ptr;
66     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
67     monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
68     MONRACE_IDX new_r_idx;
69     MONRACE_IDX old_r_idx = m_ptr->r_idx;
70     bool targeted = (target_who == g_ptr->m_idx) ? TRUE : FALSE;
71     bool health_tracked = (caster_ptr->health_who == g_ptr->m_idx) ? TRUE : FALSE;
72
73     if (floor_ptr->inside_arena || caster_ptr->phase_out)
74         return FALSE;
75     if ((caster_ptr->riding == g_ptr->m_idx) || (m_ptr->mflag2 & MFLAG2_KAGE))
76         return FALSE;
77
78     monster_type back_m = *m_ptr;
79     new_r_idx = poly_r_idx(caster_ptr, old_r_idx);
80     if (new_r_idx == old_r_idx)
81         return FALSE;
82
83     bool preserve_hold_objects = back_m.hold_o_idx ? TRUE : FALSE;
84     OBJECT_IDX this_o_idx, next_o_idx = 0;
85
86     BIT_FLAGS mode = 0L;
87     if (is_friendly(m_ptr))
88         mode |= PM_FORCE_FRIENDLY;
89     if (is_pet(m_ptr))
90         mode |= PM_FORCE_PET;
91     if (m_ptr->mflag2 & MFLAG2_NOPET)
92         mode |= PM_NO_PET;
93
94     m_ptr->hold_o_idx = 0;
95     delete_monster_idx(caster_ptr, g_ptr->m_idx);
96     bool polymorphed = FALSE;
97     if (place_monster_aux(caster_ptr, 0, y, x, new_r_idx, mode)) {
98         floor_ptr->m_list[hack_m_idx_ii].nickname = back_m.nickname;
99         floor_ptr->m_list[hack_m_idx_ii].parent_m_idx = back_m.parent_m_idx;
100         floor_ptr->m_list[hack_m_idx_ii].hold_o_idx = back_m.hold_o_idx;
101         polymorphed = TRUE;
102     } else {
103         if (place_monster_aux(caster_ptr, 0, y, x, old_r_idx, (mode | PM_NO_KAGE | PM_IGNORE_TERRAIN))) {
104             floor_ptr->m_list[hack_m_idx_ii] = back_m;
105             mproc_init(floor_ptr);
106         } else
107             preserve_hold_objects = FALSE;
108     }
109
110     if (preserve_hold_objects) {
111         for (this_o_idx = back_m.hold_o_idx; this_o_idx; this_o_idx = next_o_idx) {
112             object_type *o_ptr = &floor_ptr->o_list[this_o_idx];
113             next_o_idx = o_ptr->next_o_idx;
114             o_ptr->held_m_idx = hack_m_idx_ii;
115         }
116     } else if (back_m.hold_o_idx) {
117         for (this_o_idx = back_m.hold_o_idx; this_o_idx; this_o_idx = next_o_idx) {
118             next_o_idx = floor_ptr->o_list[this_o_idx].next_o_idx;
119             delete_object_idx(caster_ptr, this_o_idx);
120         }
121     }
122
123     if (targeted)
124         target_who = hack_m_idx_ii;
125     if (health_tracked)
126         health_track(caster_ptr, hack_m_idx_ii);
127     return polymorphed;
128 }