OSDN Git Service

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