OSDN Git Service

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