OSDN Git Service

Merge pull request #3904 from Hourier/Change-Signature-GetDirection
[hengbandforosx/hengbandosx.git] / src / specific-object / monster-ball.cpp
1 #include "specific-object/monster-ball.h"
2 #include "effect/spells-effect-util.h"
3 #include "floor/geometry.h"
4 #include "game-option/input-options.h"
5 #include "monster-floor/monster-generator.h"
6 #include "monster-floor/place-monster-types.h"
7 #include "monster-race/monster-race.h"
8 #include "monster/monster-info.h"
9 #include "monster/monster-util.h"
10 #include "object/tval-types.h"
11 #include "pet/pet-util.h"
12 #include "racial/racial-android.h"
13 #include "spell-kind/spells-launcher.h"
14 #include "system/floor-type-definition.h"
15 #include "system/item-entity.h"
16 #include "system/monster-entity.h"
17 #include "system/monster-race-info.h"
18 #include "system/player-type-definition.h"
19 #include "target/target-getter.h"
20 #include "util/flag-group.h"
21 #include "util/string-processor.h"
22 #include "view/display-messages.h"
23 #include <sstream>
24
25 static void inscribe_nickname(ItemEntity &item, const CapturedMonsterType &cap_mon)
26 {
27     if (cap_mon.nickname.empty()) {
28         return;
29     }
30
31     auto &insc = item.inscription;
32     if (!insc) {
33         insc = "";
34     }
35
36     if (auto s = angband_strchr(insc->data(), '#'); s != nullptr) {
37         insc->erase(s - insc->data());
38     }
39
40     std::stringstream nickname;
41     nickname << '#' << _("", '\'') << cap_mon.nickname << _("", '\'');
42
43     insc->append(nickname.str());
44 }
45
46 static bool capture_monster(PlayerType *player_ptr, ItemEntity &item)
47 {
48     const auto old_target_pet = target_pet;
49     target_pet = true;
50     DIRECTION dir;
51     if (!get_aim_dir(player_ptr, &dir)) {
52         target_pet = old_target_pet;
53         return false;
54     }
55
56     target_pet = old_target_pet;
57     CapturedMonsterType cap_mon;
58     if (!fire_ball(player_ptr, AttributeType::CAPTURE, dir, 0, 0, &cap_mon)) {
59         return true;
60     }
61
62     item.pval = enum2i(cap_mon.r_idx);
63     item.captured_monster_speed = cap_mon.speed;
64     item.captured_monster_current_hp = cap_mon.current_hp;
65     item.captured_monster_max_hp = cap_mon.max_hp;
66     inscribe_nickname(item, cap_mon);
67     return true;
68 }
69
70 static void restore_monster_nickname(MonsterEntity &monster, ItemEntity &item)
71 {
72     if (!item.is_inscribed()) {
73         return;
74     }
75
76     auto &insc = item.inscription;
77     const auto s = angband_strchr(insc->data(), '#');
78     if (s == nullptr) {
79         return;
80     }
81
82     std::string_view nickname = s + 1;
83 #ifndef JP
84     if (nickname.starts_with('\'')) {
85         nickname.remove_prefix(1);
86         if (nickname.ends_with('\'')) {
87             nickname.remove_suffix(1);
88         }
89     }
90 #endif
91     monster.nickname = nickname;
92
93     insc->erase(s - insc->data());
94 }
95
96 static bool release_monster(PlayerType *player_ptr, ItemEntity &item, DIRECTION dir)
97 {
98     auto r_idx = i2enum<MonsterRaceId>(item.pval);
99     if (!monster_can_enter(player_ptr, player_ptr->y + ddy[dir], player_ptr->x + ddx[dir], &monraces_info[r_idx], 0)) {
100         return false;
101     }
102
103     if (!place_specific_monster(player_ptr, 0, player_ptr->y + ddy[dir], player_ptr->x + ddx[dir], r_idx, PM_FORCE_PET | PM_NO_KAGE)) {
104         return false;
105     }
106
107     auto &monster = player_ptr->current_floor_ptr->m_list[hack_m_idx_ii];
108     if (item.captured_monster_speed > 0) {
109         monster.mspeed = item.captured_monster_speed;
110     }
111
112     if (item.captured_monster_max_hp) {
113         monster.max_maxhp = item.captured_monster_max_hp;
114     }
115
116     if (item.captured_monster_current_hp > 0) {
117         monster.hp = item.captured_monster_current_hp;
118     }
119
120     monster.maxhp = monster.max_maxhp;
121     restore_monster_nickname(monster, item);
122     item.pval = 0;
123     item.captured_monster_speed = 0;
124     item.captured_monster_current_hp = 0;
125     item.captured_monster_max_hp = 0;
126     return true;
127 }
128
129 bool exe_monster_capture(PlayerType *player_ptr, ItemEntity &item)
130 {
131     if (item.bi_key.tval() != ItemKindType::CAPTURE) {
132         return false;
133     }
134
135     if (item.pval == 0) {
136         if (!capture_monster(player_ptr, item)) {
137             return true;
138         }
139
140         calc_android_exp(player_ptr);
141         return true;
142     }
143
144     DIRECTION dir;
145     if (!get_direction(player_ptr, &dir)) {
146         return true;
147     }
148
149     if (!release_monster(player_ptr, item, dir)) {
150         msg_print(_("おっと、解放に失敗した。", "Oops.  You failed to release your pet."));
151     }
152
153     calculate_upkeep(player_ptr);
154     calc_android_exp(player_ptr);
155     return true;
156 }