OSDN Git Service

fd13998b77a85df283b8475be66512cfe9c00a8b
[hengbandforosx/hengbandosx.git] / src / floor / floor-util.cpp
1 /*!
2  * @brief フロア全体の処理に関するユーティリティ
3  * @date 2019/04/24
4  * @author deskull
5  */
6 #include "floor/floor-util.h"
7 #include "dungeon/dungeon.h"
8 #include "dungeon/quest.h"
9 #include "effect/effect-characteristics.h"
10 #include "floor/cave.h"
11 #include "floor/floor-object.h"
12 #include "floor/floor-town.h"
13 #include "floor/geometry.h"
14 #include "floor/line-of-sight.h"
15 #include "game-option/birth-options.h"
16 #include "grid/feature.h"
17 #include "object-hook/hook-checker.h"
18 #include "object-hook/hook-enchant.h"
19 #include "perception/object-perception.h"
20 #include "system/artifact-type-definition.h"
21 #include "system/floor-type-definition.h"
22 #include "system/grid-type-definition.h"
23 #include "system/monster-type-definition.h"
24 #include "system/player-type-definition.h"
25 #include "target/projection-path-calculator.h"
26 #include "world/world.h"
27
28 /*
29  * The array of floor [MAX_WID][MAX_HGT].
30  * Not completely allocated, that would be inefficient
31  * Not completely hardcoded, that would overflow memory
32  */
33 floor_type floor_info;
34
35 static int scent_when = 0;
36
37 /*
38  * Characters leave scent trails for perceptive monsters to track.
39  *
40  * Smell is rather more limited than sound.  Many creatures cannot use
41  * it at all, it doesn't extend very far outwards from the character's
42  * current position, and monsters can use it to home in the character,
43  * but not to run away from him.
44  *
45  * Smell is valued according to age.  When a character takes his turn,
46  * scent is aged by one, and new scent of the current age is laid down.
47  * Speedy characters leave more scent, true, but it also ages faster,
48  * which makes it harder to hunt them down.
49  *
50  * Whenever the age count loops, most of the scent trail is erased and
51  * the age of the remainder is recalculated.
52  */
53 void update_smell(floor_type *floor_ptr, player_type *subject_ptr)
54 {
55     /* Create a table that controls the spread of scent */
56     const int scent_adjust[5][5] = {
57         { -1, 0, 0, 0, -1 },
58         { 0, 1, 1, 1, 0 },
59         { 0, 1, 2, 1, 0 },
60         { 0, 1, 1, 1, 0 },
61         { -1, 0, 0, 0, -1 },
62     };
63
64     if (++scent_when == 254) {
65         for (POSITION y = 0; y < floor_ptr->height; y++) {
66             for (POSITION x = 0; x < floor_ptr->width; x++) {
67                 int w = floor_ptr->grid_array[y][x].when;
68                 floor_ptr->grid_array[y][x].when = (w > 128) ? (w - 128) : 0;
69             }
70         }
71
72         scent_when = 126;
73     }
74
75     for (POSITION i = 0; i < 5; i++) {
76         for (POSITION j = 0; j < 5; j++) {
77             grid_type *g_ptr;
78             POSITION y = i + subject_ptr->y - 2;
79             POSITION x = j + subject_ptr->x - 2;
80             if (!in_bounds(floor_ptr, y, x))
81                 continue;
82
83             g_ptr = &floor_ptr->grid_array[y][x];
84             if (!cave_has_flag_grid(g_ptr, FF_MOVE) && !is_closed_door(subject_ptr, g_ptr->feat))
85                 continue;
86             if (!player_has_los_bold(subject_ptr, y, x))
87                 continue;
88             if (scent_adjust[i][j] == -1)
89                 continue;
90
91             g_ptr->when = scent_when + scent_adjust[i][j];
92         }
93     }
94 }
95
96 /*
97  * Hack -- forget the "flow" information
98  */
99 void forget_flow(floor_type *floor_ptr)
100 {
101     for (POSITION y = 0; y < floor_ptr->height; y++) {
102         for (POSITION x = 0; x < floor_ptr->width; x++) {
103             memset(&floor_ptr->grid_array[y][x].costs, 0, sizeof(floor_ptr->grid_array[y][x].costs));
104             memset(&floor_ptr->grid_array[y][x].dists, 0, sizeof(floor_ptr->grid_array[y][x].dists));
105             floor_ptr->grid_array[y][x].when = 0;
106         }
107     }
108 }
109
110 /*!
111  * @brief グローバルオブジェクト配列を初期化する /
112  * Delete all the items when player leaves the level
113  * @note we do NOT visually reflect these (irrelevant) changes
114  * @details
115  * Hack -- we clear the "g_ptr->o_idx" field for every grid,
116  * and the "m_ptr->next_o_idx" field for every monster, since
117  * we know we are clearing every object.  Technically, we only
118  * clear those fields for grids/monsters containing objects,
119  * and we clear it once for every such object.
120  */
121 void wipe_o_list(floor_type *floor_ptr)
122 {
123     for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
124         object_type *o_ptr = &floor_ptr->o_list[i];
125         if (!object_is_valid(o_ptr))
126             continue;
127
128         if (!current_world_ptr->character_dungeon || preserve_mode) {
129             if (object_is_fixed_artifact(o_ptr) && !object_is_known(o_ptr)) {
130                 a_info[o_ptr->name1].cur_num = 0;
131             }
132         }
133
134         auto &list = get_o_idx_list_contains(floor_ptr, i);
135         list.clear();
136         o_ptr->wipe();
137     }
138
139     floor_ptr->o_max = 1;
140     floor_ptr->o_cnt = 0;
141 }
142
143 /*
144  * Standard "find me a location" function
145  *
146  * Obtains a legal location within the given distance of the initial
147  * location, and with "los()" from the source to destination location.
148  *
149  * This function is often called from inside a loop which searches for
150  * locations while increasing the "d" distance.
151  *
152  * Currently the "m" parameter is unused.
153  */
154 void scatter(player_type *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode)
155 {
156     floor_type *floor_ptr = player_ptr->current_floor_ptr;
157     POSITION nx, ny;
158     while (true) {
159         ny = rand_spread(y, d);
160         nx = rand_spread(x, d);
161
162         if (!in_bounds(floor_ptr, ny, nx))
163             continue;
164         if ((d > 1) && (distance(y, x, ny, nx) > d))
165             continue;
166         if (mode & PROJECT_LOS) {
167             if (los(player_ptr, y, x, ny, nx))
168                 break;
169             continue;
170         }
171
172         if (projectable(player_ptr, y, x, ny, nx))
173             break;
174     }
175
176     *yp = ny;
177     *xp = nx;
178 }
179
180 /*!
181  * @brief 現在のマップ名を返す /
182  * @param creature_ptr プレーヤーへの参照ポインタ
183  * @return マップ名の文字列参照ポインタ
184  */
185 concptr map_name(player_type *creature_ptr)
186 {
187     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
188     if (floor_ptr->inside_quest && is_fixed_quest_idx(floor_ptr->inside_quest) && (quest[floor_ptr->inside_quest].flags & QUEST_FLAG_PRESET))
189         return _("クエスト", "Quest");
190     else if (creature_ptr->wild_mode)
191         return _("地上", "Surface");
192     else if (floor_ptr->inside_arena)
193         return _("アリーナ", "Arena");
194     else if (creature_ptr->phase_out)
195         return _("闘技場", "Monster Arena");
196     else if (!floor_ptr->dun_level && creature_ptr->town_num)
197         return town_info[creature_ptr->town_num].name;
198     else
199         return d_info[creature_ptr->dungeon_idx].name.c_str();
200 }