OSDN Git Service

[Refactor] #1172 Changed '(TRUE, ', '(FALSE, ', ', TRUE)', ', FALSE)' ', TRUE,' and...
[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 "system/object-type-definition.h"
27 #include "system/player-type-definition.h"
28 #include "view/display-messages.h"
29 #include "player/player-status-flags.h"
30
31 /*!
32  * @brief 擬似鑑定を実際に行い判定を反映する
33  * @param slot 擬似鑑定を行うプレイヤーの所持リストID
34  * @param creature_ptr プレーヤーへの参照ポインタ
35  * @param heavy 重度の擬似鑑定を行うならばTRUE
36  */
37 static void sense_inventory_aux(player_type *creature_ptr, INVENTORY_IDX slot, bool heavy)
38 {
39     object_type *o_ptr = &creature_ptr->inventory_list[slot];
40     GAME_TEXT o_name[MAX_NLEN];
41     if (o_ptr->ident & (IDENT_SENSE))
42         return;
43     if (object_is_known(o_ptr))
44         return;
45
46     item_feel_type feel = (heavy ? pseudo_value_check_heavy(o_ptr) : pseudo_value_check_light(o_ptr));
47     if (!feel)
48         return;
49
50     if ((creature_ptr->muta.has(MUTA::BAD_LUCK)) && !randint0(13)) {
51         switch (feel) {
52         case FEEL_TERRIBLE: {
53             feel = FEEL_SPECIAL;
54             break;
55         }
56         case FEEL_WORTHLESS: {
57             feel = FEEL_EXCELLENT;
58             break;
59         }
60         case FEEL_CURSED: {
61             if (heavy)
62                 feel = randint0(3) ? FEEL_GOOD : FEEL_AVERAGE;
63             else
64                 feel = FEEL_UNCURSED;
65             break;
66         }
67         case FEEL_AVERAGE: {
68             feel = randint0(2) ? FEEL_CURSED : FEEL_GOOD;
69             break;
70         }
71         case FEEL_GOOD: {
72             if (heavy)
73                 feel = randint0(3) ? FEEL_CURSED : FEEL_AVERAGE;
74             else
75                 feel = FEEL_CURSED;
76             break;
77         }
78         case FEEL_EXCELLENT: {
79             feel = FEEL_WORTHLESS;
80             break;
81         }
82         case FEEL_SPECIAL: {
83             feel = FEEL_TERRIBLE;
84             break;
85         }
86
87         default:
88             break;
89         }
90     }
91
92     if (disturb_minor)
93         disturb(creature_ptr, false, false);
94
95     describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
96     if (slot >= INVEN_MAIN_HAND) {
97 #ifdef JP
98         msg_format("%s%s(%c)は%sという感じがする...", describe_use(creature_ptr, slot), o_name, index_to_label(slot), game_inscriptions[feel]);
99 #else
100         msg_format("You feel the %s (%c) you are %s %s %s...", o_name, index_to_label(slot), describe_use(creature_ptr, slot),
101             ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
102 #endif
103
104     } else {
105 #ifdef JP
106         msg_format("ザックの中の%s(%c)は%sという感じがする...", o_name, index_to_label(slot), game_inscriptions[feel]);
107 #else
108         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]);
109 #endif
110     }
111
112     o_ptr->ident |= (IDENT_SENSE);
113     o_ptr->feeling = feel;
114
115     autopick_alter_item(creature_ptr, slot, destroy_feeling);
116     creature_ptr->update |= (PU_COMBINE | PU_REORDER);
117     creature_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
118 }
119
120 /*!
121  * @brief 1プレイヤーターン毎に武器、防具の擬似鑑定が行われるかを判定する。
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  */
304 void sense_inventory2(player_type *creature_ptr)
305 {
306     PLAYER_LEVEL plev = creature_ptr->lev;
307     object_type *o_ptr;
308
309     if (creature_ptr->confused)
310         return;
311
312     switch (creature_ptr->pclass) {
313     case CLASS_WARRIOR:
314     case CLASS_ARCHER:
315     case CLASS_SAMURAI:
316     case CLASS_CAVALRY:
317     case CLASS_BERSERKER:
318     case CLASS_SNIPER: {
319         return;
320     }
321     case CLASS_SMITH:
322     case CLASS_PALADIN:
323     case CLASS_CHAOS_WARRIOR:
324     case CLASS_IMITATOR:
325     case CLASS_BEASTMASTER:
326     case CLASS_NINJA: {
327         if (0 != randint0(240000L / (plev + 5)))
328             return;
329
330         break;
331     }
332     case CLASS_RANGER:
333     case CLASS_WARRIOR_MAGE:
334     case CLASS_RED_MAGE:
335     case CLASS_MONK: {
336         if (0 != randint0(95000L / (plev * plev + 40)))
337             return;
338
339         break;
340     }
341     case CLASS_PRIEST:
342     case CLASS_BARD:
343     case CLASS_ROGUE:
344     case CLASS_FORCETRAINER:
345     case CLASS_MINDCRAFTER: {
346         if (0 != randint0(20000L / (plev * plev + 40)))
347             return;
348
349         break;
350     }
351     case CLASS_MAGE:
352     case CLASS_HIGH_MAGE:
353     case CLASS_SORCERER:
354     case CLASS_MAGIC_EATER:
355     case CLASS_MIRROR_MASTER:
356     case CLASS_BLUE_MAGE:
357     case CLASS_ELEMENTALIST: {
358         if (0 != randint0(9000L / (plev * plev + 40)))
359             return;
360
361         break;
362     }
363     case CLASS_TOURIST: {
364         if (0 != randint0(20000L / ((plev + 50) * (plev + 50))))
365             return;
366
367         break;
368     }
369
370     case MAX_CLASS:
371         break;
372     }
373
374     for (INVENTORY_IDX i = 0; i < INVEN_TOTAL; i++) {
375         bool okay = false;
376         o_ptr = &creature_ptr->inventory_list[i];
377         if (!o_ptr->k_idx)
378             continue;
379
380         switch (o_ptr->tval) {
381         case TV_RING:
382         case TV_AMULET:
383         case TV_LITE:
384         case TV_FIGURINE: {
385             okay = true;
386             break;
387         }
388
389         default:
390             break;
391         }
392
393         if (!okay)
394             continue;
395         if ((i < INVEN_MAIN_HAND) && (0 != randint0(5)))
396             continue;
397
398         sense_inventory_aux(creature_ptr, i, true);
399     }
400 }
401
402 /*!
403  * @brief 重度擬似鑑定の判断処理 / Return a "feeling" (or NULL) about an item.  Method 1 (Heavy).
404  * @param o_ptr 擬似鑑定を行うオブジェクトの参照ポインタ。
405  * @return 擬似鑑定結果のIDを返す。
406  */
407 item_feel_type pseudo_value_check_heavy(object_type *o_ptr)
408 {
409     if (object_is_artifact(o_ptr)) {
410         if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
411             return FEEL_TERRIBLE;
412
413         return FEEL_SPECIAL;
414     }
415
416     if (object_is_ego(o_ptr)) {
417         if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
418             return FEEL_WORTHLESS;
419
420         return FEEL_EXCELLENT;
421     }
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 ((o_ptr->tval == TV_RING) || (o_ptr->tval == TV_AMULET))
428         return FEEL_AVERAGE;
429     if (o_ptr->to_a > 0)
430         return FEEL_GOOD;
431     if (o_ptr->to_h + o_ptr->to_d > 0)
432         return FEEL_GOOD;
433
434     return FEEL_AVERAGE;
435 }
436
437 /*!
438  * @brief 軽度擬似鑑定の判断処理 / Return a "feeling" (or NULL) about an item.  Method 2 (Light).
439  * @param o_ptr 擬似鑑定を行うオブジェクトの参照ポインタ。
440  * @return 擬似鑑定結果のIDを返す。
441  */
442 item_feel_type pseudo_value_check_light(object_type *o_ptr)
443 {
444     if (object_is_cursed(o_ptr))
445         return FEEL_CURSED;
446     if (object_is_broken(o_ptr))
447         return FEEL_BROKEN;
448     if (object_is_artifact(o_ptr))
449         return FEEL_UNCURSED;
450     if (object_is_ego(o_ptr))
451         return FEEL_UNCURSED;
452     if (o_ptr->to_a > 0)
453         return FEEL_UNCURSED;
454     if (o_ptr->to_h + o_ptr->to_d > 0)
455         return FEEL_UNCURSED;
456
457     return FEEL_NONE;
458 }