OSDN Git Service

[Refactor] #3286 Removed player-redraw-types.h
[hengbandforosx/hengbandosx.git] / src / spell-realm / spells-hex.cpp
index f8eb345..715eb9a 100644 (file)
@@ -1,12 +1,12 @@
 #include "spell-realm/spells-hex.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
-#include "monster-attack/monster-attack-util.h"
+#include "monster-attack/monster-attack-player.h"
 #include "monster-race/monster-race.h"
+#include "player-base/player-class.h"
+#include "player-info/spell-hex-data-type.h"
 #include "player/attack-defense-types.h"
 #include "player/player-skill.h"
 #include "realm/realm-hex-numbers.h"
 #include "spell-realm/spells-crusade.h"
 #include "spell-realm/spells-song.h"
 #include "spell/spell-info.h"
-#include "spell/spell-types.h"
 #include "spell/spells-execution.h"
 #include "spell/technic-info-table.h"
 #include "status/action-setter.h"
 #include "system/floor-type-definition.h"
-#include "system/monster-race-definition.h"
-#include "system/monster-type-definition.h"
+#include "system/monster-entity.h"
+#include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
 #include "monster/monster-description-types.h"
 #endif
 
+#include <iterator>
+
 /*!< 呪術の最大詠唱数 */
 constexpr int MAX_KEEP = 4;
 
-RealmHex::RealmHex(player_type *player_ptr)
+SpellHex::SpellHex(PlayerType *player_ptr)
     : player_ptr(player_ptr)
