OSDN Git Service

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