OSDN Git Service

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