OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / store / cmd-store.cpp
1 #include "cmd-io/macro-util.h"
2 #include "core/player-redraw-types.h"
3 #include "core/player-update-types.h"
4 #include "core/stuff-handler.h"
5 #include "core/window-redrawer.h"
6 #include "flavor/flavor-describer.h"
7 #include "floor/cave.h"
8 #include "floor/floor-events.h"
9 #include "floor/floor-town.h"
10 #include "floor/wild.h"
11 #include "game-option/birth-options.h"
12 #include "game-option/input-options.h"
13 #include "grid/feature.h"
14 #include "grid/grid.h"
15 #include "inventory/inventory-object.h"
16 #include "inventory/inventory-slot-types.h"
17 #include "io/input-key-requester.h"
18 #include "main/music-definitions-table.h"
19 #include "main/sound-of-music.h"
20 #include "object/object-generator.h"
21 #include "object/object-info.h"
22 #include "store/cmd-store.h"
23 #include "store/home.h"
24 #include "store/store-key-processor.h"
25 #include "store/store-util.h"
26 #include "store/store.h"
27 #include "system/floor-type-definition.h"
28 #include "term/screen-processor.h"
29 #include "view/display-messages.h"
30 #include "view/display-store.h"
31 #include "world/world.h"
32
33 #define MIN_STOCK 12
34
35 /*!
36  * @brief 店舗処理全体のメインルーチン /
37  * Enter a store, and interact with it. *
38  * @param player_ptr プレーヤーへの参照ポインタ
39  * @return なし
40  * @note
41  * <pre>
42  * Note that we use the standard "request_command()" function
43  * to get a command, allowing us to use "command_arg" and all
44  * command macros and other nifty stuff, but we use the special
45  * "shopping" argument, to force certain commands to be converted
46  * into other commands, normally, we convert "p" (pray) and "m"
47  * (cast magic) into "g" (get), and "s" (search) into "d" (drop).
48  * </pre>
49  */
50 void do_cmd_store(player_type *player_ptr)
51 {
52     if (player_ptr->wild_mode)
53         return;
54     TERM_LEN w, h;
55     term_get_size(&w, &h);
56
57     xtra_stock = MIN(14 + 26, ((h > 24) ? (h - 24) : 0));
58     store_bottom = MIN_STOCK + xtra_stock;
59
60     grid_type *g_ptr;
61     g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
62
63     if (!cave_has_flag_grid(g_ptr, FF_STORE)) {
64         msg_print(_("ここには店がありません。", "You see no store here."));
65         return;
66     }
67
68     // TODO:
69     //   施設の種類により、一時的に現在地 (player_ptr->town_num) を違う値に偽装して処理している。
70     //   我が家および博物館は全ての町で内容を共有するため、現在地を辺境の地 (1) にしている。
71     //   ダンジョン内の店の場合、現在地を NO_TOWN にしている。
72     //   inner_town_num は、施設内で C コマンドなどを使ったときにそのままでは現在地の偽装がバレる
73     //   ため、それを糊塗するためのグローバル変数。
74     //   この辺はリファクタしたい。
75     int which = f_info[g_ptr->feat].subtype;
76     old_town_num = player_ptr->town_num;
77     if ((which == STORE_HOME) || (which == STORE_MUSEUM))
78         player_ptr->town_num = 1;
79     if (is_in_dungeon(player_ptr))
80         player_ptr->town_num = NO_TOWN;
81     inner_town_num = player_ptr->town_num;
82
83     if ((town_info[player_ptr->town_num].store[which].store_open >= current_world_ptr->game_turn) || ironman_shops) {
84         msg_print(_("ドアに鍵がかかっている。", "The doors are locked."));
85         player_ptr->town_num = old_town_num;
86         return;
87     }
88
89     int maintain_num = (current_world_ptr->game_turn - town_info[player_ptr->town_num].store[which].last_visit) / (TURNS_PER_TICK * STORE_TICKS);
90     if (maintain_num > 10)
91         maintain_num = 10;
92     if (maintain_num) {
93         store_maintenance(player_ptr, player_ptr->town_num, which, maintain_num);
94
95         town_info[player_ptr->town_num].store[which].last_visit = current_world_ptr->game_turn;
96     }
97
98     forget_lite(player_ptr->current_floor_ptr);
99     forget_view(player_ptr->current_floor_ptr);
100     current_world_ptr->character_icky_depth = 1;
101     command_arg = 0;
102     command_rep = 0;
103     command_new = 0;
104     get_com_no_macros = TRUE;
105     cur_store_num = which;
106     cur_store_feat = g_ptr->feat;
107     st_ptr = &town_info[player_ptr->town_num].store[cur_store_num];
108     ot_ptr = &owners[cur_store_num][st_ptr->owner];
109     store_top = 0;
110     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_BUILD);
111     display_store(player_ptr);
112     leave_store = FALSE;
113
114     while (!leave_store) {
115         prt("", 1, 0);
116         clear_from(20 + xtra_stock);
117         prt(_(" ESC) 建物から出る", " ESC) Exit from Building."), 21 + xtra_stock, 0);
118         if (st_ptr->stock_num > store_bottom) {
119             prt(_(" -)前ページ", " -) Previous page"), 22 + xtra_stock, 0);
120             prt(_(" スペース) 次ページ", " SPACE) Next page"), 23 + xtra_stock, 0);
121         }
122
123         if (cur_store_num == STORE_HOME) {
124             prt(_("g) アイテムを取る", "g) Get an item."), 21 + xtra_stock, 27);
125             prt(_("d) アイテムを置く", "d) Drop an item."), 22 + xtra_stock, 27);
126             prt(_("x) 家のアイテムを調べる", "x) eXamine an item in the home."), 23 + xtra_stock, 27);
127         } else if (cur_store_num == STORE_MUSEUM) {
128             prt(_("d) アイテムを置く", "d) Drop an item."), 21 + xtra_stock, 27);
129             prt(_("r) アイテムの展示をやめる", "r) order to Remove an item."), 22 + xtra_stock, 27);
130             prt(_("x) 博物館のアイテムを調べる", "x) eXamine an item in the museum."), 23 + xtra_stock, 27);
131         } else {
132             prt(_("p) 商品を買う", "p) Purchase an item."), 21 + xtra_stock, 30);
133             prt(_("s) アイテムを売る", "s) Sell an item."), 22 + xtra_stock, 30);
134             prt(_("x) 商品を調べる", "x) eXamine an item in the shop"), 23 + xtra_stock, 30);
135         }
136
137         prt(_("i/e) 持ち物/装備の一覧", "i/e) Inventry/Equipment list"), 21 + xtra_stock, 56);
138         if (rogue_like_commands)
139             prt(_("w/T) 装備する/はずす", "w/T) Wear/Take off equipment"), 22 + xtra_stock, 56);
140         else
141             prt(_("w/t) 装備する/はずす", "w/t) Wear/Take off equipment"), 22 + xtra_stock, 56);
142
143         prt(_("コマンド:", "You may: "), 20 + xtra_stock, 0);
144         request_command(player_ptr, TRUE);
145         store_process_command(player_ptr);
146
147         bool need_redraw_store_inv = (player_ptr->update & PU_BONUS) ? TRUE : FALSE;
148         current_world_ptr->character_icky_depth = 1;
149         handle_stuff(player_ptr);
150         if (player_ptr->inventory_list[INVEN_PACK].k_idx) {
151             INVENTORY_IDX item = INVEN_PACK;
152             object_type *o_ptr = &player_ptr->inventory_list[item];
153             if (cur_store_num != STORE_HOME) {
154                 if (cur_store_num == STORE_MUSEUM)
155                     msg_print(_("ザックからアイテムがあふれそうなので、あわてて博物館から出た...", "Your pack is so full that you flee the Museum..."));
156                 else
157                     msg_print(_("ザックからアイテムがあふれそうなので、あわてて店から出た...", "Your pack is so full that you flee the store..."));
158
159                 leave_store = TRUE;
160             } else if (!store_check_num(o_ptr)) {
161                 msg_print(_("ザックからアイテムがあふれそうなので、あわてて家から出た...", "Your pack is so full that you flee your home..."));
162                 leave_store = TRUE;
163             } else {
164                 int item_pos;
165                 object_type forge;
166                 object_type *q_ptr;
167                 GAME_TEXT o_name[MAX_NLEN];
168                 msg_print(_("ザックからアイテムがあふれてしまった!", "Your pack overflows!"));
169                 q_ptr = &forge;
170                 object_copy(q_ptr, o_ptr);
171                 describe_flavor(player_ptr, o_name, q_ptr, 0);
172                 msg_format(_("%sが落ちた。(%c)", "You drop %s (%c)."), o_name, index_to_label(item));
173                 vary_item(player_ptr, item, -255);
174                 handle_stuff(player_ptr);
175
176                 item_pos = home_carry(player_ptr, q_ptr);
177                 if (item_pos >= 0) {
178                     store_top = (item_pos / store_bottom) * store_bottom;
179                     display_store_inventory(player_ptr);
180                 }
181             }
182         }
183
184         if (need_redraw_store_inv)
185             display_store_inventory(player_ptr);
186
187         if (st_ptr->store_open >= current_world_ptr->game_turn)
188             leave_store = TRUE;
189     }
190
191     // 現在地の偽装を解除。
192     player_ptr->town_num = old_town_num;
193
194     select_floor_music(player_ptr);
195     take_turn(player_ptr, 100);
196     current_world_ptr->character_icky_depth = 0;
197     command_new = 0;
198     command_see = FALSE;
199     get_com_no_macros = FALSE;
200
201     msg_erase();
202     term_clear();
203
204     player_ptr->update |= PU_VIEW | PU_LITE | PU_MON_LITE;
205     player_ptr->update |= PU_MONSTERS;
206     player_ptr->redraw |= PR_BASIC | PR_EXTRA | PR_EQUIPPY;
207     player_ptr->redraw |= PR_MAP;
208     player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
209 }