OSDN Git Service

[Refactor] #3336 exe_write_diary() の引数にstrnfmt() で文字列を作っていた箇所をformat() に差し替え、basic_st...
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-death.cpp
1 #include "monster-floor/monster-death.h"
2 #include "artifact/fixed-art-generator.h"
3 #include "artifact/fixed-art-types.h"
4 #include "cmd-building/cmd-building.h"
5 #include "dungeon/quest-completion-checker.h"
6 #include "effect/effect-characteristics.h"
7 #include "effect/effect-processor.h"
8 #include "floor/floor-object.h"
9 #include "game-option/birth-options.h"
10 #include "game-option/play-record-options.h"
11 #include "io/write-diary.h"
12 #include "lore/lore-store.h"
13 #include "main/music-definitions-table.h"
14 #include "main/sound-of-music.h"
15 #include "market/arena-info-table.h"
16 #include "monster-floor/monster-death-util.h"
17 #include "monster-floor/monster-object.h"
18 #include "monster-floor/special-death-switcher.h"
19 #include "monster-race/monster-race-hook.h"
20 #include "monster-race/monster-race.h"
21 #include "monster-race/race-brightness-mask.h"
22 #include "monster-race/race-flags1.h"
23 #include "monster-race/race-flags2.h"
24 #include "monster-race/race-flags7.h"
25 #include "monster-race/race-indice-types.h"
26 #include "monster/monster-describer.h"
27 #include "monster/monster-description-types.h"
28 #include "monster/monster-flag-types.h"
29 #include "monster/monster-info.h"
30 #include "monster/monster-list.h"
31 #include "object-enchant/item-apply-magic.h"
32 #include "object-enchant/item-magic-applier.h"
33 #include "object/object-kind-hook.h"
34 #include "pet/pet-fall-off.h"
35 #include "player/patron.h"
36 #include "sv-definition/sv-other-types.h"
37 #include "sv-definition/sv-scroll-types.h"
38 #include "system/artifact-type-definition.h"
39 #include "system/building-type-definition.h"
40 #include "system/dungeon-info.h"
41 #include "system/floor-type-definition.h"
42 #include "system/item-entity.h"
43 #include "system/monster-entity.h"
44 #include "system/monster-race-info.h"
45 #include "system/player-type-definition.h"
46 #include "system/redrawing-flags-updater.h"
47 #include "system/system-variables.h"
48 #include "timed-effect/player-hallucination.h"
49 #include "timed-effect/timed-effects.h"
50 #include "util/bit-flags-calculator.h"
51 #include "view/display-messages.h"
52 #include "world/world.h"
53 #include <algorithm>
54
55 static void write_pet_death(PlayerType *player_ptr, monster_death_type *md_ptr)
56 {
57     md_ptr->md_y = md_ptr->m_ptr->fy;
58     md_ptr->md_x = md_ptr->m_ptr->fx;
59     if (record_named_pet && md_ptr->m_ptr->is_named_pet()) {
60         const auto m_name = monster_desc(player_ptr, md_ptr->m_ptr, MD_INDEF_VISIBLE);
61         exe_write_diary(player_ptr, DIARY_NAMED_PET, 3, m_name);
62     }
63 }
64
65 static void on_dead_explosion(PlayerType *player_ptr, monster_death_type *md_ptr)
66 {
67     for (int i = 0; i < 4; i++) {
68         if (md_ptr->r_ptr->blow[i].method != RaceBlowMethodType::EXPLODE) {
69             continue;
70         }
71
72         BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
73         AttributeType typ = mbe_info[enum2i(md_ptr->r_ptr->blow[i].effect)].explode_type;
74         DICE_NUMBER d_dice = md_ptr->r_ptr->blow[i].d_dice;
75         DICE_SID d_side = md_ptr->r_ptr->blow[i].d_side;
76         int damage = damroll(d_dice, d_side);
77         (void)project(player_ptr, md_ptr->m_idx, 3, md_ptr->md_y, md_ptr->md_x, damage, typ, flg);
78         break;
79     }
80 }
81
82 static void on_defeat_arena_monster(PlayerType *player_ptr, monster_death_type *md_ptr)
83 {
84     auto *floor_ptr = player_ptr->current_floor_ptr;
85     if (!floor_ptr->inside_arena || md_ptr->m_ptr->is_pet()) {
86         return;
87     }
88
89     player_ptr->exit_bldg = true;
90     if (player_ptr->arena_number > MAX_ARENA_MONS) {
91         msg_print(_("素晴らしい!君こそ真の勝利者だ。", "You are a Genuine Champion!"));
92     } else {
93         msg_print(_("勝利!チャンピオンへの道を進んでいる。", "Victorious! You're on your way to becoming Champion."));
94     }
95
96     const auto &arena = arena_info[player_ptr->arena_number];
97     const auto tval = arena.key.tval();
98     if (tval > ItemKindType::NONE) {
99         ItemEntity forge;
100         auto *q_ptr = &forge;
101         q_ptr->prep(lookup_baseitem_id(arena.key));
102         ItemMagicApplier(player_ptr, q_ptr, floor_ptr->object_level, AM_NO_FIXED_ART).execute();
103         (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
104     }
105
106     if (player_ptr->arena_number > MAX_ARENA_MONS) {
107         player_ptr->arena_number++;
108     }
109
110     player_ptr->arena_number++;
111     if (!record_arena) {
112         return;
113     }
114
115     const auto m_name = monster_desc(player_ptr, md_ptr->m_ptr, MD_WRONGDOER_NAME);
116     exe_write_diary(player_ptr, DIARY_ARENA, player_ptr->arena_number, m_name);
117 }
118
119 static void drop_corpse(PlayerType *player_ptr, monster_death_type *md_ptr)
120 {
121     auto *floor_ptr = player_ptr->current_floor_ptr;
122     bool is_drop_corpse = one_in_(md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) ? 1 : 4);
123     is_drop_corpse &= md_ptr->r_ptr->drop_flags.has_any_of({ MonsterDropType::DROP_CORPSE, MonsterDropType::DROP_SKELETON });
124     is_drop_corpse &= !(floor_ptr->inside_arena || player_ptr->phase_out || md_ptr->cloned || ((md_ptr->m_ptr->r_idx == w_ptr->today_mon) && md_ptr->m_ptr->is_pet()));
125     if (!is_drop_corpse) {
126         return;
127     }
128
129     bool corpse = false;
130     if (md_ptr->r_ptr->drop_flags.has_not(MonsterDropType::DROP_SKELETON)) {
131         corpse = true;
132     } else if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_CORPSE) && md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
133         corpse = true;
134     } else if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_CORPSE)) {
135         if ((0 - ((md_ptr->m_ptr->maxhp) / 4)) > md_ptr->m_ptr->hp) {
136             if (one_in_(5)) {
137                 corpse = true;
138             }
139         } else {
140             if (!one_in_(5)) {
141                 corpse = true;
142             }
143         }
144     }
145
146     ItemEntity forge;
147     auto *q_ptr = &forge;
148     q_ptr->prep(lookup_baseitem_id({ ItemKindType::CORPSE, (corpse ? SV_CORPSE : SV_SKELETON) }));
149     ItemMagicApplier(player_ptr, q_ptr, floor_ptr->object_level, AM_NO_FIXED_ART).execute();
150     q_ptr->pval = enum2i(md_ptr->m_ptr->r_idx);
151     (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
152 }
153
154 /*!
155  * @brief アーティファクトのドロップ判定処理
156  * @param player_ptr プレイヤーへの参照ポインタ
157  * @param md_ptr モンスター死亡構造体への参照ポインタ
158  * @return 何かドロップするならドロップしたアーティファクトのID、何もドロップしないなら0
159  */
160 static void drop_artifact_from_unique(PlayerType *player_ptr, monster_death_type *md_ptr)
161 {
162     for (const auto &[a_idx, chance] : md_ptr->r_ptr->drop_artifacts) {
163         if (!w_ptr->wizard && (randint0(100) >= chance)) {
164             continue;
165         }
166
167         if (drop_single_artifact(player_ptr, md_ptr, a_idx)) {
168             return;
169         }
170     }
171 }
172
173 /*!
174  * @brief 特定アーティファクトのドロップ処理
175  * @param player_ptr プレイヤーへの参照ポインタ
176  * @param md_ptr モンスター死亡構造体への参照ポインタ
177  * @param a_ix ドロップを試みるアーティファクトID
178  * @return ドロップするならtrue
179  */
180 bool drop_single_artifact(PlayerType *player_ptr, monster_death_type *md_ptr, FixedArtifactId a_idx)
181 {
182     auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
183     if (artifact.is_generated) {
184         return false;
185     }
186
187     return create_named_art(player_ptr, a_idx, md_ptr->md_y, md_ptr->md_x);
188 }
189
190 static short drop_dungeon_final_artifact(PlayerType *player_ptr, monster_death_type *md_ptr)
191 {
192     const auto &dungeon = dungeons_info[player_ptr->current_floor_ptr->dungeon_idx];
193     const auto has_reward = dungeon.final_object > 0;
194     const auto bi_id = has_reward ? dungeon.final_object : lookup_baseitem_id({ ItemKindType::SCROLL, SV_SCROLL_ACQUIREMENT });
195     if (dungeon.final_artifact == FixedArtifactId::NONE) {
196         return bi_id;
197     }
198
199     const auto a_idx = dungeon.final_artifact;
200     const auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
201     if (artifact.is_generated) {
202         return bi_id;
203     }
204
205     create_named_art(player_ptr, a_idx, md_ptr->md_y, md_ptr->md_x);
206
207     return dungeon.final_object ? bi_id : 0;
208 }
209
210 static void drop_artifacts(PlayerType *player_ptr, monster_death_type *md_ptr)
211 {
212     if (!md_ptr->drop_chosen_item) {
213         return;
214     }
215
216     drop_artifact_from_unique(player_ptr, md_ptr);
217     const auto *floor_ptr = player_ptr->current_floor_ptr;
218     const auto &dungeon = dungeons_info[floor_ptr->dungeon_idx];
219     if (((md_ptr->r_ptr->flags7 & RF7_GUARDIAN) == 0) || (dungeon.final_guardian != md_ptr->m_ptr->r_idx)) {
220         return;
221     }
222
223     short bi_id = drop_dungeon_final_artifact(player_ptr, md_ptr);
224     if (bi_id != 0) {
225         ItemEntity forge;
226         auto *q_ptr = &forge;
227         q_ptr->prep(bi_id);
228         ItemMagicApplier(player_ptr, q_ptr, floor_ptr->object_level, AM_NO_FIXED_ART | AM_GOOD).execute();
229         (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
230     }
231
232     msg_format(_("あなたは%sを制覇した!", "You have conquered %s!"), dungeon.name.data());
233 }
234
235 static void decide_drop_quality(monster_death_type *md_ptr)
236 {
237     md_ptr->mo_mode = 0L;
238     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_GOOD)) {
239         md_ptr->mo_mode |= AM_GOOD;
240     }
241
242     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_GREAT)) {
243         md_ptr->mo_mode |= (AM_GOOD | AM_GREAT);
244     }
245 }
246
247 static int decide_drop_numbers(PlayerType *player_ptr, monster_death_type *md_ptr, const bool drop_item)
248 {
249     int drop_numbers = 0;
250     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_60) && (randint0(100) < 60)) {
251         drop_numbers++;
252     }
253
254     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_90) && (randint0(100) < 90)) {
255         drop_numbers++;
256     }
257
258     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_1D2)) {
259         drop_numbers += damroll(1, 2);
260     }
261
262     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_2D2)) {
263         drop_numbers += damroll(2, 2);
264     }
265
266     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_3D2)) {
267         drop_numbers += damroll(3, 2);
268     }
269
270     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_4D2)) {
271         drop_numbers += damroll(4, 2);
272     }
273
274     if (md_ptr->cloned && md_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
275         drop_numbers = 0;
276     }
277
278     if (md_ptr->m_ptr->is_pet() || player_ptr->phase_out || player_ptr->current_floor_ptr->inside_arena) {
279         drop_numbers = 0;
280     }
281
282     if (!drop_item && (md_ptr->r_ptr->d_char != '$')) {
283         drop_numbers = 0;
284     }
285
286     if ((md_ptr->r_ptr->flags2 & (RF2_MULTIPLY)) && (md_ptr->r_ptr->r_akills > 1024)) {
287         drop_numbers = 0;
288     }
289
290     return drop_numbers;
291 }
292
293 static void drop_items_golds(PlayerType *player_ptr, monster_death_type *md_ptr, int drop_numbers)
294 {
295     int dump_item = 0;
296     int dump_gold = 0;
297     for (int i = 0; i < drop_numbers; i++) {
298         ItemEntity forge;
299         auto *q_ptr = &forge;
300         q_ptr->wipe();
301         if (md_ptr->do_gold && (!md_ptr->do_item || (randint0(100) < 50))) {
302             if (!make_gold(player_ptr, q_ptr)) {
303                 continue;
304             }
305
306             dump_gold++;
307         } else {
308             if (!make_object(player_ptr, q_ptr, md_ptr->mo_mode)) {
309                 continue;
310             }
311
312             dump_item++;
313         }
314
315         (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
316     }
317
318     auto *floor_ptr = player_ptr->current_floor_ptr;
319     floor_ptr->object_level = floor_ptr->base_level;
320     coin_type = 0;
321     bool visible = (md_ptr->m_ptr->ml && !player_ptr->effects()->hallucination()->is_hallucinated()) || (md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE));
322     if (visible && (dump_item || dump_gold)) {
323         lore_treasure(player_ptr, md_ptr->m_idx, dump_item, dump_gold);
324     }
325 }
326
327 /*!
328  * @brief 最終ボス(混沌のサーペント)を倒したときの処理
329  * @param player_ptr プレイヤー情報への参照ポインタ
330  */
331 static void on_defeat_last_boss(PlayerType *player_ptr)
332 {
333     w_ptr->total_winner = true;
334     add_winner_class(player_ptr->pclass);
335     RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TITLE);
336     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_FINAL_QUEST_CLEAR);
337     exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("見事に変愚蛮怒の勝利者となった!", "finally became *WINNER* of Hengband!"));
338     patron_list[player_ptr->chaos_patron].admire(player_ptr);
339     msg_print(_("*** おめでとう ***", "*** CONGRATULATIONS ***"));
340     msg_print(_("あなたはゲームをコンプリートしました。", "You have won the game!"));
341     msg_print(_("準備が整ったら引退(自殺コマンド)しても結構です。", "You may retire (commit suicide) when you are ready."));
342 }
343
344 /*!
345  * @brief モンスターが死亡した時の処理 /
346  * Handle the "death" of a monster.
347  * @param m_idx 死亡したモンスターのID
348  * @param drop_item TRUEならばモンスターのドロップ処理を行う
349  * @param type ラストアタックの属性 (単一属性)
350  */
351 void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, AttributeType type)
352 {
353     AttributeFlags flags;
354     flags.clear();
355     flags.set(type);
356     monster_death(player_ptr, m_idx, drop_item, flags);
357 }
358
359 /*!
360  * @brief モンスターが死亡した時の処理 /
361  * Handle the "death" of a monster.
362  * @param m_idx 死亡したモンスターのID
363  * @param drop_item TRUEならばモンスターのドロップ処理を行う
364  * @param attribute_flags ラストアタックの属性 (複数属性)
365  * @details
366  * <pre>
367  * Disperse treasures centered at the monster location based on the
368  * various flags contained in the monster flags fields.
369  * Check for "Quest" completion when a quest monster is killed.
370  * Note that only the player can induce "monster_death()" on Uniques.
371  * Thus (for now) all Quest monsters should be Uniques.
372  * Note that monsters can now carry objects, and when a monster dies,
373  * it drops all of its objects, which may disappear in crowded rooms.
374  * </pre>
375  */
376 void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, AttributeFlags attribute_flags)
377 {
378     monster_death_type tmp_md;
379     monster_death_type *md_ptr = initialize_monster_death_type(player_ptr, &tmp_md, m_idx, drop_item);
380     if (w_ptr->timewalk_m_idx && w_ptr->timewalk_m_idx == m_idx) {
381         w_ptr->timewalk_m_idx = 0;
382     }
383
384     // プレイヤーしかユニークを倒せないのでここで時間を記録
385     if (md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) && md_ptr->m_ptr->mflag2.has_not(MonsterConstantFlagType::CLONED)) {
386         update_playtime();
387         md_ptr->r_ptr->defeat_time = w_ptr->play_time;
388         md_ptr->r_ptr->defeat_level = player_ptr->lev;
389     }
390
391     if (md_ptr->r_ptr->brightness_flags.has_any_of(ld_mask)) {
392         RedrawingFlagsUpdater::get_instance().set_flag(StatusRedrawingFlag::MONSTER_LITE);
393     }
394
395     write_pet_death(player_ptr, md_ptr);
396     on_dead_explosion(player_ptr, md_ptr);
397     if (md_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
398         choose_new_monster(player_ptr, m_idx, true, MonsterRaceId::CHAMELEON);
399         md_ptr->r_ptr = &monraces_info[md_ptr->m_ptr->r_idx];
400     }
401
402     QuestCompletionChecker(player_ptr, md_ptr->m_ptr).complete();
403     on_defeat_arena_monster(player_ptr, md_ptr);
404     if (m_idx == player_ptr->riding && process_fall_off_horse(player_ptr, -1, false)) {
405         msg_print(_("地面に落とされた。", "You have fallen from the pet you were riding."));
406     }
407
408     drop_corpse(player_ptr, md_ptr);
409     monster_drop_carried_objects(player_ptr, md_ptr->m_ptr);
410     decide_drop_quality(md_ptr);
411     switch_special_death(player_ptr, md_ptr, attribute_flags);
412     drop_artifacts(player_ptr, md_ptr);
413     int drop_numbers = decide_drop_numbers(player_ptr, md_ptr, drop_item);
414     coin_type = md_ptr->force_coin;
415     auto *floor_ptr = player_ptr->current_floor_ptr;
416     floor_ptr->object_level = (floor_ptr->dun_level + md_ptr->r_ptr->level) / 2;
417     drop_items_golds(player_ptr, md_ptr, drop_numbers);
418     if (((md_ptr->r_ptr->flags1 & RF1_QUESTOR) == 0) || player_ptr->phase_out || (md_ptr->m_ptr->r_idx != MonsterRaceId::SERPENT) || md_ptr->cloned) {
419         return;
420     }
421
422     on_defeat_last_boss(player_ptr);
423 }
424
425 /*!
426  * @brief モンスターを撃破した際の述語メッセージを返す /
427  * Return monster death string
428  * @param r_ptr 撃破されたモンスターの種族情報を持つ構造体の参照ポインタ
429  * @return 撃破されたモンスターの述語
430  */
431 concptr extract_note_dies(MonsterRaceId r_idx)
432 {
433     const auto &r_ref = monraces_info[r_idx];
434     const auto explode = std::any_of(std::begin(r_ref.blow), std::end(r_ref.blow),
435         [](const auto &blow) { return blow.method == RaceBlowMethodType::EXPLODE; });
436
437     if (monster_living(r_idx)) {
438         if (explode) {
439             return _("は爆発して死んだ。", " explodes and dies.");
440         }
441
442         return _("は死んだ。", " dies.");
443     }
444
445     if (explode) {
446         return _("は爆発して粉々になった。", " explodes into tiny shreds.");
447     }
448
449     return _("を倒した。", " is destroyed.");
450 }