OSDN Git Service

Merge pull request #1462 from Hourier/feature/Delete-Unused-Hook-Files
[hengbandforosx/hengbandosx.git] / src / perception / simple-perception.cpp
1 /*!
2  * @brief 疑似鑑定処理
3  * @date 2020/05/15
4  * @author Hourier
5  */
6
7 #include "perception/simple-perception.h"
8 #include "autopick/autopick.h"
9 #include "avatar/avatar.h"
10 #include "core/disturbance.h"
11 #include "core/player-update-types.h"
12 #include "core/window-redrawer.h"
13 #include "flavor/flag-inscriptions-table.h"
14 #include "flavor/flavor-describer.h"
15 #include "flavor/object-flavor-types.h"
16 #include "game-option/auto-destruction-options.h"
17 #include "game-option/disturbance-options.h"
18 #include "inventory/inventory-describer.h"
19 #include "inventory/inventory-slot-types.h"
20 #include "mutation/mutation-flag-types.h"
21 #include "object-enchant/special-object-flags.h"
22 #include "object/object-info.h"
23 #include "perception/object-perception.h"
24 #include "player/player-status-flags.h"
25 #include "system/object-type-definition.h"
26 #include "system/player-type-definition.h"
27 #include "view/display-messages.h"
28
29 /*!
30  * @brief 擬似鑑定を実際に行い判定を反映する
31  * @param slot 擬似鑑定を行うプレイヤーの所持リストID
32  * @param creature_ptr プレーヤーへの参照ポインタ
33  * @param heavy 重度の擬似鑑定を行うならばTRUE
34  */
35 static void sense_inventory_aux(player_type *creature_ptr, INVENTORY_IDX slot, bool heavy)
36 {
37     object_type *o_ptr = &creature_ptr->inventory_list[slot];
38     GAME_TEXT o_name[MAX_NLEN];
39     if (o_ptr->ident & (IDENT_SENSE))
40         return;
41     if (o_ptr->is_known())
42         return;
43
44     item_feel_type feel = (heavy ? pseudo_value_check_heavy(o_ptr) : pseudo_value_check_light(o_ptr));
45     if (!feel)
46         return;
47
48     if ((creature_ptr->muta.has(MUTA::BAD_LUCK)) && !randint0(13)) {
49         switch (feel) {
50         case FEEL_TERRIBLE: {
51             feel = FEEL_SPECIAL;
52             break;
53         }
54         case FEEL_WORTHLESS: {
55             feel = FEEL_EXCELLENT;
56             break;
57         }
58         case FEEL_CURSED: {
59             if (heavy)
60                 feel = randint0(3) ? FEEL_GOOD : FEEL_AVERAGE;
61             else
62                 feel = FEEL_UNCURSED;
63             break;
64         }
65         case FEEL_AVERAGE: {
66             feel = randint0(2) ? FEEL_CURSED : FEEL_GOOD;
67             break;
68         }
69         case FEEL_GOOD: {
70             if (heavy)
71                 feel = randint0(3) ? FEEL_CURSED : FEEL_AVERAGE;
72             else
73                 feel = FEEL_CURSED;
74             break;
75         }
76         case FEEL_EXCELLENT: {
77             feel = FEEL_WORTHLESS;
78             break;
79         }
80         case FEEL_SPECIAL: {
81             feel = FEEL_TERRIBLE;
82             break;
83         }
84
85         default:
86             break;
87         }
88     }
89
90     if (disturb_minor)
91         disturb(creature_ptr, false, false);
92
93     describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
94     if (slot >= INVEN_MAIN_HAND) {
95 #ifdef JP
96         msg_format("%s%s(%c)は%sという感じがする...", describe_use(creature_ptr, slot), o_name, index_to_label(slot), game_inscriptions[feel]);
97 #else
98         msg_format("You feel the %s (%c) you are %s %s %s...", o_name, index_to_label(slot), describe_use(creature_ptr, slot),
99             ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
100 #endif
101
102     } else {
103 #ifdef JP
104         msg_format("ザックの中の%s(%c)は%sという感じがする...", o_name, index_to_label(slot), game_inscriptions[feel]);
105 #else
106         msg_format("You feel the %s (%c) in your pack %s %s...", o_name, index_to_label(slot), ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
107 #endif
108     }
109
110     o_ptr->ident |= (IDENT_SENSE);
111     o_ptr->feeling = feel;
112
113     autopick_alter_item(creature_ptr, slot, destroy_feeling);
114     creature_ptr->update |= (PU_COMBINE | PU_REORDER);
115     creature_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
116 }
117
118 /*!
119  * @brief 1プレイヤーターン毎に武器、防具の擬似鑑定が行われるかを判定する。
120  * @details
121  * Sense the inventory\n
122  *\n
123  *   Class 0 = Warrior --> fast and heavy\n
124  *   Class 1 = Mage    --> slow and light\n
125  *   Class 2 = Priest  --> fast but light\n
126  *   Class 3 = Rogue   --> okay and heavy\n
127  *   Class 4 = Ranger  --> slow but heavy  (changed!)\n
128  *   Class 5 = Paladin --> slow but heavy\n
129  */
130 void sense_inventory1(player_type *creature_ptr)
131 {
132     PLAYER_LEVEL plev = creature_ptr->lev;
133     bool heavy = false;
134     object_type *o_ptr;
135     if (creature_ptr->confused)
136         return;
137
138     switch (creature_ptr->pclass) {
139     case CLASS_WARRIOR:
140     case CLASS_ARCHER:
141     case CLASS_SAMURAI:
142     case CLASS_CAVALRY: {
143         if (0 != randint0(9000L / (plev * plev + 40)))
144             return;
145
146         heavy = true;
147         break;
148     }
149     case CLASS_SMITH: {
150         if (0 != randint0(6000L / (plev * plev + 50)))
151             return;
152
153         heavy = true;
154         break;
155     }
156     case CLASS_MAGE:
157     case CLASS_HIGH_MAGE:
158     case CLASS_SORCERER:
159     case CLASS_MAGIC_EATER:
160     case CLASS_ELEMENTALIST: {
161         if (0 != randint0(240000L / (plev + 5)))
162             return;
163
164         break;
165     }
166     case CLASS_PRIEST:
167     case CLASS_BARD: {
168         if (0 != randint0(10000L / (plev * plev + 40)))
169             return;
170
171         break;
172     }
173     case CLASS_ROGUE:
174     case CLASS_NINJA: {
175         if (0 != randint0(20000L / (plev * plev + 40)))
176             return;
177
178         heavy = true;
179         break;
180     }
181     case CLASS_RANGER: {
182         if (0 != randint0(95000L / (plev * plev + 40)))
183             return;
184
185         heavy = true;
186         break;
187     }
188     case CLASS_PALADIN:
189     case CLASS_SNIPER: {
190         if (0 != randint0(77777L / (plev * plev + 40)))
191             return;
192
193         heavy = true;
194         break;
195     }
196     case CLASS_WARRIOR_MAGE:
197     case CLASS_RED_MAGE: {
198         if (0 != randint0(75000L / (plev * plev + 40)))
199             return;
200
201         break;
202     }
203     case CLASS_MINDCRAFTER:
204     case CLASS_IMITATOR:
205     case CLASS_BLUE_MAGE:
206     case CLASS_MIRROR_MASTER: {
207         if (0 != randint0(55000L / (plev * plev + 40)))
208             return;
209
210         break;
211     }
212     case CLASS_CHAOS_WARRIOR: {
213         if (0 != randint0(80000L / (plev * plev + 40)))
214             return;
215
216         heavy = true;
217         break;
218     }
219     case CLASS_MONK:
220     case CLASS_FORCETRAINER: {
221         if (0 != randint0(20000L / (plev * plev + 40)))
222             return;
223
224         break;
225     }
226     case CLASS_TOURIST: {
227         if (0 != randint0(20000L / ((plev + 50) * (plev + 50))))
228             return;
229
230         heavy = true;
231         break;
232     }
233     case CLASS_BEASTMASTER: {
234         if (0 != randint0(65000L / (plev * plev + 40)))
235             return;
236
237         break;
238     }
239     case CLASS_BERSERKER: {
240         heavy = true;
241         break;
242     }
243
244     case MAX_CLASS:
245         break;
246     }
247
248     if (compare_virtue(creature_ptr, V_KNOWLEDGE, 100, VIRTUE_LARGE))
249         heavy = true;
250
251     for (INVENTORY_IDX i = 0; i < INVEN_TOTAL; i++) {
252         bool okay = false;
253
254         o_ptr = &creature_ptr->inventory_list[i];
255
256         if (!o_ptr->k_idx)
257             continue;
258
259         switch (o_ptr->tval) {
260         case TV_SHOT:
261         case TV_ARROW:
262         case TV_BOLT:
263         case TV_BOW:
264         case TV_DIGGING:
265         case TV_HAFTED:
266         case TV_POLEARM:
267         case TV_SWORD:
268         case TV_BOOTS:
269         case TV_GLOVES:
270         case TV_HELM:
271         case TV_CROWN:
272         case TV_SHIELD:
273         case TV_CLOAK:
274         case TV_SOFT_ARMOR:
275         case TV_HARD_ARMOR:
276         case TV_DRAG_ARMOR:
277         case TV_CARD: {
278             okay = true;
279             break;
280         }
281
282         default:
283             break;
284         }
285
286         if (!okay)
287             continue;
288         if ((i < INVEN_MAIN_HAND) && (0 != randint0(5)))
289             continue;
290
291         if (has_good_luck(creature_ptr) && !randint0(13)) {
292             heavy = true;
293         }
294
295         sense_inventory_aux(creature_ptr, i, heavy);
296     }
297 }
298
299 /*!
300  * @brief 1プレイヤーターン毎に武器、防具以外の擬似鑑定が行われるかを判定する。
301  */
302 void sense_inventory2(player_type *creature_ptr)
303 {
304     PLAYER_LEVEL plev = creature_ptr->lev;
305     object_type *o_ptr;
306
307     if (creature_ptr->confused)
308         return;
309
310     switch (creature_ptr->pclass) {
311     case CLASS_WARRIOR:
312     case CLASS_ARCHER:
313     case CLASS_SAMURAI:
314     case CLASS_CAVALRY:
315     case CLASS_BERSERKER:
316     case CLASS_SNIPER: {
317         return;
318     }
319     case CLASS_SMITH:
320     case CLASS_PALADIN:
321     case CLASS_CHAOS_WARRIOR:
322     case CLASS_IMITATOR:
323     case CLASS_BEASTMASTER:
324     case CLASS_NINJA: {
325         if (0 != randint0(240000L / (plev + 5)))
326             return;
327
328         break;
329     }
330     case CLASS_RANGER:
331     case CLASS_WARRIOR_MAGE:
332     case CLASS_RED_MAGE:
333     case CLASS_MONK: {
334         if (0 != randint0(95000L / (plev * plev + 40)))
335             return;
336
337         break;
338     }
339     case CLASS_PRIEST:
340     case CLASS_BARD:
341     case CLASS_ROGUE:
342     case CLASS_FORCETRAINER:
343     case CLASS_MINDCRAFTER: {
344         if (0 != randint0(20000L / (plev * plev + 40)))
345             return;
346
347         break;
348     }
349     case CLASS_MAGE:
350     case CLASS_HIGH_MAGE:
351     case CLASS_SORCERER:
352     case CLASS_MAGIC_EATER:
353     case CLASS_MIRROR_MASTER:
354     case CLASS_BLUE_MAGE:
355     case CLASS_ELEMENTALIST: {
356         if (0 != randint0(9000L / (plev * plev + 40)))
357             return;
358
359         break;
360     }
361     case CLASS_TOURIST: {
362         if (0 != randint0(20000L / ((plev + 50) * (plev + 50))))
363             return;
364
365         break;
366     }
367
368     case MAX_CLASS:
369         break;
370     }
371
372     for (INVENTORY_IDX i = 0; i < INVEN_TOTAL; i++) {
373         bool okay = false;
374         o_ptr = &creature_ptr->inventory_list[i];
375         if (!o_ptr->k_idx)
376             continue;
377
378         switch (o_ptr->tval) {
379         case TV_RING:
380         case TV_AMULET:
381         case TV_LITE:
382         case TV_FIGURINE: {
383             okay = true;
384             break;
385         }
386
387         default:
388             break;
389         }
390
391         if (!okay)
392             continue;
393         if ((i < INVEN_MAIN_HAND) && (0 != randint0(5)))
394             continue;
395
396         sense_inventory_aux(creature_ptr, i, true);
397     }
398 }
399
400 /*!
401  * @brief 重度擬似鑑定の判断処理 / Return a "feeling" (or NULL) about an item.  Method 1 (Heavy).
402  * @param o_ptr 擬似鑑定を行うオブジェクトの参照ポインタ。
403  * @return 擬似鑑定結果のIDを返す。
404  */
405 item_feel_type pseudo_value_check_heavy(object_type *o_ptr)
406 {
407     if (o_ptr->is_artifact()) {
408         if (o_ptr->is_cursed() || o_ptr->is_broken())
409             return FEEL_TERRIBLE;
410
411         return FEEL_SPECIAL;
412     }
413
414     if (o_ptr->is_ego()) {
415         if (o_ptr->is_cursed() || o_ptr->is_broken())
416             return FEEL_WORTHLESS;
417
418         return FEEL_EXCELLENT;
419     }
420
421     if (o_ptr->is_cursed())
422         return FEEL_CURSED;
423     if (o_ptr->is_broken())
424         return FEEL_BROKEN;
425     if ((o_ptr->tval == TV_RING) || (o_ptr->tval == TV_AMULET))
426         return FEEL_AVERAGE;
427     if (o_ptr->to_a > 0)
428         return FEEL_GOOD;
429     if (o_ptr->to_h + o_ptr->to_d > 0)
430         return FEEL_GOOD;
431
432     return FEEL_AVERAGE;
433 }
434
435 /*!
436  * @brief 軽度擬似鑑定の判断処理 / Return a "feeling" (or NULL) about an item.  Method 2 (Light).
437  * @param o_ptr 擬似鑑定を行うオブジェクトの参照ポインタ。
438  * @return 擬似鑑定結果のIDを返す。
439  */
440 item_feel_type pseudo_value_check_light(object_type *o_ptr)
441 {
442     if (o_ptr->is_cursed())
443         return FEEL_CURSED;
444     if (o_ptr->is_broken())
445         return FEEL_BROKEN;
446     if (o_ptr->is_artifact())
447         return FEEL_UNCURSED;
448     if (o_ptr->is_ego())
449         return FEEL_UNCURSED;
450     if (o_ptr->to_a > 0)
451         return FEEL_UNCURSED;
452     if (o_ptr->to_h + o_ptr->to_d > 0)
453         return FEEL_UNCURSED;
454
455     return FEEL_NONE;
456 }