OSDN Git Service

[Refactor] #37353 コメント整理 / Refactor comments.
[hengband/hengband.git] / src / monster-status.c
1 #include "angband.h"
2
3
4 /*!
5 * @brief モンスターの時限ステータスを取得する
6 * @return m_idx モンスターの参照ID
7 * @return mproc_type モンスターの時限ステータスID
8 * @return 残りターン値
9 */
10 int get_mproc_idx(MONSTER_IDX m_idx, int mproc_type)
11 {
12         s16b *cur_mproc_list = mproc_list[mproc_type];
13         int i;
14
15         for (i = mproc_max[mproc_type] - 1; i >= 0; i--)
16         {
17                 if (cur_mproc_list[i] == m_idx) return i;
18         }
19
20         return -1;
21 }
22
23 /*!
24 * @brief モンスターの時限ステータスリストを追加する
25 * @return m_idx モンスターの参照ID
26 * @return mproc_type 追加したいモンスターの時限ステータスID
27 * @return なし
28 */
29 static void mproc_add(MONSTER_IDX m_idx, int mproc_type)
30 {
31         if (mproc_max[mproc_type] < max_m_idx) mproc_list[mproc_type][mproc_max[mproc_type]++] = (s16b)m_idx;
32 }
33
34
35 /*!
36 * @brief モンスターの時限ステータスリストを削除
37 * @return m_idx モンスターの参照ID
38 * @return mproc_type 削除したいモンスターの時限ステータスID
39 * @return なし
40 */
41 static void mproc_remove(MONSTER_IDX m_idx, int mproc_type)
42 {
43         int mproc_idx = get_mproc_idx(m_idx, mproc_type);
44         if (mproc_idx >= 0) mproc_list[mproc_type][mproc_idx] = mproc_list[mproc_type][--mproc_max[mproc_type]];
45 }
46
47
48 /*!
49 * @brief モンスターの時限ステータスリストを初期化する / Initialize monster process
50 * @return なし
51 */
52 void mproc_init(void)
53 {
54         monster_type *m_ptr;
55         MONSTER_IDX i;
56         int cmi;
57
58         /* Reset "mproc_max[]" */
59         for (cmi = 0; cmi < MAX_MTIMED; cmi++) mproc_max[cmi] = 0;
60
61         /* Process the monsters (backwards) */
62         for (i = m_max - 1; i >= 1; i--)
63         {
64                 /* Access the monster */
65                 m_ptr = &m_list[i];
66
67                 /* Ignore "dead" monsters */
68                 if (!m_ptr->r_idx) continue;
69
70                 for (cmi = 0; cmi < MAX_MTIMED; cmi++)
71                 {
72                         if (m_ptr->mtimed[cmi]) mproc_add(i, cmi);
73                 }
74         }
75 }
76
77
78 /*!
79 * @brief モンスターの睡眠状態値をセットする /
80 * Set "m_ptr->mtimed[MTIMED_CSLEEP]", notice observable changes
81 * @param m_idx モンスター参照ID
82 * @param v セットする値
83 * @return 別途更新処理が必要な場合TRUEを返す
84 */
85 bool set_monster_csleep(MONSTER_IDX m_idx, int v)
86 {
87         monster_type *m_ptr = &m_list[m_idx];
88         bool notice = FALSE;
89
90         /* Hack -- Force good values */
91         v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
92
93         /* Open */
94         if (v)
95         {
96                 if (!MON_CSLEEP(m_ptr))
97                 {
98                         mproc_add(m_idx, MTIMED_CSLEEP);
99                         notice = TRUE;
100                 }
101         }
102
103         /* Shut */
104         else
105         {
106                 if (MON_CSLEEP(m_ptr))
107                 {
108                         mproc_remove(m_idx, MTIMED_CSLEEP);
109                         notice = TRUE;
110                 }
111         }
112
113         /* Use the value */
114         m_ptr->mtimed[MTIMED_CSLEEP] = (s16b)v;
115
116         if (!notice) return FALSE;
117
118         if (m_ptr->ml)
119         {
120                 /* Update health bar as needed */
121                 if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
122                 if (p_ptr->riding == m_idx) p_ptr->redraw |= (PR_UHEALTH);
123         }
124
125         if (r_info[m_ptr->r_idx].flags7 & RF7_HAS_LD_MASK) p_ptr->update |= (PU_MON_LITE);
126
127         return TRUE;
128 }
129
130
131 /*!
132 * @brief モンスターの加速状態値をセット /
133 * Set "m_ptr->mtimed[MTIMED_FAST]", notice observable changes
134 * @param m_idx モンスター参照ID
135 * @param v セットする値
136 * @return 別途更新処理が必要な場合TRUEを返す
137 */
138 bool set_monster_fast(MONSTER_IDX m_idx, int v)
139 {
140         monster_type *m_ptr = &m_list[m_idx];
141         bool notice = FALSE;
142
143         /* Hack -- Force good values */
144         v = (v > 200) ? 200 : (v < 0) ? 0 : v;
145
146         /* Open */
147         if (v)
148         {
149                 if (!MON_FAST(m_ptr))
150                 {
151                         mproc_add(m_idx, MTIMED_FAST);
152                         notice = TRUE;
153                 }
154         }
155
156         /* Shut */
157         else
158         {
159                 if (MON_FAST(m_ptr))
160                 {
161                         mproc_remove(m_idx, MTIMED_FAST);
162                         notice = TRUE;
163                 }
164         }
165
166         /* Use the value */
167         m_ptr->mtimed[MTIMED_FAST] = (s16b)v;
168
169         if (!notice) return FALSE;
170
171         if ((p_ptr->riding == m_idx) && !p_ptr->leaving) p_ptr->update |= (PU_BONUS);
172
173         return TRUE;
174 }
175
176
177 /*
178 * Set "m_ptr->mtimed[MTIMED_SLOW]", notice observable changes
179 */
180 bool set_monster_slow(MONSTER_IDX m_idx, int v)
181 {
182         monster_type *m_ptr = &m_list[m_idx];
183         bool notice = FALSE;
184
185         /* Hack -- Force good values */
186         v = (v > 200) ? 200 : (v < 0) ? 0 : v;
187
188         /* Open */
189         if (v)
190         {
191                 if (!MON_SLOW(m_ptr))
192                 {
193                         mproc_add(m_idx, MTIMED_SLOW);
194                         notice = TRUE;
195                 }
196         }
197
198         /* Shut */
199         else
200         {
201                 if (MON_SLOW(m_ptr))
202                 {
203                         mproc_remove(m_idx, MTIMED_SLOW);
204                         notice = TRUE;
205                 }
206         }
207
208         /* Use the value */
209         m_ptr->mtimed[MTIMED_SLOW] = (s16b)v;
210
211         if (!notice) return FALSE;
212
213         if ((p_ptr->riding == m_idx) && !p_ptr->leaving) p_ptr->update |= (PU_BONUS);
214
215         return TRUE;
216 }
217
218
219 /*!
220 * @brief モンスターの朦朧状態値をセット /
221 * Set "m_ptr->mtimed[MTIMED_STUNNED]", notice observable changes
222 * @param m_idx モンスター参照ID
223 * @param v セットする値
224 * @return 別途更新処理が必要な場合TRUEを返す
225 */
226 bool set_monster_stunned(MONSTER_IDX m_idx, int v)
227 {
228         monster_type *m_ptr = &m_list[m_idx];
229         bool notice = FALSE;
230
231         /* Hack -- Force good values */
232         v = (v > 200) ? 200 : (v < 0) ? 0 : v;
233
234         /* Open */
235         if (v)
236         {
237                 if (!MON_STUNNED(m_ptr))
238                 {
239                         mproc_add(m_idx, MTIMED_STUNNED);
240                         notice = TRUE;
241                 }
242         }
243
244         /* Shut */
245         else
246         {
247                 if (MON_STUNNED(m_ptr))
248                 {
249                         mproc_remove(m_idx, MTIMED_STUNNED);
250                         notice = TRUE;
251                 }
252         }
253
254         /* Use the value */
255         m_ptr->mtimed[MTIMED_STUNNED] = (s16b)v;
256
257         return notice;
258 }
259
260
261 /*!
262 * @brief モンスターの混乱状態値をセット /
263 * Set "m_ptr->mtimed[MTIMED_CONFUSED]", notice observable changes
264 * @param m_idx モンスター参照ID
265 * @param v セットする値
266 * @return 別途更新処理が必要な場合TRUEを返す
267 */
268 bool set_monster_confused(MONSTER_IDX m_idx, int v)
269 {
270         monster_type *m_ptr = &m_list[m_idx];
271         bool notice = FALSE;
272
273         /* Hack -- Force good values */
274         v = (v > 200) ? 200 : (v < 0) ? 0 : v;
275
276         /* Open */
277         if (v)
278         {
279                 if (!MON_CONFUSED(m_ptr))
280                 {
281                         mproc_add(m_idx, MTIMED_CONFUSED);
282                         notice = TRUE;
283                 }
284         }
285
286         /* Shut */
287         else
288         {
289                 if (MON_CONFUSED(m_ptr))
290                 {
291                         mproc_remove(m_idx, MTIMED_CONFUSED);
292                         notice = TRUE;
293                 }
294         }
295
296         /* Use the value */
297         m_ptr->mtimed[MTIMED_CONFUSED] = (s16b)v;
298
299         return notice;
300 }
301
302
303 /*!
304 * @brief モンスターの恐慌状態値をセット /
305 * Set "m_ptr->mtimed[MTIMED_MONFEAR]", notice observable changes
306 * @param m_idx モンスター参照ID
307 * @param v セットする値
308 * @return 別途更新処理が必要な場合TRUEを返す
309 */
310 bool set_monster_monfear(MONSTER_IDX m_idx, int v)
311 {
312         monster_type *m_ptr = &m_list[m_idx];
313         bool notice = FALSE;
314
315         /* Hack -- Force good values */
316         v = (v > 200) ? 200 : (v < 0) ? 0 : v;
317
318         /* Open */
319         if (v)
320         {
321                 if (!MON_MONFEAR(m_ptr))
322                 {
323                         mproc_add(m_idx, MTIMED_MONFEAR);
324                         notice = TRUE;
325                 }
326         }
327
328         /* Shut */
329         else
330         {
331                 if (MON_MONFEAR(m_ptr))
332                 {
333                         mproc_remove(m_idx, MTIMED_MONFEAR);
334                         notice = TRUE;
335                 }
336         }
337
338         /* Use the value */
339         m_ptr->mtimed[MTIMED_MONFEAR] = (s16b)v;
340
341         if (!notice) return FALSE;
342
343         if (m_ptr->ml)
344         {
345                 /* Update health bar as needed */
346                 if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
347                 if (p_ptr->riding == m_idx) p_ptr->redraw |= (PR_UHEALTH);
348         }
349
350         return TRUE;
351 }
352
353
354 /*!
355 * @brief モンスターの無敵状態値をセット /
356 * Set "m_ptr->mtimed[MTIMED_INVULNER]", notice observable changes
357 * @param m_idx モンスター参照ID
358 * @param v セットする値
359 * @param energy_need TRUEならば無敵解除時に行動ターン消費を行う
360 * @return 別途更新処理が必要な場合TRUEを返す
361 */
362 bool set_monster_invulner(MONSTER_IDX m_idx, int v, bool energy_need)
363 {
364         monster_type *m_ptr = &m_list[m_idx];
365         bool notice = FALSE;
366
367         /* Hack -- Force good values */
368         v = (v > 200) ? 200 : (v < 0) ? 0 : v;
369
370         /* Open */
371         if (v)
372         {
373                 if (!MON_INVULNER(m_ptr))
374                 {
375                         mproc_add(m_idx, MTIMED_INVULNER);
376                         notice = TRUE;
377                 }
378         }
379
380         /* Shut */
381         else
382         {
383                 if (MON_INVULNER(m_ptr))
384                 {
385                         mproc_remove(m_idx, MTIMED_INVULNER);
386                         if (energy_need && !p_ptr->wild_mode) m_ptr->energy_need += ENERGY_NEED();
387                         notice = TRUE;
388                 }
389         }
390
391         /* Use the value */
392         m_ptr->mtimed[MTIMED_INVULNER] = (s16b)v;
393
394         if (!notice) return FALSE;
395
396         if (m_ptr->ml)
397         {
398                 /* Update health bar as needed */
399                 if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);
400                 if (p_ptr->riding == m_idx) p_ptr->redraw |= (PR_UHEALTH);
401         }
402
403         return TRUE;
404 }
405
406
407 static u32b csleep_noise;
408
409 /*!
410 * @brief モンスターの各種状態値を時間経過により更新するサブルーチン
411 * @param m_idx モンスター参照ID
412 * @param mtimed_idx 更新するモンスターの時限ステータスID
413 * @return なし
414 */
415 static void process_monsters_mtimed_aux(MONSTER_IDX m_idx, int mtimed_idx)
416 {
417         monster_type *m_ptr = &m_list[m_idx];
418
419         switch (mtimed_idx)
420         {
421         case MTIMED_CSLEEP:
422         {
423                 monster_race *r_ptr = &r_info[m_ptr->r_idx];
424
425                 /* Assume does not wake up */
426                 bool test = FALSE;
427
428                 /* Hack -- Require proximity */
429                 if (m_ptr->cdis < AAF_LIMIT)
430                 {
431                         /* Handle "sensing radius" */
432                         if (m_ptr->cdis <= (is_pet(m_ptr) ? ((r_ptr->aaf > MAX_SIGHT) ? MAX_SIGHT : r_ptr->aaf) : r_ptr->aaf))
433                         {
434                                 /* We may wake up */
435                                 test = TRUE;
436                         }
437
438                         /* Handle "sight" and "aggravation" */
439                         else if ((m_ptr->cdis <= MAX_SIGHT) && (player_has_los_bold(m_ptr->fy, m_ptr->fx)))
440                         {
441                                 /* We may wake up */
442                                 test = TRUE;
443                         }
444                 }
445
446                 if (test)
447                 {
448                         u32b notice = randint0(1024);
449
450                         /* Nightmare monsters are more alert */
451                         if (ironman_nightmare) notice /= 2;
452
453                         /* Hack -- See if monster "notices" player */
454                         if ((notice * notice * notice) <= csleep_noise)
455                         {
456                                 /* Hack -- amount of "waking" */
457                                 /* Wake up faster near the player */
458                                 int d = (m_ptr->cdis < AAF_LIMIT / 2) ? (AAF_LIMIT / m_ptr->cdis) : 1;
459
460                                 /* Hack -- amount of "waking" is affected by speed of player */
461                                 d = (d * SPEED_TO_ENERGY(p_ptr->pspeed)) / 10;
462                                 if (d < 0) d = 1;
463
464                                 /* Monster wakes up "a little bit" */
465
466                                 /* Still asleep */
467                                 if (!set_monster_csleep(m_idx, MON_CSLEEP(m_ptr) - d))
468                                 {
469                                         /* Notice the "not waking up" */
470                                         if (is_original_ap_and_seen(m_ptr))
471                                         {
472                                                 /* Hack -- Count the ignores */
473                                                 if (r_ptr->r_ignore < MAX_UCHAR) r_ptr->r_ignore++;
474                                         }
475                                 }
476
477                                 /* Just woke up */
478                                 else
479                                 {
480                                         /* Notice the "waking up" */
481                                         if (m_ptr->ml)
482                                         {
483                                                 char m_name[80];
484
485                                                 /* Acquire the monster name */
486                                                 monster_desc(m_name, m_ptr, 0);
487
488                                                 /* Dump a message */
489                                                 msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name);
490                                         }
491
492                                         if (is_original_ap_and_seen(m_ptr))
493                                         {
494                                                 /* Hack -- Count the wakings */
495                                                 if (r_ptr->r_wake < MAX_UCHAR) r_ptr->r_wake++;
496                                         }
497                                 }
498                         }
499                 }
500                 break;
501         }
502
503         case MTIMED_FAST:
504                 /* Reduce by one, note if expires */
505                 if (set_monster_fast(m_idx, MON_FAST(m_ptr) - 1))
506                 {
507                         if (is_seen(m_ptr))
508                         {
509                                 char m_name[80];
510
511                                 /* Acquire the monster name */
512                                 monster_desc(m_name, m_ptr, 0);
513
514                                 /* Dump a message */
515                                 msg_format(_("%^sはもう加速されていない。", "%^s is no longer fast."), m_name);
516                         }
517                 }
518                 break;
519
520         case MTIMED_SLOW:
521                 /* Reduce by one, note if expires */
522                 if (set_monster_slow(m_idx, MON_SLOW(m_ptr) - 1))
523                 {
524                         if (is_seen(m_ptr))
525                         {
526                                 char m_name[80];
527
528                                 /* Acquire the monster name */
529                                 monster_desc(m_name, m_ptr, 0);
530
531                                 /* Dump a message */
532                                 msg_format(_("%^sはもう減速されていない。", "%^s is no longer slow."), m_name);
533                         }
534                 }
535                 break;
536
537         case MTIMED_STUNNED:
538         {
539                 int rlev = r_info[m_ptr->r_idx].level;
540
541                 /* Recover from stun */
542                 if (set_monster_stunned(m_idx, (randint0(10000) <= rlev * rlev) ? 0 : (MON_STUNNED(m_ptr) - 1)))
543                 {
544                         /* Message if visible */
545                         if (is_seen(m_ptr))
546                         {
547                                 char m_name[80];
548
549                                 /* Acquire the monster name */
550                                 monster_desc(m_name, m_ptr, 0);
551
552                                 /* Dump a message */
553                                 msg_format(_("%^sは朦朧状態から立ち直った。", "%^s is no longer stunned."), m_name);
554                         }
555                 }
556                 break;
557         }
558
559         case MTIMED_CONFUSED:
560                 /* Reduce the confusion */
561                 if (set_monster_confused(m_idx, MON_CONFUSED(m_ptr) - randint1(r_info[m_ptr->r_idx].level / 20 + 1)))
562                 {
563                         /* Message if visible */
564                         if (is_seen(m_ptr))
565                         {
566                                 char m_name[80];
567
568                                 /* Acquire the monster name */
569                                 monster_desc(m_name, m_ptr, 0);
570
571                                 /* Dump a message */
572                                 msg_format(_("%^sは混乱から立ち直った。", "%^s is no longer confused."), m_name);
573                         }
574                 }
575                 break;
576
577         case MTIMED_MONFEAR:
578                 /* Reduce the fear */
579                 if (set_monster_monfear(m_idx, MON_MONFEAR(m_ptr) - randint1(r_info[m_ptr->r_idx].level / 20 + 1)))
580                 {
581                         /* Visual note */
582                         if (is_seen(m_ptr))
583                         {
584                                 char m_name[80];
585 #ifndef JP
586                                 char m_poss[80];
587
588                                 /* Acquire the monster possessive */
589                                 monster_desc(m_poss, m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
590 #endif
591
592                                 /* Acquire the monster name */
593                                 monster_desc(m_name, m_ptr, 0);
594
595                                 /* Dump a message */
596 #ifdef JP
597                                 msg_format("%^sは勇気を取り戻した。", m_name);
598 #else
599                                 msg_format("%^s recovers %s courage.", m_name, m_poss);
600 #endif
601                         }
602                 }
603                 break;
604
605         case MTIMED_INVULNER:
606                 /* Reduce by one, note if expires */
607                 if (set_monster_invulner(m_idx, MON_INVULNER(m_ptr) - 1, TRUE))
608                 {
609                         if (is_seen(m_ptr))
610                         {
611                                 char m_name[80];
612
613                                 /* Acquire the monster name */
614                                 monster_desc(m_name, m_ptr, 0);
615
616                                 /* Dump a message */
617                                 msg_format(_("%^sはもう無敵でない。", "%^s is no longer invulnerable."), m_name);
618                         }
619                 }
620                 break;
621         }
622 }
623
624
625 /*!
626 * @brief 全モンスターの各種状態値を時間経過により更新するメインルーチン
627 * @param mtimed_idx 更新するモンスターの時限ステータスID
628 * @return なし
629 * @details
630 * Process the counters of monsters (once per 10 game turns)\n
631 * These functions are to process monsters' counters same as player's.
632 */
633 void process_monsters_mtimed(int mtimed_idx)
634 {
635         int  i;
636         s16b *cur_mproc_list = mproc_list[mtimed_idx];
637
638         /* Hack -- calculate the "player noise" */
639         if (mtimed_idx == MTIMED_CSLEEP) csleep_noise = (1L << (30 - p_ptr->skill_stl));
640
641         /* Process the monsters (backwards) */
642         for (i = mproc_max[mtimed_idx] - 1; i >= 0; i--)
643         {
644                 /* Access the monster */
645                 process_monsters_mtimed_aux(cur_mproc_list[i], mtimed_idx);
646         }
647 }
648
649 /*!
650 * @brief モンスターへの魔力消去処理
651 * @param m_idx 魔力消去を受けるモンスターの参照ID
652 * @return なし
653 */
654 void dispel_monster_status(MONSTER_IDX m_idx)
655 {
656         monster_type *m_ptr = &m_list[m_idx];
657         char         m_name[80];
658
659         monster_desc(m_name, m_ptr, 0);
660         if (set_monster_invulner(m_idx, 0, TRUE))
661         {
662                 if (m_ptr->ml) msg_format(_("%sはもう無敵ではない。", "%^s is no longer invulnerable."), m_name);
663         }
664         if (set_monster_fast(m_idx, 0))
665         {
666                 if (m_ptr->ml) msg_format(_("%sはもう加速されていない。", "%^s is no longer fast."), m_name);
667         }
668         if (set_monster_slow(m_idx, 0))
669         {
670                 if (m_ptr->ml) msg_format(_("%sはもう減速されていない。", "%^s is no longer slow."), m_name);
671         }
672 }
673
674 /*!
675 * @brief モンスターの時間停止処理
676 * @param num 時間停止を行った敵が行動できる回数
677 * @param who 時間停止処理の主体ID
678 * @param vs_player TRUEならば時間停止開始処理を行う
679 * @return 時間停止が行われている状態ならばTRUEを返す
680 */
681 bool process_the_world(int num, MONSTER_IDX who, bool vs_player)
682 {
683         monster_type *m_ptr = &m_list[hack_m_idx];  /* the world monster */
684
685         if (world_monster) return (FALSE);
686
687         if (vs_player)
688         {
689                 char m_name[80];
690                 monster_desc(m_name, m_ptr, 0);
691
692                 if (who == 1)
693                         msg_format(_("「『ザ・ワールド』!時は止まった!」", "%s yells 'The World! Time has stopped!'"), m_name);
694                 else if (who == 3)
695                         msg_format(_("「時よ!」", "%s yells 'Time!'"), m_name);
696                 else msg_print("hek!");
697
698                 msg_print(NULL);
699         }
700
701         /* This monster cast spells */
702         world_monster = hack_m_idx;
703
704         if (vs_player) do_cmd_redraw();
705
706         while (num--)
707         {
708                 if (!m_ptr->r_idx) break;
709                 process_monster(world_monster);
710
711                 reset_target(m_ptr);
712
713                 /* Notice stuff */
714                 if (p_ptr->notice) notice_stuff();
715
716                 if (p_ptr->update) update_stuff();
717
718                 /* Redraw stuff */
719                 if (p_ptr->redraw) redraw_stuff();
720
721                 /* Redraw stuff */
722                 if (p_ptr->window) window_stuff();
723
724                 if (vs_player) Term_xtra(TERM_XTRA_DELAY, 500);
725         }
726
727         /* Redraw map */
728         p_ptr->redraw |= (PR_MAP);
729
730         /* Update monsters */
731         p_ptr->update |= (PU_MONSTERS);
732
733         p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
734
735         world_monster = 0;
736         if (vs_player || (player_has_los_bold(m_ptr->fy, m_ptr->fx) && projectable(p_ptr->y, p_ptr->x, m_ptr->fy, m_ptr->fx)))
737         {
738                 msg_print(_("「時は動きだす…」", "You feel time flowing around you once more."));
739                 msg_print(NULL);
740         }
741
742         handle_stuff();
743
744         return (TRUE);
745 }
746
747 /*!
748 * @brief モンスターの経験値取得処理
749 * @param m_idx 経験値を得るモンスターの参照ID
750 * @param s_idx 撃破されたモンスター種族の参照ID
751 * @return なし
752 */
753 void monster_gain_exp(MONSTER_IDX m_idx, IDX s_idx)
754 {
755         monster_type *m_ptr;
756         monster_race *r_ptr;
757         monster_race *s_ptr;
758         int new_exp;
759
760         /* Paranoia */
761         if (m_idx <= 0 || s_idx <= 0) return;
762
763         m_ptr = &m_list[m_idx];
764
765         /* Paranoia -- Skip dead monsters */
766         if (!m_ptr->r_idx) return;
767
768         r_ptr = &r_info[m_ptr->r_idx];
769         s_ptr = &r_info[s_idx];
770
771         if (p_ptr->inside_battle) return;
772
773         if (!r_ptr->next_exp) return;
774
775         new_exp = s_ptr->mexp * s_ptr->level / (r_ptr->level + 2);
776         if (m_idx == p_ptr->riding) new_exp = (new_exp + 1) / 2;
777         if (!dun_level) new_exp /= 5;
778         m_ptr->exp += new_exp;
779         if (m_ptr->mflag2 & MFLAG2_CHAMELEON) return;
780
781         if (m_ptr->exp >= r_ptr->next_exp)
782         {
783                 char m_name[80];
784                 int old_hp = m_ptr->hp;
785                 int old_maxhp = m_ptr->max_maxhp;
786                 int old_r_idx = m_ptr->r_idx;
787                 byte old_sub_align = m_ptr->sub_align;
788
789                 /* Hack -- Reduce the racial counter of previous monster */
790                 real_r_ptr(m_ptr)->cur_num--;
791
792                 monster_desc(m_name, m_ptr, 0);
793                 m_ptr->r_idx = r_ptr->next_r_idx;
794
795                 /* Count the monsters on the level */
796                 real_r_ptr(m_ptr)->cur_num++;
797
798                 m_ptr->ap_r_idx = m_ptr->r_idx;
799                 r_ptr = &r_info[m_ptr->r_idx];
800
801                 if (r_ptr->flags1 & RF1_FORCE_MAXHP)
802                 {
803                         m_ptr->max_maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
804                 }
805                 else
806                 {
807                         m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
808                 }
809                 if (ironman_nightmare)
810                 {
811                         HIT_POINT hp = m_ptr->max_maxhp * 2L;
812                         m_ptr->max_maxhp = MIN(30000, hp);
813                 }
814                 m_ptr->maxhp = m_ptr->max_maxhp;
815                 m_ptr->hp = old_hp * m_ptr->maxhp / old_maxhp;
816
817                 /* dealt damage is 0 at initial*/
818                 m_ptr->dealt_damage = 0;
819
820                 /* Extract the monster base speed */
821                 m_ptr->mspeed = get_mspeed(r_ptr);
822
823                 /* Sub-alignment of a monster */
824                 if (!is_pet(m_ptr) && !(r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)))
825                         m_ptr->sub_align = old_sub_align;
826                 else
827                 {
828                         m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
829                         if (r_ptr->flags3 & RF3_EVIL) m_ptr->sub_align |= SUB_ALIGN_EVIL;
830                         if (r_ptr->flags3 & RF3_GOOD) m_ptr->sub_align |= SUB_ALIGN_GOOD;
831                 }
832
833                 m_ptr->exp = 0;
834
835                 if (is_pet(m_ptr) || m_ptr->ml)
836                 {
837                         if (!ignore_unview || player_can_see_bold(m_ptr->fy, m_ptr->fx))
838                         {
839                                 if (p_ptr->image)
840                                 {
841                                         monster_race *hallu_race;
842
843                                         do
844                                         {
845                                                 hallu_race = &r_info[randint1(max_r_idx - 1)];
846                                         } while (!hallu_race->name || (hallu_race->flags1 & RF1_UNIQUE));
847                                         msg_format(_("%sは%sに進化した。", "%^s evolved into %s."), m_name, r_name + hallu_race->name);
848                                 }
849                                 else
850                                 {
851                                         msg_format(_("%sは%sに進化した。", "%^s evolved into %s."), m_name, r_name + r_ptr->name);
852                                 }
853                         }
854
855                         if (!p_ptr->image) r_info[old_r_idx].r_xtra1 |= MR1_SINKA;
856
857                         /* Now you feel very close to this pet. */
858                         m_ptr->parent_m_idx = 0;
859                 }
860                 update_mon(m_idx, FALSE);
861                 lite_spot(m_ptr->fy, m_ptr->fx);
862         }
863         if (m_idx == p_ptr->riding) p_ptr->update |= PU_BONUS;
864 }