OSDN Git Service

[Fix] トランプ魔術の塔の選択肢が消えてしまう
[hengbandforosx/hengbandosx.git] / src / cmd-building / cmd-building.cpp
1 /*!
2  * @brief 町の施設処理 / Building commands
3  * @date 2013/12/23
4  * @author
5  * Created by Ken Wigle for Kangband - a variant of Angband 2.8.3
6  * -KMW-
7  *
8  * Rewritten for Kangband 2.8.3i using Kamband's version of
9  * building.c as written by Ivan Tkatchev
10  *
11  * Changed for ZAngband by Robert Ruehlmann
12  */
13
14 #include "cmd-building/cmd-building.h"
15 #include "avatar/avatar.h"
16 #include "cmd-action/cmd-spell.h"
17 #include "cmd-building/cmd-inn.h"
18 #include "cmd-io/cmd-dump.h"
19 #include "core/asking-player.h"
20 #include "core/player-redraw-types.h"
21 #include "core/player-update-types.h"
22 #include "core/scores.h"
23 #include "core/show-file.h"
24 #include "core/special-internal-keys.h"
25 #include "core/stuff-handler.h"
26 #include "core/window-redrawer.h"
27 #include "floor/cave.h"
28 #include "floor/floor-events.h"
29 #include "floor/floor-mode-changer.h"
30 #include "floor/wild.h"
31 #include "io/input-key-acceptor.h"
32 #include "io/input-key-requester.h"
33 #include "main/music-definitions-table.h"
34 #include "main/sound-of-music.h"
35 #include "market/arena.h"
36 #include "market/bounty.h"
37 #include "market/building-actions-table.h"
38 #include "market/building-craft-armor.h"
39 #include "market/building-craft-fix.h"
40 #include "market/building-craft-weapon.h"
41 #include "market/building-enchanter.h"
42 #include "market/building-monster.h"
43 #include "market/building-quest.h"
44 #include "market/building-recharger.h"
45 #include "market/building-service.h"
46 #include "market/building-util.h"
47 #include "market/play-gamble.h"
48 #include "market/poker.h"
49 #include "monster-race/monster-race.h"
50 #include "mutation/mutation-flag-types.h"
51 #include "mutation/mutation-investor-remover.h"
52 #include "object-hook/hook-armor.h"
53 #include "object-hook/hook-weapon.h"
54 #include "object/item-tester-hooker.h"
55 #include "player-status/player-energy.h"
56 #include "player/player-personality-types.h"
57 #include "spell-kind/spells-perception.h"
58 #include "spell-kind/spells-world.h"
59 #include "spell/spells-status.h"
60 #include "system/building-type-definition.h"
61 #include "system/floor-type-definition.h"
62 #include "system/grid-type-definition.h"
63 #include "system/item-entity.h"
64 #include "system/player-type-definition.h"
65 #include "system/terrain-type-definition.h"
66 #include "term/screen-processor.h"
67 #include "util/bit-flags-calculator.h"
68 #include "util/int-char-converter.h"
69 #include "view/display-messages.h"
70 #include "world/world.h"
71
72 uint32_t mon_odds[4];
73 int battle_odds;
74 PRICE kakekin;
75 int sel_monster;
76
77 bool reinit_wilderness = false;
78
79 /*!
80  * @brief 町に関するヘルプを表示する / Display town history
81  * @param player_ptr プレイヤーへの参照ポインタ
82  */
83 static void town_history(PlayerType *player_ptr)
84 {
85     screen_save();
86     (void)show_file(player_ptr, true, _("jbldg.txt", "bldg.txt"), nullptr, 0, 0);
87     screen_load();
88 }
89
90 /*!
91  * @brief 施設の処理実行メインルーチン / Execute a building command
92  * @param player_ptr プレイヤーへの参照ポインタ
93  * @param bldg 施設構造体の参照ポインタ
94  * @param i 実行したい施設のサービステーブルの添字
95  */
96 static void bldg_process_command(PlayerType *player_ptr, building_type *bldg, int i)
97 {
98     msg_flag = false;
99     msg_erase();
100
101     PRICE bcost;
102     if (is_owner(player_ptr, bldg)) {
103         bcost = bldg->member_costs[i];
104     } else {
105         bcost = bldg->other_costs[i];
106     }
107
108     /* action restrictions */
109     if (((bldg->action_restr[i] == 1) && !is_member(player_ptr, bldg)) || ((bldg->action_restr[i] == 2) && !is_owner(player_ptr, bldg))) {
110         msg_print(_("それを選択する権利はありません!", "You have no right to choose that!"));
111         return;
112     }
113
114     auto bact = bldg->actions[i];
115     if ((bact != BACT_RECHARGE) && (((bldg->member_costs[i] > player_ptr->au) && is_owner(player_ptr, bldg)) || ((bldg->other_costs[i] > player_ptr->au) && !is_owner(player_ptr, bldg)))) {
116         msg_print(_("お金が足りません!", "You do not have the gold!"));
117         return;
118     }
119
120     bool paid = false;
121     switch (bact) {
122     case BACT_NOTHING:
123         /* Do nothing */
124         break;
125     case BACT_RESEARCH_ITEM:
126         paid = identify_fully(player_ptr, false);
127         break;
128     case BACT_TOWN_HISTORY:
129         town_history(player_ptr);
130         break;
131     case BACT_RACE_LEGENDS:
132         race_legends(player_ptr);
133         break;
134     case BACT_QUEST:
135         castle_quest(player_ptr);
136         break;
137     case BACT_KING_LEGENDS:
138     case BACT_ARENA_LEGENDS:
139     case BACT_LEGENDS:
140         show_highclass(player_ptr);
141         break;
142     case BACT_POSTER:
143     case BACT_ARENA_RULES:
144     case BACT_ARENA:
145         arena_comm(player_ptr, bact);
146         break;
147     case BACT_IN_BETWEEN:
148     case BACT_CRAPS:
149     case BACT_SPIN_WHEEL:
150     case BACT_DICE_SLOTS:
151     case BACT_GAMBLE_RULES:
152     case BACT_POKER:
153         gamble_comm(player_ptr, bact);
154         break;
155     case BACT_REST:
156     case BACT_RUMORS:
157     case BACT_FOOD:
158         paid = inn_comm(player_ptr, bact);
159         break;
160     case BACT_RESEARCH_MONSTER:
161         paid = research_mon(player_ptr);
162         break;
163     case BACT_COMPARE_WEAPONS:
164         paid = true;
165         bcost = compare_weapons(player_ptr, bcost);
166         break;
167     case BACT_ENCHANT_WEAPON:
168         enchant_item(player_ptr, bcost, 1, 1, 0, FuncItemTester(&ItemEntity::allow_enchant_melee_weapon));
169         break;
170     case BACT_ENCHANT_ARMOR:
171         enchant_item(player_ptr, bcost, 0, 0, 1, FuncItemTester(&ItemEntity::is_protector));
172         break;
173     case BACT_RECHARGE:
174         building_recharge(player_ptr);
175         break;
176     case BACT_RECHARGE_ALL:
177         building_recharge_all(player_ptr);
178         break;
179     case BACT_IDENTS:
180         if (!get_check(_("持ち物を全て鑑定してよろしいですか?", "Do you pay to identify all your possession? "))) {
181             break;
182         }
183         identify_pack(player_ptr);
184         msg_print(_(" 持ち物全てが鑑定されました。", "Your possessions have been identified."));
185         paid = true;
186         break;
187     case BACT_IDENT_ONE:
188         paid = ident_spell(player_ptr, false);
189         break;
190     case BACT_LEARN:
191         do_cmd_study(player_ptr);
192         break;
193     case BACT_HEALING:
194         paid = cure_critical_wounds(player_ptr, 200);
195         break;
196     case BACT_RESTORE:
197         paid = restore_all_status(player_ptr);
198         break;
199     case BACT_ENCHANT_ARROWS:
200         enchant_item(player_ptr, bcost, 1, 1, 0, FuncItemTester(&ItemEntity::is_ammo));
201         break;
202     case BACT_ENCHANT_BOW:
203         enchant_item(player_ptr, bcost, 1, 1, 0, TvalItemTester(ItemKindType::BOW));
204         break;
205
206     case BACT_RECALL:
207         if (recall_player(player_ptr, 1)) {
208             paid = true;
209         }
210         break;
211
212     case BACT_TELEPORT_LEVEL:
213         screen_save();
214         clear_bldg(4, 20);
215         paid = free_level_recall(player_ptr);
216         screen_load();
217         break;
218
219     case BACT_LOSE_MUTATION: {
220         auto muta = player_ptr->muta;
221         if (player_ptr->ppersonality == PERSONALITY_LUCKY) {
222             // ラッキーマンの白オーラは突然変異治療の対象外
223             muta.reset(PlayerMutationType::GOOD_LUCK);
224         }
225         if (muta.any()) {
226             while (!lose_mutation(player_ptr, 0)) {
227                 ;
228             }
229             paid = true;
230             break;
231         }
232
233         msg_print(_("治すべき突然変異が無い。", "You have no mutations."));
234         msg_print(nullptr);
235         break;
236     }
237
238     case BACT_BATTLE:
239         monster_arena_comm(player_ptr);
240         break;
241
242     case BACT_TSUCHINOKO:
243         tsuchinoko();
244         break;
245
246     case BACT_BOUNTY:
247         show_bounty();
248         break;
249
250     case BACT_TARGET:
251         today_target(player_ptr);
252         break;
253
254     case BACT_KANKIN:
255         exchange_cash(player_ptr);
256         break;
257
258     case BACT_HEIKOUKA:
259         msg_print(_("平衡化の儀式を行なった。", "You received an equalization ritual."));
260         set_virtue(player_ptr, V_COMPASSION, 0);
261         set_virtue(player_ptr, V_HONOUR, 0);
262         set_virtue(player_ptr, V_JUSTICE, 0);
263         set_virtue(player_ptr, V_SACRIFICE, 0);
264         set_virtue(player_ptr, V_KNOWLEDGE, 0);
265         set_virtue(player_ptr, V_FAITH, 0);
266         set_virtue(player_ptr, V_ENLIGHTEN, 0);
267         set_virtue(player_ptr, V_ENCHANT, 0);
268         set_virtue(player_ptr, V_CHANCE, 0);
269         set_virtue(player_ptr, V_NATURE, 0);
270         set_virtue(player_ptr, V_HARMONY, 0);
271         set_virtue(player_ptr, V_VITALITY, 0);
272         set_virtue(player_ptr, V_UNLIFE, 0);
273         set_virtue(player_ptr, V_PATIENCE, 0);
274         set_virtue(player_ptr, V_TEMPERANCE, 0);
275         set_virtue(player_ptr, V_DILIGENCE, 0);
276         set_virtue(player_ptr, V_VALOUR, 0);
277         set_virtue(player_ptr, V_INDIVIDUALISM, 0);
278         initialize_virtues(player_ptr);
279         paid = true;
280         break;
281
282     case BACT_TELE_TOWN:
283         paid = tele_town(player_ptr);
284         break;
285
286     case BACT_EVAL_AC:
287         paid = eval_ac(player_ptr->dis_ac + player_ptr->dis_to_a);
288         break;
289
290     case BACT_BROKEN_WEAPON:
291         paid = true;
292         bcost = repair_broken_weapon(player_ptr, bcost);
293         break;
294     }
295
296     if (paid) {
297         player_ptr->au -= bcost;
298     }
299 }
300
301 /*!
302  * @brief 施設入り口にプレイヤーが乗った際の処理 / Do building commands
303  * @param プレイヤーへの参照ポインタ
304  */
305 void do_cmd_building(PlayerType *player_ptr)
306 {
307     if (player_ptr->wild_mode) {
308         return;
309     }
310
311     PlayerEnergy energy(player_ptr);
312     energy.set_player_turn_energy(100);
313
314     if (!cave_has_flag_bold(player_ptr->current_floor_ptr, player_ptr->y, player_ptr->x, TerrainCharacteristics::BLDG)) {
315         msg_print(_("ここには建物はない。", "You see no building here."));
316         return;
317     }
318
319     int which = terrains_info[player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat].subtype;
320
321     building_type *bldg;
322     bldg = &building[which];
323
324     reinit_wilderness = false;
325
326     if ((which == 2) && (player_ptr->arena_number < 0)) {
327         msg_print(_("「敗者に用はない。」", "'There's no place here for a LOSER like you!'"));
328         return;
329     } else if ((which == 2) && player_ptr->current_floor_ptr->inside_arena) {
330         if (!player_ptr->exit_bldg && player_ptr->current_floor_ptr->m_cnt > 0) {
331             prt(_("ゲートは閉まっている。モンスターがあなたを待っている!", "The gates are closed.  The monster awaits!"), 0, 0);
332         } else {
333             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_NO_RETURN);
334             player_ptr->current_floor_ptr->inside_arena = false;
335             player_ptr->leaving = true;
336             command_new = SPECIAL_KEY_BUILDING;
337             energy.reset_player_turn();
338         }
339
340         return;
341     } else if (player_ptr->phase_out) {
342         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_NO_RETURN);
343         player_ptr->leaving = true;
344         player_ptr->phase_out = false;
345         command_new = SPECIAL_KEY_BUILDING;
346         energy.reset_player_turn();
347         return;
348     } else {
349         player_ptr->oldpy = player_ptr->y;
350         player_ptr->oldpx = player_ptr->x;
351     }
352
353     forget_lite(player_ptr->current_floor_ptr);
354     forget_view(player_ptr->current_floor_ptr);
355     w_ptr->character_icky_depth++;
356
357     command_arg = 0;
358     command_rep = 0;
359     command_new = 0;
360
361     display_buikding_service(player_ptr, bldg);
362     player_ptr->leave_bldg = false;
363     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_BUILD);
364
365     bool validcmd;
366     while (!player_ptr->leave_bldg) {
367         validcmd = false;
368         prt("", 1, 0);
369
370         building_prt_gold(player_ptr);
371
372         char command = inkey();
373
374         if (command == ESCAPE) {
375             player_ptr->leave_bldg = true;
376             player_ptr->current_floor_ptr->inside_arena = false;
377             player_ptr->phase_out = false;
378             break;
379         }
380
381         int i;
382         for (i = 0; i < 8; i++) {
383             if (bldg->letters[i] && (bldg->letters[i] == command)) {
384                 validcmd = true;
385                 break;
386             }
387         }
388
389         if (validcmd) {
390             bldg_process_command(player_ptr, bldg, i);
391         }
392
393         handle_stuff(player_ptr);
394     }
395
396     select_floor_music(player_ptr);
397
398     msg_flag = false;
399     msg_erase();
400
401     if (reinit_wilderness) {
402         player_ptr->leaving = true;
403     }
404
405     w_ptr->character_icky_depth--;
406     term_clear();
407
408     player_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_BONUS | PU_LITE | PU_MON_LITE);
409     player_ptr->redraw |= (PR_BASIC | PR_EXTRA | PR_EQUIPPY | PR_MAP);
410     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
411 }