OSDN Git Service

d41c4f79ca076b287b7b67d25bab291664716ad3
[hengband/hengband.git] / src / floor / fixed-map-generator.c
1 #include "floor/fixed-map-generator.h"
2 #include "dungeon/quest.h"
3 #include "floor/floor-object.h"
4 #include "floor/floor-town.h"
5 #include "floor/floor.h"
6 #include "floor/wild.h"
7 #include "grid/trap.h"
8 #include "info-reader/general-parser.h"
9 #include "info-reader/random-grid-effect-types.h"
10 #include "io/tokenizer.h"
11 #include "object-enchant/apply-magic.h"
12 #include "object-enchant/artifact.h"
13 #include "object-enchant/item-apply-magic.h"
14 #include "object-enchant/object-ego.h"
15 #include "object/object-generator.h"
16 #include "object/object-kind-hook.h"
17 #include "object/object-kind.h"
18 #include "room/rooms-vault.h"
19 #include "sv-definition/sv-scroll-types.h"
20 #include "system/system-variables.h"
21 #include "view/display-main-window.h"
22 #include "world/world-object.h"
23 #include "world/world.h"
24
25 // PARSE_ERROR_MAXが既にあり扱い辛いのでここでconst宣言.
26 static const int PARSE_CONTINUE = 255;
27
28 qtwg_type *initialize_quest_generator_type(qtwg_type *qtwg_ptr, char *buf, int ymin, int xmin, int ymax, int xmax, int *y, int *x)
29 {
30     qtwg_ptr->buf = buf;
31     qtwg_ptr->ymin = ymin;
32     qtwg_ptr->xmin = xmin;
33     qtwg_ptr->ymax = ymax;
34     qtwg_ptr->xmax = xmax;
35     qtwg_ptr->y = y;
36     qtwg_ptr->x = x;
37     return qtwg_ptr;
38 }
39
40 /*!
41  * @brief フロアの所定のマスにオブジェクトを配置する
42  * Place the object j_ptr to a grid
43  * @param floor_ptr 現在フロアへの参照ポインタ
44  * @param j_ptr オブジェクト構造体の参照ポインタ
45  * @param y 配置先Y座標
46  * @param x 配置先X座標
47  * @return エラーコード
48  */
49 static void drop_here(floor_type *floor_ptr, object_type *j_ptr, POSITION y, POSITION x)
50 {
51     OBJECT_IDX o_idx = o_pop(floor_ptr);
52     object_type *o_ptr;
53     o_ptr = &floor_ptr->o_list[o_idx];
54     object_copy(o_ptr, j_ptr);
55     o_ptr->iy = y;
56     o_ptr->ix = x;
57     o_ptr->held_m_idx = 0;
58     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
59     o_ptr->next_o_idx = g_ptr->o_idx;
60     g_ptr->o_idx = o_idx;
61 }
62
63 static void generate_artifact(player_type *player_ptr, qtwg_type *qtwg_ptr, const ARTIFACT_IDX artifact_index)
64 {
65     if (artifact_index == 0)
66         return;
67
68     if ((a_info[artifact_index].cur_num == 0) && create_named_art(player_ptr, artifact_index, *qtwg_ptr->y, *qtwg_ptr->x)) {
69         a_info[artifact_index].cur_num = 1;
70         return;
71     }
72
73     KIND_OBJECT_IDX k_idx = lookup_kind(TV_SCROLL, SV_SCROLL_ACQUIREMENT);
74     object_type forge;
75     object_type *q_ptr = &forge;
76     object_prep(q_ptr, k_idx);
77     drop_here(player_ptr->current_floor_ptr, q_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
78 }
79
80 static void parse_qtw_D(player_type *player_ptr, qtwg_type *qtwg_ptr, char *s)
81 {
82     *qtwg_ptr->x = qtwg_ptr->xmin;
83     floor_type *floor_ptr = player_ptr->current_floor_ptr;
84     int len = strlen(s);
85     for (int i = 0; ((*qtwg_ptr->x < qtwg_ptr->xmax) && (i < len)); (*qtwg_ptr->x)++, s++, i++) {
86         grid_type *g_ptr = &floor_ptr->grid_array[*qtwg_ptr->y][*qtwg_ptr->x];
87         int idx = s[0];
88         OBJECT_IDX object_index = letter[idx].object;
89         MONSTER_IDX monster_index = letter[idx].monster;
90         int random = letter[idx].random;
91         ARTIFACT_IDX artifact_index = letter[idx].artifact;
92         g_ptr->feat = conv_dungeon_feat(floor_ptr, letter[idx].feature);
93         if (init_flags & INIT_ONLY_FEATURES)
94             continue;
95
96         g_ptr->info = letter[idx].cave_info;
97         if (random & RANDOM_MONSTER) {
98             floor_ptr->monster_level = floor_ptr->base_level + monster_index;
99
100             place_monster(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
101
102             floor_ptr->monster_level = floor_ptr->base_level;
103         } else if (monster_index) {
104             int old_cur_num, old_max_num;
105             bool clone = FALSE;
106
107             if (monster_index < 0) {
108                 monster_index = -monster_index;
109                 clone = TRUE;
110             }
111
112             old_cur_num = r_info[monster_index].cur_num;
113             old_max_num = r_info[monster_index].max_num;
114
115             if (r_info[monster_index].flags1 & RF1_UNIQUE) {
116                 r_info[monster_index].cur_num = 0;
117                 r_info[monster_index].max_num = 1;
118             } else if (r_info[monster_index].flags7 & RF7_NAZGUL) {
119                 if (r_info[monster_index].cur_num == r_info[monster_index].max_num) {
120                     r_info[monster_index].max_num++;
121                 }
122             }
123
124             place_monster_aux(player_ptr, 0, *qtwg_ptr->y, *qtwg_ptr->x, monster_index, (PM_ALLOW_SLEEP | PM_NO_KAGE));
125             if (clone) {
126                 floor_ptr->m_list[hack_m_idx_ii].smart |= SM_CLONED;
127                 r_info[monster_index].cur_num = old_cur_num;
128                 r_info[monster_index].max_num = old_max_num;
129             }
130         }
131
132         if ((random & RANDOM_OBJECT) && (random & RANDOM_TRAP)) {
133             floor_ptr->object_level = floor_ptr->base_level + object_index;
134
135             /*
136              * Random trap and random treasure defined
137              * 25% chance for trap and 75% chance for object
138              */
139             if (randint0(100) < 75) {
140                 place_object(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, 0L);
141             } else {
142                 place_trap(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
143             }
144
145             floor_ptr->object_level = floor_ptr->base_level;
146         } else if (random & RANDOM_OBJECT) {
147             floor_ptr->object_level = floor_ptr->base_level + object_index;
148             if (randint0(100) < 75)
149                 place_object(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, 0L);
150             else if (randint0(100) < 80)
151                 place_object(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, AM_GOOD);
152             else
153                 place_object(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, AM_GOOD | AM_GREAT);
154
155             floor_ptr->object_level = floor_ptr->base_level;
156         } else if (random & RANDOM_TRAP) {
157             place_trap(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
158         } else if (letter[idx].trap) {
159             g_ptr->mimic = g_ptr->feat;
160             g_ptr->feat = conv_dungeon_feat(floor_ptr, letter[idx].trap);
161         } else if (object_index) {
162             object_type tmp_object;
163             object_type *o_ptr = &tmp_object;
164             object_prep(o_ptr, object_index);
165             if (o_ptr->tval == TV_GOLD) {
166                 coin_type = object_index - OBJ_GOLD_LIST;
167                 make_gold(floor_ptr, o_ptr);
168                 coin_type = 0;
169             }
170
171             apply_magic(player_ptr, o_ptr, floor_ptr->base_level, AM_NO_FIXED_ART | AM_GOOD);
172             drop_here(floor_ptr, o_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
173         }
174
175         generate_artifact(player_ptr, qtwg_ptr, artifact_index);
176         g_ptr->special = letter[idx].special;
177     }
178 }
179
180 static bool parse_qtw_QQ(char **zz, int num, quest_type *q_ptr)
181 {
182     if (zz[1][0] != 'Q')
183         return FALSE;
184
185     if ((init_flags & INIT_ASSIGN) == 0)
186         return TRUE;
187
188     monster_race *r_ptr;
189     artifact_type *a_ptr;
190
191     if (num < 9)
192         return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
193
194     q_ptr->type = (QUEST_TYPE)atoi(zz[2]);
195     q_ptr->num_mon = (MONSTER_NUMBER)atoi(zz[3]);
196     q_ptr->cur_num = (MONSTER_NUMBER)atoi(zz[4]);
197     q_ptr->max_num = (MONSTER_NUMBER)atoi(zz[5]);
198     q_ptr->level = (DEPTH)atoi(zz[6]);
199     q_ptr->r_idx = (IDX)atoi(zz[7]);
200     q_ptr->k_idx = (IDX)atoi(zz[8]);
201     q_ptr->dungeon = (DUNGEON_IDX)atoi(zz[9]);
202
203     if (num > 10)
204         q_ptr->flags = atoi(zz[10]);
205
206     r_ptr = &r_info[q_ptr->r_idx];
207     if (r_ptr->flags1 & RF1_UNIQUE)
208         r_ptr->flags1 |= RF1_QUESTOR;
209
210     a_ptr = &a_info[q_ptr->k_idx];
211     a_ptr->gen_flags |= TRG_QUESTITEM;
212     return TRUE;
213 }
214
215 static bool parse_qtw_QR(char **zz, int num, quest_type *q_ptr)
216 {
217     if (zz[1][0] != 'R')
218         return FALSE;
219
220     if ((init_flags & INIT_ASSIGN) == 0)
221         return TRUE;
222
223     int count = 0;
224     IDX idx, reward_idx = 0;
225     for (idx = 2; idx < num; idx++) {
226         IDX a_idx = (IDX)atoi(zz[idx]);
227         if (a_idx < 1)
228             continue;
229         if (a_info[a_idx].cur_num > 0)
230             continue;
231         count++;
232         if (one_in_(count))
233             reward_idx = a_idx;
234     }
235
236     if (reward_idx) {
237         q_ptr->k_idx = reward_idx;
238         a_info[reward_idx].gen_flags |= TRG_QUESTITEM;
239     } else {
240         q_ptr->type = QUEST_TYPE_KILL_ALL;
241     }
242
243     return TRUE;
244 }
245
246 /*!
247  * @brief t_info、q_info、w_infoにおけるQトークンをパースする
248  * @param qtwg_ptr トークンパース構造体への参照ポインタ
249  * @param zz トークン保管文字列
250  * @return エラーコード、但しPARSE_CONTINUEの時は処理続行
251  */
252 static int parse_qtw_Q(qtwg_type *qtwg_ptr, char **zz)
253 {
254     if (qtwg_ptr->buf[0] != 'Q')
255         return PARSE_CONTINUE;
256
257     if (qtwg_ptr->buf[2] == '$')
258         return PARSE_ERROR_NONE;
259
260     int num = tokenize(qtwg_ptr->buf + _(2, 3), 33, zz, 0);
261     if (num < 3)
262         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
263
264     quest_type *q_ptr;
265     q_ptr = &(quest[atoi(zz[0])]);
266     if (parse_qtw_QQ(zz, num, q_ptr))
267         return PARSE_ERROR_NONE;
268
269     if (parse_qtw_QR(zz, num, q_ptr))
270         return PARSE_ERROR_NONE;
271
272     if (zz[1][0] == 'N') {
273         if (init_flags & (INIT_ASSIGN | INIT_SHOW_TEXT | INIT_NAME_ONLY)) {
274             strcpy(q_ptr->name, zz[2]);
275         }
276
277         return PARSE_ERROR_NONE;
278     }
279
280     if (zz[1][0] == 'T') {
281         if (init_flags & INIT_SHOW_TEXT) {
282             strcpy(quest_text[quest_text_line], zz[2]);
283             quest_text_line++;
284         }
285
286         return PARSE_ERROR_NONE;
287     }
288
289     return PARSE_ERROR_GENERIC;
290 }
291
292 static bool parse_qtw_P(player_type *player_ptr, qtwg_type *qtwg_ptr, char **zz)
293 {
294     if (qtwg_ptr->buf[0] != 'P')
295         return FALSE;
296
297     if ((init_flags & INIT_CREATE_DUNGEON) == 0)
298         return TRUE;
299
300     if (tokenize(qtwg_ptr->buf + 2, 2, zz, 0) != 2)
301         return TRUE;
302
303     int panels_y = (*qtwg_ptr->y / SCREEN_HGT);
304     if (*qtwg_ptr->y % SCREEN_HGT)
305         panels_y++;
306
307     floor_type *floor_ptr = player_ptr->current_floor_ptr;
308     floor_ptr->height = panels_y * SCREEN_HGT;
309     int panels_x = (*qtwg_ptr->x / SCREEN_WID);
310     if (*qtwg_ptr->x % SCREEN_WID)
311         panels_x++;
312
313     floor_ptr->width = panels_x * SCREEN_WID;
314     panel_row_min = floor_ptr->height;
315     panel_col_min = floor_ptr->width;
316     if (floor_ptr->inside_quest) {
317         delete_monster(player_ptr, player_ptr->y, player_ptr->x);
318         POSITION py = atoi(zz[0]);
319         POSITION px = atoi(zz[1]);
320         player_ptr->y = py;
321         player_ptr->x = px;
322         return TRUE;
323     }
324     
325     if (!player_ptr->oldpx && !player_ptr->oldpy) {
326         player_ptr->oldpy = atoi(zz[0]);
327         player_ptr->oldpx = atoi(zz[1]);
328     }
329
330     return TRUE;
331 }
332
333 static bool parse_qtw_M(qtwg_type *qtwg_ptr, char **zz)
334 {
335     if (qtwg_ptr->buf[0] != 'M')
336         return FALSE;
337
338     if ((tokenize(qtwg_ptr->buf + 2, 2, zz, 0) == 2) == 0)
339         return TRUE;
340
341     if (zz[0][0] == 'T') {
342         max_towns = (TOWN_IDX)atoi(zz[1]);
343     } else if (zz[0][0] == 'Q') {
344         max_q_idx = (QUEST_IDX)atoi(zz[1]);
345     } else if (zz[0][0] == 'R') {
346         max_r_idx = (player_race_type)atoi(zz[1]);
347     } else if (zz[0][0] == 'K') {
348         max_k_idx = (KIND_OBJECT_IDX)atoi(zz[1]);
349     } else if (zz[0][0] == 'V') {
350         max_v_idx = (VAULT_IDX)atoi(zz[1]);
351     } else if (zz[0][0] == 'F') {
352         max_f_idx = (FEAT_IDX)atoi(zz[1]);
353     } else if (zz[0][0] == 'A') {
354         max_a_idx = (ARTIFACT_IDX)atoi(zz[1]);
355     } else if (zz[0][0] == 'E') {
356         max_e_idx = (EGO_IDX)atoi(zz[1]);
357     } else if (zz[0][0] == 'D') {
358         current_world_ptr->max_d_idx = (DUNGEON_IDX)atoi(zz[1]);
359     } else if (zz[0][0] == 'O') {
360         current_world_ptr->max_o_idx = (OBJECT_IDX)atoi(zz[1]);
361     } else if (zz[0][0] == 'M') {
362         current_world_ptr->max_m_idx = (MONSTER_IDX)atoi(zz[1]);
363     } else if (zz[0][0] == 'W') {
364         if (zz[0][1] == 'X')
365             current_world_ptr->max_wild_x = (POSITION)atoi(zz[1]);
366
367         if (zz[0][1] == 'Y')
368             current_world_ptr->max_wild_y = (POSITION)atoi(zz[1]);
369     }
370
371     return TRUE;
372 }
373
374 /*!
375  * @brief 固定マップ (クエスト&街&広域マップ)をフロアに生成する
376  * Parse a sub-file of the "extra info"
377  * @param player_ptr プレーヤーへの参照ポインタ
378  * @param buf 文字列
379  * @param ymin 詳細不明
380  * @param xmin 詳細不明
381  * @param ymax 詳細不明
382  * @param xmax 詳細不明
383  * @param y 詳細不明
384  * @param x 詳細不明
385  * @return エラーコード
386  */
387 parse_error_type generate_fixed_map_floor(player_type *player_ptr, qtwg_type *qtwg_ptr, process_dungeon_file_pf parse_fixed_map)
388 {
389     char *zz[33];
390     if (!qtwg_ptr->buf[0])
391         return PARSE_ERROR_NONE;
392
393     if (iswspace(qtwg_ptr->buf[0]))
394         return PARSE_ERROR_NONE;
395
396     if (qtwg_ptr->buf[0] == '#')
397         return PARSE_ERROR_NONE;
398
399     if (qtwg_ptr->buf[1] != ':')
400         return PARSE_ERROR_GENERIC;
401
402     if (qtwg_ptr->buf[0] == '%')
403         return (*parse_fixed_map)(player_ptr, qtwg_ptr->buf + 2, qtwg_ptr->ymin, qtwg_ptr->xmin, qtwg_ptr->ymax, qtwg_ptr->xmax);
404
405     /* Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid */
406     if (qtwg_ptr->buf[0] == 'F')
407         return parse_line_feature(player_ptr->current_floor_ptr, qtwg_ptr->buf);
408     
409     if (qtwg_ptr->buf[0] == 'D') {
410         char *s = qtwg_ptr->buf + 2;
411         if (init_flags & INIT_ONLY_BUILDINGS)
412             return PARSE_ERROR_NONE;
413
414         parse_qtw_D(player_ptr, qtwg_ptr, s);
415         (*qtwg_ptr->y)++;
416         return PARSE_ERROR_NONE;
417     }
418     
419     parse_error_type parse_result_Q = parse_qtw_Q(qtwg_ptr, zz);
420     if (parse_result_Q != PARSE_CONTINUE)
421         return parse_result_Q;
422
423     if (qtwg_ptr->buf[0] == 'W')
424         return parse_line_wilderness(player_ptr, qtwg_ptr->buf, qtwg_ptr->xmin, qtwg_ptr->xmax, qtwg_ptr->y, qtwg_ptr->x);
425     
426     if (parse_qtw_P(player_ptr, qtwg_ptr, zz))
427         return PARSE_ERROR_NONE;
428
429     if (qtwg_ptr->buf[0] == 'B')
430         return parse_line_building(qtwg_ptr->buf);
431     
432     if (parse_qtw_M(qtwg_ptr, zz))
433         return PARSE_ERROR_NONE;
434
435     return PARSE_ERROR_GENERIC;
436 }