OSDN Git Service

Merge remote-tracking branch 'remotes/origin/For2.2.2-Fix-Hourier' into For2.2.2...
[hengband/hengband.git] / src / cmd-item / cmd-throw.c
1 #include "cmd-item/cmd-throw.h"
2 #include "action/weapon-shield.h"
3 #include "art-definition/art-weapon-types.h"
4 #include "combat/attack-power-table.h"
5 #include "combat/shoot.h"
6 #include "combat/slaying.h"
7 #include "core/player-redraw-types.h"
8 #include "core/player-update-types.h"
9 #include "core/stuff-handler.h"
10 #include "core/window-redrawer.h"
11 #include "effect/spells-effect-util.h"
12 #include "flavor/flavor-describer.h"
13 #include "flavor/object-flavor-types.h"
14 #include "floor/cave.h"
15 #include "floor/floor-object.h"
16 #include "floor/geometry.h"
17 #include "game-option/cheat-types.h"
18 #include "game-option/special-options.h"
19 #include "grid/feature-flag-types.h"
20 #include "grid/grid.h"
21 #include "inventory/inventory-object.h"
22 #include "inventory/inventory-slot-types.h"
23 #include "io/cursor.h"
24 #include "io/screen-util.h"
25 #include "main/sound-definitions-table.h"
26 #include "main/sound-of-music.h"
27 #include "monster-floor/monster-death.h"
28 #include "monster-floor/monster-summon.h"
29 #include "monster-floor/place-monster-types.h"
30 #include "monster/monster-describer.h"
31 #include "monster/monster-info.h"
32 #include "monster/monster-status.h"
33 #include "object-enchant/tr-types.h"
34 #include "object-hook/hook-checker.h"
35 #include "object-hook/hook-expendable.h"
36 #include "object-hook/hook-weapon.h"
37 #include "object/item-tester-hooker.h"
38 #include "object/item-use-flags.h"
39 #include "object/object-broken.h"
40 #include "object/object-flags.h"
41 #include "object/object-generator.h"
42 #include "object/object-info.h"
43 #include "object/object-kind.h"
44 #include "object/object-stack.h"
45 #include "player/attack-defense-types.h"
46 #include "player/special-defense-types.h"
47 #include "racial/racial-android.h"
48 #include "specific-object/torch.h"
49 #include "status/action-setter.h"
50 #include "system/floor-type-definition.h"
51 #include "system/object-type-definition.h"
52 #include "target/target-checker.h"
53 #include "target/target-getter.h"
54 #include "term/screen-processor.h"
55 #include "util/bit-flags-calculator.h"
56 #include "view/display-messages.h"
57 #include "view/object-describer.h"
58 #include "wizard/wizard-messages.h"
59
60 /*!
61  * @brief 投射処理メインルーチン /
62  * Throw an object from the pack or floor.
63  * @param mult 威力の倍率
64  * @param creature_ptr プレーヤーへの参照ポインタ
65  * @param boomerang ブーメラン処理ならばTRUE
66  * @param shuriken 忍者の手裏剣処理ならばTRUE
67  * @return ターンを消費した場合TRUEを返す
68  * @details
69  * <pre>
70  * Note: "unseen" monsters are very hard to hit.
71  *
72  * Should throwing a weapon do full damage?  Should it allow the magic
73  * to hit bonus of the weapon to have an effect?  Should it ever cause
74  * the item to be destroyed?  Should it do any damage at all?
75  * </pre>
76  */
77 bool do_cmd_throw(player_type *creature_ptr, int mult, bool boomerang, OBJECT_IDX shuriken)
78 {
79     DIRECTION dir;
80     OBJECT_IDX item;
81     int i;
82     POSITION y, x, ty, tx, prev_y, prev_x;
83     POSITION ny[19], nx[19];
84     int chance, tdam, tdis;
85     int mul, div, dd, ds;
86     int cur_dis, visible;
87     PERCENTAGE j;
88     object_type forge;
89     object_type *q_ptr;
90     object_type *o_ptr;
91     bool hit_body = FALSE;
92     bool hit_wall = FALSE;
93     bool equiped_item = FALSE;
94     bool return_when_thrown = FALSE;
95     GAME_TEXT o_name[MAX_NLEN];
96     int msec = delay_factor * delay_factor * delay_factor;
97     BIT_FLAGS flgs[TR_FLAG_SIZE];
98     concptr q, s;
99     bool come_back = FALSE;
100     bool do_drop = TRUE;
101     if (creature_ptr->wild_mode)
102         return FALSE;
103
104     if (creature_ptr->special_defense & KATA_MUSOU)
105         set_action(creature_ptr, ACTION_NONE);
106
107     if (shuriken >= 0) {
108         item = shuriken;
109         o_ptr = &creature_ptr->inventory_list[item];
110     } else if (boomerang) {
111         if (has_melee_weapon(creature_ptr, INVEN_RARM) && has_melee_weapon(creature_ptr, INVEN_LARM)) {
112             item_tester_hook = item_tester_hook_boomerang;
113             q = _("どの武器を投げますか? ", "Throw which item? ");
114             s = _("投げる武器がない。", "You have nothing to throw.");
115             o_ptr = choose_object(creature_ptr, &item, q, s, USE_EQUIP, 0);
116             if (!o_ptr) {
117                 flush();
118                 return FALSE;
119             }
120         } else if (has_melee_weapon(creature_ptr, INVEN_LARM)) {
121             item = INVEN_LARM;
122             o_ptr = &creature_ptr->inventory_list[item];
123         } else {
124             item = INVEN_RARM;
125             o_ptr = &creature_ptr->inventory_list[item];
126         }
127     } else {
128         q = _("どのアイテムを投げますか? ", "Throw which item? ");
129         s = _("投げるアイテムがない。", "You have nothing to throw.");
130         o_ptr = choose_object(creature_ptr, &item, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
131         if (!o_ptr) {
132             flush();
133             return FALSE;
134         }
135     }
136
137     if (object_is_cursed(o_ptr) && (item >= INVEN_RARM)) {
138         msg_print(_("ふーむ、どうやら呪われているようだ。", "Hmmm, it seems to be cursed."));
139         return FALSE;
140     }
141
142     if (creature_ptr->current_floor_ptr->inside_arena && !boomerang && (o_ptr->tval != TV_SPIKE)) {
143         msg_print(_("アリーナではアイテムを使えない!", "You're in the arena now. This is hand-to-hand!"));
144         msg_print(NULL);
145         return FALSE;
146     }
147
148     q_ptr = &forge;
149     object_copy(q_ptr, o_ptr);
150     object_flags(creature_ptr, q_ptr, flgs);
151     torch_flags(q_ptr, flgs);
152     distribute_charges(o_ptr, q_ptr, 1);
153     q_ptr->number = 1;
154     describe_flavor(creature_ptr, o_name, q_ptr, OD_OMIT_PREFIX);
155     if (creature_ptr->mighty_throw)
156         mult += 3;
157
158     mul = 10 + 2 * (mult - 1);
159     div = ((q_ptr->weight > 10) ? q_ptr->weight : 10);
160     if ((have_flag(flgs, TR_THROW)) || boomerang)
161         div /= 2;
162
163     tdis = (adj_str_blow[creature_ptr->stat_ind[A_STR]] + 20) * mul / div;
164     if (tdis > mul)
165         tdis = mul;
166
167     if (shuriken >= 0) {
168         ty = randint0(101) - 50 + creature_ptr->y;
169         tx = randint0(101) - 50 + creature_ptr->x;
170     } else {
171         project_length = tdis + 1;
172         if (!get_aim_dir(creature_ptr, &dir))
173             return FALSE;
174
175         tx = creature_ptr->x + 99 * ddx[dir];
176         ty = creature_ptr->y + 99 * ddy[dir];
177         if ((dir == 5) && target_okay(creature_ptr)) {
178             tx = target_col;
179             ty = target_row;
180         }
181
182         project_length = 0; /* reset to default */
183     }
184
185     if ((q_ptr->name1 == ART_MJOLLNIR) || (q_ptr->name1 == ART_AEGISFANG) || boomerang)
186         return_when_thrown = TRUE;
187
188     if (item >= 0) {
189         inven_item_increase(creature_ptr, item, -1);
190         if (!return_when_thrown)
191             inven_item_describe(creature_ptr, item);
192         inven_item_optimize(creature_ptr, item);
193     } else {
194         floor_item_increase(creature_ptr->current_floor_ptr, 0 - item, -1);
195         floor_item_optimize(creature_ptr, 0 - item);
196     }
197
198     if (item >= INVEN_RARM) {
199         equiped_item = TRUE;
200         creature_ptr->redraw |= PR_EQUIPPY;
201     }
202
203     take_turn(creature_ptr, 100);
204     if ((creature_ptr->pclass == CLASS_ROGUE) || (creature_ptr->pclass == CLASS_NINJA))
205         creature_ptr->energy_use -= creature_ptr->lev;
206
207     y = creature_ptr->y;
208     x = creature_ptr->x;
209     handle_stuff(creature_ptr);
210     if ((creature_ptr->pclass == CLASS_NINJA) && ((q_ptr->tval == TV_SPIKE) || ((have_flag(flgs, TR_THROW)) && (q_ptr->tval == TV_SWORD))))
211         shuriken = TRUE;
212     else
213         shuriken = FALSE;
214
215     if (have_flag(flgs, TR_THROW))
216         chance = ((creature_ptr->skill_tht) + ((creature_ptr->to_h_b + q_ptr->to_h) * BTH_PLUS_ADJ));
217     else
218         chance = (creature_ptr->skill_tht + (creature_ptr->to_h_b * BTH_PLUS_ADJ));
219
220     if (shuriken)
221         chance *= 2;
222
223     prev_y = y;
224     prev_x = x;
225     for (cur_dis = 0; cur_dis <= tdis;) {
226         if ((y == ty) && (x == tx))
227             break;
228
229         ny[cur_dis] = y;
230         nx[cur_dis] = x;
231         mmove2(&ny[cur_dis], &nx[cur_dis], creature_ptr->y, creature_ptr->x, ty, tx);
232         if (!cave_have_flag_bold(creature_ptr->current_floor_ptr, ny[cur_dis], nx[cur_dis], FF_PROJECT)) {
233             hit_wall = TRUE;
234             if ((q_ptr->tval == TV_FIGURINE) || object_is_potion(q_ptr) || !creature_ptr->current_floor_ptr->grid_array[ny[cur_dis]][nx[cur_dis]].m_idx)
235                 break;
236         }
237
238         if (panel_contains(ny[cur_dis], nx[cur_dis]) && player_can_see_bold(creature_ptr, ny[cur_dis], nx[cur_dis])) {
239             SYMBOL_CODE c = object_char(q_ptr);
240             TERM_COLOR a = object_attr(q_ptr);
241             print_rel(creature_ptr, c, a, ny[cur_dis], nx[cur_dis]);
242             move_cursor_relative(ny[cur_dis], nx[cur_dis]);
243             term_fresh();
244             term_xtra(TERM_XTRA_DELAY, msec);
245             lite_spot(creature_ptr, ny[cur_dis], nx[cur_dis]);
246             term_fresh();
247         } else {
248             term_xtra(TERM_XTRA_DELAY, msec);
249         }
250
251         prev_y = y;
252         prev_x = x;
253         x = nx[cur_dis];
254         y = ny[cur_dis];
255         cur_dis++;
256         if (creature_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
257             grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
258             monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
259             GAME_TEXT m_name[MAX_NLEN];
260             monster_name(creature_ptr, g_ptr->m_idx, m_name);
261             visible = m_ptr->ml;
262             hit_body = TRUE;
263             if (test_hit_fire(creature_ptr, chance - cur_dis, m_ptr, m_ptr->ml, o_name)) {
264                 bool fear = FALSE;
265                 if (!visible) {
266                     msg_format(_("%sが敵を捕捉した。", "The %s finds a mark."), o_name);
267                 } else {
268                     msg_format(_("%sが%sに命中した。", "The %s hits %s."), o_name, m_name);
269                     if (m_ptr->ml) {
270                         if (!creature_ptr->image)
271                             monster_race_track(creature_ptr, m_ptr->ap_r_idx);
272                         health_track(creature_ptr, g_ptr->m_idx);
273                     }
274                 }
275
276                 dd = q_ptr->dd;
277                 ds = q_ptr->ds;
278                 torch_dice(q_ptr, &dd, &ds);
279                 tdam = damroll(dd, ds);
280                 tdam = calc_attack_damage_with_slay(creature_ptr, q_ptr, tdam, m_ptr, 0, TRUE);
281                 tdam = critical_shot(creature_ptr, q_ptr->weight, q_ptr->to_h, 0, tdam);
282                 if (q_ptr->to_d > 0)
283                     tdam += q_ptr->to_d;
284                 else
285                     tdam += -q_ptr->to_d;
286
287                 if (boomerang) {
288                     tdam *= (mult + creature_ptr->num_blow[item - INVEN_RARM]);
289                     tdam += creature_ptr->to_d_m;
290                 } else if (have_flag(flgs, TR_THROW)) {
291                     tdam *= (3 + mult);
292                     tdam += creature_ptr->to_d_m;
293                 } else {
294                     tdam *= mult;
295                 }
296
297                 if (shuriken)
298                     tdam += ((creature_ptr->lev + 30) * (creature_ptr->lev + 30) - 900) / 55;
299
300                 if (tdam < 0)
301                     tdam = 0;
302
303                 tdam = mon_damage_mod(creature_ptr, m_ptr, tdam, FALSE);
304                 msg_format_wizard(creature_ptr, CHEAT_MONSTER, _("%dのダメージを与えた。(残りHP %d/%d(%d))", "You do %d damage. (left HP %d/%d(%d))"), tdam,
305                     m_ptr->hp - tdam, m_ptr->maxhp, m_ptr->max_maxhp);
306
307                 if (mon_take_hit(creature_ptr, g_ptr->m_idx, tdam, &fear, extract_note_dies(real_r_idx(m_ptr)))) {
308                     /* Dead monster */
309                 } else {
310                     message_pain(creature_ptr, g_ptr->m_idx, tdam);
311                     if ((tdam > 0) && !object_is_potion(q_ptr))
312                         anger_monster(creature_ptr, m_ptr);
313
314                     if (fear && m_ptr->ml) {
315                         sound(SOUND_FLEE);
316                         msg_format(_("%^sは恐怖して逃げ出した!", "%^s flees in terror!"), m_name);
317                     }
318                 }
319             }
320
321             break;
322         }
323     }
324
325     if (hit_body)
326         torch_lost_fuel(q_ptr);
327
328     j = (hit_body ? breakage_chance(creature_ptr, q_ptr, creature_ptr->pclass == CLASS_ARCHER, 0) : 0);
329
330     if ((q_ptr->tval == TV_FIGURINE) && !(creature_ptr->current_floor_ptr->inside_arena)) {
331         j = 100;
332         if (!(summon_named_creature(creature_ptr, 0, y, x, q_ptr->pval, !(object_is_cursed(q_ptr)) ? PM_FORCE_PET : 0L)))
333             msg_print(_("人形は捻じ曲がり砕け散ってしまった!", "The Figurine writhes and then shatters."));
334         else if (object_is_cursed(q_ptr))
335             msg_print(_("これはあまり良くない気がする。", "You have a bad feeling about this."));
336     }
337
338     if (object_is_potion(q_ptr)) {
339         if (hit_body || hit_wall || (randint1(100) < j)) {
340             msg_format(_("%sは砕け散った!", "The %s shatters!"), o_name);
341             if (potion_smash_effect(creature_ptr, 0, y, x, q_ptr->k_idx)) {
342                 monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[creature_ptr->current_floor_ptr->grid_array[y][x].m_idx];
343                 if (creature_ptr->current_floor_ptr->grid_array[y][x].m_idx && is_friendly(m_ptr) && !monster_invulner_remaining(m_ptr)) {
344                     GAME_TEXT m_name[MAX_NLEN];
345                     monster_desc(creature_ptr, m_name, m_ptr, 0);
346                     msg_format(_("%sは怒った!", "%^s gets angry!"), m_name);
347                     set_hostile(creature_ptr, &creature_ptr->current_floor_ptr->m_list[creature_ptr->current_floor_ptr->grid_array[y][x].m_idx]);
348                 }
349             }
350
351             do_drop = FALSE;
352         } else {
353             j = 0;
354         }
355     }
356
357     if (return_when_thrown) {
358         int back_chance = randint1(30) + 20 + ((int)(adj_dex_th[creature_ptr->stat_ind[A_DEX]]) - 128);
359         char o2_name[MAX_NLEN];
360         bool super_boomerang = (((q_ptr->name1 == ART_MJOLLNIR) || (q_ptr->name1 == ART_AEGISFANG)) && boomerang);
361         j = -1;
362         if (boomerang)
363             back_chance += 4 + randint1(5);
364         if (super_boomerang)
365             back_chance += 100;
366         describe_flavor(creature_ptr, o2_name, q_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
367         if ((back_chance > 30) && (!one_in_(100) || super_boomerang)) {
368             for (i = cur_dis - 1; i > 0; i--) {
369                 if (panel_contains(ny[i], nx[i]) && player_can_see_bold(creature_ptr, ny[i], nx[i])) {
370                     SYMBOL_CODE c = object_char(q_ptr);
371                     byte a = object_attr(q_ptr);
372                     print_rel(creature_ptr, c, a, ny[i], nx[i]);
373                     move_cursor_relative(ny[i], nx[i]);
374                     term_fresh();
375                     term_xtra(TERM_XTRA_DELAY, msec);
376                     lite_spot(creature_ptr, ny[i], nx[i]);
377                     term_fresh();
378                 } else {
379                     term_xtra(TERM_XTRA_DELAY, msec);
380                 }
381             }
382
383             if ((back_chance > 37) && !creature_ptr->blind && (item >= 0)) {
384                 msg_format(_("%sが手元に返ってきた。", "%s comes back to you."), o2_name);
385                 come_back = TRUE;
386             } else {
387                 if (item >= 0) {
388                     msg_format(_("%sを受け損ねた!", "%s comes back, but you can't catch!"), o2_name);
389                 } else {
390                     msg_format(_("%sが返ってきた。", "%s comes back."), o2_name);
391                 }
392                 y = creature_ptr->y;
393                 x = creature_ptr->x;
394             }
395         } else {
396             msg_format(_("%sが返ってこなかった!", "%s doesn't come back!"), o2_name);
397         }
398     }
399
400     if (come_back) {
401         if (item == INVEN_RARM || item == INVEN_LARM) {
402             o_ptr = &creature_ptr->inventory_list[item];
403             object_copy(o_ptr, q_ptr);
404             creature_ptr->total_weight += q_ptr->weight;
405             creature_ptr->equip_cnt++;
406             creature_ptr->update |= PU_BONUS | PU_TORCH | PU_MANA;
407             creature_ptr->window |= PW_EQUIP;
408         } else {
409             store_item_to_inventory(creature_ptr, q_ptr);
410         }
411
412         do_drop = FALSE;
413     } else if (equiped_item) {
414         verify_equip_slot(creature_ptr, item);
415         calc_android_exp(creature_ptr);
416     }
417
418     if (do_drop) {
419         if (cave_have_flag_bold(creature_ptr->current_floor_ptr, y, x, FF_PROJECT)) {
420             (void)drop_near(creature_ptr, q_ptr, j, y, x);
421         } else {
422             (void)drop_near(creature_ptr, q_ptr, j, prev_y, prev_x);
423         }
424     }
425
426     return TRUE;
427 }