OSDN Git Service

Revert "Revert "Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband""
[hengband/hengband.git] / src / perception / simple-perception.c
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->muta3 & MUT3_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     }
87
88     if (disturb_minor)
89         disturb(creature_ptr, FALSE, FALSE);
90
91     describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
92     if (slot >= INVEN_RARM) {
93 #ifdef JP
94         msg_format("%s%s(%c)は%sという感じがする...", describe_use(creature_ptr, slot), o_name, index_to_label(slot), game_inscriptions[feel]);
95 #else
96         msg_format("You feel the %s (%c) you are %s %s %s...", o_name, index_to_label(slot), describe_use(creature_ptr, slot),
97             ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
98 #endif
99
100     } else {
101 #ifdef JP
102         msg_format("ザックの中の%s(%c)は%sという感じがする...", o_name, index_to_label(slot), game_inscriptions[feel]);
103 #else
104         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]);
105 #endif
106     }
107
108     o_ptr->ident |= (IDENT_SENSE);
109     o_ptr->feeling = feel;
110
111     autopick_alter_item(creature_ptr, slot, destroy_feeling);
112     creature_ptr->update |= (PU_COMBINE | PU_REORDER);
113     creature_ptr->window |= (PW_INVEN | PW_EQUIP);
114 }
115
116 /*!
117  * @brief 1プレイヤーターン毎に武器、防具の擬似鑑定が行われるかを判定する。
118  * @return なし
119  * @details
120  * Sense the inventory\n
121  *\n
122  *   Class 0 = Warrior --> fast and heavy\n
123  *   Class 1 = Mage    --> slow and light\n
124  *   Class 2 = Priest  --> fast but light\n
125  *   Class 3 = Rogue   --> okay and heavy\n
126  *   Class 4 = Ranger  --> slow but heavy  (changed!)\n
127  *   Class 5 = Paladin --> slow but heavy\n
128  */
129 void sense_inventory1(player_type *creature_ptr)
130 {
131     PLAYER_LEVEL plev = creature_ptr->lev;
132     bool heavy = FALSE;
133     object_type *o_ptr;
134     if (creature_ptr->confused)
135         return;
136
137     switch (creature_ptr->pclass) {
138     case CLASS_WARRIOR:
139     case CLASS_ARCHER:
140     case CLASS_SAMURAI:
141     case CLASS_CAVALRY: {
142         if (0 != randint0(9000L / (plev * plev + 40)))
143             return;
144
145         heavy = TRUE;
146         break;
147     }
148     case CLASS_SMITH: {
149         if (0 != randint0(6000L / (plev * plev + 50)))
150             return;
151
152         heavy = TRUE;
153         break;
154     }
155     case CLASS_MAGE:
156     case CLASS_HIGH_MAGE:
157     case CLASS_SORCERER:
158     case CLASS_MAGIC_EATER: {
159         if (0 != randint0(240000L / (plev + 5)))
160             return;
161
162         break;
163     }
164     case CLASS_PRIEST:
165     case CLASS_BARD: {
166         if (0 != randint0(10000L / (plev * plev + 40)))
167             return;
168
169         break;
170     }
171     case CLASS_ROGUE:
172     case CLASS_NINJA: {
173         if (0 != randint0(20000L / (plev * plev + 40)))
174             return;
175
176         heavy = TRUE;
177         break;
178     }
179     case CLASS_RANGER: {
180         if (0 != randint0(95000L / (plev * plev + 40)))
181             return;
182
183         heavy = TRUE;
184         break;
185     }
186     case CLASS_PALADIN:
187     case CLASS_SNIPER: {
188         if (0 != randint0(77777L / (plev * plev + 40)))
189             return;
190
191         heavy = TRUE;
192         break;
193     }
194     case CLASS_WARRIOR_MAGE:
195     case CLASS_RED_MAGE: {
196         if (0 != randint0(75000L / (plev * plev + 40)))
197             return;
198
199         break;
200     }
201     case CLASS_MINDCRAFTER:
202     case CLASS_IMITATOR:
203     case CLASS_BLUE_MAGE:
204     case CLASS_MIRROR_MASTER: {
205         if (0 != randint0(55000L / (plev * plev + 40)))
206             return;
207
208         break;
209     }
210     case CLASS_CHAOS_WARRIOR: {
211         if (0 != randint0(80000L / (plev * plev + 40)))
212             return;
213
214         heavy = TRUE;
215         break;
216     }
217     case CLASS_MONK:
218     case CLASS_FORCETRAINER: {
219         if (0 != randint0(20000L / (plev * plev + 40)))
220             return;
221
222         break;
223     }
224     case CLASS_TOURIST: {
225         if (0 != randint0(20000L / ((plev + 50) * (plev + 50))))
226             return;
227
228         heavy = TRUE;
229         break;
230     }
231     case CLASS_BEASTMASTER: {
232         if (0 != randint0(65000L / (plev * plev + 40)))
233             return;
234
235         break;
236     }
237     case CLASS_BERSERKER: {
238         heavy = TRUE;
239         break;
240     }
241     }
242
243     if (compare_virtue(creature_ptr, V_KNOWLEDGE, 100, VIRTUE_LARGE))
244         heavy = TRUE;
245
246     for (INVENTORY_IDX i = 0; i < INVEN_TOTAL; i++) {
247         bool okay = FALSE;
248
249         o_ptr = &creature_ptr->inventory_list[i];
250
251         if (!o_ptr->k_idx)
252             continue;
253
254         switch (o_ptr->tval) {
255         case TV_SHOT:
256         case TV_ARROW:
257         case TV_BOLT:
258         case TV_BOW:
259         case TV_DIGGING:
260         case TV_HAFTED:
261         case TV_POLEARM:
262         case TV_SWORD:
263         case TV_BOOTS:
264         case TV_GLOVES:
265         case TV_HELM:
266         case TV_CROWN:
267         case TV_SHIELD:
268         case TV_CLOAK:
269         case TV_SOFT_ARMOR:
270         case TV_HARD_ARMOR:
271         case TV_DRAG_ARMOR:
272         case TV_CARD: {
273             okay = TRUE;
274             break;
275         }
276         }
277
278         if (!okay)
279             continue;
280         if ((i < INVEN_RARM) && (0 != randint0(5)))
281             continue;
282
283         if (have_good_luck(creature_ptr) && !randint0(13)) {
284             heavy = TRUE;
285         }
286
287         sense_inventory_aux(creature_ptr, i, heavy);
288     }
289 }
290
291 /*!
292  * @brief 1プレイヤーターン毎に武器、防具以外の擬似鑑定が行われるかを判定する。
293  * @return なし
294  */
295 void sense_inventory2(player_type *creature_ptr)
296 {
297     PLAYER_LEVEL plev = creature_ptr->lev;
298     object_type *o_ptr;
299
300     if (creature_ptr->confused)
301         return;
302
303     switch (creature_ptr->pclass) {
304     case CLASS_WARRIOR:
305     case CLASS_ARCHER:
306     case CLASS_SAMURAI:
307     case CLASS_CAVALRY:
308     case CLASS_BERSERKER:
309     case CLASS_SNIPER: {
310         return;
311     }
312     case CLASS_SMITH:
313     case CLASS_PALADIN:
314     case CLASS_CHAOS_WARRIOR:
315     case CLASS_IMITATOR:
316     case CLASS_BEASTMASTER:
317     case CLASS_NINJA: {
318         if (0 != randint0(240000L / (plev + 5)))
319             return;
320
321         break;
322     }
323     case CLASS_RANGER:
324     case CLASS_WARRIOR_MAGE:
325     case CLASS_RED_MAGE:
326     case CLASS_MONK: {
327         if (0 != randint0(95000L / (plev * plev + 40)))
328             return;
329
330         break;
331     }
332     case CLASS_PRIEST:
333     case CLASS_BARD:
334     case CLASS_ROGUE:
335     case CLASS_FORCETRAINER:
336     case CLASS_MINDCRAFTER: {
337         if (0 != randint0(20000L / (plev * plev + 40)))
338             return;
339
340         break;
341     }
342     case CLASS_MAGE:
343     case CLASS_HIGH_MAGE:
344     case CLASS_SORCERER:
345     case CLASS_MAGIC_EATER:
346     case CLASS_MIRROR_MASTER:
347     case CLASS_BLUE_MAGE: {
348         if (0 != randint0(9000L / (plev * plev + 40)))
349             return;
350
351         break;
352     }
353     case CLASS_TOURIST: {
354         if (0 != randint0(20000L / ((plev + 50) * (plev + 50))))
355             return;
356
357         break;
358     }
359     }
360
361     for (INVENTORY_IDX i = 0; i < INVEN_TOTAL; i++) {
362         bool okay = FALSE;
363         o_ptr = &creature_ptr->inventory_list[i];
364         if (!o_ptr->k_idx)
365             continue;
366
367         switch (o_ptr->tval) {
368         case TV_RING:
369         case TV_AMULET:
370         case TV_LITE:
371         case TV_FIGURINE: {
372             okay = TRUE;
373             break;
374         }
375         }
376
377         if (!okay)
378             continue;
379         if ((i < INVEN_RARM) && (0 != randint0(5)))
380             continue;
381
382         sense_inventory_aux(creature_ptr, i, TRUE);
383     }
384 }
385
386 /*!
387  * @brief 重度擬似鑑定の判断処理 / Return a "feeling" (or NULL) about an item.  Method 1 (Heavy).
388  * @param o_ptr 擬似鑑定を行うオブジェクトの参照ポインタ。
389  * @return 擬似鑑定結果のIDを返す。
390  */
391 item_feel_type pseudo_value_check_heavy(object_type *o_ptr)
392 {
393     if (object_is_artifact(o_ptr)) {
394         if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
395             return FEEL_TERRIBLE;
396
397         return FEEL_SPECIAL;
398     }
399
400     if (object_is_ego(o_ptr)) {
401         if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
402             return FEEL_WORTHLESS;
403
404         return FEEL_EXCELLENT;
405     }
406
407     if (object_is_cursed(o_ptr))
408         return FEEL_CURSED;
409     if (object_is_broken(o_ptr))
410         return FEEL_BROKEN;
411     if ((o_ptr->tval == TV_RING) || (o_ptr->tval == TV_AMULET))
412         return FEEL_AVERAGE;
413     if (o_ptr->to_a > 0)
414         return FEEL_GOOD;
415     if (o_ptr->to_h + o_ptr->to_d > 0)
416         return FEEL_GOOD;
417
418     return FEEL_AVERAGE;
419 }
420
421 /*!
422  * @brief 軽度擬似鑑定の判断処理 / Return a "feeling" (or NULL) about an item.  Method 2 (Light).
423  * @param o_ptr 擬似鑑定を行うオブジェクトの参照ポインタ。
424  * @return 擬似鑑定結果のIDを返す。
425  */
426 item_feel_type pseudo_value_check_light(object_type *o_ptr)
427 {
428     if (object_is_cursed(o_ptr))
429         return FEEL_CURSED;
430     if (object_is_broken(o_ptr))
431         return FEEL_BROKEN;
432     if (object_is_artifact(o_ptr))
433         return FEEL_UNCURSED;
434     if (object_is_ego(o_ptr))
435         return FEEL_UNCURSED;
436     if (o_ptr->to_a > 0)
437         return FEEL_UNCURSED;
438     if (o_ptr->to_h + o_ptr->to_d > 0)
439         return FEEL_UNCURSED;
440
441     return FEEL_NONE;
442 }