OSDN Git Service

[Refactor] MULTIPLY を新定義に合わせた
[hengbandforosx/hengbandosx.git] / src / monster-race / monster-race.cpp
1 #include "monster-race/monster-race.h"
2 #include "monster-race/race-flags-resistance.h"
3 #include "monster-race/race-flags1.h"
4 #include "monster-race/race-indice-types.h"
5 #include "monster-race/race-resistance-mask.h"
6 #include "system/monster-race-info.h"
7 #include "util/probability-table.h"
8 #include "world/world.h"
9 #include <algorithm>
10 #include <vector>
11
12 /* The monster race arrays */
13 std::map<MonsterRaceId, MonsterRaceInfo> monraces_info;
14
15 MonsterRace::MonsterRace(MonsterRaceId r_idx)
16     : r_idx(r_idx)
17 {
18 }
19
20 /*!
21  * @brief どのモンスター種族でもない事を意味する MonsterRaceId を返す
22  * @details 実態は MonsterRaceId::PLAYER だが、この値は実際にプレイヤーとしての意味として使われる場合
23  * (召喚主がプレイヤーの場合やマップ上の表示属性情報等)とどのモンスターでもない意味として使われる場合があるので、
24  * 後者ではこれを使用することでコード上の意図をわかりやすくする。
25  *
26  * @return (どのモンスター種族でもないという意味での) MonsterRaceId::PLAYER を返す
27  */
28 MonsterRaceId MonsterRace::empty_id()
29 {
30     return MonsterRaceId::PLAYER;
31 }
32
33 /*!
34  * @brief (MonsterRaceId::PLAYERを除く)実在するすべてのモンスター種族IDから等確率で1つ選択する
35  *
36  * @return 選択したモンスター種族ID
37  */
38 MonsterRaceId MonsterRace::pick_one_at_random()
39 {
40     static ProbabilityTable<MonsterRaceId> table;
41
42     if (table.empty()) {
43         for (const auto &[r_idx, r_ref] : monraces_info) {
44             if (MonsterRace(r_idx).is_valid()) {
45                 table.entry_item(r_idx, 1);
46             }
47         }
48     }
49
50     return table.pick_one_at_random();
51 }
52
53 /*!
54  * @brief コンストラクタに渡された MonsterRaceId が正当なもの(実際に存在するモンスター種族IDである)かどうかを調べる
55  * @details モンスター種族IDが MonsterRaceDefinitions に実在するもの(MonsterRaceId::PLAYERは除く)であるかどうかの用途の他、
56  * m_list 上の要素などの r_idx にMonsterRaceId::PLAYER を入れることで死亡扱いとして使われるのでその判定に使用する事もある
57  * @return 正当なものであれば true、そうでなければ false
58  */
59 bool MonsterRace::is_valid() const
60 {
61     return this->r_idx != MonsterRaceId::PLAYER;
62 }
63
64 /*!
65  * @brief モンスター種族が賞金首の対象かどうかを調べる。日替わり賞金首は対象外。
66  *
67  * @param unachieved_only true の場合未達成の賞金首のみを対象とする。false の場合達成未達成に関わらずすべての賞金首を対象とする。
68  * @return モンスター種族が賞金首の対象ならば true、そうでなければ false
69  */
70 bool MonsterRace::is_bounty(bool unachieved_only) const
71 {
72     auto it = std::find_if(std::begin(w_ptr->bounties), std::end(w_ptr->bounties),
73         [r_idx = this->r_idx](const auto &b_ref) {
74             return b_ref.r_idx == r_idx;
75         });
76
77     if (it == std::end(w_ptr->bounties)) {
78         return false;
79     }
80
81     if (unachieved_only && (*it).is_achieved) {
82         return false;
83     }
84
85     return true;
86 }
87
88 /*!
89  * @brief モンスター種族の総合的な強さを計算する。
90  * @details 現在はモンスター闘技場でのモンスターの強さの総合的な評価にのみ使用されている。
91  * @return 計算した結果のモンスター種族の総合的な強さの値を返す。
92  */
93 int MonsterRace::calc_power() const
94 {
95     int ret = 0;
96     const auto *r_ptr = &monraces_info[this->r_idx];
97     auto num_resistances = EnumClassFlagGroup<MonsterResistanceType>(r_ptr->resistance_flags & RFR_EFF_IMMUNE_ELEMENT_MASK).count();
98
99     if (r_ptr->misc_flags.has(MonsterMiscType::FORCE_MAXHP)) {
100         ret = r_ptr->hdice * r_ptr->hside * 2;
101     } else {
102         ret = r_ptr->hdice * (r_ptr->hside + 1);
103     }
104     ret = ret * (100 + r_ptr->level) / 100;
105     if (r_ptr->speed > STANDARD_SPEED) {
106         ret = ret * (r_ptr->speed * 2 - 110) / 100;
107     }
108     if (r_ptr->speed < STANDARD_SPEED) {
109         ret = ret * (r_ptr->speed - 20) / 100;
110     }
111     if (num_resistances > 2) {
112         ret = ret * (num_resistances * 2 + 5) / 10;
113     } else if (r_ptr->ability_flags.has(MonsterAbilityType::INVULNER)) {
114         ret = ret * 4 / 3;
115     } else if (r_ptr->ability_flags.has(MonsterAbilityType::HEAL)) {
116         ret = ret * 4 / 3;
117     } else if (r_ptr->ability_flags.has(MonsterAbilityType::DRAIN_MANA)) {
118         ret = ret * 11 / 10;
119     }
120     if (r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_25)) {
121         ret = ret * 9 / 10;
122     }
123     if (r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_50)) {
124         ret = ret * 9 / 10;
125     }
126     if (r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
127         ret *= 100000;
128     }
129     if (r_ptr->arena_ratio) {
130         ret = ret * r_ptr->arena_ratio / 100;
131     }
132     return ret;
133 }