2 * @brief 町の施設処理 / Building commands
5 * Created by Ken Wigle for Kangband - a variant of Angband 2.8.3
8 * Rewritten for Kangband 2.8.3i using Kamband's version of
9 * building.c as written by Ivan Tkatchev
11 * Changed for ZAngband by Robert Ruehlmann
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/scores.h"
21 #include "core/show-file.h"
22 #include "core/special-internal-keys.h"
23 #include "core/stuff-handler.h"
24 #include "core/window-redrawer.h"
25 #include "floor/cave.h"
26 #include "floor/floor-events.h"
27 #include "floor/floor-mode-changer.h"
28 #include "floor/wild.h"
29 #include "io/input-key-acceptor.h"
30 #include "io/input-key-requester.h"
31 #include "main/music-definitions-table.h"
32 #include "main/sound-of-music.h"
33 #include "market/arena.h"
34 #include "market/bounty.h"
35 #include "market/building-actions-table.h"
36 #include "market/building-craft-armor.h"
37 #include "market/building-craft-fix.h"
38 #include "market/building-craft-weapon.h"
39 #include "market/building-enchanter.h"
40 #include "market/building-monster.h"
41 #include "market/building-quest.h"
42 #include "market/building-recharger.h"
43 #include "market/building-service.h"
44 #include "market/building-util.h"
45 #include "market/play-gamble.h"
46 #include "market/poker.h"
47 #include "monster-race/monster-race.h"
48 #include "mutation/mutation-flag-types.h"
49 #include "mutation/mutation-investor-remover.h"
50 #include "object-hook/hook-armor.h"
51 #include "object-hook/hook-weapon.h"
52 #include "object/item-tester-hooker.h"
53 #include "player-status/player-energy.h"
54 #include "player/player-personality-types.h"
55 #include "spell-kind/spells-perception.h"
56 #include "spell-kind/spells-world.h"
57 #include "spell/spells-status.h"
58 #include "system/angband-system.h"
59 #include "system/building-type-definition.h"
60 #include "system/floor-type-definition.h"
61 #include "system/grid-type-definition.h"
62 #include "system/item-entity.h"
63 #include "system/player-type-definition.h"
64 #include "system/redrawing-flags-updater.h"
65 #include "system/terrain-type-definition.h"
66 #include "term/gameterm.h"
67 #include "term/screen-processor.h"
68 #include "util/bit-flags-calculator.h"
69 #include "util/int-char-converter.h"
70 #include "view/display-messages.h"
71 #include "world/world.h"
78 bool reinit_wilderness = false;
81 * @brief 町に関するヘルプを表示する / Display town history
82 * @param player_ptr プレイヤーへの参照ポインタ
84 static void town_history(PlayerType *player_ptr)
87 (void)show_file(player_ptr, true, _("jbldg.txt", "bldg.txt"), 0, 0);
92 * @brief 施設の処理実行メインルーチン / Execute a building command
93 * @param player_ptr プレイヤーへの参照ポインタ
94 * @param bldg 施設構造体の参照ポインタ
95 * @param i 実行したい施設のサービステーブルの添字
97 static void bldg_process_command(PlayerType *player_ptr, building_type *bldg, int i)
101 const auto can_be_owner = is_owner(player_ptr, bldg);
102 const auto building_cost = can_be_owner ? bldg->member_costs[i] : bldg->other_costs[i];
103 if (((bldg->action_restr[i] == 1) && !is_member(player_ptr, bldg)) || ((bldg->action_restr[i] == 2) && !can_be_owner)) {
104 msg_print(_("それを選択する権利はありません!", "You have no right to choose that!"));
108 const auto building_action = bldg->actions[i];
109 if ((building_action != BACT_RECHARGE) && (((bldg->member_costs[i] > player_ptr->au) && can_be_owner) || ((bldg->other_costs[i] > player_ptr->au) && !can_be_owner))) {
110 msg_print(_("お金が足りません!", "You do not have the gold!"));
114 switch (building_action) {
118 case BACT_RESEARCH_ITEM:
119 if (identify_fully(player_ptr, false)) {
120 player_ptr->au -= building_cost;
124 case BACT_TOWN_HISTORY:
125 town_history(player_ptr);
127 case BACT_RACE_LEGENDS:
128 race_legends(player_ptr);
131 castle_quest(player_ptr);
133 case BACT_KING_LEGENDS:
134 case BACT_ARENA_LEGENDS:
136 show_highclass(player_ptr);
139 case BACT_ARENA_RULES:
141 arena_comm(player_ptr, building_action);
143 case BACT_IN_BETWEEN:
145 case BACT_SPIN_WHEEL:
146 case BACT_DICE_SLOTS:
147 case BACT_GAMBLE_RULES:
149 gamble_comm(player_ptr, building_action);
154 if (inn_comm(player_ptr, building_action)) {
155 player_ptr->au -= building_cost;
159 case BACT_RESEARCH_MONSTER:
160 if (research_mon(player_ptr)) {
161 player_ptr->au -= building_cost;
165 case BACT_COMPARE_WEAPONS:
166 player_ptr->au -= compare_weapons(player_ptr, building_cost);
168 case BACT_ENCHANT_WEAPON:
169 enchant_item(player_ptr, building_cost, 1, 1, 0, FuncItemTester(&ItemEntity::allow_enchant_melee_weapon));
171 case BACT_ENCHANT_ARMOR:
172 enchant_item(player_ptr, building_cost, 0, 0, 1, FuncItemTester(&ItemEntity::is_protector));
175 building_recharge(player_ptr);
177 case BACT_RECHARGE_ALL:
178 building_recharge_all(player_ptr);
181 if (!input_check(_("持ち物を全て鑑定してよろしいですか?", "Do you pay to identify all your possession? "))) {
185 identify_pack(player_ptr);
186 msg_print(_(" 持ち物全てが鑑定されました。", "Your possessions have been identified."));
187 player_ptr->au -= building_cost;
190 if (ident_spell(player_ptr, false)) {
191 player_ptr->au -= building_cost;
196 do_cmd_study(player_ptr);
199 if (cure_critical_wounds(player_ptr, 200)) {
200 player_ptr->au -= building_cost;
205 if (restore_all_status(player_ptr)) {
206 player_ptr->au -= building_cost;
210 case BACT_ENCHANT_ARROWS:
211 enchant_item(player_ptr, building_cost, 1, 1, 0, FuncItemTester(&ItemEntity::is_ammo));
213 case BACT_ENCHANT_BOW:
214 enchant_item(player_ptr, building_cost, 1, 1, 0, TvalItemTester(ItemKindType::BOW));
217 if (recall_player(player_ptr, 1)) {
218 player_ptr->au -= building_cost;
222 case BACT_TELEPORT_LEVEL:
225 if (free_level_recall(player_ptr)) {
226 player_ptr->au -= building_cost;
231 case BACT_LOSE_MUTATION: {
232 auto muta = player_ptr->muta;
233 if (player_ptr->ppersonality == PERSONALITY_LUCKY) {
234 // ラッキーマンの白オーラは突然変異治療の対象外
235 muta.reset(PlayerMutationType::GOOD_LUCK);
239 while (!lose_mutation(player_ptr, 0)) {
243 player_ptr->au -= building_cost;
247 msg_print(_("治すべき突然変異が無い。", "You have no mutations."));
252 monster_arena_comm(player_ptr);
254 case BACT_TSUCHINOKO:
261 today_target(player_ptr);
264 exchange_cash(player_ptr);
267 msg_print(_("平衡化の儀式を行なった。", "You received an equalization ritual."));
268 set_virtue(player_ptr, Virtue::COMPASSION, 0);
269 set_virtue(player_ptr, Virtue::HONOUR, 0);
270 set_virtue(player_ptr, Virtue::JUSTICE, 0);
271 set_virtue(player_ptr, Virtue::SACRIFICE, 0);
272 set_virtue(player_ptr, Virtue::KNOWLEDGE, 0);
273 set_virtue(player_ptr, Virtue::FAITH, 0);
274 set_virtue(player_ptr, Virtue::ENLIGHTEN, 0);
275 set_virtue(player_ptr, Virtue::ENCHANT, 0);
276 set_virtue(player_ptr, Virtue::CHANCE, 0);
277 set_virtue(player_ptr, Virtue::NATURE, 0);
278 set_virtue(player_ptr, Virtue::HARMONY, 0);
279 set_virtue(player_ptr, Virtue::VITALITY, 0);
280 set_virtue(player_ptr, Virtue::UNLIFE, 0);
281 set_virtue(player_ptr, Virtue::PATIENCE, 0);
282 set_virtue(player_ptr, Virtue::TEMPERANCE, 0);
283 set_virtue(player_ptr, Virtue::DILIGENCE, 0);
284 set_virtue(player_ptr, Virtue::VALOUR, 0);
285 set_virtue(player_ptr, Virtue::INDIVIDUALISM, 0);
286 initialize_virtues(player_ptr);
287 player_ptr->au -= building_cost;
290 if (tele_town(player_ptr)) {
291 player_ptr->au -= building_cost;
296 if (eval_ac(player_ptr->dis_ac + player_ptr->dis_to_a)) {
297 player_ptr->au -= building_cost;
301 case BACT_BROKEN_WEAPON:
302 player_ptr->au -= repair_broken_weapon(player_ptr, building_cost);
308 * @brief 施設入り口にプレイヤーが乗った際の処理 / Do building commands
309 * @param プレイヤーへの参照ポインタ
311 void do_cmd_building(PlayerType *player_ptr)
313 if (player_ptr->wild_mode) {
317 PlayerEnergy energy(player_ptr);
318 energy.set_player_turn_energy(100);
319 const auto p_pos = player_ptr->get_position();
320 if (!cave_has_flag_bold(player_ptr->current_floor_ptr, p_pos.y, p_pos.x, TerrainCharacteristics::BLDG)) {
321 msg_print(_("ここには建物はない。", "You see no building here."));
325 int which = player_ptr->current_floor_ptr->get_grid(p_pos).get_terrain().subtype;
328 bldg = &buildings[which];
330 reinit_wilderness = false;
332 if ((which == 2) && (player_ptr->arena_number < 0)) {
333 msg_print(_("「敗者に用はない。」", "'There's no place here for a LOSER like you!'"));
337 if ((which == 2) && player_ptr->current_floor_ptr->inside_arena) {
338 if (!player_ptr->exit_bldg && player_ptr->current_floor_ptr->m_cnt > 0) {
339 prt(_("ゲートは閉まっている。モンスターがあなたを待っている!", "The gates are closed. The monster awaits!"), 0, 0);
341 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_NO_RETURN);
342 player_ptr->current_floor_ptr->inside_arena = false;
343 player_ptr->leaving = true;
344 command_new = SPECIAL_KEY_BUILDING;
345 energy.reset_player_turn();
351 TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
353 auto &system = AngbandSystem::get_instance();
354 if (system.is_phase_out()) {
355 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_NO_RETURN);
356 player_ptr->leaving = true;
357 system.set_phase_out(false);
358 command_new = SPECIAL_KEY_BUILDING;
359 energy.reset_player_turn();
363 player_ptr->oldpy = player_ptr->y;
364 player_ptr->oldpx = player_ptr->x;
365 forget_lite(player_ptr->current_floor_ptr);
366 forget_view(player_ptr->current_floor_ptr);
367 w_ptr->character_icky_depth++;
373 display_buikding_service(player_ptr, bldg);
374 player_ptr->leave_bldg = false;
375 play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_BUILD);
378 while (!player_ptr->leave_bldg) {
382 building_prt_gold(player_ptr);
384 char command = inkey();
386 if (command == ESCAPE) {
387 player_ptr->leave_bldg = true;
388 player_ptr->current_floor_ptr->inside_arena = false;
389 system.set_phase_out(false);
394 for (i = 0; i < 8; i++) {
395 if (bldg->letters[i] && (bldg->letters[i] == command)) {
402 bldg_process_command(player_ptr, bldg, i);
405 handle_stuff(player_ptr);
408 select_floor_music(player_ptr);
413 if (reinit_wilderness) {
414 player_ptr->leaving = true;
417 w_ptr->character_icky_depth--;
420 auto &rfu = RedrawingFlagsUpdater::get_instance();
421 static constexpr auto flags_srf = {
422 StatusRecalculatingFlag::VIEW,
423 StatusRecalculatingFlag::MONSTER_STATUSES,
424 StatusRecalculatingFlag::BONUS,
425 StatusRecalculatingFlag::LITE,
426 StatusRecalculatingFlag::MONSTER_LITE,
428 rfu.set_flags(flags_srf);
429 static constexpr auto flags_mwrf = {
430 MainWindowRedrawingFlag::BASIC,
431 MainWindowRedrawingFlag::EXTRA,
432 MainWindowRedrawingFlag::EQUIPPY,
433 MainWindowRedrawingFlag::MAP,
435 rfu.set_flags(flags_mwrf);
436 static constexpr auto flags_swrf = {
437 SubWindowRedrawingFlag::OVERHEAD,
438 SubWindowRedrawingFlag::DUNGEON,
440 rfu.set_flags(flags_swrf);