OSDN Git Service

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