1 #include "store/cmd-store.h"
2 #include "cmd-io/macro-util.h"
3 #include "core/player-redraw-types.h"
4 #include "core/player-update-types.h"
5 #include "core/stuff-handler.h"
6 #include "core/window-redrawer.h"
7 #include "dungeon/dungeon.h"
8 #include "flavor/flavor-describer.h"
9 #include "floor/cave.h"
10 #include "floor/floor-events.h"
11 #include "floor/floor-town.h"
12 #include "floor/wild.h"
13 #include "game-option/birth-options.h"
14 #include "game-option/input-options.h"
15 #include "grid/feature.h"
16 #include "inventory/inventory-object.h"
17 #include "inventory/inventory-slot-types.h"
18 #include "io/input-key-requester.h"
19 #include "main/music-definitions-table.h"
20 #include "main/sound-of-music.h"
21 #include "object/object-info.h"
22 #include "player-status/player-energy.h"
23 #include "store/home.h"
24 #include "store/store-key-processor.h"
25 #include "store/store-owners.h"
26 #include "store/store-util.h"
27 #include "store/store.h"
28 #include "system/floor-type-definition.h"
29 #include "system/grid-type-definition.h"
30 #include "system/object-type-definition.h"
31 #include "system/player-type-definition.h"
32 #include "term/screen-processor.h"
33 #include "util/bit-flags-calculator.h"
34 #include "view/display-messages.h"
35 #include "view/display-store.h"
36 #include "world/world.h"
41 * @brief 店舗処理全体のメインルーチン /
42 * Enter a store, and interact with it. *
43 * @param player_ptr プレイヤーへの参照ポインタ
46 * Note that we use the standard "request_command()" function
47 * to get a command, allowing us to use "command_arg" and all
48 * command macros and other nifty stuff, but we use the special
49 * "shopping" argument, to force certain commands to be converted
50 * into other commands, normally, we convert "p" (pray) and "m"
51 * (cast magic) into "g" (get), and "s" (search) into "d" (drop).
54 void do_cmd_store(PlayerType *player_ptr)
56 if (player_ptr->wild_mode) {
60 term_get_size(&w, &h);
62 xtra_stock = std::min(14 + 26, ((h > 24) ? (h - 24) : 0));
63 store_bottom = MIN_STOCK + xtra_stock;
66 g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
68 if (!g_ptr->cave_has_flag(FloorFeatureType::STORE)) {
69 msg_print(_("ここには店がありません。", "You see no store here."));
74 // 施設の種類により、一時的に現在地 (player_ptr->town_num) を違う値に偽装して処理している。
75 // 我が家および博物館は全ての町で内容を共有するため、現在地を辺境の地 (1) にしている。
76 // ダンジョン内の店の場合、現在地を NO_TOWN にしている。
77 // inner_town_num は、施設内で C コマンドなどを使ったときにそのままでは現在地の偽装がバレる
78 // ため、それを糊塗するためのグローバル変数。
80 StoreSaleType which = i2enum<StoreSaleType>(f_info[g_ptr->feat].subtype);
81 old_town_num = player_ptr->town_num;
82 if ((which == StoreSaleType::HOME) || (which == StoreSaleType::MUSEUM)) {
83 player_ptr->town_num = 1;
85 if (is_in_dungeon(player_ptr)) {
86 player_ptr->town_num = NO_TOWN;
88 inner_town_num = player_ptr->town_num;
90 if ((town_info[player_ptr->town_num].store[enum2i(which)].store_open >= w_ptr->game_turn) || ironman_shops) {
91 msg_print(_("ドアに鍵がかかっている。", "The doors are locked."));
92 player_ptr->town_num = old_town_num;
96 int maintain_num = (w_ptr->game_turn - town_info[player_ptr->town_num].store[enum2i(which)].last_visit) / (TURNS_PER_TICK * STORE_TICKS);
97 if (maintain_num > 10) {
101 store_maintenance(player_ptr, player_ptr->town_num, which, maintain_num);
103 town_info[player_ptr->town_num].store[enum2i(which)].last_visit = w_ptr->game_turn;
106 forget_lite(player_ptr->current_floor_ptr);
107 forget_view(player_ptr->current_floor_ptr);
108 w_ptr->character_icky_depth = 1;
112 get_com_no_macros = true;
113 cur_store_num = which;
114 cur_store_feat = g_ptr->feat;
115 st_ptr = &town_info[player_ptr->town_num].store[enum2i(cur_store_num)];
116 ot_ptr = &owners.at(cur_store_num)[st_ptr->owner];
118 play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_BUILD);
119 display_store(player_ptr);
122 while (!leave_store) {
124 clear_from(20 + xtra_stock);
125 prt(_(" ESC) 建物から出る", " ESC) Exit from Building."), 21 + xtra_stock, 0);
126 if (st_ptr->stock_num > store_bottom) {
127 prt(_(" -)前ページ", " -) Previous page"), 22 + xtra_stock, 0);
128 prt(_(" スペース) 次ページ", " SPACE) Next page"), 23 + xtra_stock, 0);
131 if (cur_store_num == StoreSaleType::HOME) {
132 prt(_("g) アイテムを取る", "g) Get an item."), 21 + xtra_stock, 27);
133 prt(_("d) アイテムを置く", "d) Drop an item."), 22 + xtra_stock, 27);
134 prt(_("x) 家のアイテムを調べる", "x) eXamine an item in the home."), 23 + xtra_stock, 27);
135 } else if (cur_store_num == StoreSaleType::MUSEUM) {
136 prt(_("d) アイテムを置く", "d) Drop an item."), 21 + xtra_stock, 27);
137 prt(_("r) アイテムの展示をやめる", "r) order to Remove an item."), 22 + xtra_stock, 27);
138 prt(_("x) 博物館のアイテムを調べる", "x) eXamine an item in the museum."), 23 + xtra_stock, 27);
140 prt(_("p) 商品を買う", "p) Purchase an item."), 21 + xtra_stock, 30);
141 prt(_("s) アイテムを売る", "s) Sell an item."), 22 + xtra_stock, 30);
142 prt(_("x) 商品を調べる", "x) eXamine an item in the shop"), 23 + xtra_stock, 30);
145 prt(_("i/e) 持ち物/装備の一覧", "i/e) Inventry/Equipment list"), 21 + xtra_stock, 56);
146 if (rogue_like_commands) {
147 prt(_("w/T) 装備する/はずす", "w/T) Wear/Take off equipment"), 22 + xtra_stock, 56);
149 prt(_("w/t) 装備する/はずす", "w/t) Wear/Take off equipment"), 22 + xtra_stock, 56);
152 prt(_("コマンド:", "You may: "), 20 + xtra_stock, 0);
153 InputKeyRequestor(player_ptr, true).request_command();
154 store_process_command(player_ptr);
156 bool need_redraw_store_inv = any_bits(player_ptr->update, PU_BONUS);
157 w_ptr->character_icky_depth = 1;
158 handle_stuff(player_ptr);
159 if (player_ptr->inventory_list[INVEN_PACK].k_idx) {
160 INVENTORY_IDX item = INVEN_PACK;
161 auto *o_ptr = &player_ptr->inventory_list[item];
162 if (cur_store_num != StoreSaleType::HOME) {
163 if (cur_store_num == StoreSaleType::MUSEUM) {
164 msg_print(_("ザックからアイテムがあふれそうなので、あわてて博物館から出た...", "Your pack is so full that you flee the Museum..."));
166 msg_print(_("ザックからアイテムがあふれそうなので、あわてて店から出た...", "Your pack is so full that you flee the store..."));
170 } else if (!store_check_num(o_ptr)) {
171 msg_print(_("ザックからアイテムがあふれそうなので、あわてて家から出た...", "Your pack is so full that you flee your home..."));
177 GAME_TEXT o_name[MAX_NLEN];
178 msg_print(_("ザックからアイテムがあふれてしまった!", "Your pack overflows!"));
180 q_ptr->copy_from(o_ptr);
181 describe_flavor(player_ptr, o_name, q_ptr, 0);
182 msg_format(_("%sが落ちた。(%c)", "You drop %s (%c)."), o_name, index_to_label(item));
183 vary_item(player_ptr, item, -255);
184 handle_stuff(player_ptr);
186 item_pos = home_carry(player_ptr, q_ptr);
188 store_top = (item_pos / store_bottom) * store_bottom;
189 display_store_inventory(player_ptr);
194 if (need_redraw_store_inv) {
195 display_store_inventory(player_ptr);
198 if (st_ptr->store_open >= w_ptr->game_turn) {
204 player_ptr->town_num = old_town_num;
206 select_floor_music(player_ptr);
207 PlayerEnergy(player_ptr).set_player_turn_energy(100);
208 w_ptr->character_icky_depth = 0;
211 get_com_no_macros = false;
216 player_ptr->update |= PU_VIEW | PU_LITE | PU_MON_LITE;
217 player_ptr->update |= PU_MONSTERS;
218 player_ptr->redraw |= PR_BASIC | PR_EXTRA | PR_EQUIPPY;
219 player_ptr->redraw |= PR_MAP;
220 player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;