OSDN Git Service

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