OSDN Git Service

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