OSDN Git Service

[Refactor] #40477 Separated disturbance-optioncs.c/h from cmd-gameoption.c/h
[hengband/hengband.git] / src / monster-floor / monster-move.c
1 /*!
2  * @brief モンスターの移動に関する処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "monster-floor/monster-move.h"
8 #include "effect/effect-characteristics.h"
9 #include "game-option/disturbance-options.h"
10 #include "io/files-util.h"
11 #include "monster-race/race-indice-types.h"
12 #include "core/speed-table.h"
13 #include "monster-race/race-flags1.h"
14 #include "monster-race/race-flags2.h"
15 #include "monster-race/race-flags7.h"
16 #include "monster-race/race-flags8.h"
17 #include "monster-attack/monster-attack-processor.h"
18 #include "monster/monster-describer.h"
19 #include "monster/monster-flag-types.h"
20 #include "monster-floor/monster-object.h"
21 #include "monster/monster-status.h"
22 #include "monster/monster-update.h"
23 #include "monster/monster-info.h"
24 #include "pet/pet-util.h"
25 #include "player/player-move.h"
26 #include "spell/process-effect.h"
27 #include "spell/spells-type.h"
28
29 static bool check_hp_for_feat_destruction(feature_type *f_ptr, monster_type *m_ptr)
30 {
31         return !have_flag(f_ptr->flags, FF_GLASS) ||
32                 (r_info[m_ptr->r_idx].flags2 & RF2_STUPID) ||
33                 (m_ptr->hp >= MAX(m_ptr->maxhp / 3, 200));
34 }
35
36
37 /*!
38   * @brief モンスターによる壁の透過・破壊を行う
39   * @param target_ptr プレーヤーへの参照ポインタ
40   * @param m_ptr モンスターへの参照ポインタ
41   * @param ny モンスターのY座標
42   * @param nx モンスターのX座標
43   * @param can_cross モンスターが地形を踏破できるならばTRUE
44   * @return 透過も破壊もしなかった場合はFALSE、それ以外はTRUE
45   */
46 static bool process_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx, bool can_cross)
47 {
48         monster_race *r_ptr = &r_info[m_ptr->r_idx];
49         grid_type *g_ptr;
50         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
51         feature_type *f_ptr;
52         f_ptr = &f_info[g_ptr->feat];
53         if (player_bold(target_ptr, ny, nx))
54         {
55                 turn_flags_ptr->do_move = TRUE;
56                 return TRUE;
57         }
58
59         if (g_ptr->m_idx > 0)
60         {
61                 turn_flags_ptr->do_move = TRUE;
62                 return TRUE;
63         }
64
65         if (((r_ptr->flags2 & RF2_KILL_WALL) != 0) &&
66                 (can_cross ? !have_flag(f_ptr->flags, FF_LOS) : !turn_flags_ptr->is_riding_mon) &&
67                 have_flag(f_ptr->flags, FF_HURT_DISI) && !have_flag(f_ptr->flags, FF_PERMANENT) &&
68                 check_hp_for_feat_destruction(f_ptr, m_ptr))
69         {
70                 turn_flags_ptr->do_move = TRUE;
71                 if (!can_cross) turn_flags_ptr->must_alter_to_move = TRUE;
72
73                 turn_flags_ptr->did_kill_wall = TRUE;
74                 return TRUE;
75         }
76
77         if (!can_cross) return FALSE;
78
79         turn_flags_ptr->do_move = TRUE;
80         if (((r_ptr->flags2 & RF2_PASS_WALL) != 0) && (!turn_flags_ptr->is_riding_mon || target_ptr->pass_wall) &&
81                 have_flag(f_ptr->flags, FF_CAN_PASS))
82         {
83                 turn_flags_ptr->did_pass_wall = TRUE;
84         }
85
86         return TRUE;
87 }
88
89
90 /*!
91  * @brief モンスターが普通のドアを開ける処理
92  * @param target_ptr プレーヤーへの参照ポインタ
93  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
94  * @param m_ptr モンスターへの参照ポインタ
95  * @param ny モンスターのY座標
96  * @param nx モンスターのX座標
97  * @return ここではドアを開けず、ガラスのドアを開ける可能性があるならTRUE
98  */
99 static bool bash_normal_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
100 {
101         monster_race *r_ptr = &r_info[m_ptr->r_idx];
102         grid_type *g_ptr;
103         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
104         feature_type *f_ptr;
105         f_ptr = &f_info[g_ptr->feat];
106         turn_flags_ptr->do_move = FALSE;
107         if (((r_ptr->flags2 & RF2_OPEN_DOOR) == 0) || !have_flag(f_ptr->flags, FF_OPEN) ||
108                 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
109                 return TRUE;
110
111         if (f_ptr->power == 0)
112         {
113                 turn_flags_ptr->did_open_door = TRUE;
114                 turn_flags_ptr->do_turn = TRUE;
115                 return FALSE;
116         }
117
118         if (randint0(m_ptr->hp / 10) > f_ptr->power)
119         {
120                 cave_alter_feat(target_ptr, ny, nx, FF_DISARM);
121                 turn_flags_ptr->do_turn = TRUE;
122                 return FALSE;
123         }
124
125         return TRUE;
126 }
127
128
129 /*!
130  * @brief モンスターがガラスのドアを開ける処理
131  * @param target_ptr プレーヤーへの参照ポインタ
132  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
133  * @param m_ptr モンスターへの参照ポインタ
134  * @param g_ptr グリッドへの参照ポインタ
135  * @param f_ptr 地形への参照ポインタ
136  * @return なし
137  */
138 static void bash_glass_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, feature_type *f_ptr, bool may_bash)
139 {
140         monster_race *r_ptr = &r_info[m_ptr->r_idx];
141         if (!may_bash || ((r_ptr->flags2 & RF2_BASH_DOOR) == 0) || !have_flag(f_ptr->flags, FF_BASH) ||
142                 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
143                 return;
144
145         if (!check_hp_for_feat_destruction(f_ptr, m_ptr) || (randint0(m_ptr->hp / 10) <= f_ptr->power))
146                 return;
147
148         if (have_flag(f_ptr->flags, FF_GLASS))
149                 msg_print(_("ガラスが砕ける音がした!", "You hear glass breaking!"));
150         else
151                 msg_print(_("ドアを叩き開ける音がした!", "You hear a door burst open!"));
152
153         if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
154
155         turn_flags_ptr->did_bash_door = TRUE;
156         turn_flags_ptr->do_move = TRUE;
157         turn_flags_ptr->must_alter_to_move = TRUE;
158 }
159
160
161 /*!
162  * @brief モンスターによるドアの開放・破壊を行う
163  * @param target_ptr プレーヤーへの参照ポインタ
164  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
165  * @param m_ptr モンスターへの参照ポインタ
166  * @param ny モンスターのY座標
167  * @param nx モンスターのX座標
168  * @return モンスターが死亡した場合のみFALSE
169  */
170 static bool process_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
171 {
172         monster_race *r_ptr = &r_info[m_ptr->r_idx];
173         grid_type *g_ptr;
174         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
175         if (!is_closed_door(target_ptr, g_ptr->feat)) return TRUE;
176
177         feature_type *f_ptr;
178         f_ptr = &f_info[g_ptr->feat];
179         bool may_bash = bash_normal_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx);
180         bash_glass_door(target_ptr, turn_flags_ptr, m_ptr, f_ptr, may_bash);
181
182         if (!turn_flags_ptr->did_open_door && !turn_flags_ptr->did_bash_door) return TRUE;
183
184         if (turn_flags_ptr->did_bash_door &&
185                 ((randint0(100) < 50) || (feat_state(target_ptr, g_ptr->feat, FF_OPEN) == g_ptr->feat) || have_flag(f_ptr->flags, FF_GLASS)))
186         {
187                 cave_alter_feat(target_ptr, ny, nx, FF_BASH);
188                 if (!monster_is_valid(m_ptr))
189                 {
190                         target_ptr->update |= (PU_FLOW);
191                         target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
192                         if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_BASH_DOOR);
193
194                         return FALSE;
195                 }
196         }
197         else
198         {
199                 cave_alter_feat(target_ptr, ny, nx, FF_OPEN);
200         }
201
202         f_ptr = &f_info[g_ptr->feat];
203         turn_flags_ptr->do_view = TRUE;
204         return TRUE;
205 }
206
207
208 /*!
209  * @brief 守りのルーンによるモンスターの移動制限を処理する
210  * @param target_ptr プレーヤーへの参照ポインタ
211  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
212  * @param m_ptr モンスターへの参照ポインタ
213  * @param ny モンスターのY座標
214  * @param nx モンスターのX座標
215  * @return ルーンのある/なし
216  */
217 static bool process_protection_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
218 {
219         grid_type *g_ptr;
220         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
221         monster_race *r_ptr = &r_info[m_ptr->r_idx];
222         if (!turn_flags_ptr->do_move || !is_glyph_grid(g_ptr) ||
223                 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
224                 return FALSE;
225
226         turn_flags_ptr->do_move = FALSE;
227         if (is_pet(m_ptr) || (randint1(BREAK_GLYPH) >= r_ptr->level))
228                 return TRUE;
229
230         if (g_ptr->info & CAVE_MARK)
231         {
232                 msg_print(_("守りのルーンが壊れた!", "The rune of protection is broken!"));
233         }
234
235         g_ptr->info &= ~(CAVE_MARK);
236         g_ptr->info &= ~(CAVE_OBJECT);
237         g_ptr->mimic = 0;
238         turn_flags_ptr->do_move = TRUE;
239         note_spot(target_ptr, ny, nx);
240         return TRUE;
241 }
242
243
244 /*!
245  * @brief 爆発のルーンを処理する
246  * @param target_ptr プレーヤーへの参照ポインタ
247  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
248  * @param m_ptr モンスターへの参照ポインタ
249  * @param ny モンスターのY座標
250  * @param nx モンスターのX座標
251  * @return モンスターが死亡した場合のみFALSE
252  */
253 static bool process_explosive_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
254 {
255         grid_type *g_ptr;
256         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
257         monster_race *r_ptr = &r_info[m_ptr->r_idx];
258         if (!turn_flags_ptr->do_move || !is_explosive_rune_grid(g_ptr) ||
259                 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
260                 return TRUE;
261
262         turn_flags_ptr->do_move = FALSE;
263         if (is_pet(m_ptr)) return TRUE;
264
265         if (randint1(BREAK_MINOR_GLYPH) > r_ptr->level)
266         {
267                 if (g_ptr->info & CAVE_MARK)
268                 {
269                         msg_print(_("ルーンが爆発した!", "The rune explodes!"));
270                         BIT_FLAGS project_flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI;
271                         project(target_ptr, 0, 2, ny, nx, 2 * (target_ptr->lev + damroll(7, 7)), GF_MANA, project_flags, -1);
272                 }
273         }
274         else
275         {
276                 msg_print(_("爆発のルーンは解除された。", "An explosive rune was disarmed."));
277         }
278
279         g_ptr->info &= ~(CAVE_MARK);
280         g_ptr->info &= ~(CAVE_OBJECT);
281         g_ptr->mimic = 0;
282
283         note_spot(target_ptr, ny, nx);
284         lite_spot(target_ptr, ny, nx);
285
286         if (!monster_is_valid(m_ptr)) return FALSE;
287
288         turn_flags_ptr->do_move = TRUE;
289         return TRUE;
290 }
291
292
293 /*!
294  * @brief モンスターが壁を掘った後続処理を実行する
295  * @param target_ptr プレーヤーへの参照ポインタ
296  * @turn_flags_ptr ターン経過処理フラグへの参照ポインタ
297  * @param m_ptr モンスターへの参照ポインタ
298  * @param ny モンスターのY座標
299  * @param nx モンスターのX座標
300  * @return モンスターが死亡した場合のみFALSE
301  */
302 static bool process_post_dig_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
303 {
304         monster_race *r_ptr = &r_info[m_ptr->r_idx];
305         grid_type *g_ptr;
306         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
307         feature_type *f_ptr;
308         f_ptr = &f_info[g_ptr->feat];
309         if (!turn_flags_ptr->did_kill_wall || !turn_flags_ptr->do_move) return TRUE;
310
311         if (one_in_(GRINDNOISE))
312         {
313                 if (have_flag(f_ptr->flags, FF_GLASS))
314                         msg_print(_("何かの砕ける音が聞こえる。", "There is a crashing sound."));
315                 else
316                         msg_print(_("ギシギシいう音が聞こえる。", "There is a grinding sound."));
317         }
318
319         cave_alter_feat(target_ptr, ny, nx, FF_HURT_DISI);
320
321         if (!monster_is_valid(m_ptr))
322         {
323                 target_ptr->update |= (PU_FLOW);
324                 target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
325                 if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_KILL_WALL);
326
327                 return FALSE;
328         }
329
330         f_ptr = &f_info[g_ptr->feat];
331         turn_flags_ptr->do_view = TRUE;
332         turn_flags_ptr->do_turn = TRUE;
333         return TRUE;
334 }
335
336
337 /*!
338  * todo 少し長いが、これといってブロックとしてまとまった部分もないので暫定でこのままとする
339  * @brief モンスターの移動に関するメインルーチン
340  * @param target_ptr プレーヤーへの参照ポインタ
341  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
342  * @param m_idx モンスターID
343  * @param mm モンスターの移動方向
344  * @param oy 移動前の、モンスターのY座標
345  * @param ox 移動前の、モンスターのX座標
346  * @param count 移動回数 (のはず todo)
347  * @return 移動が阻害される何か (ドア等)があったらFALSE
348  */
349 bool process_monster_movement(player_type *target_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, POSITION oy, POSITION ox, int *count)
350 {
351         for (int i = 0; mm[i]; i++)
352         {
353                 int d = mm[i];
354                 if (d == 5) d = ddd[randint0(8)];
355
356                 POSITION ny = oy + ddy[d];
357                 POSITION nx = ox + ddx[d];
358                 if (!in_bounds2(target_ptr->current_floor_ptr, ny, nx)) continue;
359
360                 grid_type *g_ptr;
361                 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
362                 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
363                 monster_race *r_ptr = &r_info[m_ptr->r_idx];
364                 bool can_cross = monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0);
365
366                 if (!process_wall(target_ptr, turn_flags_ptr, m_ptr, ny, nx, can_cross))
367                 {
368                         if (!process_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
369                                 return FALSE;
370                 }
371
372                 if (!process_protection_rune(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
373                 {
374                         if (!process_explosive_rune(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
375                                 return FALSE;
376                 }
377
378                 exe_monster_attack_to_player(target_ptr, turn_flags_ptr, m_idx, ny, nx);
379                 if (process_monster_attack_to_monster(target_ptr, turn_flags_ptr, m_idx, g_ptr, can_cross)) return FALSE;
380
381                 if (turn_flags_ptr->is_riding_mon)
382                 {
383                         if (!target_ptr->riding_ryoute && !monster_fear_remaining(&target_ptr->current_floor_ptr->m_list[target_ptr->riding])) turn_flags_ptr->do_move = FALSE;
384                 }
385
386                 if (!process_post_dig_wall(target_ptr, turn_flags_ptr, m_ptr, ny, nx)) return FALSE;
387
388                 if (turn_flags_ptr->must_alter_to_move && (r_ptr->flags7 & RF7_AQUATIC))
389                 {
390                         if (!monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0))
391                                 turn_flags_ptr->do_move = FALSE;
392                 }
393
394                 if (turn_flags_ptr->do_move && !can_cross && !turn_flags_ptr->did_kill_wall && !turn_flags_ptr->did_bash_door)
395                         turn_flags_ptr->do_move = FALSE;
396
397                 if (turn_flags_ptr->do_move && (r_ptr->flags1 & RF1_NEVER_MOVE))
398                 {
399                         if (is_original_ap_and_seen(target_ptr, m_ptr))
400                                 r_ptr->r_flags1 |= (RF1_NEVER_MOVE);
401
402                         turn_flags_ptr->do_move = FALSE;
403                 }
404
405                 if (!turn_flags_ptr->do_move)
406                 {
407                         if (turn_flags_ptr->do_turn) break;
408
409                         continue;
410                 }
411
412                 turn_flags_ptr->do_turn = TRUE;
413                 feature_type *f_ptr;
414                 f_ptr = &f_info[g_ptr->feat];
415                 if (have_flag(f_ptr->flags, FF_TREE))
416                 {
417                         if (!(r_ptr->flags7 & RF7_CAN_FLY) && !(r_ptr->flags8 & RF8_WILD_WOOD))
418                         {
419                                 m_ptr->energy_need += ENERGY_NEED();
420                         }
421                 }
422
423                 if (!update_riding_monster(target_ptr, turn_flags_ptr, m_idx, oy, ox, ny, nx)) break;
424
425                 monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
426                 if (m_ptr->ml &&
427                         (disturb_move ||
428                         (disturb_near && (m_ptr->mflag & MFLAG_VIEW) && projectable(target_ptr, target_ptr->y, target_ptr->x, m_ptr->fy, m_ptr->fx)) ||
429                                 (disturb_high && ap_r_ptr->r_tkills && ap_r_ptr->level >= target_ptr->lev)))
430                 {
431                         if (is_hostile(m_ptr))
432                                 disturb(target_ptr, FALSE, TRUE);
433                 }
434
435                 bool is_takable_or_killable = g_ptr->o_idx > 0;
436                 is_takable_or_killable &= (r_ptr->flags2 & (RF2_TAKE_ITEM | RF2_KILL_ITEM)) != 0;
437
438                 bool is_pickup_items = (target_ptr->pet_extra_flags & PF_PICKUP_ITEMS) != 0;
439                 is_pickup_items &= (r_ptr->flags2 & RF2_TAKE_ITEM) != 0;
440
441                 is_takable_or_killable &= !is_pet(m_ptr) || is_pickup_items;
442                 if (!is_takable_or_killable)
443                 {
444                         if (turn_flags_ptr->do_turn) break;
445
446                         continue;
447                 }
448
449                 update_object_by_monster_movement(target_ptr, turn_flags_ptr, m_idx, ny, nx);
450                 if (turn_flags_ptr->do_turn) break;
451
452                 (*count)++;
453         }
454
455         return TRUE;
456 }
457
458
459 /*!
460  * @brief モンスターを喋らせたり足音を立てたりする
461  * @param target_ptr プレーヤーへの参照ポインタ
462  * @param m_idx モンスターID
463  * @param oy モンスターが元々いたY座標
464  * @param ox モンスターが元々いたX座標
465  * @param aware モンスターがプレーヤーに気付いているならばTRUE、超隠密状態ならばFALSE
466  * @return なし
467  */
468 void process_speak_sound(player_type *target_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, bool aware)
469 {
470         if (target_ptr->phase_out) return;
471
472         monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
473         monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
474         if (m_ptr->ap_r_idx == MON_CYBER &&
475                 one_in_(CYBERNOISE) &&
476                 !m_ptr->ml && (m_ptr->cdis <= MAX_SIGHT))
477         {
478                 if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
479                 msg_print(_("重厚な足音が聞こえた。", "You hear heavy steps."));
480         }
481
482         if (((ap_r_ptr->flags2 & RF2_CAN_SPEAK) == 0) || !aware ||
483                 !one_in_(SPEAK_CHANCE) ||
484                 !player_has_los_bold(target_ptr, oy, ox) ||
485                 !projectable(target_ptr, oy, ox, target_ptr->y, target_ptr->x))
486                 return;
487
488         GAME_TEXT m_name[MAX_NLEN];
489         char monmessage[1024];
490         concptr filename;
491
492         if (m_ptr->ml)
493                 monster_desc(target_ptr, m_name, m_ptr, 0);
494         else
495                 strcpy(m_name, _("それ", "It"));
496
497         if (monster_fear_remaining(m_ptr))
498                 filename = _("monfear_j.txt", "monfear.txt");
499         else if (is_pet(m_ptr))
500                 filename = _("monpet_j.txt", "monpet.txt");
501         else if (is_friendly(m_ptr))
502                 filename = _("monfrien_j.txt", "monfrien.txt");
503         else
504                 filename = _("monspeak_j.txt", "monspeak.txt");
505
506         if (get_rnd_line(filename, m_ptr->ap_r_idx, monmessage) == 0)
507         {
508                 msg_format(_("%^s%s", "%^s %s"), m_name, monmessage);
509         }
510 }
511
512 /*!
513  * @brief モンスターの目標地点をセットする / Set the target of counter attack
514  * @param m_ptr モンスターの参照ポインタ
515  * @param y 目標y座標
516  * @param x 目標x座標
517  * @return なし
518  */
519 void set_target(monster_type *m_ptr, POSITION y, POSITION x)
520 {
521     m_ptr->target_y = y;
522     m_ptr->target_x = x;
523 }
524
525 /*!
526  * @brief モンスターの目標地点をリセットする / Reset the target of counter attack
527  * @param m_ptr モンスターの参照ポインタ
528  * @return なし
529  */
530 void reset_target(monster_type *m_ptr) { set_target(m_ptr, 0, 0); }