+    , spell_hex_data(PlayerClass(player_ptr).get_specific_data<spell_hex_data_type>())
 {
-    constexpr int max_realm_spells = 32;
-    for (auto spell = 0; spell < max_realm_spells; spell++) {
-        if (this->is_spelling_specific(spell)) {
-            this->casting_spells.push_back(spell);
-        }
+    if (!this->spell_hex_data) {
+        return;
     }
 
+    HexSpellFlagGroup::get_flags(this->spell_hex_data->casting_spells, std::back_inserter(this->casting_spells));
+
     if (this->casting_spells.size() > MAX_KEEP) {
         throw("Invalid numbers of hex magics keep!");
     }
 }
 
-RealmHex::RealmHex(player_type *player_ptr, monap_type *monap_ptr)
+SpellHex::SpellHex(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
     : player_ptr(player_ptr)
     , monap_ptr(monap_ptr)
 {
@@ -60,90 +62,119 @@ RealmHex::RealmHex(player_type *player_ptr, monap_type *monap_ptr)
 /*!
  * @brief プレイヤーが詠唱中の全呪術を停止する
  */
-bool RealmHex::stop_all_spells()
+void SpellHex::stop_all_spells()
 {
     for (auto spell : this->casting_spells) {
-        exe_spell(this->player_ptr, REALM_HEX, spell, SPELL_STOP);
+        exe_spell(this->player_ptr, REALM_HEX, spell, SpellProcessType::STOP);
     }
 
-    casting_hex_flags(this->player_ptr) = 0;
-    casting_hex_num(this->player_ptr) = 0;
+    this->spell_hex_data->casting_spells.clear();
     if (this->player_ptr->action == ACTION_SPELL) {
         set_action(this->player_ptr, ACTION_NONE);
     }
 
-    this->player_ptr->update |= PU_BONUS | PU_HP | PU_MANA | PU_SPELLS;
-    this->player_ptr->redraw |= PR_EXTRA | PR_HP | PR_MANA;
-    return true;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    const auto flags_srf = {
+        StatusRedrawingFlag::BONUS,
+        StatusRedrawingFlag::HP,
+        StatusRedrawingFlag::MP,
+        StatusRedrawingFlag::SPELLS,
+    };
+    rfu.set_flags(flags_srf);
+    const auto flags_mwrf = {
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    rfu.set_flags(flags_mwrf);
 }
 
 /*!
- * @brief プレイヤーが詠唱中の呪術から一つを選んで停止する
+ * @brief プレイヤーが詠唱中の呪術から選択式で一つまたは全てを停止する
+ * @return 停止したらtrue、停止をキャンセルしたらfalse
  */
-bool RealmHex::stop_one_spell()
+bool SpellHex::stop_spells_with_selection()
 {
-    if (!RealmHex(this->player_ptr).is_spelling_any()) {
+    if (!this->is_spelling_any()) {
         msg_print(_("呪文を詠唱していません。", "You are not casting a spell."));
         return false;
     }
 
-    if ((casting_hex_num(this->player_ptr) == 1) || (this->player_ptr->lev < 35)) {
-        return this->stop_all_spells();
+    auto casting_num = this->get_casting_num();
+    if ((casting_num == 1) || (this->player_ptr->lev < 35)) {
+        this->stop_all_spells();
+        return true;
     }
 
     char out_val[160];
     strnfmt(out_val, 78, _("どの呪文の詠唱を中断しますか?(呪文 %c-%c, 'l'全て, ESC)", "Which spell do you stop casting? (Spell %c-%c, 'l' to all, ESC)"),
-        I2A(0), I2A(casting_hex_num(this->player_ptr) - 1));
+        I2A(0), I2A(casting_num - 1));
     screen_save();
-    char choice = 0;
-    auto is_selected = select_spell_stopping(out_val, choice);
+    auto [is_all, is_selected, choice] = select_spell_stopping(out_val);
+    if (is_all) {
+        return true;
+    }
+
     screen_load();
     if (is_selected) {
         auto n = this->casting_spells[A2I(choice)];
-        exe_spell(this->player_ptr, REALM_HEX, n, SPELL_STOP);
-        casting_hex_flags(this->player_ptr) &= ~(1UL << n);
-        casting_hex_num(this->player_ptr)--;
-    }
-
-    this->player_ptr->update |= PU_BONUS | PU_HP | PU_MANA | PU_SPELLS;
-    this->player_ptr->redraw |= PR_EXTRA | PR_HP | PR_MANA;
+        exe_spell(this->player_ptr, REALM_HEX, n, SpellProcessType::STOP);
+        this->reset_casting_flag(i2enum<spell_hex_type>(n));
+    }
+
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    const auto flags_srf = {
+        StatusRedrawingFlag::BONUS,
+        StatusRedrawingFlag::HP,
+        StatusRedrawingFlag::MP,
+        StatusRedrawingFlag::SPELLS,
+    };
+    rfu.set_flags(flags_srf);
+    const auto flags_mwrf = {
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    rfu.set_flags(flags_mwrf);
     return is_selected;
 }
 
 /*!
  * @brief 中断する呪術を選択する
- * @param spells 詠唱中の呪術リスト
  * @param out_val 呪文名
- * @param choice 選択した呪文
- * @return 選択が完了したらtrue、キャンセルならばfalse
+ * @return
+ * Item1: 全ての呪文を中断するならばtrue、1つの呪文を中断するならばfalse
+ * Item2: 選択が完了したらtrue、キャンセルならばfalse
+ * Item3: 選択した呪文番号 (a~d、lの5択)
  */
-bool RealmHex::select_spell_stopping(char *out_val, char &choice)
+std::tuple<bool, bool, char> SpellHex::select_spell_stopping(char *out_val)
 {
     while (true) {
+        char choice = 0;
         this->display_casting_spells_list();
         if (!get_com(out_val, &choice, true)) {
-            return false;
+            return std::make_tuple(false, false, choice);
         }
 
         if (isupper(choice)) {
             choice = static_cast<char>(tolower(choice));
         }
 
-        /* All */
         if (choice == 'l') {
             screen_load();
-            return this->stop_all_spells();
+            this->stop_all_spells();
+            return std::make_tuple(true, true, choice);
         }
 
-        if ((choice < I2A(0)) || (choice > I2A(casting_hex_num(this->player_ptr) - 1))) {
+        if ((choice < I2A(0)) || (choice > I2A(this->get_casting_num() - 1))) {
             continue;
         }
 
-        return true;
+        return std::make_tuple(false, true, choice);
     }
 }
 
-void RealmHex::display_casting_spells_list()
+void SpellHex::display_casting_spells_list()
 {
     constexpr auto y = 1;
     constexpr auto x = 20;
@@ -152,8 +183,8 @@ void RealmHex::display_casting_spells_list()
     prt(_("     名前", "     Name"), y, x + 5);
     for (auto spell : this->casting_spells) {
         term_erase(x, y + n + 1, 255);
-        auto spell_result = exe_spell(this->player_ptr, REALM_HEX, spell, SPELL_NAME);
-        put_str(format("%c)  %s", I2A(n), spell_result), y + n + 1, x + 2);
+        const auto spell_name = exe_spell(this->player_ptr, REALM_HEX, spell, SpellProcessType::NAME);
+        put_str(format("%c)  %s", I2A(n), spell_name->data()), y + n + 1, x + 2);
         n++;
     }
 }
@@ -161,14 +192,13 @@ void RealmHex::display_casting_spells_list()
 /*!
  * @brief 一定時間毎に呪術で消費するMPを処理する
  */
-void RealmHex::decrease_mana()
+void SpellHex::decrease_mana()
 {
-    /* Spells spelled by player */
-    if (this->player_ptr->realm1 != REALM_HEX) {
+    if (!this->spell_hex_data) {
         return;
     }
 
-    if (!casting_hex_flags(this->player_ptr) && !this->player_ptr->magic_num1[1]) {
+    if (this->spell_hex_data->casting_spells.none() && this->spell_hex_data->interrupting_spells.none()) {
         return;
     }
 
@@ -182,9 +212,9 @@ void RealmHex::decrease_mana()
         return;
     }
 
-    this->gain_exp_from_hex();
+    this->gain_exp();
     for (auto spell : this->casting_spells) {
-        exe_spell(this->player_ptr, REALM_HEX, spell, SPELL_CONT);
+        exe_spell(this->player_ptr, REALM_HEX, spell, SpellProcessType::CONTNUATION);
     }
 }
 
@@ -192,13 +222,14 @@ void RealmHex::decrease_mana()
  * @brief 継続的な呪文の詠唱が可能な程度にMPが残っているか確認し、残量に応じて継続・中断を行う
  * @param need_restart 詠唱を再開するか否か
  * @return MPが足りているか否か
+ * @todo 64ビットの割り算をしなければいけない箇所には見えない. 調査の後不要ならば消すこと.
  */
-bool RealmHex::process_mana_cost(const bool need_restart)
+bool SpellHex::process_mana_cost(const bool need_restart)
 {
     auto need_mana = this->calc_need_mana();
     uint need_mana_frac = 0;
     s64b_div(&need_mana, &need_mana_frac, 0, 3); /* Divide by 3 */
-    need_mana += (casting_hex_num(this->player_ptr) - 1);
+    need_mana += this->get_casting_num() - 1;
 
     auto enough_mana = s64b_cmp(this->player_ptr->csp, this->player_ptr->csp_frac, need_mana, need_mana_frac) >= 0;
     if (!enough_mana) {
@@ -207,32 +238,42 @@ bool RealmHex::process_mana_cost(const bool need_restart)
     }
 
     s64b_sub(&(this->player_ptr->csp), &(this->player_ptr->csp_frac), need_mana, need_mana_frac);
-    this->player_ptr->redraw |= PR_MANA;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
     if (!need_restart) {
         return true;
     }
 
     msg_print(_("詠唱を再開した。", "You restart casting."));
     this->player_ptr->action = ACTION_SPELL;
-    this->player_ptr->update |= PU_BONUS | PU_HP;
-    this->player_ptr->redraw |= PR_MAP | PR_STATUS | PR_STATE;
-    this->player_ptr->update |= PU_MONSTERS;
+    const auto flags_srf = {
+        StatusRedrawingFlag::BONUS,
+        StatusRedrawingFlag::HP,
+        StatusRedrawingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    const auto flags_mwrf = {
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::TIMED_EFFECT,
+        MainWindowRedrawingFlag::ACTION,
+    };
+    rfu.set_flags(flags_mwrf);
     this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
     return true;
 }
 
-bool RealmHex::check_restart()
+bool SpellHex::check_restart()
 {
-    if (this->player_ptr->magic_num1[1] == 0) {
+    if (this->spell_hex_data->interrupting_spells.none()) {
         return false;
     }
 
-    this->player_ptr->magic_num1[0] = this->player_ptr->magic_num1[1];
-    this->player_ptr->magic_num1[1] = 0;
+    this->spell_hex_data->casting_spells = this->spell_hex_data->interrupting_spells;
+    this->spell_hex_data->interrupting_spells.clear();
     return true;
 }
 
-int RealmHex::calc_need_mana()
+int SpellHex::calc_need_mana()
 {
     auto need_mana = 0;
     for (auto spell : this->casting_spells) {
@@ -243,78 +284,15 @@ int RealmHex::calc_need_mana()
     return need_mana;
 }
 
-void RealmHex::gain_exp_from_hex()
+void SpellHex::gain_exp()
 {
+    PlayerSkill ps(player_ptr);
     for (auto spell : this->casting_spells) {
         if (!this->is_spelling_specific(spell)) {
             continue;
         }
 
-        if (this->player_ptr->spell_exp[spell] < SPELL_EXP_BEGINNER) {
-            this->player_ptr->spell_exp[spell] += 5;
-            continue;
-        }
-
-        if (this->gain_exp_skilled(spell)) {
-            continue;
-        }
-
-        if (this->gain_exp_expert(spell)) {
-            continue;
-        }
-
-        this->gain_exp_master(spell);
-    }
-}
-
-bool RealmHex::gain_exp_skilled(const int spell)
-{
-    if (this->player_ptr->spell_exp[spell] >= SPELL_EXP_SKILLED) {
-        return false;
-    }
-
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto gain_condition = one_in_(2);
-    gain_condition &= floor_ptr->dun_level > 4;
-    gain_condition &= (floor_ptr->dun_level + 10) > this->player_ptr->lev;
-    if (gain_condition) {
-        this->player_ptr->spell_exp[spell]++;
-    }
-
-    return true;
-}
-
-bool RealmHex::gain_exp_expert(const int spell)
-{
-    if (this->player_ptr->spell_exp[spell] >= SPELL_EXP_EXPERT) {
-        return false;
-    }
-
-    const auto *s_ptr = &technic_info[REALM_HEX - MIN_TECHNIC][spell];
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto gain_condition = one_in_(5);
-    gain_condition &= (floor_ptr->dun_level + 5) > this->player_ptr->lev;
-    gain_condition &= (floor_ptr->dun_level + 5) > s_ptr->slevel;
-    if (gain_condition) {
-        this->player_ptr->spell_exp[spell]++;
-    }
-
-    return true;
-}
-
-void RealmHex::gain_exp_master(const int spell)
-{
-    if (this->player_ptr->spell_exp[spell] >= SPELL_EXP_MASTER) {
-        return;
-    }
-
-    const auto *s_ptr = &technic_info[REALM_HEX - MIN_TECHNIC][spell];
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto gain_condition = one_in_(5);
-    gain_condition &= (floor_ptr->dun_level + 5) > this->player_ptr->lev;
-    gain_condition &= floor_ptr->dun_level > s_ptr->slevel;
-    if (gain_condition) {
-        this->player_ptr->spell_exp[spell]++;
+        ps.gain_continuous_spell_skill_exp(REALM_HEX, spell);
     }
 }
 
@@ -322,28 +300,28 @@ void RealmHex::gain_exp_master(const int spell)
  * @brief プレイヤーの呪術詠唱枠がすでに最大かどうかを返す
  * @return すでに全枠を利用しているならTRUEを返す
  */
-bool RealmHex::is_casting_full_capacity() const
+bool SpellHex::is_casting_full_capacity() const
 {
     auto k_max = (this->player_ptr->lev / 15) + 1;
-    k_max = MIN(k_max, MAX_KEEP);
-    return casting_hex_num(this->player_ptr) >= k_max;
+    k_max = std::min(k_max, MAX_KEEP);
+    return this->get_casting_num() >= k_max;
 }
 
 /*!
  * @brief 一定ゲームターン毎に復讐処理の残り期間の判定を行う
  */
-void RealmHex::continue_revenge()
+void SpellHex::continue_revenge()
 {
-    if ((this->player_ptr->realm1 != REALM_HEX) || (hex_revenge_turn(this->player_ptr) <= 0)) {
+    if (!this->spell_hex_data || (this->get_revenge_turn() == 0)) {
         return;
     }
 
-    switch (hex_revenge_type(this->player_ptr)) {
-    case 1:
-        exe_spell(this->player_ptr, REALM_HEX, HEX_PATIENCE, SPELL_CONT);
+    switch (this->get_revenge_type()) {
+    case SpellHexRevengeType::PATIENCE:
+        exe_spell(this->player_ptr, REALM_HEX, HEX_PATIENCE, SpellProcessType::CONTNUATION);
         return;
-    case 2:
-        exe_spell(this->player_ptr, REALM_HEX, HEX_REVENGE, SPELL_CONT);
+    case SpellHexRevengeType::REVENGE:
+        exe_spell(this->player_ptr, REALM_HEX, HEX_REVENGE, SpellProcessType::CONTNUATION);
         return;
     default:
         return;
@@ -354,13 +332,13 @@ void RealmHex::continue_revenge()
  * @brief 復讐ダメージの追加を行う
  * @param dam 蓄積されるダメージ量
  */
-void RealmHex::store_vengeful_damage(HIT_POINT dam)
+void SpellHex::store_vengeful_damage(int dam)
 {
-    if ((this->player_ptr->realm1 != REALM_HEX) || (hex_revenge_turn(this->player_ptr) <= 0)) {
+    if (!this->spell_hex_data || (this->get_revenge_turn() == 0)) {
         return;
     }
 
-    hex_revenge_power(this->player_ptr) += dam;
+    this->set_revenge_power(dam, false);
 }
 
 /*!
@@ -369,30 +347,35 @@ void RealmHex::store_vengeful_damage(HIT_POINT dam)
  * @return 呪術の効果が適用されるならTRUEを返す
  * @details v3.0.0現在は反テレポート・反魔法・反増殖の3種類
  */
-bool RealmHex::check_hex_barrier(MONSTER_IDX m_idx, realm_hex_type type) const
+bool SpellHex::check_hex_barrier(MONSTER_IDX m_idx, spell_hex_type type) const
 {
     const auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[m_idx];
-    const auto *r_ptr = &r_info[m_ptr->r_idx];
+    const auto *r_ptr = &monraces_info[m_ptr->r_idx];
     return this->is_spelling_specific(type) && ((this->player_ptr->lev * 3 / 2) >= randint1(r_ptr->level));
 }
 
-bool RealmHex::is_spelling_specific(int hex) const
+bool SpellHex::is_spelling_specific(int hex) const
 {
-    auto check = static_cast<uint32_t>(this->player_ptr->magic_num1[0]);
-    return (this->player_ptr->realm1 == REALM_HEX) && any_bits(check, 1U << hex);
+    return this->spell_hex_data && this->spell_hex_data->casting_spells.has(i2enum<spell_hex_type>(hex));
 }
 
-bool RealmHex::is_spelling_any() const
+bool SpellHex::is_spelling_any() const
 {
-    return (player_ptr->realm1 == REALM_HEX) && (player_ptr->magic_num1[0] != 0);
+    return this->spell_hex_data && (this->get_casting_num() > 0);
+}
+
+void SpellHex::interrupt_spelling()
+{
+    this->spell_hex_data->interrupting_spells = this->spell_hex_data->casting_spells;
+    this->spell_hex_data->casting_spells.clear();
 }
 
 /*!
  * @brief 呪術「目には目を」の効果処理
- * @param this->player_ptr ã\83\97ã\83¬ã\83¼ヤーへの参照ポインタ
- * @param monap_ptr ã\83¢ã\83³ã\82¹ã\82¿ã\83¼ã\81\8bã\82\89ã\83\97ã\83¬ã\83¼ヤーへの直接攻撃構造体への参照ポインタ
+ * @param this->player_ptr ã\83\97ã\83¬ã\82¤ヤーへの参照ポインタ
+ * @param monap_ptr ã\83¢ã\83³ã\82¹ã\82¿ã\83¼ã\81\8bã\82\89ã\83\97ã\83¬ã\82¤ヤーへの直接攻撃構造体への参照ポインタ
  */
-void RealmHex::eyes_on_eyes()
+void SpellHex::eyes_on_eyes()
 {
     if (this->monap_ptr == nullptr) {
         throw("Invalid constructor was used!");
@@ -406,19 +389,18 @@ void RealmHex::eyes_on_eyes()
 #ifdef JP
     msg_format("攻撃が%s自身を傷つけた!", this->monap_ptr->m_name);
 #else
-    GAME_TEXT m_name_self[MAX_MONSTER_NAME];
-    monster_desc(this->player_ptr, m_name_self, this->monap_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE | MD_OBJECTIVE);
-    msg_format("The attack of %s has wounded %s!", this->monap_ptr->m_name, m_name_self);
+    const auto m_name_self = monster_desc(this->player_ptr, this->monap_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE | MD_OBJECTIVE);
+    msg_format("The attack of %s has wounded %s!", this->monap_ptr->m_name, m_name_self.data());
 #endif
     const auto y = this->monap_ptr->m_ptr->fy;
     const auto x = this->monap_ptr->m_ptr->fx;
-    project(this->player_ptr, 0, 0, y, x, this->monap_ptr->get_damage, GF_MISSILE, PROJECT_KILL);
+    project(this->player_ptr, 0, 0, y, x, this->monap_ptr->get_damage, AttributeType::MISSILE, PROJECT_KILL);
     if (this->player_ptr->tim_eyeeye) {
         set_tim_eyeeye(this->player_ptr, this->player_ptr->tim_eyeeye - 5, true);
     }
 }
 
-void RealmHex::thief_teleport()
+void SpellHex::thief_teleport()
 {
     if (this->monap_ptr == nullptr) {
         throw("Invalid constructor was used!");
@@ -432,6 +414,64 @@ void RealmHex::thief_teleport()
         msg_print(_("泥棒は笑って逃げ...ようとしたがバリアに防がれた。", "The thief flees laughing...? But a magic barrier obstructs it."));
     } else {
         msg_print(_("泥棒は笑って逃げた!", "The thief flees laughing!"));
-        teleport_away(this->player_ptr, this->monap_ptr->m_idx, MAX_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
+        teleport_away(this->player_ptr, this->monap_ptr->m_idx, MAX_PLAYER_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
     }
 }
+
+void SpellHex::set_casting_flag(spell_hex_type type)
+{
+    this->spell_hex_data->casting_spells.set(type);
+}
+
+void SpellHex::reset_casting_flag(spell_hex_type type)
+{
+    this->spell_hex_data->casting_spells.reset(type);
+}
+
+int32_t SpellHex::get_casting_num() const
+{
+    return this->spell_hex_data->casting_spells.count();
+}
+
+int32_t SpellHex::get_revenge_power() const
+{
+    return this->spell_hex_data->revenge_power;
+}
+
+void SpellHex::set_revenge_power(int32_t power, bool substitution)
+{
+    if (substitution) {
+        this->spell_hex_data->revenge_power = power;
+    } else {
+        this->spell_hex_data->revenge_power += power;
+    }
+}
+
+byte SpellHex::get_revenge_turn() const
+{
+    return this->spell_hex_data->revenge_turn;
+}
+
+/*!
+ * @brief 復讐の残りターンをセットするか、残りターン数を減らす
+ * @param turn 残りターン (非負整数であること)
+ * @param substitution セットならtrue、ターン減少ならfalse
+ */
+void SpellHex::set_revenge_turn(byte turn, bool substitution)
+{
+    if (substitution) {
+        this->spell_hex_data->revenge_turn = turn;
+    } else {
+        this->spell_hex_data->revenge_turn -= turn;
+    }
+}
+
+SpellHexRevengeType SpellHex::get_revenge_type() const
+{
+    return this->spell_hex_data->revenge_type;
+}
+
+void SpellHex::set_revenge_type(SpellHexRevengeType type)
+{
+    this->spell_hex_data->revenge_type = type;
+}