OSDN Git Service

[Refactor] #3230 Removed player-update-types.h
[hengbandforosx/hengbandosx.git] / src / mind / mind-mindcrafter.cpp
1 #include "mind/mind-mindcrafter.h"
2 #include "autopick/autopick.h"
3 #include "avatar/avatar.h"
4 #include "core/window-redrawer.h"
5 #include "effect/attribute-types.h"
6 #include "effect/effect-characteristics.h"
7 #include "effect/effect-processor.h"
8 #include "flavor/flag-inscriptions-table.h"
9 #include "flavor/flavor-describer.h"
10 #include "flavor/object-flavor-types.h"
11 #include "floor/floor-object.h"
12 #include "game-option/auto-destruction-options.h"
13 #include "hpmp/hp-mp-processor.h"
14 #include "mind/mind-mindcrafter.h"
15 #include "mind/mind-numbers.h"
16 #include "object-enchant/item-feeling.h"
17 #include "object-enchant/special-object-flags.h"
18 #include "object/item-use-flags.h"
19 #include "object/object-mark-types.h"
20 #include "perception/object-perception.h"
21 #include "perception/simple-perception.h"
22 #include "player/player-status.h"
23 #include "spell-kind/spells-detection.h"
24 #include "spell-kind/spells-fetcher.h"
25 #include "spell-kind/spells-floor.h"
26 #include "spell-kind/spells-launcher.h"
27 #include "spell-kind/spells-perception.h"
28 #include "spell-kind/spells-sight.h"
29 #include "spell-kind/spells-teleport.h"
30 #include "spell/spells-status.h"
31 #include "status/bad-status-setter.h"
32 #include "status/buff-setter.h"
33 #include "status/element-resistance.h"
34 #include "status/sight-setter.h"
35 #include "system/item-entity.h"
36 #include "system/player-type-definition.h"
37 #include "system/redrawing-flags-updater.h"
38 #include "target/target-getter.h"
39 #include "util/bit-flags-calculator.h"
40 #include "view/display-messages.h"
41
42 /*!
43  * @brief 超能力者のサイコメトリー処理/ Forcibly pseudo-identify an object in the inventory (or on the floor)
44  * @param player_ptr プレイヤーへの参照ポインタ
45  * @note
46  * currently this function allows pseudo-id of any object,
47  * including silly ones like potions & scrolls, which always
48  * get '{average}'. This should be changed, either to stop such
49  * items from being pseudo-id'd, or to allow psychometry to
50  * detect whether the unidentified potion/scroll/etc is
51  * good (Cure Light Wounds, Restore Strength, etc) or
52  * bad (Poison, Weakness etc) or 'useless' (Slime Mold Juice, etc).
53  */
54 bool psychometry(PlayerType *player_ptr)
55 {
56     concptr q = _("どのアイテムを調べますか?", "Meditate on which item? ");
57     concptr s = _("調べるアイテムがありません。", "You have nothing appropriate.");
58     ItemEntity *o_ptr;
59     OBJECT_IDX item;
60     o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
61     if (!o_ptr) {
62         return false;
63     }
64
65     if (o_ptr->is_known()) {
66         msg_print(_("何も新しいことは判らなかった。", "You cannot find out anything more about that."));
67         return true;
68     }
69
70     item_feel_type feel = pseudo_value_check_heavy(o_ptr);
71     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
72     if (!feel) {
73         msg_format(_("%sからは特に変わった事は感じとれなかった。", "You do not perceive anything unusual about the %s."), item_name.data());
74         return true;
75     }
76
77 #ifdef JP
78     msg_format("%sは%sという感じがする...", item_name.data(), game_inscriptions[feel]);
79 #else
80     msg_format("You feel that the %s %s %s...", item_name.data(), ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
81 #endif
82
83     set_bits(o_ptr->ident, IDENT_SENSE);
84     o_ptr->feeling = feel;
85     o_ptr->marked.set(OmType::TOUCHED);
86
87     auto &rfu = RedrawingFlagsUpdater::get_instance();
88     const auto flags_srf = {
89         StatusRedrawingFlag::COMBINATION,
90         StatusRedrawingFlag::REORDER,
91     };
92     rfu.set_flags(flags_srf);
93     set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
94
95     bool okay = false;
96     switch (o_ptr->bi_key.tval()) {
97     case ItemKindType::SHOT:
98     case ItemKindType::ARROW:
99     case ItemKindType::BOLT:
100     case ItemKindType::BOW:
101     case ItemKindType::DIGGING:
102     case ItemKindType::HAFTED:
103     case ItemKindType::POLEARM:
104     case ItemKindType::SWORD:
105     case ItemKindType::BOOTS:
106     case ItemKindType::GLOVES:
107     case ItemKindType::HELM:
108     case ItemKindType::CROWN:
109     case ItemKindType::SHIELD:
110     case ItemKindType::CLOAK:
111     case ItemKindType::SOFT_ARMOR:
112     case ItemKindType::HARD_ARMOR:
113     case ItemKindType::DRAG_ARMOR:
114     case ItemKindType::CARD:
115     case ItemKindType::RING:
116     case ItemKindType::AMULET:
117     case ItemKindType::LITE:
118     case ItemKindType::FIGURINE:
119         okay = true;
120         break;
121
122     default:
123         break;
124     }
125
126     autopick_alter_item(player_ptr, item, (bool)(okay && destroy_feeling));
127     return true;
128 }
129
130 /*!
131  * @brief 超能力の発動 /
132  * do_cmd_cast calls this function if the player's class is 'mindcrafter'.
133  * @param spell 発動する特殊技能のID
134  * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
135  */
136 bool cast_mindcrafter_spell(PlayerType *player_ptr, MindMindcrafterType spell)
137 {
138     bool b = false;
139     int dam = 0;
140     DIRECTION dir;
141     TIME_EFFECT t;
142     PLAYER_LEVEL plev = player_ptr->lev;
143     switch (spell) {
144     case MindMindcrafterType::PRECOGNITION:
145         if (plev > 44) {
146             chg_virtue(player_ptr, Virtue::KNOWLEDGE, 1);
147             chg_virtue(player_ptr, Virtue::ENLIGHTEN, 1);
148             wiz_lite(player_ptr, false);
149         } else if (plev > 19) {
150             map_area(player_ptr, DETECT_RAD_MAP);
151         }
152
153         if (plev < 30) {
154             b = detect_monsters_normal(player_ptr, DETECT_RAD_DEFAULT);
155             if (plev > 14) {
156                 b |= detect_monsters_invis(player_ptr, DETECT_RAD_DEFAULT);
157             }
158             if (plev > 4) {
159                 b |= detect_traps(player_ptr, DETECT_RAD_DEFAULT, true);
160                 b |= detect_doors(player_ptr, DETECT_RAD_DEFAULT);
161             }
162         } else {
163             b = detect_all(player_ptr, DETECT_RAD_DEFAULT);
164         }
165
166         if ((plev > 24) && (plev < 40)) {
167             set_tim_esp(player_ptr, (TIME_EFFECT)plev, false);
168         }
169
170         if (!b) {
171             msg_print(_("安全な気がする。", "You feel safe."));
172         }
173
174         break;
175     case MindMindcrafterType::NEURAL_BLAST:
176         if (!get_aim_dir(player_ptr, &dir)) {
177             return false;
178         }
179
180         if (randint1(100) < plev * 2) {
181             fire_beam(player_ptr, AttributeType::PSI, dir, damroll(3 + ((plev - 1) / 4), (3 + plev / 15)));
182         } else {
183             fire_ball(player_ptr, AttributeType::PSI, dir, damroll(3 + ((plev - 1) / 4), (3 + plev / 15)), 0);
184         }
185         break;
186     case MindMindcrafterType::MINOR_DISPLACEMENT:
187         teleport_player(player_ptr, 10, TELEPORT_SPONTANEOUS);
188         break;
189     case MindMindcrafterType::MAJOR_DISPLACEMENT:
190         teleport_player(player_ptr, plev * 5, TELEPORT_SPONTANEOUS);
191         break;
192     case MindMindcrafterType::DOMINATION:
193         if (plev < 30) {
194             if (!get_aim_dir(player_ptr, &dir)) {
195                 return false;
196             }
197
198             fire_ball(player_ptr, AttributeType::DOMINATION, dir, plev, 0);
199         } else {
200             charm_monsters(player_ptr, plev * 2);
201         }
202
203         break;
204     case MindMindcrafterType::PLUVERISE:
205         if (!get_aim_dir(player_ptr, &dir)) {
206             return false;
207         }
208
209         fire_ball(player_ptr, AttributeType::TELEKINESIS, dir, damroll(8 + ((plev - 5) / 4), 8), (plev > 20 ? (plev - 20) / 8 + 1 : 0));
210         break;
211     case MindMindcrafterType::CHARACTER_ARMOR:
212         set_shield(player_ptr, (TIME_EFFECT)plev, false);
213         if (plev > 14) {
214             set_oppose_acid(player_ptr, (TIME_EFFECT)plev, false);
215         }
216         if (plev > 19) {
217             set_oppose_fire(player_ptr, (TIME_EFFECT)plev, false);
218         }
219         if (plev > 24) {
220             set_oppose_cold(player_ptr, (TIME_EFFECT)plev, false);
221         }
222         if (plev > 29) {
223             set_oppose_elec(player_ptr, (TIME_EFFECT)plev, false);
224         }
225         if (plev > 34) {
226             set_oppose_pois(player_ptr, (TIME_EFFECT)plev, false);
227         }
228
229         break;
230     case MindMindcrafterType::PSYCHOMETRY:
231         if (plev < 25) {
232             return psychometry(player_ptr);
233         } else {
234             return ident_spell(player_ptr, false);
235         }
236     case MindMindcrafterType::MIND_WAVE:
237         msg_print(_("精神を捻じ曲げる波動を発生させた!", "Mind-warping forces emanate from your brain!"));
238         if (plev < 25) {
239             project(player_ptr, 0, 2 + plev / 10, player_ptr->y, player_ptr->x, (plev * 3), AttributeType::PSI, PROJECT_KILL);
240         } else {
241             (void)mindblast_monsters(player_ptr, randint1(plev * ((plev - 5) / 10 + 1)));
242         }
243
244         break;
245     case MindMindcrafterType::ADRENALINE_CHANNELING: {
246         BadStatusSetter bss(player_ptr);
247         (void)bss.set_fear(0);
248         (void)bss.set_stun(0);
249         if (!is_fast(player_ptr) || !is_hero(player_ptr)) {
250             hp_player(player_ptr, plev);
251         }
252
253         t = 10 + randint1((plev * 3) / 2);
254         set_hero(player_ptr, t, false);
255         (void)set_acceleration(player_ptr, t, false);
256         break;
257     }
258     case MindMindcrafterType::TELEKINESIS:
259         if (!get_aim_dir(player_ptr, &dir)) {
260             return false;
261         }
262
263         fetch_item(player_ptr, dir, plev * 15, false);
264         break;
265     case MindMindcrafterType::PSYCHIC_DRAIN:
266         if (!get_aim_dir(player_ptr, &dir)) {
267             return false;
268         }
269
270         dam = damroll(plev / 2, 6);
271         if (fire_ball(player_ptr, AttributeType::PSI_DRAIN, dir, dam, 0)) {
272             player_ptr->energy_need += randint1(150);
273         }
274
275         break;
276     case MindMindcrafterType::PSYCHO_SPEAR:
277         if (!get_aim_dir(player_ptr, &dir)) {
278             return false;
279         }
280
281         fire_beam(player_ptr, AttributeType::PSY_SPEAR, dir, randint1(plev * 3) + plev * 3);
282         break;
283     case MindMindcrafterType::THE_WORLD:
284         time_walk(player_ptr);
285         break;
286     default:
287         msg_print(_("なに?", "Zap?"));
288     }
289
290     return true;
291 }