OSDN Git Service

d4db1e8d6a560070a8f961dce0f08cdfa04ccf2b
[hengbandforosx/hengbandosx.git] / src / object-use / read-execution.cpp
1 /*!
2  * @brief 巻物を読んだ際の効果処理
3  * @date 2020/07/23
4  * @author Hourier
5  * @todo 長い、要分割
6  */
7
8 #include "object-use/read-execution.h"
9 #include "action/action-limited.h"
10 #include "artifact/fixed-art-types.h"
11 #include "avatar/avatar.h"
12 #include "core/player-redraw-types.h"
13 #include "core/player-update-types.h"
14 #include "core/show-file.h"
15 #include "core/window-redrawer.h"
16 #include "flavor/flavor-describer.h"
17 #include "flavor/object-flavor-types.h"
18 #include "inventory/inventory-object.h"
19 #include "inventory/inventory-slot-types.h"
20 #include "io/files-util.h"
21 #include "main/sound-definitions-table.h"
22 #include "main/sound-of-music.h"
23 #include "monster-floor/monster-summon.h"
24 #include "monster-floor/place-monster-types.h"
25 #include "object-use/item-use-checker.h"
26 #include "object/object-info.h"
27 #include "object/object-kind.h"
28 #include "perception/object-perception.h"
29 #include "player-info/equipment-info.h"
30 #include "player-status/player-energy.h"
31 #include "player/attack-defense-types.h"
32 #include "player/digestion-processor.h"
33 #include "player/player-damage.h"
34 #include "player/player-status-flags.h"
35 #include "spell-kind/magic-item-recharger.h"
36 #include "spell-kind/spells-curse-removal.h"
37 #include "spell-kind/spells-detection.h"
38 #include "spell-kind/spells-enchant.h"
39 #include "spell-kind/spells-floor.h"
40 #include "spell-kind/spells-genocide.h"
41 #include "spell-kind/spells-grid.h"
42 #include "spell-kind/spells-launcher.h"
43 #include "spell-kind/spells-lite.h"
44 #include "spell-kind/spells-neighbor.h"
45 #include "spell-kind/spells-perception.h"
46 #include "spell-kind/spells-sight.h"
47 #include "spell-kind/spells-teleport.h"
48 #include "spell-kind/spells-world.h"
49 #include "spell-realm/spells-hex.h"
50 #include "spell-realm/spells-song.h"
51 #include "spell/spell-types.h"
52 #include "spell/spells-object.h"
53 #include "spell/spells-summon.h"
54 #include "spell/summon-types.h"
55 #include "status/bad-status-setter.h"
56 #include "status/body-improvement.h"
57 #include "status/buff-setter.h"
58 #include "status/element-resistance.h"
59 #include "status/experience.h"
60 #include "store/rumor.h"
61 #include "sv-definition/sv-scroll-types.h"
62 #include "system/floor-type-definition.h"
63 #include "system/object-type-definition.h"
64 #include "system/player-type-definition.h"
65 #include "term/screen-processor.h"
66 #include "util/angband-files.h"
67 #include "view/display-messages.h"
68
69 /*!
70  * @brief コンストラクタ
71  * @param player_ptr プレイヤーへの参照ポインタ
72  * @param item 読むオブジェクトの所持品ID
73  */
74 ObjectReadEntity::ObjectReadEntity(player_type *player_ptr, INVENTORY_IDX item)
75     : player_ptr(player_ptr)
76     , item(item)
77 {
78 }
79
80 /*!
81  * @brief 巻物を読む
82  * @param known 判明済ならばTRUE
83  */
84 void ObjectReadEntity::execute(bool known)
85 {
86     auto *o_ptr = ref_item(this->player_ptr, this->item);
87     PlayerEnergy(this->player_ptr).set_player_turn_energy(100);
88     if (!this->check_can_read()) {
89         return;
90     }
91
92     if (music_singing_any(this->player_ptr)) {
93         stop_singing(this->player_ptr);
94     }
95
96     SpellHex spell_hex(this->player_ptr);
97     if (spell_hex.is_spelling_any() && ((this->player_ptr->lev < 35) || spell_hex.is_casting_full_capacity())) {
98         (void)SpellHex(this->player_ptr).stop_all_spells();
99     }
100
101     auto ident = false;
102     auto lev = k_info[o_ptr->k_idx].level;
103     auto used_up = true;
104     if (o_ptr->tval == ItemKindType::SCROLL) {
105         switch (o_ptr->sval) {
106         case SV_SCROLL_DARKNESS: {
107             if (!has_resist_blind(this->player_ptr) && !has_resist_dark(this->player_ptr))
108                 (void)BadStatusSetter(this->player_ptr).mod_blindness(3 + randint1(5));
109
110             if (unlite_area(this->player_ptr, 10, 3))
111                 ident = true;
112
113             break;
114         }
115         case SV_SCROLL_AGGRAVATE_MONSTER: {
116             msg_print(_("カン高くうなる様な音が辺りを覆った。", "There is a high pitched humming noise."));
117             aggravate_monsters(this->player_ptr, 0);
118             ident = true;
119             break;
120         }
121         case SV_SCROLL_CURSE_ARMOR: {
122             if (curse_armor(this->player_ptr))
123                 ident = true;
124
125             break;
126         }
127         case SV_SCROLL_CURSE_WEAPON: {
128             auto k = 0;
129             if (has_melee_weapon(this->player_ptr, INVEN_MAIN_HAND)) {
130                 k = INVEN_MAIN_HAND;
131                 if (has_melee_weapon(this->player_ptr, INVEN_SUB_HAND) && one_in_(2))
132                     k = INVEN_SUB_HAND;
133             } else if (has_melee_weapon(this->player_ptr, INVEN_SUB_HAND))
134                 k = INVEN_SUB_HAND;
135
136             if (k && curse_weapon_object(this->player_ptr, false, &this->player_ptr->inventory_list[k]))
137                 ident = true;
138
139             break;
140         }
141         case SV_SCROLL_SUMMON_MONSTER: {
142             for (auto k = 0; k < randint1(3); k++) {
143                 if (summon_specific(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, this->player_ptr->current_floor_ptr->dun_level, SUMMON_NONE,
144                         PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)) {
145                     ident = true;
146                 }
147             }
148
149             break;
150         }
151         case SV_SCROLL_SUMMON_UNDEAD: {
152             for (auto k = 0; k < randint1(3); k++) {
153                 if (summon_specific(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, this->player_ptr->current_floor_ptr->dun_level, SUMMON_UNDEAD,
154                         PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)) {
155                     ident = true;
156                 }
157             }
158
159             break;
160         }
161         case SV_SCROLL_SUMMON_PET: {
162             if (summon_specific(
163                     this->player_ptr, -1, this->player_ptr->y, this->player_ptr->x, this->player_ptr->current_floor_ptr->dun_level, SUMMON_NONE, PM_ALLOW_GROUP | PM_FORCE_PET))
164                 ident = true;
165
166             break;
167         }
168         case SV_SCROLL_SUMMON_KIN: {
169             if (summon_kin_player(this->player_ptr, this->player_ptr->lev, this->player_ptr->y, this->player_ptr->x, PM_FORCE_PET | PM_ALLOW_GROUP))
170                 ident = true;
171
172             break;
173         }
174         case SV_SCROLL_TRAP_CREATION: {
175             if (trap_creation(this->player_ptr, this->player_ptr->y, this->player_ptr->x))
176                 ident = true;
177
178             break;
179         }
180         case SV_SCROLL_PHASE_DOOR: {
181             teleport_player(this->player_ptr, 10, TELEPORT_SPONTANEOUS);
182             ident = true;
183             break;
184         }
185         case SV_SCROLL_TELEPORT: {
186             teleport_player(this->player_ptr, 100, TELEPORT_SPONTANEOUS);
187             ident = true;
188             break;
189         }
190         case SV_SCROLL_TELEPORT_LEVEL: {
191             (void)teleport_level(this->player_ptr, 0);
192             ident = true;
193             break;
194         }
195         case SV_SCROLL_WORD_OF_RECALL: {
196             if (!recall_player(this->player_ptr, randint0(21) + 15))
197                 used_up = false;
198
199             ident = true;
200             break;
201         }
202         case SV_SCROLL_IDENTIFY: {
203             if (!ident_spell(this->player_ptr, false))
204                 used_up = false;
205
206             ident = true;
207             break;
208         }
209         case SV_SCROLL_STAR_IDENTIFY: {
210             if (!identify_fully(this->player_ptr, false))
211                 used_up = false;
212
213             ident = true;
214             break;
215         }
216         case SV_SCROLL_REMOVE_CURSE: {
217             if (remove_curse(this->player_ptr))
218                 ident = true;
219
220             break;
221         }
222         case SV_SCROLL_STAR_REMOVE_CURSE: {
223             if (remove_all_curse(this->player_ptr))
224                 ident = true;
225
226             break;
227         }
228         case SV_SCROLL_ENCHANT_ARMOR: {
229             ident = true;
230             if (!enchant_spell(this->player_ptr, 0, 0, 1))
231                 used_up = false;
232
233             break;
234         }
235         case SV_SCROLL_ENCHANT_WEAPON_TO_HIT: {
236             if (!enchant_spell(this->player_ptr, 1, 0, 0))
237                 used_up = false;
238
239             ident = true;
240             break;
241         }
242         case SV_SCROLL_ENCHANT_WEAPON_TO_DAM: {
243             if (!enchant_spell(this->player_ptr, 0, 1, 0))
244                 used_up = false;
245
246             ident = true;
247             break;
248         }
249         case SV_SCROLL_STAR_ENCHANT_ARMOR: {
250             if (!enchant_spell(this->player_ptr, 0, 0, randint1(3) + 2))
251                 used_up = false;
252
253             ident = true;
254             break;
255         }
256         case SV_SCROLL_STAR_ENCHANT_WEAPON: {
257             if (!enchant_spell(this->player_ptr, randint1(3), randint1(3), 0))
258                 used_up = false;
259
260             ident = true;
261             break;
262         }
263         case SV_SCROLL_RECHARGING: {
264             if (!recharge(this->player_ptr, 130))
265                 used_up = false;
266
267             ident = true;
268             break;
269         }
270         case SV_SCROLL_MUNDANITY: {
271             ident = true;
272             if (!mundane_spell(this->player_ptr, false))
273                 used_up = false;
274
275             break;
276         }
277         case SV_SCROLL_LIGHT: {
278             if (lite_area(this->player_ptr, damroll(2, 8), 2))
279                 ident = true;
280             break;
281         }
282
283         case SV_SCROLL_MAPPING: {
284             map_area(this->player_ptr, DETECT_RAD_MAP);
285             ident = true;
286             break;
287         }
288         case SV_SCROLL_DETECT_GOLD: {
289             if (detect_treasure(this->player_ptr, DETECT_RAD_DEFAULT) || detect_objects_gold(this->player_ptr, DETECT_RAD_DEFAULT))
290                 ident = true;
291
292             break;
293         }
294         case SV_SCROLL_DETECT_ITEM: {
295             if (detect_objects_normal(this->player_ptr, DETECT_RAD_DEFAULT))
296                 ident = true;
297
298             break;
299         }
300         case SV_SCROLL_DETECT_TRAP: {
301             if (detect_traps(this->player_ptr, DETECT_RAD_DEFAULT, known))
302                 ident = true;
303
304             break;
305         }
306         case SV_SCROLL_DETECT_DOOR: {
307             if (detect_doors(this->player_ptr, DETECT_RAD_DEFAULT) || detect_stairs(this->player_ptr, DETECT_RAD_DEFAULT))
308                 ident = true;
309
310             break;
311         }
312         case SV_SCROLL_DETECT_INVIS: {
313             if (detect_monsters_invis(this->player_ptr, DETECT_RAD_DEFAULT))
314                 ident = true;
315
316             break;
317         }
318         case SV_SCROLL_SATISFY_HUNGER: {
319             if (set_food(this->player_ptr, PY_FOOD_MAX - 1))
320                 ident = true;
321
322             break;
323         }
324         case SV_SCROLL_BLESSING: {
325             if (set_blessed(this->player_ptr, this->player_ptr->blessed + randint1(12) + 6, false))
326                 ident = true;
327
328             break;
329         }
330         case SV_SCROLL_HOLY_CHANT: {
331             if (set_blessed(this->player_ptr, this->player_ptr->blessed + randint1(24) + 12, false))
332                 ident = true;
333             break;
334         }
335
336         case SV_SCROLL_HOLY_PRAYER: {
337             if (set_blessed(this->player_ptr, this->player_ptr->blessed + randint1(48) + 24, false))
338                 ident = true;
339
340             break;
341         }
342         case SV_SCROLL_MONSTER_CONFUSION: {
343             if (!(this->player_ptr->special_attack & ATTACK_CONFUSE)) {
344                 msg_print(_("手が輝き始めた。", "Your hands begin to glow."));
345                 this->player_ptr->special_attack |= ATTACK_CONFUSE;
346                 this->player_ptr->redraw |= PR_STATUS;
347                 ident = true;
348             }
349
350             break;
351         }
352         case SV_SCROLL_PROTECTION_FROM_EVIL: {
353             auto k = 3 * this->player_ptr->lev;
354             if (set_protevil(this->player_ptr, this->player_ptr->protevil + randint1(25) + k, false))
355                 ident = true;
356
357             break;
358         }
359         case SV_SCROLL_RUNE_OF_PROTECTION: {
360             create_rune_protection_one(this->player_ptr);
361             ident = true;
362             break;
363         }
364         case SV_SCROLL_TRAP_DOOR_DESTRUCTION: {
365             if (destroy_doors_touch(this->player_ptr))
366                 ident = true;
367
368             break;
369         }
370         case SV_SCROLL_STAR_DESTRUCTION: {
371             if (destroy_area(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 13 + randint0(5), false))
372                 ident = true;
373             else
374                 msg_print(_("ダンジョンが揺れた...", "The dungeon trembles..."));
375
376             break;
377         }
378         case SV_SCROLL_DISPEL_UNDEAD: {
379             if (dispel_undead(this->player_ptr, 80))
380                 ident = true;
381
382             break;
383         }
384         case SV_SCROLL_SPELL: {
385             if ((this->player_ptr->pclass == PlayerClassType::WARRIOR) || (this->player_ptr->pclass == PlayerClassType::IMITATOR) || (this->player_ptr->pclass == PlayerClassType::MINDCRAFTER)
386                 || (this->player_ptr->pclass == PlayerClassType::SORCERER) || (this->player_ptr->pclass == PlayerClassType::ARCHER) || (this->player_ptr->pclass == PlayerClassType::MAGIC_EATER)
387                 || (this->player_ptr->pclass == PlayerClassType::RED_MAGE) || (this->player_ptr->pclass == PlayerClassType::SAMURAI) || (this->player_ptr->pclass == PlayerClassType::BLUE_MAGE)
388                 || (this->player_ptr->pclass == PlayerClassType::CAVALRY) || (this->player_ptr->pclass == PlayerClassType::BERSERKER) || (this->player_ptr->pclass == PlayerClassType::SMITH)
389                 || (this->player_ptr->pclass == PlayerClassType::MIRROR_MASTER) || (this->player_ptr->pclass == PlayerClassType::NINJA) || (this->player_ptr->pclass == PlayerClassType::SNIPER))
390                 break;
391
392             this->player_ptr->add_spells++;
393             this->player_ptr->update |= PU_SPELLS;
394             ident = true;
395             break;
396         }
397         case SV_SCROLL_GENOCIDE: {
398             (void)symbol_genocide(this->player_ptr, 300, true);
399             ident = true;
400             break;
401         }
402         case SV_SCROLL_MASS_GENOCIDE: {
403             (void)mass_genocide(this->player_ptr, 300, true);
404             ident = true;
405             break;
406         }
407         case SV_SCROLL_ACQUIREMENT: {
408             acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, true, false, false);
409             ident = true;
410             break;
411         }
412         case SV_SCROLL_STAR_ACQUIREMENT: {
413             acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, true, false, false);
414             ident = true;
415             break;
416         }
417         case SV_SCROLL_FIRE: {
418             fire_ball(this->player_ptr, GF_FIRE, 0, 666, 4);
419             if (!(is_oppose_fire(this->player_ptr) || has_resist_fire(this->player_ptr) || has_immune_fire(this->player_ptr)))
420                 take_hit(this->player_ptr, DAMAGE_NOESCAPE, 50 + randint1(50), _("炎の巻物", "a Scroll of Fire"));
421
422             ident = true;
423             break;
424         }
425         case SV_SCROLL_ICE: {
426             fire_ball(this->player_ptr, GF_ICE, 0, 777, 4);
427             if (!(is_oppose_cold(this->player_ptr) || has_resist_cold(this->player_ptr) || has_immune_cold(this->player_ptr)))
428                 take_hit(this->player_ptr, DAMAGE_NOESCAPE, 100 + randint1(100), _("氷の巻物", "a Scroll of Ice"));
429
430             ident = true;
431             break;
432         }
433         case SV_SCROLL_CHAOS: {
434             fire_ball(this->player_ptr, GF_CHAOS, 0, 1000, 4);
435             if (!has_resist_chaos(this->player_ptr))
436                 take_hit(this->player_ptr, DAMAGE_NOESCAPE, 111 + randint1(111), _("ログルスの巻物", "a Scroll of Logrus"));
437
438             ident = true;
439             break;
440         }
441         case SV_SCROLL_RUMOR: {
442             msg_print(_("巻物にはメッセージが書かれている:", "There is message on the scroll. It says:"));
443             msg_print(nullptr);
444             display_rumor(this->player_ptr, true);
445             msg_print(nullptr);
446             msg_print(_("巻物は煙を立てて消え去った!", "The scroll disappears in a puff of smoke!"));
447             ident = true;
448             break;
449         }
450         case SV_SCROLL_ARTIFACT: {
451             ident = true;
452             if (!artifact_scroll(this->player_ptr))
453                 used_up = false;
454
455             break;
456         }
457         case SV_SCROLL_RESET_RECALL: {
458             ident = true;
459             if (!reset_recall(this->player_ptr))
460                 used_up = false;
461
462             break;
463         }
464         case SV_SCROLL_AMUSEMENT: {
465             ident = true;
466             amusement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, false);
467             break;
468         }
469         case SV_SCROLL_STAR_AMUSEMENT: {
470             ident = true;
471             amusement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, false);
472             break;
473         }
474         }
475     } else if (o_ptr->name1 == ART_GHB) {
476         msg_print(_("私は苦労して『グレーター・ヘル=ビースト』を倒した。", "I had a very hard time to kill the Greater hell-beast, "));
477         msg_print(_("しかし手に入ったのはこのきたないTシャツだけだった。", "but all I got was this lousy t-shirt!"));
478         used_up = false;
479     } else if (o_ptr->name1 == ART_POWER) {
480         msg_print(_("「一つの指輪は全てを統べ、", "'One Ring to rule them all, "));
481         msg_print(nullptr);
482         msg_print(_("一つの指輪は全てを見つけ、", "One Ring to find them, "));
483         msg_print(nullptr);
484         msg_print(_("一つの指輪は全てを捕らえて", "One Ring to bring them all "));
485         msg_print(nullptr);
486         msg_print(_("暗闇の中に繋ぎとめる。」", "and in the darkness bind them.'"));
487         used_up = false;
488     } else if (o_ptr->tval == ItemKindType::PARCHMENT) {
489         GAME_TEXT o_name[MAX_NLEN];
490         char buf[1024];
491         screen_save();
492         auto q = format("book-%d_jp.txt", o_ptr->sval);
493         describe_flavor(this->player_ptr, o_name, o_ptr, OD_NAME_ONLY);
494         path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, q);
495         (void)show_file(this->player_ptr, true, buf, o_name, 0, 0);
496         screen_load();
497         used_up = false;
498     }
499
500     BIT_FLAGS inventory_flags = PU_COMBINE | PU_REORDER | (this->player_ptr->update & PU_AUTODESTROY);
501     this->player_ptr->update &= ~(PU_COMBINE | PU_REORDER | PU_AUTODESTROY);
502
503     if (!(o_ptr->is_aware())) {
504         chg_virtue(this->player_ptr, V_PATIENCE, -1);
505         chg_virtue(this->player_ptr, V_CHANCE, 1);
506         chg_virtue(this->player_ptr, V_KNOWLEDGE, -1);
507     }
508
509     object_tried(o_ptr);
510     if (ident && !o_ptr->is_aware()) {
511         object_aware(this->player_ptr, o_ptr);
512         gain_exp(this->player_ptr, (lev + (this->player_ptr->lev >> 1)) / this->player_ptr->lev);
513     }
514
515     this->player_ptr->window_flags |= PW_INVEN | PW_EQUIP | PW_PLAYER;
516     this->player_ptr->update |= inventory_flags;
517     if (!used_up)
518         return;
519
520     sound(SOUND_SCROLL);
521     vary_item(this->player_ptr, this->item, -1);
522 }
523
524 bool ObjectReadEntity::check_can_read()
525 {
526     if (cmd_limit_time_walk(this->player_ptr)) {
527         return false;
528     }
529
530     if (this->player_ptr->pclass == PlayerClassType::BERSERKER) {
531         msg_print(_("巻物なんて読めない。", "You cannot read."));
532         return false;
533     }
534
535     return ItemUseChecker(this->player_ptr).check_stun(_("朦朧としていて読めなかった!", "You were not able to read it by the stun!"));
536 }