2 * todo ちょっとギリギリ。後で分割を検討する
3 * @brief フロア生成時にアイテムを配置する
8 #include "floor/floor-object.h"
9 #include "game-option/birth-options.h"
10 #include "game-option/cheat-options.h"
11 #include "main/sound-definitions-table.h"
12 #include "main/sound-of-music.h"
13 #include "object-enchant/apply-magic.h"
14 #include "object-enchant/artifact.h"
15 #include "object-enchant/item-apply-magic.h"
16 #include "object-enchant/special-object-flags.h"
17 #include "object/object-flavor.h"
18 #include "object/object-generator.h"
19 #include "object/object-hook.h"
20 #include "object/object-info.h"
21 #include "object/object-kind-hook.h"
22 #include "object/object-kind.h"
23 #include "object/object-stack.h"
24 #include "perception/object-perception.h"
25 #include "system/system-variables.h"
26 #include "view/display-messages.h"
27 #include "view/object-describer.h"
28 #include "world/world-object.h"
29 #include "world/world.h"
31 #define MAX_GOLD 18 /* Number of "gold" entries */
34 * @brief オブジェクト生成テーブルに生成制約を加える /
35 * Apply a "object restriction function" to the "object allocation table"
37 * @details 生成の制約はグローバルのget_obj_num_hook関数ポインタで加える
39 static errr get_obj_num_prep(void)
41 alloc_entry *table = alloc_kind_table;
42 for (OBJECT_IDX i = 0; i < alloc_kind_size; i++) {
43 if (!get_obj_num_hook || (*get_obj_num_hook)(table[i].index)) {
44 table[i].prob2 = table[i].prob1;
54 * @brief デバッグ時にアイテム生成情報をメッセージに出力する / Cheat -- describe a created object for the user
55 * @param owner_ptr プレーヤーへの参照ポインタ
56 * @param o_ptr デバッグ出力するオブジェクトの構造体参照ポインタ
59 static void object_mention(player_type *owner_ptr, object_type *o_ptr)
61 object_aware(owner_ptr, o_ptr);
64 o_ptr->ident |= (IDENT_FULL_KNOWN);
65 GAME_TEXT o_name[MAX_NLEN];
66 object_desc(owner_ptr, o_name, o_ptr, 0);
67 msg_format_wizard(CHEAT_OBJECT, _("%sを生成しました。", "%s was generated."), o_name);
71 * @brief 生成階に応じたベースアイテムの生成を行う。
72 * Attempt to make an object (normal or good/great)
73 * @param owner_ptr プレーヤーへの参照ポインタ
74 * @param j_ptr 生成結果を収めたいオブジェクト構造体の参照ポインタ
75 * @param mode オプションフラグ
76 * @return 生成に成功したらTRUEを返す。
78 * This routine plays nasty games to generate the "special artifacts".\n
79 * This routine uses "floor_ptr->object_level" for the "generation level".\n
80 * We assume that the given object has been "wiped".\n
82 bool make_object(player_type *owner_ptr, object_type *j_ptr, BIT_FLAGS mode)
84 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
85 PERCENTAGE prob = ((mode & AM_GOOD) ? 10 : 1000);
86 DEPTH base = ((mode & AM_GOOD) ? (floor_ptr->object_level + 10) : floor_ptr->object_level);
87 if (!one_in_(prob) || !make_artifact_special(owner_ptr, j_ptr)) {
88 KIND_OBJECT_IDX k_idx;
89 if ((mode & AM_GOOD) && !get_obj_num_hook) {
90 get_obj_num_hook = kind_is_good;
96 k_idx = get_obj_num(owner_ptr, base, mode);
97 if (get_obj_num_hook) {
98 get_obj_num_hook = NULL;
105 object_prep(j_ptr, k_idx);
108 apply_magic(owner_ptr, j_ptr, floor_ptr->object_level, mode);
109 switch (j_ptr->tval) {
115 j_ptr->number = (byte)damroll(6, 7);
120 object_mention(owner_ptr, j_ptr);
126 * @brief 生成階に応じた財宝オブジェクトの生成を行う。
127 * Make a treasure object
128 * @param floor_ptr 現在フロアへの参照ポインタ
129 * @param j_ptr 生成結果を収めたいオブジェクト構造体の参照ポインタ
130 * @return 生成に成功したらTRUEを返す。
132 * The location must be a legal, clean, floor grid.
134 bool make_gold(floor_type *floor_ptr, object_type *j_ptr)
136 int i = ((randint1(floor_ptr->object_level + 2) + 2) / 2) - 1;
137 if (one_in_(GREAT_OBJ)) {
138 i += randint1(floor_ptr->object_level + 1);
145 object_prep(j_ptr, OBJ_GOLD_LIST + i);
147 s32b base = k_info[OBJ_GOLD_LIST + i].cost;
148 j_ptr->pval = (base + (8L * randint1(base)) + randint1(8));
154 * @brief フロア中のアイテムを全て削除する / Deletes all objects at given location
155 * Delete a dungeon object
156 * @param player_ptr プレーヤーへの参照ポインタ
157 * @param y 削除したフロアマスのY座標
158 * @param x 削除したフロアマスのX座標
161 void delete_all_items_from_floor(player_type *player_ptr, POSITION y, POSITION x)
164 OBJECT_IDX this_o_idx, next_o_idx = 0;
165 floor_type *floor_ptr = player_ptr->current_floor_ptr;
166 if (!in_bounds(floor_ptr, y, x))
169 g_ptr = &floor_ptr->grid_array[y][x];
170 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
172 o_ptr = &floor_ptr->o_list[this_o_idx];
173 next_o_idx = o_ptr->next_o_idx;
179 lite_spot(player_ptr, y, x);
183 * @brief 床上のアイテムの数を増やす /
184 * Increase the "number" of an item on the floor
185 * @param floo_ptr 現在フロアへの参照ポインタ
186 * @param item 増やしたいアイテムの所持スロット
187 * @param num 増やしたいアイテムの数
190 void floor_item_increase(floor_type *floor_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
192 object_type *o_ptr = &floor_ptr->o_list[item];
193 num += o_ptr->number;
199 num -= o_ptr->number;
200 o_ptr->number += num;
204 * @brief 床上の数の無くなったアイテムスロットを消去する /
205 * Optimize an item on the floor (destroy "empty" items)
206 * @param player_ptr プレーヤーへの参照ポインタ
207 * @param item 消去したいアイテムの所持スロット
210 void floor_item_optimize(player_type *owner_ptr, INVENTORY_IDX item)
212 object_type *o_ptr = &owner_ptr->current_floor_ptr->o_list[item];
218 delete_object_idx(owner_ptr, item);
222 * @brief オブジェクトを削除する /
223 * Delete a dungeon object
224 * @param player_ptr プレーヤーへの参照ポインタ
225 * @param o_idx 削除対象のオブジェクト構造体ポインタ
228 * Handle "stacks" of objects correctly.
230 void delete_object_idx(player_type *player_ptr, OBJECT_IDX o_idx)
233 floor_type *floor_ptr = player_ptr->current_floor_ptr;
234 excise_object_idx(floor_ptr, o_idx);
235 j_ptr = &floor_ptr->o_list[o_idx];
236 if (!OBJECT_IS_HELD_MONSTER(j_ptr)) {
240 lite_spot(player_ptr, y, x);
248 * @brief 床上、モンスター所持でスタックされたアイテムを削除しスタックを補完する / Excise a dungeon object from any stacks
249 * @param floo_ptr 現在フロアへの参照ポインタ
250 * @param o_idx 削除対象のオブジェクト構造体ポインタ
253 void excise_object_idx(floor_type *floor_ptr, OBJECT_IDX o_idx)
255 OBJECT_IDX this_o_idx, next_o_idx = 0;
256 OBJECT_IDX prev_o_idx = 0;
258 j_ptr = &floor_ptr->o_list[o_idx];
260 if (OBJECT_IS_HELD_MONSTER(j_ptr)) {
262 m_ptr = &floor_ptr->m_list[j_ptr->held_m_idx];
263 for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) {
265 o_ptr = &floor_ptr->o_list[this_o_idx];
266 next_o_idx = o_ptr->next_o_idx;
267 if (this_o_idx != o_idx) {
268 prev_o_idx = this_o_idx;
272 if (prev_o_idx == 0) {
273 m_ptr->hold_o_idx = next_o_idx;
276 k_ptr = &floor_ptr->o_list[prev_o_idx];
277 k_ptr->next_o_idx = next_o_idx;
280 o_ptr->next_o_idx = 0;
288 POSITION y = j_ptr->iy;
289 POSITION x = j_ptr->ix;
290 g_ptr = &floor_ptr->grid_array[y][x];
291 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
293 o_ptr = &floor_ptr->o_list[this_o_idx];
294 next_o_idx = o_ptr->next_o_idx;
295 if (this_o_idx != o_idx) {
296 prev_o_idx = this_o_idx;
300 if (prev_o_idx == 0) {
301 g_ptr->o_idx = next_o_idx;
304 k_ptr = &floor_ptr->o_list[prev_o_idx];
305 k_ptr->next_o_idx = next_o_idx;
308 o_ptr->next_o_idx = 0;
314 * @brief 生成済のオブジェクトをフロアの所定の位置に落とす。
315 * Let an object fall to the ground at or near a location.
316 * @param owner_ptr プレーヤーへの参照ポインタ
317 * @param j_ptr 落としたいオブジェクト構造体の参照ポインタ
318 * @param chance ドロップの消滅率(%)
319 * @param y 配置したいフロアのY座標
320 * @param x 配置したいフロアのX座標
321 * @return 生成に成功したらオブジェクトのIDを返す。
323 * The initial location is assumed to be "in_bounds(floor_ptr, )".\n
325 * This function takes a parameter "chance". This is the percentage\n
326 * chance that the item will "disappear" instead of drop. If the object\n
327 * has been thrown, then this is the chance of disappearance on contact.\n
329 * Hack -- this function uses "chance" to determine if it should produce\n
330 * some form of "description" of the drop event (under the player).\n
332 * We check several locations to see if we can find a location at which\n
333 * the object can combine, stack, or be placed. Artifacts will try very\n
334 * hard to be placed, including "teleporting" to a useful grid if needed.\n
336 OBJECT_IDX drop_near(player_type *owner_ptr, object_type *j_ptr, PERCENTAGE chance, POSITION y, POSITION x)
341 OBJECT_IDX o_idx = 0;
342 OBJECT_IDX this_o_idx, next_o_idx = 0;
344 GAME_TEXT o_name[MAX_NLEN];
349 bool plural = (j_ptr->number != 1);
351 object_desc(owner_ptr, o_name, j_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
352 if (!object_is_artifact(j_ptr) && (randint0(100) < chance)) {
354 msg_format("%sは消えた。", o_name);
356 msg_format("The %s disappear%s.", o_name, (plural ? "" : "s"));
358 if (current_world_ptr->wizard)
359 msg_print(_("(破損)", "(breakage)"));
369 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
370 for (dy = -3; dy <= 3; dy++) {
371 for (dx = -3; dx <= 3; dx++) {
373 d = (dy * dy) + (dx * dx);
379 if (!in_bounds(floor_ptr, ty, tx))
381 if (!projectable(owner_ptr, y, x, ty, tx))
384 g_ptr = &floor_ptr->grid_array[ty][tx];
385 if (!cave_drop_bold(floor_ptr, ty, tx))
389 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
391 o_ptr = &floor_ptr->o_list[this_o_idx];
392 next_o_idx = o_ptr->next_o_idx;
393 if (object_similar(o_ptr, j_ptr))
404 s = 1000 - (d + k * 5);
411 if ((++bn >= 2) && !one_in_(bn))
422 if (!flag && !object_is_artifact(j_ptr)) {
424 msg_format("%sは消えた。", o_name);
426 msg_format("The %s disappear%s.", o_name, (plural ? "" : "s"));
428 if (current_world_ptr->wizard)
429 msg_print(_("(床スペースがない)", "(no floor space)"));
434 for (i = 0; !flag && (i < 1000); i++) {
435 ty = rand_spread(by, 1);
436 tx = rand_spread(bx, 1);
438 if (!in_bounds(floor_ptr, ty, tx))
444 if (!cave_drop_bold(floor_ptr, by, bx))
451 int candidates = 0, pick;
452 for (ty = 1; ty < floor_ptr->height - 1; ty++) {
453 for (tx = 1; tx < floor_ptr->width - 1; tx++) {
454 if (cave_drop_bold(floor_ptr, ty, tx))
461 msg_format("%sは消えた。", o_name);
463 msg_format("The %s disappear%s.", o_name, (plural ? "" : "s"));
466 if (current_world_ptr->wizard)
467 msg_print(_("(床スペースがない)", "(no floor space)"));
470 if (object_is_fixed_artifact(j_ptr) && !object_is_known(j_ptr)) {
471 a_info[j_ptr->name1].cur_num = 0;
478 pick = randint1(candidates);
479 for (ty = 1; ty < floor_ptr->height - 1; ty++) {
480 for (tx = 1; tx < floor_ptr->width - 1; tx++) {
481 if (cave_drop_bold(floor_ptr, ty, tx)) {
496 g_ptr = &floor_ptr->grid_array[by][bx];
497 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
499 o_ptr = &floor_ptr->o_list[this_o_idx];
500 next_o_idx = o_ptr->next_o_idx;
501 if (object_similar(o_ptr, j_ptr)) {
502 object_absorb(o_ptr, j_ptr);
509 o_idx = o_pop(floor_ptr);
511 if (!done && !o_idx) {
513 msg_format("%sは消えた。", o_name);
515 msg_format("The %s disappear%s.", o_name, (plural ? "" : "s"));
517 if (current_world_ptr->wizard)
518 msg_print(_("(アイテムが多過ぎる)", "(too many objects)"));
520 if (object_is_fixed_artifact(j_ptr)) {
521 a_info[j_ptr->name1].cur_num = 0;
528 object_copy(&floor_ptr->o_list[o_idx], j_ptr);
529 j_ptr = &floor_ptr->o_list[o_idx];
532 j_ptr->held_m_idx = 0;
533 j_ptr->next_o_idx = g_ptr->o_idx;
535 g_ptr->o_idx = o_idx;
539 note_spot(owner_ptr, by, bx);
540 lite_spot(owner_ptr, by, bx);
543 if (chance && player_bold(owner_ptr, by, bx)) {
544 msg_print(_("何かが足下に転がってきた。", "You feel something roll beneath your feet."));
551 * @brief 床上の魔道具の残り残量メッセージを表示する /
552 * Describe the charges on an item on the floor.
553 * @param floo_ptr 現在フロアへの参照ポインタ
554 * @param item メッセージの対象にしたいアイテム所持スロット
557 void floor_item_charges(floor_type *floor_ptr, INVENTORY_IDX item)
559 object_type *o_ptr = &floor_ptr->o_list[item];
560 if ((o_ptr->tval != TV_STAFF) && (o_ptr->tval != TV_WAND))
562 if (!object_is_known(o_ptr))
566 if (o_ptr->pval <= 0) {
567 msg_print("この床上のアイテムは、もう魔力が残っていない。");
569 msg_format("この床上のアイテムは、あと %d 回分の魔力が残っている。", o_ptr->pval);
572 if (o_ptr->pval != 1) {
573 msg_format("There are %d charges remaining.", o_ptr->pval);
575 msg_format("There is %d charge remaining.", o_ptr->pval);
581 * @brief 床上のアイテムの残り数メッセージを表示する /
582 * Describe the charges on an item on the floor.
583 * @param floo_ptr 現在フロアへの参照ポインタ
584 * @param item メッセージの対象にしたいアイテム所持スロット
587 void floor_item_describe(player_type *owner_ptr, INVENTORY_IDX item)
589 object_type *o_ptr = &owner_ptr->current_floor_ptr->o_list[item];
590 GAME_TEXT o_name[MAX_NLEN];
591 object_desc(owner_ptr, o_name, o_ptr, 0);
593 if (o_ptr->number <= 0) {
594 msg_format("床上には、もう%sはない。", o_name);
596 msg_format("床上には、まだ %sがある。", o_name);
599 msg_format("You see %s.", o_name);