diff --git a/VisualStudio/Hengband/Hengband.vcxproj b/VisualStudio/Hengband/Hengband.vcxproj index c6269d9afc..1c1a8b16b0 100644 --- a/VisualStudio/Hengband/Hengband.vcxproj +++ b/VisualStudio/Hengband/Hengband.vcxproj @@ -433,7 +433,6 @@ - @@ -518,6 +517,7 @@ + @@ -1228,7 +1228,6 @@ - @@ -1320,6 +1319,7 @@ + diff --git a/VisualStudio/Hengband/Hengband.vcxproj.filters b/VisualStudio/Hengband/Hengband.vcxproj.filters index e81e86fa9f..7155b7668a 100644 --- a/VisualStudio/Hengband/Hengband.vcxproj.filters +++ b/VisualStudio/Hengband/Hengband.vcxproj.filters @@ -1850,6 +1850,9 @@ player + + player + monster-floor @@ -2111,9 +2114,6 @@ main-win - - main-win - main @@ -4640,6 +4640,9 @@ player + + player + monster-floor @@ -4913,9 +4916,6 @@ main-win - - main-win - main diff --git a/src/Makefile.am b/src/Makefile.am index f89a5dacff..0fbf17b6e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -689,6 +689,7 @@ hengband_SOURCES = \ player/player-personality.cpp player/player-personality.h \ player/player-realm.cpp player/player-realm.h \ player/player-skill.cpp player/player-skill.h \ + player/player-spell-status.cpp player/player-spell-status.h \ player/player-status.cpp player/player-status.h \ player/player-status-flags.cpp player/player-status-flags.h \ player/player-status-table.cpp player/player-status-table.h \ @@ -1052,7 +1053,6 @@ EXTRA_hengband_SOURCES = \ main-win/main-win-cfg-reader.cpp main-win/main-win-cfg-reader.h \ main-win/main-win-define.h \ main-win/main-win-exception.cpp main-win/main-win-exception.h \ - main-win/main-win-file-utils.cpp main-win/main-win-file-utils.h \ main-win/main-win-mci.cpp main-win/main-win-mci.h \ main-win/main-win-menuitem.h \ main-win/main-win-mmsystem.h \ diff --git a/src/birth/game-play-initializer.cpp b/src/birth/game-play-initializer.cpp index 10bece68cf..c7427efd68 100644 --- a/src/birth/game-play-initializer.cpp +++ b/src/birth/game-play-initializer.cpp @@ -13,6 +13,7 @@ #include "player-info/race-info.h" #include "player-info/race-types.h" #include "player/digestion-processor.h" +#include "player/player-spell-status.h" #include "system/artifact-type-definition.h" #include "system/baseitem-info.h" #include "system/dungeon-info.h" @@ -82,18 +83,10 @@ void player_wipe_without_name(PlayerType *player_ptr) } player_ptr->food = PY_FOOD_FULL - 1; - if (PlayerClass(player_ptr).equals(PlayerClassType::SORCERER)) { - player_ptr->spell_learned1 = player_ptr->spell_learned2 = 0xffffffffL; - player_ptr->spell_worked1 = player_ptr->spell_worked2 = 0xffffffffL; - } else { - player_ptr->spell_learned1 = player_ptr->spell_learned2 = 0L; - player_ptr->spell_worked1 = player_ptr->spell_worked2 = 0L; - } - player_ptr->spell_forgotten1 = player_ptr->spell_forgotten2 = 0L; - for (int i = 0; i < 64; i++) { - player_ptr->spell_order[i] = 99; - } + PlayerSpellStatus pss(player_ptr); + pss.realm1().initialize(); + pss.realm2().initialize(); player_ptr->learned_spells = 0; player_ptr->add_spells = 0; diff --git a/src/cmd-action/cmd-hissatsu.cpp b/src/cmd-action/cmd-hissatsu.cpp index 3cbce4258f..a056ffb18f 100644 --- a/src/cmd-action/cmd-hissatsu.cpp +++ b/src/cmd-action/cmd-hissatsu.cpp @@ -31,6 +31,7 @@ #include "player-status/player-energy.h" #include "player/attack-defense-types.h" #include "player/player-realm.h" +#include "player/player-spell-status.h" #include "player/special-defense-types.h" #include "spell/spells-execution.h" #include "spell/technic-info-table.h" @@ -105,6 +106,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn) } choice = always_show_list ? ESCAPE : 1; + const auto realm_status = PlayerSpellStatus(player_ptr).realm1(); while (!flag) { if (choice == ESCAPE) { choice = ' '; @@ -133,7 +135,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn) if (menu_line > 32) { menu_line -= 32; } - } while (!(player_ptr->spell_learned1 & (1UL << (menu_line - 1)))); + } while (!realm_status.is_learned(menu_line - 1)); break; } @@ -145,7 +147,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn) if (menu_line > 32) { menu_line -= 32; } - } while (!(player_ptr->spell_learned1 & (1UL << (menu_line - 1)))); + } while (!realm_status.is_learned(menu_line - 1)); break; } @@ -165,7 +167,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn) } else { menu_line += 16; } - while (!(player_ptr->spell_learned1 & (1UL << (menu_line - 1)))) { + while (!realm_status.is_learned(menu_line - 1)) { if (reverse) { menu_line--; if (menu_line < 2) { @@ -213,15 +215,12 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn) continue; } line++; - if (!(player_ptr->spell_learned1 >> i)) { - break; - } /* Access the spell */ if (spell.slevel > plev) { continue; } - if (!(player_ptr->spell_learned1 & (1UL << i))) { + if (!realm_status.is_learned(i)) { continue; } std::string psi_desc; @@ -270,7 +269,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn) } /* Totally Illegal */ - if ((i < 0) || (i >= 32) || !(player_ptr->spell_learned1 & (1U << selections[i]))) { + if ((i < 0) || (i >= 32) || !realm_status.is_learned(selections[i])) { bell(); continue; } @@ -318,7 +317,7 @@ void do_cmd_hissatsu(PlayerType *player_ptr) msg_print(_("武器を持たないと必殺技は使えない!", "You need to wield a weapon!")); return; } - if (!player_ptr->spell_learned1) { + if (PlayerSpellStatus(player_ptr).realm1().is_nothing_learned()) { msg_print(_("何も技を知らない。", "You don't know any special attacks.")); return; } @@ -395,8 +394,9 @@ void do_cmd_gain_hissatsu(PlayerType *player_ptr) const auto sval = *o_ptr->bi_key.sval(); auto gain = false; + auto realm_status = PlayerSpellStatus(player_ptr).realm1(); for (auto i = sval * 8; i < sval * 8 + 8; i++) { - if (player_ptr->spell_learned1 & (1UL << i)) { + if (realm_status.is_learned(i)) { continue; } @@ -404,19 +404,11 @@ void do_cmd_gain_hissatsu(PlayerType *player_ptr) continue; } - player_ptr->spell_learned1 |= (1UL << i); - player_ptr->spell_worked1 |= (1UL << i); + realm_status.set_learned(i); + realm_status.set_worked(i); const auto &spell_name = PlayerRealm::get_spell_name(RealmType::HISSATSU, i); msg_format(_("%sの技を覚えた。", "You have learned the special attack of %s."), spell_name.data()); - int j; - for (j = 0; j < 64; j++) { - /* Stop at the first empty space */ - if (player_ptr->spell_order[j] == 99) { - break; - } - } - - player_ptr->spell_order[j] = i; + player_ptr->spell_order_learned.push_back(i); gain = true; } diff --git a/src/cmd-action/cmd-spell.cpp b/src/cmd-action/cmd-spell.cpp index d74f6404b0..48a8e4536c 100644 --- a/src/cmd-action/cmd-spell.cpp +++ b/src/cmd-action/cmd-spell.cpp @@ -41,6 +41,7 @@ #include "player/player-damage.h" #include "player/player-realm.h" #include "player/player-skill.h" +#include "player/player-spell-status.h" #include "player/player-status.h" #include "player/special-defense-types.h" #include "spell-kind/spells-random.h" @@ -69,6 +70,7 @@ #include "view/display-messages.h" #include "view/display-util.h" #include +#include concptr KWD_DAM = _("損傷:", "dam "); concptr KWD_RANGE = _("射程:", "rng "); @@ -273,7 +275,9 @@ static bool spell_okay(PlayerType *player_ptr, int spell_id, bool learned, bool /* Spell is forgotten */ PlayerRealm pr(player_ptr); - if (pr.realm2().equals(use_realm) ? (player_ptr->spell_forgotten2 & (1UL << spell_id)) : (player_ptr->spell_forgotten1 & (1UL << spell_id))) { + PlayerSpellStatus pss(player_ptr); + const auto realm_status = pr.realm2().equals(use_realm) ? pss.realm2() : pss.realm1(); + if (realm_status.is_forgotten(spell_id)) { /* Never okay */ return false; } @@ -283,7 +287,7 @@ static bool spell_okay(PlayerType *player_ptr, int spell_id, bool learned, bool } /* Spell is learned */ - if (pr.realm2().equals(use_realm) ? (player_ptr->spell_learned2 & (1UL << spell_id)) : (player_ptr->spell_learned1 & (1UL << spell_id))) { + if (realm_status.is_learned(spell_id)) { /* Always true */ return !study_pray; } @@ -682,23 +686,11 @@ void do_cmd_browse(PlayerType *player_ptr) */ static void change_realm2(PlayerType *player_ptr, PlayerRealm &pr, RealmType next_realm) { - int i, j = 0; - for (i = 0; i < 64; i++) { - player_ptr->spell_order[j] = player_ptr->spell_order[i]; - if (player_ptr->spell_order[i] < 32) { - j++; - } - } - for (; j < 64; j++) { - player_ptr->spell_order[j] = 99; - } + PlayerSpellStatus(player_ptr).realm2().initialize(); - for (i = 32; i < 64; i++) { + for (auto i = 32; i < 64; i++) { player_ptr->spell_exp[i] = PlayerSkill::spell_exp_at(PlayerSkillRank::UNSKILLED); } - player_ptr->spell_learned2 = 0L; - player_ptr->spell_worked2 = 0L; - player_ptr->spell_forgotten2 = 0L; constexpr auto fmt_realm = _("魔法の領域を%sから%sに変更した。", "changed magic realm from %s to %s."); const auto mes = format(fmt_realm, pr.realm2().get_name().data(), PlayerRealm::get_name(next_realm).data()); @@ -724,7 +716,6 @@ static void change_realm2(PlayerType *player_ptr, PlayerRealm &pr, RealmType nex void do_cmd_study(PlayerType *player_ptr) { auto increment = 0; - auto learned = false; /* Spells of realm2 will have an increment of +32 */ SPELL_IDX spell = -1; @@ -837,21 +828,10 @@ void do_cmd_study(PlayerType *player_ptr) } /* Learn the spell */ - if (spell < 32) { - if (player_ptr->spell_learned1 & (1UL << spell)) { - learned = true; - } else { - player_ptr->spell_learned1 |= (1UL << spell); - } - } else { - if (player_ptr->spell_learned2 & (1UL << (spell - 32))) { - learned = true; - } else { - player_ptr->spell_learned2 |= (1UL << (spell - 32)); - } - } + PlayerSpellStatus pss(player_ptr); + auto realm_status = increment ? pss.realm2() : pss.realm1(); - if (learned) { + if (realm_status.is_learned(spell % 32)) { auto max_exp = PlayerSkill::spell_exp_at((spell < 32) ? PlayerSkillRank::MASTER : PlayerSkillRank::EXPERT); const auto old_exp = player_ptr->spell_exp[spell]; const auto &realm = increment ? pr.realm2() : pr.realm1(); @@ -874,17 +854,10 @@ void do_cmd_study(PlayerType *player_ptr) auto new_rank_str = PlayerSkill::skill_rank_str(new_rank); msg_format(_("%sの熟練度が%sに上がった。", "Your proficiency of %s is now %s rank."), spell_name.data(), new_rank_str); } else { - /* Find the next open entry in "player_ptr->spell_order[]" */ - int i; - for (i = 0; i < 64; i++) { - /* Stop at the first empty space */ - if (player_ptr->spell_order[i] == 99) { - break; - } - } + realm_status.set_learned(spell % 32); /* Add the spell to the known list */ - player_ptr->spell_order[i++] = spell; + player_ptr->spell_order_learned.push_back(spell); /* Mention the result */ const auto &realm = increment ? pr.realm2() : pr.realm1(); @@ -1162,15 +1135,13 @@ bool do_cmd_cast(PlayerType *player_ptr) } /* A spell was cast */ - if (!(increment ? (player_ptr->spell_worked2 & (1UL << spell_id)) : (player_ptr->spell_worked1 & (1UL << spell_id))) && !is_every_magic) { + PlayerSpellStatus pss(player_ptr); + auto realm_status = increment ? pss.realm2() : pss.realm1(); + if (!realm_status.is_worked(spell_id) && !is_every_magic) { int e = spell.sexp; /* The spell worked */ - if (pr.realm1().equals(use_realm)) { - player_ptr->spell_worked1 |= (1UL << spell_id); - } else { - player_ptr->spell_worked2 |= (1UL << spell_id); - } + realm_status.set_worked(spell_id); gain_exp(player_ptr, e * spell.slevel); RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE); diff --git a/src/load/inventory-loader.cpp b/src/load/inventory-loader.cpp index e15b455eae..61d959300a 100644 --- a/src/load/inventory-loader.cpp +++ b/src/load/inventory-loader.cpp @@ -65,8 +65,10 @@ static errr rd_inventory(PlayerType *player_ptr) errr load_inventory(PlayerType *player_ptr) { - for (int i = 0; i < 64; i++) { - player_ptr->spell_order[i] = rd_byte(); + for (auto i = 0; i < 64; i++) { + if (const auto spell_id = rd_byte(); spell_id < 64) { + player_ptr->spell_order_learned.push_back(spell_id); + } } if (!rd_inventory(player_ptr)) { diff --git a/src/load/load-zangband.cpp b/src/load/load-zangband.cpp index 39211e4e9c..e19bf901dc 100644 --- a/src/load/load-zangband.cpp +++ b/src/load/load-zangband.cpp @@ -15,6 +15,7 @@ #include "player/player-personality.h" #include "player/player-realm.h" #include "player/player-skill.h" +#include "player/player-spell-status.h" #include "realm/realm-types.h" #include "spell/spells-status.h" #include "system/building-type-definition.h" @@ -233,9 +234,12 @@ void set_zangband_class(PlayerType *player_ptr) void set_zangband_learnt_spells(PlayerType *player_ptr) { player_ptr->learned_spells = 0; - for (int i = 0; i < 64; i++) { - if ((i < 32) ? (player_ptr->spell_learned1 & (1UL << i)) : (player_ptr->spell_learned2 & (1UL << (i - 32)))) { - player_ptr->learned_spells++; + PlayerSpellStatus pss(player_ptr); + for (const auto &realm_status : { pss.realm1(), pss.realm2() }) { + for (auto i = 0; i < 32; i++) { + if (realm_status.is_learned(i)) { + player_ptr->learned_spells++; + } } } } diff --git a/src/main-win.cpp b/src/main-win.cpp index 5f152075ed..9e5460d6f5 100644 --- a/src/main-win.cpp +++ b/src/main-win.cpp @@ -103,7 +103,6 @@ #include "main-win/graphics-win.h" #include "main-win/main-win-bg.h" #include "main-win/main-win-exception.h" -#include "main-win/main-win-file-utils.h" #include "main-win/main-win-mci.h" #include "main-win/main-win-menuitem.h" #include "main-win/main-win-music.h" @@ -1913,7 +1912,7 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd) } case IDM_OPTIONS_OPEN_MUSIC_DIR: { const auto path = path_build(ANGBAND_DIR_XTRA_MUSIC, "music.cfg"); - open_dir_in_explorer(path.string()); + open_dir_in_explorer(path); break; } case IDM_OPTIONS_SOUND: { @@ -1936,7 +1935,7 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd) } case IDM_OPTIONS_OPEN_SOUND_DIR: { const auto path = path_build(ANGBAND_DIR_XTRA_SOUND, "sound.cfg"); - open_dir_in_explorer(path.string()); + open_dir_in_explorer(path); break; } case IDM_OPTIONS_NO_BG: { @@ -2645,7 +2644,7 @@ static void init_stuff() init_file_paths(path); validate_dir(ANGBAND_DIR_APEX, false); validate_dir(ANGBAND_DIR_BONE, false); - if (!check_dir(ANGBAND_DIR_EDIT)) { + if (!is_directory(ANGBAND_DIR_EDIT)) { validate_dir(ANGBAND_DIR_DATA, true); } else { validate_dir(ANGBAND_DIR_DATA, false); diff --git a/src/main-win/main-win-cfg-reader.cpp b/src/main-win/main-win-cfg-reader.cpp index f42162669e..7b562ced67 100644 --- a/src/main-win/main-win-cfg-reader.cpp +++ b/src/main-win/main-win-cfg-reader.cpp @@ -6,11 +6,11 @@ #include "main-win/main-win-cfg-reader.h" #include "locale/japanese.h" #include "main-win/main-win-define.h" -#include "main-win/main-win-file-utils.h" #include "main-win/main-win-tokenizer.h" #include "main/sound-definitions-table.h" #include "term/z-term.h" #include "util/angband-files.h" +#include #include // 1つの項目に設定可能な最大ファイル数 @@ -29,57 +29,44 @@ static cfg_key make_cfg_key(int type, int val) return (type << 16) | (val & 0xffff); } -/*! - * @brief マップのキーに対応する値を取得する - * @param key1_type the "actions" value of "term_xtra()". see:z-term.h TERM_XTRA_xxxxx - * @param key2_val the 2nd parameter of "term_xtra()" - * @return キーに対応する値を返す。登録されていない場合はnullptrを返す。 - */ -static cfg_values *get_map_value(cfg_map *map, int key1_type, int key2_val) -{ - cfg_values *value = nullptr; - auto ite = map->find(make_cfg_key(key1_type, key2_val)); - if (ite != map->end()) { - value = ite->second; - } - return value; -} - /*! * @brief 登録されている中からランダムに選択する * @param type the "actions" value of "term_xtra()". see:z-term.h TERM_XTRA_xxxxx * @param val the 2nd parameter of "term_xtra()" - * @return キーに対応する値、複数のファイル名の中からからランダムに返す。登録されていない場合はnullptrを返す。 + * @return キーに対応する値、複数のファイル名の中からからランダムに返す。登録されていない場合はstd::nulloptを返す。 */ -concptr CfgData::get_rand(int key1_type, int key2_val) +std::optional CfgData::get_rand(int key1_type, int key2_val) const { - cfg_values *filenames = get_map_value(this->map, key1_type, key2_val); - if (!filenames) { - return nullptr; + const auto it = this->map.find(make_cfg_key(key1_type, key2_val)); + if (it == this->map.end()) { + return std::nullopt; } - return filenames->at(Rand_external(filenames->size())); + const auto &filenames = it->second; + return filenames.at(Rand_external(filenames.size())); } -bool CfgData::has_key(int key1_type, int key2_val) +bool CfgData::has_key(int key1_type, int key2_val) const { - auto ite = map->find(make_cfg_key(key1_type, key2_val)); - return ite != map->end(); + return this->map.contains(make_cfg_key(key1_type, key2_val)); } -void CfgData::insert(int key1_type, int key2_val, cfg_values *value) +void CfgData::insert(int key1_type, int key2_val, cfg_values &&value) { - this->map->insert(std::make_pair(make_cfg_key(key1_type, key2_val), value)); + this->map.emplace(make_cfg_key(key1_type, key2_val), std::move(value)); } /*! * @param dir .cfgファイルのディレクトリ * @param files .cfgファイル名。複数指定可能で、最初に見つかったファイルから読み取る。 */ -CfgReader::CfgReader(std::filesystem::path dir, std::initializer_list files) +CfgReader::CfgReader(const std::filesystem::path &dir, std::initializer_list files) { this->dir = dir; - this->cfg_path = find_any_file(dir, files); + auto exists_in_dir = [dir](const char *filename) { return is_regular_file(path_build(dir, filename)); }; + if (auto it = std::find_if(files.begin(), files.end(), exists_in_dir); it != files.end()) { + this->cfg_path = path_build(dir, *it); + } } /*! @@ -87,51 +74,46 @@ CfgReader::CfgReader(std::filesystem::path dir, std::initializer_list f * @param sections 読み取るデータの指定 * @return 読み込んだデータを登録したCfgDataを返す。 */ -CfgData *CfgReader::read_sections(std::initializer_list sections) +CfgData CfgReader::read_sections(std::initializer_list sections) const { - CfgData *result = new CfgData(); + CfgData result; - if (!check_file(this->cfg_path.data())) { + if (!is_regular_file(this->cfg_path)) { return result; } - char key_buf[80]; - char buf[MAIN_WIN_MAX_PATH]; - char *tokens[SAMPLE_MAX]; + const auto cfg_path_str = this->cfg_path.string(); for (auto §ion : sections) { - - bool has_data = false; - int index = 0; concptr read_key; - while ((read_key = section.key_at(index, key_buf)) != nullptr) { - GetPrivateProfileStringA(section.section_name, read_key, "", buf, MAIN_WIN_MAX_PATH, this->cfg_path.data()); - if (*buf != '\0') { - cfg_values *filenames = new cfg_values(); + char key_buf[80]{}; + for (auto index = 0; (read_key = section.key_at(index, key_buf)) != nullptr; ++index) { + char buf[MAIN_WIN_MAX_PATH]{}; + if (GetPrivateProfileStringA(section.section_name, read_key, "", buf, MAIN_WIN_MAX_PATH, cfg_path_str.data()) == 0) { + continue; + } + #ifdef JP - // .cfg (UTF-8) to Shift-JIS - guess_convert_to_system_encoding(buf, MAIN_WIN_MAX_PATH); + // .cfg (UTF-8) to Shift-JIS + guess_convert_to_system_encoding(buf, MAIN_WIN_MAX_PATH); #endif - const int num = tokenize_whitespace(buf, SAMPLE_MAX, tokens); - for (auto j = 0; j < num; j++) { - const auto path = path_build(dir, tokens[j]); - if (check_file(path)) { - filenames->push_back(string_make(tokens[j])); - } - } - if (filenames->empty()) { - delete filenames; - } else { - result->insert(section.action_type, index, filenames); - has_data = true; + char *tokens[SAMPLE_MAX]{}; + const int num = tokenize_whitespace(buf, SAMPLE_MAX, tokens); + + cfg_values filenames; + for (const std::string_view token : std::span(tokens, num)) { + if (is_regular_file(path_build(this->dir, token))) { + filenames.emplace_back(token); } } + if (filenames.empty()) { + continue; + } - index++; - } - - if (section.has_data) { - *(section.has_data) = has_data; + result.insert(section.action_type, index, std::move(filenames)); + if (section.has_data) { + *(section.has_data) = true; + } } } diff --git a/src/main-win/main-win-cfg-reader.h b/src/main-win/main-win-cfg-reader.h index 5113299df1..1feb67a93f 100644 --- a/src/main-win/main-win-cfg-reader.h +++ b/src/main-win/main-win-cfg-reader.h @@ -4,12 +4,13 @@ #include #include #include +#include #include #include typedef uint cfg_key; -using cfg_values = std::vector; -using cfg_map = std::unordered_map; +using cfg_values = std::vector; +using cfg_map = std::unordered_map; using key_name_func = concptr (*)(int, char *); /*! @@ -38,32 +39,26 @@ struct cfg_section { class CfgData { public: - CfgData() - { - map = new cfg_map(); - } - virtual ~CfgData() - { - delete map; - } - concptr get_rand(int key1_type, int key2_val); - bool has_key(int key1_type, int key2_val); - void insert(int key1_type, int key2_val, cfg_values *value); + CfgData() = default; + + std::optional get_rand(int key1_type, int key2_val) const; + bool has_key(int key1_type, int key2_val) const; + void insert(int key1_type, int key2_val, cfg_values &&value); protected: - cfg_map *map; + cfg_map map{}; }; class CfgReader { public: - CfgReader(std::filesystem::path dir, std::initializer_list files); - CfgData *read_sections(std::initializer_list sections); - std::string get_cfg_path() + CfgReader(const std::filesystem::path &dir, std::initializer_list files); + CfgData read_sections(std::initializer_list sections) const; + const std::filesystem::path &get_cfg_path() const { return cfg_path; } protected: std::filesystem::path dir; - std::string cfg_path; + std::filesystem::path cfg_path; }; diff --git a/src/main-win/main-win-file-utils.cpp b/src/main-win/main-win-file-utils.cpp deleted file mode 100644 index a16ef94caa..0000000000 --- a/src/main-win/main-win-file-utils.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/*! - * @file main-win-file-utils.cpp - * @brief Windows版固有実装(ファイル関連処理) - */ - -#include "main-win/main-win-file-utils.h" -#include "main-win/main-win-define.h" -#include "main-win/main-win-utils.h" -#include "util/angband-files.h" - -#include - -/* - * Check for existance of a file - * @param s path of file - * @retval true 指定ファイルが存在する(かつディレクトリではない) - * @retval false 指定ファイルが存在しない、またはディレクトリである - */ -bool check_file(const std::filesystem::path &s) -{ - const auto &file = s.string(); - DWORD attrib = GetFileAttributesW(to_wchar(file.data()).wc_str()); - if (attrib == INVALID_FILE_NAME) { - return false; - } - if (attrib & FILE_ATTRIBUTE_DIRECTORY) { - return false; - } - - return true; -} - -/* - * Check for existance of a directory - * @param s path of directory - * @retval true 指定ディレクトリが存在する - * @retval false 指定ディレクトリが存在しない、またはディレクトリではない - */ -bool check_dir(const std::filesystem::path &s) -{ - const auto &dir = s.string(); - char path[MAIN_WIN_MAX_PATH]; - strcpy(path, dir.data()); - int i = strlen(path); - if (i && (path[i - 1] == '\\')) { - path[--i] = '\0'; - } - - DWORD attrib = GetFileAttributesW(to_wchar(path).wc_str()); - if (attrib == INVALID_FILE_NAME) { - return false; - } - if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) { - return false; - } - - return true; -} - -/*! - * @brief 候補リストを順に確認し、存在するファイルのパスを返す。 - * @param dir ディレクトリ - * @param files ファイル名のリスト - * @return ファイルのパスを返す。候補リストのファイルすべて存在しない場合は空文字列を返す。 - */ -std::string find_any_file(const std::filesystem::path &dir, std::initializer_list files) -{ - for (const auto *filename : files) { - const auto path = path_build(dir, filename); - if (check_file(path)) { - return path.string(); - } - } - - return ""; -} diff --git a/src/main-win/main-win-file-utils.h b/src/main-win/main-win-file-utils.h deleted file mode 100644 index ef286bd2f2..0000000000 --- a/src/main-win/main-win-file-utils.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "system/h-type.h" -#include -#include -#include - -bool check_file(const std::filesystem::path &s); -bool check_dir(const std::filesystem::path &s); -std::string find_any_file(const std::filesystem::path &dir, std::initializer_list files); diff --git a/src/main-win/main-win-music.cpp b/src/main-win/main-win-music.cpp index ed14f6996f..d54b27b2c4 100644 --- a/src/main-win/main-win-music.cpp +++ b/src/main-win/main-win-music.cpp @@ -7,7 +7,6 @@ #include "dungeon/quest.h" #include "floor/floor-town.h" #include "main-win/main-win-define.h" -#include "main-win/main-win-file-utils.h" #include "main-win/main-win-mci.h" #include "main-win/main-win-mmsystem.h" #include "main-win/main-win-tokenizer.h" @@ -37,7 +36,7 @@ std::filesystem::path ANGBAND_DIR_XTRA_MUSIC; /* * "music.cfg" data */ -CfgData *music_cfg_data; +std::optional music_cfg_data; namespace main_win_music { @@ -134,7 +133,7 @@ void load_music_prefs() CfgReader reader(ANGBAND_DIR_XTRA_MUSIC, { "music_debug.cfg", "music.cfg" }); char device_type[256]; - GetPrivateProfileStringA("Device", "type", "MPEGVideo", device_type, _countof(device_type), reader.get_cfg_path().data()); + GetPrivateProfileStringA("Device", "type", "MPEGVideo", device_type, _countof(device_type), reader.get_cfg_path().string().data()); mci_device_type = to_wchar(device_type).wc_str(); // clang-format off @@ -184,12 +183,16 @@ errr play_music(int type, int val) return 0; } // now playing + if (!music_cfg_data) { + return 1; + } + auto filename = music_cfg_data->get_rand(type, val); if (!filename) { return 1; } // no setting - auto path_music = path_build(ANGBAND_DIR_XTRA_MUSIC, filename); + auto path_music = path_build(ANGBAND_DIR_XTRA_MUSIC, *filename); if (current_music_type != TERM_XTRA_MUSIC_MUTE) { if (current_music_path == path_music) { return 0; @@ -200,10 +203,9 @@ errr play_music(int type, int val) current_music_id = val; current_music_path = path_music; - const auto &filename_music = path_music.string(); - to_wchar path(filename_music.data()); + const auto path_music_str = path_music.wstring(); mci_open_parms.lpstrDeviceType = mci_device_type.data(); - mci_open_parms.lpstrElementName = path.wc_str(); + mci_open_parms.lpstrElementName = path_music_str.data(); mciSendCommandW(mci_open_parms.wDeviceID, MCI_STOP, MCI_WAIT, 0); mciSendCommandW(mci_open_parms.wDeviceID, MCI_CLOSE, MCI_WAIT, 0); mciSendCommandW(mci_open_parms.wDeviceID, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT | MCI_NOTIFY, (DWORD)&mci_open_parms); diff --git a/src/main-win/main-win-music.h b/src/main-win/main-win-music.h index 6f2f81d3dc..9dc4f4ef4f 100644 --- a/src/main-win/main-win-music.h +++ b/src/main-win/main-win-music.h @@ -5,11 +5,12 @@ #include "system/h-type.h" #include #include +#include #include extern bool use_pause_music_inactive; extern std::filesystem::path ANGBAND_DIR_XTRA_MUSIC; -extern CfgData *music_cfg_data; +extern std::optional music_cfg_data; namespace main_win_music { void load_music_prefs(); diff --git a/src/main-win/main-win-sound.cpp b/src/main-win/main-win-sound.cpp index b47e4f2471..159754d37a 100644 --- a/src/main-win/main-win-sound.cpp +++ b/src/main-win/main-win-sound.cpp @@ -8,7 +8,6 @@ #include "main-win/main-win-sound.h" #include "main-win/main-win-cfg-reader.h" #include "main-win/main-win-define.h" -#include "main-win/main-win-file-utils.h" #include "main-win/main-win-utils.h" #include "main-win/wav-reader.h" #include "main/sound-definitions-table.h" @@ -25,7 +24,7 @@ std::filesystem::path ANGBAND_DIR_XTRA_SOUND; /* * "sound.cfg" data */ -CfgData *sound_cfg_data; +std::optional sound_cfg_data; /*! * 効果音データ @@ -92,18 +91,19 @@ std::queue sound_queue; */ static void modulate_amplitude(int bits_per_sample, BYTE *pcm_buf, size_t bufsize, int mult, int div) { - auto modulate = [mult, div](auto sample) { + auto modulate = [mult, div](auto sample, int standard = 0) { using sample_t = decltype(sample); constexpr auto min = std::numeric_limits::min(); constexpr auto max = std::numeric_limits::max(); - const auto modulated_sample = std::clamp(sample * mult / div, min, max); + const auto diff = sample - standard; + const auto modulated_sample = std::clamp(standard + diff * mult / div, min, max); return static_cast(modulated_sample); }; switch (bits_per_sample) { case 8: for (auto i = 0U; i < bufsize; ++i) { - pcm_buf[i] = modulate(pcm_buf[i]); + pcm_buf[i] = modulate(pcm_buf[i], 128); } break; @@ -182,14 +182,14 @@ static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize, in /*! * 指定ファイルを再生する * - * @param buf ファイル名 + * @param path ファイルパス * @retval true 正常に処理された * @retval false 処理エラー */ -static bool play_sound_impl(char *filename, int volume) +static bool play_sound_impl(const std::filesystem::path &path, int volume) { wav_reader reader; - if (!reader.open(filename)) { + if (!reader.open(path)) { return false; } auto wf = reader.get_waveformat(); @@ -252,14 +252,17 @@ void finalize_sound(void) */ int play_sound(int val, int volume) { + if (!sound_cfg_data) { + return 1; + } + auto filename = sound_cfg_data->get_rand(TERM_XTRA_SOUND, val); if (!filename) { return 1; } - auto path = path_build(ANGBAND_DIR_XTRA_SOUND, filename); - auto filename_sound = path.string(); - if (play_sound_impl(filename_sound.data(), volume)) { + auto path = path_build(ANGBAND_DIR_XTRA_SOUND, *filename); + if (play_sound_impl(path, volume)) { return 0; } diff --git a/src/main-win/main-win-sound.h b/src/main-win/main-win-sound.h index 12ed6c0f4a..379c0e4ccf 100644 --- a/src/main-win/main-win-sound.h +++ b/src/main-win/main-win-sound.h @@ -3,9 +3,10 @@ #include "main-win/main-win-cfg-reader.h" #include #include +#include extern std::filesystem::path ANGBAND_DIR_XTRA_SOUND; -extern CfgData *sound_cfg_data; +extern std::optional sound_cfg_data; void load_sound_prefs(); void finalize_sound(); diff --git a/src/main-win/main-win-utils.cpp b/src/main-win/main-win-utils.cpp index 55402fed54..2721ba7e95 100644 --- a/src/main-win/main-win-utils.cpp +++ b/src/main-win/main-win-utils.cpp @@ -56,13 +56,13 @@ void save_screen_as_html(HWND hWnd) /*! * @brief 対象ファイルを選択した状態でエクスプローラーを開く - * @param filename 対象ファイル + * @param path 対象ファイルのパス */ -void open_dir_in_explorer(std::string_view filename) +void open_dir_in_explorer(const std::filesystem::path &path) { - std::stringstream ss; - ss << "/select," << filename; - ShellExecuteW(NULL, NULL, L"explorer.exe", to_wchar(ss.str().data()).wc_str(), NULL, SW_SHOWNORMAL); + std::wstringstream ss; + ss << L"/select," << path.wstring(); + ShellExecuteW(NULL, NULL, L"explorer.exe", ss.str().data(), NULL, SW_SHOWNORMAL); } /*! diff --git a/src/main-win/main-win-utils.h b/src/main-win/main-win-utils.h index d8ad502358..ad3149062a 100644 --- a/src/main-win/main-win-utils.h +++ b/src/main-win/main-win-utils.h @@ -84,5 +84,5 @@ class to_multibyte { bool is_already_running(); void save_screen_as_html(HWND hWnd); -void open_dir_in_explorer(std::string_view filename); +void open_dir_in_explorer(const std::filesystem::path &path); std::optional get_open_filename(OPENFILENAMEW *ofn, const std::filesystem::path &path_dir, const std::filesystem::path &path_file, DWORD max_name_size); diff --git a/src/main-win/wav-reader.cpp b/src/main-win/wav-reader.cpp index 58c3eeef7c..421821e963 100644 --- a/src/main-win/wav-reader.cpp +++ b/src/main-win/wav-reader.cpp @@ -6,11 +6,11 @@ #include "main-win/wav-reader.h" #include "main-win/main-win-utils.h" -bool wav_reader::open(char *filename) +bool wav_reader::open(const std::filesystem::path &path) { close(); - this->hmmio = ::mmioOpenW(to_wchar(filename).wc_str(), NULL, MMIO_READ); + this->hmmio = ::mmioOpenW(path.wstring().data(), NULL, MMIO_READ); if (this->hmmio == NULL) { return false; } diff --git a/src/main-win/wav-reader.h b/src/main-win/wav-reader.h index 8534afd12a..94548a99cf 100644 --- a/src/main-win/wav-reader.h +++ b/src/main-win/wav-reader.h @@ -6,6 +6,7 @@ #include +#include #include #include @@ -29,11 +30,11 @@ class wav_reader { /*! * WAVファイルを開く * - * @param filename + * @param path ファイルパス * @retval true 正常に処理された * @retval false 処理エラー */ - bool open(char *filename); + bool open(const std::filesystem::path &path); /*! * PCMデータ取得 * @details 呼び出し元でdelete[]すること diff --git a/src/player/player-spell-status.cpp b/src/player/player-spell-status.cpp new file mode 100644 index 0000000000..4c38d3e33c --- /dev/null +++ b/src/player/player-spell-status.cpp @@ -0,0 +1,94 @@ +#include "player/player-spell-status.h" +#include "player-base/player-class.h" +#include "system/player-type-definition.h" +#include "util/bit-flags-calculator.h" + +namespace { + +void set_flag_bit(BIT_FLAGS &flags, int bit_pos, bool value) +{ + if (value) { + set_bits(flags, 1U << bit_pos); + } else { + reset_bits(flags, 1U << bit_pos); + } +} + +} + +PlayerSpellStatus::PlayerSpellStatus(PlayerType *player_ptr) + : player_ptr(player_ptr) +{ +} + +PlayerSpellStatus::Realm PlayerSpellStatus::realm1() const +{ + return Realm(this->player_ptr, true); +} + +PlayerSpellStatus::Realm PlayerSpellStatus::realm2() const +{ + return Realm(this->player_ptr, false); +} + +PlayerSpellStatus::Realm::Realm(PlayerType *player_ptr, bool is_realm1) + : player_ptr(player_ptr) + , is_realm1(is_realm1) +{ +} + +void PlayerSpellStatus::Realm::initialize() +{ + auto &learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2; + auto &worked = this->is_realm1 ? this->player_ptr->spell_worked1 : this->player_ptr->spell_worked2; + auto &forgotten = this->is_realm1 ? this->player_ptr->spell_forgotten1 : this->player_ptr->spell_forgotten2; + + const auto is_sorcerer = PlayerClass(player_ptr).equals(PlayerClassType::SORCERER); + learned = worked = is_sorcerer ? 0xffffffffU : 0; + forgotten = 0; + + auto is_erase_spell_id = this->is_realm1 ? [](int spell_id) { return spell_id >= 32; } : [](int spell_id) { return spell_id < 32; }; + std::erase_if(this->player_ptr->spell_order_learned, is_erase_spell_id); +} + +bool PlayerSpellStatus::Realm::is_nothing_learned() const +{ + const auto learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2; + return learned == 0; +} + +bool PlayerSpellStatus::Realm::is_learned(int spell_id) const +{ + const auto learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2; + return any_bits(learned, 1U << spell_id); +} + +bool PlayerSpellStatus::Realm::is_worked(int spell_id) const +{ + const auto worked = this->is_realm1 ? this->player_ptr->spell_worked1 : this->player_ptr->spell_worked2; + return any_bits(worked, 1U << spell_id); +} + +bool PlayerSpellStatus::Realm::is_forgotten(int spell_id) const +{ + const auto forgotten = this->is_realm1 ? this->player_ptr->spell_forgotten1 : this->player_ptr->spell_forgotten2; + return any_bits(forgotten, 1U << spell_id); +} + +void PlayerSpellStatus::Realm::set_learned(int spell_id, bool value) +{ + auto &learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2; + set_flag_bit(learned, spell_id, value); +} + +void PlayerSpellStatus::Realm::set_worked(int spell_id, bool value) +{ + auto &worked = this->is_realm1 ? this->player_ptr->spell_worked1 : this->player_ptr->spell_worked2; + set_flag_bit(worked, spell_id, value); +} + +void PlayerSpellStatus::Realm::set_forgotten(int spell_id, bool value) +{ + auto &forgotten = this->is_realm1 ? this->player_ptr->spell_forgotten1 : this->player_ptr->spell_forgotten2; + set_flag_bit(forgotten, spell_id, value); +} diff --git a/src/player/player-spell-status.h b/src/player/player-spell-status.h new file mode 100644 index 0000000000..2d759006bd --- /dev/null +++ b/src/player/player-spell-status.h @@ -0,0 +1,32 @@ +#pragma once + +class PlayerType; + +class PlayerSpellStatus { +public: + PlayerSpellStatus(PlayerType *player_ptr); + + class Realm { + public: + Realm(PlayerType *player_ptr, bool is_realm1); + + void initialize(); + bool is_nothing_learned() const; + bool is_learned(int spell_id) const; + bool is_worked(int spell_id) const; + bool is_forgotten(int spell_id) const; + void set_learned(int spell_id, bool value = true); + void set_worked(int spell_id, bool value = true); + void set_forgotten(int spell_id, bool value = true); + + private: + PlayerType *player_ptr; + bool is_realm1; + }; + + Realm realm1() const; + Realm realm2() const; + +private: + PlayerType *player_ptr; +}; diff --git a/src/player/player-status.cpp b/src/player/player-status.cpp index 97ee283342..6ecc6648b4 100644 --- a/src/player/player-status.cpp +++ b/src/player/player-status.cpp @@ -75,6 +75,7 @@ #include "player/player-personality.h" #include "player/player-realm.h" #include "player/player-skill.h" +#include "player/player-spell-status.h" #include "player/player-status-flags.h" #include "player/player-status-table.h" #include "player/player-view.h" @@ -536,49 +537,38 @@ static void update_num_of_spells(PlayerType *player_ptr) } } - int num_boukyaku = 0; - for (int j = 0; j < 64; j++) { - if ((j < 32) ? any_bits(player_ptr->spell_forgotten1, (1UL << j)) : any_bits(player_ptr->spell_forgotten2, (1UL << (j - 32)))) { - num_boukyaku++; - } - } + PlayerSpellStatus pss(player_ptr); - player_ptr->new_spells = num_allowed + player_ptr->add_spells + num_boukyaku - player_ptr->learned_spells; - for (int i = 63; i >= 0; i--) { - if (!player_ptr->spell_learned1 && !player_ptr->spell_learned2) { - break; + auto num_forgotten = 0; + for (const auto &realm_status : { pss.realm1(), pss.realm2() }) { + for (auto spell_id = 0; spell_id < 32; spell_id++) { + if (realm_status.is_forgotten(spell_id)) { + num_forgotten++; + } } + } - int j = player_ptr->spell_order[i]; - if (j >= 99) { - continue; - } + player_ptr->new_spells = num_allowed + player_ptr->add_spells + num_forgotten - player_ptr->learned_spells; - const auto &realm = (j < 32) ? pr.realm1() : pr.realm2(); - const auto &spell = realm.get_spell_info(j % 32); + for (auto it = player_ptr->spell_order_learned.crbegin(); it != player_ptr->spell_order_learned.crend(); ++it) { + const auto is_realm1 = *it < 32; + const auto spell_id = *it % 32; + const auto &realm = is_realm1 ? pr.realm1() : pr.realm2(); + const auto &spell = realm.get_spell_info(spell_id); if (spell.slevel <= player_ptr->lev) { continue; } - bool is_spell_learned = (j < 32) ? any_bits(player_ptr->spell_learned1, (1UL << j)) : any_bits(player_ptr->spell_learned2, (1UL << (j - 32))); - if (!is_spell_learned) { + auto realm_status = is_realm1 ? pss.realm1() : pss.realm2(); + if (!realm_status.is_learned(spell_id)) { continue; } - if (j < 32) { - set_bits(player_ptr->spell_forgotten1, (1UL << j)); - } else { - set_bits(player_ptr->spell_forgotten2, (1UL << (j - 32))); - } - - if (j < 32) { - reset_bits(player_ptr->spell_learned1, (1UL << j)); - } else { - reset_bits(player_ptr->spell_learned2, (1UL << (j - 32))); - } + realm_status.set_forgotten(spell_id); + realm_status.set_learned(spell_id, false); - const auto &spell_name = realm.get_spell_name(j % 32); + const auto &spell_name = realm.get_spell_name(spell_id); #ifdef JP msg_format("%sの%sを忘れてしまった。", spell_name.data(), spell_category.data()); #else @@ -588,38 +578,24 @@ static void update_num_of_spells(PlayerType *player_ptr) } /* Forget spells if we know too many spells */ - for (int i = 63; i >= 0; i--) { + for (auto it = player_ptr->spell_order_learned.crbegin(); it != player_ptr->spell_order_learned.crend(); ++it) { if (player_ptr->new_spells >= 0) { break; } - if (!player_ptr->spell_learned1 && !player_ptr->spell_learned2) { - break; - } - int j = player_ptr->spell_order[i]; - if (j >= 99) { - continue; - } + const auto is_realm1 = *it < 32; + const auto spell_id = *it % 32; - bool is_spell_learned = (j < 32) ? any_bits(player_ptr->spell_learned1, (1UL << j)) : any_bits(player_ptr->spell_learned2, (1UL << (j - 32))); - if (!is_spell_learned) { + auto realm_status = is_realm1 ? pss.realm1() : pss.realm2(); + if (!realm_status.is_learned(spell_id)) { continue; } - if (j < 32) { - set_bits(player_ptr->spell_forgotten1, (1UL << j)); - } else { - set_bits(player_ptr->spell_forgotten2, (1UL << (j - 32))); - } - - if (j < 32) { - reset_bits(player_ptr->spell_learned1, (1UL << j)); - } else { - reset_bits(player_ptr->spell_learned2, (1UL << (j - 32))); - } + realm_status.set_forgotten(spell_id); + realm_status.set_learned(spell_id, false); - const auto &realm = (j < 32) ? pr.realm1() : pr.realm2(); - const auto &spell_name = realm.get_spell_name(j % 32); + const auto &realm = is_realm1 ? pr.realm1() : pr.realm2(); + const auto &spell_name = realm.get_spell_name(spell_id); #ifdef JP msg_format("%sの%sを忘れてしまった。", spell_name.data(), spell_category.data()); #else @@ -629,44 +605,30 @@ static void update_num_of_spells(PlayerType *player_ptr) } /* Check for spells to remember */ - for (int i = 0; i < 64; i++) { + for (const auto j : player_ptr->spell_order_learned) { if (player_ptr->new_spells <= 0) { break; } - if (!player_ptr->spell_forgotten1 && !player_ptr->spell_forgotten2) { - break; - } - int j = player_ptr->spell_order[i]; - if (j >= 99) { - break; - } - const auto &realm = (j < 32) ? pr.realm1() : pr.realm2(); - const auto &spell = realm.get_spell_info(j % 32); + const auto is_realm1 = j < 32; + const auto spell_id = j % 32; + + const auto &realm = is_realm1 ? pr.realm1() : pr.realm2(); + const auto &spell = realm.get_spell_info(spell_id); if (spell.slevel > player_ptr->lev) { continue; } - bool is_spell_learned = (j < 32) ? any_bits(player_ptr->spell_forgotten1, (1UL << j)) : any_bits(player_ptr->spell_forgotten2, (1UL << (j - 32))); - if (!is_spell_learned) { + auto realm_status = is_realm1 ? pss.realm1() : pss.realm2(); + if (!realm_status.is_forgotten(spell_id)) { continue; } - if (j < 32) { - reset_bits(player_ptr->spell_forgotten1, (1UL << j)); - } else { - reset_bits(player_ptr->spell_forgotten2, (1UL << (j - 32))); - } - - if (j < 32) { - set_bits(player_ptr->spell_learned1, (1UL << j)); - - } else { - set_bits(player_ptr->spell_learned2, (1UL << (j - 32))); - } + realm_status.set_forgotten(spell_id, false); + realm_status.set_learned(spell_id); - const auto &spell_name = realm.get_spell_name(j % 32); + const auto &spell_name = realm.get_spell_name(spell_id); #ifdef JP msg_format("%sの%sを思い出した。", spell_name.data(), spell_category.data()); #else @@ -684,7 +646,7 @@ static void update_num_of_spells(PlayerType *player_ptr) continue; } - if (any_bits(player_ptr->spell_learned1, (1UL << j))) { + if (pss.realm1().is_learned(j)) { continue; } diff --git a/src/save/save.cpp b/src/save/save.cpp index daafd8fdfa..7bd34493a8 100644 --- a/src/save/save.cpp +++ b/src/save/save.cpp @@ -193,8 +193,9 @@ static bool wr_savefile_new(PlayerType *player_ptr) wr_u32b(player_ptr->spell_forgotten2); wr_s16b(player_ptr->learned_spells); wr_s16b(player_ptr->add_spells); - for (int i = 0; i < 64; i++) { - wr_byte((byte)player_ptr->spell_order[i]); + for (auto i = 0; i < 64; i++) { + const auto spell_id = (i < std::ssize(player_ptr->spell_order_learned)) ? player_ptr->spell_order_learned[i] : 255; + wr_byte(static_cast(spell_id)); } for (int i = 0; i < INVEN_TOTAL; i++) { diff --git a/src/spell/spell-info.cpp b/src/spell/spell-info.cpp index 9b51ae3788..3b3d57f71a 100644 --- a/src/spell/spell-info.cpp +++ b/src/spell/spell-info.cpp @@ -4,6 +4,7 @@ #include "player-info/class-info.h" #include "player/player-realm.h" #include "player/player-skill.h" +#include "player/player-spell-status.h" #include "player/player-status-table.h" #include "player/player-status.h" #include "realm/realm-types.h" @@ -303,6 +304,8 @@ void print_spells(PlayerType *player_ptr, SPELL_IDX target_spell_id, const SPELL const auto info = exe_spell(player_ptr, use_realm, spell_id, SpellProcessType::INFO); concptr comment = info->data(); byte line_attr = TERM_WHITE; + PlayerSpellStatus pss(player_ptr); + const auto realm_status = pr.realm1().equals(use_realm) ? pss.realm1() : pss.realm2(); if (pc.is_every_magic()) { if (spell.slevel > player_ptr->max_plv) { comment = _("未知", "unknown"); @@ -314,13 +317,13 @@ void print_spells(PlayerType *player_ptr, SPELL_IDX target_spell_id, const SPELL } else if (!pr.realm1().equals(use_realm) && !pr.realm2().equals(use_realm)) { comment = _("未知", "unknown"); line_attr = TERM_L_BLUE; - } else if (pr.realm1().equals(use_realm) ? ((player_ptr->spell_forgotten1 & (1UL << spell_id))) : ((player_ptr->spell_forgotten2 & (1UL << spell_id)))) { + } else if (realm_status.is_forgotten(spell_id)) { comment = _("忘却", "forgotten"); line_attr = TERM_YELLOW; - } else if (!(pr.realm1().equals(use_realm) ? (player_ptr->spell_learned1 & (1UL << spell_id)) : (player_ptr->spell_learned2 & (1UL << spell_id)))) { + } else if (!realm_status.is_learned(spell_id)) { comment = _("未知", "unknown"); line_attr = TERM_L_BLUE; - } else if (!(pr.realm1().equals(use_realm) ? (player_ptr->spell_worked1 & (1UL << spell_id)) : (player_ptr->spell_worked2 & (1UL << spell_id)))) { + } else if (!realm_status.is_worked(spell_id)) { comment = _("未経験", "untried"); line_attr = TERM_L_GREEN; } diff --git a/src/system/player-type-definition.h b/src/system/player-type-definition.h index c30ef52400..62b962e2b9 100644 --- a/src/system/player-type-definition.h +++ b/src/system/player-type-definition.h @@ -173,7 +173,7 @@ class PlayerType { BIT_FLAGS spell_worked2{}; /* bit mask of spells tried and worked */ BIT_FLAGS spell_forgotten1{}; /* bit mask of spells learned but forgotten */ BIT_FLAGS spell_forgotten2{}; /* bit mask of spells learned but forgotten */ - SPELL_IDX spell_order[64]{}; /* order spells learned/remembered/forgotten */ + std::vector spell_order_learned{}; /* order spells learned */ SUB_EXP spell_exp[64]{}; /* Proficiency of spells */ std::map> weapon_exp{}; /* Proficiency of weapons */ diff --git a/src/util/angband-files.cpp b/src/util/angband-files.cpp index 432150c937..5645319e78 100644 --- a/src/util/angband-files.cpp +++ b/src/util/angband-files.cpp @@ -2,6 +2,9 @@ #include "locale/japanese.h" #include "system/angband-exceptions.h" #include "util/string-processor.h" +#ifdef WINDOWS +#include "main-win/main-win-utils.h" +#endif #include #include @@ -169,7 +172,13 @@ std::filesystem::path path_build(const std::filesystem::path &path, std::string_ } auto parsed_path = path_parse(path); +#ifdef WINDOWS + // システムロケールがUTF-8の場合、appendによるUTF-16への変換時に + // Shift-JISをUTF-8とみなしてしまい変換に失敗するので、自前でUTF-16に変換してからappendする + const auto &path_ret = parsed_path.append(to_wchar(file.data()).wc_str()); +#else const auto &path_ret = parsed_path.append(file); +#endif constexpr auto max_path_length = 1024; const auto path_str = path_ret.string(); if (path_str.length() > max_path_length) { diff --git a/src/window/display-sub-windows.cpp b/src/window/display-sub-windows.cpp index 3c91c74961..810a5fed5e 100644 --- a/src/window/display-sub-windows.cpp +++ b/src/window/display-sub-windows.cpp @@ -22,6 +22,7 @@ #include "player-base/player-class.h" #include "player-info/class-info.h" #include "player/player-realm.h" +#include "player/player-spell-status.h" #include "player/player-status-flags.h" #include "player/player-status-table.h" #include "player/player-status.h" @@ -824,22 +825,26 @@ static void display_spell_list(PlayerType *player_ptr) y = (j < 3) ? 0 : (m[j - 3] + 2); x = 27 * (j % 3); int n = 0; - for (int i = 0; i < 32; i++) { + + PlayerSpellStatus pss(player_ptr); + const auto realm_status = (j < 1) ? pss.realm1() : pss.realm2(); + + for (auto spell_id = 0; spell_id < 32; spell_id++) { byte a = TERM_WHITE; const auto &realm = (j < 1) ? pr.realm1() : pr.realm2(); - const auto &spell = realm.get_spell_info(i); - const auto &spell_name = realm.get_spell_name(i % 32); + const auto &spell = realm.get_spell_info(spell_id); + const auto &spell_name = realm.get_spell_name(spell_id); auto name = spell_name.data(); if (spell.slevel >= 99) { name = _("(判読不能)", "(illegible)"); a = TERM_L_DARK; - } else if ((j < 1) ? ((player_ptr->spell_forgotten1 & (1UL << i))) : ((player_ptr->spell_forgotten2 & (1UL << (i % 32))))) { + } else if (realm_status.is_forgotten(spell_id)) { a = TERM_ORANGE; - } else if (!((j < 1) ? (player_ptr->spell_learned1 & (1UL << i)) : (player_ptr->spell_learned2 & (1UL << (i % 32))))) { + } else if (!realm_status.is_learned(spell_id)) { a = TERM_RED; - } else if (!((j < 1) ? (player_ptr->spell_worked1 & (1UL << i)) : (player_ptr->spell_worked2 & (1UL << (i % 32))))) { + } else if (!realm_status.is_worked(spell_id)) { a = TERM_YELLOW; } diff --git a/src/wizard/wizard-special-process.cpp b/src/wizard/wizard-special-process.cpp index 02d70d05db..1e72f19d0c 100644 --- a/src/wizard/wizard-special-process.cpp +++ b/src/wizard/wizard-special-process.cpp @@ -63,6 +63,7 @@ #include "player/patron.h" #include "player/player-realm.h" #include "player/player-skill.h" +#include "player/player-spell-status.h" #include "player/player-status-table.h" #include "player/player-status.h" #include "player/race-info-table.h" @@ -684,6 +685,10 @@ void wiz_reset_class(PlayerType *player_ptr) if (chosen_realms->first != RealmType::NONE) { pr.set(chosen_realms->first, chosen_realms->second); } + PlayerSpellStatus pss(player_ptr); + pss.realm1().initialize(); + pss.realm2().initialize(); + player_ptr->learned_spells = 0; change_birth_flags(); handle_stuff(player_ptr); } @@ -704,6 +709,10 @@ void wiz_reset_realms(PlayerType *player_ptr) if (chosen_realms->first != RealmType::NONE) { pr.set(chosen_realms->first, chosen_realms->second); } + PlayerSpellStatus pss(player_ptr); + pss.realm1().initialize(); + pss.realm2().initialize(); + player_ptr->learned_spells = 0; change_birth_flags(); handle_stuff(player_ptr); }