OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / world / world-object.cpp
1 #include "world/world-object.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "object-enchant/item-apply-magic.h"
4 #include "object/tval-types.h"
5 #include "system/alloc-entries.h"
6 #include "system/baseitem-info.h"
7 #include "system/dungeon-info.h"
8 #include "system/floor-type-definition.h"
9 #include "system/item-entity.h"
10 #include "system/player-type-definition.h"
11 #include "util/probability-table.h"
12 #include "view/display-messages.h"
13 #include "world/world.h"
14 #include <iterator>
15
16 /*!
17  * @brief グローバルオブジェクト配列から空きを取得する /
18  * Acquires and returns the index of a "free" object.
19  * @param floo_ptr 現在フロアへの参照ポインタ
20  * @return 開いているオブジェクト要素のID
21  * @details
22  * This routine should almost never fail, but in case it does,
23  * we must be sure to handle "failure" of this routine.
24  */
25 OBJECT_IDX o_pop(FloorType *floor_ptr)
26 {
27     if (floor_ptr->o_max < w_ptr->max_o_idx) {
28         OBJECT_IDX i = floor_ptr->o_max;
29         floor_ptr->o_max++;
30         floor_ptr->o_cnt++;
31         return i;
32     }
33
34     for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
35         if (floor_ptr->o_list[i].is_valid()) {
36             continue;
37         }
38
39         floor_ptr->o_cnt++;
40         return i;
41     }
42
43     if (w_ptr->character_dungeon) {
44         msg_print(_("アイテムが多すぎる!", "Too many objects!"));
45     }
46
47     return 0;
48 }
49
50 /*!
51  * @brief オブジェクト生成テーブルからアイテムを取得する /
52  * Choose an object kind that seems "appropriate" to the given level
53  * @param player_ptr プレイヤーへの参照ポインタ
54  * @param level 生成階
55  * @return 選ばれたオブジェクトベースID
56  * @details
57  * This function uses the "prob2" field of the "object allocation table",\n
58  * and various local information, to calculate the "prob3" field of the\n
59  * same table, which is then used to choose an "appropriate" object, in\n
60  * a relatively efficient manner.\n
61  *\n
62  * It is (slightly) more likely to acquire an object of the given level\n
63  * than one of a lower level.  This is done by choosing several objects\n
64  * appropriate to the given level and keeping the "hardest" one.\n
65  *\n
66  * Note that if no objects are "appropriate", then this function will\n
67  * fail, and return zero, but this should *almost* never happen.\n
68  */
69 OBJECT_IDX get_obj_index(const FloorType *floor_ptr, DEPTH level, BIT_FLAGS mode)
70 {
71     if (level > MAX_DEPTH - 1) {
72         level = MAX_DEPTH - 1;
73     }
74
75     if ((level > 0) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::BEGINNER)) {
76         if (one_in_(CHANCE_BASEITEM_LEVEL_BOOST)) {
77             level = 1 + (level * MAX_DEPTH / randint1(MAX_DEPTH));
78         }
79     }
80
81     // 候補の確率テーブル生成
82     ProbabilityTable<int> prob_table;
83     for (auto i = 0U; i < alloc_kind_table.size(); i++) {
84         const auto &entry = alloc_kind_table[i];
85         if (entry.level > level) {
86             break;
87         }
88
89         const auto &baseitem = entry.get_baseitem();
90         if ((mode & AM_FORBID_CHEST) && (baseitem.bi_key.tval() == ItemKindType::CHEST)) {
91             continue;
92         }
93
94         prob_table.entry_item(i, entry.prob2);
95     }
96
97     // 候補なし
98     if (prob_table.empty()) {
99         return 0;
100     }
101
102     // 40%で1回、50%で2回、10%で3回抽選し、その中で一番レベルが高いアイテムを選択する
103     int n = 1;
104
105     const int p = randint0(100);
106     if (p < 60) {
107         n++;
108     }
109     if (p < 10) {
110         n++;
111     }
112
113     std::vector<int> result;
114     ProbabilityTable<int>::lottery(std::back_inserter(result), prob_table, n);
115
116     auto it = std::max_element(result.begin(), result.end(), [](int a, int b) { return alloc_kind_table[a].level < alloc_kind_table[b].level; });
117
118     return alloc_kind_table[*it].index;
119 }