OSDN Git Service

[Refactor] ボール系魔法のコピペを低減
[hengbandforosx/hengbandosx.git] / src / store / home.cpp
1 #include "store/home.h"
2 #include "avatar/avatar.h"
3 #include "floor/floor-town.h"
4 #include "game-option/birth-options.h"
5 #include "game-option/game-play-options.h"
6 #include "object/object-stack.h"
7 #include "object/object-value.h"
8 #include "object/tval-types.h"
9 #include "store/store-util.h"
10 #include "system/object-type-definition.h"
11 #include "system/player-type-definition.h"
12 #include "util/object-sort.h"
13
14 /*!
15  * @brief 我が家にオブジェクトを加える /
16  * Add the item "o_ptr" to the inventory of the "Home"
17  * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ
18  * @return 収めた先のID
19  * @details
20  * <pre>
21  * In all cases, return the slot (or -1) where the object was placed
22  * Note that this is a hacked up version of "store_item_to_inventory()".
23  * Also note that it may not correctly "adapt" to "knowledge" bacoming
24  * known, the player may have to pick stuff up and drop it again.
25  * </pre>
26  */
27 int home_carry(PlayerType *player_ptr, ObjectType *o_ptr, StoreSaleType store_num)
28 {
29     bool old_stack_force_notes = stack_force_notes;
30     bool old_stack_force_costs = stack_force_costs;
31     if (store_num != StoreSaleType::HOME) {
32         stack_force_notes = false;
33         stack_force_costs = false;
34     }
35
36     for (int slot = 0; slot < st_ptr->stock_num; slot++) {
37         ObjectType *j_ptr;
38         j_ptr = &st_ptr->stock[slot];
39         if (object_similar(j_ptr, o_ptr)) {
40             object_absorb(j_ptr, o_ptr);
41             if (store_num != StoreSaleType::HOME) {
42                 stack_force_notes = old_stack_force_notes;
43                 stack_force_costs = old_stack_force_costs;
44             }
45
46             return slot;
47         }
48     }
49
50     if (store_num != StoreSaleType::HOME) {
51         stack_force_notes = old_stack_force_notes;
52         stack_force_costs = old_stack_force_costs;
53     }
54
55     /* No space? */
56     /*
57      * 隠し機能: オプション powerup_home が設定されていると
58      *           我が家が 20 ページまで使える
59      */
60     if ((store_num != StoreSaleType::HOME) || powerup_home) {
61         if (st_ptr->stock_num >= st_ptr->stock_size) {
62             return -1;
63         }
64     } else {
65         if (st_ptr->stock_num >= ((st_ptr->stock_size) / 10)) {
66             return -1;
67         }
68     }
69
70     PRICE value = object_value(o_ptr);
71     int slot;
72     for (slot = 0; slot < st_ptr->stock_num; slot++) {
73         if (object_sort_comp(player_ptr, o_ptr, value, &st_ptr->stock[slot])) {
74             break;
75         }
76     }
77
78     for (int i = st_ptr->stock_num; i > slot; i--) {
79         st_ptr->stock[i] = st_ptr->stock[i - 1];
80     }
81
82     st_ptr->stock_num++;
83     st_ptr->stock[slot] = *o_ptr;
84     chg_virtue(player_ptr, V_SACRIFICE, -1);
85     (void)combine_and_reorder_home(player_ptr, store_num);
86     return slot;
87 }
88
89 static bool exe_combine_store_items(ObjectType *o_ptr, ObjectType *j_ptr, const int max_num, const int i, bool *combined)
90 {
91     if (o_ptr->number + j_ptr->number > max_num) {
92         return false;
93     }
94
95     object_absorb(j_ptr, o_ptr);
96     st_ptr->stock_num--;
97     int k;
98     for (k = i; k < st_ptr->stock_num; k++) {
99         st_ptr->stock[k] = st_ptr->stock[k + 1];
100     }
101
102     (&st_ptr->stock[k])->wipe();
103     *combined = true;
104     return true;
105 }
106
107 static void sweep_reorder_store_item(ObjectType *o_ptr, const int i, bool *combined)
108 {
109     for (int j = 0; j < i; j++) {
110         ObjectType *j_ptr;
111         j_ptr = &st_ptr->stock[j];
112         if (!j_ptr->k_idx) {
113             continue;
114         }
115
116         int max_num = object_similar_part(j_ptr, o_ptr);
117         if (max_num == 0 || j_ptr->number >= max_num) {
118             continue;
119         }
120
121         if (exe_combine_store_items(o_ptr, j_ptr, max_num, i, combined)) {
122             break;
123         }
124
125         ITEM_NUMBER old_num = o_ptr->number;
126         ITEM_NUMBER remain = j_ptr->number + o_ptr->number - max_num;
127         object_absorb(j_ptr, o_ptr);
128         o_ptr->number = remain;
129         if (o_ptr->tval == ItemKindType::ROD) {
130             o_ptr->pval = o_ptr->pval * remain / old_num;
131             o_ptr->timeout = o_ptr->timeout * remain / old_num;
132         } else if (o_ptr->tval == ItemKindType::WAND) {
133             o_ptr->pval = o_ptr->pval * remain / old_num;
134         }
135
136         *combined = true;
137         break;
138     }
139 }
140
141 static void exe_reorder_store_item(PlayerType *player_ptr, bool *flag)
142 {
143     for (int i = 0; i < st_ptr->stock_num; i++) {
144         ObjectType *o_ptr;
145         o_ptr = &st_ptr->stock[i];
146         if (!o_ptr->k_idx) {
147             continue;
148         }
149
150         int32_t o_value = object_value(o_ptr);
151         int j;
152         for (j = 0; j < st_ptr->stock_num; j++) {
153             if (object_sort_comp(player_ptr, o_ptr, o_value, &st_ptr->stock[j])) {
154                 break;
155             }
156         }
157
158         if (j >= i) {
159             continue;
160         }
161
162         *flag = true;
163         ObjectType *j_ptr;
164         ObjectType forge;
165         j_ptr = &forge;
166         j_ptr->copy_from(&st_ptr->stock[i]);
167         for (int k = i; k > j; k--) {
168             (&st_ptr->stock[k])->copy_from(&st_ptr->stock[k - 1]);
169         }
170
171         (&st_ptr->stock[j])->copy_from(j_ptr);
172     }
173 }
174
175 /*!
176  * @brief 現在の町の指定された店舗のアイテムを整理する /
177  * Combine and reorder items in store.
178  * @param store_num 店舗ID
179  * @return 実際に整理が行われたならばTRUEを返す。
180  */
181 bool combine_and_reorder_home(PlayerType *player_ptr, const StoreSaleType store_num)
182 {
183     bool old_stack_force_notes = stack_force_notes;
184     bool old_stack_force_costs = stack_force_costs;
185     store_type *old_st_ptr = st_ptr;
186     st_ptr = &town_info[1].store[enum2i(store_num)];
187     bool flag = false;
188     if (store_num != StoreSaleType::HOME) {
189         stack_force_notes = false;
190         stack_force_costs = false;
191     }
192
193     bool combined = true;
194     while (combined) {
195         combined = false;
196         for (int i = st_ptr->stock_num - 1; i > 0; i--) {
197             ObjectType *o_ptr;
198             o_ptr = &st_ptr->stock[i];
199             if (!o_ptr->k_idx) {
200                 continue;
201             }
202
203             sweep_reorder_store_item(o_ptr, i, &combined);
204         }
205
206         flag |= combined;
207     }
208
209     exe_reorder_store_item(player_ptr, &flag);
210     st_ptr = old_st_ptr;
211     if (store_num != StoreSaleType::HOME) {
212         stack_force_notes = old_stack_force_notes;
213         stack_force_costs = old_stack_force_costs;
214     }
215
216     return flag;
217 